19 | 20 | Create a file called index.html 21 | 22 | ```bash 23 | mkdir -p ~/ckad/ 24 | vi ~/ckad/index.html 25 | ``` 26 | 27 | Edit index.html with the following text. 28 | 29 | ```bash 30 | Hardships often prepare ordinary people for an extraordinary destiny. 31 | ``` 32 | 33 | Create a file called Dockerfile 34 | 35 | ```bash 36 | vi ~/ckad/Dockerfile 37 | ``` 38 | 39 | Edit the Docker with to include the text below 40 | : 41 | ```bash 42 | FROM nginx:latest 43 | COPY ./index.html /usr/share/nginx/html/index.html 44 | ``` 45 | 46 | ```bash 47 | cd ~/ckad/ 48 | clear 49 | # Build the docker image 50 | docker build -t my-image:v0.1 . 51 | docker images 52 | ``` 53 | 54 | ```bash 55 | # Create a TAR file from the image file 56 | docker save --output my-image.tar my-image:v0.1 57 | ls my-image* 58 | ``` 59 | 60 | 61 |
62 |66 | 67 | kubernetes.io bookmark: [docker run](https://kubernetes.io/docs/reference/kubectl/docker-cli-to-kubectl/) 68 | 69 | ```bash 70 | clear 71 | # Run the docker image 72 | docker run -it --rm -d -p 8080:80 --name my-container my-image:v0.1 73 | ``` 74 | 75 | ```bash 76 | clear 77 | # Verify Operation 78 | curl localhost:8080 79 | ``` 80 | 81 | ```bash 82 | clear 83 | # List all images 84 | docker ps -a 85 | ``` 86 | 87 | ```bash 88 | clear 89 | # Stop the Container 90 | docker container stop my-container 91 | ``` 92 | 93 | ```bash 94 | clear 95 | # Delete the Image 96 | docker image rm my-image:v0.1 97 | ``` 98 | 99 |
100 |104 | 105 | ```bash 106 | clear 107 | # Prune all dangling images 108 | docker image prune -a 109 | ``` 110 | 111 |
112 |
122 |
123 | ```bash
124 | clear
125 | # Create the namespace
126 | kubectl create namespace pod-namespace
127 | ```
128 |
129 | ```bash
130 | clear
131 | # Switch context into the namespace so that all subsequent commands execute inside that namespace.
132 | kubectl config set-context --current --namespace=pod-namespace
133 | ```
134 |
135 | ##### Help Examples
136 |
137 | ```bash
138 | clear
139 | # Run the help flag to get examples
140 | kubectl run -h | more
141 | ```
142 |
143 | Output:
144 |
145 | ```console
146 | Examples:
147 |
148 | # Start a nginx pod
149 |
150 | kubectl run nginx --image=nginx
151 |
152 | # Start a hazelcast pod and let the container expose port 5701
153 |
154 | kubectl run hazelcast --image=hazelcast/hazelcast --port=5701
155 |
156 | # Start a hazelcast pod and set environment variables "DNS_DOMAIN=cluster" and "POD_NAMESPACE=default" in the
157 |
158 | container
159 | kubectl run hazelcast --image=hazelcast/hazelcast --env="DNS_DOMAIN=cluster" --env="POD_NAMESPACE=default"
160 |
161 | # Start a hazelcast pod and set labels "app=hazelcast" and "env=prod" in the container
162 |
163 | kubectl run hazelcast --image=hazelcast/hazelcast --labels="app=hazelcast,env=prod"
164 |
165 | # Dry run; print the corresponding API objects without creating them
166 |
167 | kubectl run nginx --image=nginx --dry-run=client 👈👈👈 This example matches most closely to the question. Just needs an output file.
168 |
169 | # Start a nginx pod, but overload the spec with a partial set of values parsed from JSON
170 |
171 | kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { ... } }'
172 |
173 | # Start a busybox pod and keep it in the foreground, don't restart it if it exits
174 |
175 | kubectl run -i -t busybox --image=busybox --restart=Never
176 |
177 | # Start the nginx pod using the default command, but use custom arguments (arg1 .. argN) for that command
178 |
179 | kubectl run nginx --image=nginx --
191 | 192 | kubernetes.io bookmark: [kubectl Cheat Sheet](https://kubernetes.io/docs/reference/kubectl/cheatsheet/) 193 | 194 | ```bash 195 | clear 196 | # Using the best example that matches the question 197 | mkdir -p ~/ckad/ 198 | kubectl run pod-1 --image=nginx --dry-run=client -o yaml > ~/ckad/01-02.yml 199 | ``` 200 | 201 | ```bash 202 | clear 203 | # Edit the YAML file to make required changes 204 | # Use the Question number in case you want to return to the question for reference or for review 205 | vi ~/ckad/01-02.yml 206 | ``` 207 | 208 | ```yaml 209 | apiVersion: v1 210 | kind: Pod 211 | metadata: 212 | creationTimestamp: null 213 | labels: 214 | run: pod-1 215 | name: pod-1 216 | spec: 217 | containers: 218 | - image: nginx 219 | name: container-1 #👈👈👈 Change from pod-1 to container-1 220 | resources: {} 221 | dnsPolicy: ClusterFirst 222 | restartPolicy: Always 223 | status: {} 224 | ``` 225 | 226 | ```bash 227 | clear 228 | # Apply the YAML file to the Kubernetes API server 229 | kubectl apply -f ~/ckad/01-02.yml 230 | ``` 231 | 232 | ```bash 233 | clear 234 | # Quick verification that the pod was created and is working 235 | kubectl get pod --watch 236 | ``` 237 | 238 |
239 |251 | 252 |  253 | 254 | Legend 255 | * PersistentVolume – the low level representation of a storage volume 256 | * PersistentVolumeClaim – the binding between a Pod and PersistentVolume 257 | * Pod – a running container that will consume a PersistentVolume 258 | * StorageClass – allows for dynamic provisioning of PersistentVolumes 259 | 260 | [Access Modes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes) 261 | * ReadWriteOnce(RWO) - volume can be mounted as read-write by a single node. 262 | * ReadOnlyMany(ROX) - volume can be mounted read-only by many nodes. 263 | * ReadWriteMany(RWX) - volume can be mounted as read-write by many nodes. 264 | * ReadWriteOncePod(RWOP) - volume can be mounted as read-write by a single Pod. 265 | 266 | Notes 267 | * Once a PV is bound to a PVC, that PV is essentially tied to the PVC and cannot be bound to by another PVC. 268 | * There is a one-to-one mapping of PVs and PVCs. 269 | * However, multiple pods in the same project can use the same PVC. 270 | * The link between PV and PVC is not explict, instead the PVC makes a some requests for storage. 271 | * Kubernetes will pick an appropriate PersistentVolume to meet that claim. 272 | * StorageClass provisions PV dynamically, when PVC claims it. 273 | * StorageClass allows for dynamically provisioned volumes for an incoming claim. 274 | 275 | 276 |
277 |281 | 282 | ```bash 283 | clear 284 | kubectl create namespace storage-namespace 285 | kubectl config set-context --current --namespace=storage-namespace 286 | ``` 287 | 288 |
289 |294 | 295 | kubernetes.io bookmark: [Create a PersistentVolume](https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/#create-a-persistentvolume) 296 | 297 | ```bash 298 | # Create a YAML file for the PV 299 | mkdir -p ~/ckad/ 300 | vi ~/ckad/01-03-pv.yml 301 | ``` 302 | 303 | ```yaml 304 | apiVersion: v1 305 | kind: PersistentVolume 306 | metadata: 307 | name: my-pv #👈👈👈 Change 308 | labels: 309 | type: local 310 | spec: 311 | storageClassName: manual 312 | capacity: 313 | storage: 5Gi #👈👈👈 Change 314 | accessModes: 315 | - ReadWriteOnce 316 | hostPath: 317 | path: "/mnt/my-host" #👈👈👈 Change 318 | ``` 319 | 320 | ```bash 321 | kubectl apply -f ~/ckad/01-03-pv.yml 322 | clear 323 | kubectl get pv 324 | ``` 325 | 326 | Output: 327 | 328 | ```console 329 | # Note the STATUS=Available 330 | NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM 331 | my-pv 5Gi RWO Retain Available 332 | ``` 333 | 334 |
335 |339 | 340 | kubernetes.io bookmark: [Create a PersistentVolumeClaim](https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/#create-a-persistentvolumeclaim) 341 | 342 | ```bash 343 | # Create a YAML file for the PVC 344 | mkdir -p ~/ckad/ 345 | vi ~/ckad/01-03-pvc.yml 346 | ``` 347 | 348 | ```yaml 349 | apiVersion: v1 350 | kind: PersistentVolumeClaim 351 | metadata: 352 | name: my-pvc #👈👈👈 Change 353 | spec: 354 | storageClassName: manual 355 | accessModes: 356 | - ReadWriteOnce 357 | resources: 358 | requests: 359 | storage: 2Gi #👈👈👈 Change 360 | ``` 361 | 362 | ```bash 363 | kubectl apply -f ~/ckad/01-03-pvc.yml 364 | clear 365 | kubectl get pv 366 | kubectl get pvc 367 | ``` 368 | 369 | Output: 370 | 371 | ```console 372 | NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM 373 | my-pv 5Gi RWO Retain Bound storage-namespace/my-pvc # STATUS=Bound means the PV and PVC are linked 374 | 375 | NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE 376 | my-pvc Bound my-pv 5Gi RWO manual 6s # STATUS=Bound means the PV and PVC are linked 377 | ``` 378 | 379 |
380 |384 | 385 | kubernetes.io bookmark: [Create a Pod](https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/#create-a-pod) 386 | 387 | ```bash 388 | # Create a YAML file for the Pod 389 | mkdir -p ~/ckad/ 390 | vi ~/ckad/01-03-pod.yml 391 | ``` 392 | 393 | ```yaml 394 | apiVersion: v1 395 | kind: Pod 396 | metadata: 397 | name: storage-pod #👈👈👈 Change 398 | spec: 399 | volumes: 400 | - name: my-volume 401 | persistentVolumeClaim: 402 | claimName: my-pvc #👈👈👈 Change 403 | containers: 404 | - name: my-container 405 | image: nginx 406 | ports: 407 | - containerPort: 80 408 | name: "http-server" 409 | volumeMounts: 410 | - mountPath: "/my-mount" #👈👈👈 Change 411 | name: my-volume 412 | 413 | ``` 414 | 415 | ```bash 416 | kubectl apply -f ~/ckad/01-03-pod.yml 417 | clear 418 | # Verify that the volume is mounted 419 | # Or just kubectl describe pod storage-pod 420 | kubectl describe pod storage-pod | grep -i Mounts -A1 421 | ``` 422 | 423 | Output: 424 | 425 | ```console 426 | Mounts: 427 | /my-mount from my-volume (rw) # Success 428 | ``` 429 | 430 |
431 |438 | 439 | ```bash 440 | cd 441 | yes | rm -R ~/ckad/ 442 | kubectl delete ns storage-namespace --force 443 | kubectl delete ns pod-namespace --force 444 | kubectl delete pv my-pv 445 | ``` 446 | 447 |
448 |21 | 22 | ```bash 23 | clear 24 | # kubectl get Custom Resource Definitions 25 | kubectl get crds 26 | ``` 27 | 28 | Output: 29 | 30 | ```console 31 | NAME CREATED AT 32 | bgpconfigurations.crd.projectcalico.org 2021-09-24T05:26:26Z 33 | bgppeers.crd.projectcalico.org 2021-09-24T05:26:26Z 34 | blockaffinities.crd.projectcalico.org 2021-09-24T05:26:26Z 35 | clusterinformations.crd.projectcalico.org 2021-09-24T05:26:26Z 36 | extensionservices.projectcontour.io 2021-09-24T05:26:16Z 37 | felixconfigurations.crd.projectcalico.org 2021-09-24T05:26:26Z 38 | globalnetworkpolicies.crd.projectcalico.org 2021-09-24T05:26:26Z 39 | globalnetworksets.crd.projectcalico.org 2021-09-24T05:26:26Z 40 | hostendpoints.crd.projectcalico.org 2021-09-24T05:26:26Z 41 | httpproxies.projectcontour.io 2021-09-24T05:26:16Z 42 | ipamblocks.crd.projectcalico.org 2021-09-24T05:26:26Z 43 | ipamconfigs.crd.projectcalico.org 2021-09-24T05:26:26Z 44 | ipamhandles.crd.projectcalico.org 2021-09-24T05:26:26Z 45 | ippools.crd.projectcalico.org 2021-09-24T05:26:26Z 46 | kubecontrollersconfigurations.crd.projectcalico.org 2021-09-24T05:26:26Z 47 | networkpolicies.crd.projectcalico.org 2021-09-24T05:26:26Z 48 | networksets.crd.projectcalico.org 2021-09-24T05:26:26Z 49 | tlscertificatedelegations.projectcontour.io 2021-09-24T05:26:16Z 50 | ``` 51 | 52 |
53 |57 | 58 | ```bash 59 | kubectl config set-context --current --namespace=default 60 | clear 61 | kubectl api-resources -o name | grep calico 62 | ``` 63 | 64 | Output: 65 | 66 | ```console 67 | bgpconfigurations.crd.projectcalico.org 68 | bgppeers.crd.projectcalico.org 69 | blockaffinities.crd.projectcalico.org 70 | clusterinformations.crd.projectcalico.org 71 | felixconfigurations.crd.projectcalico.org 72 | globalnetworkpolicies.crd.projectcalico.org 73 | globalnetworksets.crd.projectcalico.org 74 | hostendpoints.crd.projectcalico.org 75 | ipamblocks.crd.projectcalico.org 76 | ipamconfigs.crd.projectcalico.org 77 | ipamhandles.crd.projectcalico.org 78 | ippools.crd.projectcalico.org 79 | kubecontrollersconfigurations.crd.projectcalico.org 80 | networkpolicies.crd.projectcalico.org 👈👈👈 This is the Calico Resource Type that we want 81 | networksets.crd.projectcalico.org 82 | ``` 83 | 84 | ```bash 85 | clear 86 | # This is the command to get all Calico Network Policies 87 | # If you run this command it will return: "No resources found in storage-namespace namespace" 88 | # As we have not created any Calico Network Policies 89 | kubectl get networkpolicies.crd.projectcalico.org 90 | ``` 91 | 92 |
93 |105 | 106 | ```bash 107 | clear 108 | kubectl create namespace quota-namespace 109 | kubectl config set-context --current --namespace=quota-namespace 110 | ``` 111 | 112 |
113 |117 | 118 | ```bash 119 | clear 120 | kubectl create quota -h | more 121 | ``` 122 | 123 | Output 124 | 125 | ```console 126 | # Create a new resource quota named my-quota 127 | kubectl create quota my-quota --hard=cpu=1,memory=1G,pods=2,services=3,replicationcontrollers=2,resourcequotas=1,secrets=5,persistentvolumeclaims=10 👈👈👈 This example matches most closely to the question. 128 | 129 | # Create a new resource quota named best-effort 130 | kubectl create quota best-effort --hard=pods=100 --scopes=BestEffort 131 | ``` 132 | 133 |
134 |138 | 139 | ```bash 140 | clear 141 | kubectl create quota my-quota --hard=cpu=500m,memory=2G 142 | kubectl get quota 143 | ``` 144 | 145 | Output: 146 | 147 | ```console 148 | NAME AGE REQUEST LIMIT 149 | my-quota 118s cpu: 0/500m, memory: 0/2G 150 | ``` 151 | 152 | ```bash 153 | # Try to run a Pod with resource requests exceeding the quota 154 | mkdir -p ~/ckad/ 155 | clear 156 | kubectl run nginx --image=nginx --restart=Never --dry-run=client -o yaml | kubectl set resources -f - --requests=cpu=1000m,memory=4Gi --limits=cpu=1000m,memory=4Gi --local -o yaml > ~/ckad/02-02-exceed.yml 157 | kubectl apply -f ~/ckad/02-02-exceed.yml 158 | ``` 159 | 160 | In English: 161 | 162 | | Value | Translation | 163 | | ------- | ----------------- | 164 | | REQUEST | Minimum (Request) | 165 | | LIMIT | Maximum (Limits) | 166 | 167 | 168 | LimitRange 169 | * The LimitRange object cannot be created from the command line 170 | * Use the [Configure LimitRange](https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/memory-constraint-namespace/#create-a-limitrange-and-a-pod) bookmark to obtain a code snippet 171 | 172 | ```yaml 173 | apiVersion: v1 174 | kind: LimitRange 175 | metadata: 176 | name: my-limit 177 | spec: 178 | limits: 179 | - max: 180 | memory: 1Gi # 👈👈👈 Change this value 181 | cpu: 250m # 👈👈👈 Change this value 182 | type: Pod # 👈👈👈 Change this value 183 | ``` 184 | 185 | 186 | ```bash 187 | # This Pod is within the resource requests of the Resource Quota and LimitRange 188 | mkdir -p ~/ckad/ 189 | clear 190 | kubectl run nginx --image=nginx --restart=Never --dry-run=client -o yaml | kubectl set resources -f - --requests=cpu=200m,memory=512Mi --limits=cpu=200m,memory=512Mi --local -o yaml > ~/ckad/02-02-succeed.yml 191 | kubectl apply -f ~/ckad/02-02-succeed.yml 192 | kubectl get all 193 | kubectl get quota 194 | ``` 195 | 196 | Output: 197 | 198 | ```console 199 | NAME AGE REQUEST LIMIT 200 | my-quota 19m cpu: 250m/500m, memory: 1Gi/2G 201 | ``` 202 | 203 | [Meaning of memory](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#meaning-of-memory) 204 | 205 | - Limits and requests for MEMORY are measured in bytes. 206 | - You can express memory as a plain integer or as a fixed-point number using one of these suffixes: E, P, T, G, M, k. 207 | - You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. 208 | 209 | In English: 210 | 211 | | Suffix | Description | 212 | | ------ | ----------- | 213 | | E/Ei | Exabyte | 214 | | P/Pi | Petabyte | 215 | | T/Ti | Terrabyte | 216 | | G/Gi | Gigabyte | 217 | | M/Mi | Megabyte | 218 | | k/Ki | Kilobyte | 219 | 220 |
221 |233 | 234 | ```bash 235 | clear 236 | kubectl create namespace secret-namespace 237 | kubectl config set-context --current --namespace=secret-namespace 238 | ``` 239 | 240 |
241 |245 | 246 | ##### Help Examples 247 | 248 | Three types of secret: 249 | 250 | - generic 251 | - docker-registry 252 | - tls 253 | 254 | ##### Help Examples - GENERIC 255 | 256 | Create a secret from a local file, directory, or literal value 257 | 258 | ```bash 259 | clear 260 | # kubectl create secret -h 261 | kubectl create secret generic -h | more 262 | ``` 263 | 264 | Output: 265 | 266 | ```console 267 | Examples: 268 | # Create a new secret named my-secret with keys for each file in folder bar 269 | kubectl create secret generic my-secret --from-file=path/to/bar 270 | 271 | # Create a new secret named my-secret with specified keys instead of names on disk 272 | kubectl create secret generic my-secret --from-file=ssh-privatekey=path/to/id_rsa 273 | --from-file=ssh-publickey=path/to/id_rsa.pub 274 | 275 | # Create a new secret named my-secret with key1=supersecret and key2=topsecret 276 | kubectl create secret generic my-secret --from-literal=key1=supersecret --from-literal=key2=topsecret 👈👈👈 This example matches most closely to the question. 277 | 278 | # Create a new secret named my-secret using a combination of a file and a literal 279 | kubectl create secret generic my-secret --from-file=ssh-privatekey=path/to/id_rsa --from-literal=passphrase=topsecret 280 | 281 | # Create a new secret named my-secret from an env file 282 | kubectl create secret generic my-secret --from-env-file=path/to/bar.env 283 | ``` 284 | 285 | ##### Help Examples - TLS (Transport Layer Security) 286 | 287 | Create a TLS secret 288 | 289 | ```bash 290 | clear 291 | # kubectl create secret -h 292 | kubectl create secret tls -h | more 293 | ``` 294 | 295 | ```console 296 | Examples: 297 | # Create a new TLS secret named tls-secret with the given key pair 298 | kubectl create secret tls tls-secret --cert=path/to/tls.cert --key=path/to/tls.key 299 | ``` 300 | 301 |
302 |306 | 307 | ```bash 308 | clear 309 | # Create a generic secret 310 | mkdir -p ~/ckad/ 311 | kubectl create secret generic my-secret --from-literal=user=bob --from-literal=password=123456 --dry-run=client -o yaml > ~/ckad/02-03-secret.yml 312 | vi ~/ckad/02-03-secret.yml 313 | ``` 314 | 315 | kubernetes.io bookmark: [Immutable Secrets](https://kubernetes.io/docs/concepts/configuration/secret/#secret-immutable) 316 | 317 | ```yaml 318 | apiVersion: v1 319 | data: 320 | password: MTIzNDU2 321 | user: Ym9i 322 | immutable: true #👈👈👈 From Immutable Secrets link above 323 | kind: Secret 324 | metadata: 325 | creationTimestamp: null 326 | name: my-secret 327 | ``` 328 | 329 | [my-secret](examples/02-03-secret.yml) 330 | 331 | ```bash 332 | clear 333 | # Apply the YAML file to the Kubernetes API server 334 | # The secret is available to all pods in the namespace 335 | kubectl apply -f ~/ckad/02-03-secret.yml 336 | clear 337 | # Verify that the secret got created 338 | kubectl get secret my-secret 339 | kubectl describe secret my-secret 340 | ``` 341 | 342 | ```bash 343 | clear 344 | # Now to create the pod that will consume the secret 345 | kubectl run secret-pod --image=nginx --restart=Never -n secret-namespace --dry-run=client -o yaml > ~/ckad/02-03-pod.yml 346 | vi ~/ckad/02-03-pod.yml 347 | ``` 348 | 349 | kubernetes.io bookmark: [Using Secrets as environment variables](https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets-as-environment-variables) 350 | 351 | ```yaml 352 | apiVersion: v1 353 | kind: Pod 354 | metadata: 355 | creationTimestamp: null 356 | labels: 357 | run: secret-pod 358 | name: secret-pod 359 | namespace: secret-namespace 360 | spec: 361 | containers: 362 | - image: nginx 363 | name: secret-pod 364 | env: #👈👈👈 From Using Secrets as environment variables link above 365 | - name: SECRET-ENV-USER #👈👈👈 From Using Secrets as environment variables link above 366 | valueFrom: #👈👈👈 From Using Secrets as environment variables link above 367 | secretKeyRef: #👈👈👈 From Using Secrets as environment variables link above 368 | name: my-secret #👈👈👈 From Using Secrets as environment variables link above 369 | key: user #👈👈👈 From Using Secrets as environment variables link above 370 | - name: SECRET-ENV-PASSWORD #👈👈👈 From Using Secrets as environment variables link above 371 | valueFrom: #👈👈👈 From Using Secrets as environment variables link above 372 | secretKeyRef: #👈👈👈 From Using Secrets as environment variables link above 373 | name: my-secret #👈👈👈 From Using Secrets as environment variables link above 374 | key: password #👈👈👈 From Using Secrets as environment variables link above 375 | resources: {} 376 | dnsPolicy: ClusterFirst 377 | restartPolicy: Never 378 | status: {} 379 | ``` 380 | 381 | ```bash 382 | clear 383 | # Apply the YAML file to the Kubernetes API server 384 | kubectl apply -f ~/ckad/02-03-pod.yml 385 | ``` 386 | 387 | ```bash 388 | clear 389 | # Quick verification that the deployment was created and the secret is visible as an environmental variable 390 | kubectl exec secret-pod -- env 391 | ``` 392 | 393 | Output: 394 | 395 | ```console 396 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 397 | HOSTNAME=secret-pod 398 | NGINX_VERSION=1.21.3 399 | NJS_VERSION=0.6.2 400 | PKG_RELEASE=1~buster 401 | SECRET-ENV-USER=bob #👈👈👈 Success 402 | SECRET-ENV-PASSWORD=123456 #👈👈👈 Success 403 | KUBERNETES_PORT_443_TCP_PORT=443 404 | KUBERNETES_PORT_443_TCP_ADDR=10.245.0.1 405 | KUBERNETES_SERVICE_HOST=10.245.0.1 406 | KUBERNETES_SERVICE_PORT=443 407 | KUBERNETES_SERVICE_PORT_HTTPS=443 408 | KUBERNETES_PORT=tcp://10.245.0.1:443 409 | KUBERNETES_PORT_443_TCP=tcp://10.245.0.1:443 410 | KUBERNETES_PORT_443_TCP_PROTO=tcp 411 | TERM=xterm 412 | HOME=/root 413 | ``` 414 | 415 |
416 |428 | 429 | ```bash 430 | clear 431 | kubectl create namespace serviceaccount-namespace 432 | kubectl config set-context --current --namespace=serviceaccount-namespace 433 | ``` 434 | 435 |
436 |
440 |
441 | ```bash
442 | clear
443 | # Create the serviceAccount
444 | kubectl create sa my-serviceaccount
445 | ```
446 |
447 | ```bash
448 | # Get the corresponding secret created for the new serviceAccount
449 | clear
450 | kubectl get secret
451 | ```
452 |
453 | ```bash
454 | # Get the token out of the secret
455 | clear
456 | kubectl describe secret my-serviceaccount-token-***** #👈👈👈 Replace ***** with your values
457 | ```
458 |
459 | Output:
460 |
461 | ```console
462 | Name: my-serviceaccount-token-nptmw
463 | Namespace: serviceaccount-namespace
464 | Labels:
482 | 483 | ```bash 484 | # Create the pod declaratively 485 | mkdir -p ~/ckad/ 486 | kubectl run serviceaccount-pod --image=nginx --dry-run=client -o yaml > ~/ckad/02-04.yml 487 | ``` 488 | 489 | ```bash 490 | # Edit the manifest file 491 | vi ~/ckad/02-04.yml 492 | ``` 493 | 494 | kubernetes.io bookmark: [Configure Service Accounts for Pods](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) 495 | 496 | ```yaml 497 | apiVersion: v1 498 | kind: Pod 499 | metadata: 500 | creationTimestamp: null 501 | labels: 502 | run: serviceaccount-pod 503 | name: serviceaccount-pod 504 | spec: 505 | serviceAccountName: my-serviceaccount #👈👈👈 Configure Service Accounts for Pods, catch the value is serviceAccountName and NOT serviceaccount 506 | containers: 507 | - image: nginx 508 | name: serviceaccount-pod 509 | resources: {} 510 | dnsPolicy: ClusterFirst 511 | restartPolicy: Always 512 | status: {} 513 | ``` 514 | 515 | ```bash 516 | # Apply the YAML file to the Kubernetes API server 517 | kubectl apply -f ~/ckad/02-04.yml 518 | ``` 519 | 520 | ```bash 521 | # Bonus Section # Verify your work by checking the serviceAccount in use via JSONPath 522 | kubectl get pod serviceaccount-pod -o jsonpath={.spec.serviceAccountName} 523 | ``` 524 | 525 | Output 526 | 527 | ```console 528 | my-serviceaccount 529 | ``` 530 | 531 |
532 |541 | 542 |  543 | 544 |
545 |549 | 550 | In English: 551 | 552 | | Combination | Allowed/Disallowed | 553 | | ------ | ----------- | 554 | |Role + RoleBinding| Allowed | 555 | |ClusterRole + ClusterRoleBinding | Allowed | 556 | | ClusterRole + RoleBinding | Allowed | 557 | | Role + ClusterRoleBinding | DISALLOWED | 558 | 559 |
560 |564 | 565 | ```bash 566 | clear 567 | kubectl create namespace rbac-namespace #👈👈👈 Create a namespace 568 | kubectl config set-context --current --namespace=rbac-namespace #👈👈👈Change directory into the namespace 569 | kubectl create sa rbac-sa #👈👈👈 Create a Service Account (Who) 570 | kubectl create deployment rbac-deployment --image=nginx --replicas=3 #👈👈👈 Create a deployment 571 | kubectl create role rbac-role --verb=get,watch --resource=pods,pods/status #👈👈👈Create a Role (What and Where) 572 | kubectl create rolebinding rbac-rolebinding --role=rbac-role --serviceaccount=rbac-namespace:rbac-sa #👈👈👈 Bind Account and Role 573 | ``` 574 | 575 | ```bash 576 | kubectl auth can-i get pods --as=system:serviceaccount:rbac-namespace:rbac-sa # yes to get verb 577 | kubectl auth can-i delete pods --as=system:serviceaccount:rbac-namespace:rbac-sa # no to delete verb 578 | ``` 579 | 580 |
581 |
585 |
586 | ```bash
587 | kubectl get role #👈👈👈 Get all the roles defined in the namespace
588 | ```
589 |
590 | ```bash
591 | kubectl describe role rbac-role #👈👈👈 Describe the role
592 | ```
593 |
594 | ```console
595 | Name: rbac-role
596 | Labels:
662 | 663 | ```bash 664 | yes | rm -R ~/ckad/ 665 | kubectl delete ns secret-namespace --force 666 | kubectl delete ns quota-namespace --force 667 | kubectl delete ns serviceaccount-namespace --force 668 | kubectl delete ns rbac-namespace --force 669 | ``` 670 | 671 |
672 |19 | 20 | ```bash 21 | mkdir -p ~/ckad/ 22 | clear 23 | # Create the namespace 24 | kubectl create namespace deployment-namespace 25 | ``` 26 | 27 | ```bash 28 | clear 29 | # Switch context into the namespace so that all subsequent commands execute inside that namespace. 30 | kubectl config set-context --current --namespace=deployment-namespace 31 | ``` 32 | 33 | ##### Help Examples 34 | 35 | ```bash 36 | clear 37 | # Run the help flag to get examples 38 | # kubectl create deployment -h 39 | kubectl create deploy -h | more 40 | ``` 41 | 42 | Output: 43 | 44 | ```console 45 | Examples: 46 | # Create a deployment named my-dep that runs the busybox image 47 | kubectl create deployment my-dep --image=busybox 48 | 49 | # Create a deployment with a command 50 | kubectl create deployment my-dep --image=busybox -- date 51 | 52 | # Create a deployment named my-dep that runs the nginx image with 3 replicas 53 | kubectl create deployment my-dep --image=nginx --replicas=3 👈👈👈 This example matches most closely to the question: `three` replicas 54 | 55 | # Create a deployment named my-dep that runs the busybox image and expose port 5701 56 | kubectl create deployment my-dep --image=busybox --port=5701 👈👈👈 This example matches most closely to the question: `port 80` 57 | ``` 58 | 59 |
60 |64 | 65 | ```bash 66 | clear 67 | # Using the best example that matches the question 68 | kubectl create deployment my-deployment --image=nginx --replicas=3 --port=80 --dry-run=client -o yaml > ~/ckad/03-01.yml 69 | ``` 70 | 71 | ```bash 72 | # Edit the YAML file to make required changes 73 | mkdir -p ~/ckad/ 74 | vi ~/ckad/03-01.yml 75 | ``` 76 | 77 | kubernetes.io bookmark: [Meaning of memory](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#meaning-of-memory) 78 | 79 | ```bash 80 | apiVersion: apps/v1 81 | kind: Deployment 82 | metadata: 83 | creationTimestamp: null 84 | labels: 85 | app: my-deployment 86 | name: my-deployment 87 | spec: 88 | replicas: 3 89 | selector: 90 | matchLabels: 91 | app: my-deployment 92 | strategy: {} 93 | template: 94 | metadata: 95 | creationTimestamp: null 96 | labels: 97 | app: my-deployment 98 | spec: 99 | containers: 100 | - image: nginx 101 | ports: 102 | - containerPort: 80 103 | name: my-container #👈👈👈 Change from nginx to my container 104 | resources: #👈👈👈 From Meaning of memory link above 105 | requests: #👈👈👈 From Meaning of memory link above 106 | memory: "25Mi" #👈👈👈 From Meaning of memory link above 107 | limits: #👈👈👈 From Meaning of memory link above 108 | memory: "100Mi" #👈👈👈 From Meaning of memory link above 109 | status: {} 110 | ``` 111 | 112 | ```bash 113 | clear 114 | # Apply the YAML file to the Kubernetes API server 115 | kubectl apply -f ~/ckad/03-01.yml 116 | ``` 117 | 118 | ```bash 119 | clear 120 | # Quick verification that the deployment was created and is working 121 | kubectl get all 122 | ``` 123 | 124 | Output: 125 | 126 | ```console 127 | NAME READY STATUS RESTARTS AGE 128 | pod/my-deployment-67fc8546-9b4bm 1/1 Running 0 16m 129 | pod/my-deployment-67fc8546-mjw24 1/1 Running 0 16m 130 | pod/my-deployment-67fc8546-tp5bk 1/1 Running 0 16m 131 | 132 | NAME READY UP-TO-DATE AVAILABLE AGE 133 | deployment.apps/my-deployment 3/3 3 3 16m 134 | 135 | NAME DESIRED CURRENT READY AGE 136 | replicaset.apps/my-deployment-67fc8546 3 3 3 16m 137 | ``` 138 | 139 |
140 |149 | 150 | ```bash 151 | clear 152 | # Run the help flag to get examples 153 | kubectl expose -h | more 154 | ``` 155 | 156 | Output: 157 | 158 | ```console 159 | Examples: 160 | # Create a service for a replicated nginx, which serves on port 80 and connects to the containers on port 8000 161 | kubectl expose rc nginx --port=80 --target-port=8000 162 | 163 | # Create a service for a replication controller identified by type and name specified in "nginx-controller.yaml", 164 | which serves on port 80 and connects to the containers on port 8000 165 | kubectl expose -f nginx-controller.yaml --port=80 --target-port=8000 166 | 167 | # Create a service for a pod valid-pod, which serves on port 444 with the name "frontend" 168 | kubectl expose pod valid-pod --port=444 --name=frontend 169 | 170 | # Create a second service based on the above service, exposing the container port 8443 as port 443 with the name 171 | "nginx-https" 172 | kubectl expose service nginx --port=443 --target-port=8443 --name=nginx-https 173 | 174 | # Create a service for a replicated streaming application on port 4100 balancing UDP traffic and named 'video-stream'. 175 | kubectl expose rc streamer --port=4100 --protocol=UDP --name=video-stream 176 | 177 | # Create a service for a replicated nginx using replica set, which serves on port 80 and connects to the containers on 178 | port 8000 179 | kubectl expose rs nginx --port=80 --target-port=8000 180 | 181 | # Create a service for an nginx deployment, which serves on port 80 and connects to the containers on port 8000 182 | kubectl expose deployment nginx --port=80 --target-port=8000 👈👈👈 This example matches most closely to the question. 183 | ``` 184 | 185 |
186 |
190 |
191 | ```bash
192 | clear
193 | # Using the best example that matches the question
194 | kubectl expose deployment my-deployment --port=8080 --target-port=80
195 | ```
196 |
197 | Watch out for the statement from inside the Cluster so this is of type: ClusterIP
198 |
199 | Types include:
200 |
201 | - ClusterIP (default)
202 | - NodePort
203 | - LoadBalancer
204 | - ExternalName
205 |
206 | ```bash
207 | clear
208 | # Check that the Service was created
209 | # Inside the namespace: my-deployment
210 | # Outside the namespace: my-deployment.deployment-namespace.svc.cluster.local
211 | kubectl get service
212 | ```
213 |
214 | Output:
215 |
216 | ```console
217 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
218 | my-deployment ClusterIP 10.245.79.74
248 | 249 | ```bash 250 | clear 251 | kubectl create namespace edit-namespace 252 | kubectl create deployment edit-deployment --image=redis --replicas=2 -n edit-namespace 253 | kubectl config set-context --current --namespace=edit-namespace 254 | ``` 255 | 256 |
257 |261 | 262 | ##### Solution 263 | 264 | ```bash 265 | kubectl edit deployment.apps/edit-deployment 266 | ``` 267 | 268 | ```yaml 269 | # Please edit the object below. Lines beginning with a '#' will be ignored, 270 | # and an empty file will abort the edit. If an error occurs while saving this file will be 271 | # reopened with the relevant failures. 272 | # 273 | apiVersion: apps/v1 274 | kind: Deployment 275 | metadata: 276 | annotations: 277 | deployment.kubernetes.io/revision: "1" 278 | creationTimestamp: "2021-09-24T06:23:27Z" 279 | generation: 1 280 | labels: 281 | app: edit-deployment 282 | name: edit-deployment 283 | namespace: edit-namespace 284 | resourceVersion: "7856" 285 | uid: d482067c-da5f-43ce-aa31-25defd2d0de3 286 | spec: 287 | progressDeadlineSeconds: 600 288 | replicas: 2 289 | revisionHistoryLimit: 10 290 | selector: 291 | matchLabels: 292 | app: edit-deployment 293 | strategy: 294 | rollingUpdate: 295 | maxSurge: 25% 296 | maxUnavailable: 25% 297 | type: RollingUpdate 298 | template: 299 | metadata: 300 | creationTimestamp: null 301 | labels: 302 | app: edit-deployment 303 | spec: 304 | containers: 305 | - image: redis #👈👈👈 Change this to nginx 306 | imagePullPolicy: Always 307 | name: redis #👈👈👈 This is the catch, when you created the deployment it used the image=redis to also name the container redis 308 | resources: {} 309 | terminationMessagePath: /dev/termination-log 310 | terminationMessagePolicy: File 311 | dnsPolicy: ClusterFirst 312 | restartPolicy: Always 313 | ``` 314 | 315 | ```bash 316 | clear 317 | # Check the image in the Deployment 318 | kubectl describe deployment edit-deployment | grep Image 319 | ``` 320 | 321 | This works but does not record what the change was. 322 | 323 |
324 |328 | 329 | kubernetes.io:[Updating a Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#updating-a-deployment) 330 | 331 | ```bash 332 | clear 333 | # Use the kubectl set image command 334 | kubectl set image deployment.apps/edit-deployment redis=nginx:1.14.2 335 | ``` 336 | 337 | ```bash 338 | clear 339 | # Check the image in the Deployment 340 | kubectl describe deployment edit-deployment | grep Image 341 | ``` 342 | 343 |
344 |352 | 353 | WordPress on Bitnami [details](https://github.com/bitnami/charts/tree/master/bitnami/wordpress/#installing-the-chart) 354 | 355 | ```bash 356 | clear 357 | kubectl create namespace wordpress-namespace 358 | kubectl config set-context --current --namespace=wordpress-namespace 359 | ``` 360 | 361 |
362 |366 | 367 | ```bash 368 | clear 369 | # Add the Bitnami repo 370 | helm repo add bitnami https://charts.bitnami.com/bitnami 371 | ``` 372 | 373 | ```bash 374 | # Search the Bitnami repo for available software 375 | helm search repo bitnami 376 | ``` 377 | 378 | Output: 379 | 380 | ```console 381 | NAME CHART VERSION APP VERSION DESCRIPTION 382 | bitnami/bitnami-common 0.0.9 0.0.9 DEPRECATED Chart with custom templates used in ... 383 | bitnami/airflow 11.0.8 2.1.4 Apache Airflow is a platform to programmaticall... 384 | bitnami/apache 8.8.3 2.4.50 Chart for Apache HTTP Server 385 | bitnami/argo-cd 2.0.4 2.1.3 Declarative, GitOps continuous delivery tool fo... 386 | bitnami/argo-workflows 0.1.1 3.1.13 Argo Workflows is meant to orchestrate Kubernet... 387 | bitnami/aspnet-core 1.3.18 3.1.19 ASP.NET Core is an open-source framework create... 388 | bitnami/cassandra 8.0.6 4.0.1 Apache Cassandra is a free and open-source dist... 389 | bitnami/cert-manager 0.1.21 1.5.4 Cert Manager is a Kubernetes add-on to automate... 390 | bitnami/common 1.10.0 1.10.0 A Library Helm Chart for grouping common logic ... 391 | bitnami/concourse 0.1.7 7.5.0 Concourse is a pipeline-based continuous thing-... 392 | bitnami/consul 9.3.8 1.10.3 Highly available and distributed service discov... 393 | bitnami/contour 5.7.0 1.18.2 Contour Ingress controller for Kubernetes 394 | bitnami/contour-operator 0.1.1 1.18.2 The Contour Operator extends the Kubernetes API... 395 | bitnami/dataplatform-bp1 8.0.1 0.0.11 OCTO Data platform Kafka-Spark-Solr Helm Chart 396 | bitnami/dataplatform-bp2 8.0.3 0.0.10 OCTO Data platform Kafka-Spark-Elasticsearch He... 397 | bitnami/discourse 5.0.2 2.7.8 A Helm chart for deploying Discourse to Kubernetes 398 | bitnami/dokuwiki 11.2.8 20200729.0.0 DokuWiki is a standards-compliant, simple to us... 399 | bitnami/drupal 10.3.4 9.2.7 One of the most versatile open source content m... 400 | bitnami/ejbca 3.0.1 7.4.3-2 Enterprise class PKI Certificate Authority buil... 401 | bitnami/elasticsearch 17.1.0 7.14.2 A highly scalable open-source full-text search ... 402 | bitnami/etcd 6.8.4 3.5.0 etcd is a distributed key value store that prov... 403 | bitnami/external-dns 5.4.10 0.10.0 ExternalDNS is a Kubernetes addon that configur... 404 | bitnami/fluentd 4.2.3 1.14.1 Fluentd is an open source data collector for un... 405 | bitnami/geode 0.1.0 1.14.0 Apache Geode is a data management platform that... 406 | bitnami/ghost 14.0.22 4.17.1 A simple, powerful publishing platform that all... 407 | bitnami/grafana 6.3.2 8.2.0 Grafana is an open source, feature rich metrics... 408 | bitnami/grafana-operator 1.1.4 3.10.3 Kubernetes Operator based on the Operator SDK f... 409 | bitnami/grafana-tempo 0.2.7 1.1.0 Grafana Tempo is an open source, easy-to-use an... 410 | bitnami/haproxy 0.2.13 2.4.7 HAProxy is a TCP proxy and a HTTP reverse proxy... 411 | ... 412 | bitnami/phpmyadmin 8.2.16 5.1.1 phpMyAdmin is an mysql administration frontend 413 | bitnami/postgresql 10.12.2 11.13.0 Chart for PostgreSQL, an object-relational data... 414 | bitnami/postgresql-ha 7.10.1 11.13.0 Chart for PostgreSQL with HA architecture (usin... 415 | bitnami/prestashop 13.2.3 1.7.8-0 A popular open source ecommerce solution. Profe... 416 | bitnami/prometheus-operator 0.31.1 0.41.0 DEPRECATED The Prometheus Operator for Kubernet... 417 | bitnami/pytorch 2.3.14 1.9.0 Deep learning platform that accelerates the tra... 418 | bitnami/rabbitmq 8.22.4 3.9.7 Open source message broker software that implem... 419 | bitnami/rabbitmq-cluster-operator 0.1.6 1.9.0 The RabbitMQ Cluster Kubernetes Operator automa... 420 | bitnami/redis 15.4.1 6.2.6 Open source, advanced key-value store. It is of... 421 | bitnami/redis-cluster 6.3.9 6.2.6 Open source, advanced key-value store. It is of... 422 | bitnami/redmine 17.0.9 4.2.2 A flexible project management web application. 423 | bitnami/solr 2.0.7 8.9.0 Apache Solr is an open source enterprise search... 424 | bitnami/spark 5.7.4 3.1.2 Spark is a fast and general-purpose cluster com... 425 | bitnami/spring-cloud-dataflow 4.1.1 2.8.2 Spring Cloud Data Flow is a microservices-based... 426 | bitnami/sugarcrm 1.0.6 6.5.26 DEPRECATED SugarCRM enables businesses to creat... 427 | bitnami/suitecrm 9.3.25 7.11.22 SuiteCRM is a completely open source enterprise... 428 | bitnami/tensorflow-inception 3.3.2 1.13.0 DEPRECATED Open-source software library for ser... 429 | bitnami/tensorflow-resnet 3.2.15 2.6.0 Open-source software library serving the ResNet... 430 | bitnami/testlink 9.2.24 1.9.20 Web-based test management system that facilitat... 431 | bitnami/thanos 6.0.12 0.23.1 Thanos is a highly available metrics system tha... 432 | bitnami/tomcat 9.4.3 10.0.12 Chart for Apache Tomcat 433 | bitnami/wavefront 3.1.12 1.7.1 Chart for Wavefront Collector for Kubernetes 434 | bitnami/wavefront-adapter-for-istio 1.0.8 0.1.5 Wavefront Adapter for Istio is a lightweight Is... 435 | bitnami/wavefront-hpa-adapter 0.1.5 0.9.8 Wavefront HPA Adapter for Kubernetes is a Kuber... 436 | bitnami/wavefront-prometheus-storage-adapter 1.0.8 1.0.3 Wavefront Storage Adapter is a Prometheus integ... 437 | bitnami/wildfly 11.1.3 24.0.1 Chart for Wildfly 438 | bitnami/wordpress 12.1.20 5.8.1 Web publishing platform for building blogs and ... #👈👈👈 439 | bitnami/zookeeper 7.4.6 3.7.0 A centralized service for maintaining configura... 440 | ``` 441 | 442 | ```bash 443 | # Search the Bitnami repo for WordPress 444 | helm search repo bitnami | grep wordpress 445 | ``` 446 | 447 | Output: 448 | 449 | ```console 450 | bitnami/wordpress 12.1.20 5.8.1 Web publishing platform for building blogs and ... 451 | ``` 452 | 453 | ```bash 454 | # Install WordPress with Helm 455 | helm install my-wp-release \ 456 | --set wordpressUsername=admin \ 457 | --set wordpressPassword=password \ 458 | --set mariadb.auth.rootPassword=secretpassword \ 459 | --set service.type=ClusterIP \ 460 | bitnami/wordpress 461 | ``` 462 | 463 | Output: 464 | 465 | ```console 466 | NAME: my-wp-release 467 | LAST DEPLOYED: Fri Oct 8 15:44:30 2021 468 | NAMESPACE: wordpress-namespace 469 | STATUS: deployed 470 | REVISION: 1 471 | TEST SUITE: None 472 | NOTES: 473 | ** Please be patient while the chart is being deployed ** 474 | 475 | Your WordPress site can be accessed through the following DNS name from within your cluster: 476 | 477 | my-wp-release-wordpress.wordpress-namespace.svc.cluster.local (port 80) 478 | 479 | To access your WordPress site from outside the cluster follow the steps below: 480 | 481 | 1. Get the WordPress URL by running these commands: 482 | 483 | kubectl port-forward --namespace wordpress-namespace svc/my-wp-release-wordpress 80:80 & 484 | echo "WordPress URL: http://127.0.0.1//" 485 | echo "WordPress Admin URL: http://127.0.0.1//admin" 486 | 487 | 2. Open a browser and access WordPress using the obtained URL. 488 | 489 | 3. Login with the following credentials below to see your blog: 490 | 491 | echo Username: admin 492 | echo Password: $(kubectl get secret --namespace wordpress-namespace my-wp-release-wordpress -o jsonpath="{.data.wordpress-password}" | base64 --decode) 493 | ``` 494 | 495 | ```bash 496 | clear 497 | # Run a Busybox pod in the namespace to check your work 498 | kubectl run remote-run --image=busybox --restart=Never --rm -it 499 | # Check your work - curl the service to verify operation 500 | wget -qO- my-wp-release-wordpress 501 | ``` 502 | 503 | ```bash 504 | # List active helm releases 505 | helm ls 506 | ``` 507 | 508 | ```bash 509 | # Delete WordPress with Helm 510 | helm delete my-wp-release --purge 511 | ``` 512 | 513 | 514 |
518 | 519 | ##### Install a Release 520 | 521 | ```bash 522 | helm install happy-panda bitnami/wordpress 523 | ``` 524 | 525 | ##### Upgrade a Release 526 | 527 | ```bash 528 | helm upgrade --set foo=bar --set foo=newbar redis ./redis 529 | ``` 530 | 531 | ##### Delete a Release 532 | 533 | ```bash 534 | helm uninstall my-release 535 | ``` 536 | 537 | ##### Broken Release 538 | 539 | ```bash 540 | helm list 541 | helm uninstall my-release 542 | ``` 543 | 544 | 545 |
546 |563 | 564 |  565 | 566 | For clarity in the solution steps below i use images that return: 567 | * Green Deployment 568 | * Green !!! 569 | * Green !!! 570 | * Green !!! 571 | * Blue Deployment 572 | * Blue !!! 573 | * Blue !!! 574 | * Blue !!! 575 | 576 |
577 |581 | 582 | ```bash 583 | clear 584 | # Create the namespace 585 | kubectl create namespace blue-green-namespace 586 | ``` 587 | 588 | ```bash 589 | clear 590 | # Switch context into the namespace so that all subsequent commands execute inside that namespace. 591 | kubectl config set-context --current --namespace=blue-green-namespace 592 | ``` 593 | 594 |
595 |599 | 600 | ```bash 601 | clear 602 | mkdir -p ~/ckad/ 603 | # Create the deployment as far as possible using the CLI (imperatively) 604 | kubectl create deployment blue-deployment --image=nginx --replicas=10 --port=80 --dry-run=client -o yaml > ~/ckad/03-05-deploy-blue.yml 605 | ``` 606 | 607 | ```bash 608 | clear 609 | # Edit the YAML file to make required changes 610 | # Use the Question number in case you want to return to the question for reference or for review 611 | vi ~/ckad/03-05-deploy-blue.yml 612 | ``` 613 | 614 | ```yaml 615 | apiVersion: apps/v1 616 | kind: Deployment 617 | metadata: 618 | creationTimestamp: null 619 | labels: 620 | app: blue-deployment 621 | name: blue-deployment 622 | spec: 623 | replicas: 10 624 | selector: 625 | matchLabels: 626 | app: blue-deployment 627 | strategy: {} 628 | template: 629 | metadata: 630 | creationTimestamp: null 631 | labels: 632 | app: blue-deployment 633 | tier: web #👈👈👈 Add the label: `tier=web` 634 | spec: 635 | containers: 636 | - image: docker.io/jamesbuckett/blue:latest 637 | name: blue 638 | ports: 639 | - containerPort: 80 640 | resources: {} 641 | status: {} 642 | ``` 643 | 644 | ```bash 645 | clear 646 | # Apply the YAML file to the Kubernetes API server 647 | kubectl apply -f ~/ckad/03-05-deploy-blue.yml 648 | ``` 649 | 650 | ```bash 651 | clear 652 | # Quick verification that the pod was created and is working 653 | kubectl get pod --watch 654 | # or kubectl get pod -w 655 | ``` 656 | 657 | ```bash 658 | clear 659 | # See all labels on Pods 660 | kubectl get pods --show-labels 661 | ``` 662 | 663 | ```bash 664 | clear 665 | # Check labels specific to this question 666 | kubectl get pods -L tier,version 667 | ``` 668 | 669 |
670 |674 | 675 | ```bash 676 | clear 677 | # Create the namespace 678 | kubectl expose deployment blue-deployment --port=80 --target-port=80 --name=bg-service --dry-run=client -o yaml > ~/ckad/03-05-bsg-service.yml 679 | ``` 680 | 681 | ```bash 682 | clear 683 | mkdir -p ~/ckad/ 684 | # Edit the YAML file to make required changes 685 | vi ~/ckad/03-05-bg-service.yml 686 | ``` 687 | 688 | ```yaml 689 | apiVersion: v1 690 | kind: Service 691 | metadata: 692 | creationTimestamp: null 693 | labels: 694 | app: blue-deployment 695 | name: bg-service 696 | spec: 697 | ports: 698 | - port: 80 699 | protocol: TCP 700 | targetPort: 80 701 | selector: 702 | # app: blue-deployment #👈👈👈 Delete this 703 | tier: web #👈👈👈 Add the label: `tier=web`. This is the sauce. One label pointing to both deployments 704 | status: 705 | loadBalancer: {} 706 | ``` 707 | 708 | ```bash 709 | clear 710 | # Apply the YAML file to the Kubernetes API server 711 | kubectl apply -f ~/ckad/03-05-bg-service.yml 712 | ``` 713 | 714 |
715 |719 | 720 | ```bash 721 | clear 722 | # Create the deployment as far as possible using the CLI (imperatively) 723 | kubectl create deployment green-deployment --image=nginx --replicas=10 --port=80 --dry-run=client -o yaml > ~/ckad/03-05-deploy-green.yml 724 | ``` 725 | 726 | An even faster way would be to copy the 03-05-deploy-blue.yml to 03-05-deploy-green.yml 727 | * Alter the labels 728 | * Alter the image 729 | * Save and Apply 730 | 731 | ```bash 732 | clear 733 | mkdir -p ~/ckad/ 734 | # Edit the YAML file to make required changes 735 | # Use the Question number in case you want to return to the question for reference or for review 736 | vi ~/ckad/03-05-deploy-green.yml 737 | ``` 738 | 739 | ```yaml 740 | apiVersion: apps/v1 741 | kind: Deployment 742 | metadata: 743 | creationTimestamp: null 744 | labels: 745 | app: green-deployment 746 | name: green-deployment 747 | spec: 748 | replicas: 10 749 | selector: 750 | matchLabels: 751 | app: green-deployment 752 | strategy: {} 753 | template: 754 | metadata: 755 | creationTimestamp: null 756 | labels: 757 | app: green-deployment 758 | tier: web #👈👈👈 Add the label: `tier=web` 759 | spec: 760 | containers: 761 | - image: docker.io/jamesbuckett/green:latest 762 | name: green 763 | ports: 764 | - containerPort: 80 765 | resources: {} 766 | status: {} 767 | ``` 768 | 769 | ```bash 770 | clear 771 | # Apply the YAML file to the Kubernetes API server 772 | kubectl apply -f ~/ckad/03-05-deploy-green.yml 773 | ``` 774 | 775 | ```bash 776 | clear 777 | # Quick verification that the pod was created and is working 778 | kubectl get pod --watch 779 | # or kubectl get pod -w 780 | ``` 781 | 782 | ```bash 783 | clear 784 | # Check labels specific to this question 785 | kubectl get pods -L tier,version 786 | ``` 787 | 788 |
789 |793 | 794 | ```bash 795 | clear 796 | # Scale Blue Deployment to 7=70% 797 | kubectl scale --replicas=7 deployment blue-deployment 798 | ``` 799 | 800 | ```bash 801 | clear 802 | # Scale Green Deployment to 3=30% 803 | kubectl scale --replicas=3 deployment green-deployment 804 | ``` 805 | 806 | ```bash 807 | clear 808 | # Check labels specific to this question 809 | kubectl get pods -L tier,version 810 | ``` 811 | 812 | Output: 813 | 814 | ```console 815 | NAME READY STATUS RESTARTS AGE VERSION TIER 816 | blue-deployment-5f855f68d6-295xb 1/1 Running 0 9m52s blue web 817 | blue-deployment-5f855f68d6-2b4wv 1/1 Running 0 9m52s blue web 818 | blue-deployment-5f855f68d6-2c9wn 1/1 Running 0 9m52s blue web 819 | blue-deployment-5f855f68d6-5d4kb 1/1 Running 0 9m52s blue web 820 | blue-deployment-5f855f68d6-7tqx7 1/1 Running 0 9m52s blue web 821 | blue-deployment-5f855f68d6-k4s4w 1/1 Running 0 9m52s blue web 822 | blue-deployment-5f855f68d6-vqv8m 1/1 Running 0 9m52s blue web 823 | green-deployment-5b9f998d46-dlmsx 1/1 Running 0 112s green web 824 | green-deployment-5b9f998d46-k6lpt 1/1 Running 0 112s green web 825 | green-deployment-5b9f998d46-tjxl6 1/1 Running 0 112s green web 826 | ``` 827 | 828 | ```bash 829 | clear 830 | # Check your work - curl the service to verify operation 831 | kubectl run remote-run --image=busybox --restart=Never --rm -it 832 | # Repeat this command to see different responses 833 | wget -qO- bg-service 834 | ``` 835 | 836 | Output 837 | 838 | ```console 839 | / # wget -qO- bg-service 840 | Green !!! 841 | Green !!! 842 | Green !!! 843 | / # wget -qO- bg-service 844 | Blue !!! 845 | Blue !!! 846 | Blue !!! 847 | / # wget -qO- bg-service 848 | Blue !!! 849 | Blue !!! 850 | Blue !!! 851 | / # wget -qO- bg-service 852 | Blue !!! 853 | Blue !!! 854 | Blue !!! 855 | / # wget -qO- bg-service 856 | Blue !!! 857 | Blue !!! 858 | Blue !!! 859 | / # wget -qO- bg-service 860 | Blue !!! 861 | Blue !!! 862 | Blue !!! 863 | / # wget -qO- bg-service 864 | Blue !!! 865 | Blue !!! 866 | Blue !!! 867 | / # wget -qO- bg-service 868 | Blue !!! 869 | Blue !!! 870 | Blue !!! 871 | / # wget -qO- bg-service 872 | Green !!! 873 | Green !!! 874 | Green !!! 875 | ``` 876 | 877 |
878 |885 | 886 | ```bash 887 | yes | rm -R ~/ckad/ 888 | kubectl delete ns deployment-namespace --force 889 | kubectl delete ns edit-namespace --force 890 | kubectl delete ns wordpress-namespace --force 891 | kubectl delete ns blue-green-namespace --force 892 | ``` 893 | 894 |
895 |25 | 26 |  27 | 28 | I use the notepad to sketch out the ingress and egress before starting 29 | 30 | Rules 31 | - `tier: web` > `tier: app` on port 80 32 | 33 | Use this link to visually solve the problem: 34 | * [Network Policy Editor](https://editor.cilium.io/) 35 | 36 | Use this link for common network policy recipes: 37 | * [Kubernetes Network Policy Recipes](https://github.com/ahmetb/kubernetes-network-policy-recipes) 38 | 39 | Notes 40 | * Network policies do not conflict; they are additive. 41 | * If any policy or policies select a pod, the pod is restricted to what is allowed by the union of those policies' ingress/egress rules. 42 | * Thus, order of evaluation does not affect the policy result. 43 | 44 |
45 |
50 |
51 | For clarity in the solution steps below i use images that return:
52 | * web-pod
53 | * web-pod !!!
54 | * web-pod !!!
55 | * web-pod !!!
56 | * app-pod
57 | * app-pod !!!
58 | * app-pod !!!
59 | * app-pod !!!
60 | * db-pod
61 | * db-pod !!!
62 | * db-pod !!!
63 | * db-pod !!!
64 |
65 | ```bash
66 | mkdir ~/ckad/
67 | clear
68 | # Create all the required resources
69 | kubectl create namespace netpol-namespace
70 | kubectl config set-context --current --namespace=netpol-namespace
71 |
72 | # tier: web
73 | kubectl run web-pod --image=docker.io/jamesbuckett/web:latest --port=80 --labels="tier=web"
74 |
75 | # tier: app
76 | kubectl run app-pod --image=docker.io/jamesbuckett/app:latest --port=80 --labels="tier=app"
77 |
78 | # tier: db
79 | kubectl run db-pod --image=docker.io/jamesbuckett/db:latest --port=80 --labels="tier=db"
80 |
81 | clear
82 | kubectl get all
83 | kubectl get pod -L tier
84 | ```
85 |
86 | ```bash
87 | clear
88 | # Get the IP address of pods
89 | kubectl get pods -o wide
90 | ```
91 |
92 | ```bash
93 | # Inside the web-pod try to curl to app and db pods
94 | kubectl exec --stdin --tty web-pod -- /bin/bash
95 |
96 | #curl
105 |
106 | kubernetes.io bookmark: [The NetworkPolicy resource](https://kubernetes.io/docs/concepts/services-networking/network-policies/#networkpolicy-resource)
107 |
108 | Deny All Traffic in Namespace from [here](https://kubernetes.io/docs/concepts/services-networking/network-policies/#default-deny-all-ingress-and-all-egress-traffic)
109 |
110 | ```bash
111 | cat << EOF | kubectl apply -f -
112 | apiVersion: networking.k8s.io/v1
113 | kind: NetworkPolicy
114 | metadata:
115 | name: default-deny-all
116 | namespace: netpol-namespace
117 | spec:
118 | podSelector: {}
119 | policyTypes:
120 | - Ingress
121 | - Egress
122 | EOF
123 | ```
124 |
125 | ```bash
126 | mkdir -p ~/ckad/
127 | vi ~/ckad/04-01-netpol.yml
128 | ```
129 |
130 | ```yaml
131 | apiVersion: networking.k8s.io/v1
132 | kind: NetworkPolicy
133 | metadata:
134 | name: web-policy #👈👈👈 Change
135 | namespace: netpol-namespace
136 | spec:
137 | podSelector:
138 | matchLabels:
139 | tier: web #👈👈👈 Change - Which pod does this Network Policy Apply to i.e. any pod with label tier=web
140 | egress:
141 | - to:
142 | - podSelector:
143 | matchLabels:
144 | tier: app #👈👈👈 Egress - Traffic to pod with label tier=app
145 | ports:
146 | - port: 80
147 | ---
148 | apiVersion: networking.k8s.io/v1
149 | kind: NetworkPolicy
150 | metadata:
151 | name: app-policy #👈👈👈 Change
152 | namespace: netpol-namespace
153 | spec:
154 | podSelector:
155 | matchLabels:
156 | tier: app #👈👈👈 Change - Which pod does this Network Policy Apply to i.e. any pod with label tier=app
157 | ingress:
158 | - from:
159 | - podSelector:
160 | matchLabels:
161 | tier: web #👈👈👈 Ingress - Traffic from pod with label tier=web
162 | ports:
163 | - port: 80
164 | ```
165 |
166 | ```bash
167 | kubectl apply -f ~/ckad/04-01-netpol.yml
168 | ```
169 |
170 | ```bash
171 | clear
172 | # Get the IP address of pods
173 | kubectl get pods -o wide
174 | ```
175 |
176 | ```bash
177 | # Inside the web-pod try to curl to app and db pods
178 | kubectl exec --stdin --tty web-pod -- /bin/bash
179 |
180 | #curl
232 | 233 |  234 | 235 |
236 |240 | 241 | ```bash 242 | mkdir -p ~/ckad/ 243 | clear 244 | kubectl create namespace service-namespace 245 | kubectl config set-context --current --namespace=service-namespace 246 | ``` 247 | 248 |
249 |
253 |
254 | ##### Help Examples
255 |
256 | ```bash
257 | clear
258 | kubectl run -h | more
259 | ```
260 |
261 | Output:
262 |
263 | ```console
264 | Examples:
265 | # Start a nginx pod
266 | kubectl run nginx --image=nginx
267 |
268 | # Start a hazelcast pod and let the container expose port 5701
269 | kubectl run hazelcast --image=hazelcast/hazelcast --port=5701 👈👈👈 This example matches most closely to the question: exposing port `80`
270 |
271 | # Start a hazelcast pod and set environment variables "DNS_DOMAIN=cluster" and "POD_NAMESPACE=default" in the container
272 | kubectl run hazelcast --image=hazelcast/hazelcast --env="DNS_DOMAIN=cluster" --env="POD_NAMESPACE=default"
273 |
274 | # Start a hazelcast pod and set labels "app=hazelcast" and "env=prod" in the container
275 | kubectl run hazelcast --image=hazelcast/hazelcast --labels="app=hazelcast,env=prod" 👈👈👈 This example matches most closely to the question: Label the pod `tier=web`
276 |
277 | # Dry run; print the corresponding API objects without creating them
278 | kubectl run nginx --image=nginx --dry-run=client
279 |
280 | # Start a nginx pod, but overload the spec with a partial set of values parsed from JSON
281 | kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { ... } }'
282 |
283 | # Start a busybox pod and keep it in the foreground, don't restart it if it exits
284 | kubectl run -i -t busybox --image=busybox --restart=Never
285 |
286 | # Start the nginx pod using the default command, but use custom arguments (arg1 .. argN) for that command
287 | kubectl run nginx --image=nginx --
306 | 307 | ##### Help Examples 308 | 309 | ```bash 310 | clear 311 | kubectl expose -h | more 312 | ``` 313 | 314 | Output: 315 | 316 | ```console 317 | Examples: 318 | # Create a service for a replicated nginx, which serves on port 80 and connects to the containers on port 8000 319 | kubectl expose rc nginx --port=80 --target-port=8000 320 | 321 | # Create a service for a replication controller identified by type and name specified in "nginx-controller.yaml", 322 | which serves on port 80 and connects to the containers on port 8000 323 | kubectl expose -f nginx-controller.yaml --port=80 --target-port=8000 324 | 325 | # Create a service for a pod valid-pod, which serves on port 444 with the name "frontend" 326 | kubectl expose pod valid-pod --port=444 --name=frontend 👈👈👈 This example matches most closely to the question: pod called `my-service` 327 | 328 | # Create a second service based on the above service, exposing the container port 8443 as port 443 with the name 329 | "nginx-https" 330 | kubectl expose service nginx --port=443 --target-port=8443 --name=nginx-https 331 | 332 | # Create a service for a replicated streaming application on port 4100 balancing UDP traffic and named 'video-stream'. 333 | kubectl expose rc streamer --port=4100 --protocol=UDP --name=video-stream 334 | 335 | # Create a service for a replicated nginx using replica set, which serves on port 80 and connects to the containers on 336 | port 8000 337 | kubectl expose rs nginx --port=80 --target-port=8000 👈👈👈 This example matches most closely to the question: service expose port 8080 338 | 339 | # Create a service for an nginx deployment, which serves on port 80 and connects to the containers on port 8000 340 | kubectl expose deployment nginx --port=80 --target-port=8000 341 | ``` 342 | 343 | ##### Solution 344 | 345 | ```bash 346 | clear 347 | kubectl expose pod service-pod --port=8080 --target-port=80 --name=my-service 348 | clear 349 | kubectl get pod -o wide 350 | kubectl get service 351 | kubectl get ep 352 | ``` 353 | 354 |
355 |363 | 364 |  365 | 366 |
367 |371 | 372 | ##### Prerequisites 373 | 374 | Install the Ingress Controller if you have not already installed it: 375 | 376 | ```bash 377 | kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml 378 | ``` 379 | 380 |
381 |
385 |
386 | ##### Solution
387 |
388 | kubernetes.io bookmark: [The Ingress resource](https://kubernetes.io/docs/concepts/services-networking/ingress/#the-ingress-resource)
389 |
390 | ```bash
391 | mkdir -p ~/ckad/
392 | vi ~/ckad/04-03-ing.yml
393 | ```
394 |
395 | ```yaml
396 | apiVersion: networking.k8s.io/v1
397 | kind: Ingress
398 | metadata:
399 | name: my-ingress #👈👈👈 Change: `my-ingress`
400 | annotations:
401 | nginx.ingress.kubernetes.io/rewrite-target: /
402 | spec:
403 | ingressClassName: nginx
404 | rules:
405 | - http:
406 | paths:
407 | - path: / #👈👈👈 Change
408 | pathType: Prefix
409 | backend:
410 | service:
411 | name: my-service #👈👈👈 Change: `my-service`
412 | port:
413 | number: 8080 #👈👈👈 Change: --port=8080
414 | ```
415 |
416 | ```bash
417 | clear
418 | kubectl apply -f ~/ckad/04-03-ing.yml
419 |
420 | # Describe the ingress
421 | # This must be present to continue: Address: localhost
422 | # If not shutdown Docker Desktop and reboot Windows 10
423 | kubectl describe ingress my-ingress
424 | ```
425 |
426 | Output:
427 |
428 | ```console
429 | Name: my-ingress
430 | Namespace: service-namespace
431 | Address: localhost #👈👈👈 This must be present for the solution to work
432 | Default backend: default-http-backend:80 ( If you see this page, the nginx web server is successfully installed and
465 | working. Further configuration is required. For online documentation and support please refer to
468 | nginx.org. Thank you for using nginx.Welcome to nginx!
464 |
469 | Commercial support is available at
470 | nginx.com.
485 | 486 | ```bash 487 | yes | rm -R ~/ckad/ 488 | kubectl delete ns service-namespace --force 489 | kubectl delete ns netpol-namespace --force 490 | ``` 491 | 492 |
493 |19 | 20 | Metrics Server installs into Kubernetes 21 | 22 | By default the metrics server required for the `kubectl top` command is not present on Docker Desktop. 23 | 24 | Please install the [metrics server](https://github.com/kubernetes-sigs/metrics-server) with the following command: 25 | 26 | ```bash 27 | kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml 28 | ``` 29 | 30 | ```bash 31 | kubectl patch deployment metrics-server -n kube-system --type 'json' -p '[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-insecure-tls"}]' 32 | ``` 33 | 34 |
35 |39 | 40 | This application is useful to see CPU and Memory for a [microservices application](https://github.com/GoogleCloudPlatform/microservices-demo). 41 | 42 | ```bash 43 | kubectl create ns ns-demo 44 | kubectl apply -n ns-demo -f "https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/master/release/kubernetes-manifests.yaml" 45 | kubectl wait -n ns-demo deploy frontend --for condition=Available --timeout=90s 46 | ``` 47 |
48 |52 | 53 | ```bash 54 | clear 55 | # Requires metrics server to be installed and working 56 | # Similar to Linux top command but for pods 57 | kubectl top pods -A --sort-by=cpu | more 58 | ``` 59 | 60 | Output: 61 | 62 | ```console 63 | NAMESPACE NAME CPU(cores) MEMORY(bytes) 64 | default falco-pxf8g 51m 👈👈👈 55Mi 65 | ns-loki loki-release-prometheus-server-6d4f4df478-9z2f8 38m 356Mi 66 | ns-demo adservice-68444cb46c-jvc86 23m 202Mi 67 | ns-loki loki-release-promtail-prvvn 13m 34Mi 68 | ns-demo recommendationservice-b4cf8f489-xwv49 13m 69Mi 69 | ... 70 | ``` 71 | 72 |
73 |77 | 78 | ##### Solution 79 | 80 | ```bash 81 | clear 82 | # Requires metrics server to be installed and working 83 | # Similar to Linux top command but for pods 84 | kubectl top pods -A --sort-by=memory | more 85 | ``` 86 | 87 | Output: 88 | 89 | ```console 90 | NAMESPACE NAME CPU(cores) MEMORY(bytes) 91 | ns-loki loki-release-prometheus-server-6d4f4df478-9z2f8 11m 356Mi 👈👈👈 92 | ns-demo adservice-68444cb46c-jvc86 20m 202Mi 93 | kube-system cilium-gcnbl 6m 165Mi 94 | kube-system cilium-htrth 18m 163Mi 95 | kube-system cilium-8h6vd 5m 162Mi 96 | kube-system cilium-ml27n 11m 161Mi 97 | ... 98 | ``` 99 | 100 |
101 |111 | 112 | ```bash 113 | mkdir -p ~/ckad/ 114 | clear 115 | kubectl create namespace log-namespace 116 | kubectl run log-pod --image=nginx -n log-namespace 117 | kubectl config set-context --current --namespace=log-namespace 118 | kubectl get all 119 | ``` 120 | 121 |
122 |126 | 127 | ```bash 128 | clear 129 | kubectl logs -h | more 130 | ``` 131 | 132 | Output: 133 | 134 | ```console 135 | Examples: 136 | # Return snapshot logs from pod nginx with only one container 137 | kubectl logs nginx 138 | 139 | # Return snapshot logs from pod nginx with multi containers 140 | kubectl logs nginx --all-containers=true 141 | 142 | # Return snapshot logs from all containers in pods defined by label app=nginx 143 | kubectl logs -l app=nginx --all-containers=true 144 | 145 | # Return snapshot of previous terminated ruby container logs from pod web-1 146 | kubectl logs -p -c ruby web-1 147 | 148 | # Begin streaming the logs of the ruby container in pod web-1 149 | kubectl logs -f -c ruby web-1 150 | 151 | # Begin streaming the logs from all containers in pods defined by label app=nginx 152 | kubectl logs -f -l app=nginx --all-containers=true 153 | 154 | # Display only the most recent 20 lines of output in pod nginx 155 | kubectl logs --tail=20 nginx 156 | 157 | # Show all logs from pod nginx written in the last hour 158 | kubectl logs --since=1h nginx 👈👈👈 This example matches most closely to the question: for the `last hour` 159 | 160 | # Show logs from a kubelet with an expired serving certificate 161 | kubectl logs --insecure-skip-tls-verify-backend nginx 162 | 163 | # Return snapshot logs from first container of a job named hello 164 | kubectl logs job/hello 165 | 166 | # Return snapshot logs from container nginx-1 of a deployment named nginx 167 | kubectl logs deployment/nginx -c nginx-1 168 | ``` 169 | 170 |
171 |175 | 176 | ```bash 177 | clear 178 | # Straight forward match in the examples 179 | kubectl logs --since=1h log-pod 180 | ``` 181 | 182 |
183 |191 | 192 | kubernetes.io bookmark: [Viewing, finding resources](https://kubernetes.io/docs/reference/kubectl/cheatsheet/#viewing-finding-resources) 193 | 194 | ```bash 195 | clear 196 | kubectl get events -A --sort-by=.metadata.creationTimestamp 197 | ``` 198 | 199 |
200 |211 | 212 | * JSONPath is a query language for JSON. 213 | * It allows you to select and extract data from a JSON document. 214 | 215 |
216 |220 | 221 |  222 | 223 |
224 |228 | 229 | ```bash 230 | clear 231 | kubectl create namespace json-namespace 232 | kubectl config set-context --current --namespace=json-namespace 233 | kubectl run json-pod --image=nginx 234 | kubectl get all 235 | ``` 236 | 237 |
238 |242 | 243 | ```bash 244 | clear 245 | # kubectl explain pod.spec --recursive 246 | # kubectl explain pod.status --recursive 247 | kubectl explain pod.status | more 248 | ``` 249 | 250 | Output: 251 | 252 | ```console 253 | KIND: Pod 254 | VERSION: v1 255 | 256 | RESOURCE: status
289 |293 | 294 | Construct the search query to `hostIP`. 295 | 296 | Search term: `JSONPath Support` on [kubernetes.io](https://kubernetes.io/) 297 | 298 | kubernetes.io bookmark: [JSONPath Support](https://kubernetes.io/docs/reference/kubectl/jsonpath/) 299 | 300 | ```bash 301 | kubectl get pod json-pod -o jsonpath={.status.hostIP} 302 | ``` 303 | OR 304 | ```bash 305 | kubectl get pod json-pod -o jsonpath={..hostIP} 306 | ``` 307 | 308 |
309 |323 | 324 | ```bash 325 | clear 326 | kubectl create namespace revision-namespace 327 | kubectl config set-context --current --namespace=revision-namespace 328 | kubectl create deployment my-revision-deployment --image=nginx:1.18.0 --replicas=2 329 | kubectl rollout status deployment my-revision-deployment 330 | kubectl set image deployment.apps/my-revision-deployment nginx=nginx:1.19.0 --record 331 | kubectl rollout status deployment my-revision-deployment 332 | kubectl set image deployment.apps/my-revision-deployment nginx=nginx:1.20.0 --record 333 | kubectl rollout status deployment my-revision-deployment 334 | kubectl set image deployment.apps/my-revision-deployment nginx=ngin:1.21.0 --record 335 | clear 336 | ``` 337 | 338 |
339 |343 | 344 | ```bash 345 | clear 346 | #Situational Awareness 347 | kubectl get all 348 | ``` 349 | 350 | ```bash 351 | # Examine events from Deployment 352 | kubectl describe deployment.apps/my-revision-deployment 353 | ``` 354 | 355 | ```bash 356 | # Get Deployment Revisions 357 | kubectl rollout history deployment.apps/my-revision-deployment 358 | ``` 359 | 360 | ```bash 361 | # Fix the immediate problem 362 | kubectl rollout undo deployment.apps/my-revision-deployment 363 | ``` 364 | 365 | ```bash 366 | # Go back further to an earlier revision 367 | kubectl rollout undo deployment.apps/my-revision-deployment --to-revision=2 368 | ``` 369 | 370 |
371 |
379 |
380 | Search for `kubectl convert install` and scroll until you find the `Install kubectl convert plugin` section for installation instructions.
381 |
382 | The `kubectl convert` plugin installs into WSL Linux
383 |
384 | Please install the [`kubectl convert` plugin](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-kubectl-convert-plugin) with the following commands:
385 |
386 | ```bash
387 | curl -LO https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl-convert
388 | curl -LO "https://dl.k8s.io/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl-convert.sha256"
389 | echo "$(
399 | 400 | Typical API deprecated warning message: 401 | ```console 402 | Warning: policy/v1beta1 PodDisruptionBudget is deprecated in v1.21+, unavailable in v1.25+; use policy/v1 PodDisruptionBudget 403 | poddisruptionbudget.policy/calico-kube-controllers created 404 | ``` 405 | 406 | ```bash 407 | vi ~/ckad/06-04-beta-ingress.yml 408 | ``` 409 | 410 | ```yaml 411 | apiVersion: networking.k8s.io/v1beta1 412 | kind: Ingress 413 | metadata: 414 | name: my-ingress #👈👈👈 Change: `my-ingress` 415 | annotations: 416 | nginx.ingress.kubernetes.io/rewrite-target: / 417 | spec: 418 | rules: 419 | - http: 420 | paths: 421 | - path: / #👈👈👈 Change 422 | pathType: Prefix 423 | backend: 424 | service: 425 | name: my-service #👈👈👈 Change: `my-service` 426 | port: 427 | number: 8080 #👈👈👈 Change: --port=8080 428 | ``` 429 | 430 |
431 |435 | 436 | Search for `kubectl convert` 437 | 438 | kubernetes.io bookmark: [Migrate to non-deprecated APIs](https://kubernetes.io/docs/reference/using-api/deprecation-guide/#migrate-to-non-deprecated-apis) 439 | 440 | ```bash 441 | kubectl-convert -f ~/ckad/06-04-beta-ingress.yml --output-version networking.k8s.io/v1 442 | ``` 443 | 444 | Output: 445 | 446 | ```console 447 | apiVersion: networking.k8s.io/v1 448 | kind: Ingress 449 | metadata: 450 | annotations: 451 | nginx.ingress.kubernetes.io/rewrite-target: / 452 | creationTimestamp: null 453 | name: my-ingress 454 | spec: 455 | rules: 456 | - http: 457 | paths: 458 | - backend: {} 459 | path: / 460 | pathType: Prefix 461 | status: 462 | loadBalancer: {} 463 | ``` 464 | 465 |
466 |477 | 478 | ```bash 479 | cat << EOF | kubectl apply -f - 480 | apiVersion: v1 481 | kind: Namespace 482 | metadata: 483 | creationTimestamp: null 484 | name: set-env-namespace 485 | --- 486 | apiVersion: apps/v1 487 | kind: Deployment 488 | metadata: 489 | name: nginx-deployment 490 | namespace: set-env-namespace 491 | labels: 492 | app: nginx 493 | spec: 494 | replicas: 3 495 | selector: 496 | matchLabels: 497 | app: nginx 498 | template: 499 | metadata: 500 | labels: 501 | app: nginx 502 | spec: 503 | containers: 504 | - name: nginx 505 | image: nginx:1.14.2 506 | ports: 507 | - containerPort: 80 508 | env: 509 | - name: TIER 510 | value: web 511 | EOF 512 | ``` 513 | 514 | ```bash 515 | kubectl config set-context --current --namespace=set-env-namespace 516 | kubectl get all 517 | ``` 518 | 519 |
520 |524 | 525 | ```bash 526 | # Describe the Deployment 527 | kubectl describe deployment.apps nginx-deployment | grep -i env -A 1 528 | ``` 529 | 530 | ```bash 531 | # Set the env using kubectl set env 532 | kubectl set env deployment.apps nginx-deployment TIER=app 533 | ``` 534 | 535 | ```bash 536 | # Describe the Deployment 537 | kubectl describe deployment.apps nginx-deployment | grep -i env -A 1 538 | ``` 539 | 540 |
541 |548 | 549 | ```bash 550 | yes | rm -R ~/ckad/ 551 | kubectl delete ns json-namespace --force 552 | kubectl delete ns log-namespace --force 553 | kubectl delete ns revision-namespace --force 554 | ``` 555 | 556 |
557 |7 | 8 | ```bash 9 | # List all namespaces, but which is currently active? 10 | clear 11 | kubectl get namespace 12 | ``` 13 | 14 | ```console 15 | NAME STATUS AGE 16 | cert-manager Active 15d 17 | default Active 15d 18 | knative-serving Active 15d 19 | kourier-system Active 15d 20 | kube-node-lease Active 15d 21 | kube-public Active 15d 22 | kube-system Active 15d 23 | ns-chaos Active 15d 24 | ns-cookies Active 13d 25 | ns-demo Active 15d 26 | ns-fluentbit Active 7d20h 27 | ns-goldilocks Active 15d 28 | ns-loki Active 15d 29 | ns-vpa Active 15d 30 | projectcontour Active 15d 31 | ``` 32 | 33 | kubernetes.io bookmark: [Kubectl context and configuration](https://kubernetes.io/docs/reference/kubectl/cheatsheet/#kubectl-context-and-configuration) 34 | 35 | ```bash 36 | # Get the current active namespace 37 | kubectl config get-contexts 38 | ``` 39 | 40 | ```bash 41 | CURRENT NAME CLUSTER AUTHINFO NAMESPACE 42 | * do-sgp1-digital-ocean-cluster do-sgp1-digital-ocean-cluster do-sgp1-digital-ocean-cluster-admin ns-cookies 👈👈👈 # ns-cookies is the active namespace 43 | ``` 44 | 45 |
46 |53 | 54 | kubernetes.io bookmark: [Not All Objects are in a Namespace](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/#not-all-objects-are-in-a-namespace) 55 | 56 | ```bash 57 | clear 58 | kubectl api-resources --namespaced=true | more 59 | ``` 60 | 61 | Output: 62 | 63 | ```console 64 | NAME SHORTNAMES APIVERSION NAMESPACED KIND 65 | bindings v1 true Binding 66 | configmaps cm v1 true ConfigMap 67 | endpoints ep v1 true Endpoints 68 | ... 69 | 70 | # Do not need the additional supplied columns. 71 | 72 | ``` 73 | 74 |
75 |79 | 80 | ##### Solution 81 | 82 | ```bash 83 | clear 84 | kubectl api-resources --namespaced=true -o name | more 85 | ``` 86 | 87 | Output: 88 | 89 | ```console 90 | bindings 91 | configmaps 92 | endpoints 93 | events 94 | ... 95 | ``` 96 | 97 |
98 |105 | 106 | ```bash 107 | clear 108 | # Use the kubectl proxy to provide credentials to connect to the API server 109 | # kubectl proxy starts a local proxy service on port 8001 110 | # kubectl proxy uses credentials from kubeconfig file 111 | 112 | kubectl proxy & 113 | ``` 114 | 115 |
116 |120 | 121 | ```bash 122 | clear 123 | # List all available API groups from the API server 124 | 125 | # /api is called the core API's #👈👈👈 126 | # /apis is called the named API's - going forward new features will be made available under this API #👈👈👈 127 | 128 | curl http://localhost:8001 | more 129 | ``` 130 | 131 | Output: 132 | 133 | ```console 134 | { 135 | "paths": [ 136 | "/.well-known/openid-configuration", 137 | "/api", 138 | "/api/v1", 139 | "/apis", 140 | "/apis/", 141 | "/apis/admissionregistration.k8s.io", 142 | "/apis/admissionregistration.k8s.io/v1", 143 | "/apis/admissionregistration.k8s.io/v1beta1", 144 | "/apis/apiextensions.k8s.io", 145 | "/apis/apiextensions.k8s.io/v1", 146 | "/apis/apiextensions.k8s.io/v1beta1", 147 | "/apis/apiregistration.k8s.io", 148 | "/apis/apiregistration.k8s.io/v1", 149 | "/apis/apiregistration.k8s.io/v1beta1", 150 | "/apis/apps", 151 | "/apis/apps/v1", 152 | "/apis/authentication.k8s.io", 153 | "/apis/authentication.k8s.io/v1", 154 | "/apis/authentication.k8s.io/v1beta1", 155 | "/apis/authorization.k8s.io", 156 | "/apis/authorization.k8s.io/v1", 157 | "/apis/authorization.k8s.io/v1beta1", 158 | "/apis/autoscaling", 159 | "/apis/autoscaling/v1", 160 | "/apis/autoscaling/v2beta1", 161 | "/apis/autoscaling/v2beta2", 162 | "/apis/batch", 163 | "/apis/batch/v1", 164 | "/apis/batch/v1beta1", 165 | "/apis/certificates.k8s.io", 166 | "/apis/certificates.k8s.io/v1", 167 | "/apis/certificates.k8s.io/v1beta1", 168 | "/apis/coordination.k8s.io", 169 | "/apis/coordination.k8s.io/v1", 170 | "/apis/coordination.k8s.io/v1beta1", 171 | "/apis/discovery.k8s.io", 172 | "/apis/discovery.k8s.io/v1", 173 | "/apis/discovery.k8s.io/v1beta1", 174 | "/apis/events.k8s.io", 175 | "/apis/events.k8s.io/v1", 176 | "/apis/events.k8s.io/v1beta1", 177 | "/apis/extensions", 178 | ... 179 | ``` 180 | 181 |
182 |186 | 187 | ```bash 188 | clear 189 | # List all supported resource groups under the `named` (apis) group 190 | 191 | curl http://localhost:8001/apis | grep "name" | more 192 | ``` 193 | 194 | Output: 195 | 196 | ```console 197 | ... 198 | "name": "apiregistration.k8s.io", 199 | "name": "apps", 200 | "name": "events.k8s.io", 201 | "name": "authentication.k8s.io", 202 | "name": "authorization.k8s.io", 203 | "name": "autoscaling", 204 | "name": "batch", 205 | "name": "certificates.k8s.io", 206 | "name": "networking.k8s.io", 207 | "name": "extensions", 208 | "name": "policy", 209 | "name": "rbac.authorization.k8s.io", 210 | "name": "storage.k8s.io", 211 | "name": "admissionregistration.k8s.io", 212 | "name": "apiextensions.k8s.io", 213 | "name": "scheduling.k8s.io", 214 | "name": "coordination.k8s.io", 215 | "name": "node.k8s.io", 216 | "name": "discovery.k8s.io", 217 | "name": "flowcontrol.apiserver.k8s.io", 218 | "name": "crd.projectcalico.org", 219 | "name": "projectcontour.io", 220 | "name": "metrics.k8s.io", 221 | ... 222 | ``` 223 | 224 |
225 |233 | 234 | ##### Overview 235 | 236 | kubernetes.io bookmark: [Use a strategic merge patch to update a Deployment](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/#use-a-strategic-merge-patch-to-update-a-deployment) 237 | 238 | 239 | ```bash 240 | kubectl config set-context --current --namespace=revision-namespace 241 | clear 242 | kubectl explain deployment.spec 243 | ``` 244 | 245 | Output: 246 | 247 | ```console 248 | KIND: Deployment 249 | VERSION: apps/v1 250 | 251 | RESOURCE: spec
297 |301 | 302 | ```bash 303 | # What is the current setting 304 | kubectl get deployment my-revision-deployment -o jsonpath={.spec.revisionHistoryLimit} 305 | ``` 306 | 307 | ```bash 308 | # Create a file to hold the patch 309 | vi ~/ckad/patch-file.yaml 310 | ``` 311 | 312 | ```bash 313 | spec: # 👈👈👈 First element: =.spec 314 | revisionHistoryLimit: 20 # 👈👈👈 Second element: =.spec.revisionHistoryLimit 315 | ``` 316 | 317 | ```bash 318 | kubectl patch deployment my-revision-deployment --patch "$(cat ~/ckad/patch-file.yaml)" 319 | ``` 320 | 321 | ```bash 322 | # Verify your work 323 | kubectl get deployment my-revision-deployment -o jsonpath={.spec.revisionHistoryLimit} 324 | ``` 325 | 326 | 327 |
328 |31 | 32 | - Windows Subsystem for Linux requires you to install a Linux distribution from the Microsoft Store. 33 | - Tick the 'Use the WSL 2 based engine' under the 'General' panel 34 | - To mimic the CKAD exam please execute all the commands in this repo from this Linux distribution that you installed. 35 | - The CKAD exam terminal is Ubuntu based. 36 | - Start the distribution directly by searching for Ubuntu and starting the application 37 | 38 |
39 |
43 |
44 | Please install these software components, required to answer questions in later sections:
45 |
46 |
48 |
49 | Metrics Server installs into Kubernetes
50 |
51 | By default the metrics server required for the `kubectl top` command is not present on Docker Desktop.
52 |
53 | Please install the [metrics server](https://github.com/kubernetes-sigs/metrics-server) with the following command:
54 |
55 | ```bash
56 | kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
57 | ```
58 |
59 | ```bash
60 | kubectl patch deployment metrics-server -n kube-system --type 'json' -p '[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-insecure-tls"}]'
61 | ```
62 |
63 |
68 |
69 | Contour installs into Kubernetes
70 |
71 | 
72 |
73 | By default the Contour Ingress required for the Ingress Networking question is not present on Docker Desktop.
74 |
75 | Please install the [contour ingress](https://projectcontour.io/) with the following command:
76 |
77 | ```bash
78 | kubectl apply -f https://projectcontour.io/quickstart/contour.yaml
79 | ```
80 |
81 |
86 |
87 | Calico installs into Kubernetes
88 |
89 | 
90 |
91 | Calico is required for the non native Kubernetes resources lookup question.
92 |
93 | ```bash
94 | curl https://docs.projectcalico.org/manifests/calico.yaml | kubectl apply -f -
95 | ```
96 |
97 | To work with Calico Network Policies use the following command:
98 | ```bash
99 | kubectl get networkpolicy.p
100 | ```
101 |
102 |
107 |
108 | Helm installs into WSL Linux
109 |
110 | Please install the [Helm](https://helm.sh/docs/) with the following command:
111 |
112 | ```bash
113 | curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
114 | chmod 700 get_helm.sh
115 | ./get_helm.sh
116 | ```
117 |
118 |
123 |
124 | kubectl convert installs into WSL Linux
125 |
126 | Please install the [kubectl convert](https://kubernetes.io/docs/reference/using-api/deprecation-guide/#migrate-to-non-deprecated-apis) with the following command:
127 |
128 | ```bash
129 | curl -LO https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl-convert
130 | curl -LO "https://dl.k8s.io/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl-convert.sha256"
131 | echo "$(
141 |
142 | Octant installs into Windows 11
143 |
144 | 
145 |
146 | - Consider installing Octant to visualize Kubernetes Resource Types
147 | - This will help you understand the interaction and relationships between Kubernetes Resource types
148 | - Installation instructions for Octant can be found [here](https://octant.dev/)
149 |
150 | Metrics Server - Kubernetes top command
47 | Contour Ingress - Kubernetes Ingress Controller
67 | Calico - Kubernetes Container Network Interface (CNI)
85 | Helm - Kubernetes Package Manager
106 | kubectl convert - Deal with deprecated API versions
122 | Octant - Kubernetes UI
140 |