diff --git a/Auto-deploy-kubernetes.yml b/Auto-deploy-kubernetes.yml new file mode 100644 index 0000000000000000000000000000000000000000..0ee597f58786f6083c93d7864cce19c49436fef0 --- /dev/null +++ b/Auto-deploy-kubernetes.yml @@ -0,0 +1,319 @@ +############################## +# Define some helper functions +############################## + +.common: &common + | + set -eo pipefail + + [[ "$TRACE" ]] && set -x + + export CI_CONTAINER_NAME="ci_job_build_$CI_BUILD_ID" + export CI_REGISTRY_TAG="$CI_BUILD_REF_NAME" + + create_kubeconfig() { + echo "Generating kubeconfig..." + export KUBECONFIG="$(pwd)/kubeconfig" + export KUBE_CLUSTER_OPTIONS= + if [[ -n "$KUBE_CA_PEM" ]]; then + echo "Using KUBE_CA_PEM..." + echo "$KUBE_CA_PEM" > "$(pwd)/kube.ca.pem" + export KUBE_CLUSTER_OPTIONS=--certificate-authority="$(pwd)/kube.ca.pem" + fi + kubectl config set-cluster gitlab-deploy --server="$KUBE_URL" $KUBE_CLUSTER_OPTIONS + kubectl config set-credentials gitlab-deploy --token="$KUBE_TOKEN" $KUBE_CLUSTER_OPTIONS + kubectl config set-context gitlab-deploy --cluster=gitlab-deploy --user=gitlab-deploy --namespace="$KUBE_NAMESPACE" + kubectl config use-context gitlab-deploy + echo "" + } + + ensure_deploy_variables() { + if [[ -z "$KUBE_URL" ]]; then + echo "Missing KUBE_URL." + exit 1 + fi + + if [[ -z "$KUBE_TOKEN" ]]; then + echo "Missing KUBE_TOKEN." + exit 1 + fi + + if [[ -z "$KUBE_NAMESPACE" ]]; then + echo "Missing KUBE_NAMESPACE." + exit 1 + fi + + if [[ -z "$CI_ENVIRONMENT_SLUG" ]]; then + echo "Missing CI_ENVIRONMENT_SLUG." + exit 1 + fi + + if [[ -z "$CI_ENVIRONMENT_URL" ]]; then + echo "Missing CI_ENVIRONMENT_URL." + exit 1 + fi + } + + ping_kube() { + if kubectl version > /dev/null; then + echo "Kubernetes is online!" + echo "" + else + echo "Cannot connect to Kubernetes." + return 1 + fi + } + +############################## +# Define auto deploy functions +############################## + +.auto_build: &auto_build + | + echo "Checking docker engine..." + if ! docker info &>/dev/null; then echo "Missing docker engine to build images."; echo "Running docker:dind locally with graph driver pointing to '/cache/docker'" + if ! grep -q overlay /proc/filesystems; then + echo "Missing overlay filesystem. Are you running recent enough kernel?" + exit 1 + fi + if [[ ! -d /cache ]]; then + mkdir -p /cache + mount -t tmpfs tmpfs /cache + fi + dockerd --host=unix:///var/run/docker.sock --storage-driver=overlay --graph=/cache/docker & &>/docker.log + trap 'kill %%' EXIT + + echo "Waiting for docker..." + for i in $(seq 1 60); do + if docker info &> /dev/null; then + break + fi + sleep 1s + done + + if [[ "$i" == 60 ]]; then + echo "Failed to start docker:dind..." + cat /docker.log + exit 1 + fi + echo "" + fi + + docker rm -f "$CI_CONTAINER_NAME" &>/dev/null || true + + echo "Building application..." + + if [[ -f Dockerfile ]]; then + echo "Building Dockerfile-based application..." + # Build Dockerfile + docker build -t "$CI_REGISTRY_IMAGE:$CI_REGISTRY_TAG" . + else + # Build heroku-based application + echo "Building Heroku-based application using gliderlabs/herokuish docker image..." + docker run -i --name="$CI_CONTAINER_NAME" -v "$(pwd):/tmp/app:ro" -v "/cache/herokuish:/tmp/cache" gliderlabs/herokuish /bin/herokuish buildpack build + docker commit "$CI_CONTAINER_NAME" "$CI_REGISTRY_IMAGE:$CI_REGISTRY_TAG" + docker rm "$CI_CONTAINER_NAME" >/dev/null + echo "" + + # Create a start command, start `web` + echo "Configuring $CI_REGISTRY_IMAGE:$CI_REGISTRY_TAG docker image..." + docker create --expose 5000 --env PORT=5000 --name="$CI_CONTAINER_NAME" "$CI_REGISTRY_IMAGE:$CI_REGISTRY_TAG" /bin/herokuish procfile start web + docker commit "$CI_CONTAINER_NAME" "$CI_REGISTRY_IMAGE:$CI_REGISTRY_TAG" + docker rm "$CI_CONTAINER_NAME" >/dev/null + echo "" + fi + + if [[ -n "$CI_BUILD_TOKEN" ]]; then + echo "Logging to GitLab Container Registry with CI credentials..." + docker login -u gitlab-ci-token -p "$CI_BUILD_TOKEN" "$CI_REGISTRY" + echo "" + fi + + echo "Pushing to GitLab Container Registry..." + docker push "$CI_REGISTRY_IMAGE:$CI_REGISTRY_TAG" + echo "" + +.auto_deploy: &auto_deploy + | + CI_ENVIRONMENT_HOSTNAME="${CI_ENVIRONMENT_URL}" + CI_ENVIRONMENT_HOSTNAME="${CI_ENVIRONMENT_HOSTNAME/http:\/\//}" + CI_ENVIRONMENT_HOSTNAME="${CI_ENVIRONMENT_HOSTNAME/https:\/\//}" + + echo ciEnvironmentSlug=$CI_ENVIRONMENT_SLUG,ciPipelineID=\\"$CI_PIPELINE_ID\\",ciBuildID=\\"$CI_BUILD_ID\\",ciEnvironmentHostname=$CI_ENVIRONMENT_HOSTNAME,ciRegistryImage=$CI_REGISTRY_IMAGE,ciRegistryTag=$CI_REGISTRY_TAG + + helm status $CI_PROJECT_NAME-$CI_PROJECT_ID-$CI_ENVIRONMENT_SLUG + if [[ $? -ne 0 ]]; then + echo "Creating initial release" + helm install --wait --name $CI_PROJECT_NAME-$CI_PROJECT_ID-$CI_ENVIRONMENT_SLUG --namespace $KUBE_NAMESPACE --set ciEnvironmentSlug=$CI_ENVIRONMENT_SLUG,ciPipelineID=\\"$CI_PIPELINE_ID\\",ciBuildID=\\"$CI_BUILD_ID\\",ciEnvironmentHostname=$CI_ENVIRONMENT_HOSTNAME,ciRegistryImage=$CI_REGISTRY_IMAGE,ciRegistryTag=$CI_REGISTRY_TAG gitlab/auto-deploy-app + else + echo "Upgrading release" + helm upgrade --wait $CI_PROJECT_NAME-$CI_PROJECT_ID-$CI_ENVIRONMENT_SLUG --namespace $KUBE_NAMESPACE --set ciEnvironmentSlug=$CI_ENVIRONMENT_SLUG,ciPipelineID=\\"$CI_PIPELINE_ID\\",ciBuildID=\\"$CI_BUILD_ID\\",ciEnvironmentHostname=$CI_ENVIRONMENT_HOSTNAME,ciRegistryImage=$CI_REGISTRY_IMAGE,ciRegistryTag=$CI_REGISTRY_TAG gitlab/auto-deploy-app + fi + + echo "Application is accessible at: ${CI_ENVIRONMENT_URL}" + echo "" + +.auto_destroy: &auto_destroy + | + create_kubeconfig + + echo "Removing app..." + helm delete $CI_PROJECT_NAME-$CI_PROJECT_ID-$CI_ENVIRONMENT_SLUG + +############################## +# Define basic job definitions +############################## + +.auto_deploy_image: &auto_deploy_image + image: registry.gitlab.com/gitlab-examples/kubernetes-deploy + before_script: + - *common + +# .openshift-deploy: &openshift-deploy +# image: registry.gitlab.com/gitlab-examples/openshift-deploy +# before_script: +# - *common + +.build_branches: &build_branches + stage: build + script: + - *auto_build + only: + - branches + +.manual_deploy_to_production: &manual_deploy_to_production + stage: production + variables: + CI_ENVIRONMENT_URL: http://$CI_PROJECT_NAME.$KUBE_DOMAIN + script: + - *auto_deploy + environment: + name: production + url: http://$CI_PROJECT_NAME.$KUBE_DOMAIN + when: manual + only: + - master + +.auto_deploy_to_production: &manual_deploy_to_production + stage: production + variables: + CI_ENVIRONMENT_URL: http://$CI_PROJECT_NAME.$KUBE_DOMAIN + script: + - *auto_deploy + environment: + name: production + url: http://$CI_PROJECT_NAME.$KUBE_DOMAIN + only: + - master + +.auto_deploy_tags_to_production: &manual_deploy_to_production + stage: production + variables: + CI_ENVIRONMENT_URL: http://$CI_PROJECT_NAME.$KUBE_DOMAIN + script: + - *auto_deploy + environment: + name: production + url: http://$CI_PROJECT_NAME.$KUBE_DOMAIN + only: + - tags + +.auto_deploy_to_staging: &auto_deploy_to_staging + stage: staging + variables: + CI_ENVIRONMENT_URL: http://$CI_PROJECT_NAME-staging.$KUBE_DOMAIN + script: + - *auto_deploy + environment: + name: staging + url: http://$CI_PROJECT_NAME-staging.$KUBE_DOMAIN + only: + - master + +.start_review: &start_review + stage: review + variables: + CI_ENVIRONMENT_URL: http://$CI_PROJECT_NAME-$CI_ENVIRONMENT_SLUG.$KUBE_DOMAIN + before_script: + - *common + - apk update && apk add curl bash openssl sudo + - curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash + - ensure_deploy_variables + - create_kubeconfig + - helm init --upgrade + - helm repo add gitlab https://charts.gitlab.io + script: + - *auto_deploy + environment: + name: review/$CI_BUILD_REF_SLUG + url: http://$CI_PROJECT_NAME-$CI_ENVIRONMENT_SLUG.$KUBE_DOMAIN + on_stop: stop_review + only: + - branches + except: + - master + +.stop_review: &stop_review + stage: cleanup + variables: + GIT_STRATEGY: none + before_script: + - *common + - apk update && apk add curl bash openssl sudo + - curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash + - ensure_deploy_variables + - create_kubeconfig + - helm init --client-only + script: + - *auto_destroy + environment: + name: review/$CI_BUILD_REF_SLUG + action: stop + when: manual + only: + - branches + except: + - master + +############################## +# Define overall pipeline +############################## + +.auto_deploy: &auto_deploy + <<: *auto_deploy_image + + stages: + - build + - review + - staging + - production + - cleanup + + build: + <<: *build_branches + + # Choose between: + # *manual_deploy_to_production + # *auto_deploy_to_production + # *auto_deploy_tags_to_production + production: + <<: *manual_deploy_to_production + + staging: + <<: *auto_deploy_to_staging + + review: + <<: *start_review + + stop_review: + <<: *stop_review + +############################## +# Project's `.gitlab-ci.yml` +############################## + +<<: *auto_deploy + +variables: + # Application deployment domain + KUBE_DOMAIN: domain.example.com diff --git a/verify_templates.rb b/verify_templates.rb index 63e6527f82ee2a3b12083a8ecb63f2445400ece5..ba0f0df968bdc6c2077f17425c8b833b2cb3288c 100644 --- a/verify_templates.rb +++ b/verify_templates.rb @@ -6,7 +6,13 @@ uri = URI.parse 'https://gitlab.com/api/v3/ci/lint' Dir.glob("#{File.dirname(__FILE__)}/**/*.yml").each do |file| response = Net::HTTP.post_form(uri, content: File.read(file)) - file = file.match(/((\w|\+|#)+)\.gitlab-ci/)[1] + match = file.match(/(?<file>(\w|\+|#)+)\.gitlab-ci.yml/) + template_name = match ? match[:file] : nil + + unless template_name + puts "Invalid file format for #{file}" + exit(1) + end if JSON.parse(response.body)['status'] == 'valid' puts "\e[32mvalid\e[0m: #{file}" # Color 'valid' green @@ -17,5 +23,6 @@ Dir.glob("#{File.dirname(__FILE__)}/**/*.yml").each do |file| end # Given we test all the templates, the coverage is 100%, always. To showcase -# how this is done, we print it here. -puts "Coverage: 100%" \ No newline at end of file +# how this is done, we print it here. The regex to parse this would be: +# /Coverage:\s(d+)%/ +puts "Coverage: 100%"