CKAD Exam Preparation 3/4 - Configuration and Volumes
▶️ Introduction
This part summarizes Configuration and Volumes as key primitives of the CKAD Exam Curriculum. To learn more about the CKAD Exam please read this overview.
About this Series
During this blog series I summarize the main “study hooks” in order to be successful with your exam, as I was. The series is composed by the following articles:
- Part 1. Cross-Cutting Aspects
- Part 2. Pods and Jobs.
- Part 3. Configuration and Volumes.
- Part 4. Deployments, Services and Networking.
All the examples have been developed using minikube on macOS Catalina with VirtualBox.
🖇️ Configuration Primitives
📘 https://kubernetes.io/docs/concepts/configuration/
Environment
For running a Pod with a certain set of environment variables (env var) the easiest way is with --env
:
kubectl run p1 --image=busybox --env='var1=val1' --env='var2=val2' -- sh -c 'sleep 3600'
📌 one --env
parameter is needed per env var set.
An environment can be also be populated with variables coming from Config Maps or Secrets.
Config Maps
The simplest way to create a Config Map is with the --literal
command line option:
kubectl create configmap cm1 --from-literal='key1=value1' --from-literal='key2=value2'
📌 one --literal
parameter is needed per name/value pair.
A Config Map can also be created from a properties or environment var file:
cat file.env
var1=val1
var2=val2
kubectl create configmap cm2 --from-env-file=file.env
kubectl describe configmap cm2
Name: cm2
Namespace: default
Data
====
var1:
----
val1
var2:
----
val2
A Config Map can also be created to include all the contents of a file:
cat myconfig.json
{
"id": "a456",
"type": "Configuration"
}
kubectl create configmap cm3 --from-file=myconfig.json
Name: cm3
Namespace: default
Data
====
config.json:
----
{
"id": "a3456",
"type": "Configuration"
}
The above command will create a Config Map with just one name/value pair (named myconfig.json
) which value will be the content of the myconfig.json
file.
📌 The difference between --from-env-file
and --from-file
.
Secrets
📌 Use Secrets for sensitive configurations, TLS, private keys, certificates, etc.
📌 Secrets are stored encrypted but finally exposed to trusted containers in plain mode.
The simplest way to create a generic Secret is with the --literal
command line option:
kubectl create secret generic s1 --from-literal='username=jmcf' --from-literal='pwd=a123456'
📌 one --literal
parameter is needed per Secret’s name/value pair.
kubectl describe secrets s1
Name: s1
Namespace: default
Type: Opaque
Data
====
pwd: 7 bytes
username: 4 bytes
Assuming your K8s implementation encrypts Secrets using base64 (please do not do that in production) you can obtain a Secret’s value in plain mode as follows:
kubectl get secret s1 -o jsonpath='{.data.username}{"\n"}' | base64 -d
📌 You can create Secrets from env files and with file or folder content.
📌 Service Account tokens are also stored as Secrets
of type kubernetes.io/service-account-token
.
Pod Configuration through env vars
How to use a Config Map with direct mapping to env variables:
apiVersion: v1
kind: Pod
metadata:
labels:
run: my-pod
name: my-pod
namespace: jmcf
spec:
containers:
- image: nginx
ports:
- name: p1
containerPort: 80
name: my-pod
envFrom:
- configMapRef:
name: cm1
optional: false
dnsPolicy: ClusterFirst
restartPolicy: Always
📌 An env var will be created for each ConfigMap’s name/value pair.
📌 The same can be done with Secrets using secretRef
instead of configMapRef
.
📌 Use optional: false
to ensure you are using an already
existent/right Config Map or Secret.
ConfigMap’s or Secret’s name/value pairs can also be mapped to custom env vars. In the example below the
env var SECRET567
is mapped to the name/value pair pwd
of the Secret s1
.
apiVersion: v1
kind: Pod
metadata:
labels:
run: my-pod
name: my-pod
namespace: jmcf
spec:
containers:
- image: nginx
ports:
- name: p1
containerPort: 80
name: my-pod
env:
- name: SECRET567
valueFrom:
secretKeyRef:
name: s1
key: pwd
optional: false
dnsPolicy: ClusterFirst
restartPolicy: Always
📌 The same can be done with Config Map using configMapKeyRef
instead of secretKeyRef
.
Pod configuration through Volumes
A Volume can be easily declared to reference a Config Map or a Secret. Then, such volume can be mounted to a folder by containers. Such folder will contain a file per name/value pair. The name of the file will correspond to the key name and the content of the file will be the key value.
apiVersion: v1
kind: Pod
metadata:
labels:
run: my-pod
name: my-pod
namespace: jmcf
spec:
volumes:
- name: v1
configMap:
name: cm1
optional: false
containers:
- image: nginx
ports:
- name: p1
containerPort: 80
name: my-pod
volumeMounts:
- name: v1
mountPath: "/etc/foo"
dnsPolicy: ClusterFirst
restartPolicy: Always
📌 The same can be done with Secret using secret
instead of configMap
.
It is also possible to map specific name/value pairs of a Secret or Config Map to a path. See below
apiVersion: v1
kind: Pod
metadata:
labels:
run: my-pod
name: my-pod
namespace: jmcf
spec:
volumes:
- name: v1
secret:
secretName: s1
items:
- key: username
path: "credentials/username.conf"
optional: false
containers:
- image: busybox
command: ["sh", "-c"]
args: ["sleep 3600"]
name: my-pod
resources: {}
volumeMounts:
- name: v1
mountPath: "/etc/foo"
dnsPolicy: ClusterFirst
restartPolicy: Always
kubectl exec my-pod-4 -it -n jmcf -- cat /etc/foo/credentials/username.conf
💽 Volumes
📘 https://kubernetes.io/docs/concepts/storage/
Transient Volumes
emptyDir
allows to create a transient Volume for a Pod.
apiVersion: v1
kind: Pod
metadata:
name: pod-with-emptydir
namespace: jmcf
spec:
volumes:
- name: logs
emptyDir: {}
containers:
- name: app-container
image: alpine
command: ["/bin/sh"]
args: ["-c", "while true; do date >> /var/log/app.txt; sleep 5; done"]
volumeMounts:
- name: logs
mountPath: /var/log
kubectl exec -it -f emptydir-volume.yaml -- cat /var/log/app.txt
📌 Transient Volumes share a Pod’s lifetime.
Persistent Volumes
How to create a Persistent Volume (PV)
apiVersion: v1
kind: PersistentVolume
metadata:
name: mypv-tutorial
labels:
release: stable
spec:
storageClassName: canterafonseca
capacity:
storage: 20Mi
hostPath:
path: "/tmp/volume_test"
accessModes:
- ReadWriteOnce
- ReadWriteMany
kubectl get pv mypv-tutorial
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv-tutorial 20Mi RWO,RWX Retain Available canterafonseca 25s
📌 PVs are cluster resources and have a lifecycle independent of any individual Pod that uses the PV.
📌 The reclaim policy for a PV tells the cluster what to do with the Volume after it has been released of its claim: Retain
, Recycle
, or Delete
.
Persistent Volume Claims
A Persistent Volume Claim (PVC) is a request for storage by a user. PVCs consume PV resources. Claims can request specific size and access modes.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvclaim-t1
namespace: jmcf
spec:
storageClassName: canterafonseca
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 10Mi
selector:
matchLabels:
release: stable
kubectl get pvc -n jmcf pvclaim-t1
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvclaim-t1 Bound mypv-tutorial 20Mi RWO,RWX canterafonseca 20s
We can observe that our initial PV mypv-tutorial
it is now bound to our PVC jmcf/pvclaim-t1
.
kubectl get pv mypv-tutorial
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv-tutorial 20Mi RWO,RWX Retain Bound jmcf/pvclaim-t1 canterafonseca 17m
📌 The binding between a PV and a PVC happens provided there is a match with capacity, storage class and selector.
📌 There are storage classes marked as dynamically provisioned. In those cases PVs can be created dynamically to meet the demands of a PVC.
Mounting Persistent Volume Claims
apiVersion: v1
kind: Pod
metadata:
name: pod-with-pvc
namespace: jmcf
spec:
volumes:
- name: logs
persistentVolumeClaim:
claimName: pvclaim-t1
containers:
- name: app-container
image: alpine
command: ["/bin/sh"]
args: ["-c", "while true; do date >> /var/log/app.txt; sleep 5; done"]
volumeMounts:
- name: logs
mountPath: /var/log
kubectl exec -it -f pod-pvc.yaml -- cat /var/log/app.txt
⏭️ Next in this series
Deployments, Services and Networking