blue-green.sh 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. #!bin/bash
  2. DEPLOYMENT_NAME=$(echo "${DEPLOY_MANIFEST}" | jq -r '.metadata.name')
  3. SERVICE_NAME=$(echo "${SERVICE_MANIFEST}" | jq -r '.metadata.name')
  4. # 1. Check if the deployment exists. If it doesn't exist, this is the initial deployment and we
  5. # can simply deploy without blue-green. Add the app label using jq
  6. out=$(kubectl get --export -o json deployment.apps/${DEPLOYMENT_NAME} 2>&1)
  7. if [ $? -ne 0 ]; then
  8. if [[ "${out}" =~ "NotFound" ]] ; then
  9. echo "Initial deployment"
  10. echo ${DEPLOY_MANIFEST} | \
  11. jq ".metadata.labels += {\"app.kubernetes.io/instance\": \"${APPNAME}\"}" | \
  12. kubectl apply -o yaml -f - || exit 1
  13. echo ${SERVICE_MANIFEST} | \
  14. jq ".metadata.labels += {\"app.kubernetes.io/instance\": \"${APPNAME}\"}" | \
  15. kubectl apply -o yaml -f - || exit 1
  16. exit 0
  17. fi
  18. echo "Failed to get deployment: ${out}"
  19. exit 1
  20. fi
  21. ORIGINAL_DEPLOY_MANIFEST=$out
  22. # 2. Clone the original, running deployment to a temporary deployment, with tweaks to its name and
  23. # selectors. The jq command carries over all labels and selectors and appends the `-temp` suffix.
  24. TMP_DEPLOYMENT_NAME="${DEPLOYMENT_NAME}-temp"
  25. echo ${ORIGINAL_DEPLOY_MANIFEST} | jq -r '.metadata.name+="-temp" |
  26. .spec.template.metadata.labels += (.spec.template.metadata.labels | to_entries | map(.value+="-temp") | from_entries) |
  27. .spec.selector.matchLabels += (.spec.selector.matchLabels | to_entries | map(.value+="-temp") | from_entries)' |
  28. kubectl apply -f -
  29. # 3. Wait for cloned deployment to become ready.
  30. sleep 2
  31. echo "Waiting for successful rollout of new (temporary) deployment"
  32. kubectl rollout status --watch=true deployments.apps/${TMP_DEPLOYMENT_NAME} || exit 1
  33. echo "Rollout of temporary deployment successful"
  34. # 4. Patch the service object such that all traffic is redirected to the cloned, temporary
  35. # deployment. After this step, the original deployment will no longer be receiving traffic.
  36. kubectl get service ${SERVICE_NAME} --export -o json | \
  37. jq '.spec.selector = (.spec.selector | with_entries(.value+="-temp"))' |
  38. kubectl apply -f - || exit 1
  39. sleep 5 # Sleep slightly to allow iptables to get propagated to all nodes in the cluster
  40. # 5. Update the original deployment (now receiving no traffic) with the new manifest
  41. echo "Updating original deployment"
  42. echo ${DEPLOY_MANIFEST} | \
  43. jq ".metadata.labels += {\"app.kubernetes.io/instance\": \"${APPNAME}\"}" | \
  44. kubectl apply -f - || exit 1
  45. # 6. Wait for the new deployment to become complete
  46. sleep 2
  47. echo "Waiting for successful rollout of new deployment"
  48. kubectl rollout status --watch=true deployments.apps/${DEPLOYMENT_NAME} || exit 1
  49. echo "Rollout of new deployment successful"
  50. # dummy wait step for demo purposes
  51. echo "sleeping for 30 seconds"
  52. sleep 30
  53. # 7. Apply the new service object. Traffic will be redirected to the new version of the deployment
  54. echo "Updating original service object"
  55. echo ${SERVICE_MANIFEST} | \
  56. jq ".metadata.labels += {\"app.kubernetes.io/instance\": \"${APPNAME}\"}" | \
  57. kubectl apply -f - || exit 1
  58. sleep 10
  59. # 8. Remove the cloned deployment, which is no longer receiving any traffic
  60. echo "Deleting ephemeral deployment"
  61. kubectl delete deployments/${TMP_DEPLOYMENT_NAME} --ignore-not-found=true || exit 1