diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8e92ceed47f3a2564914ca46ee1ccc32f88eca0c..fd0b67bde4fb5d8441c5bde98366a4be256abe77 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,7 +1,7 @@
 stages:
   - checks
   - tests
-  - publish
+  - package
   - coverage
 
 variables:
@@ -105,8 +105,64 @@ tests:3.10:
   variables:
     PYTHON_VERSION: "3.10"
 
+.image:
+  stage: package
+  tags: [docker]
+  image: docker:latest
+  services:
+    - docker:dind
+  variables:
+    PYTHON_VERSION: "3.10"
+  script:
+    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
+    - docker build --pull -t "$CI_REGISTRY_IMAGE/$CHANNEL/$ENV:$CI_COMMIT_SHORT_SHA" -f image/$ENV --build-arg PYTHON_VERS=$PYTHON_VERSION .
+    - docker push "$CI_REGISTRY_IMAGE/$CHANNEL/$ENV:$CI_COMMIT_SHORT_SHA"
+    - docker tag "$CI_REGISTRY_IMAGE/$CHANNEL/$ENV:$CI_COMMIT_SHORT_SHA" "$CI_REGISTRY_IMAGE/$CHANNEL/$ENV:latest"
+    - docker push "$CI_REGISTRY_IMAGE/$CHANNEL/$ENV:latest"
+
+.image:release:
+  extends: .image
+  variables:
+    CHANNEL: "release"
+  after_script:
+    - docker tag "$CI_REGISTRY_IMAGE/$CHANNEL/$ENV:$CI_COMMIT_SHORT_SHA" "$CI_REGISTRY_IMAGE/$CHANNEL/$ENV:$CI_COMMIT_TAG"
+    - docker push "$CI_REGISTRY_IMAGE/$CHANNEL/$ENV:$CI_COMMIT_TAG"
+  rules:
+    - if: $CI_COMMIT_TAG
+      when: manual
+
+image:release:poetry:
+  extends: .image:release
+  variables:
+    ENV: "poetry"
+
+image:release:pip:
+  extends: .image:release
+  variables:
+    ENV: "pip"
+
+.image:branch:
+  extends: .image
+  allow_failure: true
+  variables:
+    CHANNEL: $CI_COMMIT_BRANCH
+  rules:
+    - if: $CI_COMMIT_TAG
+      when: never
+    - when: manual
+
+image:branch:poetry:
+  extends: .image:branch
+  variables:
+    ENV: "poetry"
+
+image:branch:pip:
+  extends: .image:branch
+  variables:
+    ENV: "pip"
+
 pypi_test:
-  stage: publish
+  stage: package
   rules:
     - if: $CI_COMMIT_TAG
       when: manual
@@ -115,7 +171,7 @@ pypi_test:
     - poetry publish --build --username $PYPI_TEST_LOGIN --password $PYPI_TEST_PASSWORD --repository pypi_test
 
 pypi:
-  stage: publish
+  stage: package
   rules:
     - if: $CI_COMMIT_TAG
       when: manual
diff --git a/image/pip b/image/pip
new file mode 100644
index 0000000000000000000000000000000000000000..ca287fb6989ae4076b19e6e52a81d0e63bfba129
--- /dev/null
+++ b/image/pip
@@ -0,0 +1,38 @@
+# ------------------------------------------------------------------------------
+# Build Stage
+# ------------------------------------------------------------------------------
+ARG PYTHON_VERS
+FROM python:${PYTHON_VERS}-slim-bullseye AS build
+
+WORKDIR /silkaj
+
+# Copy source tree
+COPY ./ ./
+
+# Install Silkaj
+RUN pip install .
+
+# ------------------------------------------------------------------------------
+# Final Stage
+# ------------------------------------------------------------------------------
+FROM python:${PYTHON_VERS}-slim-bullseye
+ARG PYTHON_VERS
+
+# Create silkaj group and user
+RUN groupadd -g 1111 silkaj && \
+    useradd -d /silkaj -g silkaj -u 1111 silkaj
+
+# Install libsodium
+RUN apt update && \
+    apt install --yes libsodium23 && \
+    rm -rf /var/lib/apt/lists
+
+# Copy the build artifact from the build stage
+COPY --from=build /usr/local/bin/silkaj /usr/local/bin/silkaj
+COPY --from=build /usr/local/lib/python${PYTHON_VERS}/site-packages/ /usr/local/lib/python${PYTHON_VERS}/site-packages/
+
+# Use silkaj user
+USER silkaj
+WORKDIR /usr/local/lib/python${PYTHON_VERS}/site-packages/silkaj
+
+CMD ["/usr/local/bin/silkaj"]
diff --git a/image/poetry b/image/poetry
new file mode 100644
index 0000000000000000000000000000000000000000..dfb7ebf60faca08d56661bc615c946361c858cd2
--- /dev/null
+++ b/image/poetry
@@ -0,0 +1,43 @@
+# ------------------------------------------------------------------------------
+# Build Stage
+# ------------------------------------------------------------------------------
+ARG PYTHON_VERS
+FROM registry.duniter.org/docker/python3/poetry/${PYTHON_VERS}:latest AS build
+
+WORKDIR /silkaj
+
+# Copy source tree
+COPY ./ ./
+
+# Install Silkaj
+RUN poetry install --no-dev
+
+# ------------------------------------------------------------------------------
+# Final Stage
+# ------------------------------------------------------------------------------
+FROM registry.duniter.org/docker/python3/poetry/${PYTHON_VERS}:latest
+ARG PYTHON_VERS
+
+# Create silkaj group and user
+RUN groupadd -g 1111 silkaj && \
+    useradd -d /silkaj -g silkaj -u 1111 silkaj
+
+# Install libsodium and git
+RUN apt update && \
+    apt install --yes libsodium23 git && \
+    rm -rf /var/lib/apt/lists
+
+# Set up alias to directly get silkaj command
+# https://stackoverflow.com/a/3638886
+RUN printf '#!/bin/bash\npoetry run silkaj "$@"' > /usr/bin/silkaj && \
+    chmod +x /usr/bin/silkaj
+
+# Copy the build artifact from the build stage
+COPY --from=build --chown=silkaj:silkaj /silkaj /silkaj
+COPY --from=build --chown=silkaj:silkaj /root/.cache/pypoetry/virtualenvs /silkaj/.cache/pypoetry/virtualenvs
+
+# Use silkaj user
+USER silkaj
+WORKDIR /silkaj
+
+CMD ["/usr/bin/silkaj"]