Created
September 26, 2017 17:10
-
-
Save bborysenko/674c5cf8d3d653df56a2442f413519ed to your computer and use it in GitHub Desktop.
Gitlab CI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # This file is a template, and might need editing before it works on your project. | |
| # Auto DevOps | |
| # This CI/CD configuration provides a standard pipeline for | |
| # * building a Docker image (using a buildpack if necessary), | |
| # * storing the image in the container registry, | |
| # * running tests from a buildpack, | |
| # * running code quality analysis, | |
| # * creating a review app for each topic branch, | |
| # * and continuous deployment to production | |
| # | |
| # In order to deploy, you must have a Kubernetes cluster configured either | |
| # via a project integration, or via group/project variables. | |
| # AUTO_DEVOPS_DOMAIN must also be set as a variable at the group or project | |
| # level, or manually added below. | |
| # | |
| # If you want to deploy to staging first, or enable canary deploys, | |
| # uncomment the relevant jobs in the pipeline below. | |
| # | |
| # If Auto DevOps fails to detect the proper buildpack, or if you want to | |
| # specify a custom buildpack, set a project variable `BUILDPACK_URL` to the | |
| # repository URL of the buildpack. | |
| # e.g. BUILDPACK_URL=https://github.com/heroku/heroku-buildpack-ruby.git#v142 | |
| # If you need multiple buildpacks, add a file to your project called | |
| # `.buildpacks` that contains the URLs, one on each line, in order. | |
| # Note: Auto CI does not work with multiple buildpacks yet | |
| image: alpine:latest | |
| variables: | |
| # AUTO_DEVOPS_DOMAIN is the application deployment domain and should be set as a variable at the group or project level. | |
| # AUTO_DEVOPS_DOMAIN: domain.example.com | |
| POSTGRES_USER: user | |
| POSTGRES_PASSWORD: testing-password | |
| POSTGRES_ENABLED: "true" | |
| POSTGRES_DB: $CI_ENVIRONMENT_SLUG | |
| stages: | |
| - build | |
| - test | |
| - review | |
| - staging | |
| - canary | |
| - production | |
| - cleanup | |
| build: | |
| stage: build | |
| image: docker:git | |
| services: | |
| - docker:dind | |
| variables: | |
| DOCKER_DRIVER: overlay2 | |
| script: | |
| - setup_docker | |
| - build | |
| only: | |
| - branches | |
| test: | |
| services: | |
| - postgres:latest | |
| variables: | |
| POSTGRES_DB: test | |
| stage: test | |
| image: gliderlabs/herokuish:latest | |
| script: | |
| - setup_test_db | |
| - cp -R . /tmp/app | |
| - /bin/herokuish buildpack test | |
| only: | |
| - branches | |
| codequality: | |
| image: docker:latest | |
| variables: | |
| DOCKER_DRIVER: overlay2 | |
| allow_failure: true | |
| services: | |
| - docker:dind | |
| script: | |
| - setup_docker | |
| - codeclimate | |
| artifacts: | |
| paths: [codeclimate.json] | |
| review: | |
| stage: review | |
| script: | |
| - check_kube_domain | |
| - install_dependencies | |
| - download_chart | |
| - ensure_namespace | |
| - install_tiller | |
| - create_secret | |
| - deploy | |
| environment: | |
| name: review/$CI_COMMIT_REF_NAME | |
| url: http://$CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_SLUG.$AUTO_DEVOPS_DOMAIN | |
| on_stop: stop_review | |
| only: | |
| refs: | |
| - branches | |
| kubernetes: active | |
| except: | |
| - master | |
| stop_review: | |
| stage: cleanup | |
| variables: | |
| GIT_STRATEGY: none | |
| script: | |
| - install_dependencies | |
| - delete | |
| environment: | |
| name: review/$CI_COMMIT_REF_NAME | |
| action: stop | |
| when: manual | |
| allow_failure: true | |
| only: | |
| refs: | |
| - branches | |
| kubernetes: active | |
| except: | |
| - master | |
| # Keys that start with a dot (.) will not be processed by GitLab CI. | |
| # Staging and canary jobs are disabled by default, to enable them | |
| # remove the dot (.) before the job name. | |
| # https://docs.gitlab.com/ee/ci/yaml/README.html#hidden-keys | |
| # Staging deploys are disabled by default since | |
| # continuous deployment to production is enabled by default | |
| # If you prefer to automatically deploy to staging and | |
| # only manually promote to production, enable this job by removing the dot (.), | |
| # and uncomment the `when: manual` line in the `production` job. | |
| .staging: | |
| stage: staging | |
| script: | |
| - check_kube_domain | |
| - install_dependencies | |
| - download_chart | |
| - ensure_namespace | |
| - install_tiller | |
| - create_secret | |
| - deploy | |
| environment: | |
| name: staging | |
| url: http://$CI_PROJECT_PATH_SLUG-staging.$AUTO_DEVOPS_DOMAIN | |
| only: | |
| refs: | |
| - master | |
| kubernetes: active | |
| # Canaries are disabled by default, but if you want them, | |
| # and know what the downsides are, enable this job by removing the dot (.), | |
| # and uncomment the `when: manual` line in the `production` job. | |
| .canary: | |
| stage: canary | |
| script: | |
| - check_kube_domain | |
| - install_dependencies | |
| - download_chart | |
| - ensure_namespace | |
| - install_tiller | |
| - create_secret | |
| - deploy canary | |
| environment: | |
| name: production | |
| url: http://$CI_PROJECT_PATH_SLUG.$AUTO_DEVOPS_DOMAIN | |
| when: manual | |
| only: | |
| refs: | |
| - master | |
| kubernetes: active | |
| # This job continuously deploys to production on every push to `master`. | |
| # To make this a manual process, either because you're enabling `staging` | |
| # or `canary` deploys, or you simply want more control over when you deploy | |
| # to production, uncomment the `when: manual` line in the `production` job. | |
| production: | |
| stage: production | |
| script: | |
| - check_kube_domain | |
| - install_dependencies | |
| - download_chart | |
| - ensure_namespace | |
| - install_tiller | |
| - create_secret | |
| - deploy | |
| - delete canary | |
| environment: | |
| name: production | |
| url: http://$CI_PROJECT_PATH_SLUG.$AUTO_DEVOPS_DOMAIN | |
| # when: manual | |
| only: | |
| refs: | |
| - master | |
| kubernetes: active | |
| # --------------------------------------------------------------------------- | |
| .auto_devops: &auto_devops | | |
| # Auto DevOps variables and functions | |
| [[ "$TRACE" ]] && set -x | |
| auto_database_url=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${CI_ENVIRONMENT_SLUG}-postgres:5432/${POSTGRES_DB} | |
| export DATABASE_URL=${DATABASE_URL-$auto_database_url} | |
| export CI_APPLICATION_REPOSITORY=$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG | |
| export CI_APPLICATION_TAG=$CI_COMMIT_SHA | |
| export CI_CONTAINER_NAME=ci_job_build_${CI_JOB_ID} | |
| export TILLER_NAMESPACE=$KUBE_NAMESPACE | |
| function codeclimate() { | |
| cc_opts="--env CODECLIMATE_CODE="$PWD" \ | |
| --volume "$PWD":/code \ | |
| --volume /var/run/docker.sock:/var/run/docker.sock \ | |
| --volume /tmp/cc:/tmp/cc" | |
| docker run ${cc_opts} codeclimate/codeclimate init | |
| docker run ${cc_opts} codeclimate/codeclimate analyze -f json > codeclimate.json | |
| } | |
| function deploy() { | |
| track="${1-stable}" | |
| name="$CI_ENVIRONMENT_SLUG" | |
| if [[ "$track" != "stable" ]]; then | |
| name="$name-$track" | |
| fi | |
| replicas="1" | |
| service_enabled="false" | |
| postgres_enabled="$POSTGRES_ENABLED" | |
| # canary uses stable db | |
| [[ "$track" == "canary" ]] && postgres_enabled="false" | |
| env_track=$( echo $track | tr -s '[:lower:]' '[:upper:]' ) | |
| env_slug=$( echo ${CI_ENVIRONMENT_SLUG//-/_} | tr -s '[:lower:]' '[:upper:]' ) | |
| if [[ "$track" == "stable" ]]; then | |
| # for stable track get number of replicas from `PRODUCTION_REPLICAS` | |
| eval new_replicas=\$${env_slug}_REPLICAS | |
| service_enabled="true" | |
| else | |
| # for all tracks get number of replicas from `CANARY_PRODUCTION_REPLICAS` | |
| eval new_replicas=\$${env_track}_${env_slug}_REPLICAS | |
| fi | |
| if [[ -n "$new_replicas" ]]; then | |
| replicas="$new_replicas" | |
| fi | |
| helm upgrade --install \ | |
| --wait \ | |
| --set service.enabled="$service_enabled" \ | |
| --set releaseOverride="$CI_ENVIRONMENT_SLUG" \ | |
| --set image.repository="$CI_APPLICATION_REPOSITORY" \ | |
| --set image.tag="$CI_APPLICATION_TAG" \ | |
| --set image.pullPolicy=IfNotPresent \ | |
| --set application.track="$track" \ | |
| --set application.database_url="$DATABASE_URL" \ | |
| --set service.url="$CI_ENVIRONMENT_URL" \ | |
| --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" \ | |
| --namespace="$KUBE_NAMESPACE" \ | |
| --version="$CI_PIPELINE_ID-$CI_JOB_ID" \ | |
| "$name" \ | |
| chart/ | |
| } | |
| function install_dependencies() { | |
| apk add -U openssl curl tar gzip bash ca-certificates git | |
| wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://raw.githubusercontent.com/sgerrand/alpine-pkg-glibc/master/sgerrand.rsa.pub | |
| wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.23-r3/glibc-2.23-r3.apk | |
| apk add glibc-2.23-r3.apk | |
| rm glibc-2.23-r3.apk | |
| curl https://kubernetes-helm.storage.googleapis.com/helm-v2.6.1-linux-amd64.tar.gz | tar zx | |
| mv linux-amd64/helm /usr/bin/ | |
| helm version --client | |
| curl -L -o /usr/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl | |
| chmod +x /usr/bin/kubectl | |
| kubectl version --client | |
| } | |
| function setup_docker() { | |
| if ! docker info &>/dev/null; then | |
| if [ -z "$DOCKER_HOST" -a "$KUBERNETES_PORT" ]; then | |
| export DOCKER_HOST='tcp://localhost:2375' | |
| fi | |
| fi | |
| } | |
| function setup_test_db() { | |
| if [ -z ${KUBERNETES_PORT+x} ]; then | |
| DB_HOST=postgres | |
| else | |
| DB_HOST=localhost | |
| fi | |
| export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${DB_HOST}:5432/${POSTGRES_DB}" | |
| } | |
| 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} | |
| else | |
| auto_chart="chart" | |
| auto_chart_name="chart" | |
| fi | |
| helm init --client-only | |
| helm repo add gitlab https://charts.gitlab.io | |
| 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 describe namespace "$KUBE_NAMESPACE" || kubectl create namespace "$KUBE_NAMESPACE" | |
| } | |
| function check_kube_domain() { | |
| if [ -z ${AUTO_DEVOPS_DOMAIN+x} ]; then | |
| echo "In order to deploy, AUTO_DEVOPS_DOMAIN must be set as a variable at the group or project level, or manually added in .gitlab-cy.yml" | |
| false | |
| else | |
| true | |
| fi | |
| } | |
| function build() { | |
| if [[ -f Dockerfile ]]; then | |
| echo "Building Dockerfile-based application..." | |
| docker build -t "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG" . | |
| else | |
| echo "Building Heroku-based application using gliderlabs/herokuish docker image..." | |
| docker run -i --name="$CI_CONTAINER_NAME" -v "$(pwd):/tmp/app:ro" gliderlabs/herokuish /bin/herokuish buildpack build | |
| docker commit "$CI_CONTAINER_NAME" "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG" | |
| docker rm "$CI_CONTAINER_NAME" >/dev/null | |
| echo "" | |
| echo "Configuring $CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG docker image..." | |
| docker create --expose 5000 --env PORT=5000 --name="$CI_CONTAINER_NAME" "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG" /bin/herokuish procfile start web | |
| docker commit "$CI_CONTAINER_NAME" "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG" | |
| docker rm "$CI_CONTAINER_NAME" >/dev/null | |
| echo "" | |
| fi | |
| if [[ -n "$CI_REGISTRY_USER" ]]; then | |
| echo "Logging to GitLab Container Registry with CI credentials..." | |
| docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY" | |
| echo "" | |
| fi | |
| echo "Pushing to GitLab Container Registry..." | |
| docker push "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG" | |
| echo "" | |
| } | |
| function install_tiller() { | |
| echo "Checking Tiller..." | |
| helm init --upgrade | |
| kubectl rollout status -n "$TILLER_NAMESPACE" -w "deployment/tiller-deploy" | |
| if ! helm version --debug; then | |
| echo "Failed to init Tiller." | |
| return 1 | |
| fi | |
| echo "" | |
| } | |
| function create_secret() { | |
| kubectl create secret -n "$KUBE_NAMESPACE" \ | |
| docker-registry gitlab-registry \ | |
| --docker-server="$CI_REGISTRY" \ | |
| --docker-username="$CI_REGISTRY_USER" \ | |
| --docker-password="$CI_REGISTRY_PASSWORD" \ | |
| --docker-email="$GITLAB_USER_EMAIL" \ | |
| -o yaml --dry-run | kubectl replace -n "$KUBE_NAMESPACE" --force -f - | |
| } | |
| function delete() { | |
| track="${1-stable}" | |
| name="$CI_ENVIRONMENT_SLUG" | |
| if [[ "$track" != "stable" ]]; then | |
| name="$name-$track" | |
| fi | |
| helm delete "$name" || true | |
| } | |
| before_script: | |
| - *auto_devops |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment