├── .gitignore ├── LICENSE ├── README.md ├── assets └── youtube-art.png └── lessons ├── 008 ├── Dockerfile.alpine ├── Dockerfile.scratch ├── README.md └── main.go ├── 009 ├── Dockerfile ├── README.md ├── deployment.yaml ├── eksctl-cluster.yaml ├── ingress.yaml ├── main.go └── service.yaml ├── 010 ├── REAME.md ├── deployment.yaml ├── ingress.yaml └── service.yaml ├── 011 ├── README.md ├── eksctl-cluster.yaml ├── sample-app.yaml └── values.yaml ├── 012 ├── README.md ├── eksctl-cluster.yaml ├── ingress-nginx │ ├── admission-webhooks │ │ ├── clusterrole.yaml │ │ ├── clusterrolebinding.yaml │ │ ├── job-createSecret.yaml │ │ ├── job-patchWebhook.yaml │ │ ├── role.yaml │ │ ├── rolebinding.yaml │ │ ├── serviceaccount.yaml │ │ └── validating-webhook.yaml │ ├── clusterrole.yaml │ ├── clusterrolebinding.yaml │ ├── controller-configmap.yaml │ ├── controller-deployment.yaml │ ├── controller-role.yaml │ ├── controller-rolebinding.yaml │ ├── controller-service-webhook.yaml │ ├── controller-service.yaml │ ├── controller-serviceaccount.yaml │ └── namespace.yaml └── sample-app.yaml ├── 013 ├── 00-eksctl │ └── eksctl-cluster.yaml ├── 01-prometheus-operator-crd │ ├── monitoring.coreos.com_alertmanagerconfigs.yaml │ ├── monitoring.coreos.com_alertmanagers.yaml │ ├── monitoring.coreos.com_podmonitors.yaml │ ├── monitoring.coreos.com_probes.yaml │ ├── monitoring.coreos.com_prometheuses.yaml │ ├── monitoring.coreos.com_prometheusrules.yaml │ ├── monitoring.coreos.com_servicemonitors.yaml │ ├── monitoring.coreos.com_thanosrulers.yaml │ └── prometheus-operator-crd-cluster-roles.yaml ├── 02-prometheus-operator │ ├── prometheus-operator-cluster-role-binding.yaml │ ├── prometheus-operator-cluster-role.yaml │ ├── prometheus-operator-deployment.yaml │ ├── prometheus-operator-service-account.yaml │ ├── prometheus-operator-service-monitor.yaml │ └── prometheus-operator-service.yaml ├── 03-prometheus │ ├── prometheus-cluster-role-binding.yaml │ ├── prometheus-cluster-role.yaml │ ├── prometheus-service-account.yaml │ ├── prometheus.yaml │ └── service.yaml ├── 04-ingress-nginx │ ├── admission-webhooks │ │ ├── clusterrole.yaml │ │ ├── clusterrolebinding.yaml │ │ ├── job-createSecret.yaml │ │ ├── job-patchWebhook.yaml │ │ ├── role.yaml │ │ ├── rolebinding.yaml │ │ ├── serviceaccount.yaml │ │ └── validating-webhook.yaml │ ├── clusterrole.yaml │ ├── clusterrolebinding.yaml │ ├── controller-configmap.yaml │ ├── controller-deployment.yaml │ ├── controller-role.yaml │ ├── controller-rolebinding.yaml │ ├── controller-service-prometheus.yaml │ ├── controller-service-webhook.yaml │ ├── controller-service.yaml │ ├── controller-serviceaccount.yaml │ └── namespace.yaml ├── 05-servicemonitor │ └── service-monitor.yaml ├── 06-grafana │ ├── configmap.yaml │ ├── deployment.yaml │ ├── rbac.yaml │ ├── secret.yaml │ └── service.yaml ├── 07-sample-app │ ├── deployment.yaml │ ├── ingress.yaml │ └── service.yaml └── README.md ├── 015 └── main.tf ├── 016 └── main.tf ├── 017 └── README.md ├── 018 └── main.tf ├── 019 └── main.tf ├── 023 ├── app │ ├── .helmignore │ ├── Chart.yaml │ ├── templates │ │ ├── NOTES.txt │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── hpa.yaml │ │ ├── ingress.yaml │ │ ├── service.yaml │ │ ├── serviceaccount.yaml │ │ └── tests │ │ │ └── test-connection.yaml │ └── values.yaml └── eksctl-cluster.yaml ├── 024 └── hello-world │ ├── .helmignore │ ├── Chart.yaml │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── deployment.yaml │ ├── hpa.yaml │ ├── ingress.yaml │ ├── service.yaml │ ├── serviceaccount.yaml │ └── tests │ │ └── test-connection.yaml │ └── values.yaml └── 025 ├── app ├── .helmignore ├── Chart.yaml ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── deployment.yaml │ ├── hpa.yaml │ ├── ingress.yaml │ ├── secrets.yaml │ ├── service.yaml │ ├── serviceaccount.yaml │ └── tests │ │ └── test-connection.yaml └── values.yaml └── secrets.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # .tfstate files 5 | *.tfstate 6 | *.tfstate.* 7 | 8 | # Crash log files 9 | crash.log 10 | 11 | # Exclude all .tfvars files, which are likely to contain sentitive data, such as 12 | # password, private keys, and other secrets. These should not be part of version 13 | # control as they are data points which are potentially sensitive and subject 14 | # to change depending on the environment. 15 | # 16 | *.tfvars 17 | 18 | # Ignore override files as they are usually used to override resources locally and so 19 | # are not checked in 20 | override.tf 21 | override.tf.json 22 | *_override.tf 23 | *_override.tf.json 24 | 25 | # Include override files you do wish to add to version control using negated pattern 26 | # 27 | # !example_override.tf 28 | 29 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 30 | # example: *tfplan* 31 | 32 | # Ignore CLI configuration files 33 | .terraformrc 34 | terraform.rc 35 | 36 | backlog 37 | *.tgz 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 devops-by-example 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tutorials 2 | ![YouTube Art](assets/youtube-art.png?raw=true "Title") 3 | 4 | ### SOCIAL 5 | 🎥 - [YouTube](https://youtube.com/channel/UCeLvlbC754U6FyFQbKc0UnQ?view_as=subscriber) 6 | 👥 - [Facebook](https://www.facebook.com/profile.php?id=100037229408982) 7 | -------------------------------------------------------------------------------- /assets/youtube-art.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devops-by-example/tutorials/929ba6809bd4ac3d30766413dc7c5e0889d051c0/assets/youtube-art.png -------------------------------------------------------------------------------- /lessons/008/Dockerfile.alpine: -------------------------------------------------------------------------------- 1 | FROM golang:1.14.9-alpine3.12 2 | 3 | WORKDIR /app 4 | 5 | COPY main.go . 6 | 7 | RUN CGO_ENABLED=0 GOOS=linux go build -o main . 8 | 9 | CMD ["/app/main"] 10 | -------------------------------------------------------------------------------- /lessons/008/Dockerfile.scratch: -------------------------------------------------------------------------------- 1 | FROM golang:1.14.9-alpine3.12 as build 2 | 3 | WORKDIR /app 4 | 5 | COPY main.go . 6 | 7 | RUN CGO_ENABLED=0 GOOS=linux go build -o main . 8 | 9 | FROM scratch 10 | 11 | COPY --from=build /app/main /main 12 | 13 | CMD ["/main"] 14 | -------------------------------------------------------------------------------- /lessons/008/README.md: -------------------------------------------------------------------------------- 1 | ### Build docker based on alpine 2 | 3 | ```bash 4 | docker build -t app:alpine -f Dockerfile.alpine . 5 | docker run --rm -p 8081:8081 app:alpine 6 | ``` 7 | 8 | ### Build docker based on scratch 9 | 10 | ```bash 11 | docker build -t app:scratch -f Dockerfile.scratch . 12 | docker run --rm -p 8081:8081 app:scratch 13 | ``` 14 | -------------------------------------------------------------------------------- /lessons/008/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "html" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | func main() { 11 | 12 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 13 | fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) 14 | }) 15 | 16 | http.HandleFunc("/hi", func(w http.ResponseWriter, r *http.Request) { 17 | fmt.Fprintf(w, "Hi") 18 | }) 19 | 20 | log.Println("Starting web server on 8081 port.") 21 | log.Fatal(http.ListenAndServe(":8081", nil)) 22 | } 23 | -------------------------------------------------------------------------------- /lessons/009/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.14.9-alpine3.12 as build 2 | 3 | WORKDIR /app 4 | 5 | COPY main.go . 6 | 7 | RUN CGO_ENABLED=0 GOOS=linux go build -o main . 8 | 9 | FROM scratch 10 | 11 | COPY --from=build /app/main /main 12 | 13 | CMD ["/main"] 14 | -------------------------------------------------------------------------------- /lessons/009/README.md: -------------------------------------------------------------------------------- 1 | # Nginx ingress controller kubernetes 2 | 3 | ### Plan for video 4 | 1. Create EKS cluster 5 | 2. Initialize Helm 3 6 | 3. Install NGINX ingress controller 7 | 4. Deploy our simple golang application 8 | 4. Destroy EKS cluster 9 | 10 | ### Create EKS cluster 11 | ```bash 12 | $ cd 009 13 | $ eksctl create cluster -f eksctl-cluster.yaml 14 | ``` 15 | 16 | ### Initialize Helm 3 on your Kubernetes cluster (add a chart repository) 17 | ```bash 18 | $ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx 19 | ``` 20 | 21 | ### Install NGINX ingress 22 | ```bash 23 | $ helm repo update 24 | $ helm install ingress-nginx/ingress-nginx --generate-name 25 | ``` 26 | 27 | ### Build golang app 28 | ```bash 29 | $ docker build -t app:v0.1.0 -f Dockerfile . 30 | $ docker tag app:v0.1.0 .dkr.ecr.us-east-1.amazonaws.com/app:v0.1.0 31 | $ aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin .dkr.ecr.us-east-1.amazonaws.com 32 | $ docker push .dkr.ecr.us-east-1.amazonaws.com/app:v0.1.0 33 | ``` 34 | 35 | ### Deploy our app to kubernetes 36 | ```bash 37 | $ kubectl apply -f deployment.yaml 38 | $ kubectl apply -f service.yaml 39 | $ kubectl get endpoints 40 | $ kubectl apply -f ingress.yaml 41 | ``` 42 | 43 | ### Create CNAME or A record based on your kubernetes provider 44 | ```bash 45 | api CNAME ab367a7323d7548b6803200859d023b8-1085326791.us-east-1.elb.amazonaws.com 46 | $ nslookup api. 47 | $ curl api./hello 48 | ``` 49 | 50 | ### Delete EKS cluster 51 | ```bash 52 | $ eksctl delete cluster -f eksctl-cluster.yaml 53 | ``` -------------------------------------------------------------------------------- /lessons/009/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: app-deployment 5 | labels: 6 | app: app 7 | spec: 8 | replicas: 2 9 | selector: 10 | matchLabels: 11 | app: app 12 | template: 13 | metadata: 14 | labels: 15 | app: app 16 | spec: 17 | containers: 18 | - name: app 19 | image: 424432388155.dkr.ecr.us-east-1.amazonaws.com/app:v0.1.0 20 | ports: 21 | - containerPort: 8081 22 | -------------------------------------------------------------------------------- /lessons/009/eksctl-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: eksctl.io/v1alpha5 2 | kind: ClusterConfig 3 | 4 | metadata: 5 | name: devops-by-example-v2 6 | region: us-east-1 7 | 8 | nodeGroups: 9 | - name: nodes-general 10 | labels: 11 | role: workers 12 | instanceType: t2.small 13 | desiredCapacity: 1 14 | volumeSize: 20 15 | -------------------------------------------------------------------------------- /lessons/009/ingress.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1beta1 2 | kind: Ingress 3 | metadata: 4 | name: app-ingress 5 | namespace: default 6 | annotations: 7 | kubernetes.io/ingress.class: nginx 8 | spec: 9 | rules: 10 | - host: api.devopsbyexample.io 11 | http: 12 | paths: 13 | - backend: 14 | serviceName: app-service 15 | servicePort: 8081 16 | path: / 17 | -------------------------------------------------------------------------------- /lessons/009/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "html" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | func main() { 11 | 12 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 13 | fmt.Fprintf(w, "Hello from NGINX ingress, %q", html.EscapeString(r.URL.Path)) 14 | }) 15 | 16 | http.HandleFunc("/hi", func(w http.ResponseWriter, r *http.Request) { 17 | fmt.Fprintf(w, "Hi") 18 | }) 19 | 20 | log.Println("Starting web server on 8081 port.") 21 | log.Fatal(http.ListenAndServe(":8081", nil)) 22 | } 23 | -------------------------------------------------------------------------------- /lessons/009/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: app-service 5 | spec: 6 | selector: 7 | app: app 8 | ports: 9 | - port: 8081 10 | -------------------------------------------------------------------------------- /lessons/010/REAME.md: -------------------------------------------------------------------------------- 1 | # Nginx Ingress Controller Minikube 2 | 3 | ### Create Minikube Cluster 4 | ```bash 5 | $ minikube start --vm=true 6 | ``` 7 | 8 | ### Enable the NGINX Ingress controller 9 | ```bash 10 | $ minikube addons enable ingress 11 | ``` 12 | 13 | ### Verify that the NGINX Ingress controller is running 14 | ```bash 15 | $ kubectl get pods -n kube-system 16 | ``` 17 | 18 | ### Create hello-world deployment 19 | ```bash 20 | $ kubectl apply -f 010/deployment.yaml 21 | ``` 22 | 23 | ### Create hello-world service 24 | ```bash 25 | $ kubectl apply -f 010/service.yaml 26 | ``` 27 | 28 | ### Create hello-world ingress 29 | ```bash 30 | $ kubectl apply -f 010/ingress.yaml 31 | ``` 32 | 33 | ### Install dnsmasq 34 | ```bash 35 | $ brew install dnsmasq 36 | ``` 37 | 38 | ### Start dnsmasq 39 | ```bash 40 | $ sudo brew services start dnsmasq 41 | ``` 42 | 43 | ### Get minikube IP for service 44 | ```bash 45 | $ minikube service hello-app-service --url 46 | ``` 47 | 48 | ### Configure dnsmasq 49 | ```bash 50 | cat << EOF > /usr/local/etc/dnsmasq.d/development.conf 51 | address=/.pvt/192.168.64.4 52 | EOF 53 | ``` 54 | 55 | ### Restart dnsmasq 56 | ```bash 57 | $ sudo brew services restart dnsmasq 58 | ``` 59 | 60 | ### Only send .pvt queries to dnsmasq 61 | ```bash 62 | sudo mkdir /etc/resolver 63 | sudo vim /etc/resolver/pvt 64 | nameserver 127.0.0.1 65 | ``` 66 | 67 | ### Check resolvers 68 | ```bash 69 | scutil --dns 70 | ``` 71 | 72 | ### Test DNS name 73 | ```bash 74 | $ dig hello-world.pvt @127.0.0.1 75 | ``` 76 | 77 | ### Cleanup 78 | ```bash 79 | $ minikube delete 80 | ``` 81 | -------------------------------------------------------------------------------- /lessons/010/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | namespace: default 6 | name: hello-app-deployment 7 | labels: 8 | app: hello-app 9 | spec: 10 | replicas: 2 11 | selector: 12 | matchLabels: 13 | app: hello-app 14 | template: 15 | metadata: 16 | labels: 17 | app: hello-app 18 | spec: 19 | containers: 20 | - name: hello-app 21 | image: gcr.io/google-samples/hello-app:1.0 22 | ports: 23 | - containerPort: 8080 24 | -------------------------------------------------------------------------------- /lessons/010/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | namespace: default 6 | name: hello-world-ingress 7 | annotations: 8 | nginx.ingress.kubernetes.io/rewrite-target: /$1 9 | spec: 10 | rules: 11 | - host: hello-world.pvt 12 | http: 13 | paths: 14 | - path: / 15 | pathType: Prefix 16 | backend: 17 | service: 18 | name: hello-app-service 19 | port: 20 | number: 8080 21 | -------------------------------------------------------------------------------- /lessons/010/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | namespace: default 6 | name: hello-app-service 7 | spec: 8 | type: NodePort 9 | selector: 10 | app: hello-app 11 | ports: 12 | - protocol: TCP 13 | port: 8080 14 | -------------------------------------------------------------------------------- /lessons/011/README.md: -------------------------------------------------------------------------------- 1 | # Nginx Ingress Controller Helm 2 | 3 | ### Create Kubernetes Cluster on AWS 4 | ```bash 5 | $ eksctl create cluster -f 011/eksctl-cluster.yaml 6 | ``` 7 | 8 | ### Get values file from 9 | ```bash 10 | https://github.com/kubernetes/ingress-nginx/tree/master/charts/ingress-nginx 11 | ``` 12 | ### Initialize a Helm Chart Repository 13 | 14 | ```bash 15 | $ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx 16 | ``` 17 | 18 | ### Install Nginx Ingress Helm Chart 19 | ```bash 20 | $ helm install sample-ingress ingress-nginx/ingress-nginx -f 011/values.yaml 21 | ``` 22 | 23 | ### Deploy Sample App 24 | ```bash 25 | $ kubectl apply -f 011/sample-app.yaml 26 | ``` 27 | 28 | ### Verify DNS 29 | ```bash 30 | $ dig +short www.devopsbyexample.io 31 | ``` 32 | 33 | ### Clean Up 34 | ```bash 35 | $ helm repo remove ingress-nginx 36 | $ eksctl delete cluster -f 011/eksctl-cluster.yaml 37 | ``` -------------------------------------------------------------------------------- /lessons/011/eksctl-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: eksctl.io/v1alpha5 2 | kind: ClusterConfig 3 | 4 | metadata: 5 | name: devops-by-example-v4 6 | region: us-east-1 7 | 8 | nodeGroups: 9 | - name: nodes-general 10 | labels: 11 | role: workers 12 | instanceType: t2.small 13 | desiredCapacity: 1 14 | volumeSize: 20 15 | -------------------------------------------------------------------------------- /lessons/011/sample-app.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | namespace: default 6 | name: hello-app-deployment 7 | labels: 8 | app: hello-app 9 | spec: 10 | replicas: 2 11 | selector: 12 | matchLabels: 13 | app: hello-app 14 | template: 15 | metadata: 16 | labels: 17 | app: hello-app 18 | spec: 19 | containers: 20 | - name: hello-app 21 | image: gcr.io/google-samples/hello-app:1.0 22 | ports: 23 | - containerPort: 8080 24 | --- 25 | apiVersion: v1 26 | kind: Service 27 | metadata: 28 | namespace: default 29 | name: hello-app-service 30 | spec: 31 | type: NodePort 32 | selector: 33 | app: hello-app 34 | ports: 35 | - protocol: TCP 36 | port: 8080 37 | --- 38 | apiVersion: networking.k8s.io/v1beta1 39 | kind: Ingress 40 | metadata: 41 | annotations: 42 | kubernetes.io/ingress.class: sample-nginx 43 | name: hello-app 44 | namespace: default 45 | spec: 46 | rules: 47 | - host: www.devopsbyexample.io 48 | http: 49 | paths: 50 | - backend: 51 | serviceName: hello-app-service 52 | servicePort: 8080 53 | path: / 54 | -------------------------------------------------------------------------------- /lessons/011/values.yaml: -------------------------------------------------------------------------------- 1 | ## nginx configuration 2 | ## Ref: https://github.com/kubernetes/ingress-nginx/blob/master/controllers/nginx/configuration.md 3 | ## 4 | controller: 5 | image: 6 | repository: k8s.gcr.io/ingress-nginx/controller 7 | tag: "v0.40.2" 8 | digest: sha256:46ba23c3fbaafd9e5bd01ea85b2f921d9f2217be082580edc22e6c704a83f02f 9 | pullPolicy: IfNotPresent 10 | # www-data -> uid 101 11 | runAsUser: 101 12 | allowPrivilegeEscalation: true 13 | 14 | # Configures the ports the nginx-controller listens on 15 | containerPort: 16 | http: 80 17 | https: 443 18 | 19 | # Will add custom configuration options to Nginx https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/ 20 | config: {} 21 | 22 | ## Annotations to be added to the controller config configuration configmap 23 | ## 24 | configAnnotations: {} 25 | 26 | # Will add custom headers before sending traffic to backends according to https://github.com/kubernetes/ingress-nginx/tree/master/docs/examples/customization/custom-headers 27 | proxySetHeaders: {} 28 | 29 | # Will add custom headers before sending response traffic to the client according to: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#add-headers 30 | addHeaders: {} 31 | 32 | # Optionally customize the pod dnsConfig. 33 | dnsConfig: {} 34 | 35 | # Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'. 36 | # By default, while using host network, name resolution uses the host's DNS. If you wish nginx-controller 37 | # to keep resolving names inside the k8s network, use ClusterFirstWithHostNet. 38 | dnsPolicy: ClusterFirst 39 | 40 | # Bare-metal considerations via the host network https://kubernetes.github.io/ingress-nginx/deploy/baremetal/#via-the-host-network 41 | # Ingress status was blank because there is no Service exposing the NGINX Ingress controller in a configuration using the host network, the default --publish-service flag used in standard cloud setups does not apply 42 | reportNodeInternalIp: false 43 | 44 | # Required for use with CNI based kubernetes installations (such as ones set up by kubeadm), 45 | # since CNI and hostport don't mix yet. Can be deprecated once https://github.com/kubernetes/kubernetes/issues/23920 46 | # is merged 47 | hostNetwork: false 48 | 49 | ## Use host ports 80 and 443 50 | ## Disabled by default 51 | ## 52 | hostPort: 53 | enabled: false 54 | ports: 55 | http: 80 56 | https: 443 57 | 58 | ## Election ID to use for status update 59 | ## 60 | electionID: ingress-controller-leader 61 | 62 | ## Name of the ingress class to route through this controller 63 | ## 64 | ingressClass: sample-nginx 65 | 66 | # labels to add to the pod container metadata 67 | podLabels: {} 68 | # key: value 69 | 70 | ## Security Context policies for controller pods 71 | ## 72 | podSecurityContext: {} 73 | 74 | ## See https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/ for 75 | ## notes on enabling and using sysctls 76 | ### 77 | sysctls: {} 78 | # sysctls: 79 | # "net.core.somaxconn": "8192" 80 | 81 | ## Allows customization of the source of the IP address or FQDN to report 82 | ## in the ingress status field. By default, it reads the information provided 83 | ## by the service. If disable, the status field reports the IP address of the 84 | ## node or nodes where an ingress controller pod is running. 85 | publishService: 86 | enabled: true 87 | ## Allows overriding of the publish service to bind to 88 | ## Must be / 89 | ## 90 | pathOverride: "" 91 | 92 | ## Limit the scope of the controller 93 | ## 94 | scope: 95 | enabled: false 96 | namespace: "" # defaults to .Release.Namespace 97 | 98 | ## Allows customization of the configmap / nginx-configmap namespace 99 | ## 100 | configMapNamespace: "" # defaults to .Release.Namespace 101 | 102 | ## Allows customization of the tcp-services-configmap 103 | ## 104 | tcp: 105 | configMapNamespace: "" # defaults to .Release.Namespace 106 | ## Annotations to be added to the tcp config configmap 107 | annotations: {} 108 | 109 | ## Allows customization of the udp-services-configmap 110 | ## 111 | udp: 112 | configMapNamespace: "" # defaults to .Release.Namespace 113 | ## Annotations to be added to the udp config configmap 114 | annotations: {} 115 | 116 | ## Additional command line arguments to pass to nginx-ingress-controller 117 | ## E.g. to specify the default SSL certificate you can use 118 | ## extraArgs: 119 | ## default-ssl-certificate: "/" 120 | extraArgs: {} 121 | 122 | ## Additional environment variables to set 123 | extraEnvs: [] 124 | # extraEnvs: 125 | # - name: FOO 126 | # valueFrom: 127 | # secretKeyRef: 128 | # key: FOO 129 | # name: secret-resource 130 | 131 | ## DaemonSet or Deployment 132 | ## 133 | kind: Deployment 134 | 135 | ## Annotations to be added to the controller Deployment or DaemonSet 136 | ## 137 | annotations: {} 138 | # keel.sh/pollSchedule: "@every 60m" 139 | 140 | ## Labels to be added to the controller Deployment or DaemonSet 141 | ## 142 | labels: {} 143 | # keel.sh/policy: patch 144 | # keel.sh/trigger: poll 145 | 146 | 147 | # The update strategy to apply to the Deployment or DaemonSet 148 | ## 149 | updateStrategy: {} 150 | # rollingUpdate: 151 | # maxUnavailable: 1 152 | # type: RollingUpdate 153 | 154 | # minReadySeconds to avoid killing pods before we are ready 155 | ## 156 | minReadySeconds: 0 157 | 158 | 159 | ## Node tolerations for server scheduling to nodes with taints 160 | ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ 161 | ## 162 | tolerations: [] 163 | # - key: "key" 164 | # operator: "Equal|Exists" 165 | # value: "value" 166 | # effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)" 167 | 168 | ## Affinity and anti-affinity 169 | ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity 170 | ## 171 | affinity: {} 172 | # # An example of preferred pod anti-affinity, weight is in the range 1-100 173 | # podAntiAffinity: 174 | # preferredDuringSchedulingIgnoredDuringExecution: 175 | # - weight: 100 176 | # podAffinityTerm: 177 | # labelSelector: 178 | # matchExpressions: 179 | # - key: app.kubernetes.io/name 180 | # operator: In 181 | # values: 182 | # - ingress-nginx 183 | # - key: app.kubernetes.io/instance 184 | # operator: In 185 | # values: 186 | # - ingress-nginx 187 | # - key: app.kubernetes.io/component 188 | # operator: In 189 | # values: 190 | # - controller 191 | # topologyKey: kubernetes.io/hostname 192 | 193 | # # An example of required pod anti-affinity 194 | # podAntiAffinity: 195 | # requiredDuringSchedulingIgnoredDuringExecution: 196 | # - labelSelector: 197 | # matchExpressions: 198 | # - key: app.kubernetes.io/name 199 | # operator: In 200 | # values: 201 | # - ingress-nginx 202 | # - key: app.kubernetes.io/instance 203 | # operator: In 204 | # values: 205 | # - ingress-nginx 206 | # - key: app.kubernetes.io/component 207 | # operator: In 208 | # values: 209 | # - controller 210 | # topologyKey: "kubernetes.io/hostname" 211 | 212 | ## Topology spread constraints rely on node labels to identify the topology domain(s) that each Node is in. 213 | ## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ 214 | ## 215 | topologySpreadConstraints: [] 216 | # - maxSkew: 1 217 | # topologyKey: failure-domain.beta.kubernetes.io/zone 218 | # whenUnsatisfiable: DoNotSchedule 219 | # labelSelector: 220 | # matchLabels: 221 | # app.kubernetes.io/instance: ingress-nginx-internal 222 | 223 | ## terminationGracePeriodSeconds 224 | ## wait up to five minutes for the drain of connections 225 | ## 226 | terminationGracePeriodSeconds: 300 227 | 228 | ## Node labels for controller pod assignment 229 | ## Ref: https://kubernetes.io/docs/user-guide/node-selection/ 230 | ## 231 | nodeSelector: 232 | kubernetes.io/os: linux 233 | 234 | ## Liveness and readiness probe values 235 | ## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes 236 | ## 237 | livenessProbe: 238 | failureThreshold: 5 239 | initialDelaySeconds: 10 240 | periodSeconds: 10 241 | successThreshold: 1 242 | timeoutSeconds: 1 243 | port: 10254 244 | readinessProbe: 245 | failureThreshold: 3 246 | initialDelaySeconds: 10 247 | periodSeconds: 10 248 | successThreshold: 1 249 | timeoutSeconds: 1 250 | port: 10254 251 | 252 | # Path of the health check endpoint. All requests received on the port defined by 253 | # the healthz-port parameter are forwarded internally to this path. 254 | healthCheckPath: "/healthz" 255 | 256 | ## Annotations to be added to controller pods 257 | ## 258 | podAnnotations: {} 259 | 260 | replicaCount: 1 261 | 262 | minAvailable: 1 263 | 264 | # Define requests resources to avoid probe issues due to CPU utilization in busy nodes 265 | # ref: https://github.com/kubernetes/ingress-nginx/issues/4735#issuecomment-551204903 266 | # Ideally, there should be no limits. 267 | # https://engineering.indeedblog.com/blog/2019/12/cpu-throttling-regression-fix/ 268 | resources: 269 | # limits: 270 | # cpu: 100m 271 | # memory: 90Mi 272 | requests: 273 | cpu: 100m 274 | memory: 90Mi 275 | 276 | autoscaling: 277 | enabled: false 278 | minReplicas: 1 279 | maxReplicas: 11 280 | targetCPUUtilizationPercentage: 50 281 | targetMemoryUtilizationPercentage: 50 282 | 283 | autoscalingTemplate: [] 284 | # Custom or additional autoscaling metrics 285 | # ref: https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#support-for-custom-metrics 286 | # - type: Pods 287 | # pods: 288 | # metric: 289 | # name: nginx_ingress_controller_nginx_process_requests_total 290 | # target: 291 | # type: AverageValue 292 | # averageValue: 10000m 293 | 294 | ## Enable mimalloc as a drop-in replacement for malloc. 295 | ## ref: https://github.com/microsoft/mimalloc 296 | ## 297 | enableMimalloc: true 298 | 299 | ## Override NGINX template 300 | customTemplate: 301 | configMapName: "" 302 | configMapKey: "" 303 | 304 | service: 305 | enabled: true 306 | 307 | annotations: {} 308 | labels: {} 309 | # clusterIP: "" 310 | 311 | ## List of IP addresses at which the controller services are available 312 | ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips 313 | ## 314 | externalIPs: [] 315 | 316 | # loadBalancerIP: "" 317 | loadBalancerSourceRanges: [] 318 | 319 | enableHttp: true 320 | enableHttps: true 321 | 322 | ## Set external traffic policy to: "Local" to preserve source IP on 323 | ## providers supporting it 324 | ## Ref: https://kubernetes.io/docs/tutorials/services/source-ip/#source-ip-for-services-with-typeloadbalancer 325 | # externalTrafficPolicy: "" 326 | 327 | # Must be either "None" or "ClientIP" if set. Kubernetes will default to "None". 328 | # Ref: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies 329 | # sessionAffinity: "" 330 | 331 | # specifies the health check node port (numeric port number) for the service. If healthCheckNodePort isn’t specified, 332 | # the service controller allocates a port from your cluster’s NodePort range. 333 | # Ref: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip 334 | # healthCheckNodePort: 0 335 | 336 | ports: 337 | http: 80 338 | https: 443 339 | 340 | targetPorts: 341 | http: http 342 | https: https 343 | 344 | type: LoadBalancer 345 | 346 | # type: NodePort 347 | # nodePorts: 348 | # http: 32080 349 | # https: 32443 350 | # tcp: 351 | # 8080: 32808 352 | nodePorts: 353 | http: "" 354 | https: "" 355 | tcp: {} 356 | udp: {} 357 | 358 | ## Enables an additional internal load balancer (besides the external one). 359 | ## Annotations are mandatory for the load balancer to come up. Varies with the cloud service. 360 | internal: 361 | enabled: false 362 | annotations: {} 363 | 364 | ## Set external traffic policy to: "Local" to preserve source IP on 365 | ## providers supporting it 366 | ## Ref: https://kubernetes.io/docs/tutorials/services/source-ip/#source-ip-for-services-with-typeloadbalancer 367 | # externalTrafficPolicy: "" 368 | 369 | extraContainers: [] 370 | ## Additional containers to be added to the controller pod. 371 | ## See https://github.com/lemonldap-ng-controller/lemonldap-ng-controller as example. 372 | # - name: my-sidecar 373 | # image: nginx:latest 374 | # - name: lemonldap-ng-controller 375 | # image: lemonldapng/lemonldap-ng-controller:0.2.0 376 | # args: 377 | # - /lemonldap-ng-controller 378 | # - --alsologtostderr 379 | # - --configmap=$(POD_NAMESPACE)/lemonldap-ng-configuration 380 | # env: 381 | # - name: POD_NAME 382 | # valueFrom: 383 | # fieldRef: 384 | # fieldPath: metadata.name 385 | # - name: POD_NAMESPACE 386 | # valueFrom: 387 | # fieldRef: 388 | # fieldPath: metadata.namespace 389 | # volumeMounts: 390 | # - name: copy-portal-skins 391 | # mountPath: /srv/var/lib/lemonldap-ng/portal/skins 392 | 393 | extraVolumeMounts: [] 394 | ## Additional volumeMounts to the controller main container. 395 | # - name: copy-portal-skins 396 | # mountPath: /var/lib/lemonldap-ng/portal/skins 397 | 398 | extraVolumes: [] 399 | ## Additional volumes to the controller pod. 400 | # - name: copy-portal-skins 401 | # emptyDir: {} 402 | 403 | extraInitContainers: [] 404 | ## Containers, which are run before the app containers are started. 405 | # - name: init-myservice 406 | # image: busybox 407 | # command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;'] 408 | 409 | admissionWebhooks: 410 | annotations: {} 411 | enabled: true 412 | failurePolicy: Fail 413 | # timeoutSeconds: 10 414 | port: 8443 415 | certificate: "/usr/local/certificates/cert" 416 | key: "/usr/local/certificates/key" 417 | namespaceSelector: {} 418 | objectSelector: {} 419 | 420 | service: 421 | annotations: {} 422 | # clusterIP: "" 423 | externalIPs: [] 424 | # loadBalancerIP: "" 425 | loadBalancerSourceRanges: [] 426 | servicePort: 443 427 | type: ClusterIP 428 | 429 | patch: 430 | enabled: true 431 | image: 432 | repository: docker.io/jettech/kube-webhook-certgen 433 | tag: v1.3.0 434 | pullPolicy: IfNotPresent 435 | ## Provide a priority class name to the webhook patching job 436 | ## 437 | priorityClassName: "" 438 | podAnnotations: {} 439 | nodeSelector: {} 440 | tolerations: [] 441 | runAsUser: 2000 442 | 443 | metrics: 444 | port: 10254 445 | # if this port is changed, change healthz-port: in extraArgs: accordingly 446 | enabled: false 447 | 448 | service: 449 | annotations: {} 450 | # prometheus.io/scrape: "true" 451 | # prometheus.io/port: "10254" 452 | 453 | # clusterIP: "" 454 | 455 | ## List of IP addresses at which the stats-exporter service is available 456 | ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips 457 | ## 458 | externalIPs: [] 459 | 460 | # loadBalancerIP: "" 461 | loadBalancerSourceRanges: [] 462 | servicePort: 9913 463 | type: ClusterIP 464 | # externalTrafficPolicy: "" 465 | # nodePort: "" 466 | 467 | serviceMonitor: 468 | enabled: false 469 | additionalLabels: {} 470 | namespace: "" 471 | namespaceSelector: {} 472 | # Default: scrape .Release.Namespace only 473 | # To scrape all, use the following: 474 | # namespaceSelector: 475 | # any: true 476 | scrapeInterval: 30s 477 | # honorLabels: true 478 | targetLabels: [] 479 | metricRelabelings: [] 480 | 481 | prometheusRule: 482 | enabled: false 483 | additionalLabels: {} 484 | # namespace: "" 485 | rules: [] 486 | # # These are just examples rules, please adapt them to your needs 487 | # - alert: NGINXConfigFailed 488 | # expr: count(nginx_ingress_controller_config_last_reload_successful == 0) > 0 489 | # for: 1s 490 | # labels: 491 | # severity: critical 492 | # annotations: 493 | # description: bad ingress config - nginx config test failed 494 | # summary: uninstall the latest ingress changes to allow config reloads to resume 495 | # - alert: NGINXCertificateExpiry 496 | # expr: (avg(nginx_ingress_controller_ssl_expire_time_seconds) by (host) - time()) < 604800 497 | # for: 1s 498 | # labels: 499 | # severity: critical 500 | # annotations: 501 | # description: ssl certificate(s) will expire in less then a week 502 | # summary: renew expiring certificates to avoid downtime 503 | # - alert: NGINXTooMany500s 504 | # expr: 100 * ( sum( nginx_ingress_controller_requests{status=~"5.+"} ) / sum(nginx_ingress_controller_requests) ) > 5 505 | # for: 1m 506 | # labels: 507 | # severity: warning 508 | # annotations: 509 | # description: Too many 5XXs 510 | # summary: More than 5% of all requests returned 5XX, this requires your attention 511 | # - alert: NGINXTooMany400s 512 | # expr: 100 * ( sum( nginx_ingress_controller_requests{status=~"4.+"} ) / sum(nginx_ingress_controller_requests) ) > 5 513 | # for: 1m 514 | # labels: 515 | # severity: warning 516 | # annotations: 517 | # description: Too many 4XXs 518 | # summary: More than 5% of all requests returned 4XX, this requires your attention 519 | 520 | ## Improve connection draining when ingress controller pod is deleted using a lifecycle hook: 521 | ## With this new hook, we increased the default terminationGracePeriodSeconds from 30 seconds 522 | ## to 300, allowing the draining of connections up to five minutes. 523 | ## If the active connections end before that, the pod will terminate gracefully at that time. 524 | ## To effectively take advantage of this feature, the Configmap feature 525 | ## worker-shutdown-timeout new value is 240s instead of 10s. 526 | ## 527 | lifecycle: 528 | preStop: 529 | exec: 530 | command: 531 | - /wait-shutdown 532 | 533 | priorityClassName: "" 534 | 535 | ## Rollback limit 536 | ## 537 | revisionHistoryLimit: 10 538 | 539 | # Maxmind license key to download GeoLite2 Databases 540 | # https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-geolite2-databases 541 | maxmindLicenseKey: "" 542 | 543 | ## Default 404 backend 544 | ## 545 | defaultBackend: 546 | ## 547 | enabled: false 548 | 549 | image: 550 | repository: k8s.gcr.io/defaultbackend-amd64 551 | tag: "1.5" 552 | pullPolicy: IfNotPresent 553 | # nobody user -> uid 65534 554 | runAsUser: 65534 555 | 556 | extraArgs: {} 557 | 558 | serviceAccount: 559 | create: true 560 | name: 561 | ## Additional environment variables to set for defaultBackend pods 562 | extraEnvs: [] 563 | 564 | port: 8080 565 | 566 | ## Readiness and liveness probes for default backend 567 | ## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/ 568 | ## 569 | livenessProbe: 570 | failureThreshold: 3 571 | initialDelaySeconds: 30 572 | periodSeconds: 10 573 | successThreshold: 1 574 | timeoutSeconds: 5 575 | readinessProbe: 576 | failureThreshold: 6 577 | initialDelaySeconds: 0 578 | periodSeconds: 5 579 | successThreshold: 1 580 | timeoutSeconds: 5 581 | 582 | ## Node tolerations for server scheduling to nodes with taints 583 | ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ 584 | ## 585 | tolerations: [] 586 | # - key: "key" 587 | # operator: "Equal|Exists" 588 | # value: "value" 589 | # effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)" 590 | 591 | affinity: {} 592 | 593 | ## Security Context policies for controller pods 594 | ## See https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/ for 595 | ## notes on enabling and using sysctls 596 | ## 597 | podSecurityContext: {} 598 | 599 | # labels to add to the pod container metadata 600 | podLabels: {} 601 | # key: value 602 | 603 | ## Node labels for default backend pod assignment 604 | ## Ref: https://kubernetes.io/docs/user-guide/node-selection/ 605 | ## 606 | nodeSelector: {} 607 | 608 | ## Annotations to be added to default backend pods 609 | ## 610 | podAnnotations: {} 611 | 612 | replicaCount: 1 613 | 614 | minAvailable: 1 615 | 616 | resources: {} 617 | # limits: 618 | # cpu: 10m 619 | # memory: 20Mi 620 | # requests: 621 | # cpu: 10m 622 | # memory: 20Mi 623 | 624 | service: 625 | annotations: {} 626 | 627 | # clusterIP: "" 628 | 629 | ## List of IP addresses at which the default backend service is available 630 | ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips 631 | ## 632 | externalIPs: [] 633 | 634 | # loadBalancerIP: "" 635 | loadBalancerSourceRanges: [] 636 | servicePort: 80 637 | type: ClusterIP 638 | 639 | priorityClassName: "" 640 | 641 | ## Enable RBAC as per https://github.com/kubernetes/ingress/tree/master/examples/rbac/nginx and https://github.com/kubernetes/ingress/issues/266 642 | rbac: 643 | create: true 644 | scope: false 645 | 646 | # If true, create & use Pod Security Policy resources 647 | # https://kubernetes.io/docs/concepts/policy/pod-security-policy/ 648 | podSecurityPolicy: 649 | enabled: false 650 | 651 | serviceAccount: 652 | create: true 653 | name: 654 | 655 | ## Optional array of imagePullSecrets containing private registry credentials 656 | ## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ 657 | imagePullSecrets: [] 658 | # - name: secretName 659 | 660 | # TCP service key:value pairs 661 | # Ref: https://github.com/kubernetes/contrib/tree/master/ingress/controllers/nginx/examples/tcp 662 | ## 663 | tcp: {} 664 | # 8080: "default/example-tcp-svc:9000" 665 | 666 | # UDP service key:value pairs 667 | # Ref: https://github.com/kubernetes/contrib/tree/master/ingress/controllers/nginx/examples/udp 668 | ## 669 | udp: {} 670 | # 53: "kube-system/kube-dns:53" -------------------------------------------------------------------------------- /lessons/012/README.md: -------------------------------------------------------------------------------- 1 | # Nginx Admission Webhook | Overview and Demo 2 | 3 | 4 | ### Create namespace 5 | ```bash 6 | $ kubectl apply -f 012/ingress-nginx/namespace.yaml 7 | ``` 8 | 9 | ### Deploy Nginx Webhook 10 | ```bash 11 | $ kubectl apply -f 012/ingress-nginx/admission-webhooks 12 | ``` 13 | 14 | ### Deploy Nginx Ingress Using YAML 15 | ```bash 16 | $ kubectl apply -f 012/ingress-nginx 17 | ``` 18 | 19 | ### Check Ingress pods, service, and webhook 20 | ```bash 21 | $ kubectl get pods -n ingress 22 | $ kubectl get svc -n ingress 23 | $ kubectl get ValidatingWebhookConfiguration 24 | ``` 25 | 26 | ### Deploy Sample App 27 | ```bash 28 | $ kubectl apply -f 012/sample-app.yaml 29 | ``` 30 | 31 | ### Verify App 32 | ```bash 33 | $ kubectl get pods -n default 34 | $ kubectl get ingress -n default 35 | ``` -------------------------------------------------------------------------------- /lessons/012/eksctl-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: eksctl.io/v1alpha5 2 | kind: ClusterConfig 3 | 4 | metadata: 5 | name: devops-by-example-v5 6 | region: us-east-1 7 | 8 | nodeGroups: 9 | - name: nodes-general 10 | labels: 11 | role: workers 12 | instanceType: t2.small 13 | desiredCapacity: 2 14 | volumeSize: 20 15 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/admission-webhooks/clusterrole.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: ingress-nginx-admission 6 | labels: 7 | app.kubernetes.io/name: ingress-nginx 8 | app.kubernetes.io/component: admission-webhook 9 | rules: 10 | - apiGroups: 11 | - admissionregistration.k8s.io 12 | resources: 13 | - validatingwebhookconfigurations 14 | verbs: 15 | - get 16 | - update 17 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/admission-webhooks/clusterrolebinding.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | name: ingress-nginx-admission 6 | labels: 7 | app.kubernetes.io/name: ingress-nginx 8 | app.kubernetes.io/component: admission-webhook 9 | roleRef: 10 | apiGroup: rbac.authorization.k8s.io 11 | kind: ClusterRole 12 | name: ingress-nginx-admission 13 | subjects: 14 | - kind: ServiceAccount 15 | name: ingress-nginx-admission 16 | namespace: ingress 17 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/admission-webhooks/job-createSecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: ingress-nginx-admission-create 6 | namespace: ingress 7 | labels: 8 | app.kubernetes.io/name: ingress-nginx 9 | app.kubernetes.io/component: admission-webhook 10 | spec: 11 | template: 12 | metadata: 13 | name: ingress-nginx-admission-create 14 | labels: 15 | app.kubernetes.io/name: ingress-nginx 16 | app.kubernetes.io/component: admission-webhook 17 | spec: 18 | containers: 19 | - name: create 20 | image: "docker.io/jettech/kube-webhook-certgen:v1.3.0" 21 | imagePullPolicy: IfNotPresent 22 | args: 23 | - create 24 | - --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc 25 | - --namespace=$(POD_NAMESPACE) 26 | - --secret-name=ingress-nginx-admission 27 | env: 28 | - name: POD_NAMESPACE 29 | valueFrom: 30 | fieldRef: 31 | fieldPath: metadata.namespace 32 | restartPolicy: OnFailure 33 | serviceAccountName: ingress-nginx-admission 34 | securityContext: 35 | runAsNonRoot: true 36 | runAsUser: 2000 37 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/admission-webhooks/job-patchWebhook.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: ingress-nginx-admission-patch 6 | namespace: ingress 7 | labels: 8 | app.kubernetes.io/name: ingress-nginx 9 | app.kubernetes.io/component: admission-webhook 10 | spec: 11 | template: 12 | metadata: 13 | name: ingress-nginx-admission-patch 14 | labels: 15 | app.kubernetes.io/name: ingress-nginx 16 | app.kubernetes.io/component: admission-webhook 17 | spec: 18 | containers: 19 | - name: patch 20 | image: "docker.io/jettech/kube-webhook-certgen:v1.3.0" 21 | imagePullPolicy: IfNotPresent 22 | args: 23 | - patch 24 | - --webhook-name=ingress-nginx-admission 25 | - --namespace=$(POD_NAMESPACE) 26 | - --patch-mutating=false 27 | - --secret-name=ingress-nginx-admission 28 | - --patch-failure-policy=Fail 29 | env: 30 | - name: POD_NAMESPACE 31 | valueFrom: 32 | fieldRef: 33 | fieldPath: metadata.namespace 34 | restartPolicy: OnFailure 35 | serviceAccountName: ingress-nginx-admission 36 | securityContext: 37 | runAsNonRoot: true 38 | runAsUser: 2000 39 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/admission-webhooks/role.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: ingress-nginx-admission 6 | namespace: ingress 7 | labels: 8 | app.kubernetes.io/name: ingress-nginx 9 | app.kubernetes.io/component: admission-webhook 10 | rules: 11 | - apiGroups: 12 | - "" 13 | resources: 14 | - secrets 15 | verbs: 16 | - get 17 | - create 18 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/admission-webhooks/rolebinding.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: RoleBinding 4 | metadata: 5 | name: ingress-nginx-admission 6 | namespace: ingress 7 | labels: 8 | app.kubernetes.io/name: ingress-nginx 9 | app.kubernetes.io/component: admission-webhook 10 | roleRef: 11 | apiGroup: rbac.authorization.k8s.io 12 | kind: Role 13 | name: ingress-nginx-admission 14 | subjects: 15 | - kind: ServiceAccount 16 | name: ingress-nginx-admission 17 | namespace: ingress 18 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/admission-webhooks/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: ingress-nginx-admission 6 | namespace: ingress 7 | labels: 8 | app.kubernetes.io/name: ingress-nginx 9 | app.kubernetes.io/component: admission-webhook 10 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/admission-webhooks/validating-webhook.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: admissionregistration.k8s.io/v1 3 | kind: ValidatingWebhookConfiguration 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/component: admission-webhook 8 | name: ingress-nginx-admission 9 | namespace: ingress 10 | webhooks: 11 | - name: validate.nginx.ingress.kubernetes.io 12 | rules: 13 | - apiGroups: 14 | - networking.k8s.io 15 | apiVersions: 16 | - v1beta1 17 | - v1 18 | operations: 19 | - CREATE 20 | - UPDATE 21 | resources: 22 | - ingresses 23 | failurePolicy: Fail 24 | sideEffects: None 25 | admissionReviewVersions: 26 | - v1 27 | - v1beta1 28 | clientConfig: 29 | service: 30 | namespace: ingress 31 | name: ingress-nginx-controller-admission 32 | path: /networking/v1beta1/ingresses 33 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/clusterrole.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | name: ingress-nginx 8 | rules: 9 | - apiGroups: 10 | - "" 11 | resources: 12 | - configmaps 13 | - endpoints 14 | - nodes 15 | - pods 16 | - secrets 17 | verbs: 18 | - list 19 | - watch 20 | - apiGroups: 21 | - "" 22 | resources: 23 | - nodes 24 | verbs: 25 | - get 26 | - apiGroups: 27 | - "" 28 | resources: 29 | - services 30 | verbs: 31 | - get 32 | - list 33 | - update 34 | - watch 35 | - apiGroups: 36 | - extensions 37 | - "networking.k8s.io" # k8s 1.14+ 38 | resources: 39 | - ingresses 40 | verbs: 41 | - get 42 | - list 43 | - watch 44 | - apiGroups: 45 | - "" 46 | resources: 47 | - events 48 | verbs: 49 | - create 50 | - patch 51 | - apiGroups: 52 | - extensions 53 | - "networking.k8s.io" # k8s 1.14+ 54 | resources: 55 | - ingresses/status 56 | verbs: 57 | - update 58 | - apiGroups: 59 | - "networking.k8s.io" # k8s 1.14+ 60 | resources: 61 | - ingressclasses 62 | verbs: 63 | - get 64 | - list 65 | - watch 66 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/clusterrolebinding.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | name: ingress-nginx 8 | roleRef: 9 | apiGroup: rbac.authorization.k8s.io 10 | kind: ClusterRole 11 | name: ingress-nginx 12 | subjects: 13 | - kind: ServiceAccount 14 | name: ingress-nginx 15 | namespace: ingress 16 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/controller-configmap.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/component: controller 8 | name: ingress-nginx-controller 9 | namespace: ingress 10 | data: 11 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/controller-deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/component: controller 8 | name: ingress-nginx-controller 9 | namespace: ingress 10 | spec: 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/name: ingress-nginx 14 | app.kubernetes.io/component: controller 15 | replicas: 1 16 | revisionHistoryLimit: 10 17 | minReadySeconds: 0 18 | template: 19 | metadata: 20 | labels: 21 | app.kubernetes.io/name: ingress-nginx 22 | app.kubernetes.io/component: controller 23 | spec: 24 | dnsPolicy: ClusterFirst 25 | containers: 26 | - name: controller 27 | image: "k8s.gcr.io/ingress-nginx/controller:v0.40.2@sha256:46ba23c3fbaafd9e5bd01ea85b2f921d9f2217be082580edc22e6c704a83f02f" 28 | imagePullPolicy: IfNotPresent 29 | lifecycle: 30 | preStop: 31 | exec: 32 | command: 33 | - /wait-shutdown 34 | args: 35 | - /nginx-ingress-controller 36 | - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller 37 | - --election-id=ingress-controller-leader 38 | - --ingress-class=sample-nginx 39 | - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller 40 | - --validating-webhook=:8443 41 | - --validating-webhook-certificate=/usr/local/certificates/cert 42 | - --validating-webhook-key=/usr/local/certificates/key 43 | securityContext: 44 | capabilities: 45 | drop: 46 | - ALL 47 | add: 48 | - NET_BIND_SERVICE 49 | runAsUser: 101 50 | allowPrivilegeEscalation: true 51 | env: 52 | - name: POD_NAME 53 | valueFrom: 54 | fieldRef: 55 | fieldPath: metadata.name 56 | - name: POD_NAMESPACE 57 | valueFrom: 58 | fieldRef: 59 | fieldPath: metadata.namespace 60 | - name: LD_PRELOAD 61 | value: /usr/local/lib/libmimalloc.so 62 | livenessProbe: 63 | httpGet: 64 | path: /healthz 65 | port: 10254 66 | scheme: HTTP 67 | initialDelaySeconds: 10 68 | periodSeconds: 10 69 | timeoutSeconds: 1 70 | successThreshold: 1 71 | failureThreshold: 5 72 | readinessProbe: 73 | httpGet: 74 | path: /healthz 75 | port: 10254 76 | scheme: HTTP 77 | initialDelaySeconds: 10 78 | periodSeconds: 10 79 | timeoutSeconds: 1 80 | successThreshold: 1 81 | failureThreshold: 3 82 | ports: 83 | - name: http 84 | containerPort: 80 85 | protocol: TCP 86 | - name: https 87 | containerPort: 443 88 | protocol: TCP 89 | - name: webhook 90 | containerPort: 8443 91 | protocol: TCP 92 | volumeMounts: 93 | - name: webhook-cert 94 | mountPath: /usr/local/certificates/ 95 | readOnly: true 96 | resources: 97 | requests: 98 | cpu: 100m 99 | memory: 90Mi 100 | nodeSelector: 101 | kubernetes.io/os: linux 102 | serviceAccountName: ingress-nginx 103 | terminationGracePeriodSeconds: 300 104 | volumes: 105 | - name: webhook-cert 106 | secret: 107 | secretName: ingress-nginx-admission 108 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/controller-role.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/component: controller 8 | name: ingress-nginx 9 | namespace: ingress 10 | rules: 11 | - apiGroups: 12 | - "" 13 | resources: 14 | - namespaces 15 | verbs: 16 | - get 17 | - apiGroups: 18 | - "" 19 | resources: 20 | - configmaps 21 | - pods 22 | - secrets 23 | - endpoints 24 | verbs: 25 | - get 26 | - list 27 | - watch 28 | - apiGroups: 29 | - "" 30 | resources: 31 | - services 32 | verbs: 33 | - get 34 | - list 35 | - update 36 | - watch 37 | - apiGroups: 38 | - extensions 39 | - "networking.k8s.io" # k8s 1.14+ 40 | resources: 41 | - ingresses 42 | verbs: 43 | - get 44 | - list 45 | - watch 46 | - apiGroups: 47 | - extensions 48 | - "networking.k8s.io" # k8s 1.14+ 49 | resources: 50 | - ingresses/status 51 | verbs: 52 | - update 53 | - apiGroups: 54 | - "networking.k8s.io" # k8s 1.14+ 55 | resources: 56 | - ingressclasses 57 | verbs: 58 | - get 59 | - list 60 | - watch 61 | - apiGroups: 62 | - "" 63 | resources: 64 | - configmaps 65 | resourceNames: 66 | - ingress-controller-leader-sample-nginx 67 | verbs: 68 | - get 69 | - update 70 | - apiGroups: 71 | - "" 72 | resources: 73 | - configmaps 74 | verbs: 75 | - create 76 | - apiGroups: 77 | - "" 78 | resources: 79 | - endpoints 80 | verbs: 81 | - create 82 | - get 83 | - update 84 | - apiGroups: 85 | - "" 86 | resources: 87 | - events 88 | verbs: 89 | - create 90 | - patch 91 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/controller-rolebinding.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: RoleBinding 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/managed-by: Helm 8 | app.kubernetes.io/component: controller 9 | name: ingress-nginx 10 | namespace: ingress 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: Role 14 | name: ingress-nginx 15 | subjects: 16 | - kind: ServiceAccount 17 | name: ingress-nginx 18 | namespace: ingress 19 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/controller-service-webhook.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/component: controller 8 | name: ingress-nginx-controller-admission 9 | namespace: ingress 10 | spec: 11 | type: ClusterIP 12 | ports: 13 | - name: https-webhook 14 | port: 443 15 | targetPort: webhook 16 | selector: 17 | app.kubernetes.io/name: ingress-nginx 18 | app.kubernetes.io/component: controller 19 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/controller-service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/component: controller 8 | name: ingress-nginx-controller 9 | namespace: ingress 10 | spec: 11 | type: LoadBalancer 12 | ports: 13 | - name: http 14 | port: 80 15 | protocol: TCP 16 | targetPort: http 17 | - name: https 18 | port: 443 19 | protocol: TCP 20 | targetPort: https 21 | selector: 22 | app.kubernetes.io/name: ingress-nginx 23 | app.kubernetes.io/component: controller 24 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/controller-serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/component: controller 8 | name: ingress-nginx 9 | namespace: ingress 10 | -------------------------------------------------------------------------------- /lessons/012/ingress-nginx/namespace.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: ingress -------------------------------------------------------------------------------- /lessons/012/sample-app.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | namespace: default 6 | name: hello-app-deployment 7 | labels: 8 | app: hello-app 9 | spec: 10 | replicas: 2 11 | selector: 12 | matchLabels: 13 | app: hello-app 14 | template: 15 | metadata: 16 | labels: 17 | app: hello-app 18 | spec: 19 | containers: 20 | - name: hello-app 21 | image: gcr.io/google-samples/hello-app:1.0 22 | ports: 23 | - containerPort: 8080 24 | --- 25 | apiVersion: v1 26 | kind: Service 27 | metadata: 28 | namespace: default 29 | name: hello-app-service 30 | spec: 31 | type: NodePort 32 | selector: 33 | app: hello-app 34 | ports: 35 | - protocol: TCP 36 | port: 8080 37 | --- 38 | apiVersion: networking.k8s.io/v1beta1 39 | kind: Ingress 40 | metadata: 41 | annotations: 42 | kubernetes.io/ingress.class: sample-nginx 43 | nginx.ingress.kubernetes.io/configuration-snippet: | 44 | more_set_headers "Server: hello-app"; 45 | name: hello-app 46 | namespace: default 47 | spec: 48 | rules: 49 | - host: www.devopsbyexample.io 50 | http: 51 | paths: 52 | - backend: 53 | serviceName: hello-app-service 54 | servicePort: 8080 55 | path: / 56 | -------------------------------------------------------------------------------- /lessons/013/00-eksctl/eksctl-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: eksctl.io/v1alpha5 2 | kind: ClusterConfig 3 | metadata: 4 | name: devops-by-example-v3 5 | region: us-east-1 6 | availabilityZones: 7 | - us-east-1a 8 | - us-east-1b 9 | nodeGroups: 10 | - name: nodes-general 11 | labels: 12 | role: workers 13 | instanceType: t2.small 14 | desiredCapacity: 2 15 | volumeSize: 20 16 | -------------------------------------------------------------------------------- /lessons/013/01-prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.2.4 7 | creationTimestamp: null 8 | name: alertmanagerconfigs.monitoring.coreos.com 9 | spec: 10 | group: monitoring.coreos.com 11 | names: 12 | kind: AlertmanagerConfig 13 | listKind: AlertmanagerConfigList 14 | plural: alertmanagerconfigs 15 | singular: alertmanagerconfig 16 | scope: Namespaced 17 | versions: 18 | - name: v1alpha1 19 | schema: 20 | openAPIV3Schema: 21 | description: AlertmanagerConfig defines a namespaced AlertmanagerConfig to 22 | be aggregated across multiple namespaces configuring one Alertmanager. 23 | properties: 24 | apiVersion: 25 | description: 'APIVersion defines the versioned schema of this representation 26 | of an object. Servers should convert recognized schemas to the latest 27 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' 28 | type: string 29 | kind: 30 | description: 'Kind is a string value representing the REST resource this 31 | object represents. Servers may infer this from the endpoint the client 32 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' 33 | type: string 34 | metadata: 35 | type: object 36 | spec: 37 | properties: 38 | inhibitRules: 39 | items: 40 | properties: 41 | equal: 42 | items: 43 | type: string 44 | type: array 45 | matcher: 46 | items: 47 | properties: 48 | name: 49 | type: string 50 | regex: 51 | type: boolean 52 | value: 53 | type: string 54 | required: 55 | - name 56 | - value 57 | type: object 58 | type: array 59 | type: object 60 | type: array 61 | receivers: 62 | items: 63 | properties: 64 | name: 65 | type: string 66 | pagerDutyConfigs: 67 | items: 68 | properties: 69 | class: 70 | type: string 71 | client: 72 | type: string 73 | clientURL: 74 | type: string 75 | component: 76 | type: string 77 | description: 78 | type: string 79 | details: 80 | items: 81 | properties: 82 | key: 83 | type: string 84 | value: 85 | type: string 86 | required: 87 | - key 88 | - value 89 | type: object 90 | type: array 91 | group: 92 | type: string 93 | httpConfig: 94 | properties: 95 | basicAuth: 96 | description: 'BasicAuth allow an endpoint to authenticate 97 | over basic authentication More info: https://prometheus.io/docs/operating/configuration/#endpoints' 98 | properties: 99 | password: 100 | description: The secret in the service monitor 101 | namespace that contains the password for authentication. 102 | properties: 103 | key: 104 | description: The key of the secret to select 105 | from. Must be a valid secret key. 106 | type: string 107 | name: 108 | description: 'Name of the referent. More info: 109 | https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 110 | TODO: Add other useful fields. apiVersion, 111 | kind, uid?' 112 | type: string 113 | optional: 114 | description: Specify whether the Secret or 115 | its key must be defined 116 | type: boolean 117 | required: 118 | - key 119 | type: object 120 | username: 121 | description: The secret in the service monitor 122 | namespace that contains the username for authentication. 123 | properties: 124 | key: 125 | description: The key of the secret to select 126 | from. Must be a valid secret key. 127 | type: string 128 | name: 129 | description: 'Name of the referent. More info: 130 | https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 131 | TODO: Add other useful fields. apiVersion, 132 | kind, uid?' 133 | type: string 134 | optional: 135 | description: Specify whether the Secret or 136 | its key must be defined 137 | type: boolean 138 | required: 139 | - key 140 | type: object 141 | type: object 142 | bearerTokenSecret: 143 | description: SecretKeySelector selects a key of a 144 | Secret. 145 | properties: 146 | key: 147 | description: The key of the secret to select from. Must 148 | be a valid secret key. 149 | type: string 150 | name: 151 | description: 'Name of the referent. More info: 152 | https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 153 | TODO: Add other useful fields. apiVersion, kind, 154 | uid?' 155 | type: string 156 | optional: 157 | description: Specify whether the Secret or its 158 | key must be defined 159 | type: boolean 160 | required: 161 | - key 162 | type: object 163 | proxyURL: 164 | type: string 165 | tlsConfig: 166 | description: SafeTLSConfig specifies safe TLS configuration 167 | parameters. 168 | properties: 169 | ca: 170 | description: Struct containing the CA cert to 171 | use for the targets. 172 | properties: 173 | configMap: 174 | description: ConfigMap containing data to 175 | use for the targets. 176 | properties: 177 | key: 178 | description: The key to select. 179 | type: string 180 | name: 181 | description: 'Name of the referent. More 182 | info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 183 | TODO: Add other useful fields. apiVersion, 184 | kind, uid?' 185 | type: string 186 | optional: 187 | description: Specify whether the ConfigMap 188 | or its key must be defined 189 | type: boolean 190 | required: 191 | - key 192 | type: object 193 | secret: 194 | description: Secret containing data to use 195 | for the targets. 196 | properties: 197 | key: 198 | description: The key of the secret to 199 | select from. Must be a valid secret 200 | key. 201 | type: string 202 | name: 203 | description: 'Name of the referent. More 204 | info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 205 | TODO: Add other useful fields. apiVersion, 206 | kind, uid?' 207 | type: string 208 | optional: 209 | description: Specify whether the Secret 210 | or its key must be defined 211 | type: boolean 212 | required: 213 | - key 214 | type: object 215 | type: object 216 | cert: 217 | description: Struct containing the client cert 218 | file for the targets. 219 | properties: 220 | configMap: 221 | description: ConfigMap containing data to 222 | use for the targets. 223 | properties: 224 | key: 225 | description: The key to select. 226 | type: string 227 | name: 228 | description: 'Name of the referent. More 229 | info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 230 | TODO: Add other useful fields. apiVersion, 231 | kind, uid?' 232 | type: string 233 | optional: 234 | description: Specify whether the ConfigMap 235 | or its key must be defined 236 | type: boolean 237 | required: 238 | - key 239 | type: object 240 | secret: 241 | description: Secret containing data to use 242 | for the targets. 243 | properties: 244 | key: 245 | description: The key of the secret to 246 | select from. Must be a valid secret 247 | key. 248 | type: string 249 | name: 250 | description: 'Name of the referent. More 251 | info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 252 | TODO: Add other useful fields. apiVersion, 253 | kind, uid?' 254 | type: string 255 | optional: 256 | description: Specify whether the Secret 257 | or its key must be defined 258 | type: boolean 259 | required: 260 | - key 261 | type: object 262 | type: object 263 | insecureSkipVerify: 264 | description: Disable target certificate validation. 265 | type: boolean 266 | keySecret: 267 | description: Secret containing the client key 268 | file for the targets. 269 | properties: 270 | key: 271 | description: The key of the secret to select 272 | from. Must be a valid secret key. 273 | type: string 274 | name: 275 | description: 'Name of the referent. More info: 276 | https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 277 | TODO: Add other useful fields. apiVersion, 278 | kind, uid?' 279 | type: string 280 | optional: 281 | description: Specify whether the Secret or 282 | its key must be defined 283 | type: boolean 284 | required: 285 | - key 286 | type: object 287 | serverName: 288 | description: Used to verify the hostname for the 289 | targets. 290 | type: string 291 | type: object 292 | type: object 293 | routingKey: 294 | description: SecretKeySelector selects a key of a Secret. 295 | properties: 296 | key: 297 | description: The key of the secret to select from. Must 298 | be a valid secret key. 299 | type: string 300 | name: 301 | description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 302 | TODO: Add other useful fields. apiVersion, kind, 303 | uid?' 304 | type: string 305 | optional: 306 | description: Specify whether the Secret or its key 307 | must be defined 308 | type: boolean 309 | required: 310 | - key 311 | type: object 312 | sendResolved: 313 | type: boolean 314 | serviceKey: 315 | description: SecretKeySelector selects a key of a Secret. 316 | properties: 317 | key: 318 | description: The key of the secret to select from. Must 319 | be a valid secret key. 320 | type: string 321 | name: 322 | description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 323 | TODO: Add other useful fields. apiVersion, kind, 324 | uid?' 325 | type: string 326 | optional: 327 | description: Specify whether the Secret or its key 328 | must be defined 329 | type: boolean 330 | required: 331 | - key 332 | type: object 333 | severity: 334 | type: string 335 | url: 336 | type: string 337 | type: object 338 | type: array 339 | required: 340 | - name 341 | type: object 342 | type: array 343 | route: 344 | properties: 345 | continue: 346 | type: boolean 347 | groupBy: 348 | items: 349 | type: string 350 | type: array 351 | groupInterval: 352 | type: string 353 | groupWait: 354 | type: string 355 | matchers: 356 | items: 357 | properties: 358 | name: 359 | type: string 360 | regex: 361 | type: boolean 362 | value: 363 | type: string 364 | required: 365 | - name 366 | - value 367 | type: object 368 | type: array 369 | receiver: 370 | type: string 371 | repeatInterval: 372 | type: string 373 | routes: 374 | items: 375 | type: object 376 | type: array 377 | type: object 378 | type: object 379 | required: 380 | - spec 381 | type: object 382 | served: true 383 | storage: true 384 | status: 385 | acceptedNames: 386 | kind: "" 387 | plural: "" 388 | conditions: [] 389 | storedVersions: [] -------------------------------------------------------------------------------- /lessons/013/01-prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.2.4 7 | creationTimestamp: null 8 | name: podmonitors.monitoring.coreos.com 9 | spec: 10 | group: monitoring.coreos.com 11 | names: 12 | kind: PodMonitor 13 | listKind: PodMonitorList 14 | plural: podmonitors 15 | singular: podmonitor 16 | scope: Namespaced 17 | versions: 18 | - name: v1 19 | schema: 20 | openAPIV3Schema: 21 | description: PodMonitor defines monitoring for a set of pods. 22 | properties: 23 | apiVersion: 24 | description: 'APIVersion defines the versioned schema of this representation 25 | of an object. Servers should convert recognized schemas to the latest 26 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' 27 | type: string 28 | kind: 29 | description: 'Kind is a string value representing the REST resource this 30 | object represents. Servers may infer this from the endpoint the client 31 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' 32 | type: string 33 | metadata: 34 | type: object 35 | spec: 36 | description: Specification of desired Pod selection for target discovery 37 | by Prometheus. 38 | properties: 39 | jobLabel: 40 | description: The label to use to retrieve the job name from. 41 | type: string 42 | namespaceSelector: 43 | description: Selector to select which namespaces the Endpoints objects 44 | are discovered from. 45 | properties: 46 | any: 47 | description: Boolean describing whether all namespaces are selected 48 | in contrast to a list restricting them. 49 | type: boolean 50 | matchNames: 51 | description: List of namespace names. 52 | items: 53 | type: string 54 | type: array 55 | type: object 56 | podMetricsEndpoints: 57 | description: A list of endpoints allowed as part of this PodMonitor. 58 | items: 59 | description: PodMetricsEndpoint defines a scrapeable endpoint of 60 | a Kubernetes Pod serving Prometheus metrics. 61 | properties: 62 | basicAuth: 63 | description: 'BasicAuth allow an endpoint to authenticate over 64 | basic authentication. More info: https://prometheus.io/docs/operating/configuration/#endpoint' 65 | properties: 66 | password: 67 | description: The secret in the service monitor namespace 68 | that contains the password for authentication. 69 | properties: 70 | key: 71 | description: The key of the secret to select from. Must 72 | be a valid secret key. 73 | type: string 74 | name: 75 | description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 76 | TODO: Add other useful fields. apiVersion, kind, uid?' 77 | type: string 78 | optional: 79 | description: Specify whether the Secret or its key must 80 | be defined 81 | type: boolean 82 | required: 83 | - key 84 | type: object 85 | username: 86 | description: The secret in the service monitor namespace 87 | that contains the username for authentication. 88 | properties: 89 | key: 90 | description: The key of the secret to select from. Must 91 | be a valid secret key. 92 | type: string 93 | name: 94 | description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 95 | TODO: Add other useful fields. apiVersion, kind, uid?' 96 | type: string 97 | optional: 98 | description: Specify whether the Secret or its key must 99 | be defined 100 | type: boolean 101 | required: 102 | - key 103 | type: object 104 | type: object 105 | bearerTokenSecret: 106 | description: Secret to mount to read bearer token for scraping 107 | targets. The secret needs to be in the same namespace as the 108 | pod monitor and accessible by the Prometheus Operator. 109 | properties: 110 | key: 111 | description: The key of the secret to select from. Must 112 | be a valid secret key. 113 | type: string 114 | name: 115 | description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 116 | TODO: Add other useful fields. apiVersion, kind, uid?' 117 | type: string 118 | optional: 119 | description: Specify whether the Secret or its key must 120 | be defined 121 | type: boolean 122 | required: 123 | - key 124 | type: object 125 | honorLabels: 126 | description: HonorLabels chooses the metric's labels on collisions 127 | with target labels. 128 | type: boolean 129 | honorTimestamps: 130 | description: HonorTimestamps controls whether Prometheus respects 131 | the timestamps present in scraped data. 132 | type: boolean 133 | interval: 134 | description: Interval at which metrics should be scraped 135 | type: string 136 | metricRelabelings: 137 | description: MetricRelabelConfigs to apply to samples before 138 | ingestion. 139 | items: 140 | description: 'RelabelConfig allows dynamic rewriting of the 141 | label set, being applied to samples before ingestion. It 142 | defines ``-section of Prometheus 143 | configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs' 144 | properties: 145 | action: 146 | description: Action to perform based on regex matching. 147 | Default is 'replace' 148 | type: string 149 | modulus: 150 | description: Modulus to take of the hash of the source 151 | label values. 152 | format: int64 153 | type: integer 154 | regex: 155 | description: Regular expression against which the extracted 156 | value is matched. Default is '(.*)' 157 | type: string 158 | replacement: 159 | description: Replacement value against which a regex replace 160 | is performed if the regular expression matches. Regex 161 | capture groups are available. Default is '$1' 162 | type: string 163 | separator: 164 | description: Separator placed between concatenated source 165 | label values. default is ';'. 166 | type: string 167 | sourceLabels: 168 | description: The source labels select values from existing 169 | labels. Their content is concatenated using the configured 170 | separator and matched against the configured regular 171 | expression for the replace, keep, and drop actions. 172 | items: 173 | type: string 174 | type: array 175 | targetLabel: 176 | description: Label to which the resulting value is written 177 | in a replace action. It is mandatory for replace actions. 178 | Regex capture groups are available. 179 | type: string 180 | type: object 181 | type: array 182 | params: 183 | additionalProperties: 184 | items: 185 | type: string 186 | type: array 187 | description: Optional HTTP URL parameters 188 | type: object 189 | path: 190 | description: HTTP path to scrape for metrics. 191 | type: string 192 | port: 193 | description: Name of the pod port this endpoint refers to. Mutually 194 | exclusive with targetPort. 195 | type: string 196 | proxyUrl: 197 | description: ProxyURL eg http://proxyserver:2195 Directs scrapes 198 | to proxy through this endpoint. 199 | type: string 200 | relabelings: 201 | description: 'RelabelConfigs to apply to samples before ingestion. 202 | More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config' 203 | items: 204 | description: 'RelabelConfig allows dynamic rewriting of the 205 | label set, being applied to samples before ingestion. It 206 | defines ``-section of Prometheus 207 | configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs' 208 | properties: 209 | action: 210 | description: Action to perform based on regex matching. 211 | Default is 'replace' 212 | type: string 213 | modulus: 214 | description: Modulus to take of the hash of the source 215 | label values. 216 | format: int64 217 | type: integer 218 | regex: 219 | description: Regular expression against which the extracted 220 | value is matched. Default is '(.*)' 221 | type: string 222 | replacement: 223 | description: Replacement value against which a regex replace 224 | is performed if the regular expression matches. Regex 225 | capture groups are available. Default is '$1' 226 | type: string 227 | separator: 228 | description: Separator placed between concatenated source 229 | label values. default is ';'. 230 | type: string 231 | sourceLabels: 232 | description: The source labels select values from existing 233 | labels. Their content is concatenated using the configured 234 | separator and matched against the configured regular 235 | expression for the replace, keep, and drop actions. 236 | items: 237 | type: string 238 | type: array 239 | targetLabel: 240 | description: Label to which the resulting value is written 241 | in a replace action. It is mandatory for replace actions. 242 | Regex capture groups are available. 243 | type: string 244 | type: object 245 | type: array 246 | scheme: 247 | description: HTTP scheme to use for scraping. 248 | type: string 249 | scrapeTimeout: 250 | description: Timeout after which the scrape is ended 251 | type: string 252 | targetPort: 253 | anyOf: 254 | - type: integer 255 | - type: string 256 | description: 'Deprecated: Use ''port'' instead.' 257 | x-kubernetes-int-or-string: true 258 | tlsConfig: 259 | description: TLS configuration to use when scraping the endpoint. 260 | properties: 261 | ca: 262 | description: Struct containing the CA cert to use for the 263 | targets. 264 | properties: 265 | configMap: 266 | description: ConfigMap containing data to use for the 267 | targets. 268 | properties: 269 | key: 270 | description: The key to select. 271 | type: string 272 | name: 273 | description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 274 | TODO: Add other useful fields. apiVersion, kind, 275 | uid?' 276 | type: string 277 | optional: 278 | description: Specify whether the ConfigMap or its 279 | key must be defined 280 | type: boolean 281 | required: 282 | - key 283 | type: object 284 | secret: 285 | description: Secret containing data to use for the targets. 286 | properties: 287 | key: 288 | description: The key of the secret to select from. Must 289 | be a valid secret key. 290 | type: string 291 | name: 292 | description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 293 | TODO: Add other useful fields. apiVersion, kind, 294 | uid?' 295 | type: string 296 | optional: 297 | description: Specify whether the Secret or its key 298 | must be defined 299 | type: boolean 300 | required: 301 | - key 302 | type: object 303 | type: object 304 | cert: 305 | description: Struct containing the client cert file for 306 | the targets. 307 | properties: 308 | configMap: 309 | description: ConfigMap containing data to use for the 310 | targets. 311 | properties: 312 | key: 313 | description: The key to select. 314 | type: string 315 | name: 316 | description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 317 | TODO: Add other useful fields. apiVersion, kind, 318 | uid?' 319 | type: string 320 | optional: 321 | description: Specify whether the ConfigMap or its 322 | key must be defined 323 | type: boolean 324 | required: 325 | - key 326 | type: object 327 | secret: 328 | description: Secret containing data to use for the targets. 329 | properties: 330 | key: 331 | description: The key of the secret to select from. Must 332 | be a valid secret key. 333 | type: string 334 | name: 335 | description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 336 | TODO: Add other useful fields. apiVersion, kind, 337 | uid?' 338 | type: string 339 | optional: 340 | description: Specify whether the Secret or its key 341 | must be defined 342 | type: boolean 343 | required: 344 | - key 345 | type: object 346 | type: object 347 | insecureSkipVerify: 348 | description: Disable target certificate validation. 349 | type: boolean 350 | keySecret: 351 | description: Secret containing the client key file for the 352 | targets. 353 | properties: 354 | key: 355 | description: The key of the secret to select from. Must 356 | be a valid secret key. 357 | type: string 358 | name: 359 | description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 360 | TODO: Add other useful fields. apiVersion, kind, uid?' 361 | type: string 362 | optional: 363 | description: Specify whether the Secret or its key must 364 | be defined 365 | type: boolean 366 | required: 367 | - key 368 | type: object 369 | serverName: 370 | description: Used to verify the hostname for the targets. 371 | type: string 372 | type: object 373 | type: object 374 | type: array 375 | podTargetLabels: 376 | description: PodTargetLabels transfers labels on the Kubernetes Pod 377 | onto the target. 378 | items: 379 | type: string 380 | type: array 381 | sampleLimit: 382 | description: SampleLimit defines per-scrape limit on number of scraped 383 | samples that will be accepted. 384 | format: int64 385 | type: integer 386 | selector: 387 | description: Selector to select Pod objects. 388 | properties: 389 | matchExpressions: 390 | description: matchExpressions is a list of label selector requirements. 391 | The requirements are ANDed. 392 | items: 393 | description: A label selector requirement is a selector that 394 | contains values, a key, and an operator that relates the key 395 | and values. 396 | properties: 397 | key: 398 | description: key is the label key that the selector applies 399 | to. 400 | type: string 401 | operator: 402 | description: operator represents a key's relationship to 403 | a set of values. Valid operators are In, NotIn, Exists 404 | and DoesNotExist. 405 | type: string 406 | values: 407 | description: values is an array of string values. If the 408 | operator is In or NotIn, the values array must be non-empty. 409 | If the operator is Exists or DoesNotExist, the values 410 | array must be empty. This array is replaced during a strategic 411 | merge patch. 412 | items: 413 | type: string 414 | type: array 415 | required: 416 | - key 417 | - operator 418 | type: object 419 | type: array 420 | matchLabels: 421 | additionalProperties: 422 | type: string 423 | description: matchLabels is a map of {key,value} pairs. A single 424 | {key,value} in the matchLabels map is equivalent to an element 425 | of matchExpressions, whose key field is "key", the operator 426 | is "In", and the values array contains only "value". The requirements 427 | are ANDed. 428 | type: object 429 | type: object 430 | targetLimit: 431 | description: TargetLimit defines a limit on the number of scraped 432 | targets that will be accepted. 433 | format: int64 434 | type: integer 435 | required: 436 | - podMetricsEndpoints 437 | - selector 438 | type: object 439 | required: 440 | - spec 441 | type: object 442 | served: true 443 | storage: true 444 | status: 445 | acceptedNames: 446 | kind: "" 447 | plural: "" 448 | conditions: [] 449 | storedVersions: [] -------------------------------------------------------------------------------- /lessons/013/01-prometheus-operator-crd/monitoring.coreos.com_probes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.2.4 7 | creationTimestamp: null 8 | name: probes.monitoring.coreos.com 9 | spec: 10 | group: monitoring.coreos.com 11 | names: 12 | kind: Probe 13 | listKind: ProbeList 14 | plural: probes 15 | singular: probe 16 | scope: Namespaced 17 | versions: 18 | - name: v1 19 | schema: 20 | openAPIV3Schema: 21 | description: Probe defines monitoring for a set of static targets or ingresses. 22 | properties: 23 | apiVersion: 24 | description: 'APIVersion defines the versioned schema of this representation 25 | of an object. Servers should convert recognized schemas to the latest 26 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' 27 | type: string 28 | kind: 29 | description: 'Kind is a string value representing the REST resource this 30 | object represents. Servers may infer this from the endpoint the client 31 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' 32 | type: string 33 | metadata: 34 | type: object 35 | spec: 36 | description: Specification of desired Ingress selection for target discovery 37 | by Prometheus. 38 | properties: 39 | interval: 40 | description: Interval at which targets are probed using the configured 41 | prober. If not specified Prometheus' global scrape interval is used. 42 | type: string 43 | jobName: 44 | description: The job name assigned to scraped metrics by default. 45 | type: string 46 | module: 47 | description: 'The module to use for probing specifying how to probe 48 | the target. Example module configuring in the blackbox exporter: 49 | https://github.com/prometheus/blackbox_exporter/blob/master/example.yml' 50 | type: string 51 | prober: 52 | description: Specification for the prober to use for probing targets. 53 | The prober.URL parameter is required. Targets cannot be probed if 54 | left empty. 55 | properties: 56 | path: 57 | description: Path to collect metrics from. Defaults to `/probe`. 58 | type: string 59 | scheme: 60 | description: HTTP scheme to use for scraping. Defaults to `http`. 61 | type: string 62 | url: 63 | description: Mandatory URL of the prober. 64 | type: string 65 | required: 66 | - url 67 | type: object 68 | scrapeTimeout: 69 | description: Timeout for scraping metrics from the Prometheus exporter. 70 | type: string 71 | targets: 72 | description: Targets defines a set of static and/or dynamically discovered 73 | targets to be probed using the prober. 74 | properties: 75 | ingress: 76 | description: Ingress defines the set of dynamically discovered 77 | ingress objects which hosts are considered for probing. 78 | properties: 79 | namespaceSelector: 80 | description: Select Ingress objects by namespace. 81 | properties: 82 | any: 83 | description: Boolean describing whether all namespaces 84 | are selected in contrast to a list restricting them. 85 | type: boolean 86 | matchNames: 87 | description: List of namespace names. 88 | items: 89 | type: string 90 | type: array 91 | type: object 92 | relabelingConfigs: 93 | description: 'RelabelConfigs to apply to samples before ingestion. 94 | More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config' 95 | items: 96 | description: 'RelabelConfig allows dynamic rewriting of 97 | the label set, being applied to samples before ingestion. 98 | It defines ``-section of Prometheus 99 | configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs' 100 | properties: 101 | action: 102 | description: Action to perform based on regex matching. 103 | Default is 'replace' 104 | type: string 105 | modulus: 106 | description: Modulus to take of the hash of the source 107 | label values. 108 | format: int64 109 | type: integer 110 | regex: 111 | description: Regular expression against which the extracted 112 | value is matched. Default is '(.*)' 113 | type: string 114 | replacement: 115 | description: Replacement value against which a regex 116 | replace is performed if the regular expression matches. 117 | Regex capture groups are available. Default is '$1' 118 | type: string 119 | separator: 120 | description: Separator placed between concatenated source 121 | label values. default is ';'. 122 | type: string 123 | sourceLabels: 124 | description: The source labels select values from existing 125 | labels. Their content is concatenated using the configured 126 | separator and matched against the configured regular 127 | expression for the replace, keep, and drop actions. 128 | items: 129 | type: string 130 | type: array 131 | targetLabel: 132 | description: Label to which the resulting value is written 133 | in a replace action. It is mandatory for replace actions. 134 | Regex capture groups are available. 135 | type: string 136 | type: object 137 | type: array 138 | selector: 139 | description: Select Ingress objects by labels. 140 | properties: 141 | matchExpressions: 142 | description: matchExpressions is a list of label selector 143 | requirements. The requirements are ANDed. 144 | items: 145 | description: A label selector requirement is a selector 146 | that contains values, a key, and an operator that 147 | relates the key and values. 148 | properties: 149 | key: 150 | description: key is the label key that the selector 151 | applies to. 152 | type: string 153 | operator: 154 | description: operator represents a key's relationship 155 | to a set of values. Valid operators are In, NotIn, 156 | Exists and DoesNotExist. 157 | type: string 158 | values: 159 | description: values is an array of string values. 160 | If the operator is In or NotIn, the values array 161 | must be non-empty. If the operator is Exists or 162 | DoesNotExist, the values array must be empty. 163 | This array is replaced during a strategic merge 164 | patch. 165 | items: 166 | type: string 167 | type: array 168 | required: 169 | - key 170 | - operator 171 | type: object 172 | type: array 173 | matchLabels: 174 | additionalProperties: 175 | type: string 176 | description: matchLabels is a map of {key,value} pairs. 177 | A single {key,value} in the matchLabels map is equivalent 178 | to an element of matchExpressions, whose key field is 179 | "key", the operator is "In", and the values array contains 180 | only "value". The requirements are ANDed. 181 | type: object 182 | type: object 183 | type: object 184 | staticConfig: 185 | description: 'StaticConfig defines static targets which are considers 186 | for probing. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#static_config.' 187 | properties: 188 | labels: 189 | additionalProperties: 190 | type: string 191 | description: Labels assigned to all metrics scraped from the 192 | targets. 193 | type: object 194 | static: 195 | description: Targets is a list of URLs to probe using the 196 | configured prober. 197 | items: 198 | type: string 199 | type: array 200 | type: object 201 | type: object 202 | type: object 203 | required: 204 | - spec 205 | type: object 206 | served: true 207 | storage: true 208 | status: 209 | acceptedNames: 210 | kind: "" 211 | plural: "" 212 | conditions: [] 213 | storedVersions: [] -------------------------------------------------------------------------------- /lessons/013/01-prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.2.4 7 | creationTimestamp: null 8 | name: prometheusrules.monitoring.coreos.com 9 | spec: 10 | group: monitoring.coreos.com 11 | names: 12 | kind: PrometheusRule 13 | listKind: PrometheusRuleList 14 | plural: prometheusrules 15 | singular: prometheusrule 16 | scope: Namespaced 17 | versions: 18 | - name: v1 19 | schema: 20 | openAPIV3Schema: 21 | description: PrometheusRule defines alerting rules for a Prometheus instance 22 | properties: 23 | apiVersion: 24 | description: 'APIVersion defines the versioned schema of this representation 25 | of an object. Servers should convert recognized schemas to the latest 26 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' 27 | type: string 28 | kind: 29 | description: 'Kind is a string value representing the REST resource this 30 | object represents. Servers may infer this from the endpoint the client 31 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' 32 | type: string 33 | metadata: 34 | type: object 35 | spec: 36 | description: Specification of desired alerting rule definitions for Prometheus. 37 | properties: 38 | groups: 39 | description: Content of Prometheus rule file 40 | items: 41 | description: 'RuleGroup is a list of sequentially evaluated recording 42 | and alerting rules. Note: PartialResponseStrategy is only used 43 | by ThanosRuler and will be ignored by Prometheus instances. Valid 44 | values for this field are ''warn'' or ''abort''. More info: https://github.com/thanos-io/thanos/blob/master/docs/components/rule.md#partial-response' 45 | properties: 46 | interval: 47 | type: string 48 | name: 49 | type: string 50 | partial_response_strategy: 51 | type: string 52 | rules: 53 | items: 54 | description: Rule describes an alerting or recording rule. 55 | properties: 56 | alert: 57 | type: string 58 | annotations: 59 | additionalProperties: 60 | type: string 61 | type: object 62 | expr: 63 | anyOf: 64 | - type: integer 65 | - type: string 66 | x-kubernetes-int-or-string: true 67 | for: 68 | type: string 69 | labels: 70 | additionalProperties: 71 | type: string 72 | type: object 73 | record: 74 | type: string 75 | required: 76 | - expr 77 | type: object 78 | type: array 79 | required: 80 | - name 81 | - rules 82 | type: object 83 | type: array 84 | type: object 85 | required: 86 | - spec 87 | type: object 88 | served: true 89 | storage: true 90 | status: 91 | acceptedNames: 92 | kind: "" 93 | plural: "" 94 | conditions: [] 95 | storedVersions: [] -------------------------------------------------------------------------------- /lessons/013/01-prometheus-operator-crd/prometheus-operator-crd-cluster-roles.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: ClusterRole 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | metadata: 5 | name: prometheus-crd-view 6 | labels: 7 | rbac.authorization.k8s.io/aggregate-to-admin: "true" 8 | rbac.authorization.k8s.io/aggregate-to-edit: "true" 9 | rbac.authorization.k8s.io/aggregate-to-view: "true" 10 | rules: 11 | - apiGroups: ["monitoring.coreos.com"] 12 | resources: ["alertmanagers", "alertmanagerconfigs", "prometheuses", "prometheusrules", "servicemonitors", "podmonitors", "probes"] 13 | verbs: ["get", "list", "watch"] 14 | --- 15 | kind: ClusterRole 16 | apiVersion: rbac.authorization.k8s.io/v1 17 | metadata: 18 | name: prometheus-crd-edit 19 | labels: 20 | rbac.authorization.k8s.io/aggregate-to-edit: "true" 21 | rbac.authorization.k8s.io/aggregate-to-admin: "true" 22 | rules: 23 | - apiGroups: ["monitoring.coreos.com"] 24 | resources: ["alertmanagers", "alertmanagerconfigs", "prometheuses", "prometheusrules", "servicemonitors", "podmonitors", "probes"] 25 | verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] 26 | -------------------------------------------------------------------------------- /lessons/013/02-prometheus-operator/prometheus-operator-cluster-role-binding.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | labels: 6 | app.kubernetes.io/component: controller 7 | app.kubernetes.io/name: prometheus-operator 8 | app.kubernetes.io/version: v0.42.1 9 | name: prometheus-operator 10 | roleRef: 11 | apiGroup: rbac.authorization.k8s.io 12 | kind: ClusterRole 13 | name: prometheus-operator 14 | subjects: 15 | - kind: ServiceAccount 16 | name: prometheus-operator 17 | namespace: default 18 | -------------------------------------------------------------------------------- /lessons/013/02-prometheus-operator/prometheus-operator-cluster-role.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/component: controller 7 | app.kubernetes.io/name: prometheus-operator 8 | app.kubernetes.io/version: v0.42.1 9 | name: prometheus-operator 10 | rules: 11 | - apiGroups: 12 | - monitoring.coreos.com 13 | resources: 14 | - alertmanagers 15 | - alertmanagers/finalizers 16 | - alertmanagerconfigs 17 | - prometheuses 18 | - prometheuses/finalizers 19 | - thanosrulers 20 | - thanosrulers/finalizers 21 | - servicemonitors 22 | - podmonitors 23 | - probes 24 | - prometheusrules 25 | verbs: 26 | - '*' 27 | - apiGroups: 28 | - apps 29 | resources: 30 | - statefulsets 31 | verbs: 32 | - '*' 33 | - apiGroups: 34 | - "" 35 | resources: 36 | - configmaps 37 | - secrets 38 | verbs: 39 | - '*' 40 | - apiGroups: 41 | - "" 42 | resources: 43 | - pods 44 | verbs: 45 | - list 46 | - delete 47 | - apiGroups: 48 | - "" 49 | resources: 50 | - services 51 | - services/finalizers 52 | - endpoints 53 | verbs: 54 | - get 55 | - create 56 | - update 57 | - delete 58 | - apiGroups: 59 | - "" 60 | resources: 61 | - nodes 62 | verbs: 63 | - list 64 | - watch 65 | - apiGroups: 66 | - "" 67 | resources: 68 | - namespaces 69 | verbs: 70 | - get 71 | - list 72 | - watch 73 | - apiGroups: 74 | - networking.k8s.io 75 | resources: 76 | - ingresses 77 | verbs: 78 | - get 79 | - list 80 | - watch 81 | -------------------------------------------------------------------------------- /lessons/013/02-prometheus-operator/prometheus-operator-deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | labels: 6 | app.kubernetes.io/component: controller 7 | app.kubernetes.io/name: prometheus-operator 8 | app.kubernetes.io/version: v0.42.1 9 | name: prometheus-operator 10 | namespace: default 11 | spec: 12 | replicas: 1 13 | selector: 14 | matchLabels: 15 | app.kubernetes.io/component: controller 16 | app.kubernetes.io/name: prometheus-operator 17 | template: 18 | metadata: 19 | labels: 20 | app.kubernetes.io/component: controller 21 | app.kubernetes.io/name: prometheus-operator 22 | app.kubernetes.io/version: v0.42.1 23 | spec: 24 | containers: 25 | - args: 26 | - --kubelet-service=kube-system/kubelet 27 | - --logtostderr=true 28 | - --prometheus-config-reloader=quay.io/prometheus-operator/prometheus-config-reloader:v0.42.1 29 | image: quay.io/prometheus-operator/prometheus-operator:v0.42.1 30 | name: prometheus-operator 31 | ports: 32 | - containerPort: 8080 33 | name: http 34 | resources: 35 | limits: 36 | cpu: 200m 37 | memory: 200Mi 38 | requests: 39 | cpu: 100m 40 | memory: 100Mi 41 | securityContext: 42 | allowPrivilegeEscalation: false 43 | nodeSelector: 44 | beta.kubernetes.io/os: linux 45 | securityContext: 46 | runAsNonRoot: true 47 | runAsUser: 65534 48 | serviceAccountName: prometheus-operator 49 | -------------------------------------------------------------------------------- /lessons/013/02-prometheus-operator/prometheus-operator-service-account.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | labels: 6 | app.kubernetes.io/component: controller 7 | app.kubernetes.io/name: prometheus-operator 8 | app.kubernetes.io/version: v0.42.1 9 | name: prometheus-operator 10 | namespace: default 11 | -------------------------------------------------------------------------------- /lessons/013/02-prometheus-operator/prometheus-operator-service-monitor.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: monitoring.coreos.com/v1 3 | kind: ServiceMonitor 4 | metadata: 5 | labels: 6 | app.kubernetes.io/component: controller 7 | app.kubernetes.io/name: prometheus-operator 8 | app.kubernetes.io/version: v0.42.1 9 | name: prometheus-operator 10 | namespace: default 11 | spec: 12 | endpoints: 13 | - honorLabels: true 14 | port: http 15 | selector: 16 | matchLabels: 17 | app.kubernetes.io/component: controller 18 | app.kubernetes.io/name: prometheus-operator 19 | app.kubernetes.io/version: v0.42.1 20 | -------------------------------------------------------------------------------- /lessons/013/02-prometheus-operator/prometheus-operator-service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | labels: 6 | app.kubernetes.io/component: controller 7 | app.kubernetes.io/name: prometheus-operator 8 | app.kubernetes.io/version: v0.42.1 9 | name: prometheus-operator 10 | namespace: default 11 | spec: 12 | clusterIP: None 13 | ports: 14 | - name: http 15 | port: 8080 16 | targetPort: http 17 | selector: 18 | app.kubernetes.io/component: controller 19 | app.kubernetes.io/name: prometheus-operator 20 | -------------------------------------------------------------------------------- /lessons/013/03-prometheus/prometheus-cluster-role-binding.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1beta1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | name: prometheus 6 | roleRef: 7 | apiGroup: rbac.authorization.k8s.io 8 | kind: ClusterRole 9 | name: prometheus 10 | subjects: 11 | - kind: ServiceAccount 12 | name: prometheus 13 | namespace: default 14 | -------------------------------------------------------------------------------- /lessons/013/03-prometheus/prometheus-cluster-role.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1beta1 3 | kind: ClusterRole 4 | metadata: 5 | name: prometheus 6 | rules: 7 | - apiGroups: [""] 8 | resources: 9 | - nodes 10 | - nodes/metrics 11 | - services 12 | - endpoints 13 | - pods 14 | verbs: ["get", "list", "watch"] 15 | - apiGroups: [""] 16 | resources: 17 | - configmaps 18 | verbs: ["get"] 19 | - apiGroups: 20 | - networking.k8s.io 21 | resources: 22 | - ingresses 23 | verbs: ["get", "list", "watch"] 24 | - nonResourceURLs: ["/metrics"] 25 | verbs: ["get"] 26 | -------------------------------------------------------------------------------- /lessons/013/03-prometheus/prometheus-service-account.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: prometheus 6 | -------------------------------------------------------------------------------- /lessons/013/03-prometheus/prometheus.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: monitoring.coreos.com/v1 3 | kind: Prometheus 4 | metadata: 5 | name: prometheus 6 | spec: 7 | serviceAccountName: prometheus 8 | serviceMonitorSelector: 9 | matchLabels: 10 | team: devops 11 | resources: 12 | requests: 13 | memory: 400Mi 14 | -------------------------------------------------------------------------------- /lessons/013/03-prometheus/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: prometheus 6 | spec: 7 | ports: 8 | - name: web 9 | port: 9090 10 | protocol: TCP 11 | selector: 12 | prometheus: prometheus 13 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/admission-webhooks/clusterrole.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: ingress-nginx-admission 6 | labels: 7 | app.kubernetes.io/name: ingress-nginx 8 | app.kubernetes.io/component: admission-webhook 9 | rules: 10 | - apiGroups: 11 | - admissionregistration.k8s.io 12 | resources: 13 | - validatingwebhookconfigurations 14 | verbs: 15 | - get 16 | - update 17 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/admission-webhooks/clusterrolebinding.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | name: ingress-nginx-admission 6 | labels: 7 | app.kubernetes.io/name: ingress-nginx 8 | app.kubernetes.io/component: admission-webhook 9 | roleRef: 10 | apiGroup: rbac.authorization.k8s.io 11 | kind: ClusterRole 12 | name: ingress-nginx-admission 13 | subjects: 14 | - kind: ServiceAccount 15 | name: ingress-nginx-admission 16 | namespace: ingress 17 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/admission-webhooks/job-createSecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: ingress-nginx-admission-create 6 | namespace: ingress 7 | labels: 8 | app.kubernetes.io/name: ingress-nginx 9 | app.kubernetes.io/component: admission-webhook 10 | spec: 11 | template: 12 | metadata: 13 | name: ingress-nginx-admission-create 14 | labels: 15 | app.kubernetes.io/name: ingress-nginx 16 | app.kubernetes.io/component: admission-webhook 17 | spec: 18 | containers: 19 | - name: create 20 | image: "docker.io/jettech/kube-webhook-certgen:v1.3.0" 21 | imagePullPolicy: IfNotPresent 22 | args: 23 | - create 24 | - --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc 25 | - --namespace=$(POD_NAMESPACE) 26 | - --secret-name=ingress-nginx-admission 27 | env: 28 | - name: POD_NAMESPACE 29 | valueFrom: 30 | fieldRef: 31 | fieldPath: metadata.namespace 32 | restartPolicy: OnFailure 33 | serviceAccountName: ingress-nginx-admission 34 | securityContext: 35 | runAsNonRoot: true 36 | runAsUser: 2000 37 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/admission-webhooks/job-patchWebhook.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: ingress-nginx-admission-patch 6 | namespace: ingress 7 | labels: 8 | app.kubernetes.io/name: ingress-nginx 9 | app.kubernetes.io/component: admission-webhook 10 | spec: 11 | template: 12 | metadata: 13 | name: ingress-nginx-admission-patch 14 | labels: 15 | app.kubernetes.io/name: ingress-nginx 16 | app.kubernetes.io/component: admission-webhook 17 | spec: 18 | containers: 19 | - name: patch 20 | image: "docker.io/jettech/kube-webhook-certgen:v1.3.0" 21 | imagePullPolicy: IfNotPresent 22 | args: 23 | - patch 24 | - --webhook-name=ingress-nginx-admission 25 | - --namespace=$(POD_NAMESPACE) 26 | - --patch-mutating=false 27 | - --secret-name=ingress-nginx-admission 28 | - --patch-failure-policy=Fail 29 | env: 30 | - name: POD_NAMESPACE 31 | valueFrom: 32 | fieldRef: 33 | fieldPath: metadata.namespace 34 | restartPolicy: OnFailure 35 | serviceAccountName: ingress-nginx-admission 36 | securityContext: 37 | runAsNonRoot: true 38 | runAsUser: 2000 39 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/admission-webhooks/role.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: ingress-nginx-admission 6 | namespace: ingress 7 | labels: 8 | app.kubernetes.io/name: ingress-nginx 9 | app.kubernetes.io/component: admission-webhook 10 | rules: 11 | - apiGroups: 12 | - "" 13 | resources: 14 | - secrets 15 | verbs: 16 | - get 17 | - create 18 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/admission-webhooks/rolebinding.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: RoleBinding 4 | metadata: 5 | name: ingress-nginx-admission 6 | namespace: ingress 7 | labels: 8 | app.kubernetes.io/name: ingress-nginx 9 | app.kubernetes.io/component: admission-webhook 10 | roleRef: 11 | apiGroup: rbac.authorization.k8s.io 12 | kind: Role 13 | name: ingress-nginx-admission 14 | subjects: 15 | - kind: ServiceAccount 16 | name: ingress-nginx-admission 17 | namespace: ingress 18 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/admission-webhooks/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: ingress-nginx-admission 6 | namespace: ingress 7 | labels: 8 | app.kubernetes.io/name: ingress-nginx 9 | app.kubernetes.io/component: admission-webhook 10 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/admission-webhooks/validating-webhook.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: admissionregistration.k8s.io/v1 3 | kind: ValidatingWebhookConfiguration 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/component: admission-webhook 8 | name: ingress-nginx-admission 9 | namespace: ingress 10 | webhooks: 11 | - name: validate.nginx.ingress.kubernetes.io 12 | rules: 13 | - apiGroups: 14 | - networking.k8s.io 15 | apiVersions: 16 | - v1beta1 17 | - v1 18 | operations: 19 | - CREATE 20 | - UPDATE 21 | resources: 22 | - ingresses 23 | failurePolicy: Fail 24 | sideEffects: None 25 | admissionReviewVersions: 26 | - v1 27 | - v1beta1 28 | clientConfig: 29 | service: 30 | namespace: ingress 31 | name: ingress-nginx-controller-admission 32 | path: /networking/v1beta1/ingresses 33 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/clusterrole.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | name: ingress-nginx 8 | rules: 9 | - apiGroups: 10 | - "" 11 | resources: 12 | - configmaps 13 | - endpoints 14 | - nodes 15 | - pods 16 | - secrets 17 | verbs: 18 | - list 19 | - watch 20 | - apiGroups: 21 | - "" 22 | resources: 23 | - nodes 24 | verbs: 25 | - get 26 | - apiGroups: 27 | - "" 28 | resources: 29 | - services 30 | verbs: 31 | - get 32 | - list 33 | - update 34 | - watch 35 | - apiGroups: 36 | - extensions 37 | - "networking.k8s.io" # k8s 1.14+ 38 | resources: 39 | - ingresses 40 | verbs: 41 | - get 42 | - list 43 | - watch 44 | - apiGroups: 45 | - "" 46 | resources: 47 | - events 48 | verbs: 49 | - create 50 | - patch 51 | - apiGroups: 52 | - extensions 53 | - "networking.k8s.io" # k8s 1.14+ 54 | resources: 55 | - ingresses/status 56 | verbs: 57 | - update 58 | - apiGroups: 59 | - "networking.k8s.io" # k8s 1.14+ 60 | resources: 61 | - ingressclasses 62 | verbs: 63 | - get 64 | - list 65 | - watch 66 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/clusterrolebinding.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | name: ingress-nginx 8 | roleRef: 9 | apiGroup: rbac.authorization.k8s.io 10 | kind: ClusterRole 11 | name: ingress-nginx 12 | subjects: 13 | - kind: ServiceAccount 14 | name: ingress-nginx 15 | namespace: ingress 16 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/controller-configmap.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/component: controller 8 | name: ingress-nginx-controller 9 | namespace: ingress 10 | data: 11 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/controller-deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/component: controller 8 | name: ingress-nginx-controller 9 | namespace: ingress 10 | spec: 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/name: ingress-nginx 14 | app.kubernetes.io/component: controller 15 | replicas: 1 16 | revisionHistoryLimit: 10 17 | minReadySeconds: 0 18 | template: 19 | metadata: 20 | labels: 21 | app.kubernetes.io/name: ingress-nginx 22 | app.kubernetes.io/component: controller 23 | spec: 24 | dnsPolicy: ClusterFirst 25 | containers: 26 | - name: controller 27 | image: "k8s.gcr.io/ingress-nginx/controller:v0.40.2@sha256:46ba23c3fbaafd9e5bd01ea85b2f921d9f2217be082580edc22e6c704a83f02f" 28 | imagePullPolicy: IfNotPresent 29 | lifecycle: 30 | preStop: 31 | exec: 32 | command: 33 | - /wait-shutdown 34 | args: 35 | - /nginx-ingress-controller 36 | - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller 37 | - --election-id=ingress-controller-leader 38 | - --ingress-class=sample-nginx 39 | - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller 40 | - --validating-webhook=:8443 41 | - --validating-webhook-certificate=/usr/local/certificates/cert 42 | - --validating-webhook-key=/usr/local/certificates/key 43 | securityContext: 44 | capabilities: 45 | drop: 46 | - ALL 47 | add: 48 | - NET_BIND_SERVICE 49 | runAsUser: 101 50 | allowPrivilegeEscalation: true 51 | env: 52 | - name: POD_NAME 53 | valueFrom: 54 | fieldRef: 55 | fieldPath: metadata.name 56 | - name: POD_NAMESPACE 57 | valueFrom: 58 | fieldRef: 59 | fieldPath: metadata.namespace 60 | - name: LD_PRELOAD 61 | value: /usr/local/lib/libmimalloc.so 62 | livenessProbe: 63 | httpGet: 64 | path: /healthz 65 | port: 10254 66 | scheme: HTTP 67 | initialDelaySeconds: 10 68 | periodSeconds: 10 69 | timeoutSeconds: 1 70 | successThreshold: 1 71 | failureThreshold: 5 72 | readinessProbe: 73 | httpGet: 74 | path: /healthz 75 | port: 10254 76 | scheme: HTTP 77 | initialDelaySeconds: 10 78 | periodSeconds: 10 79 | timeoutSeconds: 1 80 | successThreshold: 1 81 | failureThreshold: 3 82 | ports: 83 | - name: http 84 | containerPort: 80 85 | protocol: TCP 86 | - name: https 87 | containerPort: 443 88 | protocol: TCP 89 | - name: webhook 90 | containerPort: 8443 91 | protocol: TCP 92 | - name: prometheus 93 | containerPort: 10254 94 | protocol: TCP 95 | volumeMounts: 96 | - name: webhook-cert 97 | mountPath: /usr/local/certificates/ 98 | readOnly: true 99 | resources: 100 | requests: 101 | cpu: 100m 102 | memory: 90Mi 103 | nodeSelector: 104 | kubernetes.io/os: linux 105 | serviceAccountName: ingress-nginx 106 | terminationGracePeriodSeconds: 300 107 | volumes: 108 | - name: webhook-cert 109 | secret: 110 | secretName: ingress-nginx-admission 111 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/controller-role.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/component: controller 8 | name: ingress-nginx 9 | namespace: ingress 10 | rules: 11 | - apiGroups: 12 | - "" 13 | resources: 14 | - namespaces 15 | verbs: 16 | - get 17 | - apiGroups: 18 | - "" 19 | resources: 20 | - configmaps 21 | - pods 22 | - secrets 23 | - endpoints 24 | verbs: 25 | - get 26 | - list 27 | - watch 28 | - apiGroups: 29 | - "" 30 | resources: 31 | - services 32 | verbs: 33 | - get 34 | - list 35 | - update 36 | - watch 37 | - apiGroups: 38 | - extensions 39 | - "networking.k8s.io" # k8s 1.14+ 40 | resources: 41 | - ingresses 42 | verbs: 43 | - get 44 | - list 45 | - watch 46 | - apiGroups: 47 | - extensions 48 | - "networking.k8s.io" # k8s 1.14+ 49 | resources: 50 | - ingresses/status 51 | verbs: 52 | - update 53 | - apiGroups: 54 | - "networking.k8s.io" # k8s 1.14+ 55 | resources: 56 | - ingressclasses 57 | verbs: 58 | - get 59 | - list 60 | - watch 61 | - apiGroups: 62 | - "" 63 | resources: 64 | - configmaps 65 | resourceNames: 66 | - ingress-controller-leader-sample-nginx 67 | verbs: 68 | - get 69 | - update 70 | - apiGroups: 71 | - "" 72 | resources: 73 | - configmaps 74 | verbs: 75 | - create 76 | - apiGroups: 77 | - "" 78 | resources: 79 | - endpoints 80 | verbs: 81 | - create 82 | - get 83 | - update 84 | - apiGroups: 85 | - "" 86 | resources: 87 | - events 88 | verbs: 89 | - create 90 | - patch 91 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/controller-rolebinding.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: RoleBinding 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/managed-by: Helm 8 | app.kubernetes.io/component: controller 9 | name: ingress-nginx 10 | namespace: ingress 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: Role 14 | name: ingress-nginx 15 | subjects: 16 | - kind: ServiceAccount 17 | name: ingress-nginx 18 | namespace: ingress 19 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/controller-service-prometheus.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/component: controller 8 | name: ingress-nginx-prometheus 9 | namespace: ingress 10 | spec: 11 | type: ClusterIP 12 | ports: 13 | - name: prometheus 14 | port: 10254 15 | targetPort: prometheus 16 | selector: 17 | app.kubernetes.io/name: ingress-nginx 18 | app.kubernetes.io/component: controller 19 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/controller-service-webhook.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/component: controller 8 | name: ingress-nginx-controller-admission 9 | namespace: ingress 10 | spec: 11 | type: ClusterIP 12 | ports: 13 | - name: https-webhook 14 | port: 443 15 | targetPort: webhook 16 | selector: 17 | app.kubernetes.io/name: ingress-nginx 18 | app.kubernetes.io/component: controller 19 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/controller-service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/component: controller 8 | name: ingress-nginx-controller 9 | namespace: ingress 10 | spec: 11 | type: LoadBalancer 12 | ports: 13 | - name: http 14 | port: 80 15 | protocol: TCP 16 | targetPort: http 17 | - name: https 18 | port: 443 19 | protocol: TCP 20 | targetPort: https 21 | selector: 22 | app.kubernetes.io/name: ingress-nginx 23 | app.kubernetes.io/component: controller 24 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/controller-serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: ingress-nginx 7 | app.kubernetes.io/component: controller 8 | name: ingress-nginx 9 | namespace: ingress 10 | -------------------------------------------------------------------------------- /lessons/013/04-ingress-nginx/namespace.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: ingress -------------------------------------------------------------------------------- /lessons/013/05-servicemonitor/service-monitor.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: monitoring.coreos.com/v1 3 | kind: ServiceMonitor 4 | metadata: 5 | namespace: default 6 | name: nginx-ingress 7 | labels: 8 | team: devops 9 | spec: 10 | selector: 11 | matchLabels: 12 | app.kubernetes.io/name: ingress-nginx 13 | app.kubernetes.io/component: controller 14 | namespaceSelector: 15 | matchNames: 16 | - ingress 17 | endpoints: 18 | - port: prometheus 19 | interval: 5s 20 | -------------------------------------------------------------------------------- /lessons/013/06-grafana/configmap.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | namespace: default 6 | name: grafana 7 | data: 8 | grafana.ini: | 9 | [analytics] 10 | check_for_updates = true 11 | [grafana_net] 12 | url = https://grafana.net 13 | [log] 14 | mode = console 15 | [paths] 16 | data = /var/lib/grafana/data 17 | logs = /var/log/grafana 18 | plugins = /var/lib/grafana/plugins 19 | provisioning = /etc/grafana/provisioning 20 | -------------------------------------------------------------------------------- /lessons/013/06-grafana/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | namespace: default 6 | name: grafana 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: grafana 12 | strategy: 13 | type: Recreate 14 | template: 15 | metadata: 16 | labels: 17 | app: grafana 18 | spec: 19 | serviceAccountName: grafana 20 | # securityContext: 21 | # fsGroup: 472 22 | # runAsUser: 472 23 | # initContainers: 24 | # - name: init-chown-data 25 | # image: "busybox:latest" 26 | # imagePullPolicy: IfNotPresent 27 | # securityContext: 28 | # runAsUser: 0 29 | # command: ["chown", "-R", "472:472", "/var/lib/grafana"] 30 | # resources: 31 | # limits: 32 | # cpu: 100m 33 | # memory: 128Mi 34 | # requests: 35 | # cpu: 100m 36 | # memory: 128Mi 37 | containers: 38 | - name: grafana 39 | image: "grafana/grafana:7.2.1" 40 | imagePullPolicy: IfNotPresent 41 | volumeMounts: 42 | - name: config 43 | mountPath: "/etc/grafana/grafana.ini" 44 | subPath: grafana.ini 45 | ports: 46 | - name: grafana 47 | containerPort: 3000 48 | protocol: TCP 49 | env: 50 | - name: GF_SECURITY_ADMIN_USER 51 | valueFrom: 52 | secretKeyRef: 53 | name: grafana 54 | key: admin-user 55 | - name: GF_SECURITY_ADMIN_PASSWORD 56 | valueFrom: 57 | secretKeyRef: 58 | name: grafana 59 | key: admin-password 60 | livenessProbe: 61 | failureThreshold: 10 62 | httpGet: 63 | path: /api/health 64 | port: 3000 65 | initialDelaySeconds: 60 66 | timeoutSeconds: 30 67 | readinessProbe: 68 | httpGet: 69 | path: /api/health 70 | port: 3000 71 | resources: 72 | limits: 73 | cpu: 500m 74 | memory: 512Mi 75 | requests: 76 | cpu: 100m 77 | memory: 128Mi 78 | volumes: 79 | - name: config 80 | configMap: 81 | name: grafana 82 | -------------------------------------------------------------------------------- /lessons/013/06-grafana/rbac.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | namespace: default 6 | name: grafana 7 | --- 8 | kind: ClusterRole 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | metadata: 11 | labels: 12 | app: grafana 13 | name: grafana-clusterrole 14 | rules: [] 15 | --- 16 | kind: ClusterRoleBinding 17 | apiVersion: rbac.authorization.k8s.io/v1 18 | metadata: 19 | name: grafana-clusterrolebinding 20 | labels: 21 | app: grafana 22 | subjects: 23 | - kind: ServiceAccount 24 | name: grafana 25 | namespace: default 26 | roleRef: 27 | kind: ClusterRole 28 | name: grafana-clusterrole 29 | apiGroup: rbac.authorization.k8s.io 30 | --- 31 | apiVersion: rbac.authorization.k8s.io/v1beta1 32 | kind: Role 33 | metadata: 34 | namespace: default 35 | name: grafana 36 | labels: 37 | app: grafana 38 | rules: 39 | - apiGroups: ['extensions'] 40 | resources: ['podsecuritypolicies'] 41 | verbs: ['use'] 42 | resourceNames: [grafana] 43 | --- 44 | apiVersion: rbac.authorization.k8s.io/v1beta1 45 | kind: RoleBinding 46 | metadata: 47 | namespace: default 48 | name: grafana 49 | labels: 50 | app: grafana 51 | roleRef: 52 | apiGroup: rbac.authorization.k8s.io 53 | kind: Role 54 | name: grafana 55 | subjects: 56 | - kind: ServiceAccount 57 | name: grafana 58 | namespace: grafana 59 | 60 | -------------------------------------------------------------------------------- /lessons/013/06-grafana/secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | namespace: default 6 | name: grafana 7 | type: Opaque 8 | data: 9 | admin-user: "YWRtaW4=" 10 | admin-password: "YWRtaW4=" 11 | -------------------------------------------------------------------------------- /lessons/013/06-grafana/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | namespace: default 6 | name: grafana 7 | spec: 8 | type: ClusterIP 9 | ports: 10 | - name: service 11 | port: 3000 12 | protocol: TCP 13 | selector: 14 | app: grafana 15 | -------------------------------------------------------------------------------- /lessons/013/07-sample-app/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | namespace: default 6 | name: hello-app-deployment 7 | labels: 8 | app: hello-app 9 | spec: 10 | replicas: 2 11 | selector: 12 | matchLabels: 13 | app: hello-app 14 | template: 15 | metadata: 16 | labels: 17 | app: hello-app 18 | spec: 19 | containers: 20 | - name: hello-app 21 | image: gcr.io/google-samples/hello-app:1.0 22 | ports: 23 | - containerPort: 8080 24 | -------------------------------------------------------------------------------- /lessons/013/07-sample-app/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1beta1 3 | kind: Ingress 4 | metadata: 5 | annotations: 6 | kubernetes.io/ingress.class: sample-nginx 7 | name: hello-app 8 | namespace: default 9 | spec: 10 | rules: 11 | - host: www.devopsbyexample.io 12 | http: 13 | paths: 14 | - backend: 15 | serviceName: hello-app-service 16 | servicePort: 8080 17 | path: / 18 | - backend: 19 | serviceName: missing-backend 20 | servicePort: 8080 21 | path: /do-not-exists 22 | -------------------------------------------------------------------------------- /lessons/013/07-sample-app/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | namespace: default 6 | name: hello-app-service 7 | labels: 8 | app: hello-app 9 | spec: 10 | selector: 11 | app: hello-app 12 | ports: 13 | - name: web 14 | port: 8080 15 | protocol: TCP 16 | -------------------------------------------------------------------------------- /lessons/013/README.md: -------------------------------------------------------------------------------- 1 | # How to Monitor Nginx Ingress with Prometheus and Grafana 2 | 3 | ### Create Kubernetes Cluster 4 | ```bash 5 | $ eksctl create cluster -f lessons/013/00-eksctl/eksctl-cluster.yaml 6 | $ kubectl get svc -n default 7 | ``` 8 | 9 | --- 10 | 11 | ### Create CRD (Custom Resource Definitions) for Prometheus Operator 12 | ```bash 13 | $ kubectl apply -f lessons/013/01-prometheus-operator-crd 14 | ``` 15 | 16 | ### Deploy Prometheus Operator 17 | ```bash 18 | $ kubectl apply -f lessons/013/02-prometheus-operator 19 | $ kubectl get pods -n default 20 | ``` 21 | 22 | ### Deploy Prometheus 23 | ```bash 24 | $ kubectl apply -f lessons/013/03-prometheus 25 | $ kubectl get pods -n default 26 | $ kubectl logs -f prometheus-prometheus-0 prometheus 27 | ``` 28 | 29 | --- 30 | 31 | ### Create Namespace Ingress 32 | ```bash 33 | $ kubectl apply -f lessons/013/04-ingress-nginx/namespace.yaml 34 | ``` 35 | 36 | ### Deploy Nginx Admission Webhook 37 | ```bash 38 | $ kubectl apply -f lessons/013/04-ingress-nginx/admission-webhooks 39 | ``` 40 | 41 | ### Deploy Nginx Ingress Controller 42 | ```bash 43 | $ kubectl apply -f lessons/013/04-ingress-nginx 44 | $ kubectl get pods -n ingress 45 | ``` 46 | 47 | --- 48 | 49 | ### Create ServiceMonitor for Nginx Controller 50 | ```bash 51 | $ kubectl apply -f lessons/013/05-servicemonitor 52 | $ kubectl get servicemonitors 53 | ``` 54 | 55 | ### Check Prometheus Targets 56 | ```bash 57 | $ kubectl port-forward svc/prometheus 9090:9090 -n default 58 | ``` 59 | 60 | --- 61 | 62 | ### Deploy Sample App 63 | ```bash 64 | $ kubectl apply -f lessons/013/07-sample-app 65 | $ kubectl get pods -n default 66 | $ kubectl get ingress -n default 67 | ``` 68 | 69 | ### Create DNS record 70 | ```bash 71 | $ kubectl get svc -n ingress 72 | ``` 73 | 74 | --- 75 | 76 | ### Deploy Grafana 77 | ```bash 78 | $ kubectl apply -f lessons/013/06-grafana 79 | $ kubectl get pods -n default 80 | ``` 81 | 82 | ### Import Ingress Grafana Dashboard 83 | 84 | ```bash 85 | # Grafana Dashboard: https://grafana.com/grafana/dashboards/9614 86 | $ kubectl port-forward svc/grafana 3000 -n default 87 | ``` 88 | 89 | ### Verify DNS 90 | ```bash 91 | $ dig +short www.devopsbyexample.io 92 | ``` 93 | 94 | ### Script to simulate 2xx requests 95 | ```bash 96 | while true 97 | do 98 | sleep 1 99 | curl -I http://www.devopsbyexample.io 100 | done 101 | ``` 102 | 103 | ### Script to simulate 5xx requests 104 | ```bash 105 | while true 106 | do 107 | sleep 1 108 | curl -I http://www.devopsbyexample.io/do-not-exists 109 | done 110 | ``` 111 | 112 | # Cleanup 113 | ```bash 114 | $ eksctl delete cluster -f lessons/013/00-eksctl/eksctl-cluster.yaml 115 | ``` -------------------------------------------------------------------------------- /lessons/015/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | # Main VPC 6 | # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc 7 | resource "aws_vpc" "main" { 8 | cidr_block = "10.0.0.0/18" 9 | 10 | tags = { 11 | Name = "Main VPC" 12 | } 13 | } 14 | 15 | # Public Subnet with Default Route to Internet Gateway 16 | # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet 17 | resource "aws_subnet" "public" { 18 | vpc_id = aws_vpc.main.id 19 | cidr_block = "10.0.0.0/24" 20 | 21 | tags = { 22 | Name = "Public Subnet" 23 | } 24 | } 25 | 26 | # Private Subnet with Default Route to NAT Gateway 27 | # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet 28 | resource "aws_subnet" "private" { 29 | vpc_id = aws_vpc.main.id 30 | cidr_block = "10.0.1.0/24" 31 | 32 | tags = { 33 | Name = "Private Subnet" 34 | } 35 | } 36 | 37 | # Main Internal Gateway for VPC 38 | # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/internet_gateway 39 | resource "aws_internet_gateway" "igw" { 40 | vpc_id = aws_vpc.main.id 41 | 42 | tags = { 43 | Name = "Main IGW" 44 | } 45 | } 46 | 47 | # Elastic IP for NAT Gateway 48 | # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip 49 | resource "aws_eip" "nat_eip" { 50 | vpc = true 51 | depends_on = [aws_internet_gateway.igw] 52 | tags = { 53 | Name = "NAT Gateway EIP" 54 | } 55 | } 56 | 57 | # Main NAT Gateway for VPC 58 | # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway 59 | resource "aws_nat_gateway" "nat" { 60 | allocation_id = aws_eip.nat_eip.id 61 | subnet_id = aws_subnet.public.id 62 | 63 | tags = { 64 | Name = "Main NAT Gateway" 65 | } 66 | } 67 | 68 | # Route Table for Public Subnet 69 | # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table 70 | resource "aws_route_table" "public" { 71 | vpc_id = aws_vpc.main.id 72 | 73 | route { 74 | cidr_block = "0.0.0.0/0" 75 | gateway_id = aws_internet_gateway.igw.id 76 | } 77 | 78 | tags = { 79 | Name = "Public Route Table" 80 | } 81 | } 82 | 83 | # Association between Public Subnet and Public Route Table 84 | # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association 85 | resource "aws_route_table_association" "public" { 86 | subnet_id = aws_subnet.public.id 87 | route_table_id = aws_route_table.public.id 88 | } 89 | 90 | # Route Table for Private Subnet 91 | # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table 92 | resource "aws_route_table" "private" { 93 | vpc_id = aws_vpc.main.id 94 | 95 | route { 96 | cidr_block = "0.0.0.0/0" 97 | gateway_id = aws_nat_gateway.nat.id 98 | } 99 | 100 | tags = { 101 | Name = "Private Route Table" 102 | } 103 | } 104 | 105 | # Association between Private Subnet and Private Route Table 106 | # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association 107 | resource "aws_route_table_association" "private" { 108 | subnet_id = aws_subnet.private.id 109 | route_table_id = aws_route_table.private.id 110 | } 111 | -------------------------------------------------------------------------------- /lessons/016/main.tf: -------------------------------------------------------------------------------- 1 | # https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/latest 2 | module "vpc" { 3 | source = "terraform-aws-modules/vpc/aws" 4 | 5 | name = "main" 6 | cidr = "10.0.0.0/18" 7 | 8 | azs = ["us-east-1a", "us-east-1b"] 9 | private_subnets = ["10.0.1.0/24"] 10 | public_subnets = ["10.0.0.0/24"] 11 | 12 | enable_nat_gateway = true 13 | 14 | tags = { 15 | Environment = "staging" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lessons/017/README.md: -------------------------------------------------------------------------------- 1 | # GCP VPC Tutorial | How to create Public and Private Subnet in GCP 2 | 3 | ### Create GCP VPC 4 | ```bash 5 | $ gcloud compute networks create main --bgp-routing-mode=regional --subnet-mode=custom 6 | ``` 7 | 8 | ### Create Public Sunbet 9 | ```bash 10 | $ gcloud compute networks subnets create public --network=main --range=10.0.0.0/24 --region=us-west2 11 | ``` 12 | 13 | ### Create Private Sunbet 14 | ```bash 15 | $ gcloud compute networks subnets create private --network=main --range=10.0.1.0/24 --region=us-west2 --enable-private-ip-google-access 16 | ``` 17 | 18 | ### Create Cloud Router 19 | ```bash 20 | $ gcloud compute routers create router --network=main --region=us-west2 21 | ``` 22 | 23 | ### Create NAT Gateway 24 | ```bash 25 | $ gcloud compute routers nats create nat --router=router --region=us-west2 --nat-custom-subnet-ip-ranges=private --auto-allocate-nat-external-ips 26 | ``` 27 | -------------------------------------------------------------------------------- /lessons/018/main.tf: -------------------------------------------------------------------------------- 1 | provider "google" { 2 | credentials = file("~/devops-by-example-9004d3b359f5.json") 3 | project = "devops-by-example" 4 | region = "us-west2" 5 | } 6 | 7 | # Main VPC 8 | # https://www.terraform.io/docs/providers/google/r/compute_network.html#example-usage-network-basic 9 | resource "google_compute_network" "main" { 10 | name = "main" 11 | auto_create_subnetworks = false 12 | } 13 | 14 | # Public Subnet 15 | # https://www.terraform.io/docs/providers/google/r/compute_subnetwork.html 16 | resource "google_compute_subnetwork" "public" { 17 | name = "public" 18 | ip_cidr_range = "10.0.0.0/24" 19 | region = "us-west2" 20 | network = google_compute_network.main.id 21 | } 22 | 23 | # Private Subnet 24 | # https://www.terraform.io/docs/providers/google/r/compute_subnetwork.html 25 | resource "google_compute_subnetwork" "private" { 26 | name = "private" 27 | ip_cidr_range = "10.0.1.0/24" 28 | region = "us-west2" 29 | network = google_compute_network.main.id 30 | } 31 | 32 | # Cloud Router 33 | # https://www.terraform.io/docs/providers/google/r/compute_router.html 34 | resource "google_compute_router" "router" { 35 | name = "router" 36 | network = google_compute_network.main.id 37 | bgp { 38 | asn = 64514 39 | advertise_mode = "CUSTOM" 40 | } 41 | } 42 | 43 | # NAT Gateway 44 | # https://www.terraform.io/docs/providers/google/r/compute_router_nat.html 45 | resource "google_compute_router_nat" "nat" { 46 | name = "nat" 47 | router = google_compute_router.router.name 48 | region = google_compute_router.router.region 49 | nat_ip_allocate_option = "AUTO_ONLY" 50 | source_subnetwork_ip_ranges_to_nat = "LIST_OF_SUBNETWORKS" 51 | 52 | subnetwork { 53 | name = "private" 54 | source_ip_ranges_to_nat = ["ALL_IP_RANGES"] 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lessons/019/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | project = "devops-by-example" 3 | region = "us-west2" 4 | } 5 | 6 | provider "google" { 7 | credentials = file("~/devops-by-example-9004d3b359f5.json") 8 | project = local.project 9 | region = local.region 10 | } 11 | 12 | # https://github.com/terraform-google-modules/terraform-google-network 13 | module "vpc" { 14 | source = "terraform-google-modules/network/google" 15 | version = "2.5.0" 16 | 17 | project_id = local.project 18 | network_name = "main" 19 | routing_mode = "REGIONAL" 20 | 21 | delete_default_internet_gateway_routes = "true" 22 | 23 | subnets = [ 24 | { 25 | subnet_name = "public" 26 | subnet_ip = "10.0.0.0/24" 27 | subnet_region = "us-west2" 28 | subnet_private_access = "false" 29 | subnet_flow_logs = "false" 30 | }, 31 | { 32 | subnet_name = "private" 33 | subnet_ip = "10.0.1.0/24" 34 | subnet_region = "us-west2" 35 | subnet_private_access = "true" 36 | subnet_flow_logs = "false" 37 | } 38 | ] 39 | 40 | routes = [ 41 | { 42 | name = "egress-internet" 43 | description = "Default route through IGW to access internet" 44 | destination_range = "0.0.0.0/0" 45 | next_hop_internet = "true" 46 | } 47 | ] 48 | } 49 | 50 | # https://github.com/terraform-google-modules/terraform-google-cloud-router 51 | module "cloud_router" { 52 | source = "terraform-google-modules/cloud-router/google" 53 | version = "0.3.0" 54 | 55 | name = "router" 56 | project = local.project 57 | region = local.region 58 | network = module.vpc.network_name 59 | nats = [{ 60 | name = "nat" 61 | nat_ip_allocate_option = "AUTO_ONLY" 62 | source_subnetwork_ip_ranges_to_nat = "LIST_OF_SUBNETWORKS" 63 | subnetworks = [{ 64 | name = "private" 65 | source_ip_ranges_to_nat = ["ALL_IP_RANGES"] 66 | }] 67 | }] 68 | } 69 | -------------------------------------------------------------------------------- /lessons/023/app/.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 | -------------------------------------------------------------------------------- /lessons/023/app/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: app 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 | appVersion: 1.16.0 24 | -------------------------------------------------------------------------------- /lessons/023/app/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if .Values.ingress.enabled }} 3 | {{- range $host := .Values.ingress.hosts }} 4 | {{- range .paths }} 5 | http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} 6 | {{- end }} 7 | {{- end }} 8 | {{- else if contains "NodePort" .Values.service.type }} 9 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "app.fullname" . }}) 10 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 11 | echo http://$NODE_IP:$NODE_PORT 12 | {{- else if contains "LoadBalancer" .Values.service.type }} 13 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 14 | You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "app.fullname" . }}' 15 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "app.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") 16 | echo http://$SERVICE_IP:{{ .Values.service.port }} 17 | {{- else if contains "ClusterIP" .Values.service.type }} 18 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "app.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") 19 | export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") 20 | echo "Visit http://127.0.0.1:8080 to use your application" 21 | kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT 22 | {{- end }} 23 | -------------------------------------------------------------------------------- /lessons/023/app/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "app.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "app.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "app.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "app.labels" -}} 37 | helm.sh/chart: {{ include "app.chart" . }} 38 | {{ include "app.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "app.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "app.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "app.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "app.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /lessons/023/app/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "app.fullname" . }} 5 | labels: 6 | {{- include "app.labels" . | nindent 4 }} 7 | spec: 8 | {{- if not .Values.autoscaling.enabled }} 9 | replicas: {{ .Values.replicaCount }} 10 | {{- end }} 11 | selector: 12 | matchLabels: 13 | {{- include "app.selectorLabels" . | nindent 6 }} 14 | template: 15 | metadata: 16 | {{- with .Values.podAnnotations }} 17 | annotations: 18 | {{- toYaml . | nindent 8 }} 19 | {{- end }} 20 | labels: 21 | {{- include "app.selectorLabels" . | nindent 8 }} 22 | spec: 23 | {{- with .Values.imagePullSecrets }} 24 | imagePullSecrets: 25 | {{- toYaml . | nindent 8 }} 26 | {{- end }} 27 | serviceAccountName: {{ include "app.serviceAccountName" . }} 28 | securityContext: 29 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 30 | containers: 31 | - name: {{ .Chart.Name }} 32 | securityContext: 33 | {{- toYaml .Values.securityContext | nindent 12 }} 34 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 35 | imagePullPolicy: {{ .Values.image.pullPolicy }} 36 | ports: 37 | - name: http 38 | containerPort: 80 39 | protocol: TCP 40 | livenessProbe: 41 | httpGet: 42 | path: / 43 | port: http 44 | readinessProbe: 45 | httpGet: 46 | path: / 47 | port: http 48 | resources: 49 | {{- toYaml .Values.resources | nindent 12 }} 50 | {{- with .Values.nodeSelector }} 51 | nodeSelector: 52 | {{- toYaml . | nindent 8 }} 53 | {{- end }} 54 | {{- with .Values.affinity }} 55 | affinity: 56 | {{- toYaml . | nindent 8 }} 57 | {{- end }} 58 | {{- with .Values.tolerations }} 59 | tolerations: 60 | {{- toYaml . | nindent 8 }} 61 | {{- end }} 62 | -------------------------------------------------------------------------------- /lessons/023/app/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.autoscaling.enabled }} 2 | apiVersion: autoscaling/v2beta1 3 | kind: HorizontalPodAutoscaler 4 | metadata: 5 | name: {{ include "app.fullname" . }} 6 | labels: 7 | {{- include "app.labels" . | nindent 4 }} 8 | spec: 9 | scaleTargetRef: 10 | apiVersion: apps/v1 11 | kind: Deployment 12 | name: {{ include "app.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 | -------------------------------------------------------------------------------- /lessons/023/app/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.enabled -}} 2 | {{- $fullName := include "app.fullname" . -}} 3 | {{- $svcPort := .Values.service.port -}} 4 | {{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} 5 | apiVersion: networking.k8s.io/v1beta1 6 | {{- else -}} 7 | apiVersion: extensions/v1beta1 8 | {{- end }} 9 | kind: Ingress 10 | metadata: 11 | name: {{ $fullName }} 12 | labels: 13 | {{- include "app.labels" . | nindent 4 }} 14 | {{- with .Values.ingress.annotations }} 15 | annotations: 16 | {{- toYaml . | nindent 4 }} 17 | {{- end }} 18 | spec: 19 | {{- if .Values.ingress.tls }} 20 | tls: 21 | {{- range .Values.ingress.tls }} 22 | - hosts: 23 | {{- range .hosts }} 24 | - {{ . | quote }} 25 | {{- end }} 26 | secretName: {{ .secretName }} 27 | {{- end }} 28 | {{- end }} 29 | rules: 30 | {{- range .Values.ingress.hosts }} 31 | - host: {{ .host | quote }} 32 | http: 33 | paths: 34 | {{- range .paths }} 35 | - path: {{ . }} 36 | backend: 37 | serviceName: {{ $fullName }} 38 | servicePort: {{ $svcPort }} 39 | {{- end }} 40 | {{- end }} 41 | {{- end }} 42 | -------------------------------------------------------------------------------- /lessons/023/app/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "app.fullname" . }} 5 | labels: 6 | {{- include "app.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 "app.selectorLabels" . | nindent 4 }} 16 | -------------------------------------------------------------------------------- /lessons/023/app/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "app.serviceAccountName" . }} 6 | labels: 7 | {{- include "app.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /lessons/023/app/templates/tests/test-connection.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: "{{ include "app.fullname" . }}-test-connection" 5 | labels: 6 | {{- include "app.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 "app.fullname" . }}:{{ .Values.service.port }}'] 15 | restartPolicy: Never 16 | -------------------------------------------------------------------------------- /lessons/023/app/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for app. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | replicaCount: 1 6 | 7 | image: 8 | repository: nginx 9 | pullPolicy: IfNotPresent 10 | # Overrides the image tag whose default is the chart appVersion. 11 | tag: "" 12 | 13 | imagePullSecrets: [] 14 | nameOverride: "" 15 | fullnameOverride: "" 16 | 17 | serviceAccount: 18 | # Specifies whether a service account should be created 19 | create: true 20 | # Annotations to add to the service account 21 | annotations: {} 22 | # The name of the service account to use. 23 | # If not set and create is true, a name is generated using the fullname template 24 | name: "" 25 | 26 | podAnnotations: {} 27 | 28 | podSecurityContext: {} 29 | # fsGroup: 2000 30 | 31 | securityContext: {} 32 | # capabilities: 33 | # drop: 34 | # - ALL 35 | # readOnlyRootFilesystem: true 36 | # runAsNonRoot: true 37 | # runAsUser: 1000 38 | 39 | service: 40 | type: ClusterIP 41 | port: 80 42 | 43 | ingress: 44 | enabled: false 45 | annotations: {} 46 | # kubernetes.io/ingress.class: nginx 47 | # kubernetes.io/tls-acme: "true" 48 | hosts: 49 | - host: chart-example.local 50 | paths: [] 51 | tls: [] 52 | # - secretName: chart-example-tls 53 | # hosts: 54 | # - chart-example.local 55 | 56 | resources: {} 57 | # We usually recommend not to specify default resources and to leave this as a conscious 58 | # choice for the user. This also increases chances charts run on environments with little 59 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 60 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 61 | # limits: 62 | # cpu: 100m 63 | # memory: 128Mi 64 | # requests: 65 | # cpu: 100m 66 | # memory: 128Mi 67 | 68 | autoscaling: 69 | enabled: false 70 | minReplicas: 1 71 | maxReplicas: 100 72 | targetCPUUtilizationPercentage: 80 73 | # targetMemoryUtilizationPercentage: 80 74 | 75 | nodeSelector: {} 76 | 77 | tolerations: [] 78 | 79 | affinity: {} 80 | -------------------------------------------------------------------------------- /lessons/023/eksctl-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: eksctl.io/v1alpha5 3 | kind: ClusterConfig 4 | metadata: 5 | name: devops-by-example 6 | region: us-east-1 7 | availabilityZones: 8 | - us-east-1a 9 | - us-east-1b 10 | nodeGroups: 11 | - name: nodes-general 12 | labels: 13 | role: workers 14 | instanceType: t2.small 15 | desiredCapacity: 1 16 | volumeSize: 20 17 | -------------------------------------------------------------------------------- /lessons/024/hello-world/.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 | -------------------------------------------------------------------------------- /lessons/024/hello-world/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: hello-world 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 | appVersion: 1.16.0 24 | -------------------------------------------------------------------------------- /lessons/024/hello-world/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if .Values.ingress.enabled }} 3 | {{- range $host := .Values.ingress.hosts }} 4 | {{- range .paths }} 5 | http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} 6 | {{- end }} 7 | {{- end }} 8 | {{- else if contains "NodePort" .Values.service.type }} 9 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "hello-world.fullname" . }}) 10 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 11 | echo http://$NODE_IP:$NODE_PORT 12 | {{- else if contains "LoadBalancer" .Values.service.type }} 13 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 14 | You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "hello-world.fullname" . }}' 15 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "hello-world.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") 16 | echo http://$SERVICE_IP:{{ .Values.service.port }} 17 | {{- else if contains "ClusterIP" .Values.service.type }} 18 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "hello-world.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") 19 | export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") 20 | echo "Visit http://127.0.0.1:8080 to use your application" 21 | kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT 22 | {{- end }} 23 | -------------------------------------------------------------------------------- /lessons/024/hello-world/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "hello-world.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "hello-world.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "hello-world.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "hello-world.labels" -}} 37 | helm.sh/chart: {{ include "hello-world.chart" . }} 38 | {{ include "hello-world.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "hello-world.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "hello-world.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "hello-world.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "hello-world.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /lessons/024/hello-world/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "hello-world.fullname" . }} 5 | labels: 6 | {{- include "hello-world.labels" . | nindent 4 }} 7 | spec: 8 | {{- if not .Values.autoscaling.enabled }} 9 | replicas: {{ .Values.replicaCount }} 10 | {{- end }} 11 | selector: 12 | matchLabels: 13 | {{- include "hello-world.selectorLabels" . | nindent 6 }} 14 | template: 15 | metadata: 16 | {{- with .Values.podAnnotations }} 17 | annotations: 18 | {{- toYaml . | nindent 8 }} 19 | {{- end }} 20 | labels: 21 | {{- include "hello-world.selectorLabels" . | nindent 8 }} 22 | spec: 23 | {{- with .Values.imagePullSecrets }} 24 | imagePullSecrets: 25 | {{- toYaml . | nindent 8 }} 26 | {{- end }} 27 | serviceAccountName: {{ include "hello-world.serviceAccountName" . }} 28 | securityContext: 29 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 30 | containers: 31 | - name: {{ .Chart.Name }} 32 | securityContext: 33 | {{- toYaml .Values.securityContext | nindent 12 }} 34 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 35 | imagePullPolicy: {{ .Values.image.pullPolicy }} 36 | ports: 37 | - name: http 38 | containerPort: 80 39 | protocol: TCP 40 | livenessProbe: 41 | httpGet: 42 | path: / 43 | port: http 44 | readinessProbe: 45 | httpGet: 46 | path: / 47 | port: http 48 | resources: 49 | {{- toYaml .Values.resources | nindent 12 }} 50 | {{- with .Values.nodeSelector }} 51 | nodeSelector: 52 | {{- toYaml . | nindent 8 }} 53 | {{- end }} 54 | {{- with .Values.affinity }} 55 | affinity: 56 | {{- toYaml . | nindent 8 }} 57 | {{- end }} 58 | {{- with .Values.tolerations }} 59 | tolerations: 60 | {{- toYaml . | nindent 8 }} 61 | {{- end }} 62 | -------------------------------------------------------------------------------- /lessons/024/hello-world/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.autoscaling.enabled }} 2 | apiVersion: autoscaling/v2beta1 3 | kind: HorizontalPodAutoscaler 4 | metadata: 5 | name: {{ include "hello-world.fullname" . }} 6 | labels: 7 | {{- include "hello-world.labels" . | nindent 4 }} 8 | spec: 9 | scaleTargetRef: 10 | apiVersion: apps/v1 11 | kind: Deployment 12 | name: {{ include "hello-world.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 | -------------------------------------------------------------------------------- /lessons/024/hello-world/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.enabled -}} 2 | {{- $fullName := include "hello-world.fullname" . -}} 3 | {{- $svcPort := .Values.service.port -}} 4 | {{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} 5 | apiVersion: networking.k8s.io/v1beta1 6 | {{- else -}} 7 | apiVersion: extensions/v1beta1 8 | {{- end }} 9 | kind: Ingress 10 | metadata: 11 | name: {{ $fullName }} 12 | labels: 13 | {{- include "hello-world.labels" . | nindent 4 }} 14 | {{- with .Values.ingress.annotations }} 15 | annotations: 16 | {{- toYaml . | nindent 4 }} 17 | {{- end }} 18 | spec: 19 | {{- if .Values.ingress.tls }} 20 | tls: 21 | {{- range .Values.ingress.tls }} 22 | - hosts: 23 | {{- range .hosts }} 24 | - {{ . | quote }} 25 | {{- end }} 26 | secretName: {{ .secretName }} 27 | {{- end }} 28 | {{- end }} 29 | rules: 30 | {{- range .Values.ingress.hosts }} 31 | - host: {{ .host | quote }} 32 | http: 33 | paths: 34 | {{- range .paths }} 35 | - path: {{ . }} 36 | backend: 37 | serviceName: {{ $fullName }} 38 | servicePort: {{ $svcPort }} 39 | {{- end }} 40 | {{- end }} 41 | {{- end }} 42 | -------------------------------------------------------------------------------- /lessons/024/hello-world/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "hello-world.fullname" . }} 5 | labels: 6 | {{- include "hello-world.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 "hello-world.selectorLabels" . | nindent 4 }} 16 | -------------------------------------------------------------------------------- /lessons/024/hello-world/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "hello-world.serviceAccountName" . }} 6 | labels: 7 | {{- include "hello-world.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /lessons/024/hello-world/templates/tests/test-connection.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: "{{ include "hello-world.fullname" . }}-test-connection" 5 | labels: 6 | {{- include "hello-world.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 "hello-world.fullname" . }}:{{ .Values.service.port }}'] 15 | restartPolicy: Never 16 | -------------------------------------------------------------------------------- /lessons/024/hello-world/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for hello-world. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | replicaCount: 1 6 | 7 | image: 8 | repository: nginx 9 | pullPolicy: IfNotPresent 10 | # Overrides the image tag whose default is the chart appVersion. 11 | tag: "" 12 | 13 | imagePullSecrets: [] 14 | nameOverride: "" 15 | fullnameOverride: "" 16 | 17 | serviceAccount: 18 | # Specifies whether a service account should be created 19 | create: true 20 | # Annotations to add to the service account 21 | annotations: {} 22 | # The name of the service account to use. 23 | # If not set and create is true, a name is generated using the fullname template 24 | name: "" 25 | 26 | podAnnotations: {} 27 | 28 | podSecurityContext: {} 29 | # fsGroup: 2000 30 | 31 | securityContext: {} 32 | # capabilities: 33 | # drop: 34 | # - ALL 35 | # readOnlyRootFilesystem: true 36 | # runAsNonRoot: true 37 | # runAsUser: 1000 38 | 39 | service: 40 | type: ClusterIP 41 | port: 80 42 | 43 | ingress: 44 | enabled: false 45 | annotations: {} 46 | # kubernetes.io/ingress.class: nginx 47 | # kubernetes.io/tls-acme: "true" 48 | hosts: 49 | - host: chart-example.local 50 | paths: [] 51 | tls: [] 52 | # - secretName: chart-example-tls 53 | # hosts: 54 | # - chart-example.local 55 | 56 | resources: {} 57 | # We usually recommend not to specify default resources and to leave this as a conscious 58 | # choice for the user. This also increases chances charts run on environments with little 59 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 60 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 61 | # limits: 62 | # cpu: 100m 63 | # memory: 128Mi 64 | # requests: 65 | # cpu: 100m 66 | # memory: 128Mi 67 | 68 | autoscaling: 69 | enabled: false 70 | minReplicas: 1 71 | maxReplicas: 100 72 | targetCPUUtilizationPercentage: 80 73 | # targetMemoryUtilizationPercentage: 80 74 | 75 | nodeSelector: {} 76 | 77 | tolerations: [] 78 | 79 | affinity: {} 80 | -------------------------------------------------------------------------------- /lessons/025/app/.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 | -------------------------------------------------------------------------------- /lessons/025/app/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: app 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 | appVersion: 1.16.0 24 | -------------------------------------------------------------------------------- /lessons/025/app/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if .Values.ingress.enabled }} 3 | {{- range $host := .Values.ingress.hosts }} 4 | {{- range .paths }} 5 | http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} 6 | {{- end }} 7 | {{- end }} 8 | {{- else if contains "NodePort" .Values.service.type }} 9 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "app.fullname" . }}) 10 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 11 | echo http://$NODE_IP:$NODE_PORT 12 | {{- else if contains "LoadBalancer" .Values.service.type }} 13 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 14 | You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "app.fullname" . }}' 15 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "app.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") 16 | echo http://$SERVICE_IP:{{ .Values.service.port }} 17 | {{- else if contains "ClusterIP" .Values.service.type }} 18 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "app.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") 19 | export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") 20 | echo "Visit http://127.0.0.1:8080 to use your application" 21 | kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT 22 | {{- end }} 23 | -------------------------------------------------------------------------------- /lessons/025/app/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "app.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "app.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "app.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "app.labels" -}} 37 | helm.sh/chart: {{ include "app.chart" . }} 38 | {{ include "app.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "app.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "app.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "app.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "app.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /lessons/025/app/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "app.fullname" . }} 5 | labels: 6 | {{- include "app.labels" . | nindent 4 }} 7 | spec: 8 | {{- if not .Values.autoscaling.enabled }} 9 | replicas: {{ .Values.replicaCount }} 10 | {{- end }} 11 | selector: 12 | matchLabels: 13 | {{- include "app.selectorLabels" . | nindent 6 }} 14 | template: 15 | metadata: 16 | {{- with .Values.podAnnotations }} 17 | annotations: 18 | {{- toYaml . | nindent 8 }} 19 | {{- end }} 20 | labels: 21 | {{- include "app.selectorLabels" . | nindent 8 }} 22 | spec: 23 | {{- with .Values.imagePullSecrets }} 24 | imagePullSecrets: 25 | {{- toYaml . | nindent 8 }} 26 | {{- end }} 27 | serviceAccountName: {{ include "app.serviceAccountName" . }} 28 | securityContext: 29 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 30 | containers: 31 | - name: {{ .Chart.Name }} 32 | securityContext: 33 | {{- toYaml .Values.securityContext | nindent 12 }} 34 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 35 | imagePullPolicy: {{ .Values.image.pullPolicy }} 36 | env: 37 | - name: MY_PASSWORD 38 | valueFrom: 39 | secretKeyRef: 40 | name: credentials 41 | key: password 42 | ports: 43 | - name: http 44 | containerPort: 80 45 | protocol: TCP 46 | livenessProbe: 47 | httpGet: 48 | path: / 49 | port: http 50 | readinessProbe: 51 | httpGet: 52 | path: / 53 | port: http 54 | resources: 55 | {{- toYaml .Values.resources | nindent 12 }} 56 | {{- with .Values.nodeSelector }} 57 | nodeSelector: 58 | {{- toYaml . | nindent 8 }} 59 | {{- end }} 60 | {{- with .Values.affinity }} 61 | affinity: 62 | {{- toYaml . | nindent 8 }} 63 | {{- end }} 64 | {{- with .Values.tolerations }} 65 | tolerations: 66 | {{- toYaml . | nindent 8 }} 67 | {{- end }} 68 | -------------------------------------------------------------------------------- /lessons/025/app/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.autoscaling.enabled }} 2 | apiVersion: autoscaling/v2beta1 3 | kind: HorizontalPodAutoscaler 4 | metadata: 5 | name: {{ include "app.fullname" . }} 6 | labels: 7 | {{- include "app.labels" . | nindent 4 }} 8 | spec: 9 | scaleTargetRef: 10 | apiVersion: apps/v1 11 | kind: Deployment 12 | name: {{ include "app.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 | -------------------------------------------------------------------------------- /lessons/025/app/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.enabled -}} 2 | {{- $fullName := include "app.fullname" . -}} 3 | {{- $svcPort := .Values.service.port -}} 4 | {{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} 5 | apiVersion: networking.k8s.io/v1beta1 6 | {{- else -}} 7 | apiVersion: extensions/v1beta1 8 | {{- end }} 9 | kind: Ingress 10 | metadata: 11 | name: {{ $fullName }} 12 | labels: 13 | {{- include "app.labels" . | nindent 4 }} 14 | {{- with .Values.ingress.annotations }} 15 | annotations: 16 | {{- toYaml . | nindent 4 }} 17 | {{- end }} 18 | spec: 19 | {{- if .Values.ingress.tls }} 20 | tls: 21 | {{- range .Values.ingress.tls }} 22 | - hosts: 23 | {{- range .hosts }} 24 | - {{ . | quote }} 25 | {{- end }} 26 | secretName: {{ .secretName }} 27 | {{- end }} 28 | {{- end }} 29 | rules: 30 | {{- range .Values.ingress.hosts }} 31 | - host: {{ .host | quote }} 32 | http: 33 | paths: 34 | {{- range .paths }} 35 | - path: {{ . }} 36 | backend: 37 | serviceName: {{ $fullName }} 38 | servicePort: {{ $svcPort }} 39 | {{- end }} 40 | {{- end }} 41 | {{- end }} 42 | -------------------------------------------------------------------------------- /lessons/025/app/templates/secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: credentials 5 | labels: 6 | app: app 7 | chart: '{{ .Chart.Name }}-{{ .Chart.Version }}' 8 | release: '{{ .Release.Name }}' 9 | heritage: '{{ .Release.Service }}' 10 | type: Opaque 11 | data: 12 | password: {{ .Values.password | b64enc | quote }} 13 | -------------------------------------------------------------------------------- /lessons/025/app/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "app.fullname" . }} 5 | labels: 6 | {{- include "app.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 "app.selectorLabels" . | nindent 4 }} 16 | -------------------------------------------------------------------------------- /lessons/025/app/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "app.serviceAccountName" . }} 6 | labels: 7 | {{- include "app.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /lessons/025/app/templates/tests/test-connection.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: "{{ include "app.fullname" . }}-test-connection" 5 | labels: 6 | {{- include "app.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 "app.fullname" . }}:{{ .Values.service.port }}'] 15 | restartPolicy: Never 16 | -------------------------------------------------------------------------------- /lessons/025/app/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for app. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | replicaCount: 1 6 | 7 | image: 8 | repository: nginx 9 | pullPolicy: IfNotPresent 10 | # Overrides the image tag whose default is the chart appVersion. 11 | tag: "" 12 | 13 | imagePullSecrets: [] 14 | nameOverride: "" 15 | fullnameOverride: "" 16 | 17 | serviceAccount: 18 | # Specifies whether a service account should be created 19 | create: true 20 | # Annotations to add to the service account 21 | annotations: {} 22 | # The name of the service account to use. 23 | # If not set and create is true, a name is generated using the fullname template 24 | name: "" 25 | 26 | podAnnotations: {} 27 | 28 | podSecurityContext: {} 29 | # fsGroup: 2000 30 | 31 | securityContext: {} 32 | # capabilities: 33 | # drop: 34 | # - ALL 35 | # readOnlyRootFilesystem: true 36 | # runAsNonRoot: true 37 | # runAsUser: 1000 38 | 39 | service: 40 | type: ClusterIP 41 | port: 80 42 | 43 | ingress: 44 | enabled: false 45 | annotations: {} 46 | # kubernetes.io/ingress.class: nginx 47 | # kubernetes.io/tls-acme: "true" 48 | hosts: 49 | - host: chart-example.local 50 | paths: [] 51 | tls: [] 52 | # - secretName: chart-example-tls 53 | # hosts: 54 | # - chart-example.local 55 | 56 | resources: {} 57 | # We usually recommend not to specify default resources and to leave this as a conscious 58 | # choice for the user. This also increases chances charts run on environments with little 59 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 60 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 61 | # limits: 62 | # cpu: 100m 63 | # memory: 128Mi 64 | # requests: 65 | # cpu: 100m 66 | # memory: 128Mi 67 | 68 | autoscaling: 69 | enabled: false 70 | minReplicas: 1 71 | maxReplicas: 100 72 | targetCPUUtilizationPercentage: 80 73 | # targetMemoryUtilizationPercentage: 80 74 | 75 | nodeSelector: {} 76 | 77 | tolerations: [] 78 | 79 | affinity: {} 80 | -------------------------------------------------------------------------------- /lessons/025/secrets.yaml: -------------------------------------------------------------------------------- 1 | password: ENC[AES256_GCM,data:rEOmAn9qiyjfoQ==,iv:1GS8P4Xkc8Q7PFNcALwngQgyqTsX6y+A8Y3qyDOJbcc=,tag:pywoFH2/TkD7TYPob3lw/g==,type:str] 2 | sops: 3 | kms: [] 4 | gcp_kms: [] 5 | azure_kv: [] 6 | hc_vault: [] 7 | lastmodified: '2020-11-12T15:56:07Z' 8 | mac: ENC[AES256_GCM,data:nIcdvOXxTXMSSG7Ghy27a01tn+PVRETcSlORFyf9Dh5B8sA/A2uIE/2G89lGxBt++o4lC8JXI9kPZjftNbW6hADY8vSUTsq8uBOdis0frFUzwXRfmAO1VL0zGSpx8i3iSUw0b2vjo1HiRZMkre6xPKeXdMK5ZC8o4JI5hM9Ed+A=,iv:o4vhDpWy91y4ixj9wq276y6gOylzwjm956VoPCZ3o9Q=,tag:ZjECy+2qBMW6siVAkuJ9xw==,type:str] 9 | pgp: 10 | - created_at: '2020-11-12T15:55:55Z' 11 | enc: | 12 | -----BEGIN PGP MESSAGE----- 13 | 14 | hQGMA7phF/nCogIpAQv/WCYxtPYJXfwSFVgsJ4+B2qoaUF0lAmCbDXYNf8QwRoTr 15 | ysa+eFhb342AVpshvHE2hCEEkTXYMqk/BPStZMKCFDIjBxrmYorEtI2K4hNXwIM1 16 | LSeFlRXt+0JAklyil0HlPaHx7Zc0xHAwuuR3y/qMuU4z09+AwOaCzbl1fnFne2GJ 17 | KN5/sl/+zwvbEQyfWW3BXP6Z2x/MgRO3uH7UFTfRfJTJtYRKVeVUNHROI0foVHeL 18 | c2PlOo6AO7UZ+j+wgK4AJljfRmybymEMy7kdQwq79TXCcONEtO24/ylX0Uu0vmuc 19 | 35yHtaBZlPJ63btQFnP9Kv1wkeyKwuc5h9FJopPft5qIS1Dj1kzTw8KpBxF28lH3 20 | KLgRXRrEZHWzveMix/RBQAIfqpIblt2nZqbZ8u3RICnRlZIEw/ffB38xoPtg5/JO 21 | yajMlmdKAEFqRKLk3ieeGbWVR5s/IjP+/4pjQiD+vnQotUGPvxOQp6OqU/Mqr3Y1 22 | flLdkH0bUm0I1lwzKLdN0l4Ba3e5j9dhwNkJKrHmF4OmeWBp/XFb1Slkp1NDMQJ2 23 | +yFsBPUEPihOgHCYJYzpFRgZfSAxWQHPD1Y9kivgaa32yIyY/8MEWfGNOpGRrpTD 24 | xIBimrIF3jHQXHKJObcR 25 | =cC5+ 26 | -----END PGP MESSAGE----- 27 | fp: B163385D7A77BC07283535E91F6771CB1A4EF8EE 28 | unencrypted_suffix: _unencrypted 29 | version: 3.6.1 30 | --------------------------------------------------------------------------------