Compilation de conteneurs plus simples

Cette page explique comment créer des images Docker plus simples.

Compilation de conteneurs plus simples

Lorsque vous intégrez une application dans un conteneur, les fichiers inutiles au moment de l'exécution, tels que les dépendances de temps de compilation et les fichiers intermédiaires, peuvent être inclus par inadvertance dans l'image du conteneur. Ces fichiers inutiles peuvent augmenter la taille de l'image du conteneur, et donc augmenter le temps et les coûts associés au déplacement de l'image entre le registre Docker et l'environnement d'exécution du conteneur.

Pour vous aider à réduire la taille de votre image de conteneur, séparez la compilation de l'application, ainsi que les outils nécessaires pour la compiler, de l'ensemble du conteneur d'exécution.

Cloud Build fournit une série de conteneurs Docker avec des outils de développement courants, tels que Git, Docker et l'interface de ligne de commande gcloud. Utilisez ces outils pour définir un fichier de configuration compilation comportant une étape destinée à créer l'application et une autre à assembler son environnement d'exécution final.

Par exemple, si vous compilez une application Java qui nécessite des fichiers, tels que le code source, les bibliothèques d'applications, les systèmes de compilation, les dépendances du système de compilation et le JDK, il se peut que le fichier Docker ressemble à ce qui suit :

FROM java:8

COPY . workdir/

WORKDIR workdir

RUN GRADLE_USER_HOME=cache ./gradlew buildDeb -x test

RUN dpkg -i ./gate-web/build/distributions/*.deb

CMD ["/opt/gate/bin/gate"]

Dans l'exemple ci-dessus, Gradle, qui est utilisé pour créer le package, télécharge un grand nombre de bibliothèques afin de fonctionner. Ces bibliothèques sont essentielles à la compilation du package, mais ne sont pas nécessaires au moment de l'exécution. Toutes les dépendances d'exécution sont regroupées dans le package.

Chaque commande du fichier Dockerfile crée une nouvelle couche dans le conteneur. Si des données sont générées dans cette couche et ne sont pas supprimées dans la même commande, cet espace ne peut pas être récupéré. Dans ce cas, Gradle télécharge des centaines de mégaoctets de bibliothèques dans le répertoire cache afin de procéder à la compilation, sans pour autant supprimer les bibliothèques.

Une méthode de compilation plus efficace consiste à utiliser Cloud Build pour séparer la compilation de l'application de celle de sa couche d'exécution.

L'exemple suivant sépare l'étape de compilation de l'application Java de l'étape d'assemblage du conteneur d'exécution :

YAML

  1. Compiler l'application : dans cloudbuild.yaml, ajoutez une étape permettant de compiler l'application.

    Le code suivant permet d'ajouter une étape qui compile l'image java:8 contenant le code Java.

    steps:
    
    - name: 'java:8'
      env: ['GRADLE_USER_HOME=cache']
      entrypoint: 'bash'
      args: ['-c', './gradlew gate-web:installDist -x test']
    
    
  2. Assembler le conteneur d'exécution : dans cloudbuild.yaml, ajoutez une étape permettant d'assembler le conteneur d'exécution.

    Le code suivant ajoute une étape nommée gcr.io/cloud-builders/docker qui assemble le conteneur d'exécution. Il définit le conteneur d'exécution dans un fichier distinct nommé Dockerfile.slim.

    L'exemple utilise la couche de base Alpine Linux openjdk:8u111-jre-alpine, qui est incroyablement légère. Il inclut également le JRE, au lieu du JDK plus volumineux qui a été nécessaire pour créer l'application.

    cloudbuild.yaml
    
    steps:
    - name: 'java:8'
      env: ['GRADLE_USER_HOME=cache']
      entrypoint: 'bash'
      args: ['-c',
             './gradlew gate-web:installDist -x test']
    
    - name: 'gcr.io/cloud-builders/docker'
      args: ['build',
             '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA',
             '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:latest',
             '-f', 'Dockerfile.slim',
             '.'
      ]
    
    
    Dockerfile.slim
    
    FROM openjdk:8-jre-alpine
    
    COPY ./gate-web/build/install/gate /opt/gate
    
    CMD ["/opt/gate/bin/gate"]
    
  3. Créer les images Docker : dans cloudbuild.yaml, ajoutez une étape permettant de créer les images.
    steps:
    - name: 'java:8'
      env: ['GRADLE_USER_HOME=cache']
      entrypoint: 'bash'
      args: ['-c', './gradlew gate-web:installDist -x test']
    - name: 'gcr.io/cloud-builders/docker'
      args: ['build',
             '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA',
             '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:latest',
             '-f', 'Dockerfile.slim', '.']
    images:
    - 'gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA'
    - 'gcr.io/$PROJECT_ID/$REPO_NAME:latest'
    

JSON

  1. Compiler l'application : dans cloudbuild.json, ajoutez une étape permettant de compiler l'application.

    Le code suivant ajoute une étape nommée java:8 qui compile le code Java.

    {
        "steps": [
        {
            "name": "java:8",
            "env": [
                "GRADLE_USER_HOME=cache"
            ],
            "entrypoint": "bash",
            "args": [
                "-c",
                "./gradlew gate-web:installDist -x test"
            ]
        },
    }
    
  2. Assembler le conteneur d'exécution : dans cloudbuild.json, ajoutez une étape permettant d'assembler le conteneur d'exécution.

    Le code suivant ajoute une étape nommée gcr.io/cloud-builders/docker qui assemble le conteneur d'exécution. Il définit le conteneur d'exécution dans un fichier distinct nommé Dockerfile.slim.

    L'exemple utilise la couche de base Alpine Linux openjdk:8u111-jre-alpine, qui est incroyablement légère. Il inclut également le JRE, au lieu du JDK plus volumineux qui a été nécessaire pour créer l'application.

    cloudbuild.json:
    
    {
        "steps": [
        {
            "name": "java:8",
            "env": [
                "GRADLE_USER_HOME=cache"
            ],
            "entrypoint": "bash",
            "args": [
                "-c",
                "./gradlew gate-web:installDist -x test"
            ]
        },
        {
            "name": "gcr.io/cloud-builders/docker",
            "args": [
                "build",
                "-t",
                "gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA",
                "-t",
                "gcr.io/$PROJECT_ID/$REPO_NAME:latest",
                "-f",
                "Dockerfile.slim",
                "."
            ]
        }
        ],
    }
    
    Dockerfile.slim:
    
    FROM openjdk:8u111-jre-alpine
    
    COPY ./gate-web/build/install/gate /opt/gate
    
    CMD ["/opt/gate/bin/gate"]
    
  3. Créer les images Docker : dans cloudbuild.json, ajoutez une étape permettant de créer les images.
    {
        "steps": [
        {
            "name": "java:8",
            "env": [
                "GRADLE_USER_HOME=cache"
            ],
            "entrypoint": "bash",
            "args": [
                "-c",
                "./gradlew gate-web:installDist -x test"
            ]
        },
        {
            "name": "gcr.io/cloud-builders/docker",
            "args": [
                "build",
                "-t",
                "gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA",
                "-t",
                "gcr.io/$PROJECT_ID/$REPO_NAME:latest",
                "-f",
                "Dockerfile.slim",
                "."
            ]
        }
        ],
        "images": [
            "gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA",
            "gcr.io/$PROJECT_ID/$REPO_NAME:latest"
        ]
    }