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

wpis w: CKA, konteneryzacja, Kubernetes | 1

W kolejnej części przewodnika po praktykach, które pomagają zdobyć certyfikat CKA , chciałbym skoncentrować się na metodach sprawnego generowania manifestów obiektów Kubernetes w postaci plików YAML.

Podstawy

Ogólna postać polecenia

kubectl [command] [TYPE] [NAME] [flags]

TYPE: Określa typ zasobu . W typach zasobów nie jest rozróżniana wielkość liter i można określić formę pojedynczą, mnogą lub skróconą.

Możemy pytać się o to samo na kilka sposobów. Dla przykładu typ obiektu node (węzeł). Forma skrocóna no, forma pojedyńcza node, forma mnoga nodes.

kubectl get no
NAME           STATUS   ROLES    AGE   VERSION
controlplane   Ready    master   88s   v1.19.0
node01         Ready       59s   v1.19.0
kubectl get node
NAME           STATUS   ROLES    AGE    VERSION
controlplane   Ready    master   114s   v1.19.0
node01         Ready       85s    v1.19.0
kubectl get nodes
NAME           STATUS   ROLES    AGE     VERSION
controlplane   Ready    master   2m10s   v1.19.0
node01         Ready       101s    v1.19.0

NAME: Określa nazwę zasobu. W nazwach jest rozróżniana wielkość liter. W przypadku pominięcia nazwy wyświetlane są na przykład szczegóły dotyczące wszystkich zasobów kubectl get pods.

kubectl get node node01
NAME     STATUS   ROLES    AGE    VERSION
node01   Ready       4m6s   v1.19.0
kubectl get node Node01
Error from server (NotFound): nodes "Node01" not found

Warto o tym pamiętać (!)

flags: Określa opcjonalne flagi

Generatory

 

Na początku spróbujmy skorzystać z funkcjonalności dostępnych w narzędziu kubectl.  To jest główne polecenie typu cli (command line interface), z którym się trzeba zapoznać, powiem więcej, które przynajmniej musisz polubić

 

Zacznijmy od małego śledztwa

kubectl create --help

W odpowiedzi otrzymamy listę obiektów, które możemy utworzyć w sposób imperatywny

Create a resource from a file or from stdin.

JSON and YAML formats are accepted.

Examples:
# Create a pod using the data in pod.json.
kubectl create -f ./pod.json

# Create a pod based on the JSON passed into stdin.
cat pod.json | kubectl create -f -

# Edit the data in docker-registry.yaml in JSON then create the resource using the edited data.
kubectl create -f docker-registry.yaml --edit -o json

Available Commands:
clusterrole Create a ClusterRole.
clusterrolebinding Create a ClusterRoleBinding for a particular ClusterRole
configmap Create a configmap from a local file, directory or literal value
cronjob Create a cronjob with the specified name.
deployment Create a deployment with the specified name.
job Create a job with the specified name.
namespace Create a namespace with the specified name
poddisruptionbudget Create a pod disruption budget with the specified name.
priorityclass Create a priorityclass with the specified name.
quota Create a quota with the specified name.
role Create a role with single rule.
rolebinding Create a RoleBinding for a particular Role or ClusterRole
secret Create a secret using specified subcommand
service Create a service using specified subcommand.
serviceaccount Create a service account with the specified name

Odfiltruję, te obiekty, które nas interesują w zakresie certyfikacji

configmap Create a configmap from a local file, directory or literal value
cronjob Create a cronjob with the specified name.
deployment Create a deployment with the specified name.
job Create a job with the specified name.
namespace Create a namespace with the specified name
quota Create a quota with the specified name.
secret Create a secret using specified subcommand
service Create a service using specified subcommand.

Uważni zwrócą uwagę, iż brakuje możliwości utworzenia obiektu typu pod.  Z historycznych powodów zamiast polecenia kubectl create należy zastosować polecenie kubectl run.

Zobaczmy jak to wygląda:

kubectl run --help

W odpowiedzi otrzymujemy bogatą informacje, którą pozwoliłem sobie nieco skrócić (…) … (…)

Create and run a particular image in a pod.

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

# 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>

Options:
(...)
...
(...)

Usage:
kubectl run NAME --image=image [--env="key=value"] [--port=port] [--dry-run=server|client]
[--overrides=inline-json] [--command] -- [COMMAND] [args...] [options]

Lista możliwych parametrów jest dosyć długa, co ciekawe sporo z tych parametrów nie może być stosowanych w obiekcie kontrolującym pod jakim jest deployment. Na to też jest sposób.

Co z pozostałymi obiektami ?

Mamy dwie albo nawet trzy możliwości

  1. Skorzystanie z przykładowych manifestów, które znajdują się w oficjalnej dokumentacji
  2. Przekształcenie jednego typu obiektu w drugi (pokażę, to na kilku przykładach)
  3. Wykorzystanie generatora kubectl run do wklejenia tych cech obiektu, które nie są możliwe z poziomu kubectl create
  4. Użycie polecenia kube explain

 

Zadanie pierwsze

 

  1. Utwórz obiekt pod o nazwie web  w przestrzeni nazw alpha wykorzystujący obraz nginx:1.11.9-alpine, kontener ma pracować na portach 80 i 443. Uzupełnij klaster o brakującą przestrzeń nazw alpha.

 

Wykorzystajmy kubectl run:

kubectl run web --image=nginx:1.11.9-alpine --port 80  -o yaml --dry-run=client > 01.pod.web.yaml

 

W tym miejscu zaczynamy stosować nasz schemat postępowania:

  • 1. imperatywnie tworzymy plik manifestu
  • 2. poprawiamy zawartość tego pliku
  • 3. wdrażamy obiekt na klaster Kubernetes
  • 4. po weryfikacji stanu obiektu na klastrze, wracamy do punktu 2 jeśli jest taka potrzeba
  • 5. Zabieramy się za kolejne zadanie

Zobaczmy, co się znajduje w naszym pliku

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: web
  name: web
spec:
  containers:
  - image: nginx:1.11.9-alpine
    name: web
    ports:
    - containerPort: 80
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

 

Edytujemy plik

vim 01.pod.web.yaml
Dodajemy brakujący port 443.
Dodajemy brakującą przestrzeń nazwa (namespace).
Namespace zawsze jest zawarte w części metadata manifestu (do zapamiętania)
Przy okazji można pozbyć się linii creationTimestamp: null oraz  resources: {} i status: {}
Zasoby resources pozwalają definiować więzy wykorzystania procesora i pamięci naszego kontenera. Jeśli nie korzystamy z tych więzów  pole należy usunąć.
Pole status zawiera informacje o stanie obiektu na klastrze, w naszym przypadku powinien być pusty
Plik powinien wyglądać tak:
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: web
  name: web
  namespace: alpha
spec:
  containers:
  - image: nginx:1.11.9-alpine
    name: web
    ports:
    - containerPort: 80
    - containerPort: 443
  dnsPolicy: ClusterFirst
  restartPolicy: Always

Skąd wiadomo, że tak się dodaje kolejny port ?
Można szukać przykładów w obszernej dokumentacji Kubernetes, ale kubectl dostarcza nam polecenie explain

kubectl explain pod.spec.containers.ports
KIND:     Pod
VERSION:  v1

RESOURCE: ports <[]Object>
DESCRIPTION:
     List of ports to expose from the container. Exposing a port here gives the
     system additional information about the network connections a container
     uses, but is primarily informational. Not specifying a port here DOES NOT
     prevent that port from being exposed. Any port which is listening on the
     default "0.0.0.0" address inside a container will be accessible from the
     network. Cannot be updated.

     ContainerPort represents a network port in a single container.

FIELDS:
   containerPort         -required-
     Number of port to expose on the pod's IP address. This must be a valid port
     number, 0 < x > 65536.

Zgodnie z dokumentację mamy do czynienia z listą.

Bez utworzenia obiektu namespace o nazwie alpha nasze wdrożenie kończy się tak:

kubectl apply -f 01.pod.web.yaml 
Error from server (NotFound): error when creating "01.pod.web.yaml": namespaces "alpha" not found

Tu pojawia się pokusa, by wykorzystać imperatywnie utworzenie przestrzeni nazw za pomocą

kubectl create ns alpha

Polecam jednak utworzyć ten obiekt stosując nasz schemat opisany powyżej.

kubectl create ns alpha -o yaml --dry-run=client > 01.ns.alpha.yaml
cat 01.ns.alpha.yaml 
apiVersion: v1
kind: Namespace
metadata:
  creationTimestamp: null
  name: alpha
spec: {}
status: {}
kubectl apply -f 01.ns.alpha.yaml 
namespace/alpha created

 

Zadanie drugie

Wystawić za pomocą obiektu service o nazwie webservice  pod o nazwie web. Obiekt należy umieścić w przestrzeni nazw alpha. Typ serwisu to ClusterIP.
W przypadku obiektów service można skorzystać z polecenia kubectl expose.
kubectl expose pod/web --name=webservice -n alpha -o yaml --dry-run=client > 02.svc.webservice.yaml

Jak wygląda nasz plik ?

 cat 02.svc.webservice.yaml
 apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    run: web
  name: webservice
  namespace: alpha
spec:
  ports:
  - name: port-1
    port: 80
    protocol: TCP
    targetPort: 80
  - name: port-2
    port: 443
    protocol: TCP
    targetPort: 443
  selector:
    run: web
status:
  loadBalancer: {}
Koniec pliku od miejsca status: możemy usunąć.
Warto zwrócić uwagę na zgodność etykiet obiektu pod
metadata:
  labels:
    run: web
i selektora obiektu service

 

 selector:
   run: web
Jeżeli będziemy mieli niezgodność na poziomie pary klucz-wartość wystawiony serwis nie będzie poprawnie przykrywał poda lub grupy podów przez wspólną nazwą.
Na końcu pozostaje tylko wdrożenie tak przygotowanego manifestu na klaster.
kubectl apply -f 02.svc.webservice.yaml

Zadanie trzecie

 

Utwórz obiekt pod o nazwie postgresql wykorzystujący obraz postgres:12.4 i port 5432. Obiekt należy umieścić w przestrzeni nazw alpha.

 

kubectl run postgresql --image=postgres:12.4 --port 5432 -o yaml --dry-run=client > 03.pod.postgresql.yaml

Doprowadźmy nasz manifest do odpowiedniej postaci dopisując namespace. Warto też usunąć końcowy status: {}

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: postgresql
  name: postgresql
  namespace: alpha
spec:
  containers:
  - image: postgres:12.4
    name: postgresql
    ports:
    - containerPort: 5432
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
kubectl apply -f 03.pod.postgresql.yaml

Wnikliwy obserwator zauważy, iż obiekt pod nie jest w statusie Running

kubectl get pod postgresql -n alpha
NAME         READY   STATUS             RESTARTS   AGE
postgresql   0/1     CrashLoopBackOff   1          17s  

Spróbujmy dokonać prostej diagnozy naszego obiektu. W tym celu można skorzystać z polecenia kubectl describe, które zmienia postać obiektu na klastrze na bardziej zrozumiały opis ( ale to też jest kwestia dyskusyjna), bez formatu JSON czy YAML.

kubectl describe pod postgresql -n alpha
Name:         postgresql
Namespace:    alpha
Priority:     0
Node:         node01/172.17.0.58
Start Time:   Mon, 10 May 2021 18:17:34 +0000
Labels:       run=postgresql
Annotations:  
Status:       Running
IP:           10.244.1.6
IPs:
  IP:  10.244.1.6
Containers:
  postgresql:
    Container ID:   docker://893dc06e02cdad8cf6998203b08a911a4e46e37919579f213c8422d8a9ee2e61
    Image:          postgres:12.4
    Image ID:       docker-pullable://postgres@sha256:a1e04460fdd3c338d6b65a2ab66b5aa2748eb18da3e55bcdc9ef17831ed3ad46
    Port:           5432/TCP
    Host Port:      0/TCP
    State:          Waiting
      Reason:       CrashLoopBackOff

Last State: Terminated Reason: Error Exit Code: 1

      Started:      Mon, 10 May 2021 18:20:49 +0000
      Finished:     Mon, 10 May 2021 18:20:49 +0000
    Ready:          False
    Restart Count:  5
    Environment:    
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-57qw5 (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             False 
  ContainersReady   False 
  PodScheduled      True 
Volumes:
  default-token-57qw5:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-57qw5
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  
Tolerations:     node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason     Age                     From               Message
  ----     ------     ----                    ----               -------
  Normal   Scheduled  3m55s                   default-scheduler  Successfully assigned alpha/postgresql to node01
  Normal   Pulling    3m54s                   kubelet, node01    Pulling image "postgres:12.4"
  Normal   Pulled     3m53s                   kubelet, node01    Successfully pulled image "postgres:12.4" in 1.428701345s
  Normal   Started    3m4s (x4 over 3m53s)    kubelet, node01    Started container postgresql
  Warning  BackOff    2m26s (x10 over 3m51s)  kubelet, node01    Back-off restarting failed container
  Normal   Created    2m12s (x5 over 3m53s)   kubelet, node01    Created container postgresql
  Normal   Pulled     2m12s (x4 over 3m52s)   kubelet, node01    Container image "postgres:12.4" already present on machine

Widać, że mamy w manifeście poprawny adres obrazu z repozytorium (Successfully pulled image “postgres:12.4”) , ale z jakiegoś powolu zwrócony jest Exit Code o wartości 1, a obiekt jest restartowany. gdyż restartPolicy ustawione jest na wartość Always (taka jest domyślna wartość dla tej cechy)

Co możemy z tym dalej zrobić ?
Spróbujmy obejrzeć logi kontenera w obiekcie pod, tym razem korzystając z polecenia kubectl logs.

kubectl logs postgresql -n alpha
Error: Database is uninitialized and superuser password is not specified.
       You must specify POSTGRES_PASSWORD to a non-empty value for the
       superuser. For example, "-e POSTGRES_PASSWORD=password" on "docker run".

       You may also use "POSTGRES_HOST_AUTH_METHOD=trust" to allow all
       connections without a password. This is *not* recommended.

       See PostgreSQL documentation about "trust":
       https://www.postgresql.org/docs/current/auth-trust.html

I teraz jest już wszystko jasne. Nasz kontener z bazą postgresql wymaga wstrzyknięcia zmiennych środowiskowych. Tym zajmiemy się w kolejnym zadaniu.
Przy okazji zrobiliśmy mały wstęp do zadań z zakresu naprawy obiektów na klastrze. Zostawmy ten obiekt tak jak jest. Został przygotowany zgodnie ze warunkami zadania.

Zadanie czwarte

Utwórz obiekt pod o nazwie postgresql-env wykorzystujący obraz postgres:12.4 i port 5432. Dodaj obsługę trzech zmiennych środowiskowych. Obiekt należy umieścić w przestrzeni nazw alpha.
Lista zmiennych środowiskowych
POSTGRES_DB: postgresdb
POSTGRES_USER: postgresadmin
POSTGRES_PASSWORD: admin123

Spróbujmy wykorzystać pomoc dostępną w kubectl i odfiltrować jego bogatą treść:

kubectl run --help| grep -i env
  # 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"
      --env=[]: Environment variables to set in the container.

Mamy przykładowe wywołanie, które możemy wykorzystać.
Wystarczy do linii poleceń dopisać wielokrotnie –env=”KEY=VALUE”

kubectl run postgresql-env --image=postgres:12.4 --port 5432 --env="POSTGRES_DB=postgresdb" 
  --env="POSTGRES_USER=postgresadmin" --env="POSTGRES_PASSWORD=admin123" 
  -o yaml --dry-run=client  > 04.pod.postgresql-env.yaml

Zobaczmy jak wygląda nasz plik

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: postgresql-env
  name: postgresql-env
spec:
  containers:
  - env:
    - name: POSTGRES_DB
      value: postgresdb
    - name: POSTGRES_USER
      value: postgresadmin
    - name: POSTGRES_PASSWORD
      value: admin123
    image: postgres:12.4
    name: postgresql-env
    ports:
    - containerPort: 5432
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

 

Doprowadźmy nasz manifest do odpowiedniej postaci dopisując namespace i usuwając resources: {}, status: {}. Można też pozbyć się rownież linii creationTimestamp: null w sekcji metadata. Starajmy się w plikach trzymać jedynie niezbędne informacje.

Wdrażamy obiekt na klaster

kubectl apply -f 04.pod.postgresql-env.yaml

Dla zainteresowanych kontrolą zasobów kontenera proponuję wykonać

kubectl run --help |grep limit
kubectl run --help |grep request
kubectl run test --image=nginx --port 80   -o yaml --dry-run=client --limits='cpu=500m,memory=512Mi' --requests='cpu=200m,memory=256Mi'
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: test
  name: test
spec:
  containers:
  - image: nginx
    name: test
    ports:
    - containerPort: 80
    resources:
      limits:
        cpu: 500m
        memory: 512Mi
      requests:
        cpu: 200m
        memory: 256Mi
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

Na razie zakończymy zabawę z obiektami pod (w tej części)  i spróbujemy przenieść się na poziom wyżej. Czyli będziemy tworzyć jeden z tych obiektów, które kontrolują obiekty pod. Obiektem tym jest deployment

 

Zadanie piąte

 

Utwórz obiekt deployment o nazwie nginx-deployment, który jest oparty o obraz nginx:1.18.0 z wystawionym portem 80. Umieść go w przestrzeni nazw alpha.

kubectl create deployment nginx-deployment --image=nginx:1.18.0 -n alpha -o yaml --dry-run=client > 05.deployment.nginx-deployment.yaml
vim 05.deployment.nginx-deployment.yaml

Ponieważ create deployment nie pozwala na dodanie z marszu numeru portu, należy uzupełnić go ręcznie.

Czy musimy w ten sposób działać ? Niekoniecznie.

Można sprobować wygenerować manifest samego obiektu typu pod z wygenerowanym portem (tak jak w zadaniu pierwszym) i potem wkleić jego zawartość do obiektu deployment w miejscu spec.template.spec.containers, gdzie kropką odzieliłem kolejne zagnieżdzenie.

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx-deployment
  name: nginx-deployment
  namespace: alpha
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-deployment
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx-deployment
    spec:
      containers:
      - image: nginx:1.18.0
        name: nginx
        ports:
        - containerPort: 80
        resources: {}

Można też skorzystać z wbudowanej pomocy i sprawdzić jak ma wyglądać nasza składnia

kubectl explain deployment.spec.template.spec.containers --recursive

Skrócona odpowiedź (…)

KIND:     Deployment
VERSION:  apps/v1

RESOURCE: containers <[]Object>

DESCRIPTION:
     List of containers belonging to the pod. Containers cannot currently be
     added or removed. There must be at least one container in a Pod. Cannot be
     updated.

     A single application container that you want to run within a pod.

FIELDS:
(...)

Wdrażamy nasz obiekt na klaster

kubectl apply -f 05.deployment.nginx-deployment.yaml -n alpha --record
I przechodzimy do kolejnego wyzwania

Zadanie szóste

Wystaw za pomocą obiektu service o nazwie nginx-service obiekt nginx-deployment wykorzystując typ ClusterIP. Obiekt należy umieścić w przestrzeni nazw alpha.
Wystawienie serwisu na podstawie istniejącego już na klastrze obiektu znacznie ułatwia polecenie kubectl expose.
kubectl expose deploy nginx-deployment -n alpha -o yaml --port 80 --name=nginx-service -dry-run=client > 06.service.nginx-service.yaml

Tak wygląda nasz manifest

apiVersion: v1
kind: Service
metadata:  
  creationTimestamp: null  
  labels:    
    app: nginx-deployment  
  name: nginx-service  
  namespace: alpha
spec:  
  ports:  
  - port: 80    
    protocol: TCP    
    targetPort: 80  
  selector:    
    app: nginx-deployment
status:  
  loadBalancer: {}

Po poprawieniu manifestu wdrażamy go na klaster.
Zawsze warto w przypadku środowiska egzaminacyjunego pamiętać o dodaniu dla obiektów wdrażanych w przestrzemni nazw (pod, deployment,service i inne) nazwy tej przestrzeni. Pozwala nam to na ominięcie w linii poleceeń
-n nazwa_przestrzeni Jeśli natomiast użyjemy innej nazwy przestrzeni w opcjach polecenia kubectl, a inna będzie w deklaracji manifestu wdrożenie nie uda się. W ten sposób zabezpieczamy się przed pomyłkami.

kubectl apply -f 06.service.nginx-service.yaml -n alpha

Zadanie siódme

Zmień obraz obiektu deployment o nazwie nginx-deployment. Nowy obrazem ma być nginx:1.19.2. Zarejestruj na klastrze tę zmianę. Obiekty są umieszczone w przestrzeni nazw alpha. Wycofaj tę zmianę rejestrująć ją na klastrze. Zwiększ liczbę replik do pięciu (5).
Do zmiamy obrazu mamny dedykowane polecenie kubectl set image, gdzie podajemy nazwe obiektu deployment, nowy obraz i nazwę kontenera, którego dotyczy.
Łatwo rozpocząć pracę wykorzystując kubectl set image –help
kubectl set image deploy nginx-deployment -n alpha nginx=nginx:1.19.2 -o yaml --dry-run=client > 07.deploy.nginx-deployment.yaml

W tym momencie mamy juz przygotowany manifest obiektu deployment z nowym obrazem.

Pozostaje nam tylko wdrożenie go na klaster, ale należy pamietać o rejestracji tej zmiany. Do tego służy flaga –record

kubectl apply -f 07.deploy.nginx-deployment.yaml -n alpha --record

Zobaczmy jak wygląda historia

kubectl rollout history deploy/nginx-deployment -n alpha

Cofnijmy ostatnią zmianę

kubectl rollout undo deployment nginx-deployment -n alpha

Ponownie możemy zobaczyć historię obiekty deployment

kubectl rollout history deploy/nginx-deployment -n alpha

Na końcu sprobujmy wyskalować obiekt deployment zwiększając listę replik do pięciu. Tu mamy kolejne dedykowane polecenie kubectl scale. Warto je zapamiętać, a przykłady łatwo znaleźć za pomocą kubectl scale –help.

kubectl scale deploy nginx-deployment -n alpha --replicas=5

To ostatnie jest zrobione w trybie imperatywnym, proponuję też sprobować zmienić odpowiedni manifest yaml (pole replicas: x) i wdrożyc w trybie deklaratywnym. Nigdy za mało praktyki, przekonacie sie o tym podczas kontroli czasu na egzaminie.

Jakie obiekty tworzy na klastrze wdrożenie typu deployment? Oprócz kilku replik obiektu pod, powstanie obiekt replicaset, Nazwa tego obiektu to nazwa deploymentname_hashreplicaset, a nazwy obiektów pod to deploymentname_hashreplicaset_hashpod. Po pewnej wprawie łatwo będzie się można zorientować, który obiekt jest rodzicem, a który dzieckiem.

How to K8s: Pods, ReplicaSets, and Deployments

Zadanie ósme

Utwórz obiekt typu replicaset o nazwie replicaset-nginx zawierający obraz redis:alpine. Liczba instancji powinna wynosić cztery (4). Obiekt należy umieścić w przestrzeni nazw alpha. To zadanie można zrobić na dwa sposoby.

Pierwszy to sięgnąć do dokumentacji Kubernetes

https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/ i znaleźć tam gotowy przykład. Wkleić kod takiego manifestu, obrobić w edytorze tekstu i ogłosić sukces.

Drugi sposób to spreparować obiekt replicaset z obiektu deployment. Spróbujmy to zrobić

Na początku tworzymy plik o nazwie zgodnej z przyjęta konwencją.

kubectl create deployment replicaset-nginx --image=redis:alpine -n alpha -o yaml --dry-run=client > 08.replicaset.replicaset-nginx.yaml

Zobaczmy jak wygląda jego zawartość

cat 08.replicaset.replicaset-nginx.yaml
  
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: replicaset-nginx
  name: replicaset-nginx
  namespace: alpha
spec:
  replicas: 1
  selector:
    matchLabels:
      app: replicaset-nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: replicaset-nginx
    spec:
      containers:
      - image: redis:alpine
        name: redis
        resources: {}
status: {}

To co musimy zrobić to zmienić typ obiektu z kind: Deployment na kind: ReplicaSet
Sprawdzmy jak jaka powinna być wersja

kubectl explain replicaset
KIND:     ReplicaSet
VERSION:  apps/v1

usuńmy strategy{} i ustawmy liczbę replik na cztery
Nasz plik powinien wyglądać tak

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  creationTimestamp: null
  labels:
    app: replicaset-nginx
  name: replicaset-nginx
  namespace: alpha
spec:
  replicas: 4
  selector:
    matchLabels:
      app: replicaset-nginx
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: replicaset-nginx
    spec:
      containers:
      - image: redis:alpine
        name: redis
        resources: {}

Obiekt taki można następnie wdrożyć na klaster

kubectl apply -f 08.replicaset.replicaset-nginx.yaml
kubectl get all -n alpha
NAME                         READY   STATUS    RESTARTS   
AGEpod/replicaset-nginx-6ddrz   1/1     Running   0          98
spod/replicaset-nginx-95krm   1/1     Running   0          98s
pod/replicaset-nginx-chs8b   1/1     Running   0          98s
pod/replicaset-nginx-rqdf2   1/1     Running   0          98s

NAME                               DESIRED   CURRENT   READY   AGE
replicaset.apps/replicaset-nginx   4         4         4       98s

Strategia jest jest cechą obiektu deployment i pozwala na łatwe wdrażanie  kolejnych wersji obrazu. W przypadku obiektu replicaset jest to wartość niemutowalna i wymaga usunięcia obiektu z klastra i utworzenia raz jeszcze. W praktyce samodzielne tworzenie tego typu zasobów nie jest popularne.

 

Zadanie dziewiąte

 

Utwórz obiekt typu daemonset o nazwie daemonset-filebeat zawierający obraz filebat. Obiekt należy umieścić w przestrzeni nazw alpha.
W aktualnej wersji (1.20) nie ma możliwości utworzenia obiektu tego typu za pomocą kubectl create daemonset. Wykorzystajmy znany nam obiekt deployment.

kubectl create deployment daemonset-filebeat --image=filebeat -n alpha -o yaml --dry-run=client > 09.daemonset.daemonset-filebeat.yaml

Zobaczmy jak wygląda nasz manifest

cat 09.daemonset.daemonset-filebeat.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: daemonset-filebeat
  name: daemonset-filebeat
  namespace: alpha
spec:
  replicas: 1
  selector:
    matchLabels:
      app: daemonset-filebeat
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: daemonset-filebeat
    spec:
      containers:
      - image: filebeat
        name: filebeat
        resources: {}
status: {}

Sprawdzmy wersje API dla obiektu daemonset. Wersja jest ta sama i nie musimy jej zmieniać, ale warto to sprawdzić, nie uczmy sie na pamięć.

kubectl explain daemonset
KIND: DaemonSet
VERSION: apps/v1

Po drobnych zmianach nasz plik powinien wyglądać mniej więcej tak.

apiVersion: apps/v1
kind: DaemonSet
metadata:
  labels:
    app: daemonset-filebeat
  name: daemonset-filebeat
  namespace: alpha
spec:
  selector:
    matchLabels:
      app: daemonset-filebeat
  template:
    metadata:
      labels:
        app: daemonset-filebeat
    spec:
      containers:
      - image: filebeat
        name: filebeat
        resources: {}

Jakie to zmiany ? Najważniejsza to usunięcie liczby replik z manifestu. Daemonset to typu obiektu, który pozwala na wdrożenie po jednej instancji obiektu pod per węzeł (node). Jest z reguły stosowany do instalacji na klastrze kontenerów technicznych. Można też ograniczyć liczbę węzłów, na których ma się pojawić korzystająć na przykład z selektorów dla węzła.

Wdrażamy nasz obiekt na klaster i mamy poczucie dobrze zrobionego zadania.

 

Dotarliśmy do końca dzisiejszyej audycji i powinniśmy mieć wrażenie, że to jest tylko zadrapanie powierzchni z bogatego zakresu zagadnień egzaminacyjnych.

Dla tych, którzy chcą sobie poćwiczyć dodatkowo proponuję poniższą listę zadań.

https://dev.to/subodev/50-questions-for-ckad-and-cka-exam-3bjm

 

W poprzedniej części:

 

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

 

W następnych częściach

Certified Kubernetes Administrator (CKA) krok po kroku &#8211; część 3

 

 

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.