├── .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 | ![broken-demo.png](readme-assets/broken-demo.png) 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 --------------------------------------------------------------------------------