반응형

K8s에는 각 컴포넌트마다 다른 버전을 가지고 있다.

그런데, kube-apiserver가 가장 상위 버전이고, 다른 것들은 kube-apiserver보다 높은 버전을 가질 수 없다. (동일은 가능)

단, kubectl의 경우 상위버전, 동일버전, 하위버전 모두 가질 수 있다.

 

그리고, k8s는 하위 3개의 minor버전까지만 support하기 때문에, v1.13이 배포되었다는 기준으로 

v.11까지만 upgrade할 수 있다.

그리고, upgrade를 할 땐 v1.10 -> v1.13으로 바로 가지말고, minor버전을 하나씩 올리라고 권고하고 있다.

ex. v1.10 -> v1.11 -> v1.12 -> v1.13

 

그럼, upgrade는 어떻게 진행할까?

GCP등 ServiceProvider에 올린 경우 버튼 몇번으로 진행할 수 있고,

이 외는 kubeadm을 통해 진행할 수 있다.

 

upgrade 절차는 Master Node를 먼저 진행하고, 그 이후엔 3가지 전략이 있다.

1) 전체Node 삭제 후 전체 Node 생성: service impacted

2) 하나의 Node씩 Upgrade: Impact 없음

 

3) 최신 버전인 new Node를 하나 생성한 후, 기존 node를 하나씩 upgrade하고, 기존 node중 하나 삭제

 (3은 cloud 환경에 있다면 가장 쉽고 편한 방법)

 

 

실제 upgrade command는

1. kubeadm upgrade plan을 통해 available한 pkg version을 조회한다.

# kubeadm upgrade plan

 

1 apt-get을 통해 pkg를 땡겨오고 (available한 건 v1.13.4였지만, 버전이 v1.11.3이었으므로 하나씩 올린다)

2. kubeadm upgrade apply v1.12.0을 통해 pkg를 upgrade한다.

3. version을 조회하면 아직 v1.11.3이다.

4. 이유는, 해당 버전은 kubelet을 기준으로 보이는데, kubelet이 upgrade되지 않았기 때문이다.

   그래서 kubelet을 마지막으로 upgrade한다.

# apt get upgrade -y kubeadm=1.12.0-00
# kubeadm upgrade apply v1.12.0
# kubectl get nodes
# apt-get upgrade -y kubelet=1.12.0-00
# systemctl restart kubelet

 

 

각 Node들을 upgrade할 땐, 이전 포스팅에서 다루었던 drain, uncordon 명령을 통해

https://countrymouse.tistory.com/entry/cka-6-1

node에 있는 pod가 미리 다른 pod로 옮겨갈 수 있게 설정해준다.

 

 

출처: Udemy 사이트의 Certified Kubernetes Administrator (CKA) with Practice Tests 강의

반응형
반응형

pod를 upgrade할 때, pod들은 자동으로 down 되었다가 up이 된다.

그런데 이때, default 타이머가 5분으로, k8s는 5분동안 pod가 살아나지 않으면 죽었다고 판단 후 다른 node에 pod를 생성한다.

그럼, Node가 down될 경우는 어떨까?

 

(지금은 아무것도 없는) 2번째 Node에 파랑, 초록 pod들이 있었다.

그런데, Node 2가 down되면, replica에 속한 파란 노드의 경우 다른 node에 생성될 수 있다.

그런데, 초록이는 혼자 있던 pod(=daemon set)이고 replicaset에 속하지 않았기 때문에 다른 node로 생성될 수 없다.

 

그런데, 그림 상에는 왜 초록색pod가 4번째 pod에 있냐면,

# kubectl drain node-2

위 drain command를 통해, Node-2에 속한 pod들을 다른 Node로 이동시킨 것이다.

* drain: 해당Node에서 실행 중인 pod들을 다른 곳으로 이동시키는 명령어

 

직접 수행해보자.

$ kubectl get nodes
NAME                 STATUS    ROLES     AGE       VERSION
docker-for-desktop   Ready     master    4d        v1.10.3


$ kubectl drain docker-for-desktopnode
"docker-for-desktop" cordonederror: unable to drain node "docker-for-desktop", aborting command...There are pending nodes to be drained:docker-for-desktoperror: DaemonSet-managed pods (use --ignore-daemonsets to ignore): kube-proxy-4s52d
우선 kubectl drain을 해보면 다음처럼 에러가 납니다. 데몬셋으로 떠 있는 포드가 존재하기 때문입니다.
// DaemonSet의 경우 drain을 사용할 경우 반드시 아래 옵션을 줘야한다.


** --ignore-daemonsets=true 옵션을 주고 다시 실행하면 정상적으로 실행되는걸 확인할 수 있습니다.
$ kubectl drain docker-for-desktop --ignore-daemonsets=true
node "docker-for-desktop" already cordonedWARNING: Ignoring DaemonSet-managed pods: kube-proxy-4s52dpod "compose-api-6fbc44c575-k6fz8" evictedpod "compose-7447646cf5-w4mzb" evictedpod "kubernetes-simple-app-57585656fc-nvkxm" evictedpod "kube-dns-86f4d74b45-dt5rb" evictednode "docker-for-desktop" drained

출처: 
https://arisu1000.tistory.com/27845 [아리수]

출처:  https://arisu1000.tistory.com/27845  [아리수]

 

그럼 cordon 명령어는 뭘까?

* cordon: 해당 노드에 더이상 pod들이 scheduling되지 않게 하는 것(존재하던 pod는 유지)

$ kubectl get nodes
NAME                 STATUS    ROLES     AGE       VERSION
docker-for-desktop   Ready     master    4d        v1.10.3

 

$ kubectl cordon docker-for-desktop

node "docker-for-desktop" cordoned

 

$ kubectl get nodes

NAME                 STATUS                     ROLES     AGE       VERSION

docker-for-desktop   Ready,SchedulingDisabled   master    4d        v1.10.3

$  kubectl uncordon docker-for-desktop// scheduling되게 다시 변경

그럼 새로운 pod가 생성될 때, 해당 node에는 scheduling이 되지 않는다.

그리고, cordon 속성을 제거하거나 / drain 속성을 풀려면 'uncordon'을 수행하면 된다.

 kubectl uncordon docker-for-desktop// scheduling되게 다시 변경



출처: https://arisu1000.tistory.com/27845 [아리수]
출처: Udemy 사이트의 Certified Kubernetes Administrator (CKA) with Practice Tests 강의

반응형
반응형

위와 같이 pod에 특정 환경변수를 설정하려면 어떻게 하는게 편할까?

pod definition YAML에 설정할 수 있다.

 

 

하지만, pod definition file이 많다면 query files 내에 저장된 environment data 관리에 어려움이 있다.
그래서, 이 configuration들을 묶어 pod-definition 파일 밖에서 ConfigMap과 Secrets 파일을 만든다.



1. ConfigMap: 일반적인 plain text를 별도의 파일에 저장. 
  pod가 생성될 때, ConfigMap이 pod 내부로 추가되고, 해당 파일에 있는 환경 변수들을 사용할 수 있다.

 1) ConfigMap의 두 가지 phase

   (1) Create ConfigMaps
      -  imperative way (command로 생성. file 미작성)

         . kubectl create configmap 명령어

# kubectl create configmap <config-name> --from-literal=<key>=<value>
ex. app-config --from-literal=APP_COLOR=blu
                   --from-literal=APP_MOD=prod  (추가로 원하는 속성이 있다면)

 

 

    - Declarative way (file 작성)

      . kubectl create -f  [file Name]
       ex. config-map.yaml 생성

 

 

 

   (2) Inject them into the POD (다른 object들 처럼)
    - (ENV의 경우) "envFrom:" key 추가 
    envFrom:
      - configMapRef:
            name: app-config // 여기에 configmap의 name 넣기

 

 

 - (Single Env의 경우) valueFrom:
 - (Volume의 경우) configMap:

 

 

  * ConfigMap 조회

 

 

2. Kubernetes Secrets

위에서 ConfigMap을 알아봤는데, ConfigMap은 모든 data를 plain 형태로 저장했다.

그런데, id/pw와 같이 민감한 값을 저장해야 한다면 configMap이 적합할까?

 

 

당연히 아니다.

그래서, 이런 민감한 정보들은 Screts 파일에 암호화하여 저장한다.

Secrets 역시 2가지 Phase로 나눠진다.

1) CREATE Secret
2) Inject them into the POD 

 

하나씩 알아보자.

 

먼저 이 역시 명령형(imperative)와 선언형(Declarative)로 나뉜다.

 

 

먼저 명령형 부터.

# kubectl create secret generic <secret-name> --from-literal=<key>=<value>
ex. kubectl create secret generic \
       app-secret --from-literal=DB_Host=mysql app-secret
                      --from-literal=DB_User=root ...

설정이 많아지면, file로 가져오는 명령어도 있다.
# kubectl create secret generic <secret-name> --from-file=<path-to-file>
ex. kubectl create secret generic \ app-secret --from-file=app_secret.properties

 

다음은 역시, 선언형이다.

kubectl create -f secret-data.yaml
 * 단, secret은 민감한 정보를 다루기 때문에, plain text말고 encoded된 형식으로 "직접" 작성해야함.

 

 

어떻게 encoded된 형식으로 변환?   'echo -n' 명령어 사용!

# echo -n 'mysql' | base64 
# echo -n 'root' | base64 

그럼 decode 방법은!?
#'echo -n 'bXlzcWw=' | base64 --decode 

 

 

2) Inject them into the POD 
 ConfigMap과 동일하게 아래와 같은 key를 추가한다

- (ENV의 경우) "envFrom:" key 추가 
    envFrom:
      - secretRef:
            name: app-config // 여기에 configmap 이름 넣기

 


 - (Single Env의 경우) valueFrom: secretKeyRef:
 - (Volume의 경우) secretName:





생성된 secrets을 조회해보면, describe에서도 data는 숨겨지는 것을 볼 수 있다.

 

위는 정말 secret파일이 container에 포함되는지 확인하는 명령.

 

 

* Note)
# explain kubectl explain [--recursive=false] [flags]
파드, 노드, 서비스 등의 다양한 리소스에 대한 문서를 출력한다.
출처: https://kubernetes.io/ko/docs/reference/kubectl/overview/

controller-0:~$ kubectl explain pods --recursive | grep Volume -A3

 

출처: Udemy 사이트의 Certified Kubernetes Administrator (CKA) with Practice Tests 강의

반응형
반응형

1. Monitoring: K8s에서는 어떻게 Node간 Resource를 체크할까?

위 Prometheus, Elastic Stack 등 Monitoring에 대한 OpenSource를 사용한다.

 

 

 

세부 동작 과정은, Node의 Kubelet 안에  cAdvisor라는 subcomponent가 있다.

cAdvisor는 pod로부터 성능 metrics들을 조회하고, kubelet API를 통해 이것을 metric server로 노출시킨다.

 

 

메트릭 서버는 위와 같은 명령어로 설치하며, 설치 후에는 kubectl top node, top pod 명령어를 통해

각 node, pod의 사용량을 알 수 있다.

 

 

 

 

그럼, Logging에 대해서도 알아보자.

2. Logging:

Docker의 경우 이미 app에 의해 standard output으로 event를 생성하고 있다. 

docker container를 background 모드로 사용하고 싶다면, -d 옵션을 사용하면 된다.

이러면 log를 볼 수 없다.

 

만약 로그를 보고 싶다면, container ID를 이용한 logs -f 옵션을 사용하면 된다.

docker logs -f [Container ID]

 

 

그럼 K8s를 알아보자.

일단 위와 동일한 image를 사용하여 pod를 하나 만든다. 

pod가 생성된 후에는, kubectl logs -f event-simulator-pod 옵션을 통해 log를 볼 수 있다.

(-f 옵션은 docker cmd처럼 라이브로 로그를 보겠다는 의미.)

 

 

그런데, 이 로그는 pod 내 container마다 다르다.

pods는 여러 개의 docker container를 가질 수 있으므로, 'image-processor'라는 추가적인 컨테이너를 만들어 본다.

 

그러면, logs를 조회할 때도 2개의 container를 한 번에 조회할 수 있다.

# kubectl logs -f event-simulator-pod event-simulator

kubectl logs -f [Container ID 1] [Container ID 2] ...

 

 

출처: Udemy 사이트의 Certified Kubernetes Administrator (CKA) with Practice Tests 강의

반응형
반응형

K8s에는 Scheduler도 1개 이상을 생성할 수 있다.

왜 1개 이상의 생성이 필요할까?

 

이전에 Taint&Toleration, Affinity, Selector를 이용하여 Scheduler가 특정 pod에 특정 Node를 생성하게 했다.

그런데, 복합적인 절차들이 맞물려서, 여러 개의 Schedule 조건도 필요할 수 있다.

예를 들어, 이 pod는 특정 작업이 끝난 후 생성되게 해달라. 등의 작업 말이다.

 

그래서 k8s에는 Multiple Scheduler를 생성한다. 

Deploy는 위와 같은 방법으로 진행한다.

YAML파일을 하나 더 만들어서, spec: containers: command 아래에 2개의 값을 별도로 추가해준다.

-- leader-elect=false
-- scheduler-name=my-custom-scheduler 

 

 

그리고 kubectl create -f YAML파일을 통해 각 Scheduler를 생성한다.

이제부터는 pod에도 어떤 scheduler를 쓸 건지 'schedulerName'을 명시해줘야 한다. 

(명시해주지 않으면, 이전에 설정했던 -- leader-elect=true 값을 가진 scheduler가 default로 설정될 것이다.)

 

 

이후 pod를 생성해서 k8s의 events를 조회해보면,

my-custom-scheduler를 통해 생성된 pod의 event를 확인할 수 있다.

 

 

 

출처: Udemy 사이트의 Certified Kubernetes Administrator (CKA) with Practice Tests 강의

반응형
반응형

daemon set은 replicaset과 거의 동일하다. kind만 다르고, 'replica'만 없을 뿐

Daemon Sets: K8s의 ReplicaSet과 거의 동일한 object.

ReplicaSet은 2개 이상의 pod를 생성하는 반면, Daemon Sets은 1Node에 1pod만을 생성한다.

 

그럼, 어떤 app이 1 Node 1pod를 사용할까?

K8s Architecture를 배울 때, 각 Node는 kube-proxy를 하나씩 가지고 있었다.

이것도 예시가 될 수 있고, Networking (weave-net)에서 사용되던 인스턴스들도 1Node 1pod면 된다.

kubeMonitoring solution이나 Logs Viewer(Collector)도 Daemon Sets을 사용한다고 한다.

 

 

 

daemonsets에 관련된 명령어는 위와 같고, 설정이 딱히 없다 :)

 

 

 

근데, 어떻게 1 Node 1 pod에 할당하지?

 

v1.12 전까지는 scheduler에서 해당 pod가 아무 node로나 할당되지 않게끔

각 pod에 이전에 scheduler에서 배운 'Nodename'을 명시했다고 한다.

https://countrymouse.tistory.com/entry/CKA-3-1?category=1016093 

 

Certified Kubernetes Administrator (CKA) - 3-1. Scheduling (ft. Udemy)

Scheduler는 어떻게 동작할까? pod가 생성될 때, Scheduler는 각 pod에 'nodeName'라는 key가 있는지 체크한다. 없다면, Scheduler가 자동으로 알고리즘에 의해 각 pod에 적합한 node를 bind 시켜주고, 해당 key..

countrymouse.tistory.com

하지만, v1.12부터는 NodeAffinity와 default scheduler를 사용한다고 한다.

 

 

출처: Udemy 사이트의 Certified Kubernetes Administrator (CKA) with Practice Tests 강의

 

반응형
반응형

https://medium.com/the-programmer/handling-resource-requests-limits-in-kubernetes-53ea8a68a550

각 Node들엔 Resource(CPU, MEM, DISK)가 정해져 있다.

Node에는 pod들이 할당되면서 resource를 소비하게 되는데,

node의 resource가 다 떨어지면 해당 node에는 pod가 생성되지 않는다.

 

그리고, 각 app도 필요한 resource가 있기 때문에 pod에 requested / limits의 자원을 명시한다.

해당 값을 명시할 땐 이진데이터인 Xibibyte 형식을 사용한다.

- requested의 경우, pod가 생성될 때 요구되는 값이고

- limits의 경우 app이 구동 중에 자원이 더 필요하더라도, 이를 넘어가지 않도록 제한해주는 설정이다.

  cpu의 경우, limits을 넘어가면 throttling 처리되고, MEM의 경우 pod가 종료된다.

 

 

* 그리고 OOM Terminated 라는 것도 있는데, Out of Memory로 Terminated 되었다는 의미이다.  이건 app의 limits memory값을 늘려야 한다.

 

 

출처: Udemy 사이트의 Certified Kubernetes Administrator (CKA) with Practice Tests 강의

 

반응형
반응형

용량이 큰 Node1과 나머지 Node 2, 3이 있다.

그리고 많은 자원을 요구하는 pod와 적당한 pod 2개가 있다.

많은 자원을 요구하는 pod가 Node 1에 할당되게 하려면 어떻게 해야할까?

 

pod에 nodeSelector 라는 key를 추가해서, 원하는 node에 해당 pod가 생성되게끔 설정을 해준다.

(size: Large로 명시했음)

* 단, Node 1은 미리 size: Large 라는 value를 가지고 있어야 한다.

 

그래서, Node1에 해당 label 속성을 주기 위해 아래와 같은 명령어를 통해 label을 추가한다.

# kubectl label nodes <node-name> <label-key>=<label-value>
ex. kubectl label nodes node-1 size=Large
ex. kubectl label namespace <namespace> <label-key>=<label-value>

 

 

그리고 다시 'nodeSlelector'를 추가한 pod를 생성하면, Node-1에 원하던 pod가 생성된다.

그런데... 조건이 훨씬 복잡해진다면? (현재 조건은 1개 뿐이다. size:Large)

 

 

 

Node Affinity 라는 게 나온다. 

Node Affinity란? 여러 개의 조건을 사용하여 원하는 Node에 pod를 생성하기 위한 설정이다.

 

 

 

예를들어, nodeSelector는 key가 단순히 label을 비교하는 하나 였다면,

Node Affinity는 'requredDuringSchedulingIgnoredDuringExecution, match Exporessions' 등 여러 가지 조건이 있다.

 

 

 

내용은 생각보다 간단하다.

- requiredDuringSchedulingIgnoredDuringExecution

   : Scheduling 동안 해당 affinity 설정을 가진 node가 없다면 pod를 생성하지 않는다(=required) 

     && pod가 이미 생성된 상태에서 affinity나 label 설정들이 바뀐다면 이를 무시한다(=ignored). (pod는 정상 동작)

- preferredDuringSchedulingIgnoredDuringExecution

   : Scheduling 동안 해당 affinity 설정을 가진 node가 없다면 적당한 곳에 pod를 생성한다(=preferred) 

     && pod가 이미 생성된 상태에서 affinity나 label 설정들이 바뀐다면 이를 무시한다(=ignored). (pod는 정상 동작)

- requiredDuringSchedulingRequiredDuringExecution

   : Scheduling 동안 해당 affinity 설정을 가진 node가 없다면 pod를 생성하지 않는다(=required) 

     && pod가 이미 생성된 상태에서 affinity나 label 설정들이 바뀐다면 이를 반영한다. (pod가 삭제될 수도 있음)

 

 

 

그러면..

이전에 배웠던 Taint & Tolerance와 Node Affinity 차이는 무엇일까?

 

- Taint: Node에 설정해서, 해당 노드에 아무 pod나 생성되지 않게 한다.

- Tolerance: Pod에 설정해서, 해당 pod가 특정 node에"도" 생성될 수 있게 한다. (회색과 같은 다른 node에"도" 생성될 수 있다.)

- Node Affinity: 특정 pod는 특정 node에만 생성될 수 있게 한다! (아래 그림 참고)

 

 

출처: Udemy 사이트의 Certified Kubernetes Administrator (CKA) with Practice Tests 강의

반응형
반응형

Taint & Tolerations: 각 node와 pod에 값들을 붙여 pod/node할당을 제한하는 속성 (restriction)

 - Taint: Node에 적용되며, 해당 Taint와 동일한 Toleration 설정이 있는 pod만 해당 Node에 할당될 수 있다.

 - Tolerations: Pod에 적용되며, 해당 Toleration에 따라 특정 Taint가 있는 pod에도 할당될 수 있고,

                              다른 pod에도 할당될 수 있다.

 

 

그럼, node에 taint 설정이 있는데, 해당 taint 설정을 만족하는 toleration을 갖고 있는 pod가 없다면?

그에 따른 node의 동작에는 3가지 옵션이 있다.

1) NoSchedule: pod가 해당 node에 schedule되지 않는다.

2) PreferNoSchedule: 이 노드에 pod가 배치되는 것을 피할 것이지만, 개런티되진 않음.

3) NoExcute: 이미 pod가 해당 노드에 존재한다면, toleration 설정을 가질 때까지 실행되지 않음.

 

 

설정은 왼쪽처럼 cmd로 해도 되고, 오른쪽처럼 YAML파일을 직접 작성해도 된다.

단, ""를 붙여야 한다.

 

taint를 삭제할 때는, 명령어 가장 끝에 '-'만 붙여주면 된다.# kubectl taint nodes node1 app=myapp:Noschedule-

 

 

그러고보니, master node에는 항상 pod가 생성되지 않았다. 

그 이유는 무엇이었을까?

Master node에는 Taints 설정이 있어서 pod생성이 불가했기 때문이다.

 

출처: Udemy 사이트의 Certified Kubernetes Administrator (CKA) with Practice Tests 강의

반응형
반응형

* Lables & Selector: 여러 오브젝트(pod, service, node ...)들을 그룹(key, functionality, ... )으로 묶는 방법

 

 

 

https://countrymouse.tistory.com/entry/k8s-6

lables는 YAML파일을 작성할 때, metadata 아래에 있던 key 였다. (app: myapp, type: front-end)

 

 

그럼 labels 에 따른 조회는 어떻게 할까? 아래처럼 하면 된다.

# kubectl get po --show-labels // pod들의 전체 레이블 출력
# kubectl get po --selector app=front-end // app=front-end를 label로 가진 pod들 출력  

 

 

https://devops4solutions.medium.com/kubernetes-labels-and-annotation-3bb0a5a22193

annotation은 뭘까?

k8s 오브젝트들에 포함되는 unstructed information을 저장하는 데에 사용되는 key-values 짝이다.

labels&selector가 object들을 그룹화 할 때 사용한다면, annotation은 다른 정보들을(timestamps, sha, issue tracker links, name...) 저장하는 데에 사용된다.

 

 

출처: Udemy 사이트의 Certified Kubernetes Administrator (CKA) with Practice Tests 강의

 

반응형

+ Recent posts