diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 31dba783ab741f2cb578bd8112eff43b789981ff..4d6e558f690628583141d2cabd81ac1b0137d31d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -18,3 +18,19 @@ build:
     - docker push "$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME/polls:${CI_COMMIT_SHORT_SHA}"
   tags:
     - k8s
+
+deploy:
+  stage: deploy
+  image: registry-gitlab.pasteur.fr/dsi-tools/docker-images:docker_kubernetes_image
+  variables:
+    NAMESPACE: "tmenard-django"
+  environment:
+    name: tmenard-django
+    url: https://tmenard-django.k8s-dev.pasteur.fr
+  script:
+    - kubectl delete secret registry-gitlab -n ${NAMESPACE} --ignore-not-found=true
+    - kubectl create secret docker-registry -n ${NAMESPACE} registry-gitlab --docker-server=registry-gitlab.pasteur.fr --docker-username=${DEPLOY_USER} --docker-password=${DEPLOY_TOKEN} --docker-email=kubernetes@pasteur.fr
+    - envsubst < polls.yaml | kubectl apply -f -
+    - kubectl patch deployment polls -p "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"date\":\"`date +'%s'`\"}}}}}"
+  tags:
+    - k8s
diff --git a/manifest.yaml b/manifest.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d871049865412ba9443c34835879cb973582994b
--- /dev/null
+++ b/manifest.yaml
@@ -0,0 +1,190 @@
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+name: postgres-claim
+labels:
+    app: postgresql
+spec:
+accessModes:
+    - ReadWriteOnce
+resources:
+    requests:
+    storage: 1Gi
+---
+apiVersion: v1
+kind: Secret
+metadata:
+name: postgresql-credentials
+type: Opaque
+data:
+username: cG9sbHNfdXNlcgo=
+password: cG9sbHMK
+database: cG9sbHMK
+---
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+name: postgresql
+labels:
+    app: postgresql
+spec:
+strategy:
+    type: Recreate
+template:
+    metadata:
+    labels:
+        app: postgresql
+        tier: postgreSQL
+    spec:
+    containers:
+        - image: postgres:9.6.2-alpine
+        name: postgresql
+        env:
+            - name: POSTGRES_USER
+            valueFrom:
+                secretKeyRef:
+                name: postgresql-credentials
+                key: username
+            - name: POSTGRES_DB
+            valueFrom:
+                secretKeyRef:
+                name: postgresql-credentials
+                key: database
+            - name: POSTGRES_PASSWORD
+            valueFrom:
+                secretKeyRef:
+                name: postgresql-credentials
+                key: password
+        ports:
+            - containerPort: 5432
+            name: postgresql
+        volumeMounts:
+            - name: postgresql
+            mountPath: /var/lib/postgresql/data
+            subPath: data
+    volumes:
+        - name: postgresql
+        persistentVolumeClaim:
+            claimName: postgres-claim
+        - name: postgresql-credentials
+        secret:
+            secretName: postgresql
+---
+apiVersion: v1
+kind: Service
+metadata:
+name: postgresql
+labels:
+    app: postgresql
+spec:
+ports:
+    - port: 5432
+selector:
+    app: postgresql
+    tier: postgreSQL
+---
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+name: polls
+labels:
+    app: polls
+spec:
+replicas: 3
+template:
+    metadata:
+    labels:
+        app: polls
+    spec:
+    containers:
+    name: polls-app
+        image: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME/polls:${CI_COMMIT_SHORT_SHA}
+        # This setting makes nodes pull the docker image every time before
+        # starting the pod. This is useful when debugging, but should be turned
+        # off in production.
+        imagePullPolicy: Always
+        env:
+            - name: DATABASE_NAME
+            valueFrom:
+                secretKeyRef:
+                name: postgresql-credentials
+                key: database
+            - name: DATABASE_USER
+            valueFrom:
+                secretKeyRef:
+                name: postgresql-credentials
+                key: username
+            - name: DATABASE_PASSWORD
+            valueFrom:
+                secretKeyRef:
+                name: postgresql-credentials
+                key: password
+        ports:
+        - containerPort: 8080
+    volumes:
+        - name: postgresql-credentials
+        secret:
+            secretName: postgresql
+---
+apiVersion: v1
+kind: Service
+metadata:
+name: polls
+labels:
+    app: polls
+spec:
+type: ClusterIP
+ports:
+- port: 80
+    targetPort: 8080
+selector:
+    app: polls
+---
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+annotations:
+    kubernetes.io/ingress.class: traefik
+labels:
+    app: polls
+name: polls
+spec:
+rules:
+- host: https://${CI_PROJECT_NAME}.k8s-dev.pasteur.fr
+    http:
+    paths:
+    - backend:
+        serviceName: polls
+        servicePort: 80
+        path: /
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+name: polls-migrations
+spec:
+template:
+    spec:
+    containers:
+        - name: django
+        image: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME/polls:${CI_COMMIT_SHORT_SHA}
+        command: ['python', 'manage.py', 'migrate']
+        env:
+            - name: DATABASE_NAME
+            valueFrom:
+                secretKeyRef:
+                name: postgresql-credentials
+                key: database
+            - name: DATABASE_USER
+            valueFrom:
+                secretKeyRef:
+                name: postgresql-credentials
+                key: username
+            - name: DATABASE_PASSWORD
+            valueFrom:
+                secretKeyRef:
+                name: postgresql-credentials
+                key: password
+    restartPolicy: Never
+backoffLimit: 5