├── .github
└── workflows
│ └── image-ci.yml
├── .gitignore
├── 01-history-and-motivation
└── README.md
├── 02-technology-overview
├── README.md
└── readme-assets
│ ├── control-and-data-planes.jpg
│ └── k8s-architecture.jpg
├── 03-installation-and-setup
├── .gitignore
├── README.md
├── Taskfile.yaml
├── kind-bind-mount-1
│ └── hello-from-host
├── kind-bind-mount-2
│ └── hello-from-host
└── kind-config.yaml.TEMPLATE
├── 04-built-in-resource-types
├── ConfigMap
│ ├── ConfigMap.file-like-keys.yaml
│ ├── ConfigMap.property-like-keys.yaml
│ ├── Namespace.yaml
│ ├── Pod.configmap-example.yaml
│ └── Taskfile.yaml
├── CronJob
│ ├── CronJob.echo-date-better.yaml
│ ├── CronJob.echo-date-minimal.yaml
│ ├── Namespace.yaml
│ └── Taskfile.yaml
├── DaemonSet
│ ├── DaemonSet.fluentd-minimal.yaml
│ ├── Namespace.yaml
│ ├── Pod.fluentd-minimal.yaml
│ └── Taskfile.yaml
├── Deployment
│ ├── Deployment.nginx-better.yaml
│ ├── Deployment.nginx-minimal.yaml
│ ├── Namespace.yaml
│ └── Taskfile.yaml
├── GatewayAPI
│ ├── Deployment.yaml
│ ├── Gateway.gke.yaml
│ ├── Gateway.kong.yaml
│ ├── GatewayClass.kong.yaml
│ ├── HTTPRoute.gke.yaml
│ ├── HTTPRoute.kong.yaml
│ ├── Namespace.yaml
│ ├── Service.nginx-clusterip.yaml
│ ├── Service.nginx-nodeport.yaml
│ └── Taskfile.yaml
├── Ingress
│ ├── Deployment.yaml
│ ├── Ingress.fuller-nginx.yaml
│ ├── Ingress.minimal-gke.yaml
│ ├── Ingress.minimal-nginx.yaml
│ ├── Namespace.yaml
│ ├── Service.nginx-clusterip.yaml
│ ├── Service.nginx-nodeport.yaml
│ └── Taskfile.yaml
├── Job
│ ├── Job.echo-date-better.yaml
│ ├── Job.echo-date-minimal.yaml
│ ├── Namespace.yaml
│ ├── Pod.echo-date-minimal.yaml
│ └── Taskfile.yaml
├── Namespace
│ ├── Namespace.yaml
│ └── Taskfile.yaml
├── PersistentVolume
│ ├── Namespace.yaml
│ ├── Taskfile.yaml
│ ├── civo
│ │ ├── PersistentVolumeClaim.dynamic-pv-civo.yaml
│ │ ├── Pod.dynamic-pv-civo.yaml
│ │ ├── StatefulSet.individual-pvcs-civo.yaml
│ │ └── StorageClass.civo-volume.yaml
│ ├── gke
│ │ ├── PersistentVolumeClaim.dynamic-pv-gke.yaml
│ │ ├── Pod.dynamic-pv-gke.yaml
│ │ ├── StatefulSet.individual-pvcs-gke.yaml
│ │ └── StorageClass.standard-rwo.yaml
│ └── kind
│ │ ├── Deployment.shared-pvc-kind.yaml
│ │ ├── PersistentVolume.manual-kind.yaml
│ │ ├── PersistentVolumeClaim.dynamic-pv-kind.yaml
│ │ ├── PersistentVolumeClaim.manual-pv-kind.yaml
│ │ ├── Pod.manual-pv-and-pvc-kind.yaml
│ │ ├── StatefulSet.individual-pvcs-kind.yaml
│ │ └── StorageClass.standard.yaml
├── Pod
│ ├── Namespace.yaml
│ ├── Pod.nginx-better.yaml
│ ├── Pod.nginx-minimal.yaml
│ └── Taskfile.yaml
├── RBAC
│ ├── ClusterRole.pod-reader.yaml
│ ├── ClusterRoleBinding.pod-reader.yaml
│ ├── Job.cluster-pod-reader.yaml
│ ├── Job.namespaced-pod-reader-fail.yaml
│ ├── Job.namespaced-pod-reader-succeed.yaml
│ ├── Job.no-permissions.yaml
│ ├── Namespace.yaml
│ ├── Role.pod-reader.yaml
│ ├── RoleBinding.pod-reader.yaml
│ ├── ServiceAccount.cluster-pod-permissions.yaml
│ ├── ServiceAccount.namespaced-pod-permissions.yaml
│ └── Taskfile.yaml
├── README.md
├── ReplicaSet
│ ├── Namespace.yaml
│ ├── ReplicaSet.nginx-better.yaml
│ ├── ReplicaSet.nginx-minimal.yaml
│ └── Taskfile.yaml
├── Secret
│ ├── Namespace.yaml
│ ├── Pod.secret-example.yaml
│ ├── Secret.base64-data.yaml
│ ├── Secret.dockerconfigjson.yaml
│ ├── Secret.string-data.yaml
│ └── Taskfile.yaml
├── Service
│ ├── Deployment.yaml
│ ├── Namespace.yaml
│ ├── Service.nginx-clusterip.yaml
│ ├── Service.nginx-loadbalancer.yaml
│ ├── Service.nginx-nodeport.yaml
│ └── Taskfile.yaml
└── StatefulSet
│ ├── Namespace.yaml
│ ├── Service.nginx.yaml
│ ├── Service.nginxs.yaml
│ ├── StatefulSet.nginx-minimal.yaml
│ ├── StatefulSet.nginx-with-init-container.yaml
│ └── Taskfile.yaml
├── 05-helm
├── README.md
├── charts
│ ├── Namespace.yaml
│ ├── Taskfile.yaml
│ ├── helm-create-unmodified
│ │ ├── .helmignore
│ │ ├── Chart.yaml
│ │ ├── templates
│ │ │ ├── NOTES.txt
│ │ │ ├── _helpers.tpl
│ │ │ ├── deployment.yaml
│ │ │ ├── hpa.yaml
│ │ │ ├── ingress.yaml
│ │ │ ├── service.yaml
│ │ │ ├── serviceaccount.yaml
│ │ │ └── tests
│ │ │ │ └── test-connection.yaml
│ │ └── values.yaml
│ └── minimal
│ │ ├── .helmignore
│ │ ├── Chart.yaml
│ │ ├── templates
│ │ ├── NOTES.txt
│ │ ├── _helpers.tpl
│ │ └── configmap.yaml
│ │ ├── values-alt.yaml
│ │ └── values.yaml
├── postgresql
│ ├── .gitignore
│ ├── Namespace.yaml
│ ├── Taskfile.yaml
│ └── values.yaml
└── readme-assets
│ └── helm-diagram.png
├── 06-demo-application
├── README.md
├── Taskfile.yaml
├── api-golang
│ ├── .air.toml
│ ├── .dockerignore
│ ├── Dockerfile
│ ├── README.md
│ ├── Taskfile.yaml
│ ├── Tiltfile
│ ├── database
│ │ └── db.go
│ ├── go.mod
│ ├── go.sum
│ ├── healthcheck
│ │ └── healthcheck.go
│ ├── main.go
│ ├── test
│ │ └── example_test.go
│ └── tmp
│ │ ├── build-errors.log
│ │ └── main
├── api-node
│ ├── .dockerignore
│ ├── .gitignore
│ ├── .package.json.un~
│ ├── Dockerfile
│ ├── README.md
│ ├── Taskfile.yaml
│ ├── Tiltfile
│ ├── healthcheck
│ │ └── healthcheck.js
│ ├── package-lock.json
│ ├── package.json
│ ├── package.json~
│ ├── src
│ │ ├── db.js
│ │ └── index.js
│ └── test
│ │ └── example.test.js
├── client-react
│ ├── .dockerignore
│ ├── .gitignore
│ ├── Dockerfile
│ ├── README.md
│ ├── Taskfile.yaml
│ ├── Tiltfile
│ ├── index.html
│ ├── nginx.conf
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ │ └── favicon.ico
│ ├── src
│ │ ├── App.css
│ │ ├── App.jsx
│ │ ├── index.css
│ │ └── main.jsx
│ └── vite.config.js
├── load-generator-python
│ ├── Dockerfile
│ ├── Taskfile.yaml
│ ├── Tiltfile
│ ├── main.py
│ ├── poetry.lock
│ └── pyproject.toml
├── postgresql
│ ├── Dockerfile
│ ├── Taskfile.yaml
│ └── migrations
│ │ ├── 000001_create_users_table.down.sql
│ │ └── 000001_create_users_table.up.sql
└── readme-assets
│ ├── request-diagram.png
│ └── screenshot.png
├── 07-deploying-demo-application
├── Namespace.yaml
├── README.md
├── Taskfile.yaml
├── api-golang
│ ├── Deployment.yaml
│ ├── IngressRoute.yaml
│ ├── Secret.yml
│ └── Service.yaml
├── api-node
│ ├── Deployment.yaml
│ ├── IngressRoute.yaml
│ ├── Secret.yaml
│ └── Service.yaml
├── client-react
│ ├── ConfigMap.yaml
│ ├── Deployment.yaml
│ ├── IngressRoute.yaml
│ └── Service.yaml
├── common
│ ├── Middleware.yaml
│ ├── Namespace.yaml
│ └── Taskfile.yaml
├── load-generator-python
│ ├── ConfigMap.yaml
│ └── Deployment.yaml
└── postgresql
│ ├── Job.db-migrator.yaml
│ ├── Secret.db-password.yaml
│ ├── Taskfile.yaml
│ └── values.yaml
├── 08-extending-kubernetes
├── README.md
└── readme-assets
│ └── galaxy-brain.png
├── 09-deploying-auxiliary-tooling
├── README.md
├── Taskfile.yaml
├── cloudnative-pg
│ ├── Backup.yaml
│ ├── Cluster.cnpg-minimal.yaml
│ ├── Cluster.cnpg-with-backup-config-civo.yaml
│ ├── Cluster.cnpg-with-backup-config-gcp.yaml
│ ├── Namespace.yaml
│ ├── ScheduleBackup.yaml
│ ├── Secret.civo-object-store-creds.yaml.TEMPLATE
│ └── Taskfile.yaml
└── trivy-operator
│ └── Taskfile.yaml
├── 10-developer-experience
├── README.md
├── Taskfile.yaml
├── external-secrets-operator
│ ├── ClusterSecretStore.yaml
│ ├── ExternalSecret.yaml
│ ├── ServiceAccount.yaml
│ ├── Taskfile.yaml
│ └── values.yaml
└── tilt
│ ├── Taskfile.yaml
│ └── Tiltfile
├── 11-debugging
├── Namespace.yaml
├── README.md
├── Taskfile.yaml
├── microservices-demo.yaml
└── readme-assets
│ └── broken-demo.png
├── 12-deploying-to-multiple-environments
├── README.md
├── Taskfile.yaml
├── helm
│ ├── .gitignore
│ ├── Taskfile.yaml
│ └── api-golang-helm-chart
│ │ ├── .helmignore
│ │ ├── Chart.yaml
│ │ ├── templates
│ │ ├── Deployment.yaml
│ │ ├── IngressRoute.yaml
│ │ ├── Secret.yml
│ │ ├── Service.yaml
│ │ └── _helpers.tpl
│ │ ├── values.production.yaml
│ │ ├── values.staging.yaml
│ │ └── values.yaml
├── kluctl-single-service
│ ├── .kluctl.yaml
│ ├── README.md
│ ├── Taskfile.yaml
│ ├── config
│ │ ├── production.yaml
│ │ └── staging.yaml
│ ├── deployment.yaml
│ ├── namespaces
│ │ └── Namespace.demo-app.yaml
│ └── services
│ │ ├── api-golang
│ │ ├── config
│ │ │ ├── production.yaml
│ │ │ └── staging.yaml
│ │ ├── deployment.yaml
│ │ └── manifests
│ │ │ ├── Deployment.yaml
│ │ │ ├── IngressRoute.yaml
│ │ │ ├── Job.db-migrator.yaml
│ │ │ ├── Middleware.yaml
│ │ │ ├── Secret.db-migrator-password.yaml
│ │ │ ├── Secret.yml
│ │ │ └── Service.yaml
│ │ └── deployment.yaml
├── kluctl
│ ├── .helm-charts
│ │ ├── https_cloudnative-pg.github.io
│ │ │ └── charts
│ │ │ │ └── cloudnative-pg
│ │ │ │ └── 0.21.4
│ │ │ │ ├── .helmignore
│ │ │ │ ├── Chart.lock
│ │ │ │ ├── Chart.yaml
│ │ │ │ ├── LICENSE
│ │ │ │ ├── README.md
│ │ │ │ ├── charts
│ │ │ │ └── cluster
│ │ │ │ │ ├── .helmignore
│ │ │ │ │ ├── Chart.yaml
│ │ │ │ │ ├── README.md
│ │ │ │ │ ├── README.md.gotmpl
│ │ │ │ │ ├── grafana-dashboard.json
│ │ │ │ │ ├── templates
│ │ │ │ │ ├── NOTES.txt
│ │ │ │ │ └── sidecar-configmap.yaml
│ │ │ │ │ ├── values.schema.json
│ │ │ │ │ └── values.yaml
│ │ │ │ ├── monitoring
│ │ │ │ └── grafana-dashboard.json
│ │ │ │ ├── templates
│ │ │ │ ├── NOTES.txt
│ │ │ │ ├── _helpers.tpl
│ │ │ │ ├── config.yaml
│ │ │ │ ├── crds
│ │ │ │ │ └── crds.yaml
│ │ │ │ ├── deployment.yaml
│ │ │ │ ├── monitoring-configmap.yaml
│ │ │ │ ├── mutatingwebhookconfiguration.yaml
│ │ │ │ ├── podmonitor.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ ├── service.yaml
│ │ │ │ └── validatingwebhookconfiguration.yaml
│ │ │ │ ├── values.schema.json
│ │ │ │ └── values.yaml
│ │ └── https_traefik.github.io
│ │ │ └── charts
│ │ │ └── traefik
│ │ │ └── 20.8.0
│ │ │ ├── .helmignore
│ │ │ ├── Changelog.md
│ │ │ ├── Chart.yaml
│ │ │ ├── Guidelines.md
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── crds
│ │ │ ├── ingressroute.yaml
│ │ │ ├── ingressroutetcp.yaml
│ │ │ ├── ingressrouteudp.yaml
│ │ │ ├── middlewares.yaml
│ │ │ ├── middlewarestcp.yaml
│ │ │ ├── serverstransports.yaml
│ │ │ ├── tlsoptions.yaml
│ │ │ ├── tlsstores.yaml
│ │ │ └── traefikservices.yaml
│ │ │ ├── templates
│ │ │ ├── NOTES.txt
│ │ │ ├── _helpers.tpl
│ │ │ ├── _podtemplate.tpl
│ │ │ ├── _service-internal.tpl
│ │ │ ├── _service-metrics.tpl
│ │ │ ├── _service.tpl
│ │ │ ├── daemonset.yaml
│ │ │ ├── dashboard-hook-ingressroute.yaml
│ │ │ ├── deployment.yaml
│ │ │ ├── extra-objects.yaml
│ │ │ ├── gateway.yaml
│ │ │ ├── gatewayclass.yaml
│ │ │ ├── hpa.yaml
│ │ │ ├── ingressclass.yaml
│ │ │ ├── poddisruptionbudget.yaml
│ │ │ ├── prometheusrules.yaml
│ │ │ ├── pvc.yaml
│ │ │ ├── rbac
│ │ │ │ ├── clusterrole.yaml
│ │ │ │ ├── clusterrolebinding.yaml
│ │ │ │ ├── podsecuritypolicy.yaml
│ │ │ │ ├── role.yaml
│ │ │ │ ├── rolebinding.yaml
│ │ │ │ └── serviceaccount.yaml
│ │ │ ├── service-hub.yaml
│ │ │ ├── service-internal.yaml
│ │ │ ├── service-metrics.yaml
│ │ │ ├── service.yaml
│ │ │ ├── servicemonitor.yaml
│ │ │ ├── tlsoption.yaml
│ │ │ └── tlsstore.yaml
│ │ │ └── values.yaml
│ ├── .kluctl.yaml
│ ├── README.md
│ ├── Taskfile.yaml
│ ├── config
│ │ ├── production.yaml
│ │ └── staging.yaml
│ ├── deployment.yaml
│ ├── namespaces
│ │ ├── Namespace.demo-app.yaml
│ │ └── Namespace.postgres.yaml
│ ├── services
│ │ ├── api-golang
│ │ │ ├── config
│ │ │ │ ├── production.yaml
│ │ │ │ └── staging.yaml
│ │ │ ├── deployment.yaml
│ │ │ └── manifests
│ │ │ │ ├── Deployment.yaml
│ │ │ │ ├── IngressRoute.yaml
│ │ │ │ ├── Job.db-migrator.yaml
│ │ │ │ ├── Middleware.yaml
│ │ │ │ ├── Secret.db-migrator-password.yaml
│ │ │ │ ├── Secret.yml
│ │ │ │ └── Service.yaml
│ │ ├── api-node
│ │ │ ├── config
│ │ │ │ ├── production.yaml
│ │ │ │ └── staging.yaml
│ │ │ ├── deployment.yaml
│ │ │ └── manifests
│ │ │ │ ├── Deployment.yaml
│ │ │ │ ├── IngressRoute.yaml
│ │ │ │ ├── Middleware.yaml
│ │ │ │ ├── Secret.yaml
│ │ │ │ └── Service.yaml
│ │ ├── client-react
│ │ │ ├── config
│ │ │ │ ├── production.yaml
│ │ │ │ └── staging.yaml
│ │ │ ├── deployment.yaml
│ │ │ └── manifests
│ │ │ │ ├── ConfigMap.yaml
│ │ │ │ ├── Deployment.yaml
│ │ │ │ ├── IngressRoute.yaml
│ │ │ │ └── Service.yaml
│ │ ├── deployment.yaml
│ │ ├── load-generator-python
│ │ │ ├── config
│ │ │ │ ├── production.yaml
│ │ │ │ └── staging.yaml
│ │ │ ├── deployment.yaml
│ │ │ └── manifests
│ │ │ │ ├── ConfigMap.yaml
│ │ │ │ └── Deployment.yaml
│ │ └── postgres
│ │ │ ├── config
│ │ │ ├── production.yaml
│ │ │ └── staging.yaml
│ │ │ ├── deployment.yaml
│ │ │ └── manifests
│ │ │ ├── Cluster.yaml
│ │ │ └── Secret.yaml
│ └── third-party
│ │ ├── cloudnative-pg
│ │ ├── Namespace.yaml
│ │ ├── helm-chart.yaml
│ │ ├── helm-values.yaml
│ │ └── kustomization.yaml
│ │ ├── deployment.yaml
│ │ └── traefik
│ │ ├── Namespace.yaml
│ │ ├── helm-chart.yaml
│ │ ├── helm-values.yaml
│ │ └── kustomization.yaml
└── kustomize
│ ├── Taskfile.yaml
│ ├── base
│ ├── api-golang
│ │ ├── Deployment.yaml
│ │ ├── IngressRoute.yaml
│ │ ├── Secret.yaml
│ │ ├── Service.yaml
│ │ └── kustomization.yaml
│ ├── api-node
│ │ ├── Deployment.yaml
│ │ ├── IngressRoute.yaml
│ │ ├── Secret.yaml
│ │ ├── Service.yaml
│ │ └── kustomization.yaml
│ ├── client-react
│ │ ├── ConfigMap.yaml
│ │ ├── Deployment.yaml
│ │ ├── IngressRoute.yaml
│ │ ├── Service.yaml
│ │ └── kustomization.yaml
│ ├── common
│ │ ├── Middleware.yaml
│ │ ├── Namespace.yaml
│ │ └── kustomization.yaml
│ ├── kustomization.yaml
│ └── load-generator-python
│ │ ├── ConfigMap.yaml
│ │ ├── Deployment.yaml
│ │ └── kustomization.yaml
│ ├── production
│ ├── api-golang
│ │ ├── kustomization.yaml
│ │ └── patches
│ │ │ ├── Deployment.yaml
│ │ │ └── IngressRoute.replace-host.yaml
│ ├── api-node
│ │ ├── kustomization.yaml
│ │ └── patches
│ │ │ ├── Deployment.yaml
│ │ │ └── IngressRoute.replace-host.yaml
│ ├── client-react
│ │ ├── kustomization.yaml
│ │ └── patches
│ │ │ ├── Deployment.yaml
│ │ │ └── IngressRoute.replace-host.yaml
│ ├── common
│ │ └── kustomization.yaml
│ ├── kustomization.yaml
│ └── load-generator-python
│ │ ├── kustomization.yaml
│ │ └── patches
│ │ └── Deployment.yaml
│ └── staging
│ ├── api-golang
│ ├── kustomization.yaml
│ └── patches
│ │ ├── Deployment.yaml
│ │ └── IngressRoute.replace-host.yaml
│ ├── api-node
│ ├── kustomization.yaml
│ └── patches
│ │ ├── Deployment.yaml
│ │ └── IngressRoute.replace-host.yaml
│ ├── client-react
│ ├── kustomization.yaml
│ └── patches
│ │ ├── Deployment.yaml
│ │ └── IngressRoute.replace-host.yaml
│ ├── common
│ └── kustomization.yaml
│ ├── kustomization.yaml
│ └── load-generator-python
│ ├── kustomization.yaml
│ └── patches
│ └── Deployment.yaml
├── 13-cluster-and-node-upgrades
├── README.md
└── Taskfile.yaml
├── 14-cicd
├── README.md
├── Taskfile.yaml
├── github-actions
│ └── Taskfile.yaml
└── kluctl-gitops
│ ├── .kluctl.yaml
│ ├── Taskfile.yaml
│ ├── clusters
│ ├── all
│ │ └── KluctlDeployment.gitops.yaml
│ ├── deployment.yaml
│ ├── production
│ │ └── KluctlDeployment.devops-directive-kubernetes-course.yaml
│ └── staging
│ │ └── KluctlDeployment.devops-directive-kubernetes-course.yaml
│ ├── deployment.yaml
│ └── namespaces
│ ├── Namespace.kluctl-gitops.yaml
│ └── Namespace.kluctl-system.yaml
├── README.md
├── Taskfile.yaml
├── devbox.json
├── devbox.lock
├── gcloud
├── flake.lock
└── flake.nix
├── pyproject.toml
└── readme-assets
└── thumbnail.jpg
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/
2 | **/.DS_STORE
--------------------------------------------------------------------------------
/02-technology-overview/readme-assets/control-and-data-planes.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sidpalas/devops-directive-kubernetes-course/18d4bcfac1818609dfc2e9e82d0affd77e0e7c47/02-technology-overview/readme-assets/control-and-data-planes.jpg
--------------------------------------------------------------------------------
/02-technology-overview/readme-assets/k8s-architecture.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sidpalas/devops-directive-kubernetes-course/18d4bcfac1818609dfc2e9e82d0affd77e0e7c47/02-technology-overview/readme-assets/k8s-architecture.jpg
--------------------------------------------------------------------------------
/03-installation-and-setup/.gitignore:
--------------------------------------------------------------------------------
1 | kind-config.yaml
--------------------------------------------------------------------------------
/03-installation-and-setup/kind-bind-mount-1/hello-from-host:
--------------------------------------------------------------------------------
1 | 👋 (#1)
--------------------------------------------------------------------------------
/03-installation-and-setup/kind-bind-mount-2/hello-from-host:
--------------------------------------------------------------------------------
1 | 👋 (#2)
--------------------------------------------------------------------------------
/03-installation-and-setup/kind-config.yaml.TEMPLATE:
--------------------------------------------------------------------------------
1 | # three node (two workers) cluster config
2 | kind: Cluster
3 | apiVersion: kind.x-k8s.io/v1alpha4
4 | nodes:
5 | - role: control-plane
6 | - role: worker
7 | extraMounts:
8 | - hostPath: ${REPLACE_WITH_ABSOLUTE_PATH}/kind-bind-mount-1
9 | containerPath: /some/path/in/container
10 | - role: worker
11 | extraMounts:
12 | - hostPath: ${REPLACE_WITH_ABSOLUTE_PATH}/kind-bind-mount-2
13 | containerPath: /some/path/in/container
14 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/ConfigMap/ConfigMap.file-like-keys.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: file-like-keys
5 | data:
6 | conf.yml: |
7 | name: YourAppName
8 | version: 1.0.0
9 | author: YourName
10 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/ConfigMap/ConfigMap.property-like-keys.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: property-like-keys
5 | data:
6 | NAME: YourAppName
7 | VERSION: 1.0.0
8 | AUTHOR: YourName
9 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/ConfigMap/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 04--configmap
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/ConfigMap/Pod.configmap-example.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: configmap-example
5 | spec:
6 | containers:
7 | - name: nginx
8 | image: nginx:1.26.0
9 | volumeMounts:
10 | - name: configmap-file-like-keys
11 | mountPath: /etc/config
12 | envFrom:
13 | - configMapRef:
14 | name: property-like-keys
15 | volumes:
16 | - name: configmap-file-like-keys
17 | configMap:
18 | name: file-like-keys
19 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/CronJob/CronJob.echo-date-better.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: batch/v1
2 | kind: CronJob
3 | metadata:
4 | name: echo-date-better
5 | namespace: 04--cronjob
6 | spec:
7 | schedule: "* * * * *"
8 | jobTemplate:
9 | spec:
10 | parallelism: 1
11 | completions: 1
12 | activeDeadlineSeconds: 100
13 | backoffLimit: 1
14 | template:
15 | metadata:
16 | labels:
17 | app: echo-date
18 | spec:
19 | containers:
20 | - name: echo
21 | image: cgr.dev/chainguard/busybox:latest
22 | command: ["date"]
23 | resources:
24 | limits:
25 | memory: "50Mi"
26 | requests:
27 | memory: "50Mi"
28 | cpu: "250m"
29 | securityContext:
30 | allowPrivilegeEscalation: false
31 | privileged: false
32 | runAsUser: 1001
33 | runAsGroup: 1001
34 | runAsNonRoot: true
35 | restartPolicy: Never
36 | securityContext:
37 | seccompProfile:
38 | type: RuntimeDefault
39 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/CronJob/CronJob.echo-date-minimal.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: batch/v1
2 | kind: CronJob
3 | metadata:
4 | name: echo-date-minimal
5 | spec:
6 | schedule: "* * * * *"
7 | jobTemplate:
8 | spec:
9 | template:
10 | spec:
11 | containers:
12 | - name: echo
13 | image: busybox:1.36.1
14 | command: ["date"]
15 | restartPolicy: Never
16 | backoffLimit: 1
17 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/CronJob/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 04--cronjob
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/CronJob/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | env:
4 | BORDER: double
5 | BORDER_FOREGROUND: "212"
6 | PADDING: "1 1"
7 | MARGIN: "1 1"
8 | NAMESPACE: 04--cronjob
9 |
10 | tasks:
11 | 01-create-namespace:
12 | desc: "Create a namespace for these examples and set as default"
13 | cmds:
14 | - kubectl apply -f Namespace.yaml
15 | - kubens ${NAMESPACE}
16 |
17 | 02-apply-minimal:
18 | desc: "Apply the minimal CronJob configuration"
19 | cmds:
20 | - kubectl apply -f CronJob.echo-date-minimal.yaml
21 |
22 | 03-apply-better:
23 | desc: "Apply the better CronJob configuration"
24 | cmds:
25 | - kubectl apply -f CronJob.echo-date-better.yaml
26 |
27 | 04-create-job-from-cronjob:
28 | desc: "Manually create a job using a cronjob as the template"
29 | cmds:
30 | - kubectl create job --from=cronjob/echo-date-better manually-triggered
31 |
32 | 05-delete-namespace:
33 | desc: "Delete the namespace to clean up"
34 | cmds:
35 | - cmd: gum style "🚨 Deleting the namespace recursively deletes the resources inside of it! 🚨 "
36 | silent: true
37 | - kubectl delete -f Namespace.yaml
38 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/DaemonSet/DaemonSet.fluentd-minimal.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: DaemonSet
3 | metadata:
4 | name: fluentd-minimal
5 | namespace: 04--daemonset
6 | spec:
7 | selector:
8 | matchLabels:
9 | app: fluentd
10 | template:
11 | metadata:
12 | labels:
13 | app: fluentd
14 | spec:
15 | containers:
16 | - name: fluentd
17 | image: fluentd:v1.16-1
18 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/DaemonSet/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 04--daemonset
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/DaemonSet/Pod.fluentd-minimal.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: fluentd-minimal
5 | spec:
6 | containers:
7 | - name: fluentd
8 | image: fluentd:v1.16-1
9 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/DaemonSet/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | env:
4 | BORDER: double
5 | BORDER_FOREGROUND: "212"
6 | PADDING: "1 1"
7 | MARGIN: "1 1"
8 | NAMESPACE: 04--daemonset
9 |
10 | tasks:
11 | 01-create-namespace:
12 | desc: "Create a namespace for these examples and set as default"
13 | cmds:
14 | - kubectl apply -f Namespace.yaml
15 | - kubens ${NAMESPACE}
16 |
17 | 02-apply-minimal-pod:
18 | desc: "Apply a minimal fluentd pod configuration"
19 | cmds:
20 | - kubectl apply -f Pod.fluentd-minimal.yaml
21 |
22 | 03-apply-minimal-daemonset:
23 | desc: "Apply a minimal fluentd daemonset configuration"
24 | cmds:
25 | - kubectl apply -f DaemonSet.fluentd-minimal.yaml
26 |
27 | 04-delete-namespace:
28 | desc: "Delete the namespace to clean up"
29 | cmds:
30 | - cmd: gum style "🚨 Deleting the namespace recursively deletes the resources inside of it! 🚨 "
31 | silent: true
32 | - kubectl delete -f Namespace.yaml
33 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Deployment/Deployment.nginx-better.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: nginx-better
5 | namespace: 04--deployment
6 | labels:
7 | app: nginx-better
8 | spec:
9 | replicas: 3
10 | selector:
11 | matchLabels:
12 | app: nginx-better
13 | template:
14 | metadata:
15 | labels:
16 | app: nginx-better
17 | spec:
18 | containers:
19 | - name: nginx
20 | image: cgr.dev/chainguard/nginx:latest
21 | ports:
22 | - containerPort: 8080
23 | protocol: TCP
24 | readinessProbe:
25 | httpGet:
26 | path: /
27 | port: 8080
28 | resources:
29 | limits:
30 | memory: "50Mi"
31 | requests:
32 | memory: "50Mi"
33 | cpu: "250m"
34 | securityContext:
35 | allowPrivilegeEscalation: false
36 | privileged: false
37 | securityContext:
38 | seccompProfile:
39 | type: RuntimeDefault
40 | runAsUser: 1001
41 | runAsGroup: 1001
42 | runAsNonRoot: true
43 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Deployment/Deployment.nginx-minimal.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: nginx-minimal
5 | spec:
6 | replicas: 3
7 | selector:
8 | matchLabels:
9 | app: nginx-minimal
10 | template:
11 | metadata:
12 | labels:
13 | app: nginx-minimal
14 | spec:
15 | containers:
16 | - name: nginx
17 | image: nginx:1.26.0
18 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Deployment/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 04--deployment
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Deployment/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | env:
4 | BORDER: double
5 | BORDER_FOREGROUND: "212"
6 | PADDING: "1 1"
7 | MARGIN: "1 1"
8 | NAMESPACE: 04--deployment
9 |
10 | tasks:
11 | 01-create-namespace:
12 | desc: "Create a namespace for these examples and set as default"
13 | cmds:
14 | - kubectl apply -f Namespace.yaml
15 | - kubens ${NAMESPACE}
16 |
17 | 02-apply-minimal:
18 | desc: "Apply the minimal Deployment configuration"
19 | cmds:
20 | - kubectl apply -f Deployment.nginx-minimal.yaml
21 |
22 | 03-apply-better:
23 | desc: "Apply the better Deployment configuration"
24 | cmds:
25 | - kubectl apply -f Deployment.nginx-better.yaml
26 |
27 | 04-rollout-restart:
28 | desc: "Roll the pods in one of the deployments"
29 | cmds:
30 | - kubectl rollout restart deployment nginx-better
31 | - watch "kubectl get pods"
32 |
33 | 05-delete-namespace:
34 | desc: "Delete the namespace to clean up"
35 | cmds:
36 | - cmd: gum style "🚨 Deleting the namespace recursively deletes the resources inside of it! 🚨 "
37 | silent: true
38 | - kubectl delete -f Namespace.yaml
39 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/GatewayAPI/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: nginx-minimal
5 | spec:
6 | replicas: 3
7 | selector:
8 | matchLabels:
9 | app: nginx-pod-label
10 | template:
11 | metadata:
12 | labels:
13 | app: nginx-pod-label
14 | spec:
15 | containers:
16 | - name: nginx
17 | image: nginx:1.26.0
18 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/GatewayAPI/Gateway.gke.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1beta1
2 | kind: Gateway
3 | metadata:
4 | name: gke
5 | spec:
6 | gatewayClassName: gke-l7-global-external-managed
7 | listeners:
8 | - name: http
9 | protocol: HTTP
10 | port: 80
11 | allowedRoutes:
12 | kinds:
13 | - kind: HTTPRoute
14 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/GatewayAPI/Gateway.kong.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1beta1
2 | kind: Gateway
3 | metadata:
4 | name: kong
5 | spec:
6 | gatewayClassName: kong
7 | listeners:
8 | - name: proxy
9 | port: 80
10 | protocol: HTTP
11 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/GatewayAPI/GatewayClass.kong.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1beta1
2 | kind: GatewayClass
3 | metadata:
4 | name: kong
5 | annotations:
6 | konghq.com/gatewayclass-unmanaged: "true"
7 | spec:
8 | controllerName: konghq.com/kic-gateway-controller
9 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/GatewayAPI/HTTPRoute.gke.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1beta1
2 | kind: HTTPRoute
3 | metadata:
4 | name: gke
5 | spec:
6 | parentRefs:
7 | - name: gke
8 | hostnames:
9 | - "gateway-example-gke.com"
10 | rules:
11 | - matches:
12 | - path:
13 | type: PathPrefix
14 | value: /
15 | backendRefs:
16 | - name: nginx-nodeport
17 | kind: Service
18 | port: 80
19 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/GatewayAPI/HTTPRoute.kong.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1beta1
2 | kind: HTTPRoute
3 | metadata:
4 | name: kong
5 | spec:
6 | parentRefs:
7 | - name: kong
8 | hostnames:
9 | - "gateway-example-kong.com"
10 | rules:
11 | - matches:
12 | - path:
13 | type: PathPrefix
14 | value: /
15 | backendRefs:
16 | - name: nginx-clusterip
17 | kind: Service
18 | port: 80
19 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/GatewayAPI/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 04--gatewayapi
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/GatewayAPI/Service.nginx-clusterip.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: nginx-clusterip
5 | spec:
6 | type: ClusterIP # This is the default value
7 | selector:
8 | app: nginx-pod-label
9 | ports:
10 | - protocol: TCP
11 | port: 80 # Port the service is listening on
12 | targetPort: 80 # Port the container is listening on (if unset, defaults to equal port value)
13 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/GatewayAPI/Service.nginx-nodeport.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: nginx-nodeport
5 | spec:
6 | type: NodePort # For GKE load balancer this has to be a NodePort
7 | selector:
8 | app: nginx-pod-label
9 | ports:
10 | - protocol: TCP
11 | port: 80 # Port the service is listening on
12 | targetPort: 80 # Port the container is listening on (if unset, defaults to equal port value)
13 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Ingress/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: nginx-minimal
5 | spec:
6 | replicas: 3
7 | selector:
8 | matchLabels:
9 | app: nginx-pod-label
10 | template:
11 | metadata:
12 | labels:
13 | app: nginx-pod-label
14 | spec:
15 | containers:
16 | - name: nginx
17 | image: nginx:1.26.0
18 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Ingress/Ingress.fuller-nginx.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: Ingress
3 | metadata:
4 | name: fuller
5 | annotations:
6 | nginx.ingress.kubernetes.io/rewrite-target: /
7 | nginx.ingress.kubernetes.io/ssl-redirect: "false"
8 | nginx.ingress.kubernetes.io/use-regex: "true"
9 | nginx.ingress.kubernetes.io/proxy-body-size: "50m"
10 | spec:
11 | ingressClassName: nginx
12 | defaultBackend:
13 | service:
14 | name: default-backend
15 | port:
16 | number: 80
17 | rules:
18 | - host: "civo-ingress-example.com"
19 | http:
20 | paths:
21 | - path: /foo
22 | pathType: Prefix
23 | backend:
24 | service:
25 | name: foo-service
26 | port:
27 | number: 80
28 | - path: /bar
29 | pathType: ImplementationSpecific
30 | backend:
31 | service:
32 | name: bar-service
33 | port:
34 | number: 8080
35 | - path: /static/(.*)
36 | pathType: ImplementationSpecific
37 | backend:
38 | service:
39 | name: static-service
40 | port:
41 | number: 80
42 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Ingress/Ingress.minimal-gke.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: Ingress
3 | metadata:
4 | name: minimal-gke
5 | annotations:
6 | kubernetes.io/ingress.class: "gce"
7 | # kubernetes.io/ingress.class: "gce-internal" (for traffic external to cluster but internal to VPC)
8 | spec:
9 | # NOTE: You can't use spec.ingressClassName for GKE ingress
10 | rules:
11 | - host: "ingress-example-gke.com"
12 | http:
13 | paths:
14 | - path: /
15 | pathType: Prefix
16 | backend:
17 | service:
18 | name: nginx-nodeport
19 | port:
20 | number: 80
21 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Ingress/Ingress.minimal-nginx.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: Ingress
3 | metadata:
4 | name: minimal-nginx
5 | # Can use
6 | # annotations:
7 | # kubernetes.io/ingress.class: "nginx"
8 | spec:
9 | ingressClassName: nginx
10 | rules:
11 | - host: "ingress-example-nginx.com"
12 | http:
13 | paths:
14 | - path: /
15 | pathType: ImplementationSpecific
16 | backend:
17 | service:
18 | name: nginx-clusterip
19 | port:
20 | number: 80
21 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Ingress/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 04--ingress
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Ingress/Service.nginx-clusterip.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: nginx-clusterip
5 | spec:
6 | type: ClusterIP # This is the default value
7 | selector:
8 | app: nginx-pod-label
9 | ports:
10 | - protocol: TCP
11 | port: 80 # Port the service is listening on
12 | targetPort: 80 # Port the container is listening on (if unset, defaults to equal port value)
13 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Ingress/Service.nginx-nodeport.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: nginx-nodeport
5 | spec:
6 | type: NodePort # For GKE load balancer this has to be a NodePort
7 | selector:
8 | app: nginx-pod-label
9 | ports:
10 | - protocol: TCP
11 | port: 80 # Port the service is listening on
12 | targetPort: 80 # Port the container is listening on (if unset, defaults to equal port value)
13 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Job/Job.echo-date-better.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: batch/v1
2 | kind: Job
3 | metadata:
4 | name: echo-date-better
5 | namespace: 04--job
6 | spec:
7 | parallelism: 2
8 | completions: 2
9 | activeDeadlineSeconds: 100
10 | backoffLimit: 1
11 | template:
12 | metadata:
13 | labels:
14 | app: echo-date
15 | spec:
16 | containers:
17 | - name: echo
18 | image: cgr.dev/chainguard/busybox:latest
19 | command: ["date"]
20 | resources:
21 | limits:
22 | memory: "50Mi"
23 | requests:
24 | memory: "50Mi"
25 | cpu: "250m"
26 | securityContext:
27 | allowPrivilegeEscalation: false
28 | privileged: false
29 | runAsUser: 1001
30 | runAsGroup: 1001
31 | runAsNonRoot: true
32 | restartPolicy: Never
33 | securityContext:
34 | seccompProfile:
35 | type: RuntimeDefault
36 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Job/Job.echo-date-minimal.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: batch/v1
2 | kind: Job
3 | metadata:
4 | name: echo-date-minimal
5 | spec:
6 | template:
7 | spec:
8 | containers:
9 | - name: echo
10 | image: busybox:1.36.1
11 | command: ["date"]
12 | restartPolicy: Never
13 | backoffLimit: 1
14 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Job/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 04--job
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Job/Pod.echo-date-minimal.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: echo-date-minimal
5 | spec:
6 | containers:
7 | - name: echo
8 | image: busybox:1.36.1
9 | command: ["date"]
10 | restartPolicy: Never
11 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Job/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | env:
4 | BORDER: double
5 | BORDER_FOREGROUND: "212"
6 | PADDING: "1 1"
7 | MARGIN: "1 1"
8 | NAMESPACE: 04--job
9 |
10 | tasks:
11 | 01-create-namespace:
12 | desc: "Create a namespace for these examples and set as default"
13 | cmds:
14 | - kubectl apply -f Namespace.yaml
15 | - kubens ${NAMESPACE}
16 |
17 | 02-apply-minimal-pod:
18 | desc: "Apply the standalone Pod configuration"
19 | cmds:
20 | - kubectl apply -f Pod.echo-date-minimal.yaml
21 |
22 | 03-apply-minimal-job:
23 | desc: "Apply the minimal Job configuration"
24 | cmds:
25 | - kubectl apply -f Job.echo-date-minimal.yaml
26 |
27 | 04-apply-better-job:
28 | desc: "Apply the better Job configuration"
29 | cmds:
30 | - kubectl apply -f Job.echo-date-better.yaml
31 |
32 | 05-delete-namespace:
33 | desc: "Delete the namespace to clean up"
34 | cmds:
35 | - cmd: gum style "🚨 Deleting the namespace recursively deletes the resources inside of it! 🚨 "
36 | silent: true
37 | - kubectl delete -f Namespace.yaml
38 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Namespace/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 04--namespace-file
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Namespace/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | tasks:
4 | 01-create-namespace:
5 | cmds:
6 | - kubectl create namespace 04--namespace-cli
7 | desc: Create a namespace in the cluster
8 |
9 | 02-apply-namespace:
10 | cmds:
11 | - kubectl apply -f Namespace.yaml
12 | desc: Apply the namespace configuration to the cluster
13 |
14 | 03-delete-namespaces:
15 | cmds:
16 | - kubectl delete namespace 04--namespace-cli
17 | - kubectl delete -f Namespace.yaml
18 | desc: Delete the namespace
19 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/PersistentVolume/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 04--persistentvolume
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/PersistentVolume/civo/PersistentVolumeClaim.dynamic-pv-civo.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: PersistentVolumeClaim
3 | metadata:
4 | name: dynamic-pv-civo
5 | spec:
6 | accessModes:
7 | - ReadWriteOnce
8 | resources:
9 | requests:
10 | storage: 1Gi
11 | storageClassName: civo-volume
12 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/PersistentVolume/civo/Pod.dynamic-pv-civo.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: dynamic-pv-civo
5 | spec:
6 | containers:
7 | - name: nginx
8 | image: nginx:1.26.0
9 | volumeMounts:
10 | - name: storage
11 | mountPath: /some/mount/path
12 | volumes:
13 | - name: storage
14 | persistentVolumeClaim:
15 | claimName: dynamic-pv-civo
16 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/PersistentVolume/civo/StatefulSet.individual-pvcs-civo.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: StatefulSet
3 | metadata:
4 | name: individual-pvcs-civo
5 | spec:
6 | serviceName: "nginx"
7 | replicas: 2
8 | selector:
9 | matchLabels:
10 | app: nginx-sts-civo
11 | template:
12 | metadata:
13 | labels:
14 | app: nginx-sts-civo
15 | spec:
16 | containers:
17 | - name: nginx
18 | image: nginx:1.26.0
19 | ports:
20 | - containerPort: 80
21 | volumeMounts:
22 | - name: data
23 | mountPath: /some/mount/path
24 | volumeClaimTemplates:
25 | - metadata:
26 | name: data
27 | spec:
28 | accessModes: ["ReadWriteOnce"]
29 | resources:
30 | requests:
31 | storage: 1Gi
32 | storageClassName: civo-volume
33 | ---
34 | apiVersion: v1
35 | kind: Service
36 | metadata:
37 | name: individual-pvcss
38 | spec:
39 | clusterIP: None
40 | selector:
41 | app: nginx-sts-civo
42 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/PersistentVolume/civo/StorageClass.civo-volume.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: storage.k8s.io/v1
2 | kind: StorageClass
3 | metadata:
4 | name: civo-volume
5 | annotations:
6 | storageclass.kubernetes.io/is-default-class: "true"
7 | allowVolumeExpansion: true
8 | provisioner: csi.civo.com
9 | reclaimPolicy: Delete
10 | volumeBindingMode: WaitForFirstConsumer
11 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/PersistentVolume/gke/PersistentVolumeClaim.dynamic-pv-gke.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: PersistentVolumeClaim
3 | metadata:
4 | name: dynamic-pv-civo
5 | spec:
6 | accessModes:
7 | - ReadWriteOnce
8 | resources:
9 | requests:
10 | storage: 1Gi
11 | storageClassName: standard-rwo
12 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/PersistentVolume/gke/Pod.dynamic-pv-gke.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: dynamic-pv-gke
5 | spec:
6 | containers:
7 | - name: nginx
8 | image: nginx:1.26.0
9 | volumeMounts:
10 | - name: storage
11 | mountPath: /some/mount/path
12 | volumes:
13 | - name: storage
14 | persistentVolumeClaim:
15 | claimName: dynamic-pv-civo
16 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/PersistentVolume/gke/StatefulSet.individual-pvcs-gke.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: StatefulSet
3 | metadata:
4 | name: individual-pvcs-gke
5 | spec:
6 | serviceName: "nginx"
7 | replicas: 2
8 | selector:
9 | matchLabels:
10 | app: nginx-sts-gke
11 | template:
12 | metadata:
13 | labels:
14 | app: nginx-sts-gke
15 | spec:
16 | containers:
17 | - name: nginx
18 | image: nginx:1.26.0
19 | ports:
20 | - containerPort: 80
21 | volumeMounts:
22 | - name: data
23 | mountPath: /some/mount/path
24 | volumeClaimTemplates:
25 | - metadata:
26 | name: data
27 | spec:
28 | accessModes: ["ReadWriteOnce"]
29 | resources:
30 | requests:
31 | storage: 1Gi
32 | storageClassName: standard-rwo
33 | ---
34 | apiVersion: v1
35 | kind: Service
36 | metadata:
37 | name: individual-pvcss
38 | spec:
39 | clusterIP: None
40 | selector:
41 | app: nginx-sts-gke
42 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/PersistentVolume/gke/StorageClass.standard-rwo.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: storage.k8s.io/v1
2 | kind: StorageClass
3 | metadata:
4 | name: standard-rwo
5 | allowVolumeExpansion: true
6 | parameters:
7 | type: pd-balanced
8 | provisioner: pd.csi.storage.gke.io
9 | reclaimPolicy: Delete
10 | volumeBindingMode: WaitForFirstConsumer
11 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/PersistentVolume/kind/Deployment.shared-pvc-kind.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: shared-pvc-kind
5 | spec:
6 | # Both pods can only run simultaneously on the same node because
7 | # PVC has accessModes: [ReadWriteOnce]. Would be better to demo this
8 | # on multi-node cluster
9 | replicas: 2
10 | selector:
11 | matchLabels:
12 | app: nginx
13 | template:
14 | metadata:
15 | labels:
16 | app: nginx
17 | spec:
18 | containers:
19 | - name: nginx
20 | image: nginx:1.26.0
21 | volumeMounts:
22 | - name: data
23 | mountPath: /some/mount/path
24 | volumes:
25 | - name: data
26 | persistentVolumeClaim:
27 | claimName: dynamic-pv-kind
28 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/PersistentVolume/kind/PersistentVolume.manual-kind.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: PersistentVolume
3 | metadata:
4 | name: manual-kind-worker
5 | labels:
6 | name: manual-kind
7 | spec:
8 | accessModes:
9 | - ReadWriteOnce
10 | capacity:
11 | storage: 100Mi
12 | storageClassName: standard
13 | local:
14 | path: /some/path/in/container # Replace with the path to your local storage
15 | nodeAffinity:
16 | required:
17 | nodeSelectorTerms:
18 | - matchExpressions:
19 | - key: kubernetes.io/hostname
20 | operator: In
21 | values:
22 | - kind-worker
23 | ---
24 | apiVersion: v1
25 | kind: PersistentVolume
26 | metadata:
27 | name: manual-kind-worker2
28 | labels:
29 | name: manual-kind
30 | spec:
31 | accessModes:
32 | - ReadWriteOnce
33 | capacity:
34 | storage: 100Mi
35 | storageClassName: standard
36 | local:
37 | path: /some/path/in/container # Replace with the path to your local storage
38 | nodeAffinity:
39 | required:
40 | nodeSelectorTerms:
41 | - matchExpressions:
42 | - key: kubernetes.io/hostname
43 | operator: In
44 | values:
45 | - kind-worker2
46 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/PersistentVolume/kind/PersistentVolumeClaim.dynamic-pv-kind.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: PersistentVolumeClaim
3 | metadata:
4 | name: dynamic-pv-kind
5 | spec:
6 | accessModes:
7 | - ReadWriteOnce
8 | resources:
9 | requests:
10 | storage: 100Mi
11 | storageClassName: standard
12 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/PersistentVolume/kind/PersistentVolumeClaim.manual-pv-kind.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: PersistentVolumeClaim
3 | metadata:
4 | name: manual-pv-kind
5 | spec:
6 | accessModes:
7 | - ReadWriteOnce
8 | resources:
9 | requests:
10 | storage: 100Mi
11 | selector:
12 | matchLabels:
13 | name: manual-kind
14 | storageClassName: standard
15 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/PersistentVolume/kind/Pod.manual-pv-and-pvc-kind.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: manual-pv-and-pvc
5 | spec:
6 | containers:
7 | - name: nginx
8 | image: nginx:1.26.0
9 | volumeMounts:
10 | - name: storage
11 | mountPath: /some/mount/path
12 | volumes:
13 | - name: storage
14 | persistentVolumeClaim:
15 | claimName: manual-pv-kind
16 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/PersistentVolume/kind/StatefulSet.individual-pvcs-kind.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: StatefulSet
3 | metadata:
4 | name: individual-pvcs-kind
5 | spec:
6 | serviceName: "individual-pvcss"
7 | replicas: 2
8 | selector:
9 | matchLabels:
10 | app: nginx-sts-kind
11 | template:
12 | metadata:
13 | labels:
14 | app: nginx-sts-kind
15 | spec:
16 | containers:
17 | - name: nginx
18 | image: nginx:1.26.0
19 | ports:
20 | - containerPort: 80
21 | volumeMounts:
22 | - name: data
23 | mountPath: /some/mount/path
24 | volumeClaimTemplates:
25 | - metadata:
26 | name: data
27 | spec:
28 | accessModes: ["ReadWriteOnce"]
29 | resources:
30 | requests:
31 | storage: 50Mi
32 | storageClassName: "standard"
33 | ---
34 | apiVersion: v1
35 | kind: Service
36 | metadata:
37 | name: individual-pvcss
38 | spec:
39 | clusterIP: None
40 | selector:
41 | app: nginx-sts-kind
42 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/PersistentVolume/kind/StorageClass.standard.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: storage.k8s.io/v1
2 | kind: StorageClass
3 | metadata:
4 | name: standard
5 | annotations:
6 | storageclass.kubernetes.io/is-default-class: "true"
7 | provisioner: rancher.io/local-path
8 | reclaimPolicy: Delete
9 | volumeBindingMode: WaitForFirstConsumer
10 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Pod/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 04--pod
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Pod/Pod.nginx-better.yaml:
--------------------------------------------------------------------------------
1 | # Based on https://github.com/BretFisher/podspec
2 | apiVersion: v1
3 | kind: Pod
4 | metadata:
5 | name: nginx-better
6 | namespace: 04--pod
7 | spec:
8 | containers:
9 | - name: nginx
10 | image: cgr.dev/chainguard/nginx:latest
11 | ports:
12 | - containerPort: 8080
13 | protocol: TCP
14 | readinessProbe:
15 | httpGet:
16 | path: /
17 | port: 8080
18 | resources:
19 | limits:
20 | memory: "50Mi"
21 | requests:
22 | memory: "25Mi"
23 | cpu: "250m"
24 | securityContext:
25 | allowPrivilegeEscalation: false
26 | privileged: false
27 | securityContext:
28 | seccompProfile:
29 | type: RuntimeDefault
30 | runAsUser: 1001
31 | runAsGroup: 1001
32 | runAsNonRoot: true
33 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Pod/Pod.nginx-minimal.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: nginx-minimal
5 | spec:
6 | containers:
7 | - name: nginx
8 | image: nginx:1.26.0
9 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/RBAC/ClusterRole.pod-reader.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | name: pod-reader
5 | rules:
6 | - apiGroups: [""]
7 | resources: ["pods"]
8 | verbs: ["get", "list", "watch"]
9 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/RBAC/ClusterRoleBinding.pod-reader.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRoleBinding
3 | metadata:
4 | name: pod-reader
5 | roleRef:
6 | apiGroup: rbac.authorization.k8s.io
7 | kind: ClusterRole
8 | name: pod-reader
9 | subjects:
10 | - kind: ServiceAccount
11 | name: cluster-pod-reader
12 | namespace: 04--rbac
13 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/RBAC/Job.cluster-pod-reader.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: batch/v1
2 | kind: Job
3 | metadata:
4 | name: cluster-pod-permissions
5 | spec:
6 | template:
7 | spec:
8 | automountServiceAccountToken: true
9 | containers:
10 | - name: kubectl
11 | image: cgr.dev/chainguard/kubectl
12 | args: ["get", "pods", "-A"]
13 | serviceAccountName: cluster-pod-reader
14 | restartPolicy: Never
15 | backoffLimit: 1
16 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/RBAC/Job.namespaced-pod-reader-fail.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: batch/v1
2 | kind: Job
3 | metadata:
4 | name: namespaced-pod-permissions-fail
5 | spec:
6 | template:
7 | spec:
8 | automountServiceAccountToken: true
9 | containers:
10 | - name: kubectl
11 | image: cgr.dev/chainguard/kubectl
12 | args: ["get", "pods", "-A"]
13 | serviceAccountName: namespaced-pod-reader
14 | restartPolicy: Never
15 | backoffLimit: 1
16 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/RBAC/Job.namespaced-pod-reader-succeed.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: batch/v1
2 | kind: Job
3 | metadata:
4 | name: namespaced-pod-permissions-succeed
5 | spec:
6 | template:
7 | spec:
8 | automountServiceAccountToken: true
9 | containers:
10 | - name: kubectl
11 | image: cgr.dev/chainguard/kubectl
12 | args: ["get", "pods", "-n", "04--rbac"]
13 | serviceAccountName: namespaced-pod-reader
14 | restartPolicy: Never
15 | backoffLimit: 1
16 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/RBAC/Job.no-permissions.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: batch/v1
2 | kind: Job
3 | metadata:
4 | name: no-permissions
5 | spec:
6 | template:
7 | spec:
8 | containers:
9 | - name: kubectl
10 | image: cgr.dev/chainguard/kubectl
11 | args: ["get", "pods", "-A"]
12 | restartPolicy: Never
13 | backoffLimit: 1
14 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/RBAC/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 04--rbac
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/RBAC/Role.pod-reader.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: Role
3 | metadata:
4 | name: pod-reader
5 | rules:
6 | - apiGroups: [""]
7 | resources: ["pods"]
8 | verbs: ["get", "list", "watch"]
9 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/RBAC/RoleBinding.pod-reader.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: RoleBinding
3 | metadata:
4 | name: pod-reader
5 | roleRef:
6 | apiGroup: rbac.authorization.k8s.io
7 | kind: Role
8 | name: pod-reader
9 | subjects:
10 | - kind: ServiceAccount
11 | name: namespaced-pod-reader
12 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/RBAC/ServiceAccount.cluster-pod-permissions.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ServiceAccount
3 | metadata:
4 | name: cluster-pod-reader
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/RBAC/ServiceAccount.namespaced-pod-permissions.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ServiceAccount
3 | metadata:
4 | name: namespaced-pod-reader
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/ReplicaSet/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 04--replicaset
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/ReplicaSet/ReplicaSet.nginx-better.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: ReplicaSet
3 | metadata:
4 | name: nginx-better
5 | namespace: 04--replicaset
6 | labels:
7 | app: nginx-better
8 | spec:
9 | replicas: 3
10 | selector:
11 | matchLabels:
12 | app: nginx-better
13 | template:
14 | metadata:
15 | labels:
16 | app: nginx-better
17 | spec:
18 | containers:
19 | - name: nginx
20 | image: cgr.dev/chainguard/nginx:latest
21 | ports:
22 | - containerPort: 8080
23 | protocol: TCP
24 | readinessProbe:
25 | httpGet:
26 | path: /
27 | port: 8080
28 | resources:
29 | limits:
30 | memory: "50Mi"
31 | requests:
32 | memory: "50Mi"
33 | cpu: "250m"
34 | securityContext:
35 | allowPrivilegeEscalation: false
36 | privileged: false
37 | securityContext:
38 | seccompProfile:
39 | type: RuntimeDefault
40 | runAsUser: 1001
41 | runAsGroup: 1001
42 | runAsNonRoot: true
43 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/ReplicaSet/ReplicaSet.nginx-minimal.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: ReplicaSet
3 | metadata:
4 | name: nginx-minimal
5 | spec:
6 | replicas: 3
7 | selector:
8 | matchLabels:
9 | app: nginx-minimal
10 | template:
11 | metadata:
12 | labels:
13 | app: nginx-minimal
14 | spec:
15 | containers:
16 | - name: nginx
17 | image: nginx:1.26.0
18 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/ReplicaSet/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | env:
4 | BORDER: double
5 | BORDER_FOREGROUND: "212"
6 | PADDING: "1 1"
7 | MARGIN: "1 1"
8 | NAMESPACE: 04--replicaset
9 |
10 | tasks:
11 | 01-create-namespace:
12 | desc: "Create a namespace for these examples and set as default"
13 | cmds:
14 | - kubectl apply -f Namespace.yaml
15 | - kubens ${NAMESPACE}
16 |
17 | 02-minimal-apply:
18 | desc: "Apply the minimal ReplicaSet configuration"
19 | cmds:
20 | - kubectl apply -f ReplicaSet.nginx-minimal.yaml
21 |
22 | 03-better-apply:
23 | desc: "Apply the improved ReplicaSet configuration"
24 | cmds:
25 | - kubectl apply -f ReplicaSet.nginx-better.yaml
26 |
27 | 04-delete-pods:
28 | desc: "Delete all the pods! (they will be automatically recreated)"
29 | cmds:
30 | - kubectl delete pods --all
31 | - watch "kubectl get pods"
32 |
33 | 05-delete-namespace:
34 | desc: "Delete the namespace to clean up"
35 | cmds:
36 | - cmd: gum style "🚨 Deleting the namespace recursively deletes the resources inside of it! 🚨 "
37 | silent: true
38 | - kubectl delete -f Namespace.yaml
39 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Secret/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 04--secret
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Secret/Pod.secret-example.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: secret-example
5 | spec:
6 | containers:
7 | - name: nginx
8 | image: nginx:1.26.0
9 | volumeMounts:
10 | - name: secret-base64-data
11 | mountPath: /etc/config
12 | env:
13 | - name: ENV_VAR_FROM_SECRET
14 | valueFrom:
15 | secretKeyRef:
16 | name: base64-data
17 | key: foo
18 | imagePullSecrets:
19 | # Not necessary since example uses a public image, but including to show how
20 | # you would use a registry credential secret to access a private image
21 | - name: dockerconfigjson
22 | volumes:
23 | - name: secret-base64-data
24 | secret:
25 | secretName: base64-data
26 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Secret/Secret.base64-data.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Secret
3 | metadata:
4 | name: base64-data
5 | type: Opaque
6 | data:
7 | foo: YmFy
8 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Secret/Secret.dockerconfigjson.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Secret
3 | metadata:
4 | name: dockerconfigjson
5 | type: kubernetes.io/dockerconfigjson
6 | data:
7 | .dockerconfigjson: |
8 | eyJhdXRocyI6eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MSI6eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwicGFzc3dvcmQiOiJwYXNzd29yZCIsImVtYWlsIjoiZm9vQGJhci5jb20iLCJhdXRoIjoiZFhObGNtNWhiV1U2Y0dGemMzZHZjbVE9In19fQ==
9 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Secret/Secret.string-data.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Secret
3 | metadata:
4 | name: string-data
5 | type: Opaque
6 | stringData:
7 | foo: bar
8 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Service/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: nginx-minimal
5 | labels:
6 | foo: deployment-label
7 | annotations:
8 | bar: deployment-annotation
9 | spec:
10 | replicas: 3
11 | selector:
12 | matchLabels:
13 | baz: pod-label
14 | template:
15 | metadata:
16 | labels:
17 | baz: pod-label
18 | annotations:
19 | bing: pod-annotation
20 | spec:
21 | containers:
22 | - name: nginx
23 | image: nginx:1.26.0
24 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Service/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 04--service
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Service/Service.nginx-clusterip.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: nginx-clusterip
5 | labels:
6 | foo: service-label
7 | annotations:
8 | bar: service-annotation
9 | spec:
10 | type: ClusterIP # This is the default value
11 | selector:
12 | baz: pod-label
13 | ports:
14 | - protocol: TCP
15 | port: 80 # Port the service is listening on
16 | targetPort: 80 # Port the container is listening on (if unset, defaults to equal port value)
17 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Service/Service.nginx-loadbalancer.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: nginx-loadbalancer
5 | spec:
6 | type: LoadBalancer # Will only work if cluster is configured to provision one from an external source (e.g. cloud provider)
7 | selector:
8 | baz: pod-label
9 | ports:
10 | - protocol: TCP
11 | port: 80 # Port the service is listening on
12 | targetPort: 80 # Port the container is listening on (if unset, defaults to equal port value)
13 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Service/Service.nginx-nodeport.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: nginx-nodeport
5 | spec:
6 | type: NodePort
7 | selector:
8 | baz: pod-label
9 | ports:
10 | - protocol: TCP
11 | port: 80 # Port the service is listening on
12 | targetPort: 80 # Port the container is listening on (if unset, defaults to equal port value)
13 | # nodePort: 30XXX (if unset, kubernetes will assign a port within 30000-32767)
14 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/Service/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | env:
4 | BORDER: double
5 | BORDER_FOREGROUND: "212"
6 | PADDING: "1 1"
7 | MARGIN: "1 1"
8 | NAMESPACE: 04--service
9 |
10 | tasks:
11 | 01-create-namespace:
12 | desc: "Create a namespace for these examples and set as default"
13 | cmds:
14 | - kubectl apply -f Namespace.yaml
15 | - kubens ${NAMESPACE}
16 |
17 | 02-apply-deployment:
18 | desc: "Apply the Deployment configuration"
19 | cmds:
20 | - kubectl apply -f Deployment.yaml
21 |
22 | 03-apply-clusterip-service:
23 | desc: "Apply the ClusterIP Service"
24 | cmds:
25 | - kubectl apply -f Service.nginx-clusterip.yaml
26 |
27 | 04-apply-nodeport-service:
28 | desc: "Apply the NodePort Service"
29 | cmds:
30 | - kubectl apply -f Service.nginx-nodeport.yaml
31 | - cmd: gum style "💡 Add a firewall rule to allow inbound traffic for nodeport port!"
32 | silent: true
33 |
34 | 05-apply-loadbalancer-service:
35 | desc: "Apply the LoadBalancer Service"
36 | cmds:
37 | - kubectl apply -f Service.nginx-loadbalancer.yaml
38 |
39 | 06-delete-namespace:
40 | desc: "Delete the namespace to clean up"
41 | cmds:
42 | - cmd: gum style "🚨 Deleting the namespace recursively deletes the resources inside of it! 🚨 "
43 | silent: true
44 | - kubectl delete -f Namespace.yaml
45 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/StatefulSet/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 04--statefulset
5 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/StatefulSet/Service.nginx.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: nginx # singular since it points to a single cluster IP
5 | spec:
6 | type: ClusterIP
7 | selector:
8 | app: nginx
9 | ports:
10 | - protocol: TCP
11 | port: 80
12 | targetPort: 80
13 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/StatefulSet/Service.nginxs.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: nginxs # Plural because it sets up DNS for each replica in the StatefulSet (e.g. nginx-0.nginxs.default.svc.cluster.local)
5 | spec:
6 | type: ClusterIP
7 | clusterIP: None # This makes it a "headless" service
8 | selector:
9 | app: nginx
10 | ports:
11 | - protocol: TCP
12 | port: 80
13 | targetPort: 80
14 |
--------------------------------------------------------------------------------
/04-built-in-resource-types/StatefulSet/StatefulSet.nginx-minimal.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: StatefulSet
3 | metadata:
4 | name: nginx-minimal
5 | spec:
6 | serviceName: nginxs
7 | replicas: 3
8 | selector:
9 | matchLabels:
10 | app: nginx
11 | template:
12 | metadata:
13 | labels:
14 | app: nginx
15 | spec:
16 | containers:
17 | - name: nginx
18 | image: nginx:1.26.0
19 |
--------------------------------------------------------------------------------
/05-helm/charts/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 05--charts
5 |
--------------------------------------------------------------------------------
/05-helm/charts/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | env:
4 | BORDER: double
5 | BORDER_FOREGROUND: "212"
6 | PADDING: "1 1"
7 | MARGIN: "1 1"
8 | NAMESPACE: 05--charts
9 |
10 | tasks:
11 | 01-create-namespace:
12 | desc: "Create a namespace for these examples and set as default"
13 | cmds:
14 | - kubectl apply -f Namespace.yaml
15 | - kubens ${NAMESPACE}
16 |
17 | 02-install-default-values:
18 | cmds:
19 | - helm upgrade --install minimal ./minimal
20 | desc: Install with default values
21 |
22 | 03-install-alt-values:
23 | cmds:
24 | - helm upgrade --install minimal ./minimal --values=./minimal/values-alt.yaml
25 | desc: Install with alternative values
26 |
27 | 04-delete-namespace:
28 | desc: "Delete the namespace to clean up"
29 | cmds:
30 | - cmd: gum style "🚨 Deleting the namespace recursively deletes the resources inside of it! 🚨 "
31 | silent: true
32 | - kubectl delete -f Namespace.yaml
33 |
--------------------------------------------------------------------------------
/05-helm/charts/helm-create-unmodified/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *.orig
18 | *~
19 | # Various IDEs
20 | .project
21 | .idea/
22 | *.tmproj
23 | .vscode/
24 |
--------------------------------------------------------------------------------
/05-helm/charts/helm-create-unmodified/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | name: helm-create-unmodified
3 | description: A Helm chart for Kubernetes
4 |
5 | # A chart can be either an 'application' or a 'library' chart.
6 | #
7 | # Application charts are a collection of templates that can be packaged into versioned archives
8 | # to be deployed.
9 | #
10 | # Library charts provide useful utilities or functions for the chart developer. They're included as
11 | # a dependency of application charts to inject those utilities and functions into the rendering
12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed.
13 | type: application
14 |
15 | # This is the chart version. This version number should be incremented each time you make changes
16 | # to the chart and its templates, including the app version.
17 | # Versions are expected to follow Semantic Versioning (https://semver.org/)
18 | version: 0.1.0
19 |
20 | # This is the version number of the application being deployed. This version number should be
21 | # incremented each time you make changes to the application. Versions are not expected to
22 | # follow Semantic Versioning. They should reflect the version the application is using.
23 | # It is recommended to use it with quotes.
24 | appVersion: "1.16.0"
25 |
--------------------------------------------------------------------------------
/05-helm/charts/helm-create-unmodified/templates/hpa.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.autoscaling.enabled }}
2 | apiVersion: autoscaling/v2beta1
3 | kind: HorizontalPodAutoscaler
4 | metadata:
5 | name: {{ include "helm-create-unmodified.fullname" . }}
6 | labels:
7 | {{- include "helm-create-unmodified.labels" . | nindent 4 }}
8 | spec:
9 | scaleTargetRef:
10 | apiVersion: apps/v1
11 | kind: Deployment
12 | name: {{ include "helm-create-unmodified.fullname" . }}
13 | minReplicas: {{ .Values.autoscaling.minReplicas }}
14 | maxReplicas: {{ .Values.autoscaling.maxReplicas }}
15 | metrics:
16 | {{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
17 | - type: Resource
18 | resource:
19 | name: cpu
20 | targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
21 | {{- end }}
22 | {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
23 | - type: Resource
24 | resource:
25 | name: memory
26 | targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
27 | {{- end }}
28 | {{- end }}
29 |
--------------------------------------------------------------------------------
/05-helm/charts/helm-create-unmodified/templates/service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: {{ include "helm-create-unmodified.fullname" . }}
5 | labels:
6 | {{- include "helm-create-unmodified.labels" . | nindent 4 }}
7 | spec:
8 | type: {{ .Values.service.type }}
9 | ports:
10 | - port: {{ .Values.service.port }}
11 | targetPort: http
12 | protocol: TCP
13 | name: http
14 | selector:
15 | {{- include "helm-create-unmodified.selectorLabels" . | nindent 4 }}
16 |
--------------------------------------------------------------------------------
/05-helm/charts/helm-create-unmodified/templates/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.serviceAccount.create -}}
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: {{ include "helm-create-unmodified.serviceAccountName" . }}
6 | labels:
7 | {{- include "helm-create-unmodified.labels" . | nindent 4 }}
8 | {{- with .Values.serviceAccount.annotations }}
9 | annotations:
10 | {{- toYaml . | nindent 4 }}
11 | {{- end }}
12 | {{- end }}
13 |
--------------------------------------------------------------------------------
/05-helm/charts/helm-create-unmodified/templates/tests/test-connection.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: "{{ include "helm-create-unmodified.fullname" . }}-test-connection"
5 | labels:
6 | {{- include "helm-create-unmodified.labels" . | nindent 4 }}
7 | annotations:
8 | "helm.sh/hook": test
9 | spec:
10 | containers:
11 | - name: wget
12 | image: busybox
13 | command: ['wget']
14 | args: ['{{ include "helm-create-unmodified.fullname" . }}:{{ .Values.service.port }}']
15 | restartPolicy: Never
16 |
--------------------------------------------------------------------------------
/05-helm/charts/minimal/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *.orig
18 | *~
19 | # Various IDEs
20 | .project
21 | .idea/
22 | *.tmproj
23 | .vscode/
24 |
--------------------------------------------------------------------------------
/05-helm/charts/minimal/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | name: minimal
3 | description: A tiny helm chart for educational purposes
4 | type: application
5 | version: 0.1.0
6 | appVersion: 1.26.0
7 |
--------------------------------------------------------------------------------
/05-helm/charts/minimal/templates/NOTES.txt:
--------------------------------------------------------------------------------
1 | Hi 👋 -- you just deployed {{ template "envShort" . }}
--------------------------------------------------------------------------------
/05-helm/charts/minimal/templates/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{- define "envShort" -}}
2 | {{- if eq .Values.environment "production" -}}
3 | prod
4 | {{- else -}}
5 | non-prod
6 | {{- end -}}
7 | {{- end -}}
8 |
--------------------------------------------------------------------------------
/05-helm/charts/minimal/templates/configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: helm-{{ .Release.Name }}-configmap
5 | data:
6 | appVersion: {{ .Chart.AppVersion }}
7 | environment: {{ .Values.environment | quote }}
8 | envShort: {{ template "envShort" . }}
9 | {{- range .Values.configData }}
10 | {{- if .enabled }}
11 | {{ .key }}: {{ .value | quote }}
12 | {{- end }}
13 | {{- end }}
--------------------------------------------------------------------------------
/05-helm/charts/minimal/values-alt.yaml:
--------------------------------------------------------------------------------
1 | environment: staging
2 |
3 | configData:
4 | - key: conditionalKey
5 | value: "this wont be included"
6 | enabled: false
7 |
--------------------------------------------------------------------------------
/05-helm/charts/minimal/values.yaml:
--------------------------------------------------------------------------------
1 | environment: production
2 |
3 | configData:
4 | - key: conditionalKey
5 | value: "this will be included"
6 | enabled: true
7 |
--------------------------------------------------------------------------------
/05-helm/postgresql/.gitignore:
--------------------------------------------------------------------------------
1 | **.tgz
2 |
3 | postgresql/
--------------------------------------------------------------------------------
/05-helm/postgresql/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 05--postgresql
5 |
--------------------------------------------------------------------------------
/05-helm/postgresql/values.yaml:
--------------------------------------------------------------------------------
1 | commonAnnotations:
2 | foo: bar
3 |
--------------------------------------------------------------------------------
/05-helm/readme-assets/helm-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sidpalas/devops-directive-kubernetes-course/18d4bcfac1818609dfc2e9e82d0affd77e0e7c47/05-helm/readme-assets/helm-diagram.png
--------------------------------------------------------------------------------
/06-demo-application/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | includes:
4 | api-golang:
5 | taskfile: ./api-golang/Taskfile.yaml
6 | dir: ./api-golang
7 | api-node:
8 | taskfile: ./api-node/Taskfile.yaml
9 | dir: ./api-node
10 | client-react:
11 | taskfile: ./client-react/Taskfile.yaml
12 | dir: ./client-react
13 | load-generator-python:
14 | taskfile: ./load-generator-python/Taskfile.yaml
15 | dir: ./load-generator-python
16 | postgresql:
17 | taskfile: ./postgresql/Taskfile.yaml
18 | dir: ./postgresql
19 |
20 | vars:
21 | DATABASE_URL: "postgres://postgres:foobarbaz@localhost:5432/postgres"
22 |
23 | tasks:
24 | bootstrap-buildx-builder:
25 | desc: Bootstrap the builder
26 | cmds:
27 | - docker buildx create --name mybuilder --driver docker-container --driver-opt network=host --use
28 | - docker buildx inspect mybuilder --bootstrap
29 | - docker buildx use mybuilder
30 |
31 | run-local-registry:
32 | desc: Run a local registry
33 | cmds:
34 | - docker run -d -p 5000:5000 registry:2.8
35 |
--------------------------------------------------------------------------------
/06-demo-application/api-golang/.air.toml:
--------------------------------------------------------------------------------
1 | root = "."
2 | testdata_dir = "testdata"
3 | tmp_dir = "tmp"
4 |
5 | [build]
6 | args_bin = []
7 | bin = "./tmp/main"
8 | cmd = "go build -o ./tmp/main ."
9 | delay = 0
10 | exclude_dir = ["assets", "tmp", "vendor", "testdata"]
11 | exclude_file = []
12 | exclude_regex = ["_test.go"]
13 | exclude_unchanged = false
14 | follow_symlink = false
15 | full_bin = ""
16 | include_dir = []
17 | include_ext = ["go", "tpl", "tmpl", "html"]
18 | include_file = []
19 | kill_delay = "0s"
20 | log = "build-errors.log"
21 | rerun = false
22 | rerun_delay = 500
23 | send_interrupt = false
24 | stop_on_error = false
25 |
26 | [color]
27 | app = ""
28 | build = "yellow"
29 | main = "magenta"
30 | runner = "green"
31 | watcher = "cyan"
32 |
33 | [log]
34 | main_only = false
35 | time = false
36 |
37 | [misc]
38 | clean_on_exit = false
39 |
40 | [screen]
41 | clear_on_rebuild = false
42 | keep_scroll = true
43 |
--------------------------------------------------------------------------------
/06-demo-application/api-golang/.dockerignore:
--------------------------------------------------------------------------------
1 | Makefile
2 | README.md
3 | Dockerfile*
--------------------------------------------------------------------------------
/06-demo-application/api-golang/README.md:
--------------------------------------------------------------------------------
1 | ```bash
2 | mkdir go-workspace
3 | export GOPATH=$PWD/go-workspace
4 | go mod download
5 | go run main.go
6 | ```
--------------------------------------------------------------------------------
/06-demo-application/api-golang/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | vars:
4 | DATABASE_URL: "postgres://postgres:foobarbaz@localhost:5432/postgres"
5 | IMAGE_REPO: sidpalas/devops-directive-docker-course-api-golang
6 | IMAGE_TAG: foobarbaz
7 |
8 | tasks:
9 | install:
10 | desc: "download dependencies"
11 | cmds:
12 | - go mod tidy
13 |
14 | run:
15 | desc: "download dependencies"
16 | cmds:
17 | - echo $PWD
18 | - ls
19 | - DATABASE_URL={{.DATABASE_URL}} go run main.go
20 |
21 | build-container-image:
22 | desc: Build container image
23 | cmds:
24 | - |
25 | KO_DOCKER_REPO='{{.IMAGE_REPO}}' \
26 | ko build \
27 | --bare \
28 | --tags={{.IMAGE_TAG}} \
29 | --platform=all
30 |
31 | build-container-image-multi-arch:
32 | cmds:
33 | - task: build-container-image
34 |
--------------------------------------------------------------------------------
/06-demo-application/api-golang/Tiltfile:
--------------------------------------------------------------------------------
1 | load('ext://ko', 'ko_build')
2 | ko_build(
3 | 'sidpalas/devops-directive-docker-course-api-golang',
4 | './',
5 | deps=['.']
6 | )
7 | k8s_yaml('../../07-deploying-demo-application/api-golang/Deployment.yaml')
8 | k8s_resource('api-golang', port_forwards=8000)
--------------------------------------------------------------------------------
/06-demo-application/api-golang/database/db.go:
--------------------------------------------------------------------------------
1 | package database
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "os"
7 | "time"
8 |
9 | "github.com/gin-gonic/gin"
10 | "github.com/jackc/pgx/v5/pgxpool"
11 | )
12 |
13 | var pool *pgxpool.Pool
14 |
15 | // InitDB initialize the database pool and returns error
16 | func InitDB(connString string) error {
17 | var err error
18 | pool, err = pgxpool.New(context.Background(), connString)
19 | if err != nil {
20 | return err
21 | }
22 | return nil
23 | }
24 |
25 | func InsertView(ctx *gin.Context) {
26 | _, err := pool.Exec(ctx, "INSERT INTO request (api_name) VALUES ('go');")
27 | if err != nil {
28 | fmt.Fprintf(os.Stderr, "Query failed: %v\n", err)
29 | os.Exit(1)
30 | }
31 | }
32 |
33 | func GetTimeAndRequestCount(ctx *gin.Context) (time.Time, int) {
34 | var tm time.Time
35 | var reqCount int
36 | err := pool.QueryRow(ctx, "SELECT NOW() AS current_time, COUNT(*) AS request_count FROM public.request WHERE api_name = 'go';").Scan(&tm, &reqCount)
37 | if err != nil {
38 | fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
39 | os.Exit(1)
40 | }
41 | return tm, reqCount
42 | }
43 |
--------------------------------------------------------------------------------
/06-demo-application/api-golang/healthcheck/healthcheck.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | "os"
8 | "time"
9 | )
10 |
11 | func main() {
12 |
13 | port, exists := os.LookupEnv("PORT")
14 | if !exists {
15 | port = "8080"
16 | }
17 |
18 | client := http.Client{
19 | Timeout: 2 * time.Second,
20 | }
21 |
22 | resp, err := client.Get("http://localhost:" + port + "/ping")
23 | if err != nil {
24 | log.Fatal(err)
25 | }
26 |
27 | // Print the HTTP Status Code and Status Name
28 | fmt.Println("HTTP Response Status:", resp.StatusCode, http.StatusText(resp.StatusCode))
29 |
30 | if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
31 | fmt.Println("HTTP Status is in the 2xx range")
32 | } else {
33 | fmt.Println("Argh! Broken")
34 | os.Exit(1)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/06-demo-application/api-golang/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "io/ioutil"
5 | "log"
6 | "os"
7 | "time"
8 |
9 | "github.com/gin-gonic/gin"
10 |
11 | "api-golang/database"
12 | )
13 |
14 | func init() {
15 | databaseUrl := os.Getenv("DATABASE_URL")
16 | if databaseUrl == "" {
17 | content, err := ioutil.ReadFile(os.Getenv("DATABASE_URL_FILE"))
18 | if err != nil {
19 | log.Fatal(err)
20 | }
21 | databaseUrl = string(content)
22 | }
23 |
24 | errDB := database.InitDB(databaseUrl)
25 | if errDB != nil {
26 | log.Fatalf("⛔ Unable to connect to database: %v\n", errDB)
27 | } else {
28 | log.Println("DATABASE CONNECTED 🥇")
29 | }
30 |
31 | }
32 |
33 | func main() {
34 |
35 | r := gin.Default()
36 | var tm time.Time
37 | var reqCount int
38 |
39 | r.GET("/", func(c *gin.Context) {
40 | database.InsertView(c)
41 | tm, reqCount = database.GetTimeAndRequestCount(c)
42 | c.JSON(200, gin.H{
43 | "api": "go",
44 | "currentTime": tm,
45 | "requestCount": reqCount,
46 | })
47 | })
48 |
49 | r.GET("/ping", func(c *gin.Context) {
50 | _, _ = database.GetTimeAndRequestCount(c)
51 | c.JSON(200, "pong")
52 | })
53 |
54 | port := os.Getenv("PORT")
55 | if port == "" {
56 | // Defaulting to 8000 to deconflict with unprivileged nginx container
57 | port = "8000"
58 | }
59 |
60 | r.Run(":" + port) // listen and serve on 0.0.0.0:8000 (or "PORT" env var if set)}
61 | }
--------------------------------------------------------------------------------
/06-demo-application/api-golang/test/example_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import "testing"
4 |
5 | func TestOneEqualsOne(t *testing.T) {
6 | val := 1
7 | if val != 1 {
8 | t.Errorf("1 != %d; want 1", val)
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/06-demo-application/api-golang/tmp/build-errors.log:
--------------------------------------------------------------------------------
1 | exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2
--------------------------------------------------------------------------------
/06-demo-application/api-golang/tmp/main:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sidpalas/devops-directive-kubernetes-course/18d4bcfac1818609dfc2e9e82d0affd77e0e7c47/06-demo-application/api-golang/tmp/main
--------------------------------------------------------------------------------
/06-demo-application/api-node/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .npm
--------------------------------------------------------------------------------
/06-demo-application/api-node/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/06-demo-application/api-node/.package.json.un~:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sidpalas/devops-directive-kubernetes-course/18d4bcfac1818609dfc2e9e82d0affd77e0e7c47/06-demo-application/api-node/.package.json.un~
--------------------------------------------------------------------------------
/06-demo-application/api-node/Dockerfile:
--------------------------------------------------------------------------------
1 | # Pin specific version for stability
2 | # Use slim for reduced image size
3 | FROM node:20.14-bullseye-slim AS base
4 |
5 | # Set NODE_ENV
6 | ENV NODE_ENV production
7 |
8 | # Specify working directory other than /
9 | WORKDIR /usr/src/app
10 |
11 | # Copy only files required to install
12 | # dependencies (better layer caching)
13 | COPY package*.json ./
14 |
15 | # Install only production dependencies
16 | # Use cache mount to speed up install of existing dependencies
17 | RUN --mount=type=cache,target=/usr/src/app/.npm \
18 | npm set cache /usr/src/app/.npm && \
19 | npm ci --only=production
20 |
21 | # Use non-root user
22 | # Use --chown on COPY commands to set file permissions
23 | USER node
24 |
25 | # Copy the healthcheck script
26 | COPY --chown=node:node ./healthcheck/ .
27 |
28 | # Copy remaining source code AFTER installing dependencies.
29 | # Again, copy only the necessary files
30 | COPY --chown=node:node ./src/ .
31 |
32 | # Indicate expected port
33 | EXPOSE 3000
34 |
35 | CMD [ "node", "index.js" ]
--------------------------------------------------------------------------------
/06-demo-application/api-node/README.md:
--------------------------------------------------------------------------------
1 | ```bash
2 | nvm ls
3 | nvm use node 19.4
4 | npm install
5 | npm run dev
6 | ```
--------------------------------------------------------------------------------
/06-demo-application/api-node/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | vars:
4 | DATABASE_URL: "postgres://postgres:foobarbaz@localhost:5432/postgres"
5 | IMAGE_REPO: sidpalas/devops-directive-docker-course-api-node
6 | IMAGE_TAG: foobarbaz
7 |
8 | tasks:
9 | build-container-image:
10 | desc: Build container image
11 | cmds:
12 | - docker build -t {{.IMAGE_REPO}}{{.IMAGE_TAG}} .
13 |
14 | build-container-image-multi-arch:
15 | desc: Build multi-arch container image
16 | cmds:
17 | - |
18 | docker buildx build \
19 | --platform linux/amd64,linux/arm64 \
20 | -t {{.IMAGE_REPO}}:{{.IMAGE_TAG}} \
21 | --push \
22 | .
23 |
24 | install:
25 | desc: install dependencies
26 | cmds:
27 | - npm install
28 |
29 | run:
30 | desc: Start node api
31 | cmds:
32 | - DATABASE_URL={{.DATABASE_URL}} npm run dev
33 |
--------------------------------------------------------------------------------
/06-demo-application/api-node/Tiltfile:
--------------------------------------------------------------------------------
1 | docker_build(
2 | 'sidpalas/devops-directive-docker-course-api-node',
3 | './',
4 | )
5 | k8s_yaml('../../07-deploying-demo-application/api-node/Deployment.yaml')
6 | k8s_resource('api-node', port_forwards=3000)
--------------------------------------------------------------------------------
/06-demo-application/api-node/healthcheck/healthcheck.js:
--------------------------------------------------------------------------------
1 | var http = require('http');
2 |
3 | var options = {
4 | timeout: 2000,
5 | host: 'localhost',
6 | port: process.env.PORT || 3000,
7 | path: '/ping',
8 | };
9 |
10 | var request = http.request(options, (res) => {
11 | console.info('STATUS: ' + res.statusCode);
12 | process.exitCode = res.statusCode === 200 ? 0 : 1;
13 | process.exit();
14 | });
15 |
16 | request.on('error', function (err) {
17 | console.error('ERROR', err);
18 | process.exit(1);
19 | });
20 |
21 | request.end();
22 |
--------------------------------------------------------------------------------
/06-demo-application/api-node/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "api-node",
3 | "version": "1.0.0",
4 | "description": "simple api that connects to postgres",
5 | "main": "src/index.js",
6 | "scripts": {
7 | "dev": "nodemon src/index.js",
8 | "debug": "nodemon --inspect ./src/index.js",
9 | "debug-docker": "nodemon --inspect=0.0.0.0:9229 ./src/index.js",
10 | "test": "jest"
11 | },
12 | "author": "",
13 | "license": "ISC",
14 | "dependencies": {
15 | "express": "^4.18.2",
16 | "morgan": "^1.10.0",
17 | "pg": "^8.8.0"
18 | },
19 | "devDependencies": {
20 | "jest": "^29.4.1",
21 | "nodemon": "^2.0.20"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/06-demo-application/api-node/package.json~:
--------------------------------------------------------------------------------
1 | {
2 | "name": "api-node",
3 | "version": "1.0.0",
4 | "description": "simple api that connects to postgres",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "express": "^4.18.2"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/06-demo-application/api-node/src/index.js:
--------------------------------------------------------------------------------
1 | const { getDateTimeAndRequests, insertRequest } = require("./db");
2 |
3 | const express = require("express");
4 | const morgan = require("morgan");
5 |
6 | const app = express();
7 | const port = process.env.PORT || 3000;
8 |
9 | // setup the logger
10 | app.use(morgan("tiny"));
11 |
12 | app.get("/", async (req, res) => {
13 | await insertRequest();
14 | const response = await getDateTimeAndRequests();
15 | console.log = response;
16 | response.api = "node";
17 | res.send(response);
18 | });
19 |
20 | app.get("/ping", async (_, res) => {
21 | res.send("pong");
22 | });
23 |
24 | const server = app.listen(port, () => {
25 | console.log(`Example app listening on port ${port}`);
26 | });
27 |
28 | process.on("SIGTERM", () => {
29 | console.debug("SIGTERM signal received: closing HTTP server");
30 | server.close(() => {
31 | console.debug("HTTP server closed");
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/06-demo-application/api-node/test/example.test.js:
--------------------------------------------------------------------------------
1 | test('This is a test that always passes', () => {
2 | expect(true).toBe(true);
3 | });
4 |
--------------------------------------------------------------------------------
/06-demo-application/client-react/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .npm
--------------------------------------------------------------------------------
/06-demo-application/client-react/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/06-demo-application/client-react/Dockerfile:
--------------------------------------------------------------------------------
1 | # syntax=docker/dockerfile:1.5
2 |
3 | FROM node:20.14-bullseye-slim AS build
4 |
5 | # Specify working directory other than /
6 | WORKDIR /usr/src/app
7 |
8 | # Copy only files required to install
9 | # dependencies (better layer caching)
10 | COPY package*.json ./
11 |
12 | # Use cache mount to speed up install of existing dependencies
13 | RUN --mount=type=cache,target=/usr/src/app/.npm \
14 | npm set cache /usr/src/app/.npm && \
15 | npm install
16 |
17 | COPY . .
18 |
19 | RUN npm run build
20 |
21 | # Use separate stage for deployable image
22 | FROM nginxinc/nginx-unprivileged:1.23-alpine-perl
23 |
24 | # Use COPY --link to avoid breaking cache if we change the second stage base image
25 | COPY --link nginx.conf /etc/nginx/conf.d/default.conf
26 |
27 | COPY --link --from=build usr/src/app/dist/ /usr/share/nginx/html
28 |
29 | EXPOSE 8080
--------------------------------------------------------------------------------
/06-demo-application/client-react/README.md:
--------------------------------------------------------------------------------
1 | ```
2 | npm create vite@latest
3 | ```
4 |
5 | ```
6 | nvm ls
7 | nvm use node 19.4
8 | npm install
9 | npm run dev
10 | ```
11 |
--------------------------------------------------------------------------------
/06-demo-application/client-react/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | vars:
4 | IMAGE_REPO: sidpalas/devops-directive-docker-course-client-react-nginx
5 | IMAGE_TAG: foobarbaz
6 |
7 | tasks:
8 | build-container-image:
9 | desc: Build container image
10 | cmds:
11 | - docker build -t {{.IMAGE_REPO}}:{{.IMAGE_TAG}} .
12 |
13 | build-container-image-multi-arch:
14 | desc: Build multi-arch container image
15 | cmds:
16 | - |
17 | docker buildx build \
18 | --platform linux/amd64,linux/arm64 \
19 | -t {{.IMAGE_REPO}}:{{.IMAGE_TAG}} \
20 | --push \
21 | .
22 |
23 | install:
24 | desc: install dependencies
25 | cmds:
26 | - npm install
27 |
28 | run:
29 | desc: Start react client
30 | cmds:
31 | - npm run dev
32 |
--------------------------------------------------------------------------------
/06-demo-application/client-react/Tiltfile:
--------------------------------------------------------------------------------
1 | docker_build(
2 | 'sidpalas/devops-directive-docker-course-client-react-nginx',
3 | './',
4 | )
5 | k8s_yaml('../../07-deploying-demo-application/client-react/Deployment.yaml')
6 | k8s_resource('client-react-nginx', port_forwards=8080)
7 |
--------------------------------------------------------------------------------
/06-demo-application/client-react/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | DevOps Directive Kubernetes Course
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/06-demo-application/client-react/nginx.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 8080;
3 |
4 | location /ping {
5 | access_log off;
6 | add_header 'Content-Type' 'text/plain';
7 | return 200 "pong";
8 | }
9 | location /api/golang/ {
10 | proxy_set_header X-Forwarded-Host $host;
11 | proxy_set_header X-Forwarded-Server $host;
12 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
13 | proxy_http_version 1.1;
14 |
15 | rewrite ^/api-golang/(.*) /$1 break;
16 | proxy_pass http://api-golang:8000/;
17 | }
18 | location /api/node/ {
19 | proxy_set_header X-Forwarded-Host $host;
20 | proxy_set_header X-Forwarded-Server $host;
21 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
22 | proxy_http_version 1.1;
23 |
24 | rewrite ^/api/node/(.*) /$1 break;
25 | proxy_pass http://api-node:3000/;
26 | }
27 | location / {
28 | root /usr/share/nginx/html;
29 | index index.html index.htm;
30 | try_files $uri $uri/ /index.html =404;
31 | }
32 |
33 | include /etc/nginx/extra-conf.d/*.conf;
34 | }
--------------------------------------------------------------------------------
/06-demo-application/client-react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client-react",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite --host",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "@tanstack/react-query": "^4.22.4",
13 | "axios": "^1.2.3",
14 | "react": "^18.2.0",
15 | "react-dom": "^18.2.0"
16 | },
17 | "devDependencies": {
18 | "@tanstack/react-query-devtools": "^4.24.4",
19 | "@types/react": "^18.0.26",
20 | "@types/react-dom": "^18.0.9",
21 | "@vitejs/plugin-react-swc": "^3.0.0",
22 | "vite": "^4.0.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/06-demo-application/client-react/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sidpalas/devops-directive-kubernetes-course/18d4bcfac1818609dfc2e9e82d0affd77e0e7c47/06-demo-application/client-react/public/favicon.ico
--------------------------------------------------------------------------------
/06-demo-application/client-react/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | }
13 | .logo:hover {
14 | filter: drop-shadow(0 0 2em #646cffaa);
15 | }
16 | .logo.react:hover {
17 | filter: drop-shadow(0 0 2em #61dafbaa);
18 | }
19 |
20 | @keyframes logo-spin {
21 | from {
22 | transform: rotate(0deg);
23 | }
24 | to {
25 | transform: rotate(360deg);
26 | }
27 | }
28 |
29 | @media (prefers-reduced-motion: no-preference) {
30 | a:nth-of-type(2) .logo {
31 | animation: logo-spin infinite 20s linear;
32 | }
33 | }
34 |
35 | .card {
36 | padding: 2em;
37 | }
38 |
39 | .read-the-docs {
40 | color: #888;
41 | }
42 |
--------------------------------------------------------------------------------
/06-demo-application/client-react/src/App.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | QueryClient,
3 | QueryClientProvider,
4 | useQuery,
5 | } from "@tanstack/react-query";
6 | import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
7 | import axios from "axios";
8 |
9 | import "./App.css";
10 |
11 | const queryClient = new QueryClient();
12 |
13 | function CurrentTime(props) {
14 | const { isLoading, error, data, isFetching } = useQuery({
15 | queryKey: [props.api],
16 | queryFn: () => axios.get(`${props.api}`).then((res) => res.data),
17 | });
18 |
19 | if (isLoading) return `Loading ${props.api}... `;
20 |
21 | if (error) return "An error has occurred: " + error.message;
22 |
23 | return (
24 |
25 |
---
26 |
API: {data.api}
27 |
Time from DB: {data.currentTime}
28 |
Request Count: {data.requestCount}
29 |
{isFetching ? "Updating..." : ""}
30 |
31 | );
32 | }
33 |
34 | export function App() {
35 | return (
36 |
37 | Hey Team! 👋
38 |
39 |
40 |
41 |
42 | );
43 | }
44 |
45 | export default App;
46 |
--------------------------------------------------------------------------------
/06-demo-application/client-react/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/06-demo-application/client-react/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite";
2 | import react from "@vitejs/plugin-react-swc";
3 | import dns from "dns";
4 |
5 | dns.setDefaultResultOrder("verbatim");
6 |
7 | // https://vitejs.dev/config/
8 | export default defineConfig({
9 | plugins: [react()],
10 | server: {
11 | proxy: {
12 | "/api/golang": {
13 | target: "http://localhost:8000",
14 | changeOrigin: true,
15 | rewrite: (path) => path.replace(/^\/api\/golang/, ""),
16 | secure: false,
17 | },
18 | "/api/node": {
19 | target: "http://localhost:3000",
20 | changeOrigin: true,
21 | rewrite: (path) => path.replace(/^\/api\/node/, ""),
22 | secure: false,
23 | },
24 | },
25 | },
26 | });
27 |
--------------------------------------------------------------------------------
/06-demo-application/load-generator-python/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.12-slim AS generate-requirements
2 | RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
3 | RUN curl -sSL https://install.python-poetry.org | python3 -
4 | COPY pyproject.toml poetry.lock ./
5 | RUN /root/.local/bin/poetry export --output requirements.txt
6 |
7 | ###
8 |
9 | FROM python:3.12-slim AS production
10 | COPY --from=generate-requirements /requirements.txt .
11 | RUN pip install --no-cache-dir -r requirements.txt
12 | COPY . .
13 | CMD ["python", "main.py"]
--------------------------------------------------------------------------------
/06-demo-application/load-generator-python/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | vars:
4 | IMAGE_REPO: sidpalas/devops-directive-kubernetes-course-load-generator-python
5 | IMAGE_TAG: foobarbaz
6 |
7 | tasks:
8 | build-container-image:
9 | desc: Build container image
10 | cmds:
11 | - docker build -t {{.IMAGE_REPO}}:{{.IMAGE_TAG}} .
12 |
13 | build-container-image-multi-arch:
14 | desc: Build multi-arch container image
15 | cmds:
16 | - |
17 | docker buildx build \
18 | --platform linux/amd64,linux/arm64 \
19 | -t {{.IMAGE_REPO}}:{{.IMAGE_TAG}} \
20 | --push \
21 | .
22 |
23 | install:
24 | desc: Install load generator dependencies
25 | cmds:
26 | - poetry install --no-root
27 |
28 | run:
29 | desc: Start load generator
30 | cmds:
31 | # api-golang is listening on port 8000
32 | - API_URL=http://localhost:8000/ DELAY_MS=100 poetry run python main.py
33 |
--------------------------------------------------------------------------------
/06-demo-application/load-generator-python/Tiltfile:
--------------------------------------------------------------------------------
1 | docker_build(
2 | 'sidpalas/devops-directive-kubernetes-course-load-generator-python',
3 | './',
4 | )
5 | k8s_yaml('../../07-deploying-demo-application/load-generator-python/Deployment.yaml')
--------------------------------------------------------------------------------
/06-demo-application/load-generator-python/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "load-generator-python"
3 | version = "0.1.0"
4 | description = ""
5 | authors = ["sid palas"]
6 |
7 | [tool.poetry.dependencies]
8 | python = "^3.9"
9 | requests = "^2.32.2"
10 |
11 | [tool.poetry.dev-dependencies]
12 |
13 | [build-system]
14 | requires = ["poetry-core>=1.0.0"]
15 | build-backend = "poetry.core.masonry.api"
16 |
--------------------------------------------------------------------------------
/06-demo-application/postgresql/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM migrate/migrate:v4.17.1
2 |
3 | COPY ./migrations/* /app/migrations/
--------------------------------------------------------------------------------
/06-demo-application/postgresql/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | vars:
4 | IMAGE_REPO: sidpalas/devops-directive-kubernetes-course-db-migrator
5 | IMAGE_TAG: foobarbaz
6 |
7 | tasks:
8 | run-postgres:
9 | desc: Start postgres container
10 | cmds:
11 | - echo Starting postgres container
12 | - docker run -e POSTGRES_PASSWORD=foobarbaz -v pgdata:/var/lib/postgresql/data -p 5432:5432 postgres:16.3-alpine
13 |
14 | run-psql-init-script:
15 | desc: Execute psql commands
16 | cmds:
17 | - |
18 | CONTAINER_ID=$(docker ps -q --filter "ancestor=postgres:16.3-alpine")
19 | docker cp ./migrations/000001_create_users_table.up.sql $CONTAINER_ID:/tmp/
20 | docker exec $CONTAINER_ID psql -U "postgres" -f /tmp/000001_create_users_table.up.sql
21 |
22 | build-container-image:
23 | desc: Build container image
24 | cmds:
25 | - docker build -t {{.IMAGE_REPO}}{{.IMAGE_TAG}} .
26 |
27 | build-container-image-multi-arch:
28 | desc: Build multi-arch container image
29 | cmds:
30 | - |
31 | docker buildx build \
32 | --platform linux/amd64,linux/arm64 \
33 | -t {{.IMAGE_REPO}}:{{.IMAGE_TAG}} \
34 | --push \
35 | .
36 |
--------------------------------------------------------------------------------
/06-demo-application/postgresql/migrations/000001_create_users_table.down.sql:
--------------------------------------------------------------------------------
1 | -- Delete the table
2 | DROP TABLE public.request;
--------------------------------------------------------------------------------
/06-demo-application/postgresql/migrations/000001_create_users_table.up.sql:
--------------------------------------------------------------------------------
1 | -- Create the table
2 | CREATE TABLE IF NOT EXISTS public.request (
3 | created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
4 | api_name VARCHAR(10) NOT NULL CHECK (api_name IN ('node', 'go'))
5 | );
6 |
--------------------------------------------------------------------------------
/06-demo-application/readme-assets/request-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sidpalas/devops-directive-kubernetes-course/18d4bcfac1818609dfc2e9e82d0affd77e0e7c47/06-demo-application/readme-assets/request-diagram.png
--------------------------------------------------------------------------------
/06-demo-application/readme-assets/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sidpalas/devops-directive-kubernetes-course/18d4bcfac1818609dfc2e9e82d0affd77e0e7c47/06-demo-application/readme-assets/screenshot.png
--------------------------------------------------------------------------------
/07-deploying-demo-application/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: demo-app
5 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/api-golang/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | labels:
7 | app: api-golang
8 | spec:
9 | replicas: 1
10 | selector:
11 | matchLabels:
12 | app: api-golang
13 | template:
14 | metadata:
15 | labels:
16 | app: api-golang
17 | spec:
18 | containers:
19 | - name: api-golang
20 | image: sidpalas/devops-directive-docker-course-api-golang:foobarbaz
21 | env:
22 | - name: PORT
23 | value: "8000"
24 | envFrom:
25 | - secretRef:
26 | name: api-golang-database-url
27 | ports:
28 | - containerPort: 8000
29 | protocol: TCP
30 | readinessProbe:
31 | httpGet:
32 | path: /ping
33 | port: 8000
34 | resources:
35 | limits:
36 | memory: "100Mi"
37 | requests:
38 | memory: "100Mi"
39 | cpu: "50m"
40 | securityContext:
41 | allowPrivilegeEscalation: false
42 | privileged: false
43 | securityContext:
44 | seccompProfile:
45 | type: RuntimeDefault
46 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/api-golang/IngressRoute.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: traefik.containo.us/v1alpha1
2 | kind: IngressRoute
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | spec:
7 | entryPoints:
8 | - web
9 | routes:
10 | - kind: Rule
11 | match: Host(`kubernetes-course.devopsdirective.com`) && PathPrefix(`/api/golang`)
12 | middlewares:
13 | - name: strip-api-prefixes
14 | services:
15 | - kind: Service
16 | name: api-golang
17 | port: 8000
18 | scheme: http
19 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/api-golang/Secret.yml:
--------------------------------------------------------------------------------
1 | # ⛔️ DONT PUT SECRET FILES IN VCS
2 | apiVersion: v1
3 | kind: Secret
4 | type: Opaque
5 | metadata:
6 | name: api-golang-database-url
7 | namespace: demo-app
8 | stringData:
9 | DATABASE_URL: postgres://postgres:foobarbaz@postgres-postgresql.postgres.svc.cluster.local:5432/postgres
10 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/api-golang/Service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | spec:
7 | selector:
8 | app: api-golang
9 | ports:
10 | - protocol: TCP
11 | port: 8000
12 | targetPort: 8000
13 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/api-node/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: api-node
5 | namespace: demo-app
6 | labels:
7 | app: api-node
8 | spec:
9 | replicas: 1
10 | selector:
11 | matchLabels:
12 | app: api-node
13 | template:
14 | metadata:
15 | labels:
16 | app: api-node
17 | spec:
18 | containers:
19 | - name: api-node
20 | image: sidpalas/devops-directive-docker-course-api-node:foobarbaz
21 | env:
22 | - name: PORT
23 | value: "3000"
24 | envFrom:
25 | - secretRef:
26 | name: api-node-database-url
27 | ports:
28 | - containerPort: 3000
29 | protocol: TCP
30 | readinessProbe:
31 | httpGet:
32 | path: /ping
33 | port: 3000
34 | resources:
35 | limits:
36 | memory: "100Mi"
37 | requests:
38 | memory: "100Mi"
39 | cpu: "50m"
40 | securityContext:
41 | allowPrivilegeEscalation: false
42 | privileged: false
43 | securityContext:
44 | seccompProfile:
45 | type: RuntimeDefault
46 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/api-node/IngressRoute.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: traefik.containo.us/v1alpha1
2 | kind: IngressRoute
3 | metadata:
4 | name: api-node
5 | namespace: demo-app
6 | spec:
7 | entryPoints:
8 | - web
9 | routes:
10 | - kind: Rule
11 | match: Host(`kubernetes-course.devopsdirective.com`) && PathPrefix(`/api/node`)
12 | middlewares:
13 | - name: strip-api-prefixes
14 | services:
15 | - kind: Service
16 | name: api-node
17 | port: 3000
18 | scheme: http
19 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/api-node/Secret.yaml:
--------------------------------------------------------------------------------
1 | # ⛔️ DONT PUT SECRET FILES IN VCS
2 | apiVersion: v1
3 | kind: Secret
4 | type: Opaque
5 | metadata:
6 | name: api-node-database-url
7 | namespace: demo-app
8 | stringData:
9 | DATABASE_URL: postgres://postgres:foobarbaz@postgres-postgresql.postgres.svc.cluster.local:5432/postgres
10 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/api-node/Service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: api-node
5 | namespace: demo-app
6 | spec:
7 | selector:
8 | app: api-node
9 | ports:
10 | - protocol: TCP
11 | port: 3000
12 | targetPort: 3000
13 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/client-react/ConfigMap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: nginx-conf
5 | namespace: demo-app
6 | data:
7 | default.conf: |-
8 | server {
9 | listen 8080;
10 |
11 | location /ping {
12 | access_log off;
13 | add_header 'Content-Type' 'text/plain';
14 | return 200 "pong";
15 | }
16 |
17 | location / {
18 | root /usr/share/nginx/html;
19 | index index.html index.htm;
20 | try_files $uri $uri/ /index.html =404;
21 | }
22 |
23 | include /etc/nginx/extra-conf.d/*.conf;
24 | }
25 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/client-react/IngressRoute.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: traefik.containo.us/v1alpha1
2 | kind: IngressRoute
3 | metadata:
4 | name: client-react-nginx
5 | namespace: demo-app
6 | spec:
7 | entryPoints:
8 | - web
9 | routes:
10 | - kind: Rule
11 | match: Host(`kubernetes-course.devopsdirective.com`)
12 | services:
13 | - kind: Service
14 | name: client-react-nginx
15 | port: 8080
16 | scheme: http
17 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/client-react/Service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: client-react-nginx
5 | namespace: demo-app
6 | spec:
7 | selector:
8 | app: client-react-nginx
9 | ports:
10 | - protocol: TCP
11 | port: 8080
12 | targetPort: 8080
13 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/common/Middleware.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: traefik.containo.us/v1alpha1
2 | kind: Middleware
3 | metadata:
4 | name: strip-api-prefixes
5 | namespace: demo-app
6 | spec:
7 | stripPrefix:
8 | forceSlash: false
9 | prefixes:
10 | - /api/node
11 | - /api/golang
12 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/common/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: demo-app
5 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/common/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | tasks:
4 | apply-namespace:
5 | desc: "Apply Kubernetes Namespace"
6 | cmds:
7 | - kubectl apply -f Namespace.yaml
8 | - kubens demo-app
9 |
10 | deploy-traefik:
11 | desc: "Deploy Traefik using Helm"
12 | cmds:
13 | - helm repo add traefik https://traefik.github.io/charts
14 | - helm upgrade --install -n traefik --create-namespace traefik traefik/traefik --version 20.8.0
15 |
16 | apply-traefik-middleware:
17 | desc: "Deploy Traefik middleware"
18 | cmds:
19 | - "kubectl apply -f Middleware.yaml"
20 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/load-generator-python/ConfigMap.yaml:
--------------------------------------------------------------------------------
1 | # 🚨 This is currently unused (for example purposes)
2 | # The env var is defined directly in the deployment
3 | apiVersion: v1
4 | kind: ConfigMap
5 | metadata:
6 | name: load-generator-config
7 | namespace: demo-app
8 | data:
9 | API_URL: http://api-node.demo-app.svc.cluster.local:3000
10 | # API_URL: http://api-golang.demo-app.svc.cluster.local:8080
11 | DELAY_MS: "100"
12 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/postgresql/Job.db-migrator.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: batch/v1
2 | kind: Job
3 | metadata:
4 | name: db-migrator
5 | namespace: demo-app
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: migrate
11 | image: sidpalas/devops-directive-kubernetes-course-db-migrator:foobarbaz
12 | args:
13 | - -path=/app/migrations
14 | - -database=$(DATABASE_URL)?sslmode=disable
15 | - up
16 | envFrom:
17 | - secretRef:
18 | name: db-password
19 | restartPolicy: OnFailure
20 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/postgresql/Secret.db-password.yaml:
--------------------------------------------------------------------------------
1 | # ⛔️ DONT PUT SECRET FILES IN VCS
2 | apiVersion: v1
3 | kind: Secret
4 | metadata:
5 | name: db-password
6 | namespace: demo-app
7 | type: Opaque
8 | stringData:
9 | DATABASE_URL: postgres://postgres:foobarbaz@postgres-postgresql.postgres.svc.cluster.local:5432/postgres
10 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/postgresql/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | tasks:
4 | install-postgres:
5 | desc: "Deploy PostgreSQL using Helm"
6 | cmds:
7 | - helm repo add bitnami https://charts.bitnami.com/bitnami
8 | - |
9 | helm upgrade --install \
10 | -n postgres \
11 | postgres bitnami/postgresql \
12 | --set auth.postgresPassword=foobarbaz \
13 | --version 15.3.2 \
14 | --values values.yaml \
15 | --create-namespace
16 |
17 | apply-initial-db-migration-job:
18 | desc: "Run init.sql script against the DB"
19 | cmds:
20 | - "kubectl apply -f Secret.db-password.yaml"
21 | - "kubectl apply -f Job.db-migrator.yaml"
22 |
--------------------------------------------------------------------------------
/07-deploying-demo-application/postgresql/values.yaml:
--------------------------------------------------------------------------------
1 | primary:
2 | resources:
3 | limits:
4 | ephemeral-storage: 1Gi
5 | memory: 500Mi
6 | requests:
7 | cpu: 100m
8 | ephemeral-storage: 50Mi
9 | memory: 128Mi
10 |
--------------------------------------------------------------------------------
/08-extending-kubernetes/readme-assets/galaxy-brain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sidpalas/devops-directive-kubernetes-course/18d4bcfac1818609dfc2e9e82d0affd77e0e7c47/08-extending-kubernetes/readme-assets/galaxy-brain.png
--------------------------------------------------------------------------------
/09-deploying-auxiliary-tooling/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | includes:
4 | cloudnative-pg:
5 | taskfile: ./cloudnative-pg/Taskfile.yaml
6 | dir: ./cloudnative-pg
7 |
8 | trivy-operator:
9 | taskfile: ./trivy-operator/Taskfile.yaml
10 | dir: ./trivy-operator
11 |
--------------------------------------------------------------------------------
/09-deploying-auxiliary-tooling/cloudnative-pg/Backup.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: postgresql.cnpg.io/v1
2 | kind: Backup
3 | metadata:
4 | name: now-0
5 | namespace: 09--cnpg
6 | spec:
7 | method: barmanObjectStore
8 | cluster:
9 | name: cnpg-with-backup-config
10 |
--------------------------------------------------------------------------------
/09-deploying-auxiliary-tooling/cloudnative-pg/Cluster.cnpg-minimal.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: postgresql.cnpg.io/v1
2 | kind: Cluster
3 | metadata:
4 | name: cnpg-minimal
5 | spec:
6 | instances: 2
7 | storage:
8 | size: 1Gi
9 |
--------------------------------------------------------------------------------
/09-deploying-auxiliary-tooling/cloudnative-pg/Cluster.cnpg-with-backup-config-civo.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: postgresql.cnpg.io/v1
2 | kind: Cluster
3 | metadata:
4 | name: cnpg-with-backup-config
5 | spec:
6 | instances: 2
7 | storage:
8 | size: 1Gi
9 | backup:
10 | barmanObjectStore:
11 | destinationPath: "s3://cnpg-backups"
12 | endpointURL: "https://objectstore.nyc1.civo.com"
13 | s3Credentials:
14 | accessKeyId:
15 | name: civo-object-store-creds
16 | key: AWS_ACCESS_KEY_ID
17 | secretAccessKey:
18 | name: civo-object-store-creds
19 | key: AWS_SECRET_ACCESS_KEY
20 | retentionPolicy: "30d"
21 |
--------------------------------------------------------------------------------
/09-deploying-auxiliary-tooling/cloudnative-pg/Cluster.cnpg-with-backup-config-gcp.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: postgresql.cnpg.io/v1
2 | kind: Cluster
3 | metadata:
4 | name: cnpg-with-backup-config
5 | spec:
6 | instances: 2
7 | storage:
8 | size: 1Gi
9 | backup:
10 | barmanObjectStore:
11 | destinationPath: "gs://devops-directive-kubernetes-course-cnpg-backups"
12 | googleCredentials:
13 | gkeEnvironment: true
14 | retentionPolicy: "30d"
15 | serviceAccountTemplate:
16 | metadata:
17 | annotations:
18 | iam.gke.io/gcp-service-account: cnpg-backups@kubernetes-course-424917.iam.gserviceaccount.com
19 |
--------------------------------------------------------------------------------
/09-deploying-auxiliary-tooling/cloudnative-pg/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: 09--cnpg
5 |
--------------------------------------------------------------------------------
/09-deploying-auxiliary-tooling/cloudnative-pg/ScheduleBackup.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: postgresql.cnpg.io/v1
2 | kind: ScheduledBackup
3 | metadata:
4 | name: daily
5 | spec:
6 | schedule: "0 0 0 * * *"
7 | backupOwnerReference: self
8 | cluster:
9 | name: cnpg-with-backup-config
10 |
--------------------------------------------------------------------------------
/09-deploying-auxiliary-tooling/cloudnative-pg/Secret.civo-object-store-creds.yaml.TEMPLATE:
--------------------------------------------------------------------------------
1 | # ⛔️ DONT PUT SECRET FILES IN VCS
2 | apiVersion: v1
3 | kind: Secret
4 | type: Opaque
5 | metadata:
6 | name: civo-object-store-creds
7 | stringData:
8 | AWS_ACCESS_KEY_ID:
9 | AWS_SECRET_ACCESS_KEY:
10 |
--------------------------------------------------------------------------------
/09-deploying-auxiliary-tooling/trivy-operator/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: 3
2 |
3 | tasks:
4 | 01-install-trivy-operator:
5 | desc: "Install trivy operator into trivy-system namespace"
6 | cmds:
7 | - helm repo add aqua https://aquasecurity.github.io/helm-charts/
8 | - helm repo update
9 | - |
10 | helm upgrade --install trivy-operator aqua/trivy-operator \
11 | --namespace trivy-system \
12 | --create-namespace \
13 | --version 0.23.2
14 |
15 | 02-uninstall-trivy-operator:
16 | desc: "Uninstall the trivy operator"
17 | cmds:
18 | - helm uninstall trivy-operator --namespace trivy-system
19 |
--------------------------------------------------------------------------------
/10-developer-experience/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | includes:
4 | external-secrets-operator:
5 | taskfile: ./external-secrets-operator/Taskfile.yaml
6 | dir: ./external-secrets-operator
7 |
8 | tilt:
9 | taskfile: ./tilt/Taskfile.yaml
10 | dir: ./tilt
11 |
--------------------------------------------------------------------------------
/10-developer-experience/external-secrets-operator/ClusterSecretStore.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: external-secrets.io/v1beta1
2 | kind: ClusterSecretStore
3 | metadata:
4 | name: gcp-store
5 | spec:
6 | provider:
7 | gcpsm:
8 | projectID: kubernetes-course-424917
9 |
--------------------------------------------------------------------------------
/10-developer-experience/external-secrets-operator/ExternalSecret.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: external-secrets.io/v1beta1
2 | kind: ExternalSecret
3 | metadata:
4 | name: example
5 | namespace: external-secrets
6 | spec:
7 | refreshInterval: 1h # rate SecretManager pulls GCPSM
8 | secretStoreRef:
9 | kind: ClusterSecretStore
10 | name: gcp-store # name of the SecretStore (or kind specified)
11 | target:
12 | name: external-secrets-example-k8s # name of the k8s Secret to be created
13 | creationPolicy: Owner
14 | data:
15 | - secretKey: key-k8s # key in the Kubernetes Secret
16 | remoteRef:
17 | key: external-secrets-example-gcp # name of the GCPSM secret key
18 |
--------------------------------------------------------------------------------
/10-developer-experience/external-secrets-operator/ServiceAccount.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ServiceAccount
3 | metadata:
4 | name: external-secrets
5 | namespace: external-secrets
6 | annotations:
7 | iam.gke.io/gcp-service-account: external-secrets@kubernetes-course-424917.iam.gserviceaccount.com
8 |
--------------------------------------------------------------------------------
/10-developer-experience/external-secrets-operator/values.yaml:
--------------------------------------------------------------------------------
1 | serviceAccount:
2 | annotations:
3 | iam.gke.io/gcp-service-account: external-secrets@kubernetes-course-424917.iam.gserviceaccount.com
4 |
--------------------------------------------------------------------------------
/10-developer-experience/tilt/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | tasks:
4 | tilt-up:
5 | desc: "Start the applications using the top level tilt file"
6 | cmds:
7 | - tilt up
8 |
--------------------------------------------------------------------------------
/10-developer-experience/tilt/Tiltfile:
--------------------------------------------------------------------------------
1 | include('../../06-demo-application/api-golang/Tiltfile')
2 | include('../../06-demo-application/api-node/Tiltfile')
3 | include('../../06-demo-application/client-react/Tiltfile')
4 | include('../../06-demo-application/load-generator-python/Tiltfile')
--------------------------------------------------------------------------------
/11-debugging/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: microservices-demo
5 |
--------------------------------------------------------------------------------
/11-debugging/README.md:
--------------------------------------------------------------------------------
1 | # Debugging In Kubernetes
2 |
3 | Sometimes things go wrong. This section is meant to show you misconfigurations that can cause issues and how you would find/fix them.
4 |
5 | ## Application
6 |
7 | The application used for this section is https://github.com/GoogleCloudPlatform/microservices-demo, but with a few intentional breaks.
8 |
9 | 
10 |
11 | You can find the specific modifications I made to the configuration here: https://github.com/sidpalas/microservices-demo/pull/1. That being said, DON'T LOOK until you have already gone through the process of debugging it yourself.
12 |
13 | ## Flow Chart
14 |
15 | The folks over at [Learn K8s](https://learnk8s.io/) have published a very useful article and flow chart for troubleshooting deployments within kubernetes:
16 |
17 | https://learnk8s.io/troubleshooting-deployments
18 |
19 | This can provide a great structure for your debugging process.
20 |
--------------------------------------------------------------------------------
/11-debugging/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | env:
4 | BORDER: double
5 | BORDER_FOREGROUND: "212"
6 | PADDING: "1 1"
7 | MARGIN: "1 1"
8 | NAMESPACE: microservices-demo
9 |
10 | tasks:
11 | 01-create-namespace:
12 | desc: "Create a namespace for these examples and set as default"
13 | cmds:
14 | - kubectl apply -f Namespace.yaml
15 | - kubens ${NAMESPACE}
16 |
17 | 02-install-microservices-demo:
18 | cmds:
19 | - kubectl apply -f microservices-demo.yaml
20 | desc: Install the broken google microservices demo
21 |
22 | 03-delete-namespace:
23 | desc: "Delete the namespace to clean up"
24 | cmds:
25 | - cmd: gum style "🚨 Deleting the namespace recursively deletes the resources inside of it! 🚨 "
26 | silent: true
27 | - kubectl delete -f Namespace.yaml
28 |
--------------------------------------------------------------------------------
/11-debugging/readme-assets/broken-demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sidpalas/devops-directive-kubernetes-course/18d4bcfac1818609dfc2e9e82d0affd77e0e7c47/11-debugging/readme-assets/broken-demo.png
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | includes:
4 | helm:
5 | taskfile: ./helm/Taskfile.yaml
6 | dir: ./helm
7 |
8 | kluctl:
9 | taskfile: ./kluctl/Taskfile.yaml
10 | dir: ./kluctl
11 |
12 | kustomize:
13 | taskfile: ./kustomize/Taskfile.yaml
14 | dir: ./kustomize
15 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/helm/.gitignore:
--------------------------------------------------------------------------------
1 | *.tgz
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/helm/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | tasks:
4 | template-default:
5 | cmds:
6 | - helm template ./api-golang-helm-chart | yq
7 | desc: "Render chart yaml with default values"
8 |
9 | template-staging:
10 | cmds:
11 | - helm template ./api-golang-helm-chart --values=./api-golang-helm-chart/values.staging.yaml | yq
12 | desc: "Render chart yaml with staging values file"
13 |
14 | template-production:
15 | cmds:
16 | - helm template ./api-golang-helm-chart --values=./api-golang-helm-chart/values.production.yaml | yq
17 | desc: "Render chart yaml with production values file"
18 |
19 | package:
20 | cmds:
21 | - helm package ./api-golang-helm-chart
22 | desc: "Bundle helm chart as a .tgz OCI image"
23 |
24 | push:
25 | cmds:
26 | - helm push api-golang-helm-chart-0.1.0.tgz oci://registry-1.docker.io/sidpalas
27 | desc: "Push the helm chart to an oci registry"
28 |
29 | build-push:
30 | cmds:
31 | - task: build
32 | - task: push
33 | desc: "Build & Push the helm chart to an oci registry"
34 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/helm/api-golang-helm-chart/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *.orig
18 | *~
19 | # Various IDEs
20 | .project
21 | .idea/
22 | *.tmproj
23 | .vscode/
24 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/helm/api-golang-helm-chart/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | name: api-golang-helm-chart
3 | description: A minimal helm chart for deploying api-golang
4 | type: application
5 | version: 0.1.0
6 | appVersion: foobarbaz
7 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/helm/api-golang-helm-chart/templates/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | labels:
7 | app: api-golang
8 | spec:
9 | replicas: {{ .Values.replicas }}
10 | selector:
11 | matchLabels:
12 | app: api-golang
13 | template:
14 | metadata:
15 | labels:
16 | app: api-golang
17 | spec:
18 | containers:
19 | - name: api-golang
20 | image: "sidpalas/devops-directive-docker-course-api-golang:{{ .Values.version }}"
21 | env:
22 | - name: PORT
23 | value: "8000"
24 | envFrom:
25 | - secretRef:
26 | name: api-golang-database-url
27 | ports:
28 | - containerPort: 8000
29 | protocol: TCP
30 | readinessProbe:
31 | httpGet:
32 | path: /ping
33 | port: 8000
34 | resources:
35 | limits:
36 | memory: "100Mi"
37 | requests:
38 | memory: "100Mi"
39 | cpu: "50m"
40 | securityContext:
41 | allowPrivilegeEscalation: false
42 | privileged: false
43 | securityContext:
44 | seccompProfile:
45 | type: RuntimeDefault
46 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/helm/api-golang-helm-chart/templates/IngressRoute.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: traefik.containo.us/v1alpha1
2 | kind: IngressRoute
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | spec:
7 | entryPoints:
8 | - web
9 | routes:
10 | - kind: Rule
11 | match: Host(`kubernetes-course{{ .Values.environmentPostfix }}.devopsdirective.com`) && PathPrefix(`/api/golang`)
12 | middlewares:
13 | - name: strip-api-prefixes
14 | services:
15 | - kind: Service
16 | name: api-golang
17 | port: 8080
18 | scheme: http
19 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/helm/api-golang-helm-chart/templates/Secret.yml:
--------------------------------------------------------------------------------
1 | # ⛔️ DONT PUT SECRET FILES IN VCS
2 | apiVersion: v1
3 | kind: Secret
4 | type: Opaque
5 | metadata:
6 | name: api-golang-database-url
7 | namespace: demo-app
8 | stringData:
9 | DATABASE_URL: postgres://postgres:foobarbaz@postgres-postgresql.postgres.svc.cluster.local:5432/postgres
10 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/helm/api-golang-helm-chart/templates/Service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | spec:
7 | selector:
8 | app: api-golang
9 | ports:
10 | - protocol: TCP
11 | port: 8000
12 | targetPort: 8000
13 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/helm/api-golang-helm-chart/templates/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{- define "envShort" -}}
2 | {{- if eq .Values.environment "production" -}}
3 | prod
4 | {{- else -}}
5 | non-prod
6 | {{- end -}}
7 | {{- end -}}
8 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/helm/api-golang-helm-chart/values.production.yaml:
--------------------------------------------------------------------------------
1 | replicas: 2
2 | version: PRODUCTION_VERSION
3 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/helm/api-golang-helm-chart/values.staging.yaml:
--------------------------------------------------------------------------------
1 | environmentPostfix: "-staging"
2 | version: STAGING_VERSION
3 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/helm/api-golang-helm-chart/values.yaml:
--------------------------------------------------------------------------------
1 | environmentPostfix: ""
2 | replicas: 1
3 | version: DEFAULT_VERSION
4 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/.kluctl.yaml:
--------------------------------------------------------------------------------
1 | targets:
2 | - name: staging
3 | args:
4 | environment: staging
5 | # Adding a context to .kluctl.yaml helps prevent accidentally deploying to the wrong cluster!
6 | context: devops-directive-kubernetes-course
7 |
8 | - name: production
9 | args:
10 | environment: production
11 | # Adding a context to .kluctl.yaml helps prevent accidentally deploying to the wrong cluster!
12 | context: gke_kubernetes-course-424917_us-central1-a_devops-directive-kubernetes-course
13 |
14 | args:
15 | - name: environment
16 |
17 | discriminator: kluctl-{{ target.name }}
18 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sidpalas/devops-directive-kubernetes-course/18d4bcfac1818609dfc2e9e82d0affd77e0e7c47/12-deploying-to-multiple-environments/kluctl-single-service/README.md
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | tasks:
4 | helm-pull:
5 | cmds:
6 | - kluctl helm-pull
7 | desc: "Pre-pull helm charts"
8 |
9 | render-staging:
10 | cmds:
11 | - kluctl render -t staging --print-all | yq
12 | desc: "Render resource yaml with staging values"
13 |
14 | deploy-staging:
15 | cmds:
16 | - kluctl deploy -t staging
17 | desc: "Deploy staging configuration"
18 |
19 | delete-staging:
20 | cmds:
21 | - kluctl delete -t staging
22 | desc: "Render resource yaml with staging values"
23 |
24 | render-production:
25 | cmds:
26 | - kluctl render -t production --print-all | yq
27 | desc: "Render resource yaml with production values"
28 |
29 | deploy-production:
30 | cmds:
31 | - kluctl deploy -t production
32 | desc: "Deploy production configuration"
33 |
34 | delete-production:
35 | cmds:
36 | - kluctl delete -t production
37 | desc: "Render resource yaml with production values"
38 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/config/production.yaml:
--------------------------------------------------------------------------------
1 | sharedVars:
2 | hostName: "kubernetes-course.devopsdirective.com"
3 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/config/staging.yaml:
--------------------------------------------------------------------------------
1 | sharedVars:
2 | hostName: "kubernetes-course-staging.devopsdirective.com"
3 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/deployment.yaml:
--------------------------------------------------------------------------------
1 | vars:
2 | - file: config/{{ args.environment }}.yaml
3 |
4 | deployments:
5 | - path: namespaces
6 | - barrier: true
7 | - include: services
8 |
9 | commonLabels:
10 | devopsdirective.com/course: "kubernetes-course"
11 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/namespaces/Namespace.demo-app.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: demo-app
5 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/services/api-golang/config/production.yaml:
--------------------------------------------------------------------------------
1 | apiGolang:
2 | version: 1.0.0 # PRODUCTION_IMAGE_TAG
3 | replicas: 2
4 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/services/api-golang/config/staging.yaml:
--------------------------------------------------------------------------------
1 | apiGolang:
2 | version: 1.0.0 # STAGING_IMAGE_TAG
3 | replicas: 1
4 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/services/api-golang/deployment.yaml:
--------------------------------------------------------------------------------
1 | vars:
2 | - file: config/{{ args.environment }}.yaml
3 |
4 | deployments:
5 | - path: manifests
6 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/services/api-golang/manifests/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | labels:
7 | app: api-golang
8 | spec:
9 | replicas: {{apiGolang.replicas}}
10 | selector:
11 | matchLabels:
12 | app: api-golang
13 | template:
14 | metadata:
15 | labels:
16 | app: api-golang
17 | spec:
18 | containers:
19 | - name: api-golang
20 | image: sidpalas/devops-directive-docker-course-api-golang:{{ apiGolang.version }}
21 | env:
22 | - name: PORT
23 | value: "8000"
24 | envFrom:
25 | - secretRef:
26 | name: api-golang-database-url
27 | ports:
28 | - containerPort: 8000
29 | protocol: TCP
30 | readinessProbe:
31 | httpGet:
32 | path: /ping
33 | port: 8000
34 | resources:
35 | limits:
36 | memory: "100Mi"
37 | requests:
38 | memory: "100Mi"
39 | cpu: "50m"
40 | securityContext:
41 | allowPrivilegeEscalation: false
42 | privileged: false
43 | securityContext:
44 | seccompProfile:
45 | type: RuntimeDefault
46 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/services/api-golang/manifests/IngressRoute.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: traefik.containo.us/v1alpha1
2 | kind: IngressRoute
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | spec:
7 | entryPoints:
8 | - web
9 | routes:
10 | - kind: Rule
11 | match: Host(`{{ sharedVars.hostName }}`) && PathPrefix(`/api/golang`)
12 | middlewares:
13 | - name: strip-api-prefixes
14 | services:
15 | - kind: Service
16 | name: api-golang
17 | port: 8080
18 | scheme: http
19 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/services/api-golang/manifests/Job.db-migrator.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: batch/v1
2 | kind: Job
3 | metadata:
4 | name: db-migrator
5 | namespace: demo-app
6 | annotations:
7 | kluctl.io/hook: pre-deploy
8 | kluctl.io/hook-weight: 2
9 | spec:
10 | template:
11 | spec:
12 | containers:
13 | - name: migrate
14 | image: sidpalas/devops-directive-kubernetes-course-db-migrator:{{ apiGolang.version }}
15 | args:
16 | - -path=/app/migrations
17 | - -database=$(DATABASE_URL)?sslmode=disable
18 | - up
19 | envFrom:
20 | - secretRef:
21 | name: db-migrator-password
22 | restartPolicy: OnFailure
23 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/services/api-golang/manifests/Middleware.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: traefik.containo.us/v1alpha1
2 | kind: Middleware
3 | metadata:
4 | name: strip-api-prefixes-golang
5 | namespace: demo-app
6 | spec:
7 | stripPrefix:
8 | forceSlash: false
9 | prefixes:
10 | - /api/golang
11 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/services/api-golang/manifests/Secret.db-migrator-password.yaml:
--------------------------------------------------------------------------------
1 | # ⛔️ DONT PUT SECRET FILES IN VCS
2 | # Creating this secret here is a bit of a hack to ensure it exists before
3 | # the db-migrator job which runs as a pre-deploy hook for api-golang
4 | apiVersion: v1
5 | kind: Secret
6 | metadata:
7 | name: db-migrator-password
8 | namespace: demo-app
9 | annotations:
10 | kluctl.io/hook: pre-deploy
11 | kluctl.io/hook-weight: 1
12 | type: Opaque
13 | stringData:
14 | DATABASE_URL: postgres://postgres:foobarbaz@cnpg-minimal-rw.postgres.svc.cluster.local:5432/postgres
15 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/services/api-golang/manifests/Secret.yml:
--------------------------------------------------------------------------------
1 | # ⛔️ DONT PUT SECRET FILES IN VCS
2 | apiVersion: v1
3 | kind: Secret
4 | type: Opaque
5 | metadata:
6 | name: api-golang-database-url
7 | namespace: demo-app
8 | stringData:
9 | DATABASE_URL: postgres://postgres:foobarbaz@cnpg-minimal-rw.postgres.svc.cluster.local:5432/postgres
10 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/services/api-golang/manifests/Service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | spec:
7 | selector:
8 | app: api-golang
9 | ports:
10 | - protocol: TCP
11 | port: 8000
12 | targetPort: 8000
13 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl-single-service/services/deployment.yaml:
--------------------------------------------------------------------------------
1 | deployments:
2 | - include: api-golang
3 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_cloudnative-pg.github.io/charts/cloudnative-pg/0.21.4/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *.orig
18 | *~
19 | # Various IDEs
20 | .project
21 | .idea/
22 | *.tmproj
23 | .vscode/
24 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_cloudnative-pg.github.io/charts/cloudnative-pg/0.21.4/Chart.lock:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - name: cluster
3 | repository: https://cloudnative-pg.github.io/grafana-dashboards
4 | version: 0.0.2
5 | digest: sha256:fcf16ad357c17be3dd79c138723e78e9e101fecc5d07d9371299c32b9f85dbd9
6 | generated: "2024-04-25T12:32:36.61779032-04:00"
7 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_cloudnative-pg.github.io/charts/cloudnative-pg/0.21.4/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | appVersion: 1.23.1
3 | dependencies:
4 | - alias: monitoring
5 | condition: monitoring.grafanaDashboard.create
6 | name: cluster
7 | repository: https://cloudnative-pg.github.io/grafana-dashboards
8 | version: "0.0"
9 | description: CloudNativePG Operator Helm Chart
10 | home: https://cloudnative-pg.io
11 | icon: https://raw.githubusercontent.com/cloudnative-pg/artwork/main/cloudnativepg-logo.svg
12 | keywords:
13 | - operator
14 | - controller
15 | - postgresql
16 | - postgres
17 | - database
18 | maintainers:
19 | - email: p.scorsolini@gmail.com
20 | name: phisco
21 | name: cloudnative-pg
22 | sources:
23 | - https://github.com/cloudnative-pg/charts
24 | type: application
25 | version: 0.21.4
26 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_cloudnative-pg.github.io/charts/cloudnative-pg/0.21.4/charts/cluster/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *.orig
18 | *~
19 | # Various IDEs
20 | .project
21 | .idea/
22 | *.tmproj
23 | .vscode/
24 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_cloudnative-pg.github.io/charts/cloudnative-pg/0.21.4/charts/cluster/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | appVersion: 1.16.0
3 | description: CloudNativePG Grafana Cluster Dashboard.
4 | name: cluster
5 | type: application
6 | version: 0.0.2
7 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_cloudnative-pg.github.io/charts/cloudnative-pg/0.21.4/charts/cluster/templates/NOTES.txt:
--------------------------------------------------------------------------------
1 | CloudNativePG Grafana Dashboard installed successfully.
2 |
3 | {{- if (or .Values.grafanaDashboard.sidecarLabel .Values.grafanaDashboard.sidecarLabelValue) }}
4 | DEPRECATION NOTICE: The grafanaDashboard.sidecarLabel is deprecated and will be removed in a future release. Use the grafanaDashboard.labels instead.
5 | {{- end }}
6 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_cloudnative-pg.github.io/charts/cloudnative-pg/0.21.4/charts/cluster/templates/sidecar-configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: {{ .Values.grafanaDashboard.configMapName }}
5 | namespace: {{ default .Release.Namespace .Values.grafanaDashboard.namespace }}
6 | {{- if (or .Values.grafanaDashboard.labels .Values.grafanaDashboard.sidecarLabel) }}
7 | labels:
8 | {{- if .Values.grafanaDashboard.sidecarLabel }}
9 | {{ .Values.grafanaDashboard.sidecarLabel }}: {{ .Values.grafanaDashboard.sidecarLabelValue | quote }}
10 | {{- end }}
11 | {{- with .Values.grafanaDashboard.labels }}
12 | {{- toYaml . | nindent 4 }}
13 | {{- end }}
14 | {{- end }}
15 | {{- with .Values.grafanaDashboard.annotations }}
16 | annotations:
17 | {{- toYaml . | nindent 4 }}
18 | {{- end }}
19 | data:
20 | cnp.json: |-
21 | {{ .Files.Get "grafana-dashboard.json" | indent 6 }}
22 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_cloudnative-pg.github.io/charts/cloudnative-pg/0.21.4/charts/cluster/values.schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/schema#",
3 | "type": "object",
4 | "properties": {
5 | "fullnameOverride": {
6 | "type": "string"
7 | },
8 | "grafanaDashboard": {
9 | "type": "object",
10 | "properties": {
11 | "annotations": {
12 | "type": "object"
13 | },
14 | "configMapName": {
15 | "type": "string"
16 | },
17 | "labels": {
18 | "type": "object"
19 | },
20 | "namespace": {
21 | "type": "string"
22 | },
23 | "sidecarLabel": {
24 | "type": "string"
25 | },
26 | "sidecarLabelValue": {
27 | "type": "string"
28 | }
29 | }
30 | },
31 | "nameOverride": {
32 | "type": "string"
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_cloudnative-pg.github.io/charts/cloudnative-pg/0.21.4/charts/cluster/values.yaml:
--------------------------------------------------------------------------------
1 | # Default values for cluster.
2 | # This is a YAML-formatted file.
3 | # Declare variables to be passed into your templates.
4 |
5 | nameOverride: ""
6 | fullnameOverride: ""
7 |
8 | grafanaDashboard:
9 | # -- Allows overriding the namespace where the ConfigMap will be created, defaulting to the same one as the Release.
10 | namespace: ""
11 | # -- The name of the ConfigMap containing the dashboard.
12 | configMapName: "cnpg-grafana-dashboard"
13 | # -- Label that ConfigMaps should have to be loaded as dashboards. DEPRECATED: Use labels instead.
14 | sidecarLabel: "grafana_dashboard"
15 | # -- Label value that ConfigMaps should have to be loaded as dashboards. DEPRECATED: Use labels instead.
16 | sidecarLabelValue: "1"
17 | # -- Labels that ConfigMaps should have to get configured in Grafana.
18 | labels: {}
19 | # -- Annotations that ConfigMaps can have to get configured in Grafana.
20 | annotations: {}
21 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_cloudnative-pg.github.io/charts/cloudnative-pg/0.21.4/monitoring/grafana-dashboard.json:
--------------------------------------------------------------------------------
1 | The JSON file has been moved to a dedicated repository for CloudNativePG dashboards located at:
2 |
3 | https://github.com/cloudnative-pg/grafana-dashboards/blob/main/charts/cluster/grafana-dashboard.json
4 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_cloudnative-pg.github.io/charts/cloudnative-pg/0.21.4/templates/NOTES.txt:
--------------------------------------------------------------------------------
1 |
2 | CloudNativePG operator should be installed in namespace "{{ .Release.Namespace }}".
3 | You can now create a PostgreSQL cluster with 3 nodes in the current namespace as follows:
4 |
5 | cat <=1.19.0-0" .Capabilities.KubeVersion.Version -}}
6 | apiVersion: networking.k8s.io/v1
7 | {{- else if semverCompare ">=1.16.0-0" .Capabilities.KubeVersion.Version }}
8 | apiVersion: networking.k8s.io/v1beta1
9 | {{- else }}
10 | {{- fail "ERROR: You must use at least Kubernetes v1.16 with this Chart" }}
11 | {{- end }}
12 | kind: IngressClass
13 | metadata:
14 | annotations:
15 | ingressclass.kubernetes.io/is-default-class: {{ .Values.ingressClass.isDefaultClass | quote }}
16 | labels:
17 | {{- include "traefik.labels" . | nindent 4 }}
18 | name: {{ template "traefik.fullname" . }}
19 | spec:
20 | controller: traefik.io/ingress-controller
21 | {{- end -}}
22 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_traefik.github.io/charts/traefik/20.8.0/templates/poddisruptionbudget.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.podDisruptionBudget.enabled -}}
2 | {{- if .Capabilities.APIVersions.Has "policy/v1/PodDisruptionBudget" }}
3 | apiVersion: policy/v1
4 | {{- else }}
5 | apiVersion: policy/v1beta1
6 | {{- end }}
7 | kind: PodDisruptionBudget
8 | metadata:
9 | name: {{ template "traefik.fullname" . }}
10 | namespace: {{ template "traefik.namespace" . }}
11 | labels:
12 | {{- include "traefik.labels" . | nindent 4 }}
13 | spec:
14 | selector:
15 | matchLabels:
16 | {{- include "traefik.labelselector" . | nindent 6 }}
17 | {{- if .Values.podDisruptionBudget.minAvailable }}
18 | minAvailable: {{ .Values.podDisruptionBudget.minAvailable }}
19 | {{- end }}
20 | {{- if .Values.podDisruptionBudget.maxUnavailable }}
21 | maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }}
22 | {{- end }}
23 | {{- end -}}
24 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_traefik.github.io/charts/traefik/20.8.0/templates/prometheusrules.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.metrics.prometheus }}
2 | {{- if .Values.metrics.prometheus.prometheusRule }}
3 | {{- if (not (.Capabilities.APIVersions.Has "monitoring.coreos.com/v1")) }}
4 | {{- fail "ERROR: You have to deploy monitoring.coreos.com/v1 first" }}
5 | {{- end }}
6 | apiVersion: monitoring.coreos.com/v1
7 | kind: PrometheusRule
8 | metadata:
9 | name: {{ template "traefik.fullname" . }}
10 | {{- if .Values.metrics.prometheus.prometheusRule.namespace }}
11 | namespace: {{ .Values.metrics.prometheus.prometheusRule.namespace }}
12 | {{- end }}
13 | labels:
14 | {{- include "traefik.labels" . | nindent 4 }}
15 | {{- with .Values.metrics.prometheus.prometheusRule.additionalLabels }}
16 | {{- toYaml . | nindent 4 }}
17 | {{- end }}
18 | spec:
19 | {{- if .Values.metrics.prometheus.prometheusRule.rules }}
20 | groups:
21 | - name: {{ template "traefik.name" $ }}
22 | rules:
23 | {{- with .Values.metrics.prometheus.prometheusRule.rules }}
24 | {{- toYaml . | nindent 4 }}
25 | {{- end }}
26 | {{- end }}
27 | {{- end }}
28 | {{- end }}
29 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_traefik.github.io/charts/traefik/20.8.0/templates/pvc.yaml:
--------------------------------------------------------------------------------
1 | {{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) -}}
2 | apiVersion: v1
3 | kind: PersistentVolumeClaim
4 | metadata:
5 | name: {{ template "traefik.fullname" . }}
6 | namespace: {{ template "traefik.namespace" . }}
7 | annotations:
8 | {{- with .Values.persistence.annotations }}
9 | {{ toYaml . | nindent 4 }}
10 | {{- end }}
11 | helm.sh/resource-policy: keep
12 | labels:
13 | {{- include "traefik.labels" . | nindent 4 }}
14 | spec:
15 | accessModes:
16 | - {{ .Values.persistence.accessMode | quote }}
17 | resources:
18 | requests:
19 | storage: {{ .Values.persistence.size | quote }}
20 | {{- if .Values.persistence.storageClass }}
21 | storageClassName: {{ .Values.persistence.storageClass | quote }}
22 | {{- end }}
23 | {{- end -}}
24 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_traefik.github.io/charts/traefik/20.8.0/templates/rbac/clusterrolebinding.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.rbac.enabled -}}
2 | ---
3 | kind: ClusterRoleBinding
4 | apiVersion: rbac.authorization.k8s.io/v1
5 | metadata:
6 | name: {{ template "traefik.clusterRoleName" . }}
7 | labels:
8 | {{- include "traefik.labels" . | nindent 4 }}
9 | roleRef:
10 | apiGroup: rbac.authorization.k8s.io
11 | kind: ClusterRole
12 | name: {{ template "traefik.clusterRoleName" . }}
13 | subjects:
14 | - kind: ServiceAccount
15 | name: {{ include "traefik.serviceAccountName" . }}
16 | namespace: {{ template "traefik.namespace" . }}
17 | {{- end -}}
18 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_traefik.github.io/charts/traefik/20.8.0/templates/rbac/rolebinding.yaml:
--------------------------------------------------------------------------------
1 | {{- if and .Values.rbac.enabled .Values.rbac.namespaced }}
2 | kind: RoleBinding
3 | apiVersion: rbac.authorization.k8s.io/v1
4 | metadata:
5 | name: {{ template "traefik.fullname" . }}
6 | namespace: {{ template "traefik.namespace" . }}
7 | labels:
8 | {{- include "traefik.labels" . | nindent 4 }}
9 | roleRef:
10 | apiGroup: rbac.authorization.k8s.io
11 | kind: Role
12 | name: {{ template "traefik.fullname" . }}
13 | subjects:
14 | - kind: ServiceAccount
15 | name: {{ include "traefik.serviceAccountName" . }}
16 | namespace: {{ template "traefik.namespace" . }}
17 | {{- end -}}
18 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_traefik.github.io/charts/traefik/20.8.0/templates/rbac/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{- if not .Values.serviceAccount.name -}}
2 | kind: ServiceAccount
3 | apiVersion: v1
4 | metadata:
5 | name: {{ include "traefik.serviceAccountName" . }}
6 | namespace: {{ template "traefik.namespace" . }}
7 | labels:
8 | {{- include "traefik.labels" . | nindent 4 }}
9 | annotations:
10 | {{- with .Values.serviceAccountAnnotations }}
11 | {{- toYaml . | nindent 4 }}
12 | {{- end }}
13 | {{- end -}}
14 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_traefik.github.io/charts/traefik/20.8.0/templates/service-hub.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.hub.enabled -}}
2 |
3 | apiVersion: v1
4 | kind: Service
5 | metadata:
6 | name: traefik-hub
7 | namespace: {{ template "traefik.namespace" . }}
8 | {{- template "traefik.service-metadata" . }}
9 | spec:
10 | type: ClusterIP
11 | selector:
12 | {{- include "traefik.labelselector" . | nindent 4 }}
13 | ports:
14 | - port: {{ .Values.ports.metrics.port }}
15 | name: "metrics"
16 | targetPort: metrics
17 | protocol: TCP
18 | {{- if .Values.ports.metrics.nodePort }}
19 | nodePort: {{ .Values.ports.metrics.nodePort }}
20 | {{- end }}
21 | - port: {{ default 9901 .Values.hub.tunnelPort }}
22 | name: "traefikhub-tunl"
23 | targetPort: traefikhub-tunl
24 | protocol: TCP
25 | {{- end -}}
26 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_traefik.github.io/charts/traefik/20.8.0/templates/service-metrics.yaml:
--------------------------------------------------------------------------------
1 | {{- $fullname := include "traefik.fullname" . }}
2 | {{- if ge (len $fullname) 50 }}
3 | {{- fail "ERROR: Cannot create a metrics service when name contains more than 50 characters" }}
4 | {{- end }}
5 |
6 | {{- if .Values.metrics.prometheus }}
7 | {{- if .Values.metrics.prometheus.service }}
8 | {{- if (and (.Values.metrics.prometheus.service).enabled (not .Values.hub.enabled)) -}}
9 | apiVersion: v1
10 | kind: Service
11 | metadata:
12 | name: {{ $fullname }}-metrics
13 | namespace: {{ template "traefik.namespace" . }}
14 | {{- template "traefik.metrics-service-metadata" . }}
15 | annotations:
16 | {{- with .Values.metrics.prometheus.service.annotations }}
17 | {{- toYaml . | nindent 4 }}
18 | {{- end }}
19 | spec:
20 | type: ClusterIP
21 | selector:
22 | {{- include "traefik.labelselector" . | nindent 4 }}
23 | ports:
24 | - port: {{ .Values.ports.metrics.port }}
25 | name: "metrics"
26 | targetPort: metrics
27 | protocol: TCP
28 | {{- if .Values.ports.metrics.nodePort }}
29 | nodePort: {{ .Values.ports.metrics.nodePort }}
30 | {{- end }}
31 | {{- end }}
32 | {{- end }}
33 | {{- end }}
34 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_traefik.github.io/charts/traefik/20.8.0/templates/tlsoption.yaml:
--------------------------------------------------------------------------------
1 | {{- range $name, $config := .Values.tlsOptions }}
2 | apiVersion: traefik.containo.us/v1alpha1
3 | kind: TLSOption
4 | metadata:
5 | name: {{ $name }}
6 | namespace: {{ template "traefik.namespace" $ }}
7 | labels:
8 | {{- include "traefik.labels" $ | nindent 4 }}
9 | spec:
10 | {{- toYaml $config | nindent 2 }}
11 | ---
12 | {{- end -}}
13 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.helm-charts/https_traefik.github.io/charts/traefik/20.8.0/templates/tlsstore.yaml:
--------------------------------------------------------------------------------
1 | {{- range $name, $config := .Values.tlsStore }}
2 | apiVersion: traefik.containo.us/v1alpha1
3 | kind: TLSStore
4 | metadata:
5 | name: {{ $name }}
6 | namespace: {{ template "traefik.namespace" $ }}
7 | labels:
8 | {{- include "traefik.labels" $ | nindent 4 }}
9 | spec:
10 | {{- toYaml $config | nindent 2 }}
11 | ---
12 | {{- end -}}
13 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/.kluctl.yaml:
--------------------------------------------------------------------------------
1 | targets:
2 | - name: staging
3 | args:
4 | environment: staging
5 | environmentType: non-prod
6 | # Adding a context to .kluctl.yaml helps prevent accidentally deploying to the wrong cluster!
7 | context: devops-directive-kubernetes-course
8 |
9 | - name: production
10 | args:
11 | environment: production
12 | environmentType: prod
13 | # Adding a context to .kluctl.yaml helps prevent accidentally deploying to the wrong cluster!
14 | context: gke_kubernetes-course-424917_us-central1-a_devops-directive-kubernetes-course-2
15 |
16 | args:
17 | - name: environment
18 | - name: environmentType
19 |
20 | discriminator: kluctl-{{ target.name }}
21 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sidpalas/devops-directive-kubernetes-course/18d4bcfac1818609dfc2e9e82d0affd77e0e7c47/12-deploying-to-multiple-environments/kluctl/README.md
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | tasks:
4 | helm-pull:
5 | cmds:
6 | - kluctl helm-pull
7 | desc: "Pre-pull helm charts"
8 |
9 | render-staging:
10 | cmds:
11 | - kluctl render -t staging --print-all | yq
12 | desc: "Render resource yaml with staging values"
13 |
14 | deploy-staging:
15 | cmds:
16 | - kluctl deploy -t staging
17 | desc: "Deploy staging configuration"
18 |
19 | delete-staging:
20 | cmds:
21 | - kluctl delete -t staging
22 | desc: "Render resource yaml with staging values"
23 |
24 | render-production:
25 | cmds:
26 | - kluctl render -t production --print-all | yq
27 | desc: "Render resource yaml with production values"
28 |
29 | deploy-production:
30 | cmds:
31 | - kluctl deploy -t production
32 | desc: "Deploy production configuration"
33 |
34 | delete-production:
35 | cmds:
36 | - kluctl delete -t production
37 | desc: "Render resource yaml with production values"
38 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/config/production.yaml:
--------------------------------------------------------------------------------
1 | sharedVars:
2 | hostName: "kubernetes-course.devopsdirective.com"
3 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/config/staging.yaml:
--------------------------------------------------------------------------------
1 | sharedVars:
2 | hostName: "kubernetes-course-staging.devopsdirective.com"
3 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/deployment.yaml:
--------------------------------------------------------------------------------
1 | vars:
2 | - file: config/{{ args.environment }}.yaml
3 |
4 | deployments:
5 | - path: namespaces
6 | - barrier: true
7 | - include: third-party
8 | - barrier: true # postgres depends on cloudnative-pg being installed
9 | - include: services
10 |
11 | commonLabels:
12 | devopsdirective.com/course: "kubernetes-course"
13 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/namespaces/Namespace.demo-app.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: demo-app
5 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/namespaces/Namespace.postgres.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: postgres
5 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-golang/config/production.yaml:
--------------------------------------------------------------------------------
1 | apiGolang:
2 | version: 1.0.0 # PRODUCTION_IMAGE_TAG
3 | replicas: 2
4 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-golang/config/staging.yaml:
--------------------------------------------------------------------------------
1 | apiGolang:
2 | version: 1.0.0 # STAGING_IMAGE_TAG
3 | replicas: 1
4 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-golang/deployment.yaml:
--------------------------------------------------------------------------------
1 | vars:
2 | - file: config/{{ args.environment }}.yaml
3 |
4 | deployments:
5 | - path: manifests
6 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-golang/manifests/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | labels:
7 | app: api-golang
8 | spec:
9 | replicas: {{apiGolang.replicas}}
10 | selector:
11 | matchLabels:
12 | app: api-golang
13 | template:
14 | metadata:
15 | labels:
16 | app: api-golang
17 | spec:
18 | containers:
19 | - name: api-golang
20 | image: sidpalas/devops-directive-docker-course-api-golang:{{ apiGolang.version }}
21 | env:
22 | - name: PORT
23 | value: "8000"
24 | envFrom:
25 | - secretRef:
26 | name: api-golang-database-url
27 | ports:
28 | - containerPort: 8000
29 | protocol: TCP
30 | readinessProbe:
31 | httpGet:
32 | path: /ping
33 | port: 8000
34 | resources:
35 | limits:
36 | memory: "100Mi"
37 | requests:
38 | memory: "100Mi"
39 | cpu: "50m"
40 | securityContext:
41 | allowPrivilegeEscalation: false
42 | privileged: false
43 | securityContext:
44 | seccompProfile:
45 | type: RuntimeDefault
46 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-golang/manifests/IngressRoute.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: traefik.containo.us/v1alpha1
2 | kind: IngressRoute
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | spec:
7 | entryPoints:
8 | - web
9 | routes:
10 | - kind: Rule
11 | match: Host(`{{ sharedVars.hostName }}`) && PathPrefix(`/api/golang`)
12 | middlewares:
13 | - name: strip-api-prefixes
14 | services:
15 | - kind: Service
16 | name: api-golang
17 | port: 8080
18 | scheme: http
19 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-golang/manifests/Job.db-migrator.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: batch/v1
2 | kind: Job
3 | metadata:
4 | name: db-migrator
5 | namespace: demo-app
6 | annotations:
7 | kluctl.io/hook: pre-deploy
8 | kluctl.io/hook-weight: 2
9 | spec:
10 | template:
11 | spec:
12 | containers:
13 | - name: migrate
14 | image: sidpalas/devops-directive-kubernetes-course-db-migrator:{{ apiGolang.version }}
15 | args:
16 | - -path=/app/migrations
17 | - -database=$(DATABASE_URL)?sslmode=disable
18 | - up
19 | envFrom:
20 | - secretRef:
21 | name: db-migrator-password
22 | restartPolicy: OnFailure
23 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-golang/manifests/Middleware.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: traefik.containo.us/v1alpha1
2 | kind: Middleware
3 | metadata:
4 | name: strip-api-prefixes-golang
5 | namespace: demo-app
6 | spec:
7 | stripPrefix:
8 | forceSlash: false
9 | prefixes:
10 | - /api/golang
11 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-golang/manifests/Secret.db-migrator-password.yaml:
--------------------------------------------------------------------------------
1 | # ⛔️ DONT PUT SECRET FILES IN VCS
2 | # Creating this secret here is a bit of a hack to ensure it exists before
3 | # the db-migrator job which runs as a pre-deploy hook for api-golang
4 | apiVersion: v1
5 | kind: Secret
6 | metadata:
7 | name: db-migrator-password
8 | namespace: demo-app
9 | annotations:
10 | kluctl.io/hook: pre-deploy
11 | kluctl.io/hook-weight: 1
12 | type: Opaque
13 | stringData:
14 | DATABASE_URL: postgres://postgres:foobarbaz@cnpg-minimal-rw.postgres.svc.cluster.local:5432/postgres
15 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-golang/manifests/Secret.yml:
--------------------------------------------------------------------------------
1 | # ⛔️ DONT PUT SECRET FILES IN VCS
2 | apiVersion: v1
3 | kind: Secret
4 | type: Opaque
5 | metadata:
6 | name: api-golang-database-url
7 | namespace: demo-app
8 | stringData:
9 | DATABASE_URL: postgres://postgres:foobarbaz@cnpg-minimal-rw.postgres.svc.cluster.local:5432/postgres
10 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-golang/manifests/Service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | spec:
7 | selector:
8 | app: api-golang
9 | ports:
10 | - protocol: TCP
11 | port: 8000
12 | targetPort: 8000
13 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-node/config/production.yaml:
--------------------------------------------------------------------------------
1 | apiNode:
2 | version: 1.0.0 # PRODUCTION_IMAGE_TAG
3 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-node/config/staging.yaml:
--------------------------------------------------------------------------------
1 | apiNode:
2 | version: 1.0.0 # STAGING_IMAGE_TAG
3 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-node/deployment.yaml:
--------------------------------------------------------------------------------
1 | vars:
2 | - file: config/{{ args.environment }}.yaml
3 |
4 | deployments:
5 | - path: manifests
6 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-node/manifests/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: api-node
5 | namespace: demo-app
6 | labels:
7 | app: api-node
8 | spec:
9 | replicas: 1
10 | selector:
11 | matchLabels:
12 | app: api-node
13 | template:
14 | metadata:
15 | labels:
16 | app: api-node
17 | spec:
18 | containers:
19 | - name: api-node
20 | image: sidpalas/devops-directive-docker-course-api-node:{{ apiNode.version }}
21 | env:
22 | - name: PORT
23 | value: "3000"
24 | envFrom:
25 | - secretRef:
26 | name: api-node-database-url
27 | ports:
28 | - containerPort: 3000
29 | protocol: TCP
30 | readinessProbe:
31 | httpGet:
32 | path: /ping
33 | port: 3000
34 | resources:
35 | limits:
36 | memory: "100Mi"
37 | requests:
38 | memory: "100Mi"
39 | cpu: "50m"
40 | securityContext:
41 | allowPrivilegeEscalation: false
42 | privileged: false
43 | securityContext:
44 | seccompProfile:
45 | type: RuntimeDefault
46 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-node/manifests/IngressRoute.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: traefik.containo.us/v1alpha1
2 | kind: IngressRoute
3 | metadata:
4 | name: api-node
5 | namespace: demo-app
6 | spec:
7 | entryPoints:
8 | - web
9 | routes:
10 | - kind: Rule
11 | match: Host(`{{ sharedVars.hostName }}`) && PathPrefix(`/api/node`)
12 | middlewares:
13 | - name: strip-api-prefixes
14 | services:
15 | - kind: Service
16 | name: api-node
17 | port: 3000
18 | scheme: http
19 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-node/manifests/Middleware.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: traefik.containo.us/v1alpha1
2 | kind: Middleware
3 | metadata:
4 | name: strip-api-prefixes-node
5 | namespace: demo-app
6 | spec:
7 | stripPrefix:
8 | forceSlash: false
9 | prefixes:
10 | - /api/node
11 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-node/manifests/Secret.yaml:
--------------------------------------------------------------------------------
1 | # ⛔️ DONT PUT SECRET FILES IN VCS
2 | apiVersion: v1
3 | kind: Secret
4 | type: Opaque
5 | metadata:
6 | name: api-node-database-url
7 | namespace: demo-app
8 | stringData:
9 | DATABASE_URL: postgres://postgres:foobarbaz@cnpg-minimal-rw.postgres.svc.cluster.local:5432/postgres
10 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/api-node/manifests/Service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: api-node
5 | namespace: demo-app
6 | spec:
7 | selector:
8 | app: api-node
9 | ports:
10 | - protocol: TCP
11 | port: 3000
12 | targetPort: 3000
13 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/client-react/config/production.yaml:
--------------------------------------------------------------------------------
1 | clientReact:
2 | version: 1.0.0 # PRODUCTION_IMAGE_TAG
3 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/client-react/config/staging.yaml:
--------------------------------------------------------------------------------
1 | clientReact:
2 | version: 1.0.0 # STAGING_IMAGE_TAG
3 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/client-react/deployment.yaml:
--------------------------------------------------------------------------------
1 | vars:
2 | - file: config/{{ args.environment }}.yaml
3 |
4 | deployments:
5 | - path: manifests
6 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/client-react/manifests/IngressRoute.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: traefik.containo.us/v1alpha1
2 | kind: IngressRoute
3 | metadata:
4 | name: client-react-nginx
5 | namespace: demo-app
6 | spec:
7 | entryPoints:
8 | - web
9 | routes:
10 | - kind: Rule
11 | match: Host(`{{ sharedVars.hostName }}`)
12 | services:
13 | - kind: Service
14 | name: client-react-nginx
15 | port: 8080
16 | scheme: http
17 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/client-react/manifests/Service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: client-react-nginx
5 | namespace: demo-app
6 | spec:
7 | selector:
8 | app: client-react-nginx
9 | ports:
10 | - protocol: TCP
11 | port: 8080
12 | targetPort: 8080
13 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/deployment.yaml:
--------------------------------------------------------------------------------
1 | deployments:
2 | - include: postgres
3 | - barrier: true
4 | - include: api-golang
5 | - include: api-node
6 | - include: client-react
7 | - include: load-generator-python
8 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/load-generator-python/config/production.yaml:
--------------------------------------------------------------------------------
1 | loadGeneratorPython:
2 | version: 1.0.0 # PRODUCTION_IMAGE_TAG
3 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/load-generator-python/config/staging.yaml:
--------------------------------------------------------------------------------
1 | loadGeneratorPython:
2 | version: 1.0.0 # STAGING_IMAGE_TAG
3 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/load-generator-python/deployment.yaml:
--------------------------------------------------------------------------------
1 | vars:
2 | - file: config/{{ args.environment }}.yaml
3 |
4 | deployments:
5 | - path: manifests
6 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/load-generator-python/manifests/ConfigMap.yaml:
--------------------------------------------------------------------------------
1 | # 🚨 This is currently unused (for example purposes)
2 | # The env var is defined directly in the deployment
3 | apiVersion: v1
4 | kind: ConfigMap
5 | metadata:
6 | name: load-generator-config
7 | namespace: demo-app
8 | data:
9 | API_URL: http://api-node.demo-app.svc.cluster.local:3000
10 | # API_URL: http://api-golang.demo-app.svc.cluster.local:8080
11 | DELAY_MS: "100"
12 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/postgres/config/production.yaml:
--------------------------------------------------------------------------------
1 | postgres:
2 | instances: 2
3 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/postgres/config/staging.yaml:
--------------------------------------------------------------------------------
1 | postgres:
2 | instances: 1
3 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/postgres/deployment.yaml:
--------------------------------------------------------------------------------
1 | vars:
2 | - file: config/{{ args.environment }}.yaml
3 |
4 | deployments:
5 | - path: manifests
6 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/postgres/manifests/Cluster.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: postgresql.cnpg.io/v1
2 | kind: Cluster
3 | metadata:
4 | name: cnpg-minimal
5 | namespace: postgres
6 | spec:
7 | # You may or may not want to do this... I'm enabling for simplicity
8 | enableSuperuserAccess: true
9 | instances: {{postgres.instances}}
10 | storage:
11 | size: 1Gi
12 | superuserSecret:
13 | name: cnpg-minimal-superuser
14 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/services/postgres/manifests/Secret.yaml:
--------------------------------------------------------------------------------
1 | # ⛔️ DONT PUT SECRET FILES IN VCS
2 | apiVersion: v1
3 | kind: Secret
4 | type: kubernetes.io/basic-auth
5 | metadata:
6 | name: cnpg-minimal-superuser
7 | namespace: postgres
8 | stringData:
9 | password: foobarbaz
10 | user: postgres
11 | username: postgres
12 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/third-party/cloudnative-pg/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: cnpg-system
5 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/third-party/cloudnative-pg/helm-chart.yaml:
--------------------------------------------------------------------------------
1 | helmChart:
2 | repo: https://cloudnative-pg.github.io/charts
3 | chartName: cloudnative-pg
4 | chartVersion: 0.21.4
5 | releaseName: cnpg
6 | namespace: cnpg-system
7 | output: helm-rendered.yaml
8 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/third-party/cloudnative-pg/helm-values.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sidpalas/devops-directive-kubernetes-course/18d4bcfac1818609dfc2e9e82d0affd77e0e7c47/12-deploying-to-multiple-environments/kluctl/third-party/cloudnative-pg/helm-values.yaml
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/third-party/cloudnative-pg/kustomization.yaml:
--------------------------------------------------------------------------------
1 | resources:
2 | - Namespace.yaml
3 | - helm-rendered.yaml # generated at deploy time
4 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/third-party/deployment.yaml:
--------------------------------------------------------------------------------
1 | deployments:
2 | - path: traefik
3 | - path: cloudnative-pg
4 | waitReadiness: true
5 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/third-party/traefik/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: traefik
5 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/third-party/traefik/helm-chart.yaml:
--------------------------------------------------------------------------------
1 | helmChart:
2 | repo: https://traefik.github.io/charts
3 | chartName: traefik
4 | chartVersion: 20.8.0
5 | releaseName: traefik
6 | namespace: traefik
7 | output: helm-rendered.yaml
8 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/third-party/traefik/helm-values.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sidpalas/devops-directive-kubernetes-course/18d4bcfac1818609dfc2e9e82d0affd77e0e7c47/12-deploying-to-multiple-environments/kluctl/third-party/traefik/helm-values.yaml
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kluctl/third-party/traefik/kustomization.yaml:
--------------------------------------------------------------------------------
1 | resources:
2 | - Namespace.yaml
3 | - helm-rendered.yaml # generated at deploy time
4 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | tasks:
4 | render-staging:
5 | desc: "Render staging configuration"
6 | cmds:
7 | - kubectl kustomize ./staging | yq
8 |
9 | render-production:
10 | desc: "Render production configuration"
11 | cmds:
12 | - kubectl kustomize ./production | yq
13 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/api-golang/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | labels:
7 | app: api-golang
8 | spec:
9 | replicas: 1
10 | selector:
11 | matchLabels:
12 | app: api-golang
13 | template:
14 | metadata:
15 | labels:
16 | app: api-golang
17 | spec:
18 | containers:
19 | - name: api-golang
20 | image: sidpalas/devops-directive-docker-course-api-golang:foobarbaz
21 | env:
22 | - name: PORT
23 | value: "8000"
24 | envFrom:
25 | - secretRef:
26 | name: api-golang-database-url
27 | ports:
28 | - containerPort: 8000
29 | protocol: TCP
30 | readinessProbe:
31 | httpGet:
32 | path: /ping
33 | port: 8000
34 | resources:
35 | limits:
36 | memory: "100Mi"
37 | requests:
38 | memory: "100Mi"
39 | cpu: "50m"
40 | securityContext:
41 | allowPrivilegeEscalation: false
42 | privileged: false
43 | securityContext:
44 | seccompProfile:
45 | type: RuntimeDefault
46 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/api-golang/IngressRoute.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: traefik.containo.us/v1alpha1
2 | kind: IngressRoute
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | spec:
7 | entryPoints:
8 | - web
9 | routes:
10 | - kind: Rule
11 | match: # POPULATED BY PATCH
12 | middlewares:
13 | - name: strip-api-prefixes
14 | services:
15 | - kind: Service
16 | name: api-golang
17 | port: 8080
18 | scheme: http
19 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/api-golang/Secret.yaml:
--------------------------------------------------------------------------------
1 | # ⛔️ DONT PUT SECRET FILES IN VCS
2 | apiVersion: v1
3 | kind: Secret
4 | type: Opaque
5 | metadata:
6 | name: api-golang-database-url
7 | namespace: demo-app
8 | stringData:
9 | DATABASE_URL: postgres://postgres:foobarbaz@postgres-postgresql.postgres.svc.cluster.local:5432/postgres
10 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/api-golang/Service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | spec:
7 | selector:
8 | app: api-golang
9 | ports:
10 | - protocol: TCP
11 | port: 8000
12 | targetPort: 8000
13 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/api-golang/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - Deployment.yaml
6 | - IngressRoute.yaml
7 | - Secret.yaml
8 | - Service.yaml
9 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/api-node/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: api-node
5 | namespace: demo-app
6 | labels:
7 | app: api-node
8 | spec:
9 | replicas: 1
10 | selector:
11 | matchLabels:
12 | app: api-node
13 | template:
14 | metadata:
15 | labels:
16 | app: api-node
17 | spec:
18 | containers:
19 | - name: api-node
20 | image: sidpalas/devops-directive-docker-course-api-node:foobarbaz
21 | env:
22 | - name: PORT
23 | value: "3000"
24 | envFrom:
25 | - secretRef:
26 | name: api-node-database-url
27 | ports:
28 | - containerPort: 3000
29 | protocol: TCP
30 | readinessProbe:
31 | httpGet:
32 | path: /ping
33 | port: 3000
34 | resources:
35 | limits:
36 | memory: "100Mi"
37 | requests:
38 | memory: "100Mi"
39 | cpu: "50m"
40 | securityContext:
41 | allowPrivilegeEscalation: false
42 | privileged: false
43 | securityContext:
44 | seccompProfile:
45 | type: RuntimeDefault
46 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/api-node/IngressRoute.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: traefik.containo.us/v1alpha1
2 | kind: IngressRoute
3 | metadata:
4 | name: api-node
5 | namespace: demo-app
6 | spec:
7 | entryPoints:
8 | - web
9 | routes:
10 | - kind: Rule
11 | match: # POPULATED BY PATCH
12 | middlewares:
13 | - name: strip-api-prefixes
14 | services:
15 | - kind: Service
16 | name: api-node
17 | port: 3000
18 | scheme: http
19 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/api-node/Secret.yaml:
--------------------------------------------------------------------------------
1 | # ⛔️ DONT PUT SECRET FILES IN VCS
2 | apiVersion: v1
3 | kind: Secret
4 | type: Opaque
5 | metadata:
6 | name: api-node-database-url
7 | namespace: demo-app
8 | stringData:
9 | DATABASE_URL: postgres://postgres:foobarbaz@postgres-postgresql.postgres.svc.cluster.local:5432/postgres
10 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/api-node/Service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: api-node
5 | namespace: demo-app
6 | spec:
7 | selector:
8 | app: api-node
9 | ports:
10 | - protocol: TCP
11 | port: 3000
12 | targetPort: 3000
13 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/api-node/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - Deployment.yaml
6 | - IngressRoute.yaml
7 | - Secret.yaml
8 | - Service.yaml
9 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/client-react/IngressRoute.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: traefik.containo.us/v1alpha1
2 | kind: IngressRoute
3 | metadata:
4 | name: client-react-nginx
5 | namespace: demo-app
6 | spec:
7 | entryPoints:
8 | - web
9 | routes:
10 | - kind: Rule
11 | match: # POPULATED BY PATCH
12 | services:
13 | - kind: Service
14 | name: client-react-nginx
15 | port: 8080
16 | scheme: http
17 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/client-react/Service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: client-react-nginx
5 | namespace: demo-app
6 | spec:
7 | selector:
8 | app: client-react-nginx
9 | ports:
10 | - protocol: TCP
11 | port: 8080
12 | targetPort: 8080
13 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/client-react/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - ConfigMap.yaml
6 | - Deployment.yaml
7 | - IngressRoute.yaml
8 | - Service.yaml
9 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/common/Middleware.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: traefik.containo.us/v1alpha1
2 | kind: Middleware
3 | metadata:
4 | name: strip-api-prefixes
5 | namespace: demo-app
6 | spec:
7 | stripPrefix:
8 | forceSlash: false
9 | prefixes:
10 | - /api/node
11 | - /api/golang
12 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/common/Namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: demo-app
5 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/common/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - Namespace.yaml
6 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - api-golang
6 | - api-node
7 | - client-react
8 | - common
9 | - load-generator-python
10 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/load-generator-python/ConfigMap.yaml:
--------------------------------------------------------------------------------
1 | # 🚨 This is currently unused (for example purposes)
2 | # The env var is defined directly in the deployment
3 | apiVersion: v1
4 | kind: ConfigMap
5 | metadata:
6 | name: load-generator-config
7 | namespace: demo-app
8 | data:
9 | API_URL: http://api-node.demo-app.svc.cluster.local:3000
10 | # API_URL: http://api-golang.demo-app.svc.cluster.local:8080
11 | DELAY_MS: "100"
12 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/base/load-generator-python/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - ConfigMap.yaml
6 | - Deployment.yaml
7 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/production/api-golang/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - ../../base/api-golang/
6 | patches:
7 | - path: ./patches/Deployment.yaml
8 | - path: ./patches/IngressRoute.replace-host.yaml
9 | target:
10 | group: traefik.containo.us
11 | kind: IngressRoute
12 | name: api-golang
13 | namespace: demo-app
14 | version: v1alpha1
15 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/production/api-golang/patches/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | spec:
7 | replicas: 2
8 | template:
9 | spec:
10 | containers:
11 | - name: api-golang
12 | image: sidpalas/devops-directive-docker-course-api-golang:PRODUCTION_VERSION
13 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/production/api-golang/patches/IngressRoute.replace-host.yaml:
--------------------------------------------------------------------------------
1 | - op: replace
2 | path: /spec/routes/0/match
3 | value: "Host(`kubernetes-course.devopsdirective.com`) && PathPrefix(`/api/golang`)"
4 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/production/api-node/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - ../../base/api-node/
6 | patches:
7 | - path: ./patches/Deployment.yaml
8 | - path: ./patches/IngressRoute.replace-host.yaml
9 | target:
10 | group: traefik.containo.us
11 | kind: IngressRoute
12 | name: api-node
13 | namespace: demo-app
14 | version: v1alpha1
15 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/production/api-node/patches/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: api-node
5 | namespace: demo-app
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: api-node
11 | image: sidpalas/devops-directive-docker-course-api-node:PRODUCTION_VERSION
12 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/production/api-node/patches/IngressRoute.replace-host.yaml:
--------------------------------------------------------------------------------
1 | - op: replace
2 | path: /spec/routes/0/match
3 | value: "Host(`kubernetes-course.devopsdirective.com`) && PathPrefix(`/api/node`)"
4 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/production/client-react/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - ../../base/client-react/
6 | patches:
7 | - path: ./patches/Deployment.yaml
8 | - path: ./patches/IngressRoute.replace-host.yaml
9 | target:
10 | group: traefik.containo.us
11 | kind: IngressRoute
12 | name: client-react-nginx
13 | namespace: demo-app
14 | version: v1alpha1
15 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/production/client-react/patches/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: client-react-nginx
5 | namespace: demo-app
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: client-react-nginx
11 | image: sidpalas/devops-directive-docker-course-client-react-nginx:PRODUCTION_VERSION
12 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/production/client-react/patches/IngressRoute.replace-host.yaml:
--------------------------------------------------------------------------------
1 | - op: replace
2 | path: /spec/routes/0/match
3 | value: "Host(`kubernetes-course.devopsdirective.com`)"
4 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/production/common/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - ../../base/common/
6 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/production/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - api-golang
6 | - api-node
7 | - client-react
8 | - common
9 | - load-generator-python
10 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/production/load-generator-python/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - ../../base/load-generator-python/
6 | patches:
7 | - path: ./patches/Deployment.yaml
8 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/production/load-generator-python/patches/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: load-generator-python
5 | namespace: demo-app
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: load-generator
11 | image: sidpalas/devops-directive-kubernetes-course-load-generator-python:PRODUCTION_VERSION
12 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/staging/api-golang/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - ../../base/api-golang/
6 | patches:
7 | - path: ./patches/Deployment.yaml
8 | - path: ./patches/IngressRoute.replace-host.yaml
9 | target:
10 | group: traefik.containo.us
11 | kind: IngressRoute
12 | name: api-golang
13 | namespace: demo-app
14 | version: v1alpha1
15 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/staging/api-golang/patches/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: api-golang
5 | namespace: demo-app
6 | spec:
7 | replicas: 1
8 | template:
9 | spec:
10 | containers:
11 | - name: api-golang
12 | image: sidpalas/devops-directive-docker-course-api-golang:STAGING_VERSION
13 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/staging/api-golang/patches/IngressRoute.replace-host.yaml:
--------------------------------------------------------------------------------
1 | - op: replace
2 | path: /spec/routes/0/match
3 | value: "Host(`kubernetes-course-staging.devopsdirective.com`) && PathPrefix(`/api/golang`)"
4 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/staging/api-node/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - ../../base/api-node/
6 | patches:
7 | - path: ./patches/Deployment.yaml
8 | - path: ./patches/IngressRoute.replace-host.yaml
9 | target:
10 | group: traefik.containo.us
11 | kind: IngressRoute
12 | name: api-node
13 | namespace: demo-app
14 | version: v1alpha1
15 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/staging/api-node/patches/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: api-node
5 | namespace: demo-app
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: api-node
11 | image: sidpalas/devops-directive-docker-course-api-node:STAGING_VERSION
12 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/staging/api-node/patches/IngressRoute.replace-host.yaml:
--------------------------------------------------------------------------------
1 | - op: replace
2 | path: /spec/routes/0/match
3 | value: "Host(`kubernetes-course-staging.devopsdirective.com`) && PathPrefix(`/api/node`)"
4 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/staging/client-react/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - ../../base/client-react/
6 | patches:
7 | - path: ./patches/Deployment.yaml
8 | - path: ./patches/IngressRoute.replace-host.yaml
9 | target:
10 | group: traefik.containo.us
11 | kind: IngressRoute
12 | name: client-react-nginx
13 | namespace: demo-app
14 | version: v1alpha1
15 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/staging/client-react/patches/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: client-react-nginx
5 | namespace: demo-app
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: client-react-nginx
11 | image: sidpalas/devops-directive-docker-course-client-react-nginx:STAGING_VERSION
12 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/staging/client-react/patches/IngressRoute.replace-host.yaml:
--------------------------------------------------------------------------------
1 | - op: replace
2 | path: /spec/routes/0/match
3 | value: "Host(`kubernetes-course-staging.devopsdirective.com`)"
4 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/staging/common/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - ../../base/common/
6 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/staging/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - api-golang
6 | - api-node
7 | - client-react
8 | - common
9 | - load-generator-python
10 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/staging/load-generator-python/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: demo-app
4 | resources:
5 | - ../../base/load-generator-python/
6 | patches:
7 | - path: ./patches/Deployment.yaml
8 |
--------------------------------------------------------------------------------
/12-deploying-to-multiple-environments/kustomize/staging/load-generator-python/patches/Deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: load-generator-python
5 | namespace: demo-app
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: load-generator
11 | image: sidpalas/devops-directive-kubernetes-course-load-generator-python:STAGING_VERSION
12 |
--------------------------------------------------------------------------------
/14-cicd/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | includes:
4 | github-actions:
5 | taskfile: ./github-actions/Taskfile.yaml
6 | dir: ./github-actions
7 |
8 | kluctl-gitops:
9 | taskfile: ./kluctl-gitops/Taskfile.yaml
10 | dir: ./kluctl-gitops
11 |
--------------------------------------------------------------------------------
/14-cicd/kluctl-gitops/.kluctl.yaml:
--------------------------------------------------------------------------------
1 | # .kluctl.yaml
2 | targets:
3 | - name: staging
4 | args:
5 | cluster_name: staging
6 | # Adding a context to .kluctl.yaml helps prevent accidentally deploying to the wrong cluster!
7 | context: devops-directive-kubernetes-course
8 |
9 | - name: production
10 | args:
11 | cluster_name: production
12 | # Adding a context to .kluctl.yaml helps prevent accidentally deploying to the wrong cluster!
13 | context: gke_kubernetes-course-424917_us-central1-a_devops-directive-kubernetes-course-2
14 |
15 | args:
16 | # This allows us to deploy the GitOps deployment to different clusters. It is used to include dedicated deployment
17 | # items for the selected cluster.
18 | - name: cluster_name
19 |
20 | # Without a discriminator, pruning won't work. Make sure the rendered result is unique on the target cluster
21 | discriminator: gitops-{{ args.cluster_name | slugify }}
22 |
--------------------------------------------------------------------------------
/14-cicd/kluctl-gitops/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | tasks:
4 | deploy-staging-cluster:
5 | desc: "Deploy kluctl gitops staging target"
6 | cmds:
7 | - kluctl deploy -t staging
8 |
9 | deploy-production-cluster:
10 | desc: "Deploy kluctl gitops production target"
11 | cmds:
12 | - kluctl deploy -t production
13 |
14 | get-webui-password:
15 | desc: "Get password for kluctl web ui admin user"
16 | cmds:
17 | - kubectl -n kluctl-system get secret webui-secret -o jsonpath='{.data.admin-password}' | base64 -d
18 |
19 | port-forward-webui:
20 | desc: "Port forward web UI to localhost"
21 | cmds:
22 | - kubectl -n kluctl-system port-forward svc/kluctl-webui 8080
23 |
--------------------------------------------------------------------------------
/14-cicd/kluctl-gitops/clusters/all/KluctlDeployment.gitops.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gitops.kluctl.io/v1beta1
2 | kind: KluctlDeployment
3 | metadata:
4 | name: gitops
5 | namespace: kluctl-gitops
6 | spec:
7 | interval: 5m
8 | source:
9 | git:
10 | url: https://github.com/sidpalas/devops-directive-kubernetes-course.git
11 | path: 14-cicd/kluctl-gitops
12 | target: {{args.cluster_name}}
13 | args:
14 | # this passes the cluster_name initially passed via `kluctl deploy -a cluster_name=xxx.example.com` into the KluctlDeployment
15 | cluster_name: {{args.cluster_name}}
16 | context: default
17 | # let it automatically clean up orphan KluctlDeployment resources
18 | prune: true
19 | delete: true
20 |
--------------------------------------------------------------------------------
/14-cicd/kluctl-gitops/clusters/deployment.yaml:
--------------------------------------------------------------------------------
1 | # clusters/deployment.yaml
2 | deployments:
3 | - git:
4 | url: https://github.com/kluctl/kluctl.git
5 | subDir: install/controller
6 | ref:
7 | tag: v2.24.1
8 | - git:
9 | url: https://github.com/kluctl/kluctl.git
10 | subDir: install/webui
11 | ref:
12 | tag: v2.24.1
13 | - barrier: true
14 | # Include things that are required on all clusters (e.g., the KluctlDeployment for the GitOps deployment itself)
15 | - path: all
16 | # We use simple templating to change a dedicated deployment item per cluster
17 | - path: {{args.cluster_name}}
18 |
--------------------------------------------------------------------------------
/14-cicd/kluctl-gitops/clusters/production/KluctlDeployment.devops-directive-kubernetes-course.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gitops.kluctl.io/v1beta1
2 | kind: KluctlDeployment
3 | metadata:
4 | name: demo-app
5 | namespace: kluctl-gitops
6 | spec:
7 | interval: 5m
8 | source:
9 | git:
10 | url: https://github.com/sidpalas/devops-directive-kubernetes-course.git
11 | path: 12-deploying-to-multiple-environments/kluctl
12 | target: production
13 | context: default
14 | # let it automatically clean up orphan KluctlDeployment resources
15 | prune: true
16 | delete: true
17 |
--------------------------------------------------------------------------------
/14-cicd/kluctl-gitops/clusters/staging/KluctlDeployment.devops-directive-kubernetes-course.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gitops.kluctl.io/v1beta1
2 | kind: KluctlDeployment
3 | metadata:
4 | name: demo-app
5 | namespace: kluctl-gitops
6 | spec:
7 | interval: 5m
8 | source:
9 | git:
10 | url: https://github.com/sidpalas/devops-directive-kubernetes-course.git
11 | path: 12-deploying-to-multiple-environments/kluctl
12 | target: staging
13 | context: default
14 | # let it automatically clean up orphan KluctlDeployment resources
15 | prune: true
16 | delete: true
17 |
--------------------------------------------------------------------------------
/14-cicd/kluctl-gitops/deployment.yaml:
--------------------------------------------------------------------------------
1 | # deployment.yaml
2 | deployments:
3 | - path: namespaces
4 | - barrier: true
5 | - include: clusters
6 |
--------------------------------------------------------------------------------
/14-cicd/kluctl-gitops/namespaces/Namespace.kluctl-gitops.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: kluctl-gitops
5 |
--------------------------------------------------------------------------------
/14-cicd/kluctl-gitops/namespaces/Namespace.kluctl-system.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: kluctl-system
5 |
--------------------------------------------------------------------------------
/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | includes:
4 | setup:
5 | taskfile: ./03-installation-and-setup/Taskfile.yaml
6 | dir: ./03-installation-and-setup
7 |
--------------------------------------------------------------------------------
/devbox.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.10.7/.schema/devbox.schema.json",
3 | "packages": [
4 | "act@latest",
5 | "civo@latest",
6 | "envsubst@latest",
7 | "gh@latest",
8 | "go-task@latest",
9 | "go@latest",
10 | "gum@latest",
11 | "jq@latest",
12 | "k9s@latest",
13 | "kind@latest",
14 | "kluctl@latest",
15 | "ko@latest",
16 | "kubectl@latest",
17 | "kubectx@latest",
18 | "kubent@latest",
19 | "kubernetes-helm@latest",
20 | "kustomize@latest",
21 | "nodejs_20@latest",
22 | "oras@latest",
23 | "path:gcloud#google-cloud-sdk",
24 | "poetry@latest",
25 | "procps",
26 | "python312@latest",
27 | "tilt@latest",
28 | "yq-go@latest"
29 | ],
30 | "shell": {
31 | "init_hook": [
32 | "export GOBIN=$(git rev-parse --show-toplevel)/bin",
33 | "export PATH=$GOBIN:$PATH",
34 | "go install sigs.k8s.io/cloud-provider-kind@v0.2.0"
35 | ],
36 | "scripts": {
37 | "test": ["echo \"Error: no test specified\" && exit 1"]
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/gcloud/flake.nix:
--------------------------------------------------------------------------------
1 | {
2 | description = "Google Cloud SDK with GKE auth plugin";
3 |
4 | inputs = {
5 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
6 | flake-utils.url = "github:numtide/flake-utils";
7 | };
8 |
9 | outputs = { self, nixpkgs, flake-utils}:
10 | flake-utils.lib.eachDefaultSystem (system:
11 | let
12 | pkgs = import nixpkgs {
13 | inherit system;
14 | };
15 | in {
16 | packages = {
17 | google-cloud-sdk = pkgs.google-cloud-sdk.withExtraComponents [pkgs.google-cloud-sdk.components.gke-gcloud-auth-plugin];
18 | };
19 | }
20 | );
21 | }
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | ./06-demo-application/load-generator-python/pyproject.toml
--------------------------------------------------------------------------------
/readme-assets/thumbnail.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sidpalas/devops-directive-kubernetes-course/18d4bcfac1818609dfc2e9e82d0affd77e0e7c47/readme-assets/thumbnail.jpg
--------------------------------------------------------------------------------