- Define, build and modify container images **
- Understand Jobs and CronJobs
- Understand multi-container Pod design patterns (e.g. sidecar, init and others)
- Utilize persistent and ephemeral volumes **
- Create a container from the attached
Dockerfile
andindex.html
. - Name the image
my-image
. - Run the container exposing port
8080
on the host and port80
on the container. - Name the container
my-container
. Stop the container. Delete the container.
Docker Image Creation
Create a file called index.html
mkdir -p ~/ckad/
vi ~/ckad/index.html
Edit index.html with the following text.
Hardships often prepare ordinary people for an extraordinary destiny.
Create a file called Dockerfile
vi ~/ckad/Dockerfile
Edit the Docker with to include the text below :
FROM nginx:latest
COPY ./index.html /usr/share/nginx/html/index.html
cd ~/ckad/
clear
# Build the docker image
docker build -t my-image:v0.1 .
docker images
# Create a TAR file from the image file
docker save --output my-image.tar my-image:v0.1
ls my-image*
Docker Container Operations
kubernetes.io bookmark: docker run
clear
# Run the docker image
docker run -it --rm -d -p 8080:80 --name my-container my-image:v0.1
clear
# Verify Operation
curl localhost:8080
clear
# List all images
docker ps -a
clear
# Stop the Container
docker container stop my-container
clear
# Delete the Image
docker image rm my-image:v0.1
Docker Operations
clear
# Prune all dangling images
docker image prune -a
- Create a namespace called
pod-namespace
. - Create a pod called
pod-1
usingnginx
image. - The container in the pod should be named
container-1
.
Prerequisites
clear
# Create the namespace
kubectl create namespace pod-namespace
clear
# Switch context into the namespace so that all subsequent commands execute inside that namespace.
kubectl config set-context --current --namespace=pod-namespace
clear
# Run the help flag to get examples
kubectl run -h | more
Output:
Examples:
# Start a nginx pod
kubectl run nginx --image=nginx
# Start a hazelcast pod and let the container expose port 5701
kubectl run hazelcast --image=hazelcast/hazelcast --port=5701
# Start a hazelcast pod and set environment variables "DNS_DOMAIN=cluster" and "POD_NAMESPACE=default" in the
container
kubectl run hazelcast --image=hazelcast/hazelcast --env="DNS_DOMAIN=cluster" --env="POD_NAMESPACE=default"
# Start a hazelcast pod and set labels "app=hazelcast" and "env=prod" in the container
kubectl run hazelcast --image=hazelcast/hazelcast --labels="app=hazelcast,env=prod"
# Dry run; print the corresponding API objects without creating them
kubectl run nginx --image=nginx --dry-run=client 👈👈👈 This example matches most closely to the question. Just needs an output file.
# Start a nginx pod, but overload the spec with a partial set of values parsed from JSON
kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { ... } }'
# Start a busybox pod and keep it in the foreground, don't restart it if it exits
kubectl run -i -t busybox --image=busybox --restart=Never
# Start the nginx pod using the default command, but use custom arguments (arg1 .. argN) for that command
kubectl run nginx --image=nginx -- <arg1> <arg2> ... <argN>
# Start the nginx pod using a different command and custom arguments
kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>
Solution
kubernetes.io bookmark: kubectl Cheat Sheet
clear
# Using the best example that matches the question
mkdir -p ~/ckad/
kubectl run pod-1 --image=nginx --dry-run=client -o yaml > ~/ckad/01-02.yml
clear
# Edit the YAML file to make required changes
# Use the Question number in case you want to return to the question for reference or for review
vi ~/ckad/01-02.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod-1
name: pod-1
spec:
containers:
- image: nginx
name: container-1 #👈👈👈 Change from pod-1 to container-1
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
clear
# Apply the YAML file to the Kubernetes API server
kubectl apply -f ~/ckad/01-02.yml
clear
# Quick verification that the pod was created and is working
kubectl get pod --watch
- Create a namespace called
storage-namespace
. - Create a Persistent Volume called
my-pv
with5Gi
storage using hostPath/mnt/my-host
. - Create a Persistent Volume Claim called
my-pvc
with2Gi
storage. - Create a pod called
storage-pod
using the nginx image. - Mount the Persistent Volume Claim onto
/my-mount
instorage-pod
.
Overview
Legend
- PersistentVolume – the low level representation of a storage volume
- PersistentVolumeClaim – the binding between a Pod and PersistentVolume
- Pod – a running container that will consume a PersistentVolume
- StorageClass – allows for dynamic provisioning of PersistentVolumes
- ReadWriteOnce(RWO) - volume can be mounted as read-write by a single node.
- ReadOnlyMany(ROX) - volume can be mounted read-only by many nodes.
- ReadWriteMany(RWX) - volume can be mounted as read-write by many nodes.
- ReadWriteOncePod(RWOP) - volume can be mounted as read-write by a single Pod.
Notes
- Once a PV is bound to a PVC, that PV is essentially tied to the PVC and cannot be bound to by another PVC.
- There is a one-to-one mapping of PVs and PVCs.
- However, multiple pods in the same project can use the same PVC.
- The link between PV and PVC is not explict, instead the PVC makes a some requests for storage.
- Kubernetes will pick an appropriate PersistentVolume to meet that claim.
- StorageClass provisions PV dynamically, when PVC claims it.
- StorageClass allows for dynamically provisioned volumes for an incoming claim.
Prerequisites
clear
kubectl create namespace storage-namespace
kubectl config set-context --current --namespace=storage-namespace
Solution - PersistentVolume
kubernetes.io bookmark: Create a PersistentVolume
# Create a YAML file for the PV
mkdir -p ~/ckad/
vi ~/ckad/01-03-pv.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv #👈👈👈 Change
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 5Gi #👈👈👈 Change
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/my-host" #👈👈👈 Change
kubectl apply -f ~/ckad/01-03-pv.yml
clear
kubectl get pv
Output:
# Note the STATUS=Available
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM
my-pv 5Gi RWO Retain Available
Solution - PersistentVolumeClaim
kubernetes.io bookmark: Create a PersistentVolumeClaim
# Create a YAML file for the PVC
mkdir -p ~/ckad/
vi ~/ckad/01-03-pvc.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc #👈👈👈 Change
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi #👈👈👈 Change
kubectl apply -f ~/ckad/01-03-pvc.yml
clear
kubectl get pv
kubectl get pvc
Output:
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM
my-pv 5Gi RWO Retain Bound storage-namespace/my-pvc # STATUS=Bound means the PV and PVC are linked
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
my-pvc Bound my-pv 5Gi RWO manual 6s # STATUS=Bound means the PV and PVC are linked
Solution - Pod
kubernetes.io bookmark: Create a Pod
# Create a YAML file for the Pod
mkdir -p ~/ckad/
vi ~/ckad/01-03-pod.yml
apiVersion: v1
kind: Pod
metadata:
name: storage-pod #👈👈👈 Change
spec:
volumes:
- name: my-volume
persistentVolumeClaim:
claimName: my-pvc #👈👈👈 Change
containers:
- name: my-container
image: nginx
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- mountPath: "/my-mount" #👈👈👈 Change
name: my-volume
kubectl apply -f ~/ckad/01-03-pod.yml
clear
# Verify that the volume is mounted
# Or just kubectl describe pod storage-pod
kubectl describe pod storage-pod | grep -i Mounts -A1
Output:
Mounts:
/my-mount from my-volume (rw) # Success
Clean Up
cd
yes | rm -R ~/ckad/
kubectl delete ns storage-namespace --force
kubectl delete ns pod-namespace --force
kubectl delete pv my-pv
End of Section