▶️ Introduction
This part outlines the key deployment and networking aspects 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:
All the examples have been developed using minikube on macOS Catalina with VirtualBox.
🖥️ Deployments
📘 https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
Create a new Deployment boilerplate via dry-run
:
kubectl create deployment ex1 --image = nginx --dry-run = client -o = yaml > dep1.yaml
Then such deployment can be tuned, for instance setting the number of desired replicas :
apiVersion : apps/v1
kind : Deployment
metadata :
labels :
app : ex1
name : ex1
namespace : jmcf
spec :
replicas : 3
selector :
matchLabels :
app : ex1
strategy : {}
template :
metadata :
labels :
app : ex1
spec :
containers :
- image : nginx
name : nginx
Check Deployment status :
kubectl get deployments/ex1 -n jmcf -o = wide -w
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
ex1 3/3 3 3 2m18s nginx nginx app = ex1
kubectl get rs -n jmcf -o = wide --selector = 'app=ex1'
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
ex1-678d4cb9c5 3 3 3 5m23s nginx nginx app = ex1,
📌 A Replica Set is created as a subsidiary of a Deployment.
List the Pods associated to a Deployment:
kubectl get pods -n jmcf --selector = 'app=ex1' -o = wide
NAME READY STATUS RESTARTS AGE IP
ex1-678d4cb9c5-lx7sx 1/1 Running 0 7m30s 172.17.0.32
ex1-678d4cb9c5-lzlkk 1/1 Running 0 7m30s 172.17.0.47
ex1-678d4cb9c5-zmknk 1/1 Running 0 7m30s 172.17.0.48
📌 A Deployment is based on a templated Pod . There should be as many Pods as desired replicas.
📌 A delete of a Deployment is on cascade , i.e. all subsidiary Pods will be deleted.
A Deployment can be updated just through kubectl edit
:
kubectl edit -n jmcf -f dep1.yaml
📌 When you edit a Deployment a new revision might be created, allowing you to rollback later to a previous configuration.
Update Deployment image :
kubectl set image deployment/ex1 nginx = nginx:1.9.1 -n jmcf
kubectl get rs -n jmcf -o = wide --selector = 'app=ex1'
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
ex1-678d4cb9c5 0 0 0 3h30m nginx nginx app = ex1
ex1-79c777cf98 3 3 3 171m nginx nginx:1.9.1 app = ex1
📌 Changing the image of a Deployment implies the creation of a new Replica Set .
Rollout
To check the rollout status of a Deployment:
kubectl rollout status deploy ex1 -n jmcf -w
📌 maxSurge
and maxUnavailable
(spec.strategy
) are two important parameters that govern how the rollout process is conducted.
Display rollout history of a Deployment:
kubectl rollout history deployments/ex1 -n jmcf
Rolling back to a previous revision:
kubectl rollout undo deployments/ex1 --to-revision = 1 -n jmcf
📌 A rollback generates a new revision .
Scaling out a Deployment:
kubectl scale deployments/ex1 --replicas = 5 -n jmcf
📌 Scaling out a Deployment does not generate a new revision.
Auto scale an existing Deployment:
kubectl autoscale deployments/ex1 --min = 5 --max = 10 --cpu-percent = 80 -n jmcf
📌 Requesting autoscaling implies the creation of an Horizontal Pod Autoscaler.
📌 An Horizontal Pod Autoscaler takes precedence over a Replica Set.
List the existing Horizontal Pod Autoscalers :
kubectl get hpa -n jmcf
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
ex1 Deployment/ex1 <unknown>/80% 5 10 5 2m57s
Remove Horizontal Autoscaling:
kubectl delete hpa/ex1 -n jmcf
🧱 Services
📘 https://kubernetes.io/docs/concepts/services-networking/service
Headless Service
Create a headless (without Cluster IP) Service:
kubectl create service clusterip my-service --tcp = 80:80 --clusterip = "None" --dry-run = client -o = yaml > service.yaml
apiVersion : v1
kind : Service
metadata :
labels :
app : ex1
name : my-service
namespace : jmcf
spec :
clusterIP : None
ports :
- name : 80-80
port : 80
protocol : TCP
targetPort : 80
selector :
app : ex1
type : ClusterIP
📌 The name of a Service object must be a valid DNS label name.
📌 The ports exposed under a headless Service are just Pod’s container(s) ports
📌 A Service is assigned a DNS name, usually in the form <service-name>.<namespace>.svc.cluster.local
📌 A Service groups Pods based on matching labels .
kubectl describe service my-service -n jmcf
Name: my-service
Namespace: jmcf
Labels: app = ex1
Annotations: Selector: app = ex1
Type: ClusterIP
IP: None
Port: 80-80 80/TCP
TargetPort: 80/TCP
Endpoints: 172.17.0.47:80,172.17.0.48:80,172.17.0.49:80
Session Affinity: None
Events: <none>
Test that my-service
has been configured properly:
kubectl run test1 -it --rm = true --image = busybox --restart = Never -n jmcf -- wget -O - http://my-service
kubectl run test1 -it --rm = true --image = busybox --restart = Never -n jmcf -- wget -O - http://my-service.jmcf
kubectl run test1 -it --rm = true --image = busybox --restart = Never -n jmcf -- wget -O - http://my-service.jmcf.svc.cluster.local
Cluster IP Service
Create a Cluster IP Service
kubectl create service clusterip my-service --tcp = 8080:80 --dry-run = client -o = yaml > service-clusterip.yaml
apiVersion : v1
kind : Service
metadata :
labels :
app : ex1
name : my-service-cip
namespace : jmcf
spec :
ports :
- name : 8080-80
port : 8080
protocol : TCP
targetPort : 80
selector :
app : ex1
type : ClusterIP
📌 targetPort
(the second element in the --tcp
parameter) is the Pod’s container port .
kubectl describe service my-service-cip -n jmcf
Name: my-service-cip
Namespace: jmcf
Labels: app = ex1
Annotations: Selector: app = ex1
Type: ClusterIP
IP: 10.96.72.170
Port: 8080-80 8080/TCP
TargetPort: 80/TCP
Endpoints: 172.17.0.47:80,172.17.0.48:80,172.17.0.49:80
Session Affinity: None
Events: <none>
Test that the Cluster IP has been assigned properly:
kubectl run test1 -it --rm = true --image = busybox --restart = Never -n jmcf -- wget -O - http://10.96.72.170:8080
kubectl run test1 -it --rm = true --image = busybox --restart = Never -n jmcf -- wget -O - http://my-service-cip:8080
kubectl run test1 -it --rm = true --image = busybox --restart = Never -n jmcf -- wget -O - http://my-service-cip.jmcf:8080
kubectl run test1 -it --rm = true --image = busybox --restart = Never -n jmcf -- wget -O - http://my-service-cip.jmcf.svc.cluster.local:8080
Node Port Service
Create Node Port Service
kubectl create service nodeport my-service-np --tcp = 8080:80 --dry-run = client -o = yaml > service-nodeport.yaml
apiVersion : v1
kind : Service
metadata :
labels :
app : ex1
name : my-service-np
namespace : jmcf
spec :
ports :
- name : 8080-80
port : 8080
protocol : TCP
targetPort : 80
selector :
app : ex1
type : NodePort
kubectl describe service my-service-np -n jmcf
Name: my-service-np
Namespace: jmcf
Labels: app = ex1
Annotations: Selector: app = ex1
Type: NodePort
IP: 10.106.215.220
Port: 8080-80 8080/TCP
TargetPort: 80/TCP
NodePort: 8080-80 31460/TCP
Endpoints: 172.17.0.47:80,172.17.0.48:80,172.17.0.49:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
Test that the Node Port has been assigned properly:
wget -O - http://192.168.99.101:31460
kubectl run test1 -it --rm = true --image = busybox --restart = Never -n jmcf -- wget -O - http://10.106.215.220:8080
kubectl run test1 -it --rm = true --image = busybox --restart = Never -n jmcf -- wget -O - http://my-service-np:8080
kubectl run test1 -it --rm = true --image = busybox --restart = Never -n jmcf -- wget -O - http://my-service-np.jmcf:8080
kubectl run test1 -it --rm = true --image = busybox --restart = Never -n jmcf -- wget -O - http://my-service-np.jmcf.svc.cluster.local:8080
kubectl run test1 -it --rm = true --image = busybox --restart = Never -n jmcf -- wget -O - http://172.17.0.47
🌐 Networking
Ingress
📘 https://kubernetes.io/docs/concepts/services-networking/ingress/
📌 Ingress exposes HTTP and HTTPS routes from outside the cluster to services within the cluster.
📌 You must have an ingress controller to satisfy an Ingress. Only creating an Ingress
resource has no effect.
An Ingress which enables reverse proxying to your Service from a canonical address:
apiVersion : networking.k8s.io/v1beta1
kind : Ingress
metadata :
name : test-ingress
namespace : jmcf
annotations :
nginx.ingress.kubernetes.io/rewrite-target : /
spec :
rules :
- host : ckad.example.org
http :
paths :
- path : /ex1
backend :
serviceName : my-service-cip
servicePort : 8080
Then you can get access to your Service through (provided external DNS entry or etc/hosts
has been set up):
curl http://ckad.example.org/ex1
📌 The annotation nginx.ingress.kubernetes.io/rewrite-target: /
enables reverse proxying.
Network Policies
📘 https://kubernetes.io/docs/concepts/services-networking/network-policies/
📌 To use Network Policies, you must be using a networking solution (such as Calico , Cilium or Flannel ) which supports NetworkPolicy
. Creating a NetworkPolicy
resource without a controller that implements it will have no effect.
Define a Network Policy that allows to talk to, our previously defined, ex1
Pods only from containers belonging to the jmcf
Namespace which are labeled as role=test
.
kubectl label namespace jmcf 'project=ckad'
📌 Namespace selector needs matching labels.
apiVersion : networking.k8s.io/v1
kind : NetworkPolicy
metadata :
name : test-network-policy
namespace : jmcf
spec :
podSelector :
matchLabels :
app : ex1
policyTypes :
- Ingress
ingress :
- from :
- namespaceSelector :
matchLabels :
project : ckad
- podSelector :
matchLabels :
role : test
ports :
- protocol : TCP
port : 80
kubectl describe NetworkPolicy test-network-policy -n jmcf
Name: test-network-policy
Namespace: jmcf
Created on: 2020-06-25 14:03:55 +0200 CEST
Labels: <none>
Annotations: Spec:
PodSelector: app = ex1
Allowing ingress traffic:
To Port: 80/TCP
From:
NamespaceSelector: project = ckad
From:
PodSelector: role = test
Not affecting egress traffic
Policy Types: Ingress
📌 A Network Policy defines white lists for ingress traffic, egress traffic or both.
📌 A Network Policy applies to certain Pods (those matching labels) in a Namespace.
📌 A Network Policy ingress or egress rules determines from or to which Pods and/or Namespaces traffic is allowed.
📌 If you declare Ingress
or Egress
policy types (under policyTypes
), and no rule is provided under that category, then no traffic of such category will be allowed.
🗒️ Feedback
Please enable JavaScript to view the comments powered by Disqus.