Comme recommandé par la doc du CKA. Voici les commandes a effectuer dès qu'on arrive sur l'environnement d'examen :
alias k=kubectl # will already be pre-configured
export do="--dry-run=client -o yaml" # k get pod x $do
export now="--force --grace-period 0" # k delete pod x $now
Pour VIM dans le ~/.vimrc
:
set tabstop=2
set expandtab
set shiftwidth=2
Dans cette liste de questions, j'ai mis des questions typiques qui m'ont posé problème durant l'examen blanc.
Créer un pod avec la dernière image nginx
. Ce pod ne doit tourner que sur un noeud master :
Regarder les taints/labels sur les différents noeuds master :
$ kubectl describe node master1 | grep Taint
Taints: node-role.kubernetes.io/master:NoSchedule
$ kubectl describe node master1 | grep Labels -A 10
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=cluster1-master1
kubernetes.io/os=linux
node-role.kubernetes.io/control-plane=
node-role.kubernetes.io/master=
node.kubernetes.io/exclude-from-external-load-balancers=
Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /run/containerd/containerd.sock
node.alpha.kubernetes.io/ttl: 0
volumes.kubernetes.io/controller-managed-attach-detach: true
On va donc créer un pod avec une tolérance + un nodeSelector :
apiVersion: v1
kind: Pod
metadata:
labels:
run: pod1
name: pod1
spec:
containers:
- image: nginx
name: pod1-container
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/master
nodeSelector:
node-role.kubernetes.io/master: ""
Afficher l'utilisation des noeuds :
kubectl top node
Afficher l'utilisation des pods ET des containers s'il y en a :
kubectl top pod --containers=true
Vérifiez comment les composants maîtres kubelet, kube-apiserver, kube-scheduler, kube-controller-manager et etcd sont démarrés/installés sur le nœud maître. Découvrez également le nom de l'application DNS et comment elle est démarrée/installée sur le nœud maître.
Inscrivez vos résultats dans le fichier /opt/response/8/master-components.txt. Le fichier doit être structuré comme suit :
kubelet: [TYPE]
kube-apiserver: [TYPE]
kube-scheduler: [TYPE]
kube-controller-manager: [TYPE]
etcd: [TYPE]
dns: [TYPE] [NAME]
Les choix du [TYPE] sont: not-installed, process, static-pod, pod
# En root :
$ ps aux | grep kubelet # shows kubelet process
# Voir quels sont les composants gérés par systemd
$ find /etc/systemd/system/ | grep kube
/etc/systemd/system/kubelet.service.d
/etc/systemd/system/kubelet.service.d/10-kubeadm.conf
/etc/systemd/system/multi-user.target.wants/kubelet.service
$ find /etc/systemd/system/ | grep etcd
# Le cluster sera configuré avec kubadm, on peut donc retrouver les manifests :
$ find /etc/kubernetes/manifests/
/etc/kubernetes/manifests/
/etc/kubernetes/manifests/kube-controller-manager.yaml
/etc/kubernetes/manifests/etcd.yaml
/etc/kubernetes/manifests/kube-scheduler-special.yaml
/etc/kubernetes/manifests/kube-apiserver.yaml
/etc/kubernetes/manifests/kube-scheduler.yaml
Cela signifie que les 4 services principaux sont configurés comme des pods statiques (static-pod).
$ kubectl -n kube-system get pod -o wide | grep master1
coredns-5644d7b6d9-c4f68 1/1 Running ... master1
coredns-5644d7b6d9-t84sc 1/1 Running ... master1
etcd-cluster1-master1 1/1 Running ... master1
kube-apiserver-cluster1-master1 1/1 Running ... master1
kube-controller-manager-cluster1-master1 1/1 Running ... master1
kube-proxy-q955p 1/1 Running ... master1
kube-scheduler-cluster1-master1 1/1 Running ... master1
kube-scheduler-special-cluster1-master1 0/1 CrashLoopBackOff ... master1
weave-net-mwj47 2/2 Running ... master1
On peut voir que les 5 composants sont controlés par un pod statique (suffixe -cluster1-master1).
Le DNS est coredns
mais on ne sait pas par quoi il est géré. On va donc faire :
$ kubectl -n kube-system get ds
NAME DESIRED CURRENT ... NODE SELECTOR AGE
kube-proxy 3 3 ... kubernetes.io/os=linux 155m
weave-net 3 3 ... <none> 155m
$ kubectl -n kube-system get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
coredns 2/2 2 2 155m
Il est donc controlé par un deployment.
Le fichier est donc rempli de la manière suivante :
kubelet: process
kube-apiserver: static-pod
kube-scheduler: static-pod
kube-scheduler-special: static-pod
kube-controller-manager: static-pod
etcd: static-pod
dns: pod coredns
Connectez-vous au nœud maître avec ssh cluster2-master1
. Arrêtez temporairement le kube-scheduler, de manière à pouvoir le relancer par la suite.
Créez un Pod unique nommé manual-schedule
de l'image httpd:2.4-alpine
, confirmez sa création mais ne le schedule sur aucun noeud.
Maintenant que vous êtes le scheduler et que vous avez tout son pouvoir, planifiez manuellement ce pod sur le nœud cluster1-master1
. Assurez-vous qu'il est en cours d'exécution.
Redémarrez le kube-scheduler et confirmez son fonctionnement correct en créant un second pod nommé manual-schedule2 de l'image httpd:2.4-alpine et vérifiez qu'il fonctionne sur cluster2-worker1.
# On va aller déplacer le manifest du static-pod kube-scheduler :
$ cd /etc/kubernetes/manifests/
$ mv kube-scheduler.yaml ../
# Cela va stopper le static-pod
Si on vérifier :
$ kubectl -n kube-system get pod | grep scheduler-master
Rien ne ressort car le pod s'est stoppé. On va maintenant lancer un pod, mais celui-ci ne sera pas assigné :
$ k run manual-schedule --image=httpd:2.4-alpine
$ k get pod manual-schedule -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
manual-schedule 0/1 Pending 0 17s <none> <none> <none> <none>
On va donc récupérer le yaml de ce pod :
$ k get pod manual-schedule -o yaml > manual-schedule.yaml
En réalité, le scheduler rajoute juste le nom de noeud (nodeName
) dans le YAML :
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2022-03-20T15:26:44Z"
labels:
run: manual-schedule
name: manual-schedule
namespace: default
resourceVersion: "30688"
uid: 23f5daf4-7aed-437e-90f5-122a5f173481
spec:
nodeName: cluster1-master1 # ajouter le nom du noeud master
containers:
- image: httpd:2.4-alpine
imagePullPolicy: IfNotPresent
name: manual-schedule
...
On ne peut pas simplement appliquer le fichier :
$ k apply -f manual-schedule.yaml
Warning: resource pods/manual-schedule is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
On va donc forcer la recréation du pod :
$ k -f manual-schedule.yaml replace --force
pod "manual-schedule" deleted
pod/manual-schedule replaced
On va maintenant relancer le kube-scheduler
:
$ cd /etc/kubernetes/
$ mv kube-scheduler.yaml manifests/
Créer un nouveau ServiceAccount au nom de processor
dans le Namespace project-hamster
. Créez un Role et un RoleBinding, tous deux nommés processor
également. Ceux-ci devraient permettre au nouveau ServiceAccount de créer uniquement des Secrets et des ConfigMaps dans ce Namespace.
Tips: Plutot que de tout faire en yaml. Faire via CLI :
$ k -n project-hamster create role processor --verb=create --resource=secrets --resource=configmaps
RoleBinding :
$ k -n project-hamster create rolebinding processor --role processor --serviceaccount project-hamster:processor
Pour tester notre configuration RBAC, nous pouvons utiliser kubectl auth can-i
:
$ k -n project-hamster auth can-i -h
...
$ k -n project-hamster auth can-i create secret --as system:serviceaccount:project-hamster:processor
yes
$ k -n project-hamster auth can-i get secret --as system:serviceaccount:project-hamster:processor
no
Le but est de lancer un déploiement avec 3 réplicas. 1 pod maximum par noeud ! (l'équivalent d'un daemonset via un deployment) :
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
id: very-important
name: deploy-important
namespace: project-tiger
spec:
replicas: 3
selector:
matchLabels:
id: very-important
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
id: very-important
spec:
containers:
- image: nginx:1.17.6-alpine
name: container1
affinity:
# Ici, si un pod avec l'id "very-important" tourne déjà sur le noeud, on en démarre pas un 2ème
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: id
operator: In
values:
- very-important
topologyKey: kubernetes.io/hostname
Si on regarde le pod qui n'est pas schedule on voit :
Warning FailedScheduling 63s (x3 over 65s) default-scheduler 0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 2 node(s) didn't match pod affinity/anti-affinity, 2 node(s) didn't satisfy existing pods anti-affinity rules.
Le déploiement peut aussi se faire via topologySpreadConstraints
, plus simple à comprendre pour ma part :
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
id: very-important
name: deploy-important
namespace: project-tiger
spec:
replicas: 3
selector:
matchLabels:
id: very-important
template:
metadata:
labels:
id: very-important
spec:
containers:
- image: nginx:1.17.6-alpine
name: container1
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
id: very-important
Si on regarde le pod qui n'est pas schedule on voit :
Warning FailedScheduling 16s default-scheduler 0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 2 node(s) didn't match pod topology spread constraints.
1/ et 2/ On en voit 1 master et 2 workers
$ k get node
NAME STATUS ROLES AGE VERSION
cluster1-master1 Ready master 27h v1.23.1
cluster1-worker1 Ready <none> 27h v1.23.1
cluster1-worker2 Ready <none> 27h v1.23.1
3/ Pour voir cela, il faut se connecter sur le master et aller dans les fichiers de conf de kube-apiserver
. 10.96.0.0/12 est la réponse.
$ cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep range
- --service-cluster-ip-range=10.96.0.0/12
4/ En regardant dans le dossier de conf du cni, on voit que c'est weave
qui est utilisé :
$ find /etc/cni/net.d/
/etc/cni/net.d/
/etc/cni/net.d/10-weave.conflist
$ cat /etc/cni/net.d/10-weave.conflist
{
"cniVersion": "0.3.0",
"name": "weave",
...
5/ Le suffixe sera -cluster1-worker1
.
Créez un nouveau namespace appelé cka-master
.
Écrivez les noms de toutes les ressources Kubernetes qui peuvent contenir des namespaces (comme Pod, Secret, ConfigMap...) dans /opt/course/16/resources.txt.
Trouvez le Namespace du projet-*
avec le plus grand nombre de Roles définis et écrivez son nom et le nombre de Roles dans /opt/course/16/crowded-namespace.txt.
$ k create ns cka-master
$ k api-resources --namespaced -o name > /opt/course/16/resources.txt
Ensuite on va lister les roles et connaitre le nombre par namespace :
$ k -n project-c13 get role --no-headers | wc -l
No resources found in project-c13 namespace.
0
$ k -n project-c14 get role --no-headers | wc -l
300
$ k -n project-hamster get role --no-headers | wc -l
No resources found in project-hamster namespace.
0
$ k -n project-snake get role --no-headers | wc -l
No resources found in project-snake namespace.
0
$ k -n project-tiger get role --no-headers | wc -l
No resources found in project-tiger namespace.
0
Etonnemment je ne l'avais jamais vu jusque là :
$ kubeadm token create --print-join-command
kubeadm join 192.168.100.31:6443 --token leqq1l.1hlg4rw8mu7brv73 --discovery-token-ca-cert-hash sha256:2e2c3407a256fc768f0d8e70974a8e24d7b9976149a79bd08858c4d7aa2ff79a
Il peut être demandé d'écrire la date d'expiration dans un fichier txt. Pour ce faire :
$ openssl x509 -noout -text -in /etc/kubernetes/pki/etcd/server.crt | grep Validity -A2
Validity
Not Before: Sep 13 13:01:31 2021 GMT
Not After : Sep 13 13:01:31 2022 GMT