These are my study notes for the Certified Kubernetes Application Developer exam Curriculum v1.15.0. The structure follows the exam curriculum but are not meant to be exhaustive. Always check the official documentation, tasks and tutorials for a topic.
This is the exam topics and weighting
Topic | Exam weight |
---|---|
Core Concepts | 13% |
Configuration | 18% |
Multi-Container Pods | 10% |
Observability | 18% |
Pod Design | 20% |
Services & Networking | 13% |
State Persistence | 8% |
- Core Concepts
- Configuration
- Multi-Container Pods
- Observability
- Pod Design
- Services & Networking
- State Persistence
Primitives are also called objects and they represent the state of the cluster.
Basic commands to view the objects:
kubectl api-resources
kubectl get <object name>
kubectl describe <object type> <object name>
All objects have a spec and status. The spec is the desired state of the object and the status is the current state of the object.
Depending on the restart option the run command will deploy a pod in a few different ways;
Never = pod OnFailure = job Always = Deployment
kubectl run <podname> --image=<image name>
Common options
--rm # Deletes the resources once the pod has finished
--env # Adds environment variables
--port # Exposes the port
-r, --replicas # Deploys given number of replicas
--command # Runs a command inside the pod
Exec command allows us to run a command inside a running pod. Commonly used to get a shell inside the container to help troubleshoot an issue.
kubectl exec <pod name> -it -c <container name> -- bash
ConfigMaps are one of the ways Kubernetes allows us to decouple configuration data from the container image. Configuration data can be consumed by pods via:
- Populating environment variables
- Setting command-line arguments for a container
- Populate config files in a volume.
In the manifest the data field contains the configuration data in the form of key value pairs.
apiVersion: v1
kind: ConfigMap
metatdata:
name: myapp-settings
namespace: myapp
data:
dayofweek: tuesday
ConfigMaps can be created from directories and files.
Creating from directories and files both use the --from-file
flag
kubectl create configmap app-settings --from-file=/settings/app-settings
Each file in the directory will create a key: value pair with the key being the filename.
kubectl create configmap calendar-data --from-file=random-data=app/settings/calendar-data
Use the from-literal
flag to create a configMap from values on the command line.
kubectl create configmap calendar-data --from-literal=FIRSTDAY=Monday
Environment variables can be added under envFrom:
and env:
depending on which key:values we want to load.
apiVersion: v1
kind: ConfigMap
metadata:
name: calender-data
namespace: temp
data:
FIRSTDAY: Monday
FIRSTMONTH: January
---
#
# Load all key: values from the configmap
#
apiVersion: v1
kind: Pod
metadata:
name: nginxtemp1
namespace: temp
spec:
containers:
- name: nginxtemp
image: nginx
envFrom:
- configMapRef:
name: calender-data
---
#
# Load a single value from the configmap
#
apiVersion: v1
kind: Pod
metadata:
name: nginxtemp2
namespace: temp
spec:
containers:
- name: nginxtemp
image: nginx
env:
- name: CAL
valueFrom:
configMapKeyRef:
name: calender-data
key: FIRSTDAY
The concept is similar when loading as volumes.
# Load the configmap as a volume
apiVersion: v1
kind: Pod
metadata:
name: nginxtemp2
namespace: temp
spec:
containers:
- name: nginxtemp
image: nginx
volumeMounts:
- name: cal-data
mountPath: /cal/data
volumes:
- name: cal-data
configMap:
name: calender-data
---
# Load a single value from the configmap
apiVersion: v1
kind: Pod
metadata:
name: nginxtemp2
namespace: temp
spec:
containers:
- name: nginxtemp
image: nginx
volumeMounts:
- name: cal-data
mountPath: /cal/data
volumes:
- name: cal-data
configMap:
name: calender-data
items:
- key: FIRSTDAY
path: NAMEOFDAY
ConfigMaps must be created before they are consumed unless they are marked as optional. References to ConfigMaps that do not exist will prevent the pod from starting.
Security contexts can be applied at either the pod or container level. If the context is set at a pod level it will apply to all containers.
apiVersion: v1
kind: Pod
metadata:
name: data-mover
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
A value set at the container level will override any set at pod level.
Linux capabilities can be granted to a process without giving full root privileges.
apiVersion: v1
kind: Pod
meatadata:
name: data-mover
spec:
containers:
- name: busybox
image:
securityContext:
capabilities:
add: ["SETGID", "LEASE"]
SELinux labels can also be applied to a pod or container.
apiVersion: v1
kind: Pod
meatadata:
name: data-mover
spec:
containers:
- name: busybox
image:
securityContext:
seLinuxOptions:
level: "s0:c123,c456"
CPU and memory are collectively referred to as compute resources, or just resources. Compute resources are measurable quantities that can be requested, allocated, and consumed. Resources can specify a request and a limit. If a pod is scheduled the container is guaranteed the requested resources. If a pod exceeds its CPU limit it will be throttled. If it exceeds its memory limit a process using the most memory will be killed by the kernel.
CPU is specified in units of cores such as 0.5CPU or the suffix m to mean milli. 100m, 100 milliCPU and 0.1CPU are the same.
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: web
spec:
containers:
- name: nginx
image: nginx:1.7.9
resources:
limits:
cpu: "1"
requests:
cpu: "0.5"
Memory is specified in units of bytes; E, P, T, G, M, K and the power of 2 equivalent Ei, Pi, Ti, Gi, Mi, Ki.
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: web
spec:
containers:
- name: nginx
image: nginx:1.7.9
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
kubectl run nginx --restart=Never --image=nginx --requests="cpu=100m,memory=256Mi" --limits="cpu=200m,memory=512Mi"
Secrets are for storing sensitive information such as passwords or tokens. They can be mounted as files in a volume or as environment variables.
apiVersion: v1
kind: Secret
metadata:
name: madeupdata
stringData:
key: thisandthat
kubectl create secret generic madeupdata --from-literal=key=thisandthat
cat >data.conf <<EOL
password:123
secret:abc
EOL
kubectl create secret generic testing --from-file=data.conf
apiVersion: v1
Kind: Pod
metadata:
name: apptest
spec:
containers:
- name: apptest
image: nginx
env:
- name: APP_KEY
valueFrom:
secretKeyRef:
name: madeupdata
key: key
apiVersion: v1
kind: Pod
metadata:
name: datatest
spec:
containers:
- name: datatest
image: nginx
volumeMounts:
- name: appdata
mountpath: "/etc/appdata"
volumes:
- name: appdata
secret:
secretName: testing
To view a secret
echo 'dGhpc2FuZHRoYXQ=' | base64 --decode
When you (a human) access the cluster (for example, using kubectl), you are authenticated by the apiserver as a particular User Account (currently this is usually admin, unless your cluster administrator has customized your cluster). Processes in containers inside pods can also contact the apiserver. When they do, they are authenticated as a particular Service Account (for example, default).
When you create a pod, if you do not specify a service account, it is automatically assigned the default service account in the same namespace.
The service account has to exist at the time the pod is created, or it will be rejected.
apiVersion: v1
kind: ServiceAccount
metadata:
name: text-reader
---
apiVersion: v1
kind: Pod
metadata:
name: reader-app
spec:
containers:
- image: busybox
name: reader-app
serviceAccountName: text-reader
apiVersion: v1
kind: Pod
metadata:
name: sidecartest
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
- name: busy
image: busbox
command: ['sh', '-c', 'while true; do sleep 30; done;']
3 common multi-container design patterns:
- Sidecar: adds functionality like shipping logs or fetching files.
- Ambassador: network traffic routes through the ambassador container before the main container.
- Adapter: transforms the output from the main container
Kubelet uses liveness probes to know when to restart a Container and readiness probes to know when a Container is ready to start accepting traffic.
Three types of probes:
- Exec: Executes a specified command inside the Container. The diagnostic is considered successful if the command exits with a status code of 0.
- TCP check: Performs a TCP check against the Container’s IP address on a specified port. The diagnostic is considered successful if the port is open.
- HTTP Get: Performs an HTTP Get request against the Container’s IP address on a specified port and path. The diagnostic is considered successful if the response has a status code greater than or equal to 200 and less than 400.
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: myapp
image: busybox
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 60
periodSeconds: 10
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: myapp
image: busybox
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /live
port: 8080
scheme: HTTP
initialDelaySeconds: 60
periodSeconds: 10
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: myapp
image: <Image>
ports:
- containerPort: 8080
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
kubectl logs <pod> <container> --previous
kubectl top pods
kubectl top nodes
Nothing special here just understanding the commands available for seeing errors and logs.
# Describe gathers a host of information such as resources and events
kubectl describe pod nginx
# View the logs of a container/pod
kubectl logs webapp
# Get events for a namespace
kubectl get events -n webapp
# Run commands inside a container
kubectl exec -it webrunner -- sh
# Edit the current state of a resource
kubectl edit pod webrunner
Labels contain identifying information and are used by selectors. Annotations contains non identifying information that can be used by external tools and libraries.
apiVersion: apps/v1
kind: Deployment
metadata:
inx name: auth-app
labels:
app: auth
spec:
replicas: 1
selector:
matchLabels:
app: auth
template:
metadata:
labels:
app: auth
spec:
containers:
- name: auth-app
image: ng
admin@comp01:~$ kubectl get all --selector=app=auth
NAME READY STATUS RESTARTS AGE
pod/auth-app-5f5cb6f99-cskz8 1/1 Running 0 2m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/auth-app 1/1 1 1 2m1s
NAME DESIRED CURRENT READY AGE
replicaset.apps/auth-app-5f5cb6f99 1 1 1 2m1s
Annotations are key/value pairs. Valid annotation keys have two segments: an optional prefix and name, separated by a slash (/). The kubernetes.io/ and k8s.io/ prefixes are reserved for Kubernetes core components.
apiVersion: v1
kind: Pod
metadata:
name: jumper
annotations:
version: 1.2.3-stable
owner: sre
contact: 01234 657891 option 1
prometheus.io/port: 10254
prometheus.io/scrape: true
spec:
containers:
name: jumper
image: busybox
Deployments allow us to gradually update pods to minimize service interruptions. Under the deployment spec is the strategy field, this covers how existing pods are replaced with new ones. You only need to specify these if you want settings that differ from the defaults which are RollingUpdate and 25% for both max surge and max unavailable.
apiVersion: apps/v1
kind: Deployment
metadata:
inx name: auth-app
labels:
app: auth
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
# Absolute numbers are also accepted
maxUnavailable: 2
selector:
matchLabels:
app: auth
template:
metadata:
labels:
# One of these labels should match the selector above
app: auth
spec:
containers:
- name: auth-app
image: nginx
To update the image of a deployment
kubectl set image deployment auth-app auth-app=nginx:1.9.1 --record
The record flag adds the command as an annotation to the deployment and appears in the change-cause field in the rollout history.
To view the status of a rollout
kubectl rollout status deployment auth-app
To undo the last rollout change
kubectl rollout undo deployment auth-app
The settings under the strategy spec applies to rollbacks as well as rollouts.
To rollback to a specific revision, add the revision number flag.
kubectl rollout history deployment auth-app
deployment.extensions/auth-app
REVISION CHANGE-CAUSE
1 <none>
2 kubectl set image deployment auth-app auth-app=nginx:1.17 --record=true
kubectl rollout undo deployment auth-app --to-revision=1
A job runs a container until its workload is complete. A CronJob is a job run on a schedule.
kubectl create job dateprint --image=busybox -- /bin/sh -c 'echo The date and time is;date'
kubectl create cronjob dateprint --image=busybox --schedule="* 1 * * *" -- /bin/sh -c 'echo The date and time is;date'
apiVersion: batch/v1
kind: Job
metadata:
name: dateprint
spec:
template:
spec:
containers:
- name: dateprint
image: busybox
command:
- /bin/sh
- -c
- echo The date and time is;date
restartPolicy: Never
---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: dateprint
spec:
schedule: '* 1 * * *'
jobTemplate:
spec:
template:
spec:
containers:
- name: dateprint
image: busybox
command:
- /bin/sh
- -c
- echo The date and time is;date
A service object uses a selector to proxy traffic to a set of pods.
4 types of service objects:
- ClusterIp: Uses an cluster internal IP
- NodePort: Allocates a port on all nodes
- LoadBalancer: launches a cloud providers LoadBalancer
- ExternalName: Provide a CNAME pointing to a resource outside of Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: webapp
spec:
replicas: 3
selector:
matchLabels:
web: frontend
template:
metadata:
labels:
web: frontend
spec:
containers:
- name: nginx
image: nginx
ports:
containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: frontend
namespace: webapp
spec:
selector:
web: frontend
type: NodePort
ports:
- name: frontend
port: 8080
targetPort: 80
Creating the service from the command line will set the selector key as app and the value as the service name.
kubectl create svc clusterip webapp-svc --tcp=8080:80
Ports are ordered as <service port>:<target port>
.
Network policies define how groups of pods are allowed to communicate with each other. By default pods accept traffic from any source. Network policies only work if the installed networking solution supports them.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name:
namespace:
spec:
podSelector:
matchLabels:
app: auth
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
Persistent Volumes can be created dynamically or statically by an Administrator. The storageClass must already exist for the dynamic provisioning to work.
Lots of storage options are supported by Kubernetes.
apiVersion: v1
kind: PersistentVolume
metadata:
name: mysql-pv
spec:
storageClassName: fast
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
spec:
storageClassName: fast
accessModes:
- ReadWriteOnce
requests:
storage:
capacity: 10Gi
apiVersion: v1
kind: Pod
metadata:
name: mysql
spec:
containers:
- name: db
image: mysql
volumeMounts:
- name: mysql-db
mountpath: /var/lib/mysql
volumes:
- name: mysql-db
persistentVolumeClaim:
claimName: mysql-pvc