Créer un service Cloud Run avec un side-car

1. Présentation

Introduction

Dans cet atelier de programmation, vous apprendrez à déployer un service Cloud Run qui utilise plusieurs conteneurs. Vous allez créer une application node.js qui servira de conteneur d'entrée Cloud Run et une application Node.js supplémentaire qui servira de side-car.

Présentation technique

Lorsque vous utilisez plusieurs conteneurs dans une instance Cloud Run, un conteneur est utilisé comme conteneur principal pour l'entrée Web. Le ou les conteneurs supplémentaires sont appelés side-cars.

Il existe deux façons pour plusieurs conteneurs de communiquer entre eux:

  1. Les conteneurs partagent l'interface réseau localhost afin qu'ils puissent écouter un port (par exemple, localhost:port.
  2. Vous pouvez également utiliser des volumes en mémoire et les installer sur les conteneurs pour partager des fichiers.

Cas d'utilisation

Étant donné que tous les conteneurs de l'instance Cloud Run partagent l'interface réseau de l'hôte local, vous pouvez utiliser un side-car devant votre conteneur principal pour transmettre les requêtes par proxy. Ces proxys peuvent fournir une couche d'abstraction supplémentaire pour un flux plus efficace du trafic vers l'application entre le client et les serveurs en interceptant les requêtes et en les transmettant au point de terminaison approprié. Par exemple, vous pouvez utiliser l'image Nginx officielle de DockerHub (comme indiqué ici).

Étant donné que plusieurs conteneurs peuvent communiquer en partageant des fichiers via des volumes partagés, vous ajoutez diverses applications side-car à votre service. Par exemple, vous pouvez instrumenter votre service Cloud Run afin d'utiliser des agents personnalisés tels qu'OpenTelemetry pour exporter des journaux, des métriques et des traces (exemple OpenTelemetry). Un autre exemple consiste à utiliser une connexion side-car à une base de données PostgreSQL Cloud Spanner (exemple de Postgres Cloud Spanner).

Exemples présentés dans cet atelier de programmation

Dans cet atelier de programmation, vous commencerez par déployer un service Cloud Run dans lequel son conteneur d'entrée communique avec un side-car via un port localhost. Vous mettrez ensuite à jour le conteneur d'entrée et le side-car pour partager un fichier via un montage de volume.

Points abordés

  • Créer un conteneur qui utilise un side-car
  • Comment un conteneur d'entrée peut communiquer avec un side-car à l'aide de localhost
  • Comment un conteneur d'entrée et un side-car peuvent partager un fichier via un volume installé

2. Préparation

Prérequis

Activer Cloud Shell

  1. Dans Cloud Console, cliquez sur Activer Cloud Shell d1264ca30785e435.png.

cb81e7c8e34bc8d.png

Si vous démarrez Cloud Shell pour la première fois, un écran intermédiaire vous explique de quoi il s'agit. Si un écran intermédiaire s'est affiché, cliquez sur Continuer.

d95252b003979716.png

Le provisionnement et la connexion à Cloud Shell ne devraient pas prendre plus de quelques minutes.

7833d5e1c5d18f54.png

Cette machine virtuelle contient tous les outils de développement nécessaires. Elle comprend un répertoire d'accueil persistant de 5 Go et s'exécute dans Google Cloud, ce qui améliore considérablement les performances du réseau et l'authentification. Une grande partie, voire la totalité, de votre travail dans cet atelier de programmation peut être effectué dans un navigateur.

Une fois connecté à Cloud Shell, vous êtes authentifié et le projet est défini sur votre ID de projet.

  1. Exécutez la commande suivante dans Cloud Shell pour vérifier que vous êtes authentifié :
gcloud auth list

Résultat de la commande

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Exécutez la commande suivante dans Cloud Shell pour vérifier que la commande gcloud connaît votre projet:
gcloud config list project

Résultat de la commande

[core]
project = <PROJECT_ID>

Si vous obtenez un résultat différent, exécutez cette commande :

gcloud config set project <PROJECT_ID>

Résultat de la commande

Updated property [core/project].

3. Créer l'application d'entrée

Définir des variables d'environnement

Dans cet atelier de programmation, vous allez créer quelques variables d'environnement pour améliorer la lisibilité des commandes gcloud utilisées.

REGION=<YOUR-REGION>
PROJECT_ID=<YOUR-PROJECT-ID>

SERVICE_NAME=sidecar-codelab
REPO_NAME=sidecar-codelab

Créer un dépôt ArtifactRegistry pour stocker vos images de conteneurs

Pour cet atelier de programmation, vous pouvez créer un dépôt dans Artifact Registry pour stocker vos images de conteneurs.

gcloud artifacts repositories create $REPO_NAME --repository-format=docker \
--location=$REGION --description="sidecar codelab"

Ensuite, créez un fichier package.json avec le contenu suivant:

{
  "name": "sidecar-codelab",
  "version": "1.0.0",
  "private": true,
  "description": "demonstrates how to use sidecars in cloud run",
  "main": "index.js",
  "author": "Google LLC",
  "license": "Apache-2.0",
  "scripts": {
    "start": "node ingress.js"
  },
  "dependencies": {
    "axios": "^1.6.2",
    "express": "^4.18.2"
  }
}

Créez maintenant un fichier nommé ingress.js avec le contenu suivant:

const express = require('express');
const app = express();
const axios = require("axios");

app.get('/', async (req, res) => {

    let response = await axios.get("http://localhost:5000");

    res.send("The sidecar says: " + response.data);
});

const port = parseInt(process.env.PORT) || 8080;
app.listen(port, () => {
    console.log(`Ingress container listening on port ${port}`);
});

Créer un fichier Docker pour le conteneur d'entrée

FROM node:20.10.0-slim
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install --production

# Copy local code to the container image.
COPY . .

# Run the web service on container startup.
ENV PORT=8080
CMD [ "npm", "start" ]

Et créez un fichier ".dockerignore" pour le conteneur d'entrée.

# Exclude locally installed dependencies
node_modules/

# Exclude "build-time" ignore files.
.dockerignore
.gcloudignore

# Exclude git history and configuration.
.gitignore

Vous pouvez maintenant créer l'image pour votre conteneur d'entrée en exécutant la commande suivante:

gcloud builds submit --tag $REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/ingress:latest

4. Créer l'application side-car

Dans cette section, vous allez créer une deuxième application Node.js qui sera utilisée comme side-car dans le service Cloud Run.

Accédez au répertoire side-car.

cd ../sidecar

Créez un fichier package.json avec le contenu suivant:

{
  "name": "sidecar-codelab",
  "version": "1.0.0",
  "private": true,
  "description": "demonstrates how to use sidecars in cloud run",
  "main": "index.js",
  "author": "Google LLC",
  "license": "Apache-2.0",
  "scripts": {
    "start": "node sidecar.js"
  },
  "dependencies": {
    "axios": "^1.6.2",
    "express": "^4.18.2"
  }
}

Créez maintenant un fichier nommé sidecar.js avec le contenu suivant:

const express = require('express');
const app = express();

app.get('/', async (req, res) => {
    res.send("Hello ingress container! I'm the sidecar.");
});

const port = parseInt(process.env.PORT || 5000);
app.listen(port, () => {
    console.log(`Sidecar container listening on port ${port}`);
});

Créer un Dockerfile pour le conteneur side-car

FROM node:20.10.0-slim
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install --production

# Copy local code to the container image.
COPY . .

# Run the web service on container startup.
ENV PORT=5000
CMD [ "npm", "start" ]

Et créez un fichier ".dockerignore" pour le conteneur side-car.

# Exclude locally installed dependencies
node_modules/

# Exclude "build-time" ignore files.
.dockerignore
.gcloudignore

# Exclude git history and configuration.
.gitignore

Vous pouvez maintenant créer l'image pour votre conteneur d'entrée en exécutant la commande suivante:

gcloud builds submit --tag $REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/sidecar:latest

Déployer le service Cloud Run

Vous allez déployer le service Cloud Run à l'aide d'un fichier yaml.

Accédez au répertoire parent.

cd ..

Créez un fichier nommé sidecar-codelab.yaml avec le contenu suivant :

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  annotations:
  name: sidecar-codelab
  labels:
    cloud.googleapis.com/location: "<YOUR_REGION>"
spec:
  template:
    spec:
      containers:
        - image: "<YOUR_REGION>-docker.pkg.dev/<YOUR_PROJECT_ID>/sidecar-codelab/ingress:latest"
          ports:
            - containerPort: 8080
        - image: "<YOUR_REGION>-docker.pkg.dev/<YOUR_PROJECT_ID>/sidecar-codelab/sidecar:latest"
          env:
            - name: PORT
              value: "5000"

Déployez ensuite le service à l'aide de la commande suivante. Vous devez utiliser la version bêta de gcloud, car les installations de volume sont en version Preview publique.

gcloud beta run services replace sidecar-codelab.yaml

Une fois le service déployé, enregistrez l'URL du service dans une variable d'environnement.

SERVICE_URL=$(gcloud run services describe $SERVICE_NAME --platform managed --region $REGION --format 'value(status.url)') 

5. Appeler le service Cloud Run

Vous pouvez maintenant appeler votre service en fournissant votre jeton d'identité.

curl -X GET -H "Authorization: Bearer $(gcloud auth print-identity-token)" ${SERVICE_URL}

Vos résultats doivent ressembler à l'exemple ci-dessous:

The sidecar says: Hello ingress container! I'm the sidecar.

6. Partager un fichier via un montage de volume

Dans cette section, vous allez mettre à jour les conteneurs pour qu'ils partagent un fichier via un montage de volume. Dans cet exemple, le conteneur Ingress écrira dans un fichier sur un volume partagé. Le side-car lit le fichier et renvoie son contenu au conteneur d'entrée.

Commencez par mettre à jour le code du conteneur d'entrée. Accédez au répertoire d'entrée.

cd ../ingress

Remplacez ensuite le contenu du fichier ingress.js par ce qui suit:

const express = require('express');
const app = express();
const fs = require('fs');
const axios = require("axios");

const filename = "test.txt"

let path = "/my-volume-mount";
app.use(path, express.static(path));

try {
    fs.writeFileSync(`${path}/${filename}`, "The ingress container created this file.");
} catch (err) {
    console.error(err);
}

app.get('/', async (req, res) => {

    let response = await axios.get("http://localhost:5000");

    res.send("The sidecar says: " + response.data);
});

const port = parseInt(process.env.PORT) || 8080;
app.listen(port, () => {
    console.log(`Ingress container listening on port ${port}`);
});

Créez ensuite la nouvelle image pour votre conteneur d'entrée en exécutant la commande suivante:

gcloud builds submit --tag $REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/ingress:latest

Accédez maintenant au répertoire side-car:

cd ../sidecar

Mettez à jour sidecar.js avec le contenu suivant:

const express = require('express');
const app = express();
const fs = require('fs');

const filename = "test.txt"

let path = "/my-volume-mount";
app.use(path, express.static(path));

async function readFile() {
    try {
        return await fs.readFileSync(`${path}/${filename}`, { encoding: 'utf8' });
    } catch (err) {
        console.log(err);
    }
}

app.get('/', async (req, res) => {
    let contents = await readFile();
    res.send(contents);
});

const port = parseInt(process.env.PORT || 5000);
app.listen(port, () => {
    console.log(`Sidecar container listening on port ${port}`);
});

Créez ensuite la nouvelle image pour votre conteneur side-car en exécutant la commande suivante:

gcloud builds submit --tag $REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/sidecar:latest

Modifiez le sidecar-codelab.yaml avec le code suivant pour partager un volume:

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  annotations:
  name: sidecar-codelab
  labels:
    cloud.googleapis.com/location: "<YOUR_REGION>"
spec:
  template:
    spec:
      containers:
        - image: "<YOUR_REGION>-docker.pkg.dev/<YOUR_PROJECT_ID>/sidecar-codelab/ingress:latest"
          ports:
            - containerPort: 8080
          volumeMounts:
            - mountPath: /my-volume-mount
              name: in-memory-1
        - image: "<YOUR_REGION>-docker.pkg.dev/<YOUR_PROJECT_ID>/sidecar-codelab/sidecar:latest"
          env:
            - name: PORT
              value: "5000"
          volumeMounts:
            - mountPath: /my-volume-mount
              name: in-memory-1
      volumes:
        - emptyDir:
            medium: Memory
          name: in-memory-1

Déployer le fichier sidecar-codelab.yaml mis à jour

gcloud beta run services replace sidecar-codelab.yaml

Vous pouvez maintenant appeler votre service en fournissant votre jeton d'identité.

curl -X GET -H "Authorization: Bearer $(gcloud auth print-identity-token)" ${SERVICE_URL}

Vos résultats doivent ressembler à l'exemple ci-dessous:

The sidecar says: the ingress container created this file.

7. Félicitations !

Félicitations ! Vous avez terminé cet atelier de programmation.

Nous vous recommandons de consulter la documentation sur Cloud Run, en particulier sur le déploiement des multiconteneurs et l'utilisation d'installations de volumes en mémoire.

Points abordés

  • Créer un conteneur qui utilise un side-car
  • Comment un conteneur d'entrée peut communiquer avec un side-car à l'aide de localhost
  • Comment un conteneur d'entrée et un side-car peuvent partager un volume installé

8. Effectuer un nettoyage

Pour éviter des frais accidentels (par exemple, si cette fonction Cloud est invoquée plus de fois que l'allocation mensuelle des appels Cloud Run dans le niveau sans frais), vous pouvez supprimer le service Cloud Run ou le projet créé à l'étape 2.

Pour supprimer la fonction Cloud, accédez à la console Cloud de la fonction Cloud à l'adresse https://console.cloud.google.com/run/ et supprimez le service sidecar-codelab (ou $SERVICE_NAME au cas où vous auriez utilisé un autre nom).

Si vous choisissez de supprimer l'intégralité du projet, vous pouvez accéder à https://console.cloud.google.com/cloud-resource-manager, sélectionner le projet que vous avez créé à l'étape 2, puis cliquer sur "Supprimer". Si vous supprimez le projet, vous devrez le modifier dans Cloud SDK. Vous pouvez afficher la liste de tous les projets disponibles en exécutant gcloud projects list.