Gitlab

docker-compose.yml

Le Docker-compose permet de décrire l’ensemble des services formant une application.

Cette description sera utilisée à différentes étapes du projet, principalement pour le développement et sur le serveur d’intégration continue (tests de l’application, préparation des assets …) et éventuellement en production.

Les variables d’environnement

Le Docker-compose utilise un fichier .env pour initialiser des variables d’environnement. Ce fichier sera utilisé en local pour stocker les accès aux services dont l’application a besoin pour fonctionner (serveur de base de données, serveur d’envoi d’email …), mais aussi pour reproduire le comportement de Gitlab CI en initialisant quelques variables de la CI utilisées par Gitlab. Ensuite, les projets déployés dans un environnement conteneurisé auront un .env généré automatiquement pour chaque environnement de déploiement (préprod/prod/…).

CI_REGISTRY_IMAGE=myapp
CI_COMMIT_SHA=dev
CI_ENVIRONMENT_NAME=dev

Dans l’exemple ci-dessus, on a besoin de simuler 3 variables de la CI dans un fichier .env afin de pouvoir construire et utiliser l’image de notre application python en local.

Docker-compose

L’image construite grâce au Dockerfile pourra être utilisée dans le fichier docker-compose.yml afin de définir le service de notre application.

# this file is good to go for production
version: "3"

services:
    # our webapp. 
    app:
        # use our image
        image: ${CI_REGISTRY_IMAGE}/app:${CI_COMMIT_SHA}
        # expose our server port
        expose: [9000]
        # define some env vars available to our container
        environment:
            ENV: ${CI_ENVIRONMENT_NAME}
            CI_ENVIRONMENT_DOMAIN: ${CI_ENVIRONMENT_DOMAIN}

Le docker-compose.yml utilise les 3 variables définies dans le fichier .env. Une nouvelle variable CI_ENVIRONMENT_DOMAIN est ajoutée pour indiquer au reverse-proxy le domaine utilisé par l’application. Ce point sera abordé plus loin, mais en l’état l’application peut être joignable en HTTP en utilisant l’IP et le port du conteneur.

Ajout d’un service de base de données

Si notre application a besoin de se connecter à une base de données, il faut lui ajouter les directives qui conviennent pour qu’elle se connecte au serveur de bdd.

Dans le fichier .env, on ajoute les valeurs d’accès au serveur de BDD:

MYSQL_DATABASE=myapp_python
MYSQL_USER=myapp_python
MYSQL_PASSWORD=password

Dans le Docker-compose, on ajoute un nouveau service:

    # mysql database service
    mysql:
        image: mariadb:10.1
        environment:
            MYSQL_ROOT_PASSWORD: ${MYSQL_PASSWORD}
            MYSQL_DATABASE: ${MYSQL_DATABASE}
            MYSQL_USER: ${MYSQL_USER}
            MYSQL_PASSWORD: ${MYSQL_PASSWORD}
        volumes:
            - mysql_db_data:/var/lib/mysql			

qu’on vient lier à notre service “app” de cette manière:

    # our webapp. 
    app:
	[...]
	# link this container to the mysql service
	depends_on:
	  - mysql
	# define some env vars available to our container
	environment:
	  ENV: ${CI_ENVIRONMENT_NAME}
	  CI_ENVIRONMENT_DOMAIN: ${CI_ENVIRONMENT_DOMAIN}
	  # mysql database connection
	  MYSQL_DATABASE: ${MYSQL_DATABASE}
	  MYSQL_USER: ${MYSQL_USER}
	  MYSQL_PASSWORD: ${MYSQL_PASSWORD}

Ajouter un volume

Si notre application a besoin d’un volume pour stocker des valeurs persistantes, on ajoute la directive suivante dans la description du service:

    # our webapp. 
    app:
	[...]
	# define a volume where we can write uploads
	volumes:
	  - ./data/uploads:/var/www/uploads

Au final, le docker-compose ressemblera à ce qui suit:

# this file is good to go for production
version: "3"

services:

    # our webapp.
    app:
        # use our image
        image: ${CI_REGISTRY_IMAGE}/app:${CI_COMMIT_SHA}
        # expose our server port
        expose: [9000]
        # link this container to the mysql service		
        depends_on:
            - mysql
        # define a volume where we can write uploads
        volumes:
            - ./data/uploads:/var/www/uploads
        # define some env vars available to our container
        environment:
            ENV: ${CI_ENVIRONMENT_NAME}
            CI_ENVIRONMENT_DOMAIN: ${CI_ENVIRONMENT_DOMAIN}
            # mysql database connection
            MYSQL_DATABASE: ${MYSQL_DATABASE}
            MYSQL_USER: ${MYSQL_USER}
            MYSQL_PASSWORD: ${MYSQL_PASSWORD}

    # mysql database service
    mysql:
        image: mariadb:10.1
        environment:
            MYSQL_ROOT_PASSWORD: ${MYSQL_PASSWORD}
            MYSQL_DATABASE: ${MYSQL_DATABASE}
            MYSQL_USER: ${MYSQL_USER}
            MYSQL_PASSWORD: ${MYSQL_PASSWORD}
        volumes:
            - mysql_db_data:/var/lib/mysql			

Pour le moment, il n’y a rien d’exceptionnel par rapport à la manière classique de construire une application conteneurisée, à part l’utilisation des variables d’environnement de la CI.

Mais avant de détailler le fonctionnement de l’intégration continue, il est temps de documenter la manière dont le workflow expose publiquement l’application avec son reverse-proxy et sa gestion du routage HTTP.

NB: Le paramétrage du routage http est requis dans le cadre d’un projet qui vise un déploiement en mode conteneurisé ou qui a besoin de réaliser des tests dans les conteneurs lors de la phase d’intégration.

Top