Gitlab

Makefile

Nous utilisons un fichier Makefile pour organiser les scripts qui seront appelés dans les étapes de la CI.

Il regroupe les commandes nécessaires à la construction de l’application, et qui seront jouées dans le scénario décrit dans le fichier .gitlab-ci.yml, et ainsi reproduites sur le serveur d’intégration.

Préparation

La récupération de la dernière version des images de base est nécessaire pour s’assurer que le build de l’application utilisera une version à jour des images de base Docker. En utilisant les outils propres aux langages du projet, la CI va télécharger les bibliothèques nécessaires. Il peut être judicieux d’utiliser les volumes et le système de cache proposé par la CI pour diminuer le temps requis par certaines étapes du pipeline.

pull:
  # pull latest images required for our build
  docker pull bearstech/python:3
  docker pull bearstech/python-dev:3

Etape de build

La construction de l’image de notre application se fait au sein de cette étape préalable aux autres:

# current user id is usefull to be able to write in volumes
export UID:=$(shell id -u)

build:
  # build the docker images with the commit as tag
  docker build -t $(CI_REGISTRY_IMAGE)/app:$(CI_COMMIT_SHA) \
        -f Dockerfile --build-arg=uid=$(UID) .

Ici, on vient spécifier l’uid (celui de l’utilisateur courant) qui sera utilisé pour instancier l’application tel que définit dans le Dockerfile. On remarque aussi que la commande docker build utilise les variables d’environnement de Gitlab CI afin de taguer l’image.

Pousser l’image sur la registry

Une fois l’image de l’application construite, elle doit être disponible sur la registry privée de Gitlab:

push:
  # push images to our private registry
  docker push $(CI_REGISTRY_IMAGE)/app:$(CI_COMMIT_SHA)

Instancier l’application

Les directives qui permettent d’instancier l’application sont utiles pour lancer l’application en local, mais aussi pour réaliser des tests unitaires ou fonctionnels sur le serveur de CI:

up:
  # run compose in background
  docker-compose up -d
  # wait for services using the bearstech/traefik-dev container utils
  docker-compose exec -T traefik wait_for_services -v --timeout 20
  # show apps logs
  docker-compose logs --tail="all" app

Le Makefile utilisé pour faire fonctionner le workflow regroupe les commandes nécessaires aux étapes de la CI:

  • Le build de l’image garantit la mise à jour des librairies et des briques du système qui seront embarqués dans les conteneurs.
  • Le push sur la registry dépend du commit, et ainsi il est toujours possible de retrouver l’état de l’application au moment du build.
  • Le développeur peut travailler sur l’application dans un environnement similaire à celui de la production

Voici le Makefile qui sera utilisé pour réaliser l’intégration de l’application écrite en python:

# The Makefile defines all builds steps

# current user id is usefull to be able to write in volumes
export UID:=$(shell id -u)

# compose command to merge production file and and dev/tools overrides
COMPOSE?=docker-compose -f docker-compose.yml -f tools.yml -f dev.yml

# docker run command used to build dependencies before images build
DOCKER?=docker run --rm -u $(UID) -e "HOME=/home/myapp" -w "/home/myapp" \
    -v "$(PWD):/home/myapp" -v "$(HOME)/.cache:/.cache" \
    bearstech/python-dev:3

export COMPOSE DOCKER

# Define some defaults if we are not on CI
TRAEFIK_HTTP_PORT?=80
TRAEFIK_UI_PORT?=8080

# Let compose be aware of some vars
export TRAEFIK_HTTP_PORT TRAEFIK_UI_PORT

# this is usefull with most python apps in dev mode because if stdout is
# buffered logs do not shows in realtime
PYTHONUNBUFFERED=1
export PYTHONUNBUFFERED

pull:
    # pull latest images required for our build
    docker pull bearstech/python:3
    docker pull bearstech/python-dev:3

$(HOME)/.cache:
    mkdir -p $(HOME)/.cache

venv: $(HOME)/.cache
    # install some software with a dev image here
    $(DOCKER) python3 -m venv venv
    $(DOCKER) venv/bin/pip install -U pip wheel
    $(DOCKER) venv/bin/pip install -U -r requirements.txt

build: venv
    # build the docker images with the commit as tag
    docker build -t $(CI_REGISTRY_IMAGE)/app:$(CI_COMMIT_SHA) \
        -f Dockerfile.app --build-arg=uid=$(UID) .

push:
    # push images to our private registry
    docker push $(CI_REGISTRY_IMAGE)/app:$(CI_COMMIT_SHA)

data/uploads:
    # initialize some dirs. do not let docker create them with uid root
    mkdir -p data/uploads

volumes: data/uploads

up: volumes
    # run compose in background
    $(COMPOSE) up -d
    # wait for services using the bearstech/traefik-dev container utils
    $(COMPOSE) exec -T traefik wait_for_services -v --timeout 20
    # show apps logs
    $(COMPOSE) logs --tail="all" app

dev: volumes
    # run compose in foreground
    $(COMPOSE) up app

down:
    # stop compose
    $(COMPOSE) down --remove-orphans
Top