Skip to content

Instantly share code, notes, and snippets.

@aklinkert
Created October 14, 2016 14:03
Show Gist options
  • Select an option

  • Save aklinkert/5d2e4b81d7cf3c0be524663c63dc3da6 to your computer and use it in GitHub Desktop.

Select an option

Save aklinkert/5d2e4b81d7cf3c0be524663c63dc3da6 to your computer and use it in GitHub Desktop.

Revisions

  1. aklinkert created this gist Oct 14, 2016.
    104 changes: 104 additions & 0 deletions kubernetes_continuous.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,104 @@
    #!/usr/bin/env bash

    set -e

    VERSION="${CIRCLE_SHA1}"
    KUBE_CONTEXT="$(kubectl config current-context)"

    # getKubeValue "${KUBE_CONTEXT}" "${KUBE_NAMESPACE}" "${deployment}" "${path}"
    getKubeValue() {
    kubectl --context "${1}" --namespace "${2}" get "deployment/${3}" -o "jsonpath={${4}}"
    }

    # getKubeRevision "${KUBE_CONTEXT}" "${KUBE_NAMESPACE}" "${deployment}"
    getKubeRevision() {
    kubectl --context "${1}" --namespace "${2}" get "deployment/${3}" -o go-template --template='{{ index .metadata.annotations "deployment.kubernetes.io/revision"}}'
    }

    # updateKubernetesDeployment "${KUBE_CONTEXT}" "${KUBE_NAMESPACE}" "${deployment}" "${repo}"
    updateKubernetesDeployment() {
    local deployedImage deployedRepo currentRevision wantedReplicas availableReplicas updatedReplicas wantedGeneration observedGeneration

    # first check, if desired deployment does exist. If not, we can exit early
    if ! kubectl --context "${KUBE_CONTEXT}" --namespace "${KUBE_NAMESPACE}" describe deployment "${deployment}" > /dev/null ; then
    echo "Deployment '${deployment}' does not exist."

    return 0
    fi

    deployedImage="$(getKubeValue "${1}" "${2}" "${3}" ".spec.template.spec.containers[0].image")"
    deployedRepo="$(echo "${deployedImage}" |cut -d':' -f1)"
    echo "Deployment ${3} has currently the repo ${deployedRepo} deployed, trying to match repo ${4} ..."

    # next we check, that the deployment we wanna update has given repo deployed. If not, we can exit early
    if ! [[ "${deployedRepo}" == "${4}" ]]; then
    echo "Deployment '${deployment}' does not contain docker repo ${repo}."

    return 0
    fi

    # get the current revision to enable rollbacks
    currentRevision=$(getKubeRevision "${1}" "${2}" "${3}")
    echo "Current revision is ${currentRevision}"

    # actually update the deployment to new image version
    echo "Updating kubernetes deployment ${3} to use ${4}:${VERSION} in env ${2} ..."
    kubectl --context "${1}" --namespace "${2}" patch deployment "${3}" -p "{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\": \"${3}\",\"image\":\"${4}:${VERSION}\"}]}}}}"

    echo "Updated to revision $(getKubeRevision "${1}" "${2}" "${3}")"
    sleep 1

    # try 30 times to check the deployment for success
    for i in $(seq 1 30); do
    wantedReplicas="$(getKubeValue "${1}" "${2}" "${3}" ".spec.replicas")"
    availableReplicas="$(getKubeValue "${1}" "${2}" "${3}" ".status.availableReplicas")"
    updatedReplicas="$(getKubeValue "${1}" "${2}" "${3}" ".status.updatedReplicas")"
    wantedGeneration="$(getKubeValue "${1}" "${2}" "${3}" ".metadata.generation")"
    observedGeneration="$(getKubeValue "${1}" "${2}" "${3}" ".status.observedGeneration")"

    echo "check ${i} | wanted repl: ${wantedReplicas}; updated repl: ${updatedReplicas}; available repl: ${availableReplicas}; wanted gen: ${wantedGeneration}; observed gen: ${observedGeneration}"

    # when the deployment was successful, we can exit the function, our job here is done
    if [[ "${wantedReplicas}" == "${updatedReplicas}" ]] && [[ "${wantedGeneration}" && "${observedGeneration}" ]] && [[ 0 -lt "${availableReplicas}" ]]; then
    echo "Kubernetes deployment of ${3} was successful after ${i} check iterations."
    return 0
    fi
    done

    # when the check loop ended without returning, we can assume that the deployment is broken. In this case, we roll back to the previous reversion.
    echo "Kubernetes deployment of ${3} was NOT successful! Rolling back to previous revision ${currentRevision} ..."
    kubectl --context "${1}" --namespace "${2}" rollout undo "deployment/${3}" --to-revision="${currentRevision}"

    return 1
    }

    echo "Using kubectl context ${KUBE_CONTEXT} and namespace ${KUBE_NAMESPACE}"

    echo "checking if context for env exists ... "
    if ! kubectl get nodes --context "${KUBE_CONTEXT}" > /dev/null ; then
    echo "Desired context does not exist"
    exit 0
    fi

    if [ -z "${KUBE_DEPLOYMENTS}" ] && [ -n "${KUBE_DEPLOYMENT:-}" ]; then
    KUBE_DEPLOYMENTS="${KUBE_DEPLOYMENT}"
    fi

    if [ -z "${KUBE_DEPLOYMENTS}" ]; then
    echo "No kubernetes deployment env var set"
    exit 0
    fi

    declare -a deployments
    deployments=(${KUBE_DEPLOYMENTS})

    declare -a repos
    repos=(${DOCKER_REPOS})

    for repo in "${repos[@]}" ; do
    for deployment in "${deployments[@]}" ; do
    updateKubernetesDeployment "${KUBE_CONTEXT}" "${KUBE_NAMESPACE}" "${deployment}" "${repo}"
    done
    done

    echo "Done."