28 changed files with 540 additions and 0 deletions

No files matched your search

+11
View File
@@ -1 +1,12 @@
# ArgoCD Example Apps # ArgoCD Example Apps
This repository contains example ksonnet applications for demoing ArgoCD functionality. Feel free
to register this repository to your ArgoCD instance, or fork this repo and push your own commits
to explore ArgoCD and GitOps!
| Application | Description |
|-------------|-------------|
| [guestbook](guestbook/) | The ksonnet hello word application |
| [pre-post-sync](pre-post-sync/) | Demonstrates ArgoCD PreSync and PostSync hooks |
| [blue-green-deploy](blue-green-deploy/) | Demonstrates an ArgoCD Sync hook which performs a blue/green deployment |
| [sock-shop](sock-shop/) | A microservices demo application (https://microservices-demo.github.io) |
+4
View File
@@ -0,0 +1,4 @@
/lib
/.ksonnet/registries
/app.override.yaml
/.ks_environment
+11
View File
@@ -0,0 +1,11 @@
apiVersion: 0.1.0
environments:
default:
destination:
namespace: default
server: https://kubernetes.default.svc
k8sVersion: v1.10.0
path: default
kind: ksonnet.io/app
name: blue-green-deploy
version: 0.0.1
@@ -0,0 +1,64 @@
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components["bg-guestbook"];
[
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": params.name,
"annotations": {
"argocd.argoproj.io/hook": "Skip",
},
},
"spec": {
"ports": [
{
"port": params.servicePort,
"targetPort": params.containerPort
}
],
"selector": {
"app": params.name
},
"type": params.type
}
},
{
"apiVersion": "apps/v1beta2",
"kind": "Deployment",
"metadata": {
"name": params.name,
"annotations": {
"argocd.argoproj.io/hook": "Skip",
},
},
"spec": {
"replicas": params.replicas,
"selector": {
"matchLabels": {
"app": params.name
},
},
"template": {
"metadata": {
"labels": {
"app": params.name
}
},
"spec": {
"containers": [
{
"image": params.image,
"name": params.name,
"ports": [
{
"containerPort": params.containerPort
}
]
}
]
}
}
}
}
]
@@ -0,0 +1,20 @@
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)},
],
},
},
}
]
@@ -0,0 +1,19 @@
{
global: {
// User-defined global parameters; accessible to all component and environments, Ex:
// replicas: 4,
},
components: {
// Component-level parameters, defined initially from 'ks prototype use ...'
// Each object below should correspond to a component in the components/ directory
"bg-guestbook": {
containerPort: 80,
image: "gcr.io/heptio-images/ks-guestbook-demo:0.2",
name: "bg-guestbook",
replicas: 3,
servicePort: 80,
type: "LoadBalancer",
},
"bg-workflow": {},
},
}
@@ -0,0 +1,150 @@
# 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"]
@@ -0,0 +1,4 @@
local components = std.extVar("__ksonnet/components");
components + {
// Insert user-specified overrides here.
}
@@ -0,0 +1,2 @@
{
}
@@ -0,0 +1,8 @@
local base = import "base.libsonnet";
// uncomment if you reference ksonnet-lib
// local k = import "k.libsonnet";
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"})
}
@@ -0,0 +1,17 @@
local params = std.extVar("__ksonnet/params");
local globals = import "globals.libsonnet";
local envParams = params + {
components +: {
// Insert component parameter overrides here. Ex:
// guestbook +: {
// name: "guestbook-dev",
// replicas: params.global.replicas,
// },
},
};
{
components: {
[x]: envParams.components[x] + globals, for x in std.objectFields(envParams.components)
},
}
+12
View File
@@ -6,6 +6,18 @@ environments:
server: https://kubernetes.default.svc server: https://kubernetes.default.svc
k8sVersion: v1.10.0 k8sVersion: v1.10.0
path: default path: default
dev:
destination:
namespace: dev
server: https://kubernetes.default.svc
k8sVersion: v1.10.0
path: dev
prod:
destination:
namespace: prod
server: https://kubernetes.default.svc
k8sVersion: v1.10.0
path: prod
kind: ksonnet.io/app kind: ksonnet.io/app
name: guestbook name: guestbook
version: 0.0.1 version: 0.0.1
@@ -0,0 +1,2 @@
{
}
+8
View File
@@ -0,0 +1,8 @@
local base = import "base.libsonnet";
// uncomment if you reference ksonnet-lib
// local k = import "k.libsonnet";
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"})
}
@@ -0,0 +1,17 @@
local params = std.extVar("__ksonnet/params");
local globals = import "globals.libsonnet";
local envParams = params + {
components +: {
// Insert component parameter overrides here. Ex:
// guestbook +: {
// name: "guestbook-dev",
// replicas: params.global.replicas,
// },
},
};
{
components: {
[x]: envParams.components[x] + globals, for x in std.objectFields(envParams.components)
},
}
@@ -0,0 +1,2 @@
{
}
+8
View File
@@ -0,0 +1,8 @@
local base = import "base.libsonnet";
// uncomment if you reference ksonnet-lib
// local k = import "k.libsonnet";
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"})
}
@@ -0,0 +1,17 @@
local params = std.extVar("__ksonnet/params");
local globals = import "globals.libsonnet";
local envParams = params + {
components +: {
// Insert component parameter overrides here. Ex:
// guestbook +: {
// name: "guestbook-dev",
// replicas: params.global.replicas,
// },
},
};
{
components: {
[x]: envParams.components[x] + globals, for x in std.objectFields(envParams.components)
},
}
+4
View File
@@ -0,0 +1,4 @@
/lib
/.ksonnet/registries
/app.override.yaml
/.ks_environment
+11
View File
@@ -0,0 +1,11 @@
apiVersion: 0.1.0
environments:
default:
destination:
namespace: default
server: https://kubernetes.default.svc
k8sVersion: v1.10.0
path: default
kind: ksonnet.io/app
name: pre-post-sync
version: 0.0.1
@@ -0,0 +1,66 @@
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components["guestbook-ui"];
[
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": params.name
},
"spec": {
"ports": [
{
"port": params.servicePort,
"targetPort": params.containerPort
}
],
"selector": {
"app": params.name
},
"type": params.type
}
},
{
"apiVersion": "apps/v1beta2",
"kind": "Deployment",
"metadata": {
"name": params.name
},
"spec": {
"replicas": params.replicas,
"selector": {
"matchLabels": {
"app": params.name
},
},
"template": {
"metadata": {
"labels": {
"app": params.name
}
},
"spec": {
"containers": [
{
"image": params.image,
"name": params.name,
"ports": [
{
"containerPort": params.containerPort
}
],
// dummy readiness probe to slow down the rollout for demo/testing
"readinessProbe": {
"exec": {
"command": [ "sh", "-c", "exit 0" ],
},
"initialDelaySeconds": 10,
"periodSeconds": 30,
}
}
]
}
}
}
}
]
+20
View File
@@ -0,0 +1,20 @@
{
global: {
// User-defined global parameters; accessible to all component and environments, Ex:
// replicas: 4,
},
components: {
// Component-level parameters, defined initially from 'ks prototype use ...'
// Each object below should correspond to a component in the components/ directory
"guestbook-ui": {
containerPort: 80,
image: "gcr.io/heptio-images/ks-guestbook-demo:0.2",
name: "pre-post-sync",
replicas: 1,
servicePort: 80,
type: "ClusterIP",
},
"pre-sync-job": {},
"post-sync-job": {},
},
}
@@ -0,0 +1,16 @@
apiVersion: batch/v1
kind: Job
metadata:
generateName: after-
annotations:
argocd.argoproj.io/hook: PostSync
argocd.argoproj.io/hook-delete-policy: OnSuccess
spec:
template:
spec:
containers:
- name: sleep
image: alpine:latest
command: ["sleep", "10"]
restartPolicy: Never
backoffLimit: 0
@@ -0,0 +1,16 @@
apiVersion: batch/v1
kind: Job
metadata:
generateName: before-
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: OnSuccess
spec:
template:
spec:
containers:
- name: sleep
image: alpine:latest
command: ["sleep", "10"]
restartPolicy: Never
backoffLimit: 0
@@ -0,0 +1,4 @@
local components = std.extVar("__ksonnet/components");
components + {
// Insert user-specified overrides here.
}
@@ -0,0 +1,2 @@
{
}
@@ -0,0 +1,8 @@
local base = import "base.libsonnet";
// uncomment if you reference ksonnet-lib
// local k = import "k.libsonnet";
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"})
}
@@ -0,0 +1,17 @@
local params = std.extVar("__ksonnet/params");
local globals = import "globals.libsonnet";
local envParams = params + {
components +: {
// Insert component parameter overrides here. Ex:
// guestbook +: {
// name: "guestbook-dev",
// replicas: params.global.replicas,
// },
},
};
{
components: {
[x]: envParams.components[x] + globals, for x in std.objectFields(envParams.components)
},
}