Migrer des applications Node.js de Heroku vers Cloud Run

Ce tutoriel explique comment migrer des applications Web Node.js exécutées sur Heroku vers Cloud Run sur Google Cloud. Il est destiné aux architectes et aux propriétaires de produits qui souhaitent migrer leurs applications de Heroku vers des services gérés sur Google Cloud.

Cloud Run est une plate-forme de calcul gérée qui vous permet d'exécuter des conteneurs sans état pouvant être appelés via des requêtes HTTP. Il repose sur une instance Knative Open Source, qui rend possible la portabilité entre différentes plates-formes et prend en charge des normes et des workflows de conteneurs pour la livraison continue. La plate-forme Cloud Run est bien intégrée à la suite de produits Google Cloud, et facilite la conception et le développement d'applications portables, évolutives et résilientes.

Dans ce tutoriel, vous allez apprendre à migrer vers Google Cloud une application écrite dans Node.js et qui utilise Heroku Postgres comme service de sauvegarde sur Heroku. L'application Web, qui est placée dans un conteneur et hébergée dans Cloud Run, utilise Cloud SQL pour PostgreSQL en tant que couche de persistance.

Dans ce tutoriel, vous utilisez une application simple appelée "Tasks" qui vous permet d'afficher et de créer des tâches. Ces dernières sont stockées dans Heroku Postgres dans le déploiement actuel de l'application sur Heroku.

Dans ce tutoriel, nous partons du principe que vous maîtrisez les fonctionnalités de base de Heroku et que vous possédez un compte Heroku (ou que vous y avez accès). Nous partons également du principe que vous connaissez bien Cloud Run, Cloud SQL, Docker et Node.js.

Objectifs

  • Créer une image Docker pour déployer l'application sur Cloud Run
  • Créer une instance Cloud SQL pour PostgreSQL qui servira de backend après la migration vers Google Cloud
  • Examiner le code Node.js pour comprendre comment Cloud Run se connecte à Cloud SQL et pour voir les modifications qui doivent être apportées au code (le cas échéant) afin d'effectuer la migration de Heroku vers Cloud Run
  • Migrer les données de Heroku Postgres vers Cloud SQL pour PostgreSQL
  • Déployer l'application sur Cloud Run
  • Tester l'application déployée

Coûts

Ce tutoriel utilise les composants facturables suivants de Google Cloud :

Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût. Les nouveaux utilisateurs de Google Cloud peuvent bénéficier d'un essai gratuit.

Les ressources que vous utilisez sur Heroku peuvent également vous être facturées.

Avant de commencer

  1. Connectez-vous à votre compte Google.

    Si vous n'en possédez pas déjà un, vous devez en créer un.

  2. Dans Cloud Console, sur la page de sélection du projet, sélectionnez ou créez un projet Cloud.

    Accéder à la page de sélection du projet

  3. Vérifiez que la facturation est activée pour votre projet Google Cloud. Découvrez comment vérifier que la facturation est activée pour votre projet.

  4. Activer les API Cloud SQL and Cloud Run .

    Activer les API

Configurer votre environnement

  1. Ouvrez Cloud Shell.

    OUVRIR Cloud Shell

  2. Dans Cloud Shell, attribuez des paramètres par défaut pour les valeurs utilisées tout au long du tutoriel, telles que la région et la zone. Dans ce tutoriel, vous utilisez us-central1 comme région par défaut et us-central1-a comme zone par défaut.

    gcloud config set compute/region us-central1
    gcloud config set compute/zone us-central1-a
    
  3. Configurez l'outil de ligne de commande gcloud de sorte qu'il utilise us-central1 comme région par défaut pour Cloud Run :

    gcloud config set run/region us-central1
    
  4. Créez une variable d'environnement destinée à contenir un nom d'application par défaut pour ce tutoriel :

    export APP_NAME=tasks-web-app
    

Architecture

Les figures suivantes décrivent l'architecture de l'application Web sur Heroku (en l'état) et son agencement architectural sur Google Cloud (que vous allez créer).

Architecture en l'état sur Heroku.
Figure 1. Architecture en l'état sur Heroku.

L'application Tasks actuellement déployée sur Heroku comprend un ou plusieurs dynos Web. Les dynos Web sont capables de recevoir du trafic HTTP et d'y répondre, contrairement aux dynos de nœud de calcul, qui conviennent mieux aux tâches en arrière-plan et aux tâches temporisées. L'application diffuse une page d'index qui affiche les tâches stockées dans une base de données Postgres, à l'aide de la bibliothèque de modèles Mustache pour Node.js.

Vous pouvez accéder à l'application via une URL HTTPS. Une route /tasks au niveau de cette URL vous permet de créer des tâches.

Architecture en l'état sur Heroku.
Figure 2. Architecture que vous créez sur Google Cloud

Sur Google Cloud, Cloud Run est utilisé comme plate-forme sans serveur pour déployer l'application Tasks. Cloud Run est conçu pour exécuter des conteneurs sans état et basés sur des requêtes. Il convient parfaitement lorsque votre service géré doit prendre en charge des applications en conteneur dotées d'une fonctionnalité d'autoscaling, mais également de scaling à zéro instance lorsqu'elles ne diffusent pas de trafic.

Mettre en correspondance les composants utilisés dans Heroku et Google Cloud

Le tableau suivant met en correspondance les composants de la plate-forme Heroku et ceux de Google Cloud. Cela vous aide à traduire l'architecture décrite dans ce tutoriel de Heroku vers Google Cloud.

Composant Plate-forme Heroku Google Cloud
Conteneurs Dynos : Heroku utilise le modèle de conteneur pour créer des applications Heroku et procéder à leur scaling. Ces conteneurs Linux sont appelés dynos et peuvent effectuer un scaling jusqu'à un nombre d'instances que vous spécifiez afin de répondre aux exigences de ressources de votre application Heroku. Vous pouvez choisir parmi un éventail de types de dynos en fonction des exigences en termes de processeur et de mémoire de votre application. Conteneurs Cloud Run : Google Cloud accepte l'exécution de charges de travail placées dans des conteneurs sans état, qui peuvent être exécutés dans un environnement entièrement géré ou dans des clusters Google Kubernetes Engine (GKE).
Application Web Application Heroku : les dynos sont les principaux composants des applications Heroku. Les applications sont en général composées d'un ou de plusieurs types de dynos. Il s'agit habituellement d'une combinaison de dynos Web et de nœud de calcul. Service Cloud Run : une application Web peut être modélisée comme un service Cloud Run. Chaque service obtient son propre point de terminaison HTTPS et peut automatiquement passer de 0 à N instances ou inversement en fonction du trafic sur le point de terminaison du service.
Base de données Heroku Postgres est la base de données en tant que service (DaaS) reposant sur PostgreSQL d'Heroku. Cloud SQL est un service de base de données géré pour les bases de données relationnelles sur Google Cloud. Il offre deux variantes : PostgreSQL et MySQL.

Déployer l'exemple d'application Web Tasks sur Heroku

Les sections suivantes montrent comment configurer l'interface de ligne de commande (CLI) pour Heroku, cloner le dépôt source GitHub et déployer l'application sur Heroku.

Configurer l'interface de ligne de commande pour Heroku

  1. Dans Cloud Shell, exécutez la commande suivante pour configurer la CLI Heroku :

    curl https://cli-assets.heroku.com/install-ubuntu.sh | sh
    
  2. Connectez-vous à votre compte Heroku :

    heroku login --interactive
    

Cloner le dépôt source

  1. Dans Cloud Shell, clonez le dépôt GitHub de l'exemple d'application Tasks :

    git clone https://github.com/GoogleCloudPlatform/migrate-webapp-heroku-to-cloudrun-node.git
    
  2. Remplacez les répertoires par le répertoire créé en clonant le dépôt :

    cd migrate-webapp-heroku-to-cloudrun-node
    

    Le répertoire contient les fichiers suivants :

    • Un script Node.js nommé index.js comportant le code des routes diffusées par l'application Web.
    • Les fichiers package.json et package-lock.json décrivant les dépendances de l'application Web. Vous devez installer ces dépendances pour que l'application s'exécute.
    • Un fichier Procfile qui spécifie la commande que l'application exécute au démarrage. Vous créez un fichier Procfile pour déployer votre application sur Heroku.
    • Un répertoire views qui comporte le contenu HTML diffusé par l'application Web sur la route "/".
    • Un fichier .gitignore.

Déployer une application sur Heroku

  1. Dans Cloud Shell, créez une application Heroku :

    heroku create
    
  2. Ajoutez le module complémentaire Heroku Postgres pour provisionner une base de données PostgreSQL :

    heroku addons:create heroku-postgresql:hobby-dev
    
  3. Assurez-vous que le module complémentaire a bien été ajouté :

    heroku addons
    

    Si le module complémentaire Postgres a bien été ajouté, un message de ce type apparaît :

    Owning-App               Add-on                      Plan                          Price    State
    ----------------------   ------------------------    --------------------------    -----    -----
    sample-nodejs-todo-app   postgresql-adjacent-95585   heroku-postgresql:hobby-dev   free     created
    
  4. Déployez l'application sur Heroku :

    git push heroku master
    
  5. Récupérez l'URI Heroku Postgres à partir de la console Heroku. Vous pouvez également exécuter la commande suivante pour récupérer l'URI :

    heroku config
    

    Notez l'URI récupéré. Vous en aurez besoin à l'étape suivante.

  6. Exécutez un conteneur Docker. Remplacez database-uri par l'URI Heroku Postgres que vous avez noté à l'étape précédente.

    docker run -it --rm postgres psql "database-uri"
    
  7. Dans le conteneur Docker, créez la table TASKS à l'aide de la commande suivante :

    CREATE TABLE TASKS
    (DESCRIPTION TEXT NOT NULL);
    
  8. Quittez le conteneur :

    exit
    
  9. Dans Cloud Shell, obtenez l'URL de votre application Heroku :

    heroku info
    
  10. Ouvrez l'URL de l'application dans une fenêtre de navigateur. L'application ressemble à ceci (bien qu'aucune tâche ne soit répertoriée dans votre version) :

    Application de liste de tâches dans le navigateur Web.

  11. Créez des exemples de tâches dans votre application à partir du navigateur. Assurez-vous que les tâches sont récupérées à partir de la base de données et visibles dans l'interface utilisateur.

Préparer le code de l'application Web pour la migration vers Cloud Run

Cette section détaille les étapes à suivre pour préparer votre application Web en vue de son déploiement sur Cloud Run.

Créer et publier votre conteneur Docker dans Container Registry

Vous avez besoin d'une image Docker pour créer le conteneur d'applications afin qu'il puisse s'exécuter dans Cloud Run. Vous pouvez créer le conteneur manuellement ou à l'aide de Buildpacks.

Créer le conteneur manuellement

  1. Dans Cloud Shell, créez un fichier Dockerfile dans le répertoire créé en clonant le dépôt de ce tutoriel :

    cat <<EOF > Dockerfile
    # Use the official Node image.
    # https://hub.docker.com/_/node
    FROM node:10-alpine
    
    # Create and change to the app directory.
    WORKDIR /app
    
    # Copying this separately prevents re-running npm install on every code change.
    COPY package*.json ./
    RUN npm install
    
    # Copy local code to the container image.
    COPY . /app
    
    # Configure and document the service HTTP port.
    ENV PORT 8080
    EXPOSE $PORT
    
    # Run the web service on container startup.
    CMD ["npm", "start"]
    EOF
    
  2. Créez votre conteneur avec Cloud Build, puis publiez l'image dans Container Registry :

    gcloud builds submit --tag gcr.io/${DEVSHELL_PROJECT_ID}/$APP_NAME:1
    
  3. Créez une variable d'environnement destinée à contenir le nom de l'image Docker que vous avez créée :

    export IMAGE_NAME="gcr.io/${DEVSHELL_PROJECT_ID}/$APP_NAME:1"
    

Créer un conteneur avec Buildpacks

  1. Dans Cloud Shell, installez la CLI pack :

    wget https://github.com/buildpack/pack/releases/download/v0.2.1/pack-v0.2.1-linux.tgz
    tar xvf pack-v0.2.1-linux.tgz
    rm pack-v0.2.1-linux.tgz
    sudo mv pack /usr/local/bin/
    
  2. Configurez la CLI pack de sorte qu'elle utilise l'outil de création Heroku par défaut :

    pack set-default-builder heroku/buildpacks
    
  3. Créez une variable d'environnement destinée à contenir le nom de l'image Docker :

    export IMAGE_NAME=gcr.io/${DEVSHELL_PROJECT_ID}/$APP_NAME:1
    
  4. Créez l'image à l'aide de la commande pack, puis transférez-la ou publiez-la dans Container Registry :

    pack build --publish $IMAGE_NAME
    

Créer une instance Cloud SQL pour PostgreSQL

Créez une instance Cloud SQL pour PostgreSQL qui servira de backend pour l'application Web. Dans ce tutoriel, PostgreSQL est le mieux adapté comme exemple d'application déployé sur Heroku, car celui-ci se sert d'une base de données Postgres comme backend. Pour les besoins de cette application, la migration vers Cloud SQL pour PostgreSQL à partir d'un service Postgres géré ne nécessite aucune modification du schéma.

gcloud

  1. Créez une variable d'environnement nommée CLOUDSQL_DB_NAME et destinée à contenir le nom de l'instance de base de données que vous allez créer à l'étape suivante :

    export CLOUDSQL_DB_NAME=tasks-db
    
  2. Créez la base de données :

    gcloud sql instances create $CLOUDSQL_DB_NAME  \
        --cpu=1 \
        --memory=4352Mib \
        --database-version=POSTGRES_9_6 \
        --region=us-central1
    

    L'initialisation de l'instance peut prendre quelques minutes.

  3. Définissez le mot de passe de l'utilisateur Postgres :

    gcloud sql users set-password postgres \
        --instance=$CLOUDSQL_DB_NAME  \
        --password=postgres-password
    

Console

  1. Dans Cloud Console, accédez à la page Instances Cloud SQL :

    Accéder à la page "Instances Cloud SQL"

  2. Cliquez sur Créer une instance.

  3. Sélectionnez PostgreSQL et cliquez sur Suivant.

  4. Saisissez tasks-db comme nom de l'instance.

  5. Créez le mot de passe de l'utilisateur postgres.

  6. Pour la région, sélectionnez us-central1.

  7. Ne modifiez pas les autres paramètres par défaut.

Importer des données dans Cloud SQL à partir de Heroku Postgres

Vous disposez de plusieurs modèles de migration pour migrer des données vers Cloud SQL. En règle générale, la meilleure approche, qui nécessite peu ou pas de temps d'arrêt, consiste à configurer Cloud SQL en tant qu'instance dupliquée de la base de données en cours de migration, et à faire de Cloud SQL l'instance principale après la migration. Heroku Postgres ne prend pas en charge les instances dupliquées externes (suiveurs). Dans ce tutoriel, vous migrez le schéma de l'application à l'aide d'outils Open Source.

Dans le cadre de l'application Tasks de ce tutoriel, vous vous servez de l'utilitaire pg_dump pour exporter des données de Heroku Postgres vers un bucket Cloud Storage, puis les importer dans Cloud SQL. Cet utilitaire peut transférer des données entre des versions homogènes ou lorsque la version de la base de données de destination est plus récente que celle de la base de données source.

  1. Dans Cloud Shell, obtenez les identifiants de la base de données Heroku Postgres associée à l'exemple d'application. Vous en aurez besoin à l'étape suivante.

    heroku pg:credentials:url
    

    Cette commande affiche la chaîne d'informations de connexion et l'URL de connexion de votre application. La chaîne d'informations de connexion respecte le format suivant :

    "dbname=database-name host=FQDN port=5432 user=user-name password=password-string sslmode=require"
    

    Pour obtenir un exemple de valeur FQDN (nom de domaine complet) dans une chaîne d'informations de connexion, consultez la documentation Heroku.

  2. Définissez les variables d'environnement de sorte qu'elles contiennent les valeurs Heroku que vous utiliserez aux étapes suivantes. Remplacez les espaces réservés FQDN, user-name, password-string et database-name par leurs valeurs correspondantes dans la chaîne d'informations de connexion.

    export HEROKU_PG_HOST=FQDN
    export HEROKU_PG_USER=user-name
    export HEROKU_PG_PASSWORD=password-string
    export HEROKU_PG_DBNAME=database-name
    
  3. Créez une sauvegarde au format SQL de votre base de données Heroku Postgres :

    docker run \
      -it --rm \
      -e PGPASSWORD=$HEROKU_PG_PASSWORD \
      -v $(pwd):/tmp \
      --entrypoint "pg_dump" \
      postgres \
      -Fp \
      --no-acl \
      --no-owner \
      -h $HEROKU_PG_HOST \
      -U $HEROKU_PG_USER \
      $HEROKU_PG_DBNAME > herokudump.sql
    
  4. Créez une variable d'environnement destinée à contenir le nom de votre bucket Cloud Storage. Ce nom doit être unique. La variable d'environnement doit respecter le format gs://bucket-name.

    export PG_BACKUP_BUCKET=gs://bucket-name
    
  5. Créez un bucket Cloud Storage à l'aide de l'outil de ligne de commande gsutil :

    gsutil mb -c regional -l us-central1 $PG_BACKUP_BUCKET
    
  6. Importez le fichier SQL dans ce bucket :

    gsutil cp herokudump.sql $PG_BACKUP_BUCKET
    
  7. Dans Cloud Console, accédez à la page Instances Cloud SQL :

    Accéder à la page "Instances Cloud SQL"

  8. Sélectionnez l'instance afin d'ouvrir sa page Instance details (Détails de l'instance).

  9. Dans la barre de boutons, cliquez sur Import (Importer).

    Importer le fichier de vidage SQL à partir de Cloud Storage.

  10. Dans le champ Fichier Cloud Storage, saisissez le chemin d'accès au fichier de vidage SQL que vous avez importé dans Cloud Storage.

  11. Dans le champ Format d'importation, sélectionnez SQL.

  12. Dans le champ Base de données, sélectionnez postgres.

  13. Développez Options avancées, puis sélectionnez postgres dans le champ Utilisateur.

  14. Cliquez sur Importer pour démarrer l'importation.

  15. Examinez les mises à jour figurant dans l'onglet Opérations de l'instance afin de vérifier que l'importation a abouti.

Méthode d'accès de Cloud Run à la base de données Cloud SQL

De la même façon que l'application Web déployée sur Heroku doit se connecter à l'instance gérée de Heroku Postgres, Cloud Run doit avoir accès à Cloud SQL pour pouvoir lire et écrire des données.

Cloud Run communique avec Cloud SQL à l'aide du proxy Cloud SQL activé et configuré automatiquement lorsque vous déployez le conteneur sur Cloud Run. La base de données n'a pas besoin d'adresses IP externes approuvées, car toutes les communications qu'elle reçoit proviennent du proxy utilisant un protocole TCP sécurisé.

Votre code doit appeler des opérations de base de données (telles que l'extraction de données de la base de données ou l'écriture dans celle-ci) en appelant le proxy via un socket UNIX.

Étant donné que cette application Web est écrite dans Node.js, vous utilisez la bibliothèque pg-connection-string pour analyser une URL de base de données et créer un objet config. L'avantage de cette approche est qu'elle facilite la connexion à la base de données backend sur Heroku et Cloud Run.

À l'étape suivante, vous transmettez l'URL de la base de données en tant que variable d'environnement lors du déploiement de l'application Web.

Déployer l'exemple d'application sur Cloud Run

  1. Dans Cloud Shell, créez une variable d'environnement contenant le nom de connexion de l'instance Cloud SQL créée :

    export DB_CONN_NAME=$(gcloud sql instances describe $CLOUDSQL_DB_NAME --format='value(connectionName)')
    
  2. Créez une variable d'environnement nommée DATABASE_URL et destinée à contenir la chaîne de connexion permettant de se connecter au proxy Cloud SQL via un port UNIX. Remplacez your-db-password par le mot de passe que vous avez créé pour votre instance de base de données.

    export DATABASE_URL="socket:/cloudsql/${DB_CONN_NAME}?db=postgres&user=postgres&password=your-db-password"
    
  3. Déployez l'application Web sur Cloud Run.

    gcloud beta run deploy tasksapp-$DEVSHELL_PROJECT_ID \
        --image=$IMAGE_NAME \
        --set-env-vars=DATABASE_URL=$DATABASE_URL \
        --add-cloudsql-instances $DB_CONN_NAME \
        --allow-unauthenticated \
        --platform managed
    

    La commande précédente associe également votre conteneur Cloud Run à l'instance de base de données Cloud SQL que vous avez créée. La commande définit une variable d'environnement pour Cloud Run afin qu'elle pointe vers la chaîne DATABASE_URL que vous avez créée à l'étape précédente.

Tester l'application

  1. Dans Cloud Shell, obtenez l'URL à laquelle Cloud Run diffuse le trafic :

    gcloud beta run services list --platform managed
    

    Vous pouvez également examiner le service Cloud Run dans Cloud Console.

  2. Assurez-vous que votre application Web accepte les requêtes HTTP en accédant à l'URL du service Cloud Run.

Cloud Run crée ou lance un conteneur lorsqu'une requête HTTP est envoyée au point de terminaison de diffusion et si un conteneur n'est pas déjà en cours d'exécution. Cela signifie que la diffusion de la requête qui entraîne le lancement d'un nouveau conteneur risque de prendre un peu plus de temps. Étant donné ce temps supplémentaire, tenez compte du nombre de requêtes simultanées que votre application peut prendre en charge et de ses exigences spécifiques en matière de mémoire.

Pour cette application, vous utilisez les paramètres de simultanéité par défaut, qui permettent à un service Cloud Run de diffuser 80 requêtes simultanément à partir d'un même conteneur.

Effectuer un nettoyage

Pour éviter que les ressources utilisées dans ce tutoriel soient facturées sur votre compte Google Cloud, procédez comme suit : Vous pouvez également supprimer les ressources créées dans Heroku pour ce tutoriel.

Supprimer le projet Google Cloud

  1. Dans Cloud Console, accédez à la page Gérer les ressources.

    Accéder à la page Gérer les ressources

  2. Dans la liste des projets, sélectionnez le projet que vous souhaitez supprimer, puis cliquez sur Supprimer .
  3. Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur Arrêter pour supprimer le projet.

Supprimer l'application Heroku

Pour supprimer l'exemple d'application que vous avez déployé sur Heroku et le module complémentaire PostgreSQL associé, exécutez la commande suivante :

heroku apps:destroy -a $APP_NAME

Étapes suivantes