[CKAD] Kubernetes Certificate Application Developer(CKAD) with Tests 학습노트(1/)

개요 : CKAD

쿠버네티스 학습, 자격증 취득 등. Kubernetes Certificate Application Developer with Tests 학습

Pod

최소 서비스 단위. 단일 혹은 복수 컨테이너로 구성됨. 예를 들어.

  • 단일 : 지 혼자서 서비스 가능한 컨테이너 하나를 배포함
  • 멀티 : 좀 이상하지만 프론트(nginx)/백엔드(tomcat)를 같이 배포할 수 있음.

pod에 배포한 것만으로는 서비스 할 수 없다. 외부에 서비스 접근자가 노출되지 않았기 때문에... 이 부분은 네트워크에 대한 학습이 추가적으로 필요함

yaml 생성

모든 자원은 yaml로 정의할 수 있다. 쿠버네티스 설정에 필요한 기본 yaml 설정은 다음과 같은 부분을 포함한다.

기본 형식

yaml파일은 다음과 같은 내용을 포함하고 있어야 한다

apiVerion:
kind:
metadata:
spec:

apiVersion

OpenAPI 버전. value=문자열하나. kube-apiserver의 버전..이라고하기는 좀 그렇고... 프로토콜 버전을 먼저 정의해야 하는 것과 비슷한 개념으로 이해하면 좋겠다. pod은 v1부터 지정되어 설정되어 있었으므로 v1만 기입하면 되지만 Repa 등을 설정하려면 apps/v1 등 해당 기능을 지원하는 api 버전을 정확히 명기하여야 한다 https://kubernetes.io/ko/docs/concepts/overview/kubernetes-api/

apiVersion: v1

kind

yaml에서 정의하는 개체의 유형. value=문자열하나.

kind: Pod

metadata

해당 자원의 메타 데이터. 이름, 레이블 등의 정보를 가진다. 단일 정보가 아니므로 dictionary로 정의한다.

metadata:
name: myapp-pod
labels:
app: myapp
type: front-end

spec

자원의 실제 사양을 정의하는 부분이다.

spec:
containers:
- name: nginx-container
image: nginx
ports:
- containerPort: 80
containers

Pod내 컨테이너에 대한 정의. 복수의 컨테이너를 담을 수 있기 때문에 리스트로 정의한다. 개별 컨테이너는 아래와 같은 정의를 가진다.

  • name : 이름
  • image : 컨테이너 이미지
  • ports : 포트.
    • containerPort : 해당 컨테이너가 통신을 위해 사용하는 포트. 기본적으로 파드 내의 컨테이너끼리는 로컬 아이피가 부여되어 별다는 조치(ex. nat)없이 서로 통신이 가능한데, 이를 위해 컨테이너가 외부로 공개할 포트(ex. http)를 정의할 수 있다. 이때 containerPort를 사용한다.

yaml를 정의하였으면 실제 pod를 생성하여야 한다.
pod-definition.yaml라는 yaml을 생성하였으면 아래 방법으로 생성하자.

kubectl create -f pod-definition.yaml

pod를 생성하였으면 다음 명령을 이용하여 pod을 확인할 수 있다.

kubectl get pods // 전체 pod 목록
kubectl describe pod myapp-pod // 개별 pod에 대한 디테일

pod실행으로부터 yaml파일 땡기기

yaml없이 컨테이너 이미지 이름과 pod의 이름만 이용하여 pod을 생성할 수 있다. 예를 들어 redis이미지를 redis라는 pod으로 실행하고 싶다면,

kubectl run redis --image=redis

로 실행할 수 있다. 이때 pod를 생성하지 않고, 해당 pod를 정의하는 yaml을 보고 싶다면 --dry-run과 -o옵션을 사용하면 된다.

% kubectl run redis --image=redis --dry-run -o yaml
W0402 16:57:56.759491 62580 helpers.go:663] --dry-run is deprecated and can be replaced with --dry-run=client.
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: redis
name: redis
spec:
containers:
- image: redis
name: redis
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}

실행 중인 pod의 설정을 yaml 파일로 뽑기

실행 중인 pod를 yaml로 뽑고 싶으면 아래와 같이 뽑을 수 있다. 실행 중인 pod를 수정하려면 yaml뽑기, yaml 수정, apply 순서로 진행하면 된다.

kubectl get pod <pod-name> -o yaml > output-file-name.yaml

혹은 아래 명령으로 바로 수정할 수 있다.

kubectl edit pod <pod-name>

복제(replication)

replication controller와 replicaset 두가지로 정의한다.

https://medium.com/avmconsulting-blog/replication-controller-replica-sets-in-kubernetes-820f3cec7170

replication controller(or replicaset)

pod 복제에 대한 정의를 하며, pod에 대한 scaleout을 처리하기 위한 정의한다.

apiVersion: v1
kind: ReplicationController
metadata:
name: myapp-replicationcontroller
spec:
template:
metadata:
name: myapp-pod
labels:
app: myapp
type: frontend
spec:
containers:
- name: nginx-container
image: nginx
replicas: 3

replicatset

replication controller의

apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myapp-replicaset
labels:
app: myapp
type: front-end
spec:
template:
metadata:
name: myapp-pod
labels:
app: myapp
type: front-end
spec:
containers:
- name: nginx-container
image: nginx
replicas: 3
selector:
matchLabels:
tier: front-end

label과 selector

왜 둘다 필요할까? replicaset레벨에서 pod를 땡겨올 수 있게 하기 위함이다. 예를 들어, replicaset을 이용하여 복수의 node에서 수행 중인 pod이 있다. 전체 pod이 잘 동작하고 있음을 확인하려면 어떻게 해야할까? replicaset의 matchlabels를 이용하여 해당 레이블을 가진 pod를 뽑아낼 수 있다. 이를 위하여 replicaset의 template(pod)에 있는 label이 selector의 matchlabels를 포함해야 함. pod labels > replicaset selector matchlabels

update replicaset and pod

replicaset을 수정하더라도 replicaset이 실행시킨 pod이 업데이트되진 않는다. 에를 들어 template의 이미지 경로를 수정하더라도, 생성딘 pod의 이미지가 재생성되지는 않는다. replicaset을 수정하고, 수행 중인 pod을 전부 날리면 복제수량만큼 저절로 실행시켜 줌.

명령

replicaset 수정 등의 커맨드

kubectl edit replicaset <replicaset-name >
kubectl scale replicaset <replicaset-name > --replicas
kubectl explain replicaset //설명을 가져올 수 있다.

Deployment

Deployment는 앱 배포에 대한 설정을 정의한다. replicaset과 유사하게 pod와 replicas에 대한 정의를 포함한다. 그래서 deployment를 만들면, deployment, replicaset, pod 세가지가 정의된다. 함께 정의된 replicaset과 pod는 생명 주기를 함께 가져가므로 삭제할 수 있다.

deplyment와 replicaset의 차이점은...?

apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
namespace: product
labels:
app: myapp
type: front-end
spec:
template:
metadata:
name: myapp-pod
namespace: product
labels:
app: myapp
type: front-end
spec:
containers:
- name: nginx-container
image: nginx
replicas: 3
selector:
matchLabels:
type: front-end
kubectl get deployments
kubectl get replicaset
kubectl get pods
kubectl get all

yaml을 작성하지 않고 간단하게 명령 줄로 생성할 수도 있다.

kubectl create deployment --help

를 입력하면 deployment를 생성할 수 있는 커맨드가 나온다.

kubectl create deployment [deploymentname] --image=[image] --replicas=[numberOfReplica]

ex. "httpd:2.4-alpine"이미지로 "httpd-frontend"라는 deployment를 3개의 replica로 생성하는 명령은 다음과 같다.

kubectl create deployment httpd-frontend --image=httpd:2.4-alpine --replicas=3

namespace

구분자. 프로그래밍 언어의 바로 그 namespace와 동일하다.

기본 생성 네임스페이스

쿠버네티스에서 기본 생성하는 네임스페이스는 다음과 같다.

  • default : 네임스페이스를 지정하지 않고 작업을 하면 쌓이는 곳
  • kube-system : 시스템 영역(network, dns 등)의 네임스페이스
  • kube-public : 사용자가 사용할 수 있어야 할 자원이 생성되는 곳? 모르겠

도메인네임으로 응용

pod과 namespace 등의 요소를 추가(create)하면 쿠버네티스 내부 DNS에 레코드를 추가하게 된다. 단일 요소 뿐만 아니라 여러 요소를 조합하여 엔드포인트를 구성할 수 있다.

예를 들어 db-serivce.dev.svc.cluster.local 라는 엔드포인트는 아래와 같이 해석할 수 있다. cluster.local라는 클러스터 안에 서비스가 있는데(svc, 지시자) dev라는 네임스페이스 db-service라는 이름이다.

네임스페이스 생성

yaml로 정의하고 생성하거나 kubectl로 생성할 수 있다.

apiVersion: v1
kind: Namespace
metadata:
name: dev
kubectl create namsapce dev

네임스페이스 설정

다양한 기능에서 --namespace 옵션을 이용하여 네임 스페이스를 설정할 수 있다. 네임스페이스를 특정하지 않으면 현재 컨텍스트 기준의 네임스페이스의 자원에 대한 명령을 수행하며, pod

$ kubectl get pods --namespace=default
$ kubectl get pods --all-namespaces

현재 컨텍스트의 네임스페이스 변경 방법은 다음과 같다. 컨텍스트를 현재 컨텍스트로 변경하며 네임스페이스만 변경하면 된다.

$ kubectl config set-context $(kubectl config get-currentcontext) --namepsace=[namepsacename]

ResourceQuota

자원 한계 설정을 위한 정의 dev 네임스페이스에 대한 자원 제한 정의는 아래와 같이 할 수 있다.

apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: dev
spec:
hard:
pods: "10"
requests.cpu: "4"
requests.memory: 5Gi
limits.cpu: "10"
limits.memory: 10Gi

시험팁

yaml 생성 옵션 적극 사용

  • 3시간에서 2시간으로 시험 시간이 줄어서 kubectl로 바로 처리할 수 있는 명령들(ex. pod 실행시 kubectl run ...등)을 사용하는 것이 의미있게 시간을 줄일 수 있다. yaml파일 작성을 하지 않고 처리할 수 있는 문제들은 그렇게 처리하자.

그럼에도 불구하고 작성해야 하는 경우 --dry-run=client -o yaml > template.yaml를 이용하여 기본 yaml을 수정하는 방향으로 작업을 수행하자.

예를 들어

$ kubectl run nginx --image=nginx --dry-run=client -o yaml > nginx-pod.yaml

과 같이 템플릿을 쭉쭉 뽑아쓰자.

Deployment

Deployment도 이렇게 그릴 수 있다.

$ kubectl create deployment --image=nginx nginx --dry-run -o yaml
or
$ kubectl create deployment nginx --image=nginx --replicas=4

스케일도 된다.

$ kubectl scale deployment nginx --replicas=4

Service

pod(redis)에서 ClusterIP로 서비스도 뽑을 수 있다.

$ kubectl expose pod redis --port=6379 --name redis-service --dry-run=client -o yaml
kubectl create service clusterip redis --tcp=6379:6379 --dry-run=client -o yaml

이 경우 selector를 뽑아쓰는 것은 아니고 label의 app=redis를 뽑아서 추정한다. 그리고 옵션으로 selectors를 설정하는 것은 불가능하다.

당연히 포트를 지정하여 뽑아서 NodePort로도 뽑을 수 있다.

kubectl expose pod nginx --port=80 --name nginx-service --type=NodePort --dry-run=client -o yaml

같은 노드포트지만 NodePort 서비스를 생성한다고 명확하게 설정할 수 있다.

kubectl create service nodeport nginx --tcp=80:80 --node-port=30080 --dry-run=client -o yaml

예제 테스트

kubectl run nginx-pod --image:alpine
kubectl run redis --image:alpine --labels="tier=db"
kubectl expose pod redis --port=6379 --name=redis-service
kubectl create deployment webapp --image=nginx --replicas=3
kubectl create pod custom-nginx --image=nginx --port=
kubectl expose pod redis --im=gs=6389 --port=6389
kubectl create namespace dev
kubectl cratte create deployku
grep -A 4 "abel" 4줄 더 땡겨오기

Node Selectors

파드가 어느 노드에 배치될지 지정한다. 노드셀렉터라는 표현을 이용하여 배치될 노드를 지정하는데, 노드셀렉터의 값과 노드의 레이블(키밸류)이 일치하면 해당 노드로 배치한다. 파드와 노드는 아래와 같이 표현할 수 있다.

  1. 파드에 노드셀렉터 설정
spec:
containers:
nodeSelector:
size: Large
  1. 노드에 레이블 설정
kubectl label <node-name> <label-key>=<label-value>
kubectl label mynode-1 size=Large

Node Affinity

노드셀렉터는 파드의 배치에 노드 레이블과의 일치만을 판단한다. 하지만 다양한 다른 경우(해당 레이블이 설정이 되어 있다거나..)하는 경우가 있다. 그럴때는 NodeAffinity를 사용하면 된다. 위 셀렉터와 같이 레이블(size: Large)인 곳에만 스케쥴링하고 싶을 경우 아래와 같이 정의하면 된다.

pod.yaml

spec:
containers:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: size
operator: In
values:
- Large

nodeAffinity타입은 아래와 같이 설정할 수 있다.

  • requiredDuringSchedulingIgnoreDuringExecution -> requiredDuringScheduling : 스케줄링할 때 nodeAffinity에 정의한 노드가 있어야하고, 그곳에 스케줄링함 -> IgnoreDuringExecution : 실행 중인 파드를 중지하지는 않음
  • preferredDuringSchedulingIgnoreDuringExecution -> preferredDuringScheduling : 스케줄링할 때 nodeAffinity에 정의한 노드를 권장하고, 정의한 노드가 풀이면 다른 노드에 배치함 -> IgnoreDuringExecution : 실행 중인 파드를 중지하지는 않음 -> RequiredDuringExecution : 실행 중인 파드도 다른 곳으로 배치함를 중지하지는 않음

Multi-Container Pods

하나의 파드에 여러개의 컨테이너를 두는 구조 크게 세가지 패턴이 있다

  • sidecar : 주 기능과 기능을 보조하는 완전히 분리된 기능 ex) 웹서버와 로깅 에이전트
  • adapter : 어댑터 기능의 컨테이너 ex) 에이전트가 쏜 로그를 로그서버가 받도록 변환
  • ambassader : ex) 개발, 테스트, 운영 디비가 있을 때 백엔드 컨테이너는 항상 ambassader쪽으로 던지고 엠베세더가 설정에 따라 개발, 테스트, 운영을 결정

참조

[1] 강의링크 :
https://www.udemy.com/course/certified-kubernetes-application-developer

[2] Certified Kubernetes Application Developer: https://www.cncf.io/certification/ckad/

[3] Candidate Handbook: https://www.cncf.io/certification/candidate-handbook

[4] Exam Tips: https://docs.linuxfoundation.org/tc-docs/certification/tips-cka-and-ckad

[5] "Lecture Request" and "CKAD": https://github.com/mmumshad/kubernetes-the-hard-way

[5] kubectl conventions : https://kubernetes.io/docs/reference/kubectl/conventions/

[5] https://www.linkedin.com/pulse/my-ckad-exam-experience-atharva-chauthaiwale/

[5] https://medium.com/@harioverhere/ckad-certified-kubernetes-application-developer-my-journey-3afb0901014

[5] https://github.com/lucassha/CKAD-resources