Certified Kubernetes Administrator (CKA) krok po kroku – część 1

Kubernetes stał się od pewnego czasu tym orkiestratorem skonteneryzowanych aplikacji, który podbija i zdobywa kolejne obszary rozwoju infrastruktury i architektury systemów informatycznych.  Postanowiłem się zmierzyć z certyfikacją z tego obszaru. Egzaminy, z jakimi miałem do tej pory do czynienia, były inne, głównie sprowadzały się do testów jednokrotnego lub wielokrotnego wyboru. Tu jest inaczej, gdyż wszystkie zadania są w pełni praktyczne i wymagają przygotowania obiektu (zasobu), który następnie powinien być wdrożony na klaster. Czy warto zainteresować się taką certyfikacją? Myślę, że tak, ale należy ją potraktować jako przygodę, którą powinna usystematyzować wiedzę i ugruntować kompetencje w konfigurowaniu klastra za pomocą jedynie dokumentacji i natywnych narzędzi.

 

Aktualnie możliwe są trzy ścieżki

  1. CKA (Certified Kubernetes Administrator)

https://training.linuxfoundation.org/certification/certified-kubernetes-administrator-cka/

2. CKAD ( Certified Kubernetes Aplication Developer)

https://training.linuxfoundation.org/certification/certified-kubernetes-application-developer-ckad/

3. CKS ( Certified Kubernetes Security Specialist)

https://training.linuxfoundation.org/certification/certified-kubernetes-security-specialist/

Wybrałem ścieżkę administratora, chociaż jest ona najbardziej obszerna, to pozwala zweryfikować umiejętności radzenia sobie z klastrem jedynie za pomocą dokumentacji i narzędzia typu cli.

 

Egzamin przeprowadzany jest za pomocą wtyczki do Gogle Chrome

Całość pracy odbywa się w oknie przeglądarki. Pracujemy na systemie Ubuntu i mamy do dyspozycji drugą zakładkę , za pomocą której możemy korzystać z oficjalnej dokumentacji

Należy pamiętać, że zamiast Control+C (Copy) i Control+V mamy odpowiednio Control+Insert (Copy) i Shift+Insert (Paste).

Dostępny jest też notatnik, ale po jego uruchomieniu zasłania on ok 1/3 obszaru roboczego.

Mamy do zrobienia ok. 17 zadań w czasie dwóch godzin. Należy dobrze kontrolować czas. Każde z zadań ma podaną wagę, jeśli któreś z zadań sprawia nam trudności i utknęliśmy na dłużej niż 10 minut proponuję je oflagować (co umożliwia środowisko) i przejść do kolejnego.

Zakres egzaminu podzielony jest na pięć kategorii

  • Workloads & Scheduling, 15%
  • Services & Networking, 20%
  • Storage, 10%
  • Troubleshooting, 30%

Ponieważ nie mamy za dużo czasu na przygotowanie rozwiązań, warto zastanowić się jak pracować w szybszym tempie.

Zwiększanie efektywności pracy

  1. Używanie aliasów
  2. Praca w trybie próbnym (–dry-run)
  3. Wdrażanie zmian na klastrze z przygotowanych manifestów YAML.
  4. Korzystanie z oficjalnej dokumentacji w postaci przygotowanych zakładek w przeglądarce)

 

1. Aliasy

 

alias k='kubectl'

alias kn='kubectl get nodes -o wide'
alias kp='kubectl get pods -o wide'
alias kd='kubectl get deployment -o wide'
alias ks='kubectl get svc -o wide'

Lista aliasów może być inna i o wiele większa, ważne, aby z nich korzystać regularnie podczas ćwiczeń.

 

2. Praca w trybie dry-run

 

Praca w trybie dry-run sprowadza się do skorzystania poniższego szablonu  poleceń

kubectl <polecenie> --dry-run=client -o yaml > <plik.yaml> 

Warto wyeksportować zmienną $do, która ułatwi nam pracę:

export do=" --dry-run=client -o yaml "

Od tego momentu, praca w wersji skróconej (wykorzystującej aliasy i zmienne środowiskowe) sprowadza się do postaci:

k <polecenie> $do > <plik.yaml>

 

W praktyce sprowadzi się do wykonywania poleceń typu:

# Create a pod  nginx image
kubectl run nginx --image=nginx

# Create the pod template file with dry-run
kubectl run nginx --image=nginx --dry-run=client -o yaml>nginx.yaml

# Create a deployment
kubectl create deploy nginx-app --image=nginx --dry-run=client

# Scale a deployment
kubectl scale deploy nginx-app --replicas=3 

# Create nginx-service and expose
kubectl expose pod nginx--name=nginx-service --port=80 --dry-run=client -o yaml>nginx.yaml

# Create a secret name my-secret with username admin
kubectl create secret generic my-secret --from-literal username=admin --dry-run=client -o yaml>nginx.yaml

 

3. Korzystanie z manifestów YAML

 

Przygotowujemy polecenie tworzenia obiektu w trybie imperatywnym, wyświetlamy jego postać w formacie YAML i zapisujemy w postaci pliku. Taki plik możemy modyfikować za pomocą edytora tekstu.

Unikałbym stosowania edycji obiektów bezpośrednio na klastrze

  kubectl edit deployment nginx

Bardziej efektywne będzie zapisanie obiektu w postaci pliku, jego edycja, a następnie jego modyfikacji na klastrze za pomocą

kubectl apply -f plik.yaml

Sekwencja poleceń wygląda mniej więcej tak

kubectl get deployment nginx -o yaml > 01.deploy.nginx.yaml

vim 01.deploy.nginx.yaml

kubectl apply -f 01.deploy.nginx.yaml

Tu proponuję zastosować konwencję nazewnictwa pliku

numer_zadania:typ_obiektu:nazwa_obiektu.yaml

Można tez stosować inną konwencję, ale odpowiednio spójną wewnętrznie.

 

Dla tych, którzy chcą spróbować zabawy z klastrem przygotowałem piaskownicę w postaci środowiska w narzędziu Katacoda

Pozwala ono na godzinna zabawę.

Przykład utworzenia obiektu pod o nazwie test zbudowanego na obrazie nginx:1.16. Obiekt powinien zostać umieszczony w przestrzeni nazwa default

kubectl run test --image=nginx:1.16 -o yaml --dry-run=client

Na wyjściu pojawia się plik

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: test
  name: test
spec:
  containers:
  - image: nginx
    name: test
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}                    

Zapiszmy go do pliku na nazwie 01.pod.test.yaml

kubectl run test --image=nginx:1.16 -o yaml --dry-run=client > 01.pod.test.yaml
vim 01.pod.nginx.yaml

Tutaj warto dodać brakujący namespace: default. To jest przydatne podczas tworzenia manifestów dla innych przestrzeni nazw i uwalnia nas to od dodawania do polecenia –namespace abc (lub -n  abc).

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: test
  name: test
  namespace: default
spec:
  containers:
  - image: nginx:1.16
    name: test
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
kubectl apply -f 01.pod.test.yaml
pod/test created

 

Spróbujmy po wdrożeniu zmienić nazwę kontenera, ale nie jego obraz

Zmieniamy w pliku jedną linię
name: test2

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: test
  name: test
  namespace: default
  
spec:
  containers:
  - image: nginx:1.16
    name: test2
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

 

kubectl apply -f 01.pod.test.yaml 

Próba wdrożenia tak zmodyfikowanego manifestu na klaster kończy się spektakularnie

The Pod "test" is invalid: spec: Forbidden: pod updates may not change fields other than `spec.containers[*].image`, `spec.initContainers[*].image`, `spec.activeDeadlineSeconds` or `spec.tolerations` (only additions to existing tolerations)
  core.PodSpec{
        Volumes:        []core.Volume{{Name: "default-token-dbflg", VolumeSource: core.VolumeSource{Secret: &core.SecretVolumeSource{SecretName: "default-token-dbflg", DefaultMode: &420}}}},
        InitContainers: nil,
        Containers: []core.Container{
                {
-                       Name:    "test2",
+                       Name:    "test",
                        Image:   "nginx:1.16",
                        Command: nil,
                        ... // 4 identical fields
                        Env:          nil,
                        Resources:    core.ResourceRequirements{},
-                       VolumeMounts: nil,
+                       VolumeMounts: []core.VolumeMount{
+                               {
+                                       Name:      "default-token-dbflg",
+                                       ReadOnly:  true,
+                                       MountPath: "/var/run/secrets/kubernetes.io/serviceaccount",
+                               },
+                       },
                        VolumeDevices: nil,
                        LivenessProbe: nil,
                        ... // 10 identical fields
                },
        },
        EphemeralContainers: nil,
        RestartPolicy:       "Always",
        ... // 24 identical fields
  }

Okazuje się, że nie wszystkie zmiany są możliwe w takim trybie. Można oczywiście usunąć obiekt z klastra i wdrożyć jeszcze raz. Czas na goni. Lepiej jest opanować tryb siłowy, która przyśpiesza pracę, ale nie używajcie go bezrefleksyjnie na produkcji (!).
W naszym przypadku nie można modyfikować nazwy kontenera, ale można modyfikować obraz, z którego korzysta.

kubectl apply -f 01.pod.test.yaml --force            
pod/test configured

To samo może nam się przytrafić podczas edycji obiektu bezpośrednio na klastrze, a przecież pod to podstawowy obiekt wdrożeniowym. Nie należy o tym zapominać podczas pracy z obiektami, które kontrolują jego stan.

Dla bardziej skomplikowanych obiektów np. statefulset czy daemonset warto jest skorzystać z gotowych przykładów w dokumentacji i przystosować je do wymogów zadania.

 

4. Dokumentacja:

 

Dostępne strony są ograniczone do

Można mieć jednocześnie otwartą jedna zakładkę. Ponieważ dozwolone jest korzystanie z zakładek przeglądarki Chrome warto przygotować sobie dedykowaną listę zakładek.

Przykładowa lista zakładek https://gist.github.com/jonatasbaldin/4e76846ce8fb17e5d2fa64bdea594930

Oprócz dokumentacji  można skorzystać z polecenia

kubectl explain
kubectl explain pod.spec.containers --recursive

 

5. YAML w Kubernetes

W tym miejscu warto poświęcić chwilę budowę manifestów YAML w Kubernetes.

 

Definicja obiektów Kubernetes w postaci manifestu YAML daje wiele zalet, m.in:

Wygoda: Nie ma potrzeby dodawania kolejnego parametru do linii poleceń
Utrzymanie: Pliki YAML  można łatwo przechowywać w systemach kontroli wersji
Elastyczność: Można tworzyć o wiele bardziej skompilowane struktury niż z linii poleceń.

 

YAML jest nadzbiorem JSON, co oznacza, że każdy obiekt w formacie JSON jest poprawny w postaci YAML, ale w drugą stronę niekoniecznie.

Na szczęście YAML w Kubernetes jest prosty do nauki. Mamy tylko dwa typy struktur, które musimy opanować:

  • Listy
  • Mapy

Te dwie struktury mogą się przeplatać , czyli możemy mieć listę map i mapę list oraz każdą możliwą kombinację z obu stron.

Mapy

Zacznijmy od prostego, ale praktycznego przykładu

---
apiVersion: v1
kind: Pod

Pierwsza linia to separator obiektów, które można zapisać w jednym pliku. W praktyce nie polecam, wolę mieć poszczególne manifesty rozbite per plik.

Jest to o wiele bardziej elastyczne, jeśli zaczynami stosować systemy kontroli wersji. Wtedy mamy pełną kontrolę nad zmianami w każdym obiekcie niezależnie.

Mapa to para klucz: wartość. Nasz przykład zawiera dwie mapy, gdzie  klucz od wartości oddziela znak :

 

klucz apiVersion o wartości v1

klucz kind o wartości Pod.

 

Odpowiednik w notacji JSON wygląda tak:

{
   "apiVersion": "v1",
   "kind": "Pod"
}

Większość manifestów w Kubernetes ma strukturę akms (apiVersion, kind, metadata, spec)

apiVersion: v1
kind:
metadata:
spec:

W porównaniu do JSON znaki “” są opcjonalne.

Można też zbudować struktury, gdzie klucz nie wskazuje na wartość, ale na kolejną parę klucz:wartość, czyli na  mapę

---
apiVersion: v1
kind: Pod
metadata:
  name: rss-site
  labels:
    app: web

Klucz metadata wskazuje na parę name: rss-site. Para jest przeniesiona do następnej lini z odpowiednim wcięciem w stosunku do klucza nadrzędnego (metadata).  Takie konstrukcje można swobodnie zagnieżdżać. Wcięcia realizowane są za pomocą spacji. Należy unikać i nie stosować w plikach YAML tabulacji. Z reguły stosuje się dwie spacje, ale może być ich więcej. Ważne, by było to spójne w obrębie pliku.

Odpowiednik w notacji JSON wygląda tak:

{
  "apiVersion": "v1",
  "kind": "Pod",
  "metadata": {
               "name": "rss-site",
               "labels": {
                          "app": "web"
                         }
              }
}

 

Listy

Listy w YAML to sekwencja obiektów:

args:
  - sleep
  - "1000"
  - message
  - "Bring back Firefly!"

Każdy z  elementów listy rozpoczyna się od znaku – wciętego względem rodzica i w praktyce pozwala to na budowę nieskończonie długiej struktury.

Odpowiednik w notacji JSON wygląda tak:

{
   "args": ["sleep", "1000", "message", "Bring back Firefly!"]
}

Oczywiście poszczególne elementy listy mogą być mapami.

---
apiVersion: v1
kind: Pod
metadata:
  name: rss-site
  labels:
    app: web
spec:
  containers:
    - name: front-end
      image: nginx
      ports:
        - containerPort: 80
    - name: rss-reader
      image: nickchase/rss-php-nginx:v1
      ports:
        - containerPort: 88

Mamy tutaj listę obiektów kontener (containers), z których każdy składa się z imienia (name), obrazu (image) i listy portów (czyli listę w liście).

Każdy element listy wcięty poniżej znacznika ports jest listą zawierającą mapę o nazwie containerPort i wartości 80 (lub 88).

Dla porównania, spójrzmy na odpowiednik w postaci JSON:

{ “apiVersion”: “v1”, “kind”: “Pod”, “metadata”: { “name”: “rss-site”, “labels”: { “app”: “web” } }, “spec”: { “containers”: [{ “name”: “front-end”, “image”: “nginx”, “ports”: [{ “containerPort”: “80” }] }, { “name”: “rss-reader”, “image”: “nickchase/rss-php-nginx:v1”, “ports”: [{ “containerPort”: “88” }] }] } }

Sami szybko dojdziemy do wniosku, że YAML czyta się (i modyfikuje)  znacznie lepiej niż JSON. Dla API Kubernetes nie ma to żadnego znaczenia.

 

Podsumowując, mamy do dyspozycji:

 

  • mapy, które są grupą struktur klucz: wartość
  • listy,które są zbiorem indywidualnych wartości
  • mapy złożone z map
  • mapy złożone z list
  • listy złożone z list
  • listy złożone z map

 

Te dwie struktury pozwalają nam złożyć razem bardziej skomplikowane manifesty.

Zacznijmy od najprostszego obiektu jakim jest pod.

Zapiszmy taki plik w postaci pliku pod.yaml

—
apiVersion: v1
kind: Pod
metadata:
 name: rss-site
 labels:
   app: web
spec:
 containers:
   – name: front-end
     image: nginx
     ports:
       – containerPort: 80
   – name: rss-reader
     image: nickchase/rss-php-nginx:v1
     ports:
       – containerPort: 88

Wdrożenie obiektu na klaster jest realizowane za pomocą opcji -f, która wskazuje plik zawierający przygotowany manifest.

kubectl create -f pod.yaml

 

W następnych częściach postaram się opisać najczęściej spotykane zagadnienia w poszczególnych obszarach tematycznych zakresu egzaminu.

 

6. Kursy

 

Pośród wielu kursów, które można znaleźć na różnych platformach  szkoleniowych wybrałem

https://www.udemy.com/course/certified-kubernetes-administrator-with-practice-tests/

Było to dobrze wydane kilkadziesiąt złotych. Warto zrobić go spokojnie i po kolei, jedną z głównych zalet są przygotowane ćwiczenia. Te przygotowane laboratoria stanowią cenny dodatek, który pozwala nam na nabranie wprawy manualnej i ułatwia poruszanie się po nieco ascetycznym środowisku egzaminacyjnym.

 

Następne części

 

Certified Kubernetes Administrator (CKA) krok po kroku – część 2

 

Literatura:

 

https://www.kubernative.net/de/17-tutorial/69-exam-experience-cka

https://github.com/David-VTUK/CKA-StudyGuide

https://www.mirantis.com/blog/introduction-to-yaml-creating-a-kubernetes-deployment/

https://www.katacoda.com/djkormo/scenarios/kubernetes-sandbox

https://codeburst.io/the-ckad-browser-terminal-10fab2e8122e

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.