From 12d9f06f8a139c9bf285e2b1a63a5f56099deb86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Petazzoni?= Date: Thu, 23 Jun 2022 08:29:37 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9E=95=20Add=20YTT=20content?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- k8s/ytt/1-variables/app.yaml | 164 +++++ k8s/ytt/2-functions/app.yaml | 167 +++++ k8s/ytt/3-labels/app.yaml | 164 +++++ k8s/ytt/4-data/app.yaml | 162 +++++ k8s/ytt/4-data/schema.yaml | 4 + k8s/ytt/5-factor/app.yaml | 54 ++ k8s/ytt/5-factor/schema.yaml | 4 + k8s/ytt/6-template/app.yaml | 56 ++ k8s/ytt/6-template/schema.yaml | 4 + k8s/ytt/7-morevalues/app.yaml | 65 ++ k8s/ytt/7-morevalues/schema.yaml | 19 + .../_ytt_lib/component/deployment.yaml | 26 + .../8-library/_ytt_lib/component/schema.yaml | 7 + .../8-library/_ytt_lib/component/service.yaml | 19 + k8s/ytt/8-library/app.yaml | 20 + k8s/ytt/8-library/schema.yaml | 19 + .../_ytt_lib/component/deployment.yaml | 26 + .../9-overlay/_ytt_lib/component/schema.yaml | 7 + .../9-overlay/_ytt_lib/component/service.yaml | 19 + k8s/ytt/9-overlay/app.yaml | 20 + k8s/ytt/9-overlay/rng-healthcheck.yaml | 20 + k8s/ytt/9-overlay/schema.yaml | 19 + k8s/ytt/9-overlay/worker-scaling.yaml | 25 + slides/k8s/ytt.md | 635 ++++++++++++++++++ slides/kube-adv.yml | 1 + slides/kube-fullday.yml | 1 + slides/kube-halfday.yml | 1 + slides/kube-selfpaced.yml | 1 + slides/kube-twodays.yml | 1 + 29 files changed, 1730 insertions(+) create mode 100644 k8s/ytt/1-variables/app.yaml create mode 100644 k8s/ytt/2-functions/app.yaml create mode 100644 k8s/ytt/3-labels/app.yaml create mode 100644 k8s/ytt/4-data/app.yaml create mode 100644 k8s/ytt/4-data/schema.yaml create mode 100644 k8s/ytt/5-factor/app.yaml create mode 100644 k8s/ytt/5-factor/schema.yaml create mode 100644 k8s/ytt/6-template/app.yaml create mode 100644 k8s/ytt/6-template/schema.yaml create mode 100644 k8s/ytt/7-morevalues/app.yaml create mode 100644 k8s/ytt/7-morevalues/schema.yaml create mode 100644 k8s/ytt/8-library/_ytt_lib/component/deployment.yaml create mode 100644 k8s/ytt/8-library/_ytt_lib/component/schema.yaml create mode 100644 k8s/ytt/8-library/_ytt_lib/component/service.yaml create mode 100644 k8s/ytt/8-library/app.yaml create mode 100644 k8s/ytt/8-library/schema.yaml create mode 100644 k8s/ytt/9-overlay/_ytt_lib/component/deployment.yaml create mode 100644 k8s/ytt/9-overlay/_ytt_lib/component/schema.yaml create mode 100644 k8s/ytt/9-overlay/_ytt_lib/component/service.yaml create mode 100644 k8s/ytt/9-overlay/app.yaml create mode 100644 k8s/ytt/9-overlay/rng-healthcheck.yaml create mode 100644 k8s/ytt/9-overlay/schema.yaml create mode 100644 k8s/ytt/9-overlay/worker-scaling.yaml create mode 100644 slides/k8s/ytt.md diff --git a/k8s/ytt/1-variables/app.yaml b/k8s/ytt/1-variables/app.yaml new file mode 100644 index 00000000..659ab04d --- /dev/null +++ b/k8s/ytt/1-variables/app.yaml @@ -0,0 +1,164 @@ +#! Define and use variables. +--- +#@ repository = "dockercoins" +#@ tag = "v0.1" +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: hasher + name: hasher +spec: + replicas: 1 + selector: + matchLabels: + app: hasher + template: + metadata: + labels: + app: hasher + spec: + containers: + - image: #@ "{}/hasher:{}".format(repository, tag) + name: hasher +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: hasher + name: hasher +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: hasher + type: ClusterIP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: redis + name: redis +spec: + replicas: 1 + selector: + matchLabels: + app: redis + template: + metadata: + labels: + app: redis + spec: + containers: + - image: redis + name: redis +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: redis + name: redis +spec: + ports: + - port: 6379 + protocol: TCP + targetPort: 6379 + selector: + app: redis + type: ClusterIP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: rng + name: rng +spec: + replicas: 1 + selector: + matchLabels: + app: rng + template: + metadata: + labels: + app: rng + spec: + containers: + - image: #@ "{}/rng:{}".format(repository, tag) + name: rng +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: rng + name: rng +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: rng + type: ClusterIP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: webui + name: webui +spec: + replicas: 1 + selector: + matchLabels: + app: webui + template: + metadata: + labels: + app: webui + spec: + containers: + - image: #@ "{}/webui:{}".format(repository, tag) + name: webui +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: webui + name: webui +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: webui + type: NodePort +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: worker + name: worker +spec: + replicas: 1 + selector: + matchLabels: + app: worker + template: + metadata: + labels: + app: worker + spec: + containers: + - image: #@ "{}/worker:{}".format(repository, tag) + name: worker diff --git a/k8s/ytt/2-functions/app.yaml b/k8s/ytt/2-functions/app.yaml new file mode 100644 index 00000000..1fce3de2 --- /dev/null +++ b/k8s/ytt/2-functions/app.yaml @@ -0,0 +1,167 @@ +#! Define and use a function to set the deployment image. +--- +#@ repository = "dockercoins" +#@ tag = "v0.1" +#@ def image(component): +#@ return "{}/{}:{}".format(repository, component, tag) +#@ end +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: hasher + name: hasher +spec: + replicas: 1 + selector: + matchLabels: + app: hasher + template: + metadata: + labels: + app: hasher + spec: + containers: + - image: #@ image("hasher") + name: hasher +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: hasher + name: hasher +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: hasher + type: ClusterIP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: redis + name: redis +spec: + replicas: 1 + selector: + matchLabels: + app: redis + template: + metadata: + labels: + app: redis + spec: + containers: + - image: redis + name: redis +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: redis + name: redis +spec: + ports: + - port: 6379 + protocol: TCP + targetPort: 6379 + selector: + app: redis + type: ClusterIP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: rng + name: rng +spec: + replicas: 1 + selector: + matchLabels: + app: rng + template: + metadata: + labels: + app: rng + spec: + containers: + - image: #@ image("rng") + name: rng +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: rng + name: rng +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: rng + type: ClusterIP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: webui + name: webui +spec: + replicas: 1 + selector: + matchLabels: + app: webui + template: + metadata: + labels: + app: webui + spec: + containers: + - image: #@ image("webui") + name: webui +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: webui + name: webui +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: webui + type: NodePort +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: worker + name: worker +spec: + replicas: 1 + selector: + matchLabels: + app: worker + template: + metadata: + labels: + app: worker + spec: + containers: + - image: #@ image("worker") + name: worker diff --git a/k8s/ytt/3-labels/app.yaml b/k8s/ytt/3-labels/app.yaml new file mode 100644 index 00000000..143b8d5e --- /dev/null +++ b/k8s/ytt/3-labels/app.yaml @@ -0,0 +1,164 @@ +#! Define and use functions, demonstrating how to generate labels. +--- +#@ repository = "dockercoins" +#@ tag = "v0.1" +#@ def image(component): +#@ return "{}/{}:{}".format(repository, component, tag) +#@ end +#@ def labels(component): +#@ return { +#@ "app": component, +#@ "container.training/generated-by": "ytt", +#@ } +#@ end +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: #@ labels("hasher") + name: hasher +spec: + replicas: 1 + selector: + matchLabels: + app: hasher + template: + metadata: + labels: + app: hasher + spec: + containers: + - image: #@ image("hasher") + name: hasher +--- +apiVersion: v1 +kind: Service +metadata: + labels: #@ labels("hasher") + name: hasher +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: hasher + type: ClusterIP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: #@ labels("redis") + name: redis +spec: + replicas: 1 + selector: + matchLabels: + app: redis + template: + metadata: + labels: + app: redis + spec: + containers: + - image: redis + name: redis +--- +apiVersion: v1 +kind: Service +metadata: + labels: #@ labels("redis") + name: redis +spec: + ports: + - port: 6379 + protocol: TCP + targetPort: 6379 + selector: + app: redis + type: ClusterIP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: #@ labels("rng") + name: rng +spec: + replicas: 1 + selector: + matchLabels: + app: rng + template: + metadata: + labels: + app: rng + spec: + containers: + - image: #@ image("rng") + name: rng +--- +apiVersion: v1 +kind: Service +metadata: + labels: #@ labels("rng") + name: rng +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: rng + type: ClusterIP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: #@ labels("webui") + name: webui +spec: + replicas: 1 + selector: + matchLabels: + app: webui + template: + metadata: + labels: + app: webui + spec: + containers: + - image: #@ image("webui") + name: webui +--- +apiVersion: v1 +kind: Service +metadata: + labels: #@ labels("webui") + name: webui +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: webui + type: NodePort +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: #@ labels("worker") + name: worker +spec: + replicas: 1 + selector: + matchLabels: + app: worker + template: + metadata: + labels: + app: worker + spec: + containers: + - image: #@ image("worker") + name: worker diff --git a/k8s/ytt/4-data/app.yaml b/k8s/ytt/4-data/app.yaml new file mode 100644 index 00000000..9d9d4c97 --- /dev/null +++ b/k8s/ytt/4-data/app.yaml @@ -0,0 +1,162 @@ +--- +#@ load("@ytt:data", "data") +#@ def image(component): +#@ return "{}/{}:{}".format(data.values.repository, component, data.values.tag) +#@ end +#@ def labels(component): +#@ return { +#@ "app": component, +#@ "container.training/generated-by": "ytt", +#@ } +#@ end +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: #@ labels("hasher") + name: hasher +spec: + replicas: 1 + selector: + matchLabels: + app: hasher + template: + metadata: + labels: + app: hasher + spec: + containers: + - image: #@ image("hasher") + name: hasher +--- +apiVersion: v1 +kind: Service +metadata: + labels: #@ labels("hasher") + name: hasher +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: hasher + type: ClusterIP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: #@ labels("redis") + name: redis +spec: + replicas: 1 + selector: + matchLabels: + app: redis + template: + metadata: + labels: + app: redis + spec: + containers: + - image: redis + name: redis +--- +apiVersion: v1 +kind: Service +metadata: + labels: #@ labels("redis") + name: redis +spec: + ports: + - port: 6379 + protocol: TCP + targetPort: 6379 + selector: + app: redis + type: ClusterIP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: #@ labels("rng") + name: rng +spec: + replicas: 1 + selector: + matchLabels: + app: rng + template: + metadata: + labels: + app: rng + spec: + containers: + - image: #@ image("rng") + name: rng +--- +apiVersion: v1 +kind: Service +metadata: + labels: #@ labels("rng") + name: rng +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: rng + type: ClusterIP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: #@ labels("webui") + name: webui +spec: + replicas: 1 + selector: + matchLabels: + app: webui + template: + metadata: + labels: + app: webui + spec: + containers: + - image: #@ image("webui") + name: webui +--- +apiVersion: v1 +kind: Service +metadata: + labels: #@ labels("webui") + name: webui +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: webui + type: NodePort +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: #@ labels("worker") + name: worker +spec: + replicas: 1 + selector: + matchLabels: + app: worker + template: + metadata: + labels: + app: worker + spec: + containers: + - image: #@ image("worker") + name: worker diff --git a/k8s/ytt/4-data/schema.yaml b/k8s/ytt/4-data/schema.yaml new file mode 100644 index 00000000..04744d05 --- /dev/null +++ b/k8s/ytt/4-data/schema.yaml @@ -0,0 +1,4 @@ +#@data/values-schema +--- +repository: dockercoins +tag: v0.1 diff --git a/k8s/ytt/5-factor/app.yaml b/k8s/ytt/5-factor/app.yaml new file mode 100644 index 00000000..4b6e619d --- /dev/null +++ b/k8s/ytt/5-factor/app.yaml @@ -0,0 +1,54 @@ +--- +#@ load("@ytt:data", "data") +--- +#@ def Deployment(component, repository=data.values.repository, tag=data.values.tag): +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: #@ component + container.training/generated-by: ytt + name: #@ component +spec: + replicas: 1 + selector: + matchLabels: + app: #@ component + template: + metadata: + labels: + app: #@ component + spec: + containers: + - image: #@ repository + "/" + component + ":" + tag + name: #@ component +#@ end +--- +#@ def Service(component, port=80, type="ClusterIP"): +apiVersion: v1 +kind: Service +metadata: + labels: + app: #@ component + container.training/generated-by: ytt + name: #@ component +spec: + ports: + - port: #@ port + protocol: TCP + targetPort: #@ port + selector: + app: #@ component + type: #@ type +#@ end +--- +--- #@ Deployment("hasher") +--- #@ Service("hasher") +--- #@ Deployment("redis", repository="library", tag="latest") +--- #@ Service("redis", port=6379) +--- #@ Deployment("rng") +--- #@ Service("rng") +--- #@ Deployment("webui") +--- #@ Service("webui", type="NodePort") +--- #@ Deployment("worker") +--- diff --git a/k8s/ytt/5-factor/schema.yaml b/k8s/ytt/5-factor/schema.yaml new file mode 100644 index 00000000..04744d05 --- /dev/null +++ b/k8s/ytt/5-factor/schema.yaml @@ -0,0 +1,4 @@ +#@data/values-schema +--- +repository: dockercoins +tag: v0.1 diff --git a/k8s/ytt/6-template/app.yaml b/k8s/ytt/6-template/app.yaml new file mode 100644 index 00000000..cd78260c --- /dev/null +++ b/k8s/ytt/6-template/app.yaml @@ -0,0 +1,56 @@ +--- +#@ load("@ytt:data", "data") +#@ load("@ytt:template", "template") +--- +#@ def component(name, repository=data.values.repository, tag=data.values.tag, port=None, type="ClusterIP"): +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: #@ name + container.training/generated-by: ytt + name: #@ name +spec: + replicas: 1 + selector: + matchLabels: + app: #@ name + template: + metadata: + labels: + app: #@ name + spec: + containers: + - image: #@ repository + "/" + name + ":" + tag + name: #@ name + #@ if/end port==80: + readinessProbe: + httpGet: + port: #@ port +#@ if port != None: +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: #@ name + container.training/generated-by: ytt + name: #@ name +spec: + ports: + - port: #@ port + protocol: TCP + targetPort: #@ port + selector: + app: #@ name + type: #@ type +#@ end +#@ end +--- +--- #@ template.replace(component("hasher", port=80)) +--- #@ template.replace(component("redis", repository="library", tag="latest", port=6379)) +--- #@ template.replace(component("rng", port=80)) +--- #@ template.replace(component("webui", port=80, type="NodePort")) +--- #@ template.replace(component("worker")) +--- diff --git a/k8s/ytt/6-template/schema.yaml b/k8s/ytt/6-template/schema.yaml new file mode 100644 index 00000000..04744d05 --- /dev/null +++ b/k8s/ytt/6-template/schema.yaml @@ -0,0 +1,4 @@ +#@data/values-schema +--- +repository: dockercoins +tag: v0.1 diff --git a/k8s/ytt/7-morevalues/app.yaml b/k8s/ytt/7-morevalues/app.yaml new file mode 100644 index 00000000..3a547193 --- /dev/null +++ b/k8s/ytt/7-morevalues/app.yaml @@ -0,0 +1,65 @@ +--- +#@ load("@ytt:data", "data") +#@ load("@ytt:template", "template") +--- +#@ def component(name, repository, tag, port=None, type="ClusterIP"): +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: #@ name + container.training/generated-by: ytt + name: #@ name +spec: + replicas: 1 + selector: + matchLabels: + app: #@ name + template: + metadata: + labels: + app: #@ name + spec: + containers: + - image: #@ repository + "/" + name + ":" + tag + name: #@ name + #@ if/end port==80: + readinessProbe: + httpGet: + port: #@ port +#@ if port != None: +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: #@ name + container.training/generated-by: ytt + name: #@ name +spec: + ports: + - port: #@ port + protocol: TCP + targetPort: #@ port + selector: + app: #@ name + type: #@ type +#@ end +#@ end +--- +#@ defaults = {} +#@ for name in data.values: +#@ if name.startswith("_"): +#@ defaults.update(data.values[name]) +#@ end +#@ end +--- +#@ for name in data.values: +#@ if not name.startswith("_"): +#@ values = dict(name=name) +#@ values.update(defaults) +#@ values.update(data.values[name]) +--- #@ template.replace(component(**values)) +#@ end +#@ end diff --git a/k8s/ytt/7-morevalues/schema.yaml b/k8s/ytt/7-morevalues/schema.yaml new file mode 100644 index 00000000..3aeb5c58 --- /dev/null +++ b/k8s/ytt/7-morevalues/schema.yaml @@ -0,0 +1,19 @@ +#@data/values-schema +#! Entries starting with an underscore will hold default values. +#! Entires NOT starting with an underscore will generate a Deployment +#! (and a Service if a port number is set). +--- +_default_: + repository: dockercoins + tag: v0.1 +hasher: + port: 80 +redis: + repository: library + tag: latest +rng: + port: 80 +webui: + port: 80 + type: NodePort +worker: {} diff --git a/k8s/ytt/8-library/_ytt_lib/component/deployment.yaml b/k8s/ytt/8-library/_ytt_lib/component/deployment.yaml new file mode 100644 index 00000000..83466709 --- /dev/null +++ b/k8s/ytt/8-library/_ytt_lib/component/deployment.yaml @@ -0,0 +1,26 @@ +#@ load("@ytt:data", "data") +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: #@ data.values.name + container.training/generated-by: ytt + name: #@ data.values.name +spec: + replicas: 1 + selector: + matchLabels: + app: #@ data.values.name + template: + metadata: + labels: + app: #@ data.values.name + spec: + containers: + - image: #@ data.values.repository + "/" + data.values.name + ":" + data.values.tag + name: #@ data.values.name + #@ if/end data.values.port==80: + readinessProbe: + httpGet: + port: #@ data.values.port diff --git a/k8s/ytt/8-library/_ytt_lib/component/schema.yaml b/k8s/ytt/8-library/_ytt_lib/component/schema.yaml new file mode 100644 index 00000000..d2b85a8e --- /dev/null +++ b/k8s/ytt/8-library/_ytt_lib/component/schema.yaml @@ -0,0 +1,7 @@ +#@data/values-schema +--- +name: component +repository: dockercoins +tag: v0.1 +port: 0 +type: ClusterIP diff --git a/k8s/ytt/8-library/_ytt_lib/component/service.yaml b/k8s/ytt/8-library/_ytt_lib/component/service.yaml new file mode 100644 index 00000000..81bd1e99 --- /dev/null +++ b/k8s/ytt/8-library/_ytt_lib/component/service.yaml @@ -0,0 +1,19 @@ +#@ load("@ytt:data", "data") +#@ if data.values.port > 0: +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: #@ data.values.name + container.training/generated-by: ytt + name: #@ data.values.name +spec: + ports: + - port: #@ data.values.port + protocol: TCP + targetPort: #@ data.values.port + selector: + app: #@ data.values.name + type: #@ data.values.type +#@ end \ No newline at end of file diff --git a/k8s/ytt/8-library/app.yaml b/k8s/ytt/8-library/app.yaml new file mode 100644 index 00000000..1081d1b3 --- /dev/null +++ b/k8s/ytt/8-library/app.yaml @@ -0,0 +1,20 @@ +#@ load("@ytt:data", "data") +#@ load("@ytt:library", "library") +#@ load("@ytt:template", "template") +#@ +#@ component = library.get("component") +#@ +#@ defaults = {} +#@ for name in data.values: +#@ if name.startswith("_"): +#@ defaults.update(data.values[name]) +#@ end +#@ end +#@ for name in data.values: +#@ if not name.startswith("_"): +#@ values = dict(name=name) +#@ values.update(defaults) +#@ values.update(data.values[name]) +--- #@ template.replace(component.with_data_values(values).eval()) +#@ end +#@ end diff --git a/k8s/ytt/8-library/schema.yaml b/k8s/ytt/8-library/schema.yaml new file mode 100644 index 00000000..3aeb5c58 --- /dev/null +++ b/k8s/ytt/8-library/schema.yaml @@ -0,0 +1,19 @@ +#@data/values-schema +#! Entries starting with an underscore will hold default values. +#! Entires NOT starting with an underscore will generate a Deployment +#! (and a Service if a port number is set). +--- +_default_: + repository: dockercoins + tag: v0.1 +hasher: + port: 80 +redis: + repository: library + tag: latest +rng: + port: 80 +webui: + port: 80 + type: NodePort +worker: {} diff --git a/k8s/ytt/9-overlay/_ytt_lib/component/deployment.yaml b/k8s/ytt/9-overlay/_ytt_lib/component/deployment.yaml new file mode 100644 index 00000000..83466709 --- /dev/null +++ b/k8s/ytt/9-overlay/_ytt_lib/component/deployment.yaml @@ -0,0 +1,26 @@ +#@ load("@ytt:data", "data") +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: #@ data.values.name + container.training/generated-by: ytt + name: #@ data.values.name +spec: + replicas: 1 + selector: + matchLabels: + app: #@ data.values.name + template: + metadata: + labels: + app: #@ data.values.name + spec: + containers: + - image: #@ data.values.repository + "/" + data.values.name + ":" + data.values.tag + name: #@ data.values.name + #@ if/end data.values.port==80: + readinessProbe: + httpGet: + port: #@ data.values.port diff --git a/k8s/ytt/9-overlay/_ytt_lib/component/schema.yaml b/k8s/ytt/9-overlay/_ytt_lib/component/schema.yaml new file mode 100644 index 00000000..d2b85a8e --- /dev/null +++ b/k8s/ytt/9-overlay/_ytt_lib/component/schema.yaml @@ -0,0 +1,7 @@ +#@data/values-schema +--- +name: component +repository: dockercoins +tag: v0.1 +port: 0 +type: ClusterIP diff --git a/k8s/ytt/9-overlay/_ytt_lib/component/service.yaml b/k8s/ytt/9-overlay/_ytt_lib/component/service.yaml new file mode 100644 index 00000000..81bd1e99 --- /dev/null +++ b/k8s/ytt/9-overlay/_ytt_lib/component/service.yaml @@ -0,0 +1,19 @@ +#@ load("@ytt:data", "data") +#@ if data.values.port > 0: +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: #@ data.values.name + container.training/generated-by: ytt + name: #@ data.values.name +spec: + ports: + - port: #@ data.values.port + protocol: TCP + targetPort: #@ data.values.port + selector: + app: #@ data.values.name + type: #@ data.values.type +#@ end \ No newline at end of file diff --git a/k8s/ytt/9-overlay/app.yaml b/k8s/ytt/9-overlay/app.yaml new file mode 100644 index 00000000..1081d1b3 --- /dev/null +++ b/k8s/ytt/9-overlay/app.yaml @@ -0,0 +1,20 @@ +#@ load("@ytt:data", "data") +#@ load("@ytt:library", "library") +#@ load("@ytt:template", "template") +#@ +#@ component = library.get("component") +#@ +#@ defaults = {} +#@ for name in data.values: +#@ if name.startswith("_"): +#@ defaults.update(data.values[name]) +#@ end +#@ end +#@ for name in data.values: +#@ if not name.startswith("_"): +#@ values = dict(name=name) +#@ values.update(defaults) +#@ values.update(data.values[name]) +--- #@ template.replace(component.with_data_values(values).eval()) +#@ end +#@ end diff --git a/k8s/ytt/9-overlay/rng-healthcheck.yaml b/k8s/ytt/9-overlay/rng-healthcheck.yaml new file mode 100644 index 00000000..8a066eab --- /dev/null +++ b/k8s/ytt/9-overlay/rng-healthcheck.yaml @@ -0,0 +1,20 @@ +#@ load("@ytt:overlay", "overlay") + +#@ def match(): +kind: Deployment +metadata: + name: rng +#@ end + +#@overlay/match by=overlay.subset(match()) +--- +spec: + template: + spec: + containers: + #@overlay/match by="name" + - name: rng + readinessProbe: + httpGet: + #@overlay/match missing_ok=True + path: /1 diff --git a/k8s/ytt/9-overlay/schema.yaml b/k8s/ytt/9-overlay/schema.yaml new file mode 100644 index 00000000..3aeb5c58 --- /dev/null +++ b/k8s/ytt/9-overlay/schema.yaml @@ -0,0 +1,19 @@ +#@data/values-schema +#! Entries starting with an underscore will hold default values. +#! Entires NOT starting with an underscore will generate a Deployment +#! (and a Service if a port number is set). +--- +_default_: + repository: dockercoins + tag: v0.1 +hasher: + port: 80 +redis: + repository: library + tag: latest +rng: + port: 80 +webui: + port: 80 + type: NodePort +worker: {} diff --git a/k8s/ytt/9-overlay/worker-scaling.yaml b/k8s/ytt/9-overlay/worker-scaling.yaml new file mode 100644 index 00000000..38565228 --- /dev/null +++ b/k8s/ytt/9-overlay/worker-scaling.yaml @@ -0,0 +1,25 @@ +#@ load("@ytt:overlay", "overlay") + +#@ def match(): +kind: Deployment +metadata: + name: worker +#@ end + +#! This removes the number of replicas: +#@overlay/match by=overlay.subset(match()) +--- +spec: + #@overlay/remove + replicas: + +#! This overrides it: +#@overlay/match by=overlay.subset(match()) +--- +spec: + #@overlay/match missing_ok=True + replicas: 10 + +#! Note that it's not necessary to remove the number of replicas. +#! We're just presenting both options here (for instance, you might +#! want to remove the number of replicas if you're using an HPA). diff --git a/slides/k8s/ytt.md b/slides/k8s/ytt.md new file mode 100644 index 00000000..49351576 --- /dev/null +++ b/slides/k8s/ytt.md @@ -0,0 +1,635 @@ +# YTT + +- YAML Templating Tool + +- Part of [Carvel] + + (a set of tools for Kubernetes application building, configuration, and deployment) + +- Can be used for any YAML + + (Kubernetes, Compose, CI pipelines...) + +[Carvel]: https://carvel.dev/ + +--- + +## Features + +- Manipulate data structures, not text (≠ Helm) + +- Deterministic, hermetic execution + +- Define variables, blocks, functions + +- Write code in Starlark (dialect of Python) + +- Define and override values (Helm-style) + +- Patch resources arbitrarily (Kustomize-style) + +--- + +## Getting started + +- Install `ytt` ([binary download][download]) + +- Start with one (or multiple) Kubernetes YAML files + + *(without comments; no `#` allowed at this point!)* + +- `ytt -f one.yaml -f two.yaml | kubectl apply -f-` + +- `ytt -f. | kubectl apply -f-` + +[download]: https://github.com/vmware-tanzu/carvel-ytt/releases/latest + +--- + +## No comments?!? + +- Replace `#` with `#!` + +- `#@` is used by ytt + +- It's a kind of template tag, for instance: + + ```yaml + #! This is a comment + #@ a = 42 + #@ b = "*" + a: #@ a + b: #@ b + operation: multiply + result: #@ a*b + ``` + +- `#@` at the beginning of a line = instruction + +- `#@` somewhere else = value + +--- + +## Building strings + +- Concatenation: + + ```yaml + #@ repository = "dockercoins" + #@ tag = "v0.1" + containers: + - name: worker + image: #@ repository + "/worker:" + tag + ``` + +- Formatting: + + ```yaml + #@ repository = "dockercoins" + #@ tag = "v0.1" + containers: + - name: worker + image: #@ "{}/worker:{}".format(repository, tag) + ``` + +--- + +## Defining functions + +- Reusable functions can be written in Starlark (=Python) + +- Blocks (`def`, `if`, `for`...) must be terminated with `#@ end` + +- Example: + + ```yaml + #@ def image(component, repository="dockercoins", tag="v0.1"): + #@ return "{}/{}:{}".format(repository, component, tag) + #@ end + containers: + - name: worker + image: #@ image("worker") + - name: hasher + image: #@ image("hasher") + ``` + +--- + +## Structured data + +- Functions can return complex types + +- Example: defining a common set of labels + + ```yaml + #@ name = "worker" + #@ def labels(component): + #@ return { + #@ "app": component, + #@ "container.training/generated-by": "ytt", + #@ } + #@ end + kind: Pod + apiVersion: v1 + metadata: + name: #@ name + labels: #@ labels(name) + ``` + +--- + +## YAML functions + +- Function body can also be straight YAML: + + ```yaml + #@ name = "worker" + + #@ def labels(component): + app: #@ component + container.training/generated-by: ytt + #@ end + + kind: Pod + apiVersion: v1 + metadata: + name: #@ name + labels: #@ labels(name) + ``` + +- The return type of the function is then a [YAML fragment][fragment] + +[fragment]: https://carvel.dev/ytt/docs/v0.41.0/ + +--- + +## More YAML functions + +- We can load library functions: + ```yaml + #@ load("@ytt:sha256", "sha256") + ``` + +- This is (sort of) equivalent fo `from ytt.sha256 import sha256` + +- Functions can contain a mix of code and YAML fragment: + + ```yaml + #@ load("@ytt:sha256", "sha256") + + #@ def annotations(): + #@ author = "Jérôme Petazzoni" + author: #@ author + author_hash: #@ sha256.sum(author)[:8] + #@ end + + annotations: #@ annotations() + ``` + +--- + +## Data values + +- We can define a *schema* in a separate file: + ```yaml + #@data/values-schema + --- #! there must be a "---" here! + repository: dockercoins + tag: v0.1 + ``` + +- This defines the data values (=customizable parameters), + + as well as their *types* and *default values* + +- Technically, `#@data/values-schema` is an annotation, + and it applies to a YAML document; so the following + element must be a YAML document + +- This is conceptually similar to Helm's *values* file +
+ (but with type enforcement as a bonus) + +--- + +## Using data values + +- Requires loading `@ytt:data` + +- Values are then available in `data.values` + +- Example: + + ```yaml + #@ load("@ytt:data", "data") + #@ def image(component): + #@ return "{}/{}:{}".format(data.values.repository, component, data.values.tag) + #@ end + #@ name = "worker" + containers: + - name: #@ name + image: #@ image(name) + ``` + +--- + +## Overriding data values + +- There are many ways to set and override data values: + + - plain YAML files + + - data value overlays + + - environment variables + + - command-line flags + +- Precedence of the different methods is defined in the [docs] + +[docs]: https://carvel.dev/ytt/docs/v0.41.0/ytt-data-values/#data-values-merge-order + +--- + +## Values in plain YAML files + +- Content of `values.yaml`: + ```yaml + tag: latest + ``` + +- Values get merged with `--data-values-file`: + ```bash + ytt -f config/ --data-values-file values.yaml + ``` + +- Multiple files can be specified + +- These files can also be URLs! + +--- + +## Data value overlay + +- Content of `values.yaml`: + ```yaml + #@data/values + --- #! must have --- here + tag: latest + ``` + +- Values get merged by being specified like "normal" files: + ```bash + ytt -f config/ -f values.yaml + ``` + +- Multiple files can be specified + +--- + +## Set a value with a flag + +- Set a string value: + ```bash + ytt -f config/ --data-value tag=latest + ``` + +- Set a YAML value (useful to parse it as e.g. integer, boolean...): + ```bash + ytt -f config/ --data-value-yaml replicas=10 + ``` + +- Read a string value from a file: + ```bash + ytt -f config/ --data-value-file ca_cert=cert.pem + ``` + +--- + +## Set values from environment variables + +- Set environment variables with a prefix: + ```bash + export VAL_tag=latest + export VAL_repository=ghcr.io/dockercoins + ``` + +- Use the variables as strings: + ```bash + ytt -f config/ --data-values-env VAL + ``` + +- Or parse them as YAML: + ```bash + ytt -f config/ --data-values-env-yaml VAL + ``` + +--- + +## Lines starting with `#@` + +- This generates an empty document: + ```yaml + #@ def hello(): + hello: world + #@ end + + #@ hello() + ``` + +- Do this instead: + ```yaml + #@ def hello(): + hello: world + #@ end + + --- #@ hello() + ``` + +--- + +## Generating multiple documents, take 1 + +- This won't work: + + ```yaml + #@ def app(): + kind: Deployment + apiVersion: apps/v1 + --- #! separate from next document + kind: Service + apiVersion: v1 + #@ end + + --- #@ app() + ``` + +--- + +## Generating multiple documents, take 2 + +- This won't work either: + + ```yaml + #@ def app(): + --- #! the initial separator indicates "this is a Document Set" + kind: Deployment + apiVersion: apps/v1 + --- #! separate from next document + kind: Service + apiVersion: v1 + #@ end + + --- #@ app() + ``` + +--- + +## Generating multiple documents, take 3 + +- We must use the `template` module: + + ```yaml + #@ load("@ytt:template", "template") + + #@ def app(): + --- #! the initial separator indicates "this is a Document Set" + kind: Deployment + apiVersion: apps/v1 + --- #! separate from next document + kind: Service + apiVersion: v1 + #@ end + + --- #@ template.replace(app()) + ``` + +- `template.replace(...)` is the only way (?) to replace one element with many + +--- + +## Libraries + +- A reusable ytt configuration can be transformed into a library + +- Put it in a subdirectory named `_ytt_lib/whatever`, then: + + ```yaml + #@ load("@ytt:library", "library") + #@ load("@ytt:template", "template") + #@ whatever = library.get("whatever") + #@ my_values = {"tag": "latest", "registry": "..."} + #@ output = whatever.with_data_values(my_values).eval() + --- #@ template.replace(output) + ``` + +- The `with_data_values()` step is optional, but useful to "configure" the library + +- Note the whole combo: + ```yaml + template.replace(library.get("...").with_data_values(...).eval()) + ``` + +--- + +## Overlays + +- Powerful, but complex, but powerful! 💥 + +- Define transformations that are applied after generating the whole document set + +- General idea: + + - select YAML nodes to be transformed with an `#@overlay/match` decorator + + - write a YAML snippet with the modifications to be applied +
+ (a bit like a strategic merge patch) + +--- + +## Example + +```yaml +#@ load("@ytt:overlay", "overlay") + +#@ selector = {"kind": "Deployment", "metadata": {"name": "worker"}} +#@overlay/match by=overlay.subset(selector) +--- +spec: + replicas: 10 +``` + +- By default, `#@overlay/match` must find *exactly* one match + + (that can be changed by specifying `expects=...`, `missing_ok=True`... see [docs]) + +- By default, the specified fields (here, `spec.replicas`) must exist + + (that can also be changed by annotating the optional fields) + +[docs]: https://carvel.dev/ytt/docs/v0.41.0/lang-ref-ytt-overlay/#overlaymatch + +--- + +## Matching using a YAML document + +```yaml +#@ load("@ytt:overlay", "overlay") + +#@ def match(): +kind: Deployment +metadata: + name: worker +#@ end + +#@overlay/match by=overlay.subset(match()) +--- +spec: + replicas: 10 +``` + +- This is equivalent to the subset match of the previous slide + +- It will find YAML nodes having all the listed fields + +--- + +## Removing a field + +```yaml +#@ load("@ytt:overlay", "overlay") + +#@ def match(): +kind: Deployment +metadata: + name: worker +#@ end + +#@overlay/match by=overlay.subset(match()) +--- +spec: + #@overlay/remove + replicas: +``` + +- This would remove the `replicas:` field from a specific Deployment spec + +- This could be used e.g. when enabling autoscaling + +--- + +## Selecting multiple nodes + +```yaml +#@ load("@ytt:overlay", "overlay") + +#@ def match(): +kind: Deployment +#@ end + +#@overlay/match by=overlay.subset(match()), expects="1+" +--- +spec: + #@overlay/remove + replicas: +``` + +- This would match all Deployments +
+ (assuming that *at least one* exists) + +- It would remove the `replicas:` field from their spec +
+ (the field must exist!) + +--- + +## Adding a field + +```yaml +#@ load("@ytt:overlay", "overlay") + +#@overlay/match by=overlay.all, expects="1+" +--- +metadata: + #@overlay/match missing_ok=True + annotations: + #@overlay/match expects=0 + rainbow: 🌈 +``` + +- `#@overlay/match missing_ok=True` +
+ *will match whether our resources already have annotations or not* + +- `#@overlay/match expects=0` +
+ *will only match if the `rainbow` annotation doesn't exist* +
+ *(to make sure that we don't override/replace an existing annotation)* + +--- + +## Overlays vs data values + +- The documentation has a [detailed discussion][docs] about this question + +- In short: + + - values = for parameters that are exposed to the user + + - overlays = for arbitrary extra modifications + +- Values are easier to use (use them when possible!) + +- Fallback to overlays when values don't expose what you need + + (keeping in mind that overlays are harder to write/understand/maintain) + +[docs]: https://carvel.dev/ytt/docs/v0.41.0/data-values-vs-overlays/ + +--- + +## Gotchas + +- Reminder: put your `#@` at the right place! + +```yaml +#! This will generate "hello, world!" +--- #@ "{}, {}!".format("hello", "world") +``` + +```yaml +#! But this will generate an empty document +--- +#@ "{}, {}!".format("hello", "world") +``` + +- Also, don't use YAML anchors (`*foo` and `&foo`) + +- They don't mix well with ytt + +- Remember to use `template.render(...)` when generating multiple nodes + + (or to update lists or arrays without replacing them entirely) + +--- + +## Next steps with ytt + +- Read this documentation page about [injecting secrets][secrets] + +- Check the [FAQ], it gives some insights about what's possible with ytt + +- Exercise idea: write an overlay that will find all ConfigMaps mounted in Pods... + + ...and annotate the Pod with a hash of the ConfigMap + +[FAQ]: https://carvel.dev/ytt/docs/v0.41.0/faq/ +[secrets]: https://carvel.dev/ytt/docs/v0.41.0/injecting-secrets/ + +??? + +:EN:- YTT +:FR:- YTT diff --git a/slides/kube-adv.yml b/slides/kube-adv.yml index 229e0179..6f765a04 100644 --- a/slides/kube-adv.yml +++ b/slides/kube-adv.yml @@ -53,6 +53,7 @@ content: - k8s/helm-dependencies.md - k8s/helm-values-schema-validation.md - k8s/helm-secrets.md + - k8s/ytt.md - #5 - k8s/extending-api.md - k8s/operators.md diff --git a/slides/kube-fullday.yml b/slides/kube-fullday.yml index ebfb1feb..1800af5c 100644 --- a/slides/kube-fullday.yml +++ b/slides/kube-fullday.yml @@ -92,6 +92,7 @@ content: #- k8s/helm-values-schema-validation.md #- k8s/helm-secrets.md #- k8s/exercise-helm.md + #- k8s/ytt.md #- k8s/gitlab.md #- k8s/create-chart.md #- k8s/create-more-charts.md diff --git a/slides/kube-halfday.yml b/slides/kube-halfday.yml index 268259fe..0fe41beb 100644 --- a/slides/kube-halfday.yml +++ b/slides/kube-halfday.yml @@ -80,6 +80,7 @@ content: #- k8s/helm-values-schema-validation.md #- k8s/helm-secrets.md #- k8s/kustomize.md + #- k8s/ytt.md #- k8s/netpol.md - k8s/whatsnext.md # - k8s/links.md diff --git a/slides/kube-selfpaced.yml b/slides/kube-selfpaced.yml index 3fd1dca5..86b0ca6c 100644 --- a/slides/kube-selfpaced.yml +++ b/slides/kube-selfpaced.yml @@ -95,6 +95,7 @@ content: - k8s/helm-secrets.md #- k8s/exercise-helm.md - k8s/gitlab.md + - k8s/ytt.md - - k8s/netpol.md - k8s/authn-authz.md diff --git a/slides/kube-twodays.yml b/slides/kube-twodays.yml index 38859f51..b8eb46ab 100644 --- a/slides/kube-twodays.yml +++ b/slides/kube-twodays.yml @@ -90,6 +90,7 @@ content: - k8s/helm-values-schema-validation.md - k8s/helm-secrets.md #- k8s/exercise-helm.md + #- k8s/ytt.md - k8s/gitlab.md - - k8s/netpol.md