Guide de démarrage rapide : déployer une application propre à un langage

Cette page vous explique comment :

  1. Créer une application Hello World
  2. Empaqueter l'application dans une image de conteneur à l'aide de Cloud Build
  3. Créer un cluster dans Google Kubernetes Engine (GKE)
  4. Déployer l'image de conteneur sur votre cluster.

L'exemple est proposé dans plusieurs langages, mais notez que vous pouvez en utiliser d'autres en plus de ceux présentés.

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 Build and Google Kubernetes Engine.

    Activer les API

  5. Installez et initialisez le SDK Cloud.
  6. kubectl permet de gérer Kubernetes, le système d'orchestration de clusters utilisé par GKE. Vous pouvez installer kubectl à l'aide de gcloud :
    gcloud components install kubectl

Écrire l'exemple d'application

Pour obtenir des instructions sur la création d'une application Hello World exécutée dans GKE, cliquez sur votre langage :

Go

  1. Créez un répertoire nommé helloworld-gke et modifiez les sous-répertoires comme suit :

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Créez un module nommé example.com/helloworld :

    go mod init example.com/helloworld
    
  3. Créez un fichier nommé helloworld.go et collez-y le code suivant :

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    	"os"
    )
    
    func main() {
    	http.HandleFunc("/", handler)
    
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    	}
    
    	log.Printf("Listening on localhost:%s", port)
    	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
    }
    
    func handler(w http.ResponseWriter, r *http.Request) {
    	log.Print("Hello world received a request.")
    	target := os.Getenv("TARGET")
    	if target == "" {
    		target = "World"
    	}
    	fmt.Fprintf(w, "Hello %s!\n", target)
    }
    

    Ce code crée un serveur Web qui écoute le port défini par la variable d'environnement PORT.

Votre application est terminée et prête à être empaquetée dans un conteneur Docker, puis importée dans Container Registry.

Node.js

  1. Créez un répertoire nommé helloworld-gke et modifiez les sous-répertoires comme suit :

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Créez un fichier package.json avec le contenu suivant :

    {
      "name": "gke-helloworld",
      "version": "1.0.0",
      "description": "GKE hello world sample in Node",
      "main": "index.js",
      "scripts": {
        "start": "node index.js"
      },
      "author": "",
      "license": "Apache-2.0",
      "dependencies": {
        "express": "^4.16.4"
      }
    }
    
  3. Dans le même répertoire, créez un fichier index.js, puis copiez-y les lignes suivantes :

    const express = require('express');
    const app = express();
    
    app.get('/', (req, res) => {
      console.log('Hello world received a request.');
    
      const target = process.env.TARGET || 'World';
      res.send(`Hello ${target}!`);
    });
    
    const port = process.env.PORT || 8080;
    app.listen(port, () => {
      console.log('Hello world listening on port', port);
    });
    

    Ce code crée un serveur Web qui écoute le port défini par la variable d'environnement PORT.

Votre application est terminée et prête à être empaquetée dans un conteneur Docker, puis importée dans Container Registry.

Python

  1. Créez un répertoire nommé helloworld-gke et modifiez les sous-répertoires comme suit :

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Créez un fichier nommé app.py et collez-y le code suivant :

    import os
    
    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        target = os.environ.get('TARGET', 'World')
        return 'Hello {}!\n'.format(target)
    
    if __name__ == "__main__":
        app.run(debug=True,host='0.0.0.0',port=int(os.environ.get('PORT', 8080)))
    

Java

Créez une application Spring Boot.

  1. Installez Java SE 8 ou une version ultérieure du JDK, et cURL. Java SE et cURL ne sont requis que pour créer le projet Web à l'étape suivante. Le fichier Docker, décrit ultérieurement, charge toutes les dépendances dans le conteneur.

  2. Depuis votre terminal, créez un projet Web vide :

    curl https://start.spring.io/starter.zip \
        -d dependencies=web \
        -d javaVersion=1.8 \
        -d bootVersion=2.1.3.RELEASE \
        -d name=helloworld \
        -d artifactId=helloworld \
        -d baseDir=helloworld-gke \
        -o helloworld-gke.zip
    unzip helloworld-gke.zip
    cd helloworld-gke
    

    Vous disposez maintenant d'un nouveau projet Spring Boot dans helloworld-gke.

  3. Dans le fichier src/main/java/com/example/helloworld/HelloworldApplication.java, mettez à jour la classe HelloworldApplication en ajoutant un champ @RestController pour gérer le mappage /.

    package com.example.helloworld;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    public class HelloworldApplication {
    
    	@Value("${TARGET:World}")
    	String target;
    
    	@RestController
    	class HelloworldController {
    		@GetMapping("/")
    		String hello() {
    			return "Hello " + target + "!";
    		}
    	}
    
    	public static void main(String[] args) {
    		SpringApplication.run(HelloworldApplication.class, args);
    	}
    }
    

    Ce code crée un serveur Web qui écoute le port défini par la variable d'environnement PORT.

Votre application est terminée et prête à être empaquetée dans un conteneur Docker, puis importée dans Container Registry.

C#

  1. Installez le SDK .NET Core 2.2. Le SDK .NET Core n'est requis que pour créer le projet Web à l'étape suivante. Le fichier Dockerfile, décrit ultérieurement, charge toutes les dépendances dans le conteneur.

  2. Depuis votre terminal, créez un projet Web vide :

    dotnet new web -o helloworld-gke
    
  3. Remplacez le répertoire par helloworld-gke.

  4. Mettez à jour la définition CreateWebHostBuilder dans Program.cs en spécifiant l'URL du port pour .UseUrls() afin de définir le port en service. L'exemple indique le port 8080, mais vous pouvez définir d'autres ports. Votre serveur doit écouter le port que vous spécifiez ici :

    // Copyright (c) 2019 Google LLC.
    //
    // Licensed under the Apache License, Version 2.0 (the "License"); you may not
    // use this file except in compliance with the License. You may obtain a copy of
    // the License at
    //
    // http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    // License for the specific language governing permissions and limitations under
    // the License.
    
    using System;
    using Microsoft.AspNetCore;
    using Microsoft.AspNetCore.Hosting;
    
    namespace HelloGKE
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateWebHostBuilder(args).Build().Run();
            }
    
            public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
                WebHost.CreateDefaultBuilder(args)
                    .UseStartup<Startup>()
                    .UsePortEnvironmentVariable();
        }
    
        static class ProgramExtensions
        {
            // Google Cloud Run sets the PORT environment variable to tell this
            // process which port to listen to.
            public static IWebHostBuilder UsePortEnvironmentVariable(
                this IWebHostBuilder builder)
            {
                string port = Environment.GetEnvironmentVariable("PORT");
                if (!string.IsNullOrEmpty(port))
                {
                    builder.UseUrls($"http://0.0.0.0:{port}");
                }
                return builder;
            }
        }
    }
    

Votre application est terminée et prête à être empaquetée dans un conteneur Docker, puis importée dans Container Registry.

PHP

  1. Créez un répertoire nommé helloworld-gke et modifiez les sous-répertoires comme suit :

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Créez un fichier nommé index.php et collez-y le code suivant :

    <?php
    $target = getenv('TARGET', true) ?: 'World';
    echo sprintf("Hello %s!", $target);
    

Votre application est terminée et prête à être empaquetée dans un conteneur Docker, puis importée dans Container Registry.

Ruby

  1. Créez un répertoire nommé helloworld-gke et modifiez les sous-répertoires comme suit :

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Créez un fichier nommé app.rb et collez-y le code suivant :

    require 'sinatra'
    
    set :bind, '0.0.0.0'
    set :port, ENV['PORT'] || '8080'
    
    get '/' do
      target = ENV['TARGET'] || 'World'
      "Hello #{target}!\n"
    end
    

    Ce code crée un serveur Web qui écoute le port défini par la variable d'environnement PORT.

  3. Créez un fichier nommé Gemfile et copiez-y les éléments suivants :

    source 'https://rubygems.org'
    
    gem 'sinatra'
    gem 'rack', '>= 2.0.6'
    

Conteneuriser l'application à l'aide de Cloud Build

  1. Pour conteneuriser l'exemple d'application, créez un fichier nommé Dockerfile dans le même répertoire que les fichiers sources, puis copiez le contenu suivant :

    Go

    # Use the offical Golang image to create a build artifact.
    # This is based on Debian and sets the GOPATH to /go.
    # https://hub.docker.com/_/golang
    FROM golang:1.12 as builder
    
    # Copy local code to the container image.
    WORKDIR /app
    COPY . .
    
    # Build the command inside the container.
    RUN CGO_ENABLED=0 GOOS=linux go build -v -o helloworld
    
    # Use a Docker multi-stage build to create a lean production image.
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM alpine
    RUN apk add --no-cache ca-certificates
    
    # Copy the binary to the production image from the builder stage.
    COPY --from=builder /app/helloworld /helloworld
    
    # Run the web service on container startup.
    CMD ["/helloworld"]
    

    Node.js

    # Use the official lightweight Node.js 10 image.
    # https://hub.docker.com/_/node
    FROM node:10-slim
    
    # Create and change to the app directory.
    WORKDIR /usr/src/app
    
    # Copy application dependency manifests to the container image.
    # A wildcard is used to ensure both package.json AND package-lock.json are copied.
    # Copying this separately prevents re-running npm install on every code change.
    COPY package*.json ./
    
    # Install production dependencies.
    RUN npm install --only=production
    
    # Copy local code to the container image.
    COPY . ./
    
    # Run the web service on container startup.
    CMD [ "npm", "start" ]
    

    Ajoutez un autre fichier .dockerignore pour vous assurer que les fichiers locaux n'affectent pas le processus de création du conteneur :

    Dockerfile
    README.md
    node_modules
    npm-debug.log
    

    Python

    # Use the official lightweight Python image.
    # https://hub.docker.com/_/python
    FROM python:3.7-slim
    
    # Copy local code to the container image.
    ENV APP_HOME /app
    WORKDIR $APP_HOME
    COPY . ./
    
    # Install production dependencies.
    RUN pip install Flask gunicorn
    
    # Run the web service on container startup. Here we use the gunicorn
    # webserver, with one worker process and 8 threads.
    # For environments with multiple CPU cores, increase the number of workers
    # to be equal to the cores available.
    CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:app
    

    Ajoutez un fichier .dockerignore pour vous assurer que les fichiers locaux n'affectent pas le processus de création du conteneur :

    Dockerfile
    README.md
    *.pyc
    *.pyo
    *.pyd
    __pycache__
    

    Java

    # Use the official maven/Java 8 image to create a build artifact.
    # https://hub.docker.com/_/maven
    FROM maven:3.5-jdk-8-alpine as builder
    
    # Copy local code to the container image.
    WORKDIR /app
    COPY pom.xml ./
    COPY src ./src/
    
    # Build a release artifact.
    RUN mvn package -DskipTests
    
    # Use AdoptOpenJDK for base image.
    # It's important to use OpenJDK 8u191 or above that has container support enabled.
    # https://hub.docker.com/r/adoptopenjdk/openjdk8
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM adoptopenjdk/openjdk8:jdk8u202-b08-alpine-slim
    
    # Copy the jar to the production image from the builder stage.
    COPY --from=builder /app/target/helloworld-*.jar /helloworld.jar
    
    # Run the web service on container startup.
    CMD ["java","-Djava.security.egd=file:/dev/./urandom","-Dserver.port=${PORT}","-jar","/helloworld.jar"]
    

    C#

    # Use Microsoft's official lightweight .NET images.
    # https://hub.docker.com/r/microsoft/dotnet
    
    FROM mcr.microsoft.com/dotnet/core/sdk:2.2-alpine AS build
    WORKDIR /app
    
    # Install production dependencies.
    # Copy csproj and restore as distinct layers.
    COPY *.csproj ./
    RUN dotnet restore
    
    # Copy local code to the container image.
    COPY . ./
    
    # Build a release artifact.
    RUN dotnet publish -c Release -o out
    
    # Run the web service on container startup in a lean production image.
    FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-alpine
    WORKDIR /app
    
    COPY --from=build /app/out ./
    CMD ["dotnet", "HelloGKE.dll"]
    

    Ajoutez un fichier .dockerignore pour vous assurer que les fichiers locaux n'affectent pas le processus de création du conteneur :

    Dockerfile
    README.md
    **/obj/
    **/bin/
    

    PHP

    # Use the official PHP 7.2 image.
    # https://hub.docker.com/_/php
    FROM php:7.2-apache
    
    # Copy local code to the container image.
    COPY index.php /var/www/html/
    
    # Use port 8080 in Apache configuration files.
    RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf
    
    # Configure PHP for development.
    # Switch to the production php.ini for production operations.
    # RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
    # https://hub.docker.com/_/php#configuration
    RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
    

    Ajoutez un fichier .dockerignore pour vous assurer que les fichiers locaux n'affectent pas le processus de création du conteneur :

    Dockerfile
    README.md
    vendor
    

    Ruby

    # Use the official lightweight Ruby image.
    # https://hub.docker.com/_/ruby
    FROM ruby:2.5-slim
    
    # Install production dependencies.
    WORKDIR /usr/src/app
    COPY Gemfile ./
    RUN bundle install
    
    # Copy local code to the container image.
    COPY . ./
    
    # Run the web service on container startup.
    CMD ["ruby", "./app.rb"]
    

  2. Obtenez votre ID de projet Google Cloud :

    gcloud config get-value project
    

    Créez votre image de conteneur à l'aide de Cloud Build. Ce processus est semblable à l'exécution de docker build et docker push, mais il est effectué sur Google Cloud. Remplacez project-id par votre ID Google Cloud :

    gcloud builds submit --tag gcr.io/project-id/helloworld-gke .
    

    L'image est stockée dans Container Registry.

Créer un cluster Kubernetes Engine

Un cluster GKE est un ensemble géré de machines virtuelles Compute Engine fonctionnant comme un cluster GKE unique. Ce tutoriel utilise un nœud unique.

  1. Créez le cluster. Remplacez your-gcp-zone par la zone Google Cloud dans laquelle vous souhaitez héberger votre cluster. Pour obtenir la liste complète, consultez la section Zones géographiques et régions.

    gcloud container clusters create helloworld-gke \
       --num-nodes 1 \
       --enable-basic-auth \
       --issue-client-certificate \
       --zone your-gcp-zone
    
  2. Vérifiez que vous avez accès au cluster. La commande suivante répertorie les nœuds de votre cluster de conteneurs qui sont opérationnels et indique que vous y avez accès.

    kubectl get nodes
    

    Si vous rencontrez des erreurs, consultez le guide de dépannage de Kubernetes.

Déployer sur GKE

Pour déployer votre application sur le cluster GKE que vous avez créé, vous avez besoin de deux objets Kubernetes.

  1. Un déploiement pour définir votre application
  2. Un service pour définir comment accéder à votre application

Déployer une application

L'application dispose d'une interface qui gère les requêtes Web. Vous définissez les ressources de cluster nécessaires à l'exécution de l'interface dans un nouveau fichier appelé deployment.yaml. Ces ressources sont décrites comme un déploiement. Vous utilisez les déploiements pour créer et mettre à jour un ensemble d'instances dupliquées (ReplicaSet) et ses pods associés.

  1. Créez le fichier deployment.yaml dans le même répertoire que vos autres fichiers et copiez le contenu suivant, en remplaçant $GCLOUD_PROJECT par votre ID de projet Google Cloud :

    # This file configures the hello-world app which serves public web traffic.
    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      name: helloworld-gke
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: hello
      template:
        metadata:
          labels:
            app: hello
        spec:
          containers:
          - name: hello-app
            # Replace $GCLOUD_PROJECT with your project ID
            image: gcr.io/$GCLOUD_PROJECT/helloworld-gke:latest
            # This app listens on port 8080 for web traffic by default.
            ports:
            - containerPort: 8080
            env:
              - name: PORT
                value: "8080"
    
  2. Déployez la ressource sur le cluster :

    kubectl apply -f deployment.yaml
    
  3. Suivez l'état du déploiement :

    kubectl get deployments
    

    Le déploiement est terminé lorsque tous les déploiements AVAILABLE affichent l'état READY.

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    hello-deployment   1/1     1            1           20s
    

    Si le déploiement rencontre une erreur, exécutez à nouveau kubectl apply -f deployment.yaml pour mettre à jour le déploiement en cas de modification.

  4. Une fois le déploiement terminé, les pods créés par le déploiement s'affichent :

    kubectl get pods
    

Déployer un service

Les services fournissent un point d'accès unique à un ensemble de pods. Bien qu'il soit possible d'accéder à un pod unique, les pods sont éphémères et ne peuvent être accessibles de manière fiable qu'à l'aide d'une adresse de service. Dans l'application Hello World, le service "hello" définit un équilibreur de charge pour accéder aux pods hello-app à partir d'une adresse IP unique. Ce service est défini dans le fichier service.yaml.

  1. Créez le fichier service.yaml dans le même répertoire que vos autres fichiers sources en incluant le contenu suivant :

    # The hello service provides a load-balancing proxy over the hello-app
    # pods. By specifying the type as a 'LoadBalancer', Kubernetes Engine will
    # create an external HTTP load balancer.
    apiVersion: v1
    kind: Service
    metadata:
      name: hello
    spec:
      type: LoadBalancer
      selector:
        app: hello
      ports:
      - port: 80
        targetPort: 8080
    

    Les pods sont définis séparément du service qui utilise les pods. Kubernetes utilise des libellés pour sélectionner les pods auxquels accède un service. Les libellés vous permettent d'utiliser un service unique pour interagir avec les pods de différents ensembles d'instances dupliquées. Vous pouvez également faire pointer plusieurs services vers un pod unique.

  2. Créez le service Hello World :

    kubectl apply -f service.yaml
    
  3. Obtenez l'adresse IP externe du service :

    kubectl get services
    

    L'allocation de l'adresse IP peut prendre jusqu'à 60 secondes. L'adresse IP externe est répertoriée sous la colonne EXTERNAL-IP du service hello.

    NAME         TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
    hello        LoadBalancer   10.22.222.222   35.111.111.11   80:32341/TCP   1m
    kubernetes   ClusterIP      10.22.222.1     <none>          443/TCP        20m
    

Afficher une application déployée

Vous avez déployé toutes les ressources nécessaires à l'exécution de l'application Hello World sur GKE. Utilisez l'adresse IP externe de l'étape précédente pour charger l'application dans votre navigateur Web et afficher votre application en cours d'exécution.

# Example cURL call to your running application on GKE (external IP address of service)
curl 35.111.111.11
Hello World!

Effectuer un nettoyage

Afin d'éviter que des frais ne soient facturés sur votre compte Google Cloud pour les ressources utilisées dans ce guide de démarrage rapide, procédez comme suit :

Les instances Compute Engine exécutées dans votre cluster vous sont facturées, ainsi que l'image de conteneur dans Container Registry.

Supprimer le projet

La suppression de votre projet Cloud arrête la facturation de toutes les ressources utilisées dans ce projet.

  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 le cluster et le conteneur

Si vous souhaitez conserver le projet et ne supprimer que les ressources que vous avez utilisées dans ce tutoriel, supprimez le cluster et l'image.

Pour supprimer un cluster à l'aide de l'outil de ligne de commande gcloud, exécutez la commande suivante :

gcloud container clusters delete helloworld-gke

Pour supprimer une image de l'un de vos dépôts Container Registry, exécutez la commande suivante :

gcloud container images delete gcr.io/project-id/helloworld-gke

Étapes suivantes

Pour plus d'informations sur Kubernetes, consultez les ressources suivantes :

Pour plus d'informations sur le déploiement sur GKE, consultez les ressources suivantes :

Pour plus d'informations sur le déploiement sur GKE directement à partir de votre IDE à l'aide de Cloud Code, consultez les ressources suivantes :