Update examples for Argo CD v0.11
This commit is contained in:
62 files changed
+287
-150
No files matched your search
@@ -1,11 +1,15 @@
|
||||
apiVersion: 0.1.0
|
||||
apiVersion: 0.3.0
|
||||
environments:
|
||||
default:
|
||||
destination:
|
||||
namespace: default
|
||||
namespace: blue-green-deploy
|
||||
server: https://kubernetes.default.svc
|
||||
k8sVersion: v1.10.0
|
||||
path: default
|
||||
kind: ksonnet.io/app
|
||||
name: blue-green-deploy
|
||||
registries:
|
||||
incubator:
|
||||
protocol: github
|
||||
uri: github.com/ksonnet/parts/tree/master/incubator
|
||||
version: 0.0.1
|
||||
Executable
+71
@@ -0,0 +1,71 @@
|
||||
#!bin/bash
|
||||
|
||||
DEPLOYMENT_NAME=$(echo "${DEPLOY_MANIFEST}" | jq -r '.metadata.name')
|
||||
SERVICE_NAME=$(echo "${SERVICE_MANIFEST}" | jq -r '.metadata.name')
|
||||
|
||||
# 1. Check if the deployment exists. If it doesn't exist, this is the initial deployment and we
|
||||
# can simply deploy without blue-green. Add the app label using jq
|
||||
out=$(kubectl get --export -o json deployment.apps/${DEPLOYMENT_NAME} 2>&1)
|
||||
if [ $? -ne 0 ]; then
|
||||
if [[ "${out}" =~ "NotFound" ]] ; then
|
||||
echo "Initial deployment"
|
||||
echo ${DEPLOY_MANIFEST} | \
|
||||
jq ".metadata.labels += {\"app.kubernetes.io/instance\": \"${APPNAME}\"}" | \
|
||||
kubectl apply -o yaml -f - || exit 1
|
||||
echo ${SERVICE_MANIFEST} | \
|
||||
jq ".metadata.labels += {\"app.kubernetes.io/instance\": \"${APPNAME}\"}" | \
|
||||
kubectl apply -o yaml -f - || exit 1
|
||||
exit 0
|
||||
fi
|
||||
echo "Failed to get deployment: ${out}"
|
||||
exit 1
|
||||
fi
|
||||
ORIGINAL_DEPLOY_MANIFEST=$out
|
||||
|
||||
# 2. Clone the original, running deployment to a temporary deployment, with tweaks to its name and
|
||||
# selectors. The jq command carries over all labels and selectors and appends the `-temp` suffix.
|
||||
TMP_DEPLOYMENT_NAME="${DEPLOYMENT_NAME}-temp"
|
||||
echo ${ORIGINAL_DEPLOY_MANIFEST} | jq -r '.metadata.name+="-temp" |
|
||||
.spec.template.metadata.labels += (.spec.template.metadata.labels | to_entries | map(.value+="-temp") | from_entries) |
|
||||
.spec.selector.matchLabels += (.spec.selector.matchLabels | to_entries | map(.value+="-temp") | from_entries)' |
|
||||
kubectl apply -f -
|
||||
|
||||
# 3. Wait for cloned deployment to become ready.
|
||||
sleep 2
|
||||
echo "Waiting for successful rollout of new (temporary) deployment"
|
||||
kubectl rollout status --watch=true deployments.apps/${TMP_DEPLOYMENT_NAME} || exit 1
|
||||
echo "Rollout of temporary deployment successful"
|
||||
|
||||
# 4. Patch the service object such that all traffic is redirected to the cloned, temporary
|
||||
# deployment. After this step, the original deployment will no longer be receiving traffic.
|
||||
kubectl get service ${SERVICE_NAME} --export -o json | \
|
||||
jq '.spec.selector = (.spec.selector | with_entries(.value+="-temp"))' |
|
||||
kubectl apply -f - || exit 1
|
||||
sleep 5 # Sleep slightly to allow iptables to get propagated to all nodes in the cluster
|
||||
|
||||
# 5. Update the original deployment (now receiving no traffic) with the new manifest
|
||||
echo "Updating original deployment"
|
||||
echo ${DEPLOY_MANIFEST} | \
|
||||
jq ".metadata.labels += {\"app.kubernetes.io/instance\": \"${APPNAME}\"}" | \
|
||||
kubectl apply -f - || exit 1
|
||||
|
||||
# 6. Wait for the new deployment to become complete
|
||||
sleep 2
|
||||
echo "Waiting for successful rollout of new deployment"
|
||||
kubectl rollout status --watch=true deployments.apps/${DEPLOYMENT_NAME} || exit 1
|
||||
echo "Rollout of new deployment successful"
|
||||
|
||||
# dummy wait step for demo purposes
|
||||
echo "sleeping for 30 seconds"
|
||||
sleep 30
|
||||
|
||||
# 7. Apply the new service object. Traffic will be redirected to the new version of the deployment
|
||||
echo "Updating original service object"
|
||||
echo ${SERVICE_MANIFEST} | \
|
||||
jq ".metadata.labels += {\"app.kubernetes.io/instance\": \"${APPNAME}\"}" | \
|
||||
kubectl apply -f - || exit 1
|
||||
|
||||
sleep 10
|
||||
# 8. Remove the cloned deployment, which is no longer receiving any traffic
|
||||
echo "Deleting ephemeral deployment"
|
||||
kubectl delete deployments/${TMP_DEPLOYMENT_NAME} --ignore-not-found=true || exit 1
|
||||
@@ -51,9 +51,9 @@ local params = std.extVar("__ksonnet/params").components["bg-guestbook"];
|
||||
"image": params.image,
|
||||
"name": params.name,
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": params.containerPort
|
||||
}
|
||||
{
|
||||
"containerPort": params.containerPort
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
local bgGuestbook = std.extVar("__ksonnet/components")["bg-guestbook"];
|
||||
local bgGuestbookSvc = bgGuestbook[0];
|
||||
local bgGuestbookDeploy = bgGuestbook[1];
|
||||
|
||||
[
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Pod",
|
||||
"metadata": {
|
||||
"generateName": "blue-green-",
|
||||
"annotations": {
|
||||
"argocd.argoproj.io/hook": "Sync",
|
||||
"deploy-manifest": std.manifestJson(bgGuestbookDeploy),
|
||||
"svc-manifest": std.manifestJson(bgGuestbookSvc),
|
||||
},
|
||||
},
|
||||
"spec": {
|
||||
"serviceAccountName": "blue-green-sa",
|
||||
"restartPolicy": "Never",
|
||||
"containers": [
|
||||
{
|
||||
"name": "blue-green",
|
||||
"image": "argoproj/argoexec:latest",
|
||||
"command": ["bash", "-c"],
|
||||
"args": ["
|
||||
curl -L -o /usr/local/bin/kubectl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl &&
|
||||
chmod +x /usr/local/bin/kubectl &&
|
||||
curl -sSL -o /usr/local/bin/blue-green.sh https://raw.githubusercontent.com/argoproj/argocd-example-apps/master/blue-green-deploy/blue-green.sh &&
|
||||
chmod +x /usr/local/bin/blue-green.sh &&
|
||||
blue-green.sh
|
||||
"],
|
||||
"env": [
|
||||
{
|
||||
"name": "DEPLOY_MANIFEST",
|
||||
"valueFrom": {
|
||||
"fieldRef": {
|
||||
"fieldPath": "metadata.annotations['deploy-manifest']"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "SERVICE_MANIFEST",
|
||||
"valueFrom": {
|
||||
"fieldRef": {
|
||||
"fieldPath": "metadata.annotations['svc-manifest']"
|
||||
}
|
||||
}
|
||||
},
|
||||
// NOTE: app.kubernetes.io/instance will get injected into the hook object
|
||||
{
|
||||
"name": "APPNAME",
|
||||
"valueFrom": {
|
||||
"fieldRef": {
|
||||
"fieldPath": "metadata.labels['app.kubernetes.io/instance']"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
// RBAC to allow the blue-green pod privileges to manipulate deployments and services
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ServiceAccount",
|
||||
"metadata": {
|
||||
"name": "blue-green-sa"
|
||||
}
|
||||
},
|
||||
{
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"kind": "Role",
|
||||
"metadata": {
|
||||
"name": "blue-green-role"
|
||||
},
|
||||
"rules": [
|
||||
{
|
||||
"apiGroups": [
|
||||
"apps",
|
||||
"extensions"
|
||||
],
|
||||
"resources": [
|
||||
"deployments",
|
||||
],
|
||||
"verbs": [
|
||||
"list",
|
||||
"get",
|
||||
"create",
|
||||
"update",
|
||||
"patch",
|
||||
"delete",
|
||||
]
|
||||
},
|
||||
{
|
||||
"apiGroups": [
|
||||
""
|
||||
],
|
||||
"resources": [
|
||||
"services"
|
||||
],
|
||||
"verbs": [
|
||||
"list",
|
||||
"get",
|
||||
"create",
|
||||
"update",
|
||||
"patch",
|
||||
"delete",
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"kind": "RoleBinding",
|
||||
"metadata": {
|
||||
"name": "blue-green-rolebinding"
|
||||
},
|
||||
"roleRef": {
|
||||
"apiGroup": "rbac.authorization.k8s.io",
|
||||
"kind": "Role",
|
||||
"name": "blue-green-role"
|
||||
},
|
||||
"subjects": [
|
||||
{
|
||||
"kind": "ServiceAccount",
|
||||
"name": "blue-green-sa"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1,20 +0,0 @@
|
||||
local bgGuestbook = std.extVar("__ksonnet/components")["bg-guestbook"];
|
||||
local bgGuestbookSvc = bgGuestbook[0];
|
||||
local bgGuestbookDeploy = bgGuestbook[1];
|
||||
local parseYaml = std.native("parseYaml");
|
||||
local bgWorkflow = parseYaml(importstr 'wf/bluegreen.yaml')[0];
|
||||
|
||||
[
|
||||
bgWorkflow + {
|
||||
spec +: {
|
||||
arguments +: {
|
||||
parameters : [
|
||||
{name: "deployment-name", value: bgGuestbookDeploy.metadata.name},
|
||||
{name: "service-name", value: bgGuestbookSvc.metadata.name},
|
||||
{name: "new-deployment-manifest", value: std.manifestJson(bgGuestbookDeploy)},
|
||||
{name: "new-service-manifest", value: std.manifestJson(bgGuestbookSvc)},
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
]
|
||||
@@ -9,11 +9,11 @@
|
||||
"bg-guestbook": {
|
||||
containerPort: 80,
|
||||
image: "gcr.io/heptio-images/ks-guestbook-demo:0.2",
|
||||
name: "bg-guestbook",
|
||||
name: "blue-green-guestbook",
|
||||
replicas: 3,
|
||||
servicePort: 80,
|
||||
type: "LoadBalancer",
|
||||
},
|
||||
"bg-workflow": {},
|
||||
"bg-pod": {},
|
||||
},
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
# This workflow performs a "blue-green" deployment, while preserving the original deployment object
|
||||
# and name. It accomplishes this by temporarily redirecting traffic to a *clone* of the original
|
||||
# deployment. Then after upgrading the original deployment to a later version, redirects traffic
|
||||
# back to the original (now upgraded) deployment.
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Workflow
|
||||
metadata:
|
||||
generateName: k8s-bluegreen-
|
||||
annotations:
|
||||
argocd.argoproj.io/hook: Sync
|
||||
spec:
|
||||
entrypoint: k8s-bluegreen
|
||||
arguments:
|
||||
parameters:
|
||||
- name: deployment-name
|
||||
- name: service-name
|
||||
- name: new-deployment-manifest
|
||||
- name: new-service-manifest
|
||||
|
||||
templates:
|
||||
- name: k8s-bluegreen
|
||||
steps:
|
||||
# 1. Create a parallel Kubernetes deployment with tweaks to name and selectors
|
||||
- - name: create-blue-deployment
|
||||
template: clone-deployment
|
||||
|
||||
# 2. Wait for parallel deployment to become ready
|
||||
- - name: wait-for-blue-deployment
|
||||
template: wait-deployment-ready
|
||||
arguments:
|
||||
parameters:
|
||||
- name: deployment-name
|
||||
value: '{{workflow.parameters.deployment-name}}-blue'
|
||||
|
||||
# 3. Patch the named service to point to the parallel deployment app
|
||||
- - name: switch-service-to-blue-deployment
|
||||
template: patch-service
|
||||
|
||||
# 4. Update the original deployment (receiving no traffic) with a new version
|
||||
- - name: apply-green-deployment
|
||||
template: apply-manifest
|
||||
arguments:
|
||||
parameters:
|
||||
- name: manifest
|
||||
value: '{{workflow.parameters.new-deployment-manifest}}'
|
||||
|
||||
# 5. Wait for the original deployment, now updated, to become ready
|
||||
- - name: wait-for-green-deployment
|
||||
template: wait-deployment-ready
|
||||
arguments:
|
||||
parameters:
|
||||
- name: deployment-name
|
||||
value: '{{workflow.parameters.deployment-name}}'
|
||||
|
||||
# dummy approval step for demo purposes. Sleeps for 30 seconds
|
||||
- - name: approve
|
||||
template: approve
|
||||
|
||||
# 6. Patch the named service to point to the original, now updated app
|
||||
- - name: switch-service-to-green-deployment
|
||||
template: apply-manifest
|
||||
arguments:
|
||||
parameters:
|
||||
- name: manifest
|
||||
value: '{{workflow.parameters.new-service-manifest}}'
|
||||
|
||||
# 7. Remove the cloned deployment (no longer receiving traffic)
|
||||
- - name: delete-cloned-deployment
|
||||
template: delete-deployment
|
||||
|
||||
# end of steps
|
||||
|
||||
# clone-deployment creates a "blue" clone of an existing deployment. The string -blue is appended to:
|
||||
# - metadata.name
|
||||
# - spec.selector.matchLabels
|
||||
# - spec.template.metadata.labels
|
||||
- name: clone-deployment
|
||||
container:
|
||||
image: argoproj/argoexec:v2.1.1
|
||||
command: [sh, -c, -x]
|
||||
args:
|
||||
- kubectl get --export -o json deployment.apps/{{workflow.parameters.deployment-name}} > /original-deploy &&
|
||||
jq -r '.metadata.name+="-blue" |
|
||||
.spec.template.metadata.labels += (.spec.template.metadata.labels | to_entries | map(select(.key != "applications.argoproj.io/app-name")) | map(.value+="-blue") | from_entries) |
|
||||
.spec.selector.matchLabels += (.spec.selector.matchLabels | to_entries | map(select(.key != "applications.argoproj.io/app-name")) | map(.value+="-blue") | from_entries)'
|
||||
/original-deploy > /cloned-deploy &&
|
||||
cat /cloned-deploy &&
|
||||
kubectl apply -o yaml -f /cloned-deploy
|
||||
|
||||
# apply-manifest takes a kubernetes manifest and carrys over the app-name label (if present)
|
||||
# before running `kubectl apply`. The label is used by ArgoCD for monitoring.
|
||||
- name: apply-manifest
|
||||
inputs:
|
||||
parameters:
|
||||
- name: manifest
|
||||
artifacts:
|
||||
- name: manifest-file
|
||||
path: /manifest
|
||||
raw:
|
||||
data: '{{inputs.parameters.manifest}}'
|
||||
container:
|
||||
image: argoproj/argoexec:v2.1.1
|
||||
command: [sh, -c, -x]
|
||||
args:
|
||||
- cp /manifest /manifest-new &&
|
||||
APP_NAME=$(kubectl get -n default -f /manifest-new -o json | jq -r '.metadata.labels."applications.argoproj.io/app-name"') &&
|
||||
if [ "$APP_NAME" != "null" ]; then
|
||||
jq -r --arg APP_NAME "$APP_NAME" '.metadata.labels."applications.argoproj.io/app-name" = $APP_NAME' /manifest-new > /manifest-new.tmp &&
|
||||
mv /manifest-new.tmp /manifest-new &&
|
||||
if [ "$(jq -r .spec.template.metadata.labels /manifest-new)" != "null" ]; then
|
||||
jq -r --arg APP_NAME "$APP_NAME" '.spec.template.metadata.labels."applications.argoproj.io/app-name" = $APP_NAME' /manifest-new > /manifest-new.tmp &&
|
||||
mv /manifest-new.tmp /manifest-new ;
|
||||
fi ;
|
||||
fi &&
|
||||
cat /manifest-new &&
|
||||
kubectl apply -f /manifest-new
|
||||
|
||||
# wait-deployment-ready waits for a deployment to become fully deployed and ready, using the
|
||||
# `kubectl rollout` command
|
||||
- name: wait-deployment-ready
|
||||
inputs:
|
||||
parameters:
|
||||
- name: deployment-name
|
||||
container:
|
||||
image: argoproj/argoexec:v2.1.1
|
||||
command: [kubectl, rollout, status, --watch=true, 'deployments/{{inputs.parameters.deployment-name}}']
|
||||
|
||||
# patch-service updates the service selector labels to point to the "blue" deployment
|
||||
- name: patch-service
|
||||
container:
|
||||
image: argoproj/argoexec:v2.1.1
|
||||
command: [sh, -c, -x]
|
||||
args:
|
||||
- kubectl get -n default service {{workflow.parameters.service-name}} --export -o json > /original-svc &&
|
||||
jq '.spec.selector = (.spec.selector | with_entries(.value+="-blue"))' /original-svc > /blue-svc &&
|
||||
kubectl apply -o yaml -f /blue-svc
|
||||
|
||||
- name: delete-deployment
|
||||
resource:
|
||||
action: delete
|
||||
manifest: |
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{workflow.parameters.deployment-name}}-blue
|
||||
|
||||
- name: approve
|
||||
container:
|
||||
image: argoproj/argoexec:v2.1.1
|
||||
command: [sleep, "30"]
|
||||
@@ -1,8 +1,9 @@
|
||||
local base = import "base.libsonnet";
|
||||
// uncomment if you reference ksonnet-lib
|
||||
// local k = import "k.libsonnet";
|
||||
// local deployment = k.apps.v1beta2.deployment;
|
||||
|
||||
base + {
|
||||
// Insert user-specified overrides here. For example if a component is named \"nginx-deployment\", you might have something like:\n")
|
||||
// "nginx-deployment"+: k.deployment.mixin.metadata.labels({foo: "bar"})
|
||||
// "nginx-deployment"+: deployment.mixin.metadata.withLabels({foo: "bar"})
|
||||
}
|
||||
Reference in new issue
Block a user