Commit 972f59a0 authored by Pierre Smeyers's avatar Pierre Smeyers
Browse files

Merge branch '3-auto-stop-environments' into 'master'

Resolve "auto-stop environments"

Closes #3

See merge request to-be-continuous/helmfile!8
parents 63cc525f c0e94d78
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ The environment variables are available in the helmfile template with the
| `$environment_type`  | `{{ env "environment_type" }}` | the current deployment environment type (`review`, `integration`, `staging` or `production`) |
| `$environment_url` | `{{ env "environment_url" }}` | the environment URL (see also [environment url management](#environments-url-management)) |
| `$environment_hostname` | `{{ env "environment_hostname" }}` | the environment hostname, extracted from the environment URL |
| `$kube_namespace`    | `{{ .Namespace }}` | the Kubernetes namespace currently used for deployment/cleanup |

The `$environment_type` is also passed as `--environment` parameter to `helmfile` which allows you
to inject a set of values specific to the environment type
@@ -276,6 +277,7 @@ Here are variables supported to configure review environments:
| `HELMFILE_REVIEW_ENVIRONMENT_URL`| The review environments url _(only define for static environment URLs declaration and if different from default)_ | `$HELMFILE_ENVIRONMENT_URL` |
| `HELMFILE_REVIEW_NAMESPACE`  | The Kubernetes namespace to use for `review` env _(only define to override default)_ | `$KUBE_NAMESPACE` |
| :lock: `HELMFILE_REVIEW_KUBE_CONFIG` | Specific kubeconfig for `review` env _(only define to override default)_ | `$HELMFILE_DEFAULT_KUBE_CONFIG` |
| `HELMFILE_REVIEW_AUTOSTOP_DURATION`| The amount of time before GitLab will automatically stop `review` environments | `4 hours` |

### Integration environment configuration

@@ -292,6 +294,7 @@ Here are variables supported to configure the integration environment:
| `HELMFILE_INTEG_ENVIRONMENT_URL`| The integration environment url _(only define for static environment URLs declaration and if different from default)_ | `$HELMFILE_ENVIRONMENT_URL` |
| `HELMFILE_INTEG_NAMESPACE`   | The Kubernetes namespace to use for `integration` env _(only define to override default)_ | `$KUBE_NAMESPACE` |
| :lock: `HELMFILE_INTEG_KUBE_CONFIG` | Specific kubeconfig for `integration` env _(only define to override default)_ | `$HELMFILE_DEFAULT_KUBE_CONFIG` |
| `HELMFILE_INTEG_AUTOSTOP_DURATION`| The amount of time before GitLab will automatically stop the `integration` env | `never` |

### Staging environment configuration

@@ -308,6 +311,7 @@ Here are variables supported to configure the staging environment:
| `HELMFILE_STAGING_ENVIRONMENT_URL`| The staging environment url _(only define for static environment URLs declaration and if different from default)_ | `$HELMFILE_ENVIRONMENT_URL` |
| `HELMFILE_STAGING_NAMESPACE` | The Kubernetes namespace to use for `staging` env _(only define to override default)_ | `$KUBE_NAMESPACE` |
| :lock: `HELMFILE_STAGING_KUBE_CONFIG` | Specific kubeconfig for `staging` env _(only define to override default)_ | `$HELMFILE_DEFAULT_KUBE_CONFIG` |
| `HELMFILE_STAGING_AUTOSTOP_DURATION`| The amount of time before GitLab will automatically stop the `staging` env | `never` |

### Production environment configuration

+15 −0
Original line number Diff line number Diff line
@@ -110,6 +110,11 @@
          "default": "${HELMFILE_BASE_APP_NAME}-${CI_ENVIRONMENT_SLUG}",
          "advanced": true
        },
        {
          "name": "HELMFILE_REVIEW_AUTOSTOP_DURATION",
          "description": "The amount of time before GitLab will automatically stop `review` environments",
          "default": "4 hours"
        },
        {
          "name": "HELMFILE_REVIEW_ENVIRONMENT_URL",
          "type": "url",
@@ -143,6 +148,11 @@
          "default": "${HELMFILE_BASE_APP_NAME}-integration",
          "advanced": true
        },
        {
          "name": "HELMFILE_INTEG_AUTOSTOP_DURATION",
          "description": "The amount of time before GitLab will automatically stop the `integration` env",
          "default": "never"
        },
        {
          "name": "HELMFILE_INTEG_ENVIRONMENT_URL",
          "type": "url",
@@ -176,6 +186,11 @@
          "default": "${HELMFILE_BASE_APP_NAME}-staging",
          "advanced": true
        },
        {
          "name": "HELMFILE_STAGING_AUTOSTOP_DURATION",
          "description": "The amount of time before GitLab will automatically stop the `staging` env",
          "default": "never"
        },
        {
          "name": "HELMFILE_STAGING_ENVIRONMENT_URL",
          "type": "url",
+44 −40
Original line number Diff line number Diff line
@@ -87,6 +87,10 @@ variables:
#  HELMFILE_LINT_ENABLED: "true"
#  HELMFILE_TEST_ENABLED: "true"

  HELMFILE_REVIEW_AUTOSTOP_DURATION: "4 hours"
  HELMFILE_INTEG_AUTOSTOP_DURATION: "never"
  HELMFILE_STAGING_AUTOSTOP_DURATION: "never"

  # default: one-click deploy
  HELMFILE_PROD_DEPLOY_STRATEGY: manual

@@ -314,24 +318,25 @@ stages:
  }

  function setup_kubeconfig() {
    if [[ -f "$1" ]]
    explicit_config=${ENV_KUBE_CONFIG:-${HELMFILE_DEFAULT_KUBE_CONFIG}}
    if [[ -f "$explicit_config" ]]
    then
      # arg1 is a path to a Kubeconfig file
      # is a path to a Kuberconfig file
      export KUBECONFIG="$CI_PROJECT_DIR/.kubeconfig"
      cp -f "$1" "$KUBECONFIG"
      cp -f "$explicit_config" "$KUBECONFIG"
      log_info "--- using \\e[32mKUBECONFIG\\e[0m provided by env variables"
    elif [[ -n "$1" ]]
    elif [[ -n "$explicit_config" ]]
    then
      # arg1 is a Kubeconfig file content
      # is a Kuberconfig file content
      export KUBECONFIG="$CI_PROJECT_DIR/.kubeconfig"
      echo "$1" > "$KUBECONFIG"
      echo "$explicit_config" > "$KUBECONFIG"
      log_info "--- using \\e[32mKUBECONFIG\\e[0m provided by env variables"
    elif [[ -n "$KUBECONFIG" ]]
    then
      log_info "--- using \\e[32mKUBECONFIG\\e[0m provided by GitLab"
      if [[ -n "$KUBE_CONTEXT" ]]
      then
        kubectl config use-context "$KUBE_CONTEXT"
        export HELM_KUBECONTEXT="${HELM_KUBECONTEXT:-$KUBE_CONTEXT}"
        log_info "--- switch to the given \\e[32mKUBE_CONTEXT\\e[0m: ${KUBE_CONTEXT}"
      fi
    else
@@ -356,10 +361,10 @@ stages:

  # deploy application
  function helmfile_deploy() {
    export environment_type=$1
    export environment_name=$2
    namespace=$3
    environment_url=$4
    export environment_type=$ENV_TYPE
    export environment_name=${ENV_APP_NAME:-${HELMFILE_BASE_APP_NAME}${ENV_APP_SUFFIX}}
    export kube_namespace=${ENV_NAMESPACE:-${KUBE_NAMESPACE}}
    environment_url=${ENV_URL:-${HELMFILE_ENVIRONMENT_URL:-$ENV_URL_LEGACY}}

    # variables expansion in $environment_url
    environment_url=$(echo "$environment_url" | awkenvsubst)
@@ -369,12 +374,12 @@ stages:
    export environment_hostname

    log_info "--- \\e[32mdeploy\\e[0m"
    log_info "--- \$namespace: \\e[33;1m${namespace}\\e[0m"
    log_info "--- \$kube_namespace: \\e[33;1m${kube_namespace}\\e[0m"
    log_info "--- \$environment_type: \\e[33;1m${environment_type}\\e[0m (passed as helmfile environment)"
    log_info "--- \$environment_name: \\e[33;1m${environment_name}\\e[0m"
    log_info "--- \$environment_hostname: \\e[33;1m${environment_hostname}\\e[0m"

    kubectl config set-context --current --namespace="$namespace"
    kubectl config set-context --current --namespace="$kube_namespace"

    # Auto-create docker-registry secret for Gitlab deploy token
    if [[ -n "$CI_DEPLOY_USER" ]]; then
@@ -383,7 +388,7 @@ stages:
      kubectl create secret docker-registry "$pull_secret"\
        --docker-server="${CI_REGISTRY}" --docker-username="${CI_DEPLOY_USER}"\
        --docker-password="${CI_DEPLOY_PASSWORD}" --docker-email="${GITLAB_USER_EMAIL}"\
        -o yaml --dry-run=client | kubectl apply -f - --namespace="$namespace"
        -o yaml --dry-run=client | kubectl apply -f - --namespace="$kube_namespace"
    fi

    # unset any upstream deployment env & artifacts
@@ -402,9 +407,9 @@ stages:
    helmfile_opts=${TRACE+--debug}
    helmfile_opts="$helmfile_opts --file ${HELMFILE_PATH}"
    
    if [ -n "$namespace" ]; then
      log_info "--- using \\e[32mnamespace\\e[0m: \\e[33;1m${namespace}\\e[0m"
      helmfile_opts="$helmfile_opts --namespace $namespace"
    if [ -n "$kube_namespace" ]; then
      log_info "--- using \\e[32mnamespace\\e[0m: \\e[33;1m${kube_namespace}\\e[0m"
      helmfile_opts="$helmfile_opts --namespace $kube_namespace"
    fi

    if [ -n "$environment_type" ]; then
@@ -438,12 +443,12 @@ stages:

  # delete application (and dependencies)
  function helmfile_delete() {
    export environment_type=$1
    export environment_name=$2
    namespace=$3
    export environment_type=$ENV_TYPE
    export environment_name=${ENV_APP_NAME:-${HELMFILE_BASE_APP_NAME}${ENV_APP_SUFFIX}}
    export kube_namespace=${ENV_NAMESPACE:-${KUBE_NAMESPACE}}

    log_info "--- \\e[32mdelete"
    log_info "--- \$namespace: \\e[33;1m${namespace}\\e[0m"
    log_info "--- \$kube_namespace: \\e[33;1m${kube_namespace}\\e[0m"
    log_info "--- \$environment_type: \\e[33;1m${environment_type}\\e[0m"
    log_info "--- \$environment_name: \\e[33;1m${environment_name}\\e[0m"

@@ -459,9 +464,9 @@ stages:
    helmfile_opts=${TRACE+--debug}    
    helmfile_opts="$helmfile_opts --file ${HELMFILE_PATH}"

    if [ -n "$namespace" ]; then
      log_info "--- using \\e[32mnamespace\\e[0m: \\e[33;1m${namespace}\\e[0m"
      helmfile_opts="$helmfile_opts --namespace $namespace"
    if [ -n "$kube_namespace" ]; then
      log_info "--- using \\e[32mnamespace\\e[0m: \\e[33;1m${kube_namespace}\\e[0m"
      helmfile_opts="$helmfile_opts --namespace $kube_namespace"
    fi

    if [ -n "$environment_type" ]; then
@@ -483,22 +488,21 @@ stages:
  }

  # test application (and dependencies)
  # $environment_type and $environment_name are propagated by dotenv artifact
  function helmfile_test() {
    export environment_type=$1
    export environment_name=$2
    namespace=$3
    export kube_namespace=${ENV_NAMESPACE:-${KUBE_NAMESPACE}}

    log_info "--- \\e[32mtest\\e[0m (env: ${environment_type})"
    log_info "--- \$namespace: \\e[33;1m${namespace}\\e[0m"
    log_info "--- \$kube_namespace: \\e[33;1m${kube_namespace}\\e[0m"
    log_info "--- \$environment_name: \\e[33;1m${environment_name}\\e[0m"
    log_info "--- \$environment_type: \\e[33;1m${environment_type}\\e[0m"

    helmfile_opts=""
    helmfile_opts="$helmfile_opts --file ${HELMFILE_PATH}"

    if [ -n "$namespace" ]; then
      log_info "--- using \\e[32mnamespace\\e[0m: \\e[33;1m${namespace}\\e[0m"
      helmfile_opts="$helmfile_opts --namespace $namespace"
    if [ -n "$kube_namespace" ]; then
      log_info "--- using \\e[32mnamespace\\e[0m: \\e[33;1m${kube_namespace}\\e[0m"
      helmfile_opts="$helmfile_opts --namespace $kube_namespace"
    fi

    if [ -n "$environment_type" ]; then
@@ -592,12 +596,11 @@ helmfile-lint:
  before_script:
    - *helmfile-scripts
    - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}"
    - assert_defined "${ENV_KUBE_CONFIG:-${HELMFILE_DEFAULT_KUBE_CONFIG:-${KUBECONFIG}}}" 'Missing required env $ENV_KUBE_CONFIG or $HELMFILE_DEFAULT_KUBE_CONFIG'
    - setup_kubeconfig "${ENV_KUBE_CONFIG:-${HELMFILE_DEFAULT_KUBE_CONFIG}}"
    - setup_kubeconfig
    - setup_pgp_key
  script:
    - set_default_namespace
    - helmfile_deploy $ENV_TYPE "${ENV_APP_NAME:-${HELMFILE_BASE_APP_NAME}${ENV_APP_SUFFIX}}" "${ENV_NAMESPACE:-${KUBE_NAMESPACE}}" "${ENV_URL:-${HELMFILE_ENVIRONMENT_URL:-$ENV_URL_LEGACY}}"
    - helmfile_deploy
  artifacts:
    name: "$ENV_TYPE env url for $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
    paths:
@@ -626,12 +629,11 @@ helmfile-lint:
  before_script:
    - *helmfile-scripts
    - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}"
    - assert_defined "${ENV_KUBE_CONFIG:-${HELMFILE_DEFAULT_KUBE_CONFIG:-${KUBECONFIG}}}" 'Missing required Kubeconfig'
    - setup_kubeconfig "${ENV_KUBE_CONFIG:-${HELMFILE_DEFAULT_KUBE_CONFIG}}"
    - setup_kubeconfig
    - setup_pgp_key
  script:
    - set_default_namespace
    - helmfile_delete $ENV_TYPE "${ENV_APP_NAME:-${HELMFILE_BASE_APP_NAME}${ENV_APP_SUFFIX}}" "${ENV_NAMESPACE:-${KUBE_NAMESPACE}}"
    - helmfile_delete
  environment:
    action: stop
  resource_group: $CI_ENVIRONMENT_NAME
@@ -648,12 +650,11 @@ helmfile-lint:
  before_script:
    - *helmfile-scripts
    - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}"
    - assert_defined "${ENV_KUBE_CONFIG:-${HELMFILE_DEFAULT_KUBE_CONFIG:-${KUBECONFIG}}}" 'Missing required Kubeconfig'
    - setup_kubeconfig "${ENV_KUBE_CONFIG:-${HELMFILE_DEFAULT_KUBE_CONFIG}}"
    - setup_kubeconfig
    - setup_pgp_key
  script:
    - set_default_namespace
    - helmfile_test "$environment_type" "$environment_name" "${ENV_NAMESPACE:-${KUBE_NAMESPACE}}"
    - helmfile_test
  environment:
    action: verify

@@ -674,6 +675,7 @@ helmfile-review:
  environment:
    name: review/$CI_COMMIT_REF_NAME
    on_stop: helmfile-cleanup-review
    auto_stop_in: "$HELMFILE_REVIEW_AUTOSTOP_DURATION"
  resource_group: review/$CI_COMMIT_REF_NAME
  rules:
    # exclude tags and on $HELMFILE_REVIEW_ENABLED not set
@@ -745,6 +747,7 @@ helmfile-integration:
  environment:
    name: integration
    on_stop: helmfile-cleanup-integration
    auto_stop_in: "$HELMFILE_INTEG_AUTOSTOP_DURATION"
  resource_group: integration
  rules:
    # exclude on $HELMFILE_INTEG_ENABLED not set
@@ -813,6 +816,7 @@ helmfile-staging:
  environment:
    name: staging
    on_stop: helmfile-cleanup-staging
    auto_stop_in: "$HELMFILE_STAGING_AUTOSTOP_DURATION"
  resource_group: staging
  rules:
    # exclude on $HELMFILE_STAGING_ENABLED not set