Packager une application avec Docker

Nous avons vu précédemment qu'il était possible de compiler, déployer, voire de créer un Artifact (livrable) avec l'intégration continue. Cependant nous pouvons aller bien plus loin, nous pouvons carrément créer un conteneur Docker directement depuis le CI.

Sommaire

Objectif

L'objectif de faire construire une image Docker directement depuis la CI est d'automatiser à 100% le processus de packaging de votre application. Plus d'humain == plus de risque.

Plus de risque ?

Façon de parler évidemment… En sécurité l'humain est source de vulnérabilité « volontaire » et « involontaire ». En automatisant au maximum les opérations de packaging, nous pourrons par la même réduire les risques :

  • D'erreurs.
  • De corruption du livrable.
  • de perte de temps.

La finalité est donc de créer directement depuis le CI le livrable ici l'image Docker de notre application. Nous utiliserons Gitlab-ci, mais la même opération est possible maintenant avec Githubopen in new window.

Avec Gitlab ce service s'appelle le Gitlab Container Registryopen in new window, le service est gratuit et est intégré à Gitlab (quelle que soit la version que vous avez). Bonus vous avez un registry intégré à chaque projet 👍.

Créer un projet sur Gitlab

Pour l'instant pas de problème vous savez faireopen in new window. La première étape est de versionner votre projet sur Gitlab comme habituellement. Je vous laisse créer votre projet, le nom importe peu.

Project creation

Ajouter l'application à packager

Je vous propose que l'on package une application Web. Bien que l'on puisse packager ce que l'on souhaite (API, Application, Web), je pense que le web est le plus intéressant, car il possède des étapes « de compilation » en amont ; ces étapes peuvent prendre un peu de temps et sont très facilement automatisables.

Je vous propose de créer un site « fictif » avec ViteJS (VueJS 3), pour ça dans un terminal :

npm init @vitejs/app

Vite Init

Un projet vide vient d'être créé. Je vous laisse le tester dans un premier temps sur votre ordinateur, dans mon cas

cd ci-packaging
npm install
npm run dev

Je vous laisse vérifier que tout fonctionne comme attendu !

npm, yarn, pnpm ?

Personnellement j'utilise pnpm, pourquoi ? À cause du dépôt centralisé ; vous souhaitez en savoir plus ? Je suis là 👋

Vous souhaitez packager autres choses ?

Aucun problème je peux vous aider à packager votre site / api / service.

Commiter / pusher une première version

Maintenant que tout fonctionne, nous allons créer une première version. Ici bien évidemment on utilise git (ça semble évident…).

Ajouter un gitlab-ci.yml

Pour activer Gitlab-CI, c'est aussi simple que d'ajouter un fichier (.gitlab-ci.yml), dans le code source de votre projet. Je vous laisse ajouter la configuration suivante.

build:
  image: node:latest
  stage: build
  script:
    - npm install
    - npm run build
  only:
    - master

Comprendre le fonctionnement

Vous voyez ici que finalement l'important c'est de comprendre le fonctionnement pour l'adapteur à notre besoin. Dans le cadre du CI/CD, il faut souvent lire la documentation, adapter, réessayer, etc.

Mais une fois configuré… La vie sera belle et votre travail en grande partie automatisé.

Tester

Pour l'instant pas de création d'image Docker, nous allons-y aller étape par étape. La première ? Valider que l'installation des dépendances fonctionne sans problème sur Gitlab-CI.

Je vous laisse donc commiter et pusher votre code source.

Si tout se passe bien vous devez avoir :

Build CI

Dockeriser

La première étape est de Dockeriser votre application actuelle. L'idée est donc de créer le fichier Dockerfile nécessaire au bon fonctionnement de votre site web. Je vous laisse réfléchir au besoin, mais pensez qu'ici nous avons un site static qui ne possède aucune dépendance ; vous pouvez donc rester très très simple !

Vous n'avez pas d'inspiration ? Pas de problème, la documentation officielle nous aideopen in new window

Vous avez besoin d'aide ?
FROM nginx:stable-alpine
COPY dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

STOP !

Avant de pusher votre code, tester sur votre ordinateur le bon fonctionnement !

Dans mon cas :

docker build -t vue:test .
docker run -it -p 8080:80 --rm --name vuetest vue:test

Packager

Nous avons maintenant tout le nécessaire pour packager notre application directement sur Gitlab-CI et la publier sur le Registry interne à GitLab. Nous allons devoir modifier notre fichier .gitlab-ci.yml pour y ajouter une autre step, celle de « release » / « packaging » / « encapsulation ».

La conception de ce gitlab-ci, est un peu plus complexe, je vous propose de vous le donner pour que nous le décortiquer ensemble :

stages:
  - build
  - release

build:
  image: node:latest
  stage: build
  script:
    - npm install
    - npm run build
  only:
    - master
  artifacts:
    paths:
      - dist/
    expire_in: 1 hour

release-img:
  image: docker:19.03.12
  stage: release
  dependencies:
    - build
  services:
    - docker:19.03.12-dind
  variables:
    IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $IMAGE_TAG .
    - docker push $IMAGE_TAG
  only:
    - master

Normalement si tout se passe bien vous devriez avoir …

Si tout se passe bien…

Si tout se passe bien…

Tester depuis votre poste l'image obtenue

Vous connecter

Votre image est maintenant sauvegardée sur les serveurs de Gitlab, nous pouvons donc maintenant nous en servir sans la builder sur notre poste préalablement. Cependant ce « hub » n'est pas public comme l'officiel, il faudra donc se connecter préalablement / s'authentifier auprès des serveurs de Gitlab.

STOP

Votre mot de passe ne fonctionnera pas ! Pour des raisons de sécurité vous ne pourrez pas utiliser votre propre mot de passe pour vous authentifiez. Vous allez devoir générer un Token depuis votre profilopen in new window

Si tout se passe bien…

Une fois le token généré il suffit de vous connecter au Registry via la commande :

docker login registry.gitlab.com

Lancer votre image

Pour lancer votre image, rien de bien complexe ! Il suffit de spécifier le bon projet et le bon tag. Dans mon cas voilà à quoi ça ressemble :

docker run registry.gitlab.com/vbrosseau/ci-packaging:master

Docker RUN

Apporter des modifications

Votre stack est maintenant prête, elle est jouable / rejouable à l'infinie. Je vous laisse apporter des modifications « importante » à votre site Internet pour tester que l'image Docker s'update correctement après vos commits.

Booster les performances

Votre compilation doit-être actuellement plutôt lente… C'est normal l'installation des dépendances prend un peu de temps. Dans gitlab-ci nous pouvons ajouter du cache, j'ai donné pas mal de pistes pour les autres étapes… Pour celle-ci je vous laisse chercher dans la documentation.

Gestion du cacheopen in new window

Image multi-architectures ?

Vous souhaitez créer une image qui fonctionnera sur un Raspberry Pi, mais également sur une machine X86? C'est possible, c'est ce que l'on appel le « Multi-architectures. Nous sommes plus dans quelques choses d'aussi simple qu'avec l'exemple précédent, mais vous pouvez le faire sans problème depuis Gitlab-CI ?

dockerise:
  image: docker:19.03.12
  stage: deploy
  dependencies:
    - build
  services:
    - name: docker:19.03.12-dind
      command: ["--experimental"]
  variables:
    IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
    DOCKER_DRIVER: overlay2
    DOCKER_TLS_CERTDIR: ""
    BUILDX_VERSION: v0.4.1
  before_script:
    - apk add curl
    - mkdir -p ~/.docker/cli-plugins
    - curl -sSLo ~/.docker/cli-plugins/docker-buildx https://github.com/docker/buildx/releases/download/$BUILDX_VERSION/buildx-$BUILDX_VERSION.linux-amd64
    - chmod +x ~/.docker/cli-plugins/docker-buildx
    - docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
    - docker info
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker buildx create --use
    - docker buildx build --push --platform linux/arm/v8,linux/amd64 -t $IMAGE_TAG .
  only:
    - master