diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index efbaa2252ab033d9979b43b1914119c7d1fffd35..caca7be44191f92dd447131aea370bc3aa303048 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -5,8 +5,83 @@ include:
   - local: templates/Rules.yaml
   - local: templates/Runners/eole-docker.yaml
   - local: templates/Lint/Commitlint.yaml
+  - local: templates/Docker.yaml
   - local: templates/Release/Semantic-release.yaml
 
 stages:
   - lint
+  - build
   - release
+
+.docker-matrix:
+  parallel:
+    matrix:
+      - IMAGE_NAME: [commitlint, semantic-release-gitlab]
+
+###############################################################################
+# `build` stage: `*-docker-build`
+###############################################################################
+# Suffix all jobs to avoid conflict with other jobs names
+build-docker:
+  extends:
+    - .docker-matrix
+    - .build-docker-image
+
+###############################################################################
+# `release` stage: `semantic-release`, `*-docker-tag`
+###############################################################################
+# Suffix all jobs to avoid conflict with other jobs names
+.tag-docker:
+  extends:
+    - .docker-matrix
+    - .tag-docker-image
+
+## dev images
+tag dev:
+  extends:
+    - .tag-docker
+    - .on-dev
+  variables:
+    IMAGE_TAG: dev
+
+## testing images
+tag testing:
+  extends:
+    - .tag-docker
+    - .on-testing
+  variables:
+    IMAGE_TAG: testing
+
+## stable images
+.tag-stable:
+  extends: .tag-docker
+  variables:
+    SOURCE_TAG: testing
+
+tag release:
+  extends: .tag-stable
+
+tag major:
+  extends: .tag-stable
+  before_script:
+    - export RELEASE_PREFIX=${RELEASE_PREFIX:-release/}
+    - export RELEASE=${CI_COMMIT_TAG#${RELEASE_PREFIX}}
+    - export IMAGE_TAG=${RELEASE%%.*}
+
+tag minor:
+  extends:
+    - .tag-stable
+  before_script:
+    - export RELEASE_PREFIX=${RELEASE_PREFIX:-release/}
+    - export RELEASE=${CI_COMMIT_TAG#${RELEASE_PREFIX}}
+    - export IMAGE_TAG=${RELEASE%.${RELEASE##*.}}
+
+tag stable:
+  extends: .tag-stable
+  variables:
+    IMAGE_TAG: stable
+
+tag latest:
+  extends: .tag-stable
+  variables:
+    IMAGE_TAG: latest
diff --git a/Dockerfile.commitlint b/Dockerfile.commitlint
new file mode 100644
index 0000000000000000000000000000000000000000..f24930d17f18c50ee5c9b84fe5c4e3d424d2277b
--- /dev/null
+++ b/Dockerfile.commitlint
@@ -0,0 +1,12 @@
+FROM node:current-alpine
+
+LABEL maintainer="eole@ac-dijon.fr"
+
+ARG COMMITLINT_VERSION=13
+ARG COMMITLINT_CONFIG_CONVENTIONAL_VERSION=13
+
+RUN apk add --no-cache git \
+                       ca-certificates
+
+RUN npm install -g commitlint@${COMMITLINT_VERSION} \
+                   @commitlint/config-conventional@${COMMITLINT_CONFIG_CONVENTIONAL_VERSION}
diff --git a/Dockerfile.semantic-release-gitlab b/Dockerfile.semantic-release-gitlab
new file mode 100644
index 0000000000000000000000000000000000000000..cb87dfe5d1a57b87f35ab738d90289ad4c797940
--- /dev/null
+++ b/Dockerfile.semantic-release-gitlab
@@ -0,0 +1,18 @@
+FROM node:current-alpine
+
+LABEL maintainer="eole@ac-dijon.fr"
+
+ARG SEMANTIC_RELEASE_VERSION=18
+ARG SEMAINTIC_GITLAB_VERSION=7
+ARG SEMAINTIC_CHANGELOG_VERSION=6
+ARG SEMAINTIC_EXEC_VERSION=6
+ARG SEMAINTIC_GIT_VERSION=10
+
+RUN apk add --no-cache git \
+                       ca-certificates
+
+RUN npm install -g semantic-release@${SEMAINTIC_RELEASE_VERSION} \
+                   @semantic-release/gitlab@${SEMAINTIC_GITLAB_VERSION} \
+                   @semantic-release/changelog@${SEMAINTIC_CHANGELOG_VERSION} \
+                   @semantic-release/exec@${SEMAINTIC_EXEC_VERSION} \
+                   @semantic-release/git@${SEMAINTIC_GIT_VERSION}
diff --git a/templates/Docker.yaml b/templates/Docker.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e6441f29e9a6a1f0bdca4b7450696985a6673ca8
--- /dev/null
+++ b/templates/Docker.yaml
@@ -0,0 +1,104 @@
+# -*- mode: yaml; coding: utf-8 -*-
+# vim: ft=yaml
+#
+# Define `.build-docker-image` template used by `*-docker-build` jobs
+# It build the container image and push it to `${CI_REGISTRY}`
+#
+# USAGE
+# =====
+#
+# foo-docker-build:
+#   extends: .build-docker-image
+#   variables:
+#     DOCKERFILE: Some-specific.Dockerfile
+#     IMAGE_TAG: $CI_COMMIT_REF_SLUG
+#
+# REQUIREMENTS
+# ============
+#
+# - A `build` stage must be present in your pipeline or it must be
+#   overriden by the extending job to feet your need.
+# - The `.not-on-stable` rules template
+#
+# OPTIONAL VARIABLES
+# ==================
+#
+# - `IMAGE_NAME`: defaults to `${CI_JOB_NAME}` with any suffix `-docker-build*` removed
+# - `DOCKERFILE`: defaults, in order
+#    - to value set by the user
+#    - to `Dockerfile.${IMAGE_NAME}` if the file exists
+#    - to `Dockerfile` if the file exists
+# - `IMAGE_TAG`: defaults to `git-${CI_COMMIT_SHORT_SHA}`
+#
+# USED CI VARIABLES
+# =================
+#
+# - `CI_REGISTRY`
+# - `CI_REGISTRY_USER`
+# - `CI_REGISTRY_PASSWORD`
+# - `CI_REGISTRY_IMAGE`
+#
+.build-docker-image:
+  stage: build
+  extends: .not-on-stable
+  image:
+    name: gcr.io/kaniko-project/executor:v1.7.0-debug
+    entrypoint: [""]
+  script:
+    - export IMAGE_NAME=${IMAGE_NAME:-${CI_JOB_NAME%-docker-build*}}
+    - test -f Dockerfile.${IMAGE_NAME} && export DOCKERFILE=${DOCKERFILE:-Dockerfile.${IMAGE_NAME}} || true
+    - test -f Dockerfile && export DOCKERFILE=${DOCKERFILE:-Dockerfile} || true
+    - export IMAGE_TAG=${IMAGE_TAG:-git-${CI_COMMIT_SHORT_SHA}}
+    - mkdir -p /kaniko/.docker
+    - echo "{\"auths\":{\"${CI_REGISTRY}\":{\"auth\":\"$(echo -n ${CI_REGISTRY_USER}:${CI_REGISTRY_PASSWORD} | base64 | tr -d '\n')\"}}}" > /kaniko/.docker/config.json
+    - /kaniko/executor --context ${CI_PROJECT_DIR} --dockerfile $CI_PROJECT_DIR/${DOCKERFILE} --destination ${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${IMAGE_TAG}
+
+# Define `.tag-docker-image` template used by `*-docker-tag` jobs
+# It tag the `${IMAGE_NAME}:${SOURCE_TAG}` with the tag `${IMAGE_TAG}`
+#
+# USAGE
+# =====
+#
+# foo-docker-tag-devel:
+#   extends: .tag-docker-image
+#   variables:
+#     IMAGE_TAG: 'devel'
+#
+# REQUIREMENTS
+# ============
+#
+# - A `release` stage must be present in your pipeline or it must be
+#   overriden by the extending job to feet your need.
+# - The `.not-on-stable` rules template
+#
+# OPTIONAL VARIABLES
+# ==================
+#
+# - `IMAGE_NAME`: defaults to `${CI_JOB_NAME}` with any suffix `-docker-tag*` removed
+# - `SOURCE_TAG`: source image tag to retag, defaults to `git-${CI_COMMIT_SHORT_SHA}`
+# - `IMAGE_TAG`: image tag, defaults to `${CI_COMMIT_TAG}` with prefix `RELEASE_PREFIX` removed
+# - `RELEASE_PREFIX`: prefix of the `RELEASE`, defaults to `release/`
+#
+# USED CI VARIABLES
+# =================
+#
+# - `CI_REGISTRY`
+# - `CI_REGISTRY_USER`
+# - `CI_REGISTRY_PASSWORD`
+# - `CI_REGISTRY_IMAGE`
+#
+.tag-docker-image:
+  stage: release
+  extends: .on-release-tag
+  image:
+    name: gcr.io/go-containerregistry/crane:debug
+    entrypoint: [""]
+  variables:
+    GIT_STRATEGY: none
+  script:
+    - export IMAGE_NAME=${IMAGE_NAME:-${CI_JOB_NAME%-docker-tag*}}
+    - export SOURCE_TAG=${SOURCE_TAG:-git-${CI_COMMIT_SHORT_SHA}}
+    - export RELEASE_PREFIX=${RELEASE_PREFIX:-release/}
+    - export IMAGE_TAG=${IMAGE_TAG:-${CI_COMMIT_TAG#${RELEASE_PREFIX}}}
+    - crane auth login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY}
+    - crane tag ${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${SOURCE_TAG} ${IMAGE_TAG}