diff --git a/charts/appmesh-gateway/.helmignore b/charts/appmesh-gateway/.helmignore new file mode 100644 index 00000000..f0c13194 --- /dev/null +++ b/charts/appmesh-gateway/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/charts/appmesh-gateway/Chart.yaml b/charts/appmesh-gateway/Chart.yaml new file mode 100644 index 00000000..b31e96c2 --- /dev/null +++ b/charts/appmesh-gateway/Chart.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +name: appmesh-gateway +description: Flagger Gateway for AWS App Mesh is an edge L7 load balancer that exposes applications outside the mesh. +version: 1.0.0 +appVersion: 1.0.0 +home: https://flagger.app +icon: https://raw.githubusercontent.com/weaveworks/flagger/master/docs/logo/weaveworks.png +sources: + - https://github.com/stefanprodan/appmesh-gateway +maintainers: + - name: Stefan Prodan + url: https://github.com/stefanprodan + email: stefanprodan@users.noreply.github.com +keywords: + - flagger + - appmesh + - envoy + - gateway + - ingress diff --git a/charts/appmesh-gateway/README.md b/charts/appmesh-gateway/README.md new file mode 100644 index 00000000..12d1f47b --- /dev/null +++ b/charts/appmesh-gateway/README.md @@ -0,0 +1,87 @@ +# Flagger Gateway for App Mesh + +[Flagger Gateway for App Mesh](https://github.com/stefanprodan/appmesh-gateway) is an +Envoy-powered load balancer that exposes applications outside the mesh. +The gateway facilitates canary deployments and A/B testing for user-facing web applications running on AWS App Mesh. + +## Prerequisites + +* Kubernetes >= 1.13 +* [App Mesh controller](https://github.com/aws/eks-charts/tree/master/stable/appmesh-controller) >= 0.2.0 +* [App Mesh inject](https://github.com/aws/eks-charts/tree/master/stable/appmesh-inject) >= 0.2.0 + +## Installing the Chart + +Add Flagger Helm repository: + +```console +$ helm repo add flagger https://flagger.app +``` + +Create a namespace with App Mesh sidecar injection enabled: + +```sh +kubectl create ns flagger-system +kubectl label namespace test appmesh.k8s.aws/sidecarInjectorWebhook=enabled +``` + +Install App Mesh Gateway for an existing mesh: + +```sh +helm upgrade -i appmesh-gateway flagger/appmesh-gateway \ +--namespace flagger-system \ +--set mesh.name=global +``` + +Optionally you can create a mesh at install time: + +```sh +helm upgrade -i appmesh-gateway flagger/appmesh-gateway \ +--namespace flagger-system \ +--set mesh.name=global \ +--set mesh.create=true +``` + +The [configuration](#configuration) section lists the parameters that can be configured during installation. + +## Uninstalling the Chart + +To uninstall/delete the `appmesh-gateway` deployment: + +```console +helm delete --purge appmesh-gateway +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Configuration + +The following tables lists the configurable parameters of the chart and their default values. + +Parameter | Description | Default +--- | --- | --- +`service.type` | When set to LoadBalancer it creates an AWS NLB | `LoadBalancer` +`proxy.access_log_path` | to enable the access logs, set it to `/dev/stdout` | `/dev/null` +`proxy.image.repository` | image repository | `envoyproxy/envoy` +`proxy.image.tag` | image tag | `` +`proxy.image.pullPolicy` | image pull policy | `IfNotPresent` +`controller.image.repository` | image repository | `weaveworks/flagger-appmesh-gateway` +`controller.image.tag` | image tag | `` +`controller.image.pullPolicy` | image pull policy | `IfNotPresent` +`resources.requests/cpu` | pod CPU request | `100m` +`resources.requests/memory` | pod memory request | `128Mi` +`resources.limits/memory` | pod memory limit | `2Gi` +`nodeSelector` | node labels for pod assignment | `{}` +`tolerations` | list of node taints to tolerate | `[]` +`rbac.create` | if `true`, create and use RBAC resources | `true` +`rbac.pspEnabled` | If `true`, create and use a restricted pod security policy | `false` +`serviceAccount.create` | If `true`, create a new service account | `true` +`serviceAccount.name` | Service account to be used | None +`mesh.create` | If `true`, create mesh custom resource | `false` +`mesh.name` | The name of the mesh to use | `global` +`mesh.discovery` | The service discovery type to use, can be dns or cloudmap | `dns` +`hpa.enabled` | `true` if HPA resource should be created, metrics-server is required | `true` +`hpa.maxReplicas` | number of max replicas | `3` +`hpa.cpu` | average total CPU usage per pod (1-100) | `99` +`hpa.memory` | average memory usage per pod (100Mi-1Gi) | None +`discovery.optIn` | `true` if only services with the 'expose' annotation are discoverable | `true` diff --git a/charts/appmesh-gateway/templates/NOTES.txt b/charts/appmesh-gateway/templates/NOTES.txt new file mode 100644 index 00000000..8ebd989e --- /dev/null +++ b/charts/appmesh-gateway/templates/NOTES.txt @@ -0,0 +1 @@ +App Mesh Gateway installed! \ No newline at end of file diff --git a/charts/appmesh-gateway/templates/_helpers.tpl b/charts/appmesh-gateway/templates/_helpers.tpl new file mode 100644 index 00000000..05f80903 --- /dev/null +++ b/charts/appmesh-gateway/templates/_helpers.tpl @@ -0,0 +1,56 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "appmesh-gateway.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 "appmesh-gateway.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 "appmesh-gateway.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "appmesh-gateway.labels" -}} +app.kubernetes.io/name: {{ include "appmesh-gateway.name" . }} +helm.sh/chart: {{ include "appmesh-gateway.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "appmesh-gateway.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "appmesh-gateway.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/charts/appmesh-gateway/templates/account.yaml b/charts/appmesh-gateway/templates/account.yaml new file mode 100644 index 00000000..3c0e3606 --- /dev/null +++ b/charts/appmesh-gateway/templates/account.yaml @@ -0,0 +1,8 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "appmesh-gateway.serviceAccountName" . }} + labels: +{{ include "appmesh-gateway.labels" . | indent 4 }} +{{- end }} diff --git a/charts/appmesh-gateway/templates/config.yaml b/charts/appmesh-gateway/templates/config.yaml new file mode 100644 index 00000000..f41bb20b --- /dev/null +++ b/charts/appmesh-gateway/templates/config.yaml @@ -0,0 +1,41 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "appmesh-gateway.fullname" . }} + labels: +{{ include "appmesh-gateway.labels" . | indent 4 }} +data: + envoy.yaml: |- + admin: + access_log_path: {{ .Values.proxy.access_log_path }} + address: + socket_address: + address: 0.0.0.0 + port_value: 8081 + + dynamic_resources: + ads_config: + api_type: GRPC + grpc_services: + - envoy_grpc: + cluster_name: xds + cds_config: + ads: {} + lds_config: + ads: {} + + static_resources: + clusters: + - name: xds + connect_timeout: 0.50s + type: static + http2_protocol_options: {} + load_assignment: + cluster_name: xds + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: 127.0.0.1 + port_value: 18000 diff --git a/charts/appmesh-gateway/templates/deployment.yaml b/charts/appmesh-gateway/templates/deployment.yaml new file mode 100644 index 00000000..fca9b9d1 --- /dev/null +++ b/charts/appmesh-gateway/templates/deployment.yaml @@ -0,0 +1,144 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "appmesh-gateway.fullname" . }} + labels: +{{ include "appmesh-gateway.labels" . | indent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + strategy: + type: Recreate + selector: + matchLabels: + app.kubernetes.io/name: {{ include "appmesh-gateway.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "appmesh-gateway.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: appmesh + annotations: + prometheus.io/scrape: "true" + prometheus.io/path: "/stats/prometheus" + prometheus.io/port: "8081" + # exclude inbound traffic on port 8080 + appmesh.k8s.aws/ports: "444" + # exclude egress traffic to xDS server and Kubernetes API + appmesh.k8s.aws/egressIgnoredPorts: "18000,22,443" + checksum/config: {{ include (print $.Template.BasePath "/config.yaml") . | sha256sum | quote }} + spec: + serviceAccountName: {{ include "appmesh-gateway.serviceAccountName" . }} + terminationGracePeriodSeconds: 45 + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchLabels: + app.kubernetes.io/name: {{ include "appmesh-gateway.name" . }} + topologyKey: kubernetes.io/hostname + weight: 100 + volumes: + - name: appmesh-gateway-config + configMap: + name: {{ template "appmesh-gateway.fullname" . }} + containers: + - name: controller + image: "{{ .Values.controller.image.repository }}:{{ .Values.controller.image.tag }}" + imagePullPolicy: {{ .Values.controller.image.pullPolicy }} + securityContext: + readOnlyRootFilesystem: true + runAsUser: 10001 + capabilities: + drop: + - ALL + add: + - NET_BIND_SERVICE + command: + - ./appmesh-gateway + - --opt-in={{ .Values.discovery.optIn }} + - --gateway-mesh={{ .Values.mesh.name }} + - --gateway-name=$(POD_SERVICE_ACCOUNT) + - --gateway-namespace=$(POD_NAMESPACE) + env: + - name: POD_SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + ports: + - name: grpc + containerPort: 18000 + protocol: TCP + livenessProbe: + initialDelaySeconds: 5 + tcpSocket: + port: grpc + readinessProbe: + initialDelaySeconds: 5 + tcpSocket: + port: grpc + resources: + limits: + memory: 1Gi + requests: + cpu: 10m + memory: 32Mi + - name: proxy + image: "{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }}" + imagePullPolicy: {{ .Values.proxy.image.pullPolicy }} + securityContext: + capabilities: + drop: + - ALL + add: + - NET_BIND_SERVICE + args: + - -c + - /config/envoy.yaml + - --service-cluster $(POD_NAMESPACE) + - --service-node $(POD_NAME) + - --log-level info + - --base-id 1234 + ports: + - name: admin + containerPort: 8081 + protocol: TCP + - name: http + containerPort: 8080 + protocol: TCP + livenessProbe: + initialDelaySeconds: 5 + tcpSocket: + port: admin + readinessProbe: + initialDelaySeconds: 5 + httpGet: + path: /ready + port: admin + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + volumeMounts: + - name: appmesh-gateway-config + mountPath: /config + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/charts/appmesh-gateway/templates/hpa.yaml b/charts/appmesh-gateway/templates/hpa.yaml new file mode 100644 index 00000000..c24a452e --- /dev/null +++ b/charts/appmesh-gateway/templates/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.hpa.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ template "appmesh-gateway.fullname" . }} + labels: +{{ include "appmesh-gateway.labels" . | indent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ template "appmesh-gateway.fullname" . }} + minReplicas: {{ .Values.replicaCount }} + maxReplicas: {{ .Values.hpa.maxReplicas }} + metrics: + {{- if .Values.hpa.cpu }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.hpa.cpu }} + {{- end }} + {{- if .Values.hpa.memory }} + - type: Resource + resource: + name: memory + targetAverageValue: {{ .Values.hpa.memory }} + {{- end }} +{{- end }} diff --git a/charts/appmesh-gateway/templates/mesh.yaml b/charts/appmesh-gateway/templates/mesh.yaml new file mode 100644 index 00000000..8542dd39 --- /dev/null +++ b/charts/appmesh-gateway/templates/mesh.yaml @@ -0,0 +1,12 @@ +{{- if .Values.mesh.create }} +apiVersion: appmesh.k8s.aws/v1beta1 +kind: Mesh +metadata: + name: {{ .Values.mesh.name }} + annotations: + helm.sh/resource-policy: keep + labels: +{{ include "appmesh-gateway.labels" . | indent 4 }} +spec: + serviceDiscoveryType: {{ .Values.mesh.discovery }} +{{- end }} diff --git a/charts/appmesh-gateway/templates/psp.yaml b/charts/appmesh-gateway/templates/psp.yaml new file mode 100644 index 00000000..20444979 --- /dev/null +++ b/charts/appmesh-gateway/templates/psp.yaml @@ -0,0 +1,57 @@ +{{- if .Values.rbac.pspEnabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "appmesh-gateway.fullname" . }} + labels: +{{ include "appmesh-gateway.labels" . | indent 4 }} + annotations: + seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*' +spec: + privileged: false + hostIPC: false + hostNetwork: false + hostPID: false + readOnlyRootFilesystem: false + allowPrivilegeEscalation: false + allowedCapabilities: + - '*' + fsGroup: + rule: RunAsAny + runAsUser: + rule: RunAsAny + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + volumes: + - '*' +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "appmesh-gateway.fullname" . }}-psp + labels: +{{ include "appmesh-gateway.labels" . | indent 4 }} +rules: + - apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "appmesh-gateway.fullname" . }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "appmesh-gateway.fullname" . }}-psp + labels: +{{ include "appmesh-gateway.labels" . | indent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "appmesh-gateway.fullname" . }}-psp +subjects: + - kind: ServiceAccount + name: {{ template "appmesh-gateway.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/appmesh-gateway/templates/rbac.yaml b/charts/appmesh-gateway/templates/rbac.yaml new file mode 100644 index 00000000..51e7fa78 --- /dev/null +++ b/charts/appmesh-gateway/templates/rbac.yaml @@ -0,0 +1,39 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: {{ template "appmesh-gateway.fullname" . }} + labels: +{{ include "appmesh-gateway.labels" . | indent 4 }} +rules: + - apiGroups: + - "" + resources: + - services + verbs: ["*"] + - apiGroups: + - appmesh.k8s.aws + resources: + - meshes + - meshes/status + - virtualnodes + - virtualnodes/status + - virtualservices + - virtualservices/status + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: {{ template "appmesh-gateway.fullname" . }} + labels: +{{ include "appmesh-gateway.labels" . | indent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "appmesh-gateway.fullname" . }} +subjects: +- name: {{ template "appmesh-gateway.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + kind: ServiceAccount +{{- end }} diff --git a/charts/appmesh-gateway/templates/service.yaml b/charts/appmesh-gateway/templates/service.yaml new file mode 100644 index 00000000..e11c2dd1 --- /dev/null +++ b/charts/appmesh-gateway/templates/service.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "appmesh-gateway.fullname" . }} + annotations: + gateway.appmesh.k8s.aws/expose: "false" + {{- if eq .Values.service.type "LoadBalancer" }} + service.beta.kubernetes.io/aws-load-balancer-type: "nlb" + {{- end }} + labels: +{{ include "appmesh-gateway.labels" . | indent 4 }} +spec: + type: {{ .Values.service.type }} + {{- if eq .Values.service.type "LoadBalancer" }} + externalTrafficPolicy: Local + {{- end }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app.kubernetes.io/name: {{ include "appmesh-gateway.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/charts/appmesh-gateway/values.yaml b/charts/appmesh-gateway/values.yaml new file mode 100644 index 00000000..b5b89be2 --- /dev/null +++ b/charts/appmesh-gateway/values.yaml @@ -0,0 +1,69 @@ +# Default values for appmesh-gateway. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 +discovery: + # discovery.optIn `true` if only services with the 'expose' annotation are discoverable + optIn: true + +proxy: + access_log_path: /dev/null + image: + repository: docker.io/envoyproxy/envoy + tag: v1.12.0 + pullPolicy: IfNotPresent + +controller: + image: + repository: weaveworks/flagger-appmesh-gateway + tag: v1.0.0 + pullPolicy: IfNotPresent + +nameOverride: "" +fullnameOverride: "" + +service: + # service.type: When set to LoadBalancer it creates an AWS NLB + type: LoadBalancer + port: 80 + +hpa: + # hpa.enabled `true` if HPA resource should be created, metrics-server is required + enabled: true + maxReplicas: 3 + # hpa.cpu average total CPU usage per pod (1-100) + cpu: 99 + # hpa.memory average memory usage per pod (100Mi-1Gi) + memory: + +resources: + limits: + memory: 2Gi + requests: + cpu: 100m + memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +serviceAccount: + # serviceAccount.create: Whether to create a service account or not + create: true + # serviceAccount.name: The name of the service account to create or use + name: "" + +rbac: + # rbac.create: `true` if rbac resources should be created + create: true + # rbac.pspEnabled: `true` if PodSecurityPolicy resources should be created + pspEnabled: false + +mesh: + # mesh.create: `true` if mesh resource should be created + create: false + # mesh.name: The name of the mesh to use + name: "global" + # mesh.discovery: The service discovery type to use, can be dns or cloudmap + discovery: dns diff --git a/charts/flagger/Chart.yaml b/charts/flagger/Chart.yaml index dbf3f4b8..707a58b8 100644 --- a/charts/flagger/Chart.yaml +++ b/charts/flagger/Chart.yaml @@ -4,18 +4,20 @@ version: 0.20.2 appVersion: 0.20.2 kubeVersion: ">=1.11.0-0" engine: gotpl -description: Flagger is a Kubernetes operator that automates the promotion of canary deployments using Istio, Linkerd, App Mesh, Gloo or NGINX routing for traffic shifting and Prometheus metrics for canary analysis. -home: https://docs.flagger.app -icon: https://raw.githubusercontent.com/weaveworks/flagger/master/docs/logo/flagger-icon.png +description: Flagger is a progressive delivery operator for Kubernetes +home: https://flagger.app +icon: https://raw.githubusercontent.com/weaveworks/flagger/master/docs/logo/weaveworks.png sources: -- https://github.com/weaveworks/flagger + - https://github.com/weaveworks/flagger maintainers: -- name: stefanprodan - url: https://github.com/stefanprodan - email: stefanprodan@users.noreply.github.com + - name: stefanprodan + url: https://github.com/stefanprodan + email: stefanprodan@users.noreply.github.com keywords: -- canary -- istio -- appmesh -- linkerd -- gitops + - flagger + - istio + - appmesh + - linkerd + - gloo + - gitops + - canary diff --git a/charts/flagger/README.md b/charts/flagger/README.md index 51331d66..50aea993 100644 --- a/charts/flagger/README.md +++ b/charts/flagger/README.md @@ -1,7 +1,8 @@ # Flagger -[Flagger](https://github.com/weaveworks/flagger) is a Kubernetes operator that automates the promotion of -canary deployments using Istio, Linkerd, App Mesh, NGINX or Gloo routing for traffic shifting and Prometheus metrics for canary analysis. +[Flagger](https://github.com/weaveworks/flagger) is a Kubernetes operator that automates the promotion of canary +deployments using Istio, Linkerd, App Mesh, NGINX or Gloo routing for traffic shifting and Prometheus metrics for canary analysis. + Flagger implements a control loop that gradually shifts traffic to the canary while measuring key performance indicators like HTTP requests success rate, requests average duration and pods health. Based on the KPIs analysis a canary is promoted or aborted and the analysis result is published to Slack or MS Teams. @@ -45,6 +46,16 @@ $ helm upgrade -i flagger flagger/flagger \ --set metricsServer=http://linkerd-prometheus:9090 ``` +To install the chart with the release name `flagger` for AWS App Mesh: + +```console +$ helm upgrade -i flagger flagger/flagger \ + --namespace=appmesh-system \ + --set crd.create=false \ + --set meshProvider=appmesh \ + --set metricsServer=http://appmesh-prometheus:9090 +``` + The [configuration](#configuration) section lists the parameters that can be configured during installation. ## Uninstalling the Chart @@ -91,7 +102,7 @@ Specify each parameter using the `--set key=value[,key=value]` argument to `helm ```console $ helm upgrade -i flagger flagger/flagger \ - --namespace istio-system \ + --namespace flagger-system \ --set crd.create=false \ --set slack.url=https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK \ --set slack.channel=general diff --git a/charts/flagger/values.yaml b/charts/flagger/values.yaml index 6bb9ad5d..dbd8a6b7 100644 --- a/charts/flagger/values.yaml +++ b/charts/flagger/values.yaml @@ -9,6 +9,7 @@ image: podAnnotations: prometheus.io/scrape: "true" prometheus.io/port: "8080" + appmesh.k8s.aws/sidecarInjectorWebhook: disabled metricsServer: "http://prometheus:9090" diff --git a/charts/grafana/Chart.yaml b/charts/grafana/Chart.yaml index 554e09df..ab0dc460 100644 --- a/charts/grafana/Chart.yaml +++ b/charts/grafana/Chart.yaml @@ -3,11 +3,18 @@ name: grafana version: 1.3.0 appVersion: 6.2.5 description: Grafana dashboards for monitoring Flagger canary deployments -icon: https://raw.githubusercontent.com/weaveworks/flagger/master/docs/logo/flagger-icon.png +icon: https://raw.githubusercontent.com/weaveworks/flagger/master/docs/logo/weaveworks.png home: https://flagger.app sources: -- https://github.com/weaveworks/flagger + - https://github.com/weaveworks/flagger maintainers: -- name: stefanprodan - url: https://github.com/stefanprodan - email: stefanprodan@users.noreply.github.com + - name: stefanprodan + url: https://github.com/stefanprodan + email: stefanprodan@users.noreply.github.com +keywords: + - flagger + - grafana + - canary + - istio + - appmesh + diff --git a/charts/grafana/README.md b/charts/grafana/README.md index 15c54f98..2af02569 100644 --- a/charts/grafana/README.md +++ b/charts/grafana/README.md @@ -1,13 +1,12 @@ # Flagger Grafana -Grafana dashboards for monitoring progressive deployments powered by Istio, Prometheus and Flagger. +Grafana dashboards for monitoring progressive deployments powered by Flagger and Prometheus. ![flagger-grafana](https://raw.githubusercontent.com/weaveworks/flagger/master/docs/screens/grafana-canary-analysis.png) ## Prerequisites * Kubernetes >= 1.11 -* Istio >= 1.0 * Prometheus >= 2.6 ## Installing the Chart @@ -18,14 +17,20 @@ Add Flagger Helm repository: helm repo add flagger https://flagger.app ``` -To install the chart with the release name `flagger-grafana`: +To install the chart for Istio run: ```console helm upgrade -i flagger-grafana flagger/grafana \ --namespace=istio-system \ ---set url=http://prometheus:9090 \ ---set user=admin \ ---set password=admin +--set url=http://prometheus:9090 +``` + +To install the chart for AWS App Mesh run: + +```console +helm upgrade -i flagger-grafana flagger/grafana \ +--namespace=appmesh-system \ +--set url=http://appmesh-prometheus:9090 ``` The command deploys Grafana on the Kubernetes cluster in the default namespace. @@ -56,10 +61,7 @@ Parameter | Description | Default `affinity` | node/pod affinities | `node` `nodeSelector` | node labels for pod assignment | `{}` `service.type` | type of service | `ClusterIP` -`url` | Prometheus URL, used when Weave Cloud token is empty | `http://prometheus:9090` -`token` | Weave Cloud token | `none` -`user` | Grafana admin username | `admin` -`password` | Grafana admin password | `admin` +`url` | Prometheus URL | `http://prometheus:9090` Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, diff --git a/charts/loadtester/Chart.yaml b/charts/loadtester/Chart.yaml index 4e74157d..66692ec0 100644 --- a/charts/loadtester/Chart.yaml +++ b/charts/loadtester/Chart.yaml @@ -6,7 +6,7 @@ kubeVersion: ">=1.11.0-0" engine: gotpl description: Flagger's load testing services based on rakyll/hey and bojand/ghz that generates traffic during canary analysis when configured as a webhook. home: https://docs.flagger.app -icon: https://raw.githubusercontent.com/weaveworks/flagger/master/docs/logo/flagger-icon.png +icon: https://raw.githubusercontent.com/weaveworks/flagger/master/docs/logo/weaveworks.png sources: - https://github.com/weaveworks/flagger maintainers: @@ -14,8 +14,10 @@ maintainers: url: https://github.com/stefanprodan email: stefanprodan@users.noreply.github.com keywords: - - canary + - flagger - istio - appmesh + - linkerd + - gloo - gitops - load testing diff --git a/charts/podinfo/Chart.yaml b/charts/podinfo/Chart.yaml index 9483925c..1aa57f10 100644 --- a/charts/podinfo/Chart.yaml +++ b/charts/podinfo/Chart.yaml @@ -3,10 +3,12 @@ version: 3.1.0 appVersion: 3.1.0 name: podinfo engine: gotpl -description: Flagger canary deployment demo chart -home: https://flagger.app -maintainers: -- email: stefanprodan@users.noreply.github.com - name: stefanprodan +description: Flagger canary deployment demo application +home: https://docs.flagger.app +icon: https://raw.githubusercontent.com/weaveworks/flagger/master/docs/logo/weaveworks.png sources: -- https://github.com/weaveworks/flagger + - https://github.com/stefanprodan/podinfo +maintainers: + - name: stefanprodan + url: https://github.com/stefanprodan + email: stefanprodan@users.noreply.github.com diff --git a/docs/gitbook/install/flagger-install-on-eks-appmesh.md b/docs/gitbook/install/flagger-install-on-eks-appmesh.md index f53efc99..73d19046 100644 --- a/docs/gitbook/install/flagger-install-on-eks-appmesh.md +++ b/docs/gitbook/install/flagger-install-on-eks-appmesh.md @@ -12,7 +12,7 @@ The App Mesh integration with EKS is made out of the following components: * `virtualservice.appmesh.k8s.aws` defines the routing rules for a workload inside the mesh * CRD controller - keeps the custom resources in sync with the App Mesh control plane * Admission controller - injects the Envoy sidecar and assigns Kubernetes pods to App Mesh virtual nodes -* Metrics server - Prometheus instance that collects and stores Envoy's metrics +* Telemetry service - Prometheus instance that collects and stores Envoy's metrics ### Create a Kubernetes cluster @@ -100,7 +100,7 @@ kubectl create ns appmesh-system Apply the App Mesh CRDs: ```sh -kubectl apply -f https://raw.githubusercontent.com/aws/eks-charts/master/stable/appmesh-controller/crds/crds.yaml +kubectl apply -k github.com/aws/eks-charts/stable/appmesh-controller//crds ``` Add the EKS repository to Helm: @@ -113,10 +113,10 @@ Install the App Mesh CRD controller: ```sh helm upgrade -i appmesh-controller eks/appmesh-controller \ ---wait --namespace appmesh-system --version 0.2.0 +--wait --namespace appmesh-system ``` -Install the App Mesh admission controller: +Install the App Mesh admission controller and create a mesh called `global`: ```sh helm upgrade -i appmesh-inject eks/appmesh-inject \ diff --git a/docs/gitbook/usage/appmesh-progressive-delivery.md b/docs/gitbook/usage/appmesh-progressive-delivery.md index d872add1..075d8469 100644 --- a/docs/gitbook/usage/appmesh-progressive-delivery.md +++ b/docs/gitbook/usage/appmesh-progressive-delivery.md @@ -14,22 +14,33 @@ The only App Mesh object you need to create by yourself is the mesh resource. Create a mesh called `global`: ```bash -export REPO=https://raw.githubusercontent.com/weaveworks/flagger/master - -kubectl apply -f ${REPO}/artifacts/appmesh/global-mesh.yaml +cat << EOF | kubectl apply -f - +apiVersion: appmesh.k8s.aws/v1beta1 +kind: Mesh +metadata: + name: global +spec: + serviceDiscoveryType: dns +EOF ``` Create a test namespace with App Mesh sidecar injection enabled: ```bash -kubectl apply -f ${REPO}/artifacts/namespaces/test.yaml +cat << EOF | kubectl apply -f - +apiVersion: v1 +kind: Namespace +metadata: + name: test + labels: + appmesh.k8s.aws/sidecarInjectorWebhook: enabled +EOF ``` Create a deployment and a horizontal pod autoscaler: ```bash -kubectl apply -f ${REPO}/artifacts/appmesh/deployment.yaml -kubectl apply -f ${REPO}/artifacts/appmesh/hpa.yaml +kubectl apply -k github.com/weaveworks/flagger//kustomize/podinfo ``` Deploy the load testing service to generate traffic during the canary analysis: @@ -72,20 +83,25 @@ spec: portName: http # App Mesh reference meshName: global + # App Mesh ingress (optional) + hosts: + - "*" + # App Mesh ingress timeout (optional) + timeout: 5s # App Mesh egress (optional) backends: - backend.test # App Mesh retry policy (optional) retries: attempts: 3 - perTryTimeout: 1s + perTryTimeout: 5s retryOn: "gateway-error,client-error,stream-error" # define the canary analysis timing and KPIs canaryAnalysis: # schedule interval (default 60s) - interval: 10s + interval: 1m # max number of failed metric checks before rollback - threshold: 10 + threshold: 5 # max traffic percentage routed to canary # percentage (0-100) maxWeight: 50 @@ -166,37 +182,42 @@ The App Mesh specific settings are: App Mesh blocks all egress traffic by default. If your application needs to call another service, you have to create an App Mesh virtual service for it and add the virtual service name to the backend list. -### Setup App Mesh ingress (optional) +### Setup App Mesh Gateway (optional) -In order to expose the podinfo app outside the mesh you'll be using an Envoy ingress and an AWS classic load balancer. -The ingress binds to an internet domain and forwards the calls into the mesh through the App Mesh sidecar. -If podinfo becomes unavailable due to a HPA downscaling or a node restart, -the ingress will retry the calls for a short period of time. +In order to expose the podinfo app outside the mesh you'll be using an Envoy-powered ingress gateway and an AWS network load balancer. +The gateway binds to an internet domain and forwards the calls into the mesh through the App Mesh sidecar. +If podinfo becomes unavailable due to a cluster downscaling or a node restart, +the gateway will retry the calls for a short period of time. -Deploy the ingress and the AWS ELB service: +Deploy the gateway behind an AWS NLB: ```bash -kubectl apply -f ${REPO}/artifacts/appmesh/ingress.yaml +helm upgrade -i test flagger/appmesh-gateway \ +--namespace flagger-system \ +--set mesh.name=global ``` -Find the ingress public address: +Find the gateway public address: ```bash -kubectl -n test describe svc/ingress | grep Ingress - -LoadBalancer Ingress: yyy-xx.us-west-2.elb.amazonaws.com +export URL="http://$(kubectl -n demo get svc/appmesh-gateway -ojson | jq -r ".status.loadBalancer.ingress[].hostname")" +echo $URL ``` -Wait for the ELB to become active: +Wait for the NLB to become active: ```bash - watch curl -sS ${INGRESS_URL} + watch curl -sS $URL ``` Open your browser and navigate to the ingress address to access podinfo UI. ### Automated canary promotion +A canary deployment is triggered by changes in any of the following objects: +* Deployment PodSpec (container image, command, ports, env, resources, etc) +* ConfigMaps and Secrets mounted as volumes or mapped to environment variables + Trigger a canary deployment by updating the container image: ```bash @@ -237,11 +258,6 @@ When the canary analysis starts, Flagger will call the pre-rollout webhooks befo **Note** that if you apply new changes to the deployment during the canary analysis, Flagger will restart the analysis. -A canary deployment is triggered by changes in any of the following objects: -* Deployment PodSpec (container image, command, ports, env, resources, etc) -* ConfigMaps mounted as volumes or mapped to environment variables -* Secrets mounted as volumes or mapped to environment variables - During the analysis the canary’s progress can be monitored with Grafana. The App Mesh dashboard URL is http://localhost:3000/d/flagger-appmesh/appmesh-canary?refresh=10s&orgId=1&var-namespace=test&var-primary=podinfo-primary&var-canary=podinfo @@ -264,7 +280,7 @@ If you’ve enabled the Slack notifications, you should receive the following me ### Automated rollback -During the canary analysis you can generate HTTP 500 errors to test if Flagger pauses the rollout. +During the canary analysis you can generate HTTP 500 errors or high latency to test if Flagger pauses the rollout. Trigger a canary deployment: @@ -295,25 +311,20 @@ When the number of failed checks reaches the canary analysis threshold, the traf the canary is scaled to zero and the rollout is marked as failed. ```text -kubectl -n test describe canary/podinfo +kubectl -n appmesh-system logs deploy/flagger -f | jq .msg -Status: - Canary Weight: 0 - Failed Checks: 5 - Phase: Failed -Events: - Starting canary analysis for podinfo.test - Pre-rollout check acceptance-test passed - Advance podinfo.test canary weight 5 - Advance podinfo.test canary weight 10 - Advance podinfo.test canary weight 15 - Halt podinfo.test advancement success rate 69.17% < 99% - Halt podinfo.test advancement success rate 61.39% < 99% - Halt podinfo.test advancement success rate 55.06% < 99% - Halt podinfo.test advancement request duration 1.20s > 0.5s - Halt podinfo.test advancement request duration 1.45s > 0.5s - Rolling back podinfo.test failed checks threshold reached 5 - Canary failed! Scaling down podinfo.test +New revision detected! Starting canary analysis for podinfo.test +Pre-rollout check acceptance-test passed +Advance podinfo.test canary weight 5 +Advance podinfo.test canary weight 10 +Advance podinfo.test canary weight 15 +Halt podinfo.test advancement success rate 69.17% < 99% +Halt podinfo.test advancement success rate 61.39% < 99% +Halt podinfo.test advancement success rate 55.06% < 99% +Halt podinfo.test advancement request duration 1.20s > 0.5s +Halt podinfo.test advancement request duration 1.45s > 0.5s +Rolling back podinfo.test failed checks threshold reached 5 +Canary failed! Scaling down podinfo.test ``` If you’ve enabled the Slack notifications, you’ll receive a message if the progress deadline is exceeded, @@ -334,7 +345,7 @@ Edit the canary analysis, remove the max/step weight and add the match condition ```yaml canaryAnalysis: interval: 1m - threshold: 10 + threshold: 5 iterations: 10 match: - headers: diff --git a/docs/logo/weaveworks.png b/docs/logo/weaveworks.png new file mode 100644 index 00000000..9399ceb8 Binary files /dev/null and b/docs/logo/weaveworks.png differ diff --git a/kustomize/README.md b/kustomize/README.md index ea4ba8c4..dc26f87d 100644 --- a/kustomize/README.md +++ b/kustomize/README.md @@ -25,7 +25,7 @@ Install Flagger for AWS App Mesh: kubectl apply -k github.com/weaveworks/flagger//kustomize/appmesh ``` -This deploys Flagger and Prometheus (configured to scrape the App Mesh Envoy sidecars) in the `appmesh-system` namespace. +This deploys Flagger in the `appmesh-system` namespace and sets the metrics server URL to App Mesh Prometheus instance. Install Flagger for Linkerd: diff --git a/kustomize/appmesh/kustomization.yaml b/kustomize/appmesh/kustomization.yaml index 13e8a53d..8bd8f9de 100644 --- a/kustomize/appmesh/kustomization.yaml +++ b/kustomize/appmesh/kustomization.yaml @@ -1,6 +1,5 @@ namespace: appmesh-system bases: - ../base/flagger - - ../base/prometheus patchesStrategicMerge: - patch.yaml diff --git a/kustomize/appmesh/patch.yaml b/kustomize/appmesh/patch.yaml index a800bff0..408379d1 100644 --- a/kustomize/appmesh/patch.yaml +++ b/kustomize/appmesh/patch.yaml @@ -10,7 +10,20 @@ spec: args: - -log-level=info - -mesh-provider=appmesh - - -metrics-server=http://flagger-prometheus:9090 + - -metrics-server=http://appmesh-prometheus:9090 - -slack-user=flagger - -slack-channel= - -slack-url= +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: flagger +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: flagger +subjects: + - kind: ServiceAccount + name: flagger + namespace: appmesh-system diff --git a/kustomize/istio/patch.yaml b/kustomize/istio/patch.yaml index f9b69b6c..8180d2d8 100644 --- a/kustomize/istio/patch.yaml +++ b/kustomize/istio/patch.yaml @@ -14,3 +14,17 @@ spec: - -slack-user=flagger - -slack-channel= - -slack-url= +--- +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: flagger +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: flagger +subjects: + - kind: ServiceAccount + name: flagger + namespace: istio-system diff --git a/kustomize/linkerd/patch.yaml b/kustomize/linkerd/patch.yaml index 04772b41..e2053138 100644 --- a/kustomize/linkerd/patch.yaml +++ b/kustomize/linkerd/patch.yaml @@ -14,3 +14,16 @@ spec: - -slack-user=flagger - -slack-channel= - -slack-url= +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: flagger +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: flagger +subjects: + - kind: ServiceAccount + name: flagger + namespace: linkerd