Commit f2b6c6ca authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'extract_auto_deploy_into_base_image' into 'master'

Extract Auto DevOps deploy functions in a base image

Closes #50286

See merge request gitlab-org/gitlab-ce!30404
parents 861959ca b297cdcb
---
title: Extract Auto DevOps deploy functions into a base image
merge_request: 30404
author:
type: changed
...@@ -50,9 +50,6 @@ variables: ...@@ -50,9 +50,6 @@ variables:
POSTGRES_DB: $CI_ENVIRONMENT_SLUG POSTGRES_DB: $CI_ENVIRONMENT_SLUG
POSTGRES_VERSION: 9.6.2 POSTGRES_VERSION: 9.6.2
KUBERNETES_VERSION: 1.11.10
HELM_VERSION: 2.14.0
DOCKER_DRIVER: overlay2 DOCKER_DRIVER: overlay2
ROLLOUT_RESOURCE_TYPE: deployment ROLLOUT_RESOURCE_TYPE: deployment
......
.auto-deploy:
image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.1.0"
review: review:
extends: .auto-deploy
stage: review stage: review
script: script:
- check_kube_domain - auto-deploy check_kube_domain
- install_dependencies - auto-deploy download_chart
- download_chart - auto-deploy ensure_namespace
- ensure_namespace - auto-deploy initialize_tiller
- initialize_tiller - auto-deploy create_secret
- create_secret - auto-deploy deploy
- deploy - auto-deploy persist_environment_url
- persist_environment_url
environment: environment:
name: review/$CI_COMMIT_REF_NAME name: review/$CI_COMMIT_REF_NAME
url: http://$CI_PROJECT_ID-$CI_ENVIRONMENT_SLUG.$KUBE_INGRESS_BASE_DOMAIN url: http://$CI_PROJECT_ID-$CI_ENVIRONMENT_SLUG.$KUBE_INGRESS_BASE_DOMAIN
...@@ -27,13 +30,13 @@ review: ...@@ -27,13 +30,13 @@ review:
- $REVIEW_DISABLED - $REVIEW_DISABLED
stop_review: stop_review:
extends: .auto-deploy
stage: cleanup stage: cleanup
variables: variables:
GIT_STRATEGY: none GIT_STRATEGY: none
script: script:
- install_dependencies - auto-deploy initialize_tiller
- initialize_tiller - auto-deploy delete
- delete
environment: environment:
name: review/$CI_COMMIT_REF_NAME name: review/$CI_COMMIT_REF_NAME
action: stop action: stop
...@@ -57,15 +60,15 @@ stop_review: ...@@ -57,15 +60,15 @@ stop_review:
# STAGING_ENABLED. # STAGING_ENABLED.
staging: staging:
extends: .auto-deploy
stage: staging stage: staging
script: script:
- check_kube_domain - auto-deploy check_kube_domain
- install_dependencies - auto-deploy download_chart
- download_chart - auto-deploy ensure_namespace
- ensure_namespace - auto-deploy initialize_tiller
- initialize_tiller - auto-deploy create_secret
- create_secret - auto-deploy deploy
- deploy
environment: environment:
name: staging name: staging
url: http://$CI_PROJECT_PATH_SLUG-staging.$KUBE_INGRESS_BASE_DOMAIN url: http://$CI_PROJECT_PATH_SLUG-staging.$KUBE_INGRESS_BASE_DOMAIN
...@@ -81,15 +84,15 @@ staging: ...@@ -81,15 +84,15 @@ staging:
# CANARY_ENABLED. # CANARY_ENABLED.
canary: canary:
extends: .auto-deploy
stage: canary stage: canary
script: script:
- check_kube_domain - auto-deploy check_kube_domain
- install_dependencies - auto-deploy download_chart
- download_chart - auto-deploy ensure_namespace
- ensure_namespace - auto-deploy initialize_tiller
- initialize_tiller - auto-deploy create_secret
- create_secret - auto-deploy deploy canary
- deploy canary
environment: environment:
name: production name: production
url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN
...@@ -102,18 +105,18 @@ canary: ...@@ -102,18 +105,18 @@ canary:
- $CANARY_ENABLED - $CANARY_ENABLED
.production: &production_template .production: &production_template
extends: .auto-deploy
stage: production stage: production
script: script:
- check_kube_domain - auto-deploy check_kube_domain
- install_dependencies - auto-deploy download_chart
- download_chart - auto-deploy ensure_namespace
- ensure_namespace - auto-deploy initialize_tiller
- initialize_tiller - auto-deploy create_secret
- create_secret - auto-deploy deploy
- deploy - auto-deploy delete canary
- delete canary - auto-deploy delete rollout
- delete rollout - auto-deploy persist_environment_url
- persist_environment_url
environment: environment:
name: production name: production
url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN
...@@ -152,17 +155,17 @@ production_manual: ...@@ -152,17 +155,17 @@ production_manual:
# This job implements incremental rollout on for every push to `master`. # This job implements incremental rollout on for every push to `master`.
.rollout: &rollout_template .rollout: &rollout_template
extends: .auto-deploy
script: script:
- check_kube_domain - auto-deploy check_kube_domain
- install_dependencies - auto-deploy download_chart
- download_chart - auto-deploy ensure_namespace
- ensure_namespace - auto-deploy initialize_tiller
- initialize_tiller - auto-deploy create_secret
- create_secret - auto-deploy deploy rollout $ROLLOUT_PERCENTAGE
- deploy rollout $ROLLOUT_PERCENTAGE - auto-deploy scale stable $((100-ROLLOUT_PERCENTAGE))
- scale stable $((100-ROLLOUT_PERCENTAGE)) - auto-deploy delete canary
- delete canary - auto-deploy persist_environment_url
- persist_environment_url
environment: environment:
name: production name: production
url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN
...@@ -240,331 +243,3 @@ rollout 100%: ...@@ -240,331 +243,3 @@ rollout 100%:
<<: *manual_rollout_template <<: *manual_rollout_template
<<: *production_template <<: *production_template
allow_failure: false allow_failure: false
.deploy_helpers: &deploy_helpers |
[[ "$TRACE" ]] && set -x
export RELEASE_NAME=${HELM_RELEASE_NAME:-$CI_ENVIRONMENT_SLUG}
auto_database_url=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${RELEASE_NAME}-postgres:5432/${POSTGRES_DB}
export DATABASE_URL=${DATABASE_URL-$auto_database_url}
export TILLER_NAMESPACE=$KUBE_NAMESPACE
function get_replicas() {
track="${1:-stable}"
percentage="${2:-100}"
env_track=$( echo $track | tr -s '[:lower:]' '[:upper:]' )
env_slug=$( echo ${CI_ENVIRONMENT_SLUG//-/_} | tr -s '[:lower:]' '[:upper:]' )
if [[ "$track" == "stable" ]] || [[ "$track" == "rollout" ]]; then
# for stable track get number of replicas from `PRODUCTION_REPLICAS`
eval new_replicas=\$${env_slug}_REPLICAS
if [[ -z "$new_replicas" ]]; then
new_replicas=$REPLICAS
fi
else
# for all tracks get number of replicas from `CANARY_PRODUCTION_REPLICAS`
eval new_replicas=\$${env_track}_${env_slug}_REPLICAS
if [[ -z "$new_replicas" ]]; then
eval new_replicas=\${env_track}_REPLICAS
fi
fi
replicas="${new_replicas:-1}"
replicas="$(($replicas * $percentage / 100))"
# always return at least one replicas
if [[ $replicas -gt 0 ]]; then
echo "$replicas"
else
echo 1
fi
}
# Extracts variables prefixed with K8S_SECRET_
# and creates a Kubernetes secret.
#
# e.g. If we have the following environment variables:
# K8S_SECRET_A=value1
# K8S_SECRET_B=multi\ word\ value
#
# Then we will create a secret with the following key-value pairs:
# data:
# A: dmFsdWUxCg==
# B: bXVsdGkgd29yZCB2YWx1ZQo=
function create_application_secret() {
track="${1-stable}"
export APPLICATION_SECRET_NAME=$(application_secret_name "$track")
env | sed -n "s/^K8S_SECRET_\(.*\)$/\1/p" > k8s_prefixed_variables
kubectl create secret \
-n "$KUBE_NAMESPACE" generic "$APPLICATION_SECRET_NAME" \
--from-env-file k8s_prefixed_variables -o yaml --dry-run |
kubectl replace -n "$KUBE_NAMESPACE" --force -f -
export APPLICATION_SECRET_CHECKSUM=$(cat k8s_prefixed_variables | sha256sum | cut -d ' ' -f 1)
rm k8s_prefixed_variables
}
function deploy_name() {
name="$RELEASE_NAME"
track="${1-stable}"
if [[ "$track" != "stable" ]]; then
name="$name-$track"
fi
echo $name
}
function application_secret_name() {
track="${1-stable}"
name=$(deploy_name "$track")
echo "${name}-secret"
}
function deploy() {
track="${1-stable}"
percentage="${2:-100}"
name=$(deploy_name "$track")
if [[ -z "$CI_COMMIT_TAG" ]]; then
image_repository=${CI_APPLICATION_REPOSITORY:-$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG}
image_tag=${CI_APPLICATION_TAG:-$CI_COMMIT_SHA}
else
image_repository=${CI_APPLICATION_REPOSITORY:-$CI_REGISTRY_IMAGE}
image_tag=${CI_APPLICATION_TAG:-$CI_COMMIT_TAG}
fi
service_enabled="true"
postgres_enabled="$POSTGRES_ENABLED"
# if track is different than stable,
# re-use all attached resources
if [[ "$track" != "stable" ]]; then
service_enabled="false"
postgres_enabled="false"
fi
replicas=$(get_replicas "$track" "$percentage")
if [[ "$CI_PROJECT_VISIBILITY" != "public" ]]; then
secret_name='gitlab-registry'
else
secret_name=''
fi
create_application_secret "$track"
env_slug=$(echo ${CI_ENVIRONMENT_SLUG//-/_} | tr -s '[:lower:]' '[:upper:]')
eval env_ADDITIONAL_HOSTS=\$${env_slug}_ADDITIONAL_HOSTS
if [ -n "$env_ADDITIONAL_HOSTS" ]; then
additional_hosts="{$env_ADDITIONAL_HOSTS}"
elif [ -n "$ADDITIONAL_HOSTS" ]; then
additional_hosts="{$ADDITIONAL_HOSTS}"
fi
if [[ -n "$DB_INITIALIZE" && -z "$(helm ls -q "^$name$")" ]]; then
echo "Deploying first release with database initialization..."
helm upgrade --install \
--wait \
--set service.enabled="$service_enabled" \
--set gitlab.app="$CI_PROJECT_PATH_SLUG" \
--set gitlab.env="$CI_ENVIRONMENT_SLUG" \
--set releaseOverride="$RELEASE_NAME" \
--set image.repository="$image_repository" \
--set image.tag="$image_tag" \
--set image.pullPolicy=IfNotPresent \
--set image.secrets[0].name="$secret_name" \
--set application.track="$track" \
--set application.database_url="$DATABASE_URL" \
--set application.secretName="$APPLICATION_SECRET_NAME" \
--set application.secretChecksum="$APPLICATION_SECRET_CHECKSUM" \
--set service.commonName="le-$CI_PROJECT_ID.$KUBE_INGRESS_BASE_DOMAIN" \
--set service.url="$CI_ENVIRONMENT_URL" \
--set service.additionalHosts="$additional_hosts" \
--set replicaCount="$replicas" \
--set postgresql.enabled="$postgres_enabled" \
--set postgresql.nameOverride="postgres" \
--set postgresql.postgresUser="$POSTGRES_USER" \
--set postgresql.postgresPassword="$POSTGRES_PASSWORD" \
--set postgresql.postgresDatabase="$POSTGRES_DB" \
--set postgresql.imageTag="$POSTGRES_VERSION" \
--set application.initializeCommand="$DB_INITIALIZE" \
$HELM_UPGRADE_EXTRA_ARGS \
--namespace="$KUBE_NAMESPACE" \
"$name" \
chart/
echo "Deploying second release..."
helm upgrade --reuse-values \
--wait \
--set application.initializeCommand="" \
--set application.migrateCommand="$DB_MIGRATE" \
$HELM_UPGRADE_EXTRA_ARGS \
--namespace="$KUBE_NAMESPACE" \
"$name" \
chart/
else
echo "Deploying new release..."
helm upgrade --install \
--wait \
--set service.enabled="$service_enabled" \
--set gitlab.app="$CI_PROJECT_PATH_SLUG" \
--set gitlab.env="$CI_ENVIRONMENT_SLUG" \
--set releaseOverride="$RELEASE_NAME" \
--set image.repository="$image_repository" \
--set image.tag="$image_tag" \
--set image.pullPolicy=IfNotPresent \
--set image.secrets[0].name="$secret_name" \
--set application.track="$track" \
--set application.database_url="$DATABASE_URL" \
--set application.secretName="$APPLICATION_SECRET_NAME" \
--set application.secretChecksum="$APPLICATION_SECRET_CHECKSUM" \
--set service.commonName="le-$CI_PROJECT_ID.$KUBE_INGRESS_BASE_DOMAIN" \
--set service.url="$CI_ENVIRONMENT_URL" \
--set service.additionalHosts="$additional_hosts" \
--set replicaCount="$replicas" \
--set postgresql.enabled="$postgres_enabled" \
--set postgresql.nameOverride="postgres" \
--set postgresql.postgresUser="$POSTGRES_USER" \
--set postgresql.postgresPassword="$POSTGRES_PASSWORD" \
--set postgresql.postgresDatabase="$POSTGRES_DB" \
--set postgresql.imageTag="$POSTGRES_VERSION" \
--set application.migrateCommand="$DB_MIGRATE" \
$HELM_UPGRADE_EXTRA_ARGS \
--namespace="$KUBE_NAMESPACE" \
"$name" \
chart/
fi
if [[ -z "$ROLLOUT_STATUS_DISABLED" ]]; then
kubectl rollout status -n "$KUBE_NAMESPACE" -w "$ROLLOUT_RESOURCE_TYPE/$name"
fi
}
function scale() {
track="${1-stable}"
percentage="${2-100}"
name=$(deploy_name "$track")
replicas=$(get_replicas "$track" "$percentage")
if [[ -n "$(helm ls -q "^$name$")" ]]; then
helm upgrade --reuse-values \
--wait \
--set replicaCount="$replicas" \
--namespace="$KUBE_NAMESPACE" \
"$name" \
chart/
fi
}
function install_dependencies() {
apk add -U openssl curl tar gzip bash ca-certificates git
curl -sSL -o /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
curl -sSL -O https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk
apk add glibc-2.28-r0.apk
rm glibc-2.28-r0.apk
curl -sS "https://kubernetes-helm.storage.googleapis.com/helm-v${HELM_VERSION}-linux-amd64.tar.gz" | tar zx
mv linux-amd64/helm /usr/bin/
mv linux-amd64/tiller /usr/bin/
helm version --client
tiller -version
curl -sSL -o /usr/bin/kubectl "https://storage.googleapis.com/kubernetes-release/release/v${KUBERNETES_VERSION}/bin/linux/amd64/kubectl"
chmod +x /usr/bin/kubectl
kubectl version --client
}
function download_chart() {
if [[ ! -d chart ]]; then
auto_chart=${AUTO_DEVOPS_CHART:-gitlab/auto-deploy-app}
auto_chart_name=$(basename $auto_chart)
auto_chart_name=${auto_chart_name%.tgz}
auto_chart_name=${auto_chart_name%.tar.gz}
else
auto_chart="chart"
auto_chart_name="chart"
fi
helm init --client-only
helm repo add ${AUTO_DEVOPS_CHART_REPOSITORY_NAME:-gitlab} ${AUTO_DEVOPS_CHART_REPOSITORY:-https://charts.gitlab.io} ${AUTO_DEVOPS_CHART_REPOSITORY_USERNAME:+"--username" "$AUTO_DEVOPS_CHART_REPOSITORY_USERNAME"} ${AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD:+"--password" "$AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD"}
if [[ ! -d "$auto_chart" ]]; then
helm fetch ${auto_chart} --untar
fi
if [ "$auto_chart_name" != "chart" ]; then
mv ${auto_chart_name} chart
fi
helm dependency update chart/
helm dependency build chart/
}
function ensure_namespace() {
kubectl get namespace "$KUBE_NAMESPACE" || kubectl create namespace "$KUBE_NAMESPACE"
}
function check_kube_domain() {
if [[ -z "$KUBE_INGRESS_BASE_DOMAIN" ]]; then
echo "In order to deploy or use Review Apps,"
echo "KUBE_INGRESS_BASE_DOMAIN variables must be set"
echo "From 11.8, you can set KUBE_INGRESS_BASE_DOMAIN in cluster settings"
echo "or by defining a variable at group or project level."
echo "You can also manually add it in .gitlab-ci.yml"
false
else
true
fi
}
function initialize_tiller() {
echo "Checking Tiller..."
export HELM_HOST="localhost:44134"
tiller -listen ${HELM_HOST} -alsologtostderr > /dev/null 2>&1 &
echo "Tiller is listening on ${HELM_HOST}"
if ! helm version --debug; then
echo "Failed to init Tiller."
return 1
fi
echo ""
}
function create_secret() {
echo "Create secret..."
if [[ "$CI_PROJECT_VISIBILITY" == "public" ]]; then
return
fi
kubectl create secret -n "$KUBE_NAMESPACE" \
docker-registry gitlab-registry \
--docker-server="$CI_REGISTRY" \
--docker-username="${CI_DEPLOY_USER:-$CI_REGISTRY_USER}" \
--docker-password="${CI_DEPLOY_PASSWORD:-$CI_REGISTRY_PASSWORD}" \
--docker-email="$GITLAB_USER_EMAIL" \
-o yaml --dry-run | kubectl replace -n "$KUBE_NAMESPACE" --force -f -
}
function persist_environment_url() {
echo $CI_ENVIRONMENT_URL > environment_url.txt
}
function delete() {
track="${1-stable}"
name=$(deploy_name "$track")
if [[ -n "$(helm ls -q "^$name$")" ]]; then
helm delete --purge "$name"
fi
secret_name=$(application_secret_name "$track")
kubectl delete secret --ignore-not-found -n "$KUBE_NAMESPACE" "$secret_name"
}
before_script:
- *deploy_helpers
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment