From 86776db91a027d7bca0a27d936ca1b0a2fea6268 Mon Sep 17 00:00:00 2001 From: Thomas MENARD <thomas.menard@pasteur.fr> Date: Tue, 4 Jun 2019 23:28:06 +0200 Subject: [PATCH] Add Dockerfile, gitlab-ci --- .gitlab-ci.yml | 1 - Makefile | 34 ------ README.md | 318 ++++++++++++++++++++++++++----------------------- 3 files changed, 172 insertions(+), 181 deletions(-) delete mode 100755 Makefile diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4f73448..a0dcbd2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -23,7 +23,6 @@ deploy: name: tmenard-django url: https://tmenard-django.k8s-dev.pasteur.fr script: - - yum install -y gettext - 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 < manifest.yaml | kubectl apply -n ${NAMESPACE} -f - diff --git a/Makefile b/Makefile deleted file mode 100755 index e91b01e..0000000 --- a/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -.PHONY: all -all: build push docker_token template deploy - -.PHONY: build -build: - docker build -t ${CI_REGISTRY}/${CI_PROJECT_NAME}/polls:${CI_COMMIT_SHORT_SHA} . - docker tag ${CI_REGISTRY}/${CI_PROJECT_NAME}/polls:${CI_COMMIT_SHORT_SHA} ${CI_REGISTRY}/${CI_PROJECT_NAME}/polls:latest - -.PHONY: push -push: build - docker push -- ${CI_REGISTRY}/${CI_PROJECT_NAME}/polls - -.PHONY: docker_token -docker_token: - 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 - -.PHONY: template -template: - envsubst <polls.yaml >> deploy.yaml - -.PHONY: deploy -deploy: build template push - kubectl apply -n ${NAMESPACE} -f deploy.yaml - -.PHONY: update -update: - kubectl patch deployment -n ${NAMESPACE} polls -p "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"date\":\"`date +'%s'`\"}}}}}" - -.PHONY: delete -delete: - kubectl delete deployment -n ${NAMESPACE} polls - kubectl delete service -n ${NAMESPACE} polls - kubectl delete ingress -n ${NAMESPACE} polls diff --git a/README.md b/README.md index 6b7429d..1479de3 100644 --- a/README.md +++ b/README.md @@ -59,24 +59,20 @@ FROM python:3 # Here we update the image and add python3 virtualenv RUN apt-get update && apt-get upgrade -y && apt-get install \ - -y --no-install-recommends python3 virtualenv - -# Create a virtualenv for the application dependencies. -# # If you want to use Python 2, use the -p python2.7 flag. -RUN virtualenv -p python3 /env -ENV PATH /env/bin:$PATH + -y --no-install-recommends python3 # Install pip dependencies ADD requirements.txt /app/requirements.txt -RUN /env/bin/pip install --upgrade pip && /env/bin/pip install -r /app/requirements.txt +RUN pip install --default-timeout=100 --upgrade pip && pip install -r /app/requirements.txt # We add the current content of the git repo in the /app directory ADD . /app - +WORKDIR /app +RUN rm -rf .gitlab-ci.yml Dockerfile README.md img # We use the CMD command to start the gunicorn daemon # when we start the container. # Note the $PORT variable, we will need to define it when we start the container -CMD gunicorn -b :$PORT mysite.wsgi +CMD python manage.py runserver 0.0.0.0:$PORT ``` ### Setup Gitlab CI @@ -94,19 +90,14 @@ stages: services: - docker:dind -variables: - DOCKER_HOST: tcp://localhost:2375 - build: image: docker:latest stage: build script: - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY - - docker build -t ${CI_REGISTRY}/${CI_PROJECT_NAME}/polls:${CI_COMMIT_SHORT_SHA} . - - docker tag ${CI_REGISTRY}/${CI_PROJECT_NAME}/polls:${CI_COMMIT_SHORT_SHA} ${CI_REGISTRY}/${CI_PROJECT_NAME}/polls:latest - - docker push -- ${CI_REGISTRY}/${CI_PROJECT_NAME}/polls - tags: - - k8s + - docker build -t "$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME/polls:${CI_COMMIT_SHORT_SHA}" . + - docker tag "$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME/polls:${CI_COMMIT_SHORT_SHA}" "$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME/polls:latest" + - docker push "$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME/polls:${CI_COMMIT_SHORT_SHA}" ``` Save, commit and push; you should be abble to see your first running pipeline @@ -139,15 +130,15 @@ We do this using a `Persistent Volume Claim`. apiVersion: v1 kind: PersistentVolumeClaim metadata: -name: postgres-claim -labels: - app: postgresql + name: postgres-claim + labels: + app: postgresql spec: -accessModes: - - ReadWriteOnce -resources: - requests: - storage: 1Gi + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi ``` ##### PostgreSQL secret @@ -162,65 +153,76 @@ We are here defining the PostgreSQL basic parameters : username, password and da apiVersion: v1 kind: Secret metadata: -name: postgresql-credentials + name: postgresql-credentials type: Opaque data: -username: cG9sbHNfdXNlcgo= -password: c2xsb3BfYzNiaQo= -database: cG9sbHMK + username: cG9sbHNfdXNlcgo= + password: cG9sbHMK + database: cG9sbHMK ``` ##### PostgreSQL Deployment ```yaml -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: -name: postgresql -labels: + name: postgresql + labels: app: postgresql spec: -strategy: + replicas: 1 + selector: + matchLabels: + app: postgresql + strategy: type: Recreate -template: + template: metadata: - labels: + labels: app: postgresql tier: postgreSQL spec: - containers: - - image: postgres:9.6.2-alpine - name: postgresql + containers: + - name: postgresql + image: postgres:9.6.2-alpine 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 + - 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 + - containerPort: 5432 + name: postgresql + resources: + requests: + memory: "64Mi" + cpu: "50m" + limits: + memory: "128Mi" + cpu: "100m" volumeMounts: - - name: postgresql - mountPath: /var/lib/postgresql/data - subPath: data - volumes: - name: postgresql + mountPath: /var/lib/postgresql/data + subPath: data + volumes: + - name: postgresql persistentVolumeClaim: - claimName: postgres-claim - - name: postgresql-credentials + claimName: postgres-claim + - name: postgresql-credentials secret: - secretName: postgresql + secretName: postgresql-credentials ``` ##### PostgreSQL Service @@ -229,13 +231,13 @@ template: apiVersion: v1 kind: Service metadata: -name: postgresql -labels: + name: postgresql + labels: app: postgresql spec: -ports: + ports: - port: 5432 -selector: + selector: app: postgresql tier: postgreSQL ```` @@ -244,48 +246,61 @@ selector: ##### Deployment ```yaml -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: -name: polls -labels: - app: polls + name: polls + labels: + app: polls spec: -replicas: 3 -template: + replicas: 1 + selector: + matchLabels: + app: polls + template: metadata: - labels: + labels: app: polls spec: - containers: - name: polls-app - image: ${CI_REGISTRY}/${CI_PROJECT_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. + containers: + - name: polls-app + image: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME/polls:${CI_COMMIT_SHORT_SHA} 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 + - name: DATABASE_HOST + value: postgresql + - 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 + - name: PORT + value: "8080" ports: - containerPort: 8080 - volumes: - - name: postgresql-credentials + resources: + requests: + memory: "64Mi" + cpu: "50m" + limits: + memory: "128Mi" + cpu: "100m" + imagePullSecrets: + - name: registry-gitlab + volumes: + - name: postgresql-credentials secret: - secretName: postgresql + secretName: postgresql-credentials ``` ##### Service @@ -294,15 +309,14 @@ template: apiVersion: v1 kind: Service metadata: -name: polls -labels: + name: polls + labels: app: polls spec: -type: ClusterIP -ports: -- port: 80 - targetPort: 8080 -selector: + type: ClusterIP + ports: + - port: 8080 + selector: app: polls ``` @@ -312,57 +326,68 @@ selector: apiVersion: extensions/v1beta1 kind: Ingress metadata: -annotations: + annotations: kubernetes.io/ingress.class: traefik -labels: + labels: app: polls -name: polls + name: polls spec: -rules: -- host: https://${CI_PROJECT_NAME}.k8s-dev.pasteur.fr + rules: + - host: ${GITLAB_USER_LOGIN}.k8s-dev.pasteur.fr http: - paths: - - backend: - serviceName: polls - servicePort: 80 + paths: + - backend: + serviceName: polls + servicePort: 8080 path: / ``` ##### Kubernetes Job +Create a file `job.yaml` at the root directory of your git repository and fill it with the following definition. + We will use a `Job` in order to manage django migrations. -> Note: Kubernetes jobs are run only once opposed to `Deployments` that run continiously. +> Note: Kubernetes jobs are run only once opposed to `Deployments` that run continiously. We put it in a seperate file because a Job is immutable and cannot be updated. ```yaml +--- apiVersion: batch/v1 kind: Job metadata: -name: polls-migrations + name: polls-migrations spec: -template: - spec: - containers: - - name: django - image: ${CI_REGISTRY}/${CI_PROJECT_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 + template: + spec: + containers: + - name: django + image: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME/polls:${CI_COMMIT_SHORT_SHA} + command: ['python', '/app/manage.py', 'migrate'] + env: + - name: DATABASE_HOST + value: postgresql + - 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 + imagePullSecrets: + - name: registry-gitlab + volumes: + - name: postgresql-credentials + secret: + secretName: postgresql-credentials + backoffLimit: 5 ``` ### Setup Continuous Delivery in Gitlab CI @@ -372,17 +397,18 @@ deploy: stage: deploy image: registry-gitlab.pasteur.fr/dsi-tools/docker-images:docker_kubernetes_image variables: - NAMESPACE: "mynamespace" + NAMESPACE: "<your gitlab user>-django" environment: - name: mynamespace - url: https://${CI_PROJECT_NAME}.k8s-dev.pasteur.fr + name: <your gitlab user>-django + url: https://<your gitlab user>-django.k8s-dev.pasteur.fr script: + - yum install -y gettext - 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 - + - envsubst < manifest.yaml | kubectl apply -n ${NAMESPACE} -f - + - kubectl delete job polls-migrations -n ${NAMESPACE} --ignore-not-found=true + - envsubst < job.yaml | kubectl apply -n ${NAMESPACE} -f - - kubectl patch deployment polls -p "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"date\":\"`date +'%s'`\"}}}}}" - tags: - - k8s ``` ## What else ? @@ -396,4 +422,4 @@ deploy: ### Grafana : Metrics and Logs ### Best Practices -Always use Gitlab \ No newline at end of file +Always use Gitlab !!! \ No newline at end of file -- GitLab