CI: Add k8s deployment

This commit is contained in:
Igor Scheller 2020-05-09 13:08:53 +02:00 committed by msquare
parent 4995aa2a0b
commit 9e507eda66
4 changed files with 342 additions and 13 deletions

View File

@ -20,6 +20,11 @@ stages:
- test
- release
- deploy
- deploy-production
#
# Validation
#
check-style:
image: composer:latest
@ -45,6 +50,10 @@ validate-yarn:
script:
- pjv
#
# Build
#
.docker_template: &docker_definition
image: docker:18
services:
@ -78,6 +87,10 @@ build-image:
- docker build --pull --build-arg VERSION="${VERSION}" -t "${TEST_IMAGE}" -f docker/Dockerfile .
- docker push "${TEST_IMAGE}"
#
# Test
#
audit-composer:
image: ${TEST_IMAGE}
stage: test
@ -125,6 +138,10 @@ test:
after_script:
- '"${DOCROOT}/bin/migrate" down'
#
# Release
#
release-image:
<<: *docker_definition
stage: release
@ -146,11 +163,27 @@ release-image-nginx:
- master
.deploy_template: &deploy_definition
stage: deploy
stage: release
image: ${TEST_IMAGE}
before_script:
- apk add -q bash rsync openssh-client
build-release-file:
<<: *deploy_definition
stage: release
artifacts:
name: release_${CI_COMMIT_REF_SLUG}_${CI_JOB_ID}_${CI_COMMIT_SHA}
expire_in: 1 week
paths:
- ./release/
script:
- rsync -vAax "${DOCROOT}" "${DOCROOT}/.babelrc" "${DOCROOT}/.browserslistrc" release/
- rsync -vAax public/assets release/public/
#
# Deploy staging
#
.deploy_template_script:
# Configure SSH
- &deploy_template_script |-
@ -158,20 +191,9 @@ release-image-nginx:
rsync -vAax public/assets ${DOCROOT}/public/
cd "${DOCROOT}"
build-release-file:
deploy:
<<: *deploy_definition
stage: deploy
artifacts:
name: "release_${CI_COMMIT_REF_SLUG}_${CI_JOB_ID}_${CI_COMMIT_SHA}"
expire_in: 1 week
paths:
- ./release/
script:
- rsync -vAax "${DOCROOT}" "${DOCROOT}/.babelrc" "${DOCROOT}/.browserslistrc" release/
- rsync -vAax public/assets release/public/
deploy-staging:
<<: *deploy_definition
environment:
name: staging
only:
@ -187,8 +209,84 @@ deploy-staging:
# Deploy to server
- ./bin/deploy.sh -r "${STAGING_REMOTE}" -p "${STAGING_REMOTE_PATH}" -i "${CI_JOB_ID}-${CI_COMMIT_SHA}"
.kubectl_deployment: &kubectl_deployment
stage: deploy
image:
name: bitnami/kubectl:latest
entrypoint: ['']
before_script:
- &kubectl_deployment_script if [[ -z "${KUBE_INGRESS_BASE_DOMAIN}" ]]; then echo "Skipping deployment"; exit; fi
.deploy_k8s: &deploy_k8s
<<: *kubectl_deployment
artifacts:
name: deployment.yaml
expire_in: 1 day
when: always
paths:
- deployment.yaml
script:
# CI_ENVIRONMENT_URL is the URL configured in the GitLab environment
- export CI_ENVIRONMENT_URL="${CI_ENVIRONMENT_URL:-https://${CI_PROJECT_PATH_SLUG}.${KUBE_INGRESS_BASE_DOMAIN}/}"
- export CI_IMAGE=$RELEASE_IMAGE
- export CI_IMAGE_NGINX=$RELEASE_IMAGE_NGINX
- export CI_INGRESS_DOMAIN=$(echo "$CI_ENVIRONMENT_URL" | grep -oP '(?:https?://)?\K([^/]+)' | head -n1)
- export CI_INGRESS_PATH=$(echo "$CI_ENVIRONMENT_URL" | grep -oP '(?:https?://)?(?:[^/])+\K(.*)')
- export CI_KUBE_NAMESPACE=$KUBE_NAMESPACE
# Any available storage class like longhorn
- export CI_PVC_SC=${CI_PVC_SC:-"${CI_PVC_SC_LOCAL:-local-path}"}
- export CI_REPLICAS=${CI_REPLICAS_REVIEW:-${CI_REPLICAS:-2}}
- export CI_APP_NAME=${CI_APP_NAME:-Engelsystem}
- cp deployment.tpl.yaml deployment.yaml
- for env in ${!CI_*}; do sed -i "s#<${env}>#$(echo "${!env}"|head -n1)#g" deployment.yaml; done
- echo "Deploying to ${CI_ENVIRONMENT_URL}"
- kubectl apply -f deployment.yaml
- >-
kubectl -n $CI_KUBE_NAMESPACE wait --for=condition=Ready pods --timeout=${CI_WAIT_TIMEOUT:-5}m
-l app=$CI_PROJECT_PATH_SLUG -l tier=database
- >-
kubectl -n $CI_KUBE_NAMESPACE wait --for=condition=Ready pods --timeout=${CI_WAIT_TIMEOUT:-5}m
-l app=$CI_PROJECT_PATH_SLUG -l tier=application -l commit=$CI_COMMIT_SHORT_SHA
.deploy_k8s_stop: &deploy_k8s_stop
<<: *kubectl_deployment
variables:
GIT_STRATEGY: none
dependencies: []
when: manual
script:
- kubectl delete all,ingress,pvc -l app=$CI_PROJECT_PATH_SLUG -l environment=$CI_ENVIRONMENT_SLUG
deploy-k8s-review:
<<: *deploy_k8s
environment:
name: review/${CI_COMMIT_REF_NAME}
on_stop: stop-k8s-review
auto_stop_in: 1 week
url: https://${CI_PROJECT_PATH_SLUG}-review.${KUBE_INGRESS_BASE_DOMAIN}/${CI_COMMIT_REF_SLUG}
variables:
CI_REPLICAS_REVIEW: 1
CI_APP_NAME: review/${CI_COMMIT_REF_NAME}
before_script:
- *kubectl_deployment_script
- RELEASE_IMAGE=$TEST_IMAGE
- RELEASE_IMAGE_NGINX=$TEST_IMAGE_NGINX
stop-k8s-review:
<<: *deploy_k8s_stop
environment:
name: review/${CI_COMMIT_REF_NAME}
action: stop
#
# Deploy production
#
deploy-production:
<<: *deploy_definition
stage: deploy-production
environment:
name: production
when: manual
@ -204,3 +302,22 @@ deploy-production:
- *deploy_template_script
# Deploy to server
- ./bin/deploy.sh -r "${PRODUCTION_REMOTE}" -p "${PRODUCTION_REMOTE_PATH}" -i "${CI_JOB_ID}-${CI_COMMIT_SHA}"
deploy-k8s-production:
<<: *deploy_k8s
stage: deploy-production
environment:
name: production
on_stop: stop-k8s-production
when: manual
only:
- master
stop-k8s-production:
<<: *deploy_k8s_stop
stage: deploy-production
only:
- master
environment:
name: production
action: stop

199
deployment.tpl.yaml Normal file
View File

@ -0,0 +1,199 @@
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: engelsystem-db
labels:
app: <CI_PROJECT_PATH_SLUG>
environment: <CI_ENVIRONMENT_SLUG>
spec:
accessModes:
- ReadWriteOnce
storageClassName: <CI_PVC_SC>
resources:
requests:
storage: 2Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: database
labels:
app: <CI_PROJECT_PATH_SLUG>
environment: <CI_ENVIRONMENT_SLUG>
spec:
replicas: 1
selector:
matchLabels:
app: <CI_PROJECT_PATH_SLUG>
environment: <CI_ENVIRONMENT_SLUG>
template:
metadata:
labels:
app: <CI_PROJECT_PATH_SLUG>
environment: <CI_ENVIRONMENT_SLUG>
tier: database
spec:
containers:
- image: mariadb:10.2
name: database
imagePullPolicy: Always
env:
- name: MYSQL_DATABASE
value: engelsystem
- name: MYSQL_USER
value: engelsystem
- name: MYSQL_PASSWORD
value: engelsystem
- name: MYSQL_RANDOM_ROOT_PASSWORD
value: '1'
- name: MYSQL_INITDB_SKIP_TZINFO
value: 'yes'
volumeMounts:
- mountPath: /var/lib/mysql
name: data
volumes:
- name: data
persistentVolumeClaim:
claimName: engelsystem-db
---
apiVersion: v1
kind: Service
metadata:
name: database
labels:
app: <CI_PROJECT_PATH_SLUG>
environment: <CI_ENVIRONMENT_SLUG>
commit: <CI_COMMIT_SHORT_SHA>
spec:
type: ClusterIP
ports:
- port: 3306
targetPort: 3306
name: database
selector:
app: <CI_PROJECT_PATH_SLUG>
environment: <CI_ENVIRONMENT_SLUG>
tier: database
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: engelsystem
labels:
app: <CI_PROJECT_PATH_SLUG>
environment: <CI_ENVIRONMENT_SLUG>
commit: <CI_COMMIT_SHORT_SHA>
spec:
replicas: <CI_REPLICAS>
selector:
matchLabels:
app: <CI_PROJECT_PATH_SLUG>
environment: <CI_ENVIRONMENT_SLUG>
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
template:
metadata:
labels:
app: <CI_PROJECT_PATH_SLUG>
environment: <CI_ENVIRONMENT_SLUG>
tier: application
commit: <CI_COMMIT_SHORT_SHA>
annotations:
app.gitlab.com/app: <CI_PROJECT_PATH_SLUG>
app.gitlab.com/env: <CI_ENVIRONMENT_SLUG>
commit: <CI_COMMIT_SHORT_SHA>
spec:
initContainers:
- image: <CI_IMAGE>
name: engelsystem-migrate
imagePullPolicy: Always
command:
- sh
- -c
- while ! bin/migrate up; do sleep 1; done
env:
- name: MYSQL_HOST
value: database
- name: MYSQL_DATABASE
value: engelsystem
- name: MYSQL_USER
value: engelsystem
- name: MYSQL_PASSWORD
value: engelsystem
containers:
- image: <CI_IMAGE>
name: engelsystem-fpm
imagePullPolicy: Always
env:
- name: MYSQL_HOST
value: database
- name: MYSQL_DATABASE
value: engelsystem
- name: MYSQL_USER
value: engelsystem
- name: MYSQL_PASSWORD
value: engelsystem
- name: APP_URL
value: <CI_ENVIRONMENT_URL>
- name: APP_NAME
value: '<CI_APP_NAME>'
- image: <CI_IMAGE_NGINX>
name: engelsystem-nginx
imagePullPolicy: Always
env:
- name: PHP_FPM_HOST
value: localhost
---
apiVersion: v1
kind: Service
metadata:
name: engelsystem
labels:
app: <CI_PROJECT_PATH_SLUG>
environment: <CI_ENVIRONMENT_SLUG>
commit: <CI_COMMIT_SHORT_SHA>
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
name: engelsystem
selector:
app: <CI_PROJECT_PATH_SLUG>
environment: <CI_ENVIRONMENT_SLUG>
tier: application
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: engelsystem-ingress
annotations:
kubernetes.io/tls-acme: 'true'
kubernetes.io/ingress.class: 'nginx'
nginx.ingress.kubernetes.io/rewrite-target: /$1
labels:
app: <CI_PROJECT_PATH_SLUG>
environment: <CI_ENVIRONMENT_SLUG>
commit: <CI_COMMIT_SHORT_SHA>
spec:
tls:
- hosts:
- <CI_INGRESS_DOMAIN>
secretName: <CI_INGRESS_DOMAIN>
rules:
- host: <CI_INGRESS_DOMAIN>
http:
paths:
- path: '<CI_INGRESS_PATH>/?(.*)'
backend:
serviceName: engelsystem
servicePort: 80

View File

@ -1,4 +1,6 @@
FROM nginx:alpine as es_nginx
COPY docker/nginx/entrypoint.sh /
ENTRYPOINT /entrypoint.sh
RUN mkdir -p /var/www/public/ && touch /var/www/public/index.php
COPY docker/nginx/nginx.conf /etc/nginx/nginx.conf

11
docker/nginx/entrypoint.sh Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env sh
set -e
sed -i "s/es_php_fpm:/${PHP_FPM_HOST:-es_php_fpm}:/g" /etc/nginx/nginx.conf
# If first arg starts with a `-` or is empty
if [[ "${1#-}" != "${1}" ]] || [[ -z "${1}" ]]; then
set -- nginx -g 'daemon off;' "$@"
fi
exec "$@"