Skip to content

Instantly share code, notes, and snippets.

@aklinkert
Created October 14, 2016 14:03
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aklinkert/5d2e4b81d7cf3c0be524663c63dc3da6 to your computer and use it in GitHub Desktop.
Save aklinkert/5d2e4b81d7cf3c0be524663c63dc3da6 to your computer and use it in GitHub Desktop.
Kubernetes continuous integration
#!/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."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment