commit 4a59d4bd2d46c125e7315140fb79753eaf68f1e2 Author: ermisw Date: Mon Nov 13 15:25:46 2023 +0100 first commit diff --git a/argo/carts.tgz b/argo/carts.tgz new file mode 100644 index 0000000..5cd9d3d Binary files /dev/null and b/argo/carts.tgz differ diff --git a/argo/carts/Chart.yaml b/argo/carts/Chart.yaml new file mode 100644 index 0000000..cfb84b9 --- /dev/null +++ b/argo/carts/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +description: A Helm chart for service carts +name: carts +version: 0.1.0 diff --git a/argo/carts/templates/NOTES.txt b/argo/carts/templates/NOTES.txt new file mode 100644 index 0000000..96ff70e --- /dev/null +++ b/argo/carts/templates/NOTES.txt @@ -0,0 +1,19 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range .Values.ingress.hosts }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "carts.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get svc -w {{ template "carts.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "carts.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "carts.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl port-forward $POD_NAME 8080:80 +{{- end }} diff --git a/argo/carts/templates/_helpers.tpl b/argo/carts/templates/_helpers.tpl new file mode 100644 index 0000000..8dd6d17 --- /dev/null +++ b/argo/carts/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "carts.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "carts.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "carts.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/argo/carts/templates/carts-db-deployment.yaml b/argo/carts/templates/carts-db-deployment.yaml new file mode 100644 index 0000000..3f72721 --- /dev/null +++ b/argo/carts/templates/carts-db-deployment.yaml @@ -0,0 +1,47 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: carts-db-mongodata +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi +status: {} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: carts-db + labels: + app: carts-db +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: carts-db + template: + metadata: + labels: + app: carts-db + deployment: carts-db + spec: + containers: + - name: carts-db + image: mongo + imagePullPolicy: IfNotPresent + ports: + - containerPort: 27017 + resources: {} + volumeMounts: + - mountPath: /data/db + name: carts-db-mongodata + restartPolicy: Always + volumes: + - name: carts-db-mongodata + persistentVolumeClaim: + claimName: carts-db-mongodata diff --git a/argo/carts/templates/carts-db-service.yaml b/argo/carts/templates/carts-db-service.yaml new file mode 100644 index 0000000..48a21ae --- /dev/null +++ b/argo/carts/templates/carts-db-service.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: carts-db +spec: + ports: + - name: carts-db + port: 27017 + targetPort: 27017 + selector: + app: carts-db \ No newline at end of file diff --git a/argo/carts/templates/keptn-hook.yaml b/argo/carts/templates/keptn-hook.yaml new file mode 100644 index 0000000..d0563a2 --- /dev/null +++ b/argo/carts/templates/keptn-hook.yaml @@ -0,0 +1,28 @@ +apiVersion: batch/v1 +kind: Job +metadata: + generateName: app-keptn-notification- + annotations: + argocd.argoproj.io/hook: Sync + argocd.argoproj.io/hook-delete-policy: HookSucceeded +spec: + template: + spec: + containers: + - name: keptn-notification + image: agrimmer/alpine-curl-uuid-kubectl:latest + command: ["/bin/sh","-c"] + args: ['while [[ $(kubectl get rollout {{ .Values.keptn.service }}-{{ .Values.keptn.stage }} -n {{ .Values.keptn.project }}-{{ .Values.keptn.stage }} -o "jsonpath={..status.conditions[?(@.type==\"Progressing\")].reason}") == "ReplicaSetUpdated" ]]; do echo "waiting for rollout" && sleep 1; done; UUID=$(uuidgen); now=$(TZ=UTC date "+%FT%T.00Z"); curl -X POST -H "Content-Type: application/cloudevents+json" -H "x-token: ${KEPTN_API_TOKEN}" --insecure -d "{\"contenttype\": \"application/json\", \"data\": { \"project\": \"{{ .Values.keptn.project }}\", \"service\": \"{{ .Values.keptn.service }}\", \"stage\": \"{{ .Values.keptn.stage }}\", \"deploymentURILocal\": \"http://{{ .Values.keptn.service }}-canary.{{ .Values.keptn.project }}-{{ .Values.keptn.stage }}\", \"deploymentstrategy\": \"blue_green_service\", \"teststrategy\": \"performance\"}, \"id\": \"${UUID}\", \"source\": \"argo\", \"specversion\": \"0.2\", \"time\": \"${now}\", \"type\": \"sh.keptn.events.deployment-finished\", \"shkeptncontext\": \"${UUID}\"}" ${KEPTN_API_URL}/v1/event'] + env: + - name: KEPTN_API_URL + valueFrom: + secretKeyRef: + name: argo + key: KEPTN_API_URL + - name: KEPTN_API_TOKEN + valueFrom: + secretKeyRef: + name: argo + key: KEPTN_API_TOKEN + restartPolicy: Never + backoffLimit: 2 \ No newline at end of file diff --git a/argo/carts/templates/rollout.yaml b/argo/carts/templates/rollout.yaml new file mode 100644 index 0000000..340c8e9 --- /dev/null +++ b/argo/carts/templates/rollout.yaml @@ -0,0 +1,75 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: {{ template "carts.fullname" . }} + labels: + app: {{ template "carts.name" . }} + chart: {{ template "carts.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + revisionHistoryLimit: 3 + selector: + matchLabels: + app: {{ template "carts.name" . }} + release: {{ .Release.Name }} + strategy: + blueGreen: + autoPromotionEnabled: false + activeService: {{ template "carts.name" . }}-primary + previewService: {{ template "carts.name" . }}-canary + template: + metadata: + labels: + app: {{ template "carts.name" . }} + release: {{ .Release.Name }} + spec: + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 8080 + protocol: TCP + env: + - name: DT_CUSTOM_PROP + value: "keptn_project={{ .Values.keptn.project }} keptn_service={{ .Values.keptn.service }} keptn_stage={{ .Values.keptn.stage }}" + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: "metadata.name" + - name: DEPLOYMENT_NAME + valueFrom: + fieldRef: + fieldPath: "metadata.labels['deployment']" + - name: CONTAINER_IMAGE + value: "{{ .Values.image }}" + - name: KEPTN_PROJECT + value: "{{ .Values.keptn.project }}" + - name: KEPTN_STAGE + value: "{{ .Values.keptn.stage }}" + - name: KEPTN_SERVICE + value: "{{ .Values.keptn.service }}" + livenessProbe: + httpGet: + path: /health + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 15 + readinessProbe: + httpGet: + path: /health + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 15 + resources: + limits: + cpu: 1000m + memory: 2048Mi + requests: + cpu: 500m + memory: 1024Mi diff --git a/argo/carts/templates/service.yaml b/argo/carts/templates/service.yaml new file mode 100644 index 0000000..8c0d093 --- /dev/null +++ b/argo/carts/templates/service.yaml @@ -0,0 +1,41 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "carts.name" . }}-primary + labels: + app: {{ template "carts.name" . }} + chart: {{ template "carts.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: 8080 + protocol: TCP + name: http + selector: + app: {{ template "carts.name" . }} + release: {{ .Release.Name }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "carts.name" . }}-canary + labels: + app: {{ template "carts.name" . }} + chart: {{ template "carts.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: 8080 + protocol: TCP + name: http + selector: + app: {{ template "carts.name" . }} + release: {{ .Release.Name }} + \ No newline at end of file diff --git a/argo/carts/values.yaml b/argo/carts/values.yaml new file mode 100644 index 0000000..4e9e8de --- /dev/null +++ b/argo/carts/values.yaml @@ -0,0 +1,28 @@ +replicaCount: 1 + +image: + repository: docker.io/keptnexamples/carts + tag: 0.13.1 + pullPolicy: Always + +service: + type: LoadBalancer + port: 80 + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + path: / + hosts: + - chart-example.local + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +keptn: + project: sockshop + stage: production + service: carts \ No newline at end of file diff --git a/carts-db.tgz b/carts-db.tgz new file mode 100644 index 0000000..6247f4c Binary files /dev/null and b/carts-db.tgz differ diff --git a/carts-db/Chart.yaml b/carts-db/Chart.yaml new file mode 100644 index 0000000..1d6030e --- /dev/null +++ b/carts-db/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +description: A Helm chart for service carts-db +name: carts-db +version: 0.1.0 diff --git a/carts-db/templates/carts-db-deployment.yaml b/carts-db/templates/carts-db-deployment.yaml new file mode 100644 index 0000000..1260d70 --- /dev/null +++ b/carts-db/templates/carts-db-deployment.yaml @@ -0,0 +1,53 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: carts-db-mongodata +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +status: {} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: carts-db + labels: + app: carts-db +spec: + replicas: {{ .Values.replicaCount }} + strategy: + type: Recreate + selector: + matchLabels: + app: carts-db + template: + metadata: + labels: + app: carts-db + deployment: carts-db + app.kubernetes.io/name: {{ .Values.keptn.service }} + app.kubernetes.io/instance: "{{ .Values.keptn.service }}-{{ .Values.keptn.deployment }}" + app.kubernetes.io/component: database + app.kubernetes.io/part-of: "{{ .Values.keptn.project }}" + app.kubernetes.io/managed-by: Keptn + app.kubernetes.io/version: {{ (split ":" .Values.image)._1 | default "latest" }} + spec: + containers: + - name: carts-db + image: {{ .Values.image }} + imagePullPolicy: IfNotPresent + ports: + - containerPort: 27017 + resources: {} + volumeMounts: + - mountPath: /data/db + name: carts-db-mongodata + restartPolicy: Always + volumes: + - name: carts-db-mongodata + persistentVolumeClaim: + claimName: carts-db-mongodata diff --git a/carts-db/templates/carts-db-service.yaml b/carts-db/templates/carts-db-service.yaml new file mode 100644 index 0000000..6fa9e78 --- /dev/null +++ b/carts-db/templates/carts-db-service.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: carts-db +spec: + ports: + - name: {{ .Values.service.name }} + port: {{ .Values.service.externalPort }} + targetPort: {{ .Values.service.internalPort }} + selector: + app: carts-db \ No newline at end of file diff --git a/carts-db/values.yaml b/carts-db/values.yaml new file mode 100644 index 0000000..d0fc26b --- /dev/null +++ b/carts-db/values.yaml @@ -0,0 +1,6 @@ +image: mongo +service: + externalPort: 27017 + internalPort: 27017 + name: carts-db +replicaCount: 1 diff --git a/carts.tgz b/carts.tgz new file mode 100644 index 0000000..80a6f63 Binary files /dev/null and b/carts.tgz differ diff --git a/carts/Chart.yaml b/carts/Chart.yaml new file mode 100644 index 0000000..cfb84b9 --- /dev/null +++ b/carts/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +description: A Helm chart for service carts +name: carts +version: 0.1.0 diff --git a/carts/templates/deployment.yaml b/carts/templates/deployment.yaml new file mode 100644 index 0000000..52dc329 --- /dev/null +++ b/carts/templates/deployment.yaml @@ -0,0 +1,77 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: carts +spec: + replicas: {{ .Values.replicaCount }} + strategy: + rollingUpdate: + maxUnavailable: 0 + type: RollingUpdate + selector: + matchLabels: + app: carts + template: + metadata: + labels: + app: carts + app.kubernetes.io/name: {{ .Values.keptn.service }} + app.kubernetes.io/instance: "{{ .Values.keptn.service }}-{{ .Values.keptn.deployment }}" + app.kubernetes.io/component: api + app.kubernetes.io/part-of: "{{ .Values.keptn.project }}" + app.kubernetes.io/managed-by: Keptn + app.kubernetes.io/version: {{ (split ":" .Values.image)._1 | default "latest" }} + spec: + containers: + - name: carts + image: "{{ .Values.image }}" + imagePullPolicy: IfNotPresent + ports: + - name: http + protocol: TCP + containerPort: 8080 + env: + - name: DT_CUSTOM_PROP + value: "version={{ .Chart.Version }} revision={{ .Release.Revision }} releasename={{ .Release.Name }} keptn_project={{ .Values.keptn.project }} keptn_service={{ .Values.keptn.service }} keptn_stage={{ .Values.keptn.stage }} keptn_deployment={{ .Values.keptn.deployment }}" + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: "metadata.name" + - name: DEPLOYMENT_NAME + valueFrom: + fieldRef: + fieldPath: "metadata.labels['deployment']" + - name: CONTAINER_IMAGE + value: "{{ .Values.image }}" + - name: KEPTN_PROJECT + value: "{{ .Chart.Name }}" + - name: KEPTN_STAGE + valueFrom: + fieldRef: + fieldPath: "metadata.namespace" + - name: KEPTN_SERVICE + value: "carts" + - name: UNLEASH_SERVER_URL + value: "http://unleash.unleash-dev/api" + livenessProbe: + httpGet: + path: /health + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 15 + readinessProbe: + httpGet: + path: /health + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 15 + resources: + limits: + cpu: 1000m + memory: 2048Mi + requests: + cpu: 500m + memory: 1024Mi diff --git a/carts/templates/service.yaml b/carts/templates/service.yaml new file mode 100644 index 0000000..daea781 --- /dev/null +++ b/carts/templates/service.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: carts +spec: + type: ClusterIP + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 8080 + selector: + app: carts diff --git a/carts/values.yaml b/carts/values.yaml new file mode 100644 index 0000000..559ee01 --- /dev/null +++ b/carts/values.yaml @@ -0,0 +1,2 @@ +image: docker.io/keptnexamples/carts:0.13.1 +replicaCount: 1 \ No newline at end of file diff --git a/dynatrace/dynatrace.conf.yaml b/dynatrace/dynatrace.conf.yaml new file mode 100644 index 0000000..8fece01 --- /dev/null +++ b/dynatrace/dynatrace.conf.yaml @@ -0,0 +1,2 @@ +spec_version: '0.1.0' +dtCreds: dynatrace \ No newline at end of file diff --git a/jmeter/basiccheck.jmx b/jmeter/basiccheck.jmx new file mode 100644 index 0000000..e83cd87 --- /dev/null +++ b/jmeter/basiccheck.jmx @@ -0,0 +1,177 @@ + + + + + + false + false + + + + SERVER_URL + carts.sockshop-staging.public.demo.keptn.sh + = + + + CHECK_PATH + / + = + + + DT_LTN + Default + = + + + DefaultThinkTime + 250 + = + + + SERVER_PORT + 80 + = + + + PROTOCOL + http + = + + + VUCount + 1 + = + + + LoopCount + 1 + = + + + + + + + + continue + + false + ${__P(LoopCount,${VUCount})} + + ${__P(VUCount,${VUCount})} + 1 + 1444323045000 + 1444323045000 + false + + + + + + + false + + + + + + + + true + + + import org.apache.jmeter.util.JMeterUtils; +import org.apache.jmeter.protocol.http.control.HeaderManager; +import java.io; +import java.util; + +// ------------------------------------------------------------------------------------- +// Generate the x-dynatrace-test header based on this best practic +// -> https://www.dynatrace.com/support/help/integrations/test-automation-frameworks/how-do-i-integrate-dynatrace-into-my-load-testing-process/ +// ------------------------------------------------------------------------------------- +String LTN=JMeterUtils.getProperty("DT_LTN"); +if((LTN == null) || (LTN.length() == 0)) { + if(vars != null) { + LTN = vars.get("DT_LTN"); + } +} +if(LTN == null) LTN = "NoTestName"; + +String LSN = (bsh.args.length > 0) ? bsh.args[0] : "Test Scenario"; +String TSN = sampler.getName(); +String VU = ctx.getThreadGroup().getName() + ctx.getThreadNum(); +String headerValue = "LSN="+ LSN + ";TSN=" + TSN + ";LTN=" + LTN + ";VU=" + VU + ";"; + +// ------------------------------------------- +// Set header +// ------------------------------------------- +HeaderManager hm = sampler.getHeaderManager(); +hm.removeHeaderNamed("x-dynatrace-test"); +hm.add(new org.apache.jmeter.protocol.http.control.Header("x-dynatrace-test", headerValue)); + + + + + + + ${__P(SERVER_URL,${SERVER_URL})} + ${__P(SERVER_PORT,${SERVER_PORT})} + ${__P(PROTOCOL,${PROTOCOL})} + + ${__P(CHECK_PATH,${CHECK_PATH})} + GET + true + false + true + false + + + + + + + + + + + + {__P(ThinkTime,${DefaultThinkTime})} + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + false + false + false + false + false + 0 + true + true + + + + + + + + diff --git a/jmeter/load.jmx b/jmeter/load.jmx new file mode 100644 index 0000000..235227a --- /dev/null +++ b/jmeter/load.jmx @@ -0,0 +1,191 @@ + + + + + + false + false + + + + SERVER_URL + carts.sockshop-staging.public.demo.keptn.sh + = + + + DefaultThinkTime + 250 + = + + + DT_LTN + Default + = + + + SERVER_PORT + 80 + = + + + PROTOCOL + http + = + + + VUCount + 1 + = + + + LoopCount + 1 + = + + + + + + + + continue + + false + ${__P(LoopCount,${LoopCount})} + + ${__P(VUCount,${VUCount})} + 1 + 1536064517000 + 1536064517000 + false + + + + + + + false + + + + + + Cache-Control + no-cache + + + Content-Type + application/json + + + json + true + + + + + + + + false + import org.apache.jmeter.util.JMeterUtils; +import org.apache.jmeter.protocol.http.control.HeaderManager; +import java.io; +import java.util; + +// ------------------------------------------------------------------------------------- +// Generate the x-dynatrace-test header based on this best practic +// -> https://www.dynatrace.com/support/help/integrations/test-automation-frameworks/how-do-i-integrate-dynatrace-into-my-load-testing-process/ +// ------------------------------------------------------------------------------------- +String LTN=JMeterUtils.getProperty("DT_LTN"); +if((LTN == null) || (LTN.length() == 0)) { + if(vars != null) { + LTN = vars.get("DT_LTN"); + } +} +if(LTN == null) LTN = "NoTestName"; + +String LSN = (bsh.args.length > 0) ? bsh.args[0] : "Test Scenario"; +String TSN = sampler.getName(); +String VU = ctx.getThreadGroup().getName() + ctx.getThreadNum(); +String headerValue = "LSN="+ LSN + ";TSN=" + TSN + ";LTN=" + LTN + ";VU=" + VU + ";"; + +// ------------------------------------------- +// Set header +// ------------------------------------------- +HeaderManager hm = sampler.getHeaderManager(); +hm.removeHeaderNamed("x-dynatrace-test"); +hm.add(new org.apache.jmeter.protocol.http.control.Header("x-dynatrace-test", headerValue)); + + + + true + + + + false + { + "itemId":"03fef6ac-1896-4ce8-bd69-b798f85c6e0b", + "unitPrice":"99.99" + } + = + + + + ${__P(SERVER_URL,${SERVER_URL})} + ${__P(SERVER_PORT,${SERVER_PORT})} + ${__P(PROTOCOL,${PROTOCOL})} + + /carts/1/items + POST + true + false + true + false + true + + + + + + + {__P(ThinkTime,${DefaultThinkTime})} + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + false + false + false + false + false + 0 + true + true + + + + + + + + diff --git a/lighthouse-source-dynatrace.yaml b/lighthouse-source-dynatrace.yaml new file mode 100644 index 0000000..2fc0e52 --- /dev/null +++ b/lighthouse-source-dynatrace.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +data: + sli-provider: dynatrace +kind: ConfigMap +metadata: + name: lighthouse-config-sockshop + namespace: keptn diff --git a/lighthouse-source-prometheus.yaml b/lighthouse-source-prometheus.yaml new file mode 100644 index 0000000..357112b --- /dev/null +++ b/lighthouse-source-prometheus.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +data: + sli-provider: prometheus +kind: ConfigMap +metadata: + name: lighthouse-config-sockshop + namespace: keptn diff --git a/manifests/manifest-carts-db.yaml b/manifests/manifest-carts-db.yaml new file mode 100644 index 0000000..24f4663 --- /dev/null +++ b/manifests/manifest-carts-db.yaml @@ -0,0 +1,58 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: carts-db-mongodata + namespace: sockshop-hardening +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi +status: {} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: carts-db + namespace: sockshop-hardening +spec: + replicas: 1 + selector: + matchLabels: + app: carts-db + strategy: + type: Recreate + template: + metadata: + labels: + app: carts-db + spec: + containers: + - image: mongo + name: carts-db + ports: + - containerPort: 27017 + resources: {} + volumeMounts: + - mountPath: /data/db + name: carts-db-mongodata + restartPolicy: Always + volumes: + - name: carts-db-mongodata + persistentVolumeClaim: + claimName: carts-db-mongodata +--- +apiVersion: v1 +kind: Service +metadata: + name: carts-db + namespace: sockshop-hardening +spec: + ports: + - name: "27017" + port: 27017 + targetPort: 27017 + selector: + app: carts-db diff --git a/manifests/manifest-carts.yaml b/manifests/manifest-carts.yaml new file mode 100644 index 0000000..0d242ca --- /dev/null +++ b/manifests/manifest-carts.yaml @@ -0,0 +1,88 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: carts + namespace: sockshop-hardening +spec: + replicas: 1 + selector: + matchLabels: + app: carts + template: + metadata: + labels: + app: carts + version: v1 + deployment: carts + spec: + containers: + - name: carts + image: docker.io/keptnexamples/carts:0.13.1 + env: + - name: JAVA_OPTS + value: -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=128m -XX:+UseG1GC -Djava.security.egd=file:/dev/urandom + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: "metadata.name" + - name: KUBERNETES_NAMESPACE + valueFrom: + fieldRef: + fieldPath: "metadata.namespace" + - name: DEPLOYMENT_NAME + valueFrom: + fieldRef: + fieldPath: "metadata.labels['deployment']" + - name: CONTAINER_IMAGE + value: docker.io/keptnexamples/carts:0.13.1 + - name: DT_CUSTOM_PROP + value: "keptn_stage=hardening keptn_project=sockshop keptn_service=carts" + resources: + limits: + cpu: 500m + memory: 1024Mi + requests: + cpu: 400m + memory: 768Mi + ports: + - containerPort: 8080 + volumeMounts: + - mountPath: /tmp + name: tmp-volume + livenessProbe: + httpGet: + path: /health + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 15 + readinessProbe: + httpGet: + path: /health + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 15 + volumes: + - name: tmp-volume + emptyDir: + medium: Memory + nodeSelector: + beta.kubernetes.io/os: linux +--- +apiVersion: v1 +kind: Service +metadata: + name: carts + labels: + app: carts + namespace: sockshop-hardening +spec: + ports: + - name: http + port: 80 + targetPort: 8080 + selector: + app: carts + type: LoadBalancer diff --git a/remediation.yaml b/remediation.yaml new file mode 100644 index 0000000..22cfc56 --- /dev/null +++ b/remediation.yaml @@ -0,0 +1,18 @@ +apiVersion: spec.keptn.sh/0.1.4 +kind: Remediation +metadata: + name: carts-remediation +spec: + remediations: + - problemType: Response time degradation + actionsOnOpen: + - action: scaling + name: scaling + description: Scale up + value: "1" + - problemType: response_time_p90 + actionsOnOpen: + - action: scaling + name: scaling + description: Scale up + value: "1" diff --git a/remediation_feature_toggle.yaml b/remediation_feature_toggle.yaml new file mode 100644 index 0000000..343152f --- /dev/null +++ b/remediation_feature_toggle.yaml @@ -0,0 +1,20 @@ +apiVersion: spec.keptn.sh/0.1.4 +kind: Remediation +metadata: + name: carts-remediation +spec: + remediations: + - problemType: Response time degradation + actionsOnOpen: + - action: toggle-feature + name: Toogle feature flag + description: Toogle feature flag EnableItemCache to ON + value: + EnableItemCache: "on" + - problemType: Failure rate increase + actionsOnOpen: + - action: toggle-feature + name: Toogle feature flag + description: Toogle feature flag EnablePromotion to OFF + value: + EnablePromotion: "off" diff --git a/shipyard-argo.yaml b/shipyard-argo.yaml new file mode 100644 index 0000000..a2770e3 --- /dev/null +++ b/shipyard-argo.yaml @@ -0,0 +1,18 @@ +apiVersion: "spec.keptn.sh/0.2.2" +kind: "Shipyard" +metadata: + name: "shipyard-sockshop" +spec: + stages: + - name: "production" + sequences: + - name: "artifact-delivery" + tasks: + - name: "deployment" + properties: + deploymentstrategy: "blue_green_service" + - name: "test" + properties: + teststrategy: "performance" + - name: "evaluation" + - name: "release" diff --git a/shipyard-quality-gates.yaml b/shipyard-quality-gates.yaml new file mode 100644 index 0000000..641c5b9 --- /dev/null +++ b/shipyard-quality-gates.yaml @@ -0,0 +1,7 @@ +apiVersion: "spec.keptn.sh/0.2.2" +kind: "Shipyard" +metadata: + name: "shipyard-quality-gates" +spec: + stages: + - name: "hardening" diff --git a/shipyard.yaml b/shipyard.yaml new file mode 100644 index 0000000..1ec6727 --- /dev/null +++ b/shipyard.yaml @@ -0,0 +1,96 @@ +apiVersion: "spec.keptn.sh/0.2.2" +kind: "Shipyard" +metadata: + name: "shipyard-sockshop" +spec: + stages: + - name: "dev" + sequences: + - name: "delivery" + tasks: + - name: "deployment" + properties: + deploymentstrategy: "direct" + - name: "test" + properties: + teststrategy: "functional" + - name: "evaluation" + - name: "release" + - name: "delivery-direct" + tasks: + - name: "deployment" + properties: + deploymentstrategy: "direct" + - name: "release" + + - name: "staging" + sequences: + - name: "delivery" + triggeredOn: + - event: "dev.delivery.finished" + tasks: + - name: "deployment" + properties: + deploymentstrategy: "blue_green_service" + - name: "test" + properties: + teststrategy: "performance" + - name: "evaluation" + - name: "release" + - name: "rollback" + triggeredOn: + - event: "staging.delivery.finished" + selector: + match: + result: "fail" + tasks: + - name: "rollback" + - name: "delivery-direct" + triggeredOn: + - event: "dev.delivery-direct.finished" + tasks: + - name: "deployment" + properties: + deploymentstrategy: "direct" + - name: "release" + + - name: "production" + sequences: + - name: "delivery" + triggeredOn: + - event: "staging.delivery.finished" + tasks: + - name: "deployment" + properties: + deploymentstrategy: "blue_green_service" + - name: "release" + - name: "rollback" + triggeredOn: + - event: "production.delivery.finished" + selector: + match: + result: "fail" + tasks: + - name: "rollback" + - name: "delivery-direct" + triggeredOn: + - event: "staging.delivery-direct.finished" + tasks: + - name: "deployment" + properties: + deploymentstrategy: "direct" + - name: "release" + + - name: "remediation" + triggeredOn: + - event: "production.remediation.finished" + selector: + match: + evaluation.result: "fail" + tasks: + - name: "get-action" + - name: "action" + - name: "evaluation" + triggeredAfter: "15m" + properties: + timeframe: "15m" diff --git a/sli-config-argo-prometheus.yaml b/sli-config-argo-prometheus.yaml new file mode 100644 index 0000000..af25f11 --- /dev/null +++ b/sli-config-argo-prometheus.yaml @@ -0,0 +1,6 @@ +--- +spec_version: '1.0' +indicators: + response_time_p50: histogram_quantile(0.5, sum by(le) (rate(http_response_time_milliseconds_bucket{handler="ItemsController.addToCart",job="$SERVICE-$PROJECT-$STAGE-canary"}[$DURATION_SECONDS]))) + response_time_p90: histogram_quantile(0.9, sum by(le) (rate(http_response_time_milliseconds_bucket{handler="ItemsController.addToCart",job="$SERVICE-$PROJECT-$STAGE-canary"}[$DURATION_SECONDS]))) + response_time_p95: histogram_quantile(0.95, sum by(le) (rate(http_response_time_milliseconds_bucket{handler="ItemsController.addToCart",job="$SERVICE-$PROJECT-$STAGE-canary"}[$DURATION_SECONDS]))) \ No newline at end of file diff --git a/sli-config-dynatrace-no-deployment-tag.yaml b/sli-config-dynatrace-no-deployment-tag.yaml new file mode 100644 index 0000000..59a6756 --- /dev/null +++ b/sli-config-dynatrace-no-deployment-tag.yaml @@ -0,0 +1,8 @@ +--- +spec_version: '1.0' +indicators: + throughput: "metricSelector=builtin:service.requestCount.total:merge(\"dt.entity.service\"):sum&entitySelector=type(SERVICE),tag(keptn_project:$PROJECT),tag(keptn_stage:$STAGE),tag(keptn_service:$SERVICE)" + error_rate: "metricSelector=builtin:service.errors.total.count:merge(\"dt.entity.service\"):avg&entitySelector=type(SERVICE),tag(keptn_project:$PROJECT),tag(keptn_stage:$STAGE),tag(keptn_service:$SERVICE)" + response_time_p50: "metricSelector=builtin:service.response.time:merge(\"dt.entity.service\"):percentile(50)&entitySelector=type(SERVICE),tag(keptn_project:$PROJECT),tag(keptn_stage:$STAGE),tag(keptn_service:$SERVICE)" + response_time_p90: "metricSelector=builtin:service.response.time:merge(\"dt.entity.service\"):percentile(90)&entitySelector=type(SERVICE),tag(keptn_project:$PROJECT),tag(keptn_stage:$STAGE),tag(keptn_service:$SERVICE)" + response_time_p95: "metricSelector=builtin:service.response.time:merge(\"dt.entity.service\"):percentile(95)&entitySelector=type(SERVICE),tag(keptn_project:$PROJECT),tag(keptn_stage:$STAGE),tag(keptn_service:$SERVICE)" \ No newline at end of file diff --git a/sli-config-dynatrace.yaml b/sli-config-dynatrace.yaml new file mode 100644 index 0000000..26089df --- /dev/null +++ b/sli-config-dynatrace.yaml @@ -0,0 +1,8 @@ +--- +spec_version: '1.0' +indicators: + throughput: "metricSelector=builtin:service.requestCount.total:merge(\"dt.entity.service\"):sum&entitySelector=type(SERVICE),tag(keptn_project:$PROJECT),tag(keptn_stage:$STAGE),tag(keptn_service:$SERVICE),tag(keptn_deployment:$DEPLOYMENT)" + error_rate: "metricSelector=builtin:service.errors.total.count:merge(\"dt.entity.service\"):avg&entitySelector=type(SERVICE),tag(keptn_project:$PROJECT),tag(keptn_stage:$STAGE),tag(keptn_service:$SERVICE),tag(keptn_deployment:$DEPLOYMENT)" + response_time_p50: "metricSelector=builtin:service.response.time:merge(\"dt.entity.service\"):percentile(50)&entitySelector=type(SERVICE),tag(keptn_project:$PROJECT),tag(keptn_stage:$STAGE),tag(keptn_service:$SERVICE),tag(keptn_deployment:$DEPLOYMENT)" + response_time_p90: "metricSelector=builtin:service.response.time:merge(\"dt.entity.service\"):percentile(90)&entitySelector=type(SERVICE),tag(keptn_project:$PROJECT),tag(keptn_stage:$STAGE),tag(keptn_service:$SERVICE),tag(keptn_deployment:$DEPLOYMENT)" + response_time_p95: "metricSelector=builtin:service.response.time:merge(\"dt.entity.service\"):percentile(95)&entitySelector=type(SERVICE),tag(keptn_project:$PROJECT),tag(keptn_stage:$STAGE),tag(keptn_service:$SERVICE),tag(keptn_deployment:$DEPLOYMENT)" \ No newline at end of file diff --git a/sli-config-prometheus.yaml b/sli-config-prometheus.yaml new file mode 100644 index 0000000..e4cb42f --- /dev/null +++ b/sli-config-prometheus.yaml @@ -0,0 +1,6 @@ +--- +spec_version: '1.0' +indicators: + response_time_p50: histogram_quantile(0.5, sum by(le) (rate(http_response_time_milliseconds_bucket{handler="ItemsController.addToCart",job="$SERVICE-$PROJECT-$STAGE-$DEPLOYMENT"}[$DURATION_SECONDS]))) + response_time_p90: histogram_quantile(0.9, sum by(le) (rate(http_response_time_milliseconds_bucket{handler="ItemsController.addToCart",job="$SERVICE-$PROJECT-$STAGE-$DEPLOYMENT"}[$DURATION_SECONDS]))) + response_time_p95: histogram_quantile(0.95, sum by(le) (rate(http_response_time_milliseconds_bucket{handler="ItemsController.addToCart",job="$SERVICE-$PROJECT-$STAGE-$DEPLOYMENT"}[$DURATION_SECONDS]))) \ No newline at end of file diff --git a/slo-quality-gates.yaml b/slo-quality-gates.yaml new file mode 100644 index 0000000..1fa9d13 --- /dev/null +++ b/slo-quality-gates.yaml @@ -0,0 +1,23 @@ +--- +spec_version: "1.0" +comparison: + aggregate_function: "avg" + compare_with: "single_result" + include_result_with_score: "pass" + number_of_comparison_results: 1 +filter: +objectives: + - sli: "response_time_p95" + displayName: "Response time P95" + key_sli: false + pass: # pass if (relative change <= 10% AND absolute value is < 600ms) + - criteria: + - "<=+10%" # relative values require a prefixed sign (plus or minus) + - "<600" # absolute values only require a logical operator + warning: # if the response time is below 800ms, the result should be a warning + - criteria: + - "<=800" + weight: 1 +total_score: + pass: "90%" + warning: "75%" \ No newline at end of file diff --git a/slo-self-healing-dynatrace.yaml b/slo-self-healing-dynatrace.yaml new file mode 100644 index 0000000..9101c6e --- /dev/null +++ b/slo-self-healing-dynatrace.yaml @@ -0,0 +1,30 @@ +--- +spec_version: "1.0" +comparison: + aggregate_function: "avg" + compare_with: "single_result" + include_result_with_score: "pass" + number_of_comparison_results: 1 +filter: +objectives: + - sli: "response_time_p90" + displayName: "Response time P90" + key_sli: false + pass: # pass if (relative change <= 10% AND absolute value is < 1000) + - criteria: + - "<=+10%" # relative values require a prefixed sign (plus or minus) + - "<1000" # absolute values only require a logical operator + warning: # if the response time is below 1200ms, the result should be a warning + - criteria: + - "<=1200" + weight: 1 + - sli: "problem_open" + displayName: "Problem open" + key_sli: true + pass: + - criteria: + - "=0" + weight: 1 +total_score: + pass: "90%" + warning: "40%" diff --git a/slo-self-healing-prometheus.yaml b/slo-self-healing-prometheus.yaml new file mode 100644 index 0000000..3291113 --- /dev/null +++ b/slo-self-healing-prometheus.yaml @@ -0,0 +1,23 @@ +--- +spec_version: "1.0" +comparison: + aggregate_function: "avg" + compare_with: "single_result" + include_result_with_score: "pass" + number_of_comparison_results: 1 +filter: +objectives: + - sli: "response_time_p90" + displayName: "Response time P90" + key_sli: false + pass: # pass if (relative change <= 10% AND absolute value is < 1000) + - criteria: + - "<=+10%" # relative values require a prefixed sign (plus or minus) + - "<1000" # absolute values only require a logical operator + warning: # if the response time is below 1200ms, the result should be a warning + - criteria: + - "<=1200" + weight: 1 +total_score: + pass: "90%" + warning: "40%"