Dockérisation d’une application de démarrage à ressort

Dockerizing une application de démarrage de printemps

1. Vue d'ensemble

Dans cet article, nous allons nous concentrer sur la façon d'ancrer unSpring Boot Application pour l'exécuter dans un environnement isolé, a.k.a. container.

En outre, nous montrerons comment créer une composition de conteneurs, qui dépendent les uns des autres et sont liés les uns aux autres dans un réseau privé virtuel. Nous verrons également comment ils peuvent être gérés avec des commandes uniques.

Commençons par créer une image de base légère et compatible Java, exécutanthttps://hub.docker.com//alpine/[_Alpine Linux].

2. Image de base commune

Nous allons utiliser le propre format de fichier de construction deDocker’s: aDockerfile.

UnDockerfile est en principe un fichier batch par ligne, contenant des commandes pour construire une image. Il n’est pas absolument nécessaire de placer ces commandes dans un fichier, car nous pouvons également les transmettre à la ligne de commande - un fichier est tout simplement plus pratique.

Alors, écrivons nos premiersDockerfile:

FROM alpine:edge
MAINTAINER example.com
RUN apk add --no-cache openjdk8
COPY files/UnlimitedJCEPolicyJDK8/* \
  /usr/lib/jvm/java-1.8-openjdk/jre/lib/security/
  • FROM: Le mot-cléFROM, dit àDocker d'utiliser une image donnée avec sa balise comme base de construction. Si cette image n'est pas dans la bibliothèque locale, une recherche en ligne surDockerHub ou sur tout autre registre distant configuré est effectuée

  • MAINTAINER: UnMAINTAINER est généralement une adresse e-mail, identifiant l'auteur d'une image

  • RUN: avec la commandeRUN, nous exécutons une ligne de commande shell dans le système cible. Ici, nous utilisons le gestionnaire de paquetsAlpine Linux’sapk pour installer lesJava 8 OpenJDK

  • COPY: La dernière commande indique àDocker àCOPY quelques fichiers du système de fichiers local, en particulier un sous-dossier vers le répertoire de construction, dans l'image dans un chemin donné

REQUIREMENTS: Pour exécuter le didacticiel avec succès, vous devez télécharger lesJava Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files depuisOracle. Extrayez simplement l'archive téléchargée dans un dossier local nommé‘files'.

Pour finalement construire l'image et la stocker dans la bibliothèque locale, nous devons exécuter:

docker build --tag=alpine-java:base --rm=true .

NOTICE: L'option–tag donnera son nom à l'image et–rm=true supprimera les images intermédiaires une fois qu'elle a été construite avec succès. Le dernier caractère de cette commande est un point, faisant office d'argument de répertoire de construction.

3. Dockerize une application Spring Boot autonome

Comme exemple d'application que nous pouvons dockeriser, nous prendrons lesspring-cloud-config/server desspring cloud configuration tutorial. Comme étape de préparation, nous devons assembler un fichier jar exécutable et le copier dans notre répertoire de constructionDocker:

tutorials $> cd spring-cloud-config/server
server    $> mvn package spring-boot:repackage
server    $> cp target/server-0.0.1-SNAPSHOT.jar \
               ../../spring-boot-docker/files/config-server.jar
server    $> cd ../../spring-boot-docker

Nous allons maintenant créer unDockerfile nomméDockerfile.server avec le contenu suivant:

FROM alpine-java:base
MAINTAINER example.com
COPY files/spring-cloud-config-server.jar /opt/spring-cloud/lib/
COPY files/spring-cloud-config-server-entrypoint.sh /opt/spring-cloud/bin/
ENV SPRING_APPLICATION_JSON= \
  '{"spring": {"cloud": {"config": {"server": \
  {"git": {"uri": "/var/lib/spring-cloud/config-repo", \
  "clone-on-start": true}}}}}}'
ENTRYPOINT ["/usr/bin/java"]
CMD ["-jar", "/opt/spring-cloud/lib/spring-cloud-config-server.jar"]
VOLUME /var/lib/spring-cloud/config-repo
EXPOSE 8888
  • FROM: Comme base de notre image, nous prendrons lesJava-enabledAlpine Linux, créés dans la section précédente

  • COPY: Nous laissonsDocker copier notre fichier jar dans l'image

  • ENV: Cette commande nous permet de définir certaines variables d'environnement, qui seront respectées par l'application exécutée dans le conteneur. Ici, nous définissons unSpring Boot Application configuration personnalisé, à remettre à l'exécutable jar plus tard

  • ENTRYPOINT/CMD: This will be the executable to start when the container is booting. Nous devons les définir commeJSON-Array, car nous utiliserons unENTRYPOINT en combinaison avec unCMD pour certains arguments d'application

  • VOLUME: Comme notre conteneur fonctionnera dans un environnement isolé, sans accès direct au réseau, nous devons définir un espace réservé de point de montage pour notre référentiel de configuration

  • EXPOSE: Ici, nous indiquons àDocker, sur quel port notre application est listée. Ce port sera publié sur l'hôte lors du démarrage du conteneur

Pour créer une image à partir de nosDockerfile, nous devons exécuter‘docker build', comme avant:

$> docker build --file=Dockerfile.server \
     --tag=config-server:latest --rm=true .

Mais avant de lancer un conteneur à partir de notre image, nous devons créer un volume pour le montage:

$> docker volume create --name=spring-cloud-config-repo

NOTICE: Lorsqu'un conteneur est immuable, lorsqu'il n'est pas validé dans une image après la fermeture de l'application, les données stockées dans un volume seront persistantes sur plusieurs conteneurs.

Enfin, nous pouvons exécuter le conteneur à partir de notre image:

$> docker run --name=config-server --publish=8888:8888 \
     --volume=spring-cloud-config-repo:/var/lib/spring-cloud/config-repo \
     config-server:latest
  • Tout d'abord, nous devons–name notre conteneur. Sinon, on en choisira automatiquement un

  • Ensuite, nous devons–publish notre port exposé (voirDockerfile) vers un port sur notre hôte. La valeur est donnée sous la forme‘host-port:container-port'. Si seul un conteneur-port est donné, un port hôte choisi au hasard sera utilisé. Si nous laissons cette option de côté, le conteneur sera complètement isolé

  • L'option–volume donne accès à un répertoire sur l'hôte (lorsqu'il est utilisé avec un chemin absolu) ou à un volumeDocker précédemment créé (lorsqu'il est utilisé avec unvolume-name). Le chemin après les deux points spécifie lesmountpoint dans le conteneur

  • Comme argument, nous devons indiquer àDocker quelle image utiliser. Ici, nous devons donner lesimage-name de l’étape précédente ‘docker build

  • Quelques options plus utiles:

    • -it - activer le mode interactif et allouer unpseudo-tty

    • -d - se détacher du conteneur après le démarrage

Si nous avons exécuté le conteneur en mode détaché, nous pouvons en examiner les détails, l'arrêter et le supprimer à l'aide des commandes suivantes:

$> docker inspect config-server
$> docker stop config-server
$> docker rm config-server

4. Dockerize Applications dépendantes dans un composite

Les commandesDocker etDockerfiles sont particulièrement adaptées à la création de conteneurs individuels. Mais si vous voulezoperate on a network of isolated applications, la gestion des conteneurs devient rapidement encombrée.

To solve that, Docker provides a tool named Docker Compose. Ceci est livré avec un propre fichier de construction au formatYAML et est mieux adapté à la gestion de plusieurs conteneurs. Par exemple: il est capable de démarrer ou d'arrêter un composite de services en une seule commande, ou de fusionner la sortie de journalisation de plusieurs services en un seulpseudo-tty.

Créons un exemple de deux applications s'exécutant dans différents conteneurs Docker. Ils communiqueront entre eux et seront présentés comme «unité unique» au système hôte. Nous allons construire et copier l'exemple despring-cloud-config/client décrit dans lespring cloud configuration tutorial dans notre dossierfiles, comme nous l'avons fait auparavant avec lesconfig-server.

Ce seront nosdocker-compose.yml:

version: '2'
services:
    config-server:
        container_name: config-server
        build:
            context: .
            dockerfile: Dockerfile.server
        image: config-server:latest
        expose:
            - 8888
        networks:
            - spring-cloud-network
        volumes:
            - spring-cloud-config-repo:/var/lib/spring-cloud/config-repo
        logging:
            driver: json-file
    config-client:
        container_name: config-client
        build:
            context: .
            dockerfile: Dockerfile.client
        image: config-client:latest
        entrypoint: /opt/spring-cloud/bin/config-client-entrypoint.sh
        environment:
            SPRING_APPLICATION_JSON: \
              '{"spring": {"cloud":  \
              {"config": {"uri": "http://config-server:8888"}}}}'
        expose:
            - 8080
        ports:
            - 8080:8080
        networks:
            - spring-cloud-network
        links:
            - config-server:config-server
        depends_on:
            - config-server
        logging:
            driver: json-file
networks:
    spring-cloud-network:
        driver: bridge
volumes:
    spring-cloud-config-repo:
        external: true
  • version: spécifie la version de format à utiliser. C'est un champ obligatoire. Ici, nous utilisons la version la plus récente, alors que lelegacy format vaut «1»

  • services: chaque objet de cette clé définit un conteneurservice, a.k.a. Cette section est obligatoire

    • build: s'il est donné,docker-compose est capable de construire une image à partir d'unDockerfile

      • context: s'il est donné, il spécifie le répertoire de construction, où leDockerfile est recherché

      • dockerfile: s'il est donné, il définit un autre nom pour unDockerfile

    • image: indique àDocker quel nom il doit donner à l'image lorsque les fonctionnalités de construction sont utilisées. Sinon, il recherche cette image dans la bibliothèque ou dansremote-registry

    • networks: il s'agit de l'identifiant des réseaux nommés à utiliser. Unname-value donné doit être répertorié dans la sectionnetworks

    • volumes: identifie les volumes nommés à utiliser et les points de montage sur lesquels monter les volumes, séparés par deux-points. De même dans la sectionnetworks, unvolume-name doit être défini dans une sectionvolumes distincte

    • links: Cela créera un lien réseau interne entre le servicethis et le service répertorié. Le serviceThis pourra se connecter au service répertorié, la partie avant les deux points spécifiant unservice-name de la sectionservices et la partie après les deux points spécifiant le nom d'hôte auquel le service écoute sur un port exposé

    • depends_on: Ceci indique àDocker de démarrer un service uniquement, si les services répertoriés ont démarré avec succès. NOTICE: Cela ne fonctionne qu'au niveau du conteneur! Pour une solution de contournement pour démarrer lesapplication dépendants en premier, voirconfig-client-entrypoint.sh

    • logging: Ici, nous utilisons le pilote‘json-file', qui est celui par défaut. Alternativement‘syslog' avec une option d'adresse donnée ou‘none' peuvent être utilisés

  • networks: Dans cette section, nous spécifions lesnetworks disponibles pour nos services. Dans cet exemple, nous laissonsdocker-compose créer unnetwork nommé de type‘bridge' pour nous. Si l'optionexternal est définie surtrue, elle utilisera une option existante avec le nom donné

  • volumes: Ceci est très similaire à la sectionnetworks

Avant de continuer, nous allons vérifier dans notre fichier de construction les erreurs de syntaxe:

$> docker-compose config

Ce sera notreDockerfile.client pour construire l'image deconfig-client. Il diffère desDockerfile.server en ce que nous installons en plusOpenBSD netcat (ce qui est nécessaire à l'étape suivante) et rendons leentrypoint exécutable:

FROM alpine-java:base
MAINTAINER example.com
RUN apk --no-cache add netcat-openbsd
COPY files/config-client.jar /opt/spring-cloud/lib/
COPY files/config-client-entrypoint.sh /opt/spring-cloud/bin/
RUN chmod 755 /opt/spring-cloud/bin/config-client-entrypoint.sh

Et ce seront lesentrypoint personnalisés pour nosconfig-client service. Ici, nous utilisonsnetcat dans une boucle pour vérifier si notreconfig-server est prêt. Vous devez remarquer que nous pouvons atteindre nosconfig-server par seslink-name, au lieu d'une adresse IP:

#!/bin/sh
while ! nc -z config-server 8888 ; do
    echo "Waiting for upcoming Config Server"
    sleep 2
done
java -jar /opt/spring-cloud/lib/config-client.jar

Enfin, nous pouvons construire nos images, créer les conteneurs définis et les lancer en une seule commande:

$> docker-compose up --build

Pour arrêter les conteneurs, le supprimer deDocker et en supprimer lesnetworks etvolumes connectés, nous pouvons utiliser la commande inverse:

$> docker-compose down

Une fonctionnalité intéressante dedocker-compose est leability to scale services. Par exemple, nous pouvons dire àDocker d'exécuter un conteneur pour lesconfig-server et trois conteneurs pour lesconfig-client.

Mais pour que cela fonctionne correctement, nous devons supprimer lescontainer_name de nosdocker-compose.yml, pour laisserDocker en choisir un, et nous devons changer lesexposed port configuration, pour éviter les conflits .

Après cela, nous pouvons adapter nos services comme suit:

$> docker-compose build
$> docker-compose up -d
$> docker-compose scale config-server=1 config-client=3

5. Conclusion

Comme nous l'avons vu, nous sommes maintenant en mesure de créer des imagesDocker personnalisées, en exécutant unSpring Boot Application en tant que conteneurDocker et en créant des conteneurs dépendants avecdocker-compose.

Pour plus d'informations sur les fichiers de construction, nous nous référons auxDockerfile reference officiels et auxdocker-compose.yml reference.

Comme d'habitude, les codes sources de ce tutoriel peuvent être trouvéson Github.