-
06. 쿠버네티스 핵심 개념 (1)24년 11월 이전/데브옵스(DevOps)를 위한 쿠버네티스 마스터 2021. 7. 9. 20:41반응형
이 문서는 인프런 강의 "데브옵스를 위한 쿠버네티스 마스터"을 듣고 작성되었습니다. 최대한 요약해서 강의 내용을 최소로 하는데 목표를 두고 있어서, 더 친절하고 정확한 내용을 원하신다면 강의를 구매하시는 것을 추천드립니다. => 강의 링크
큐브 시스템 컴포넌트란
큐브 시스템 컴포넌트란 쿠버네티스(kubenetes) 시스템을 구성하는 중요 컴포넌트입니다. 그림으로 나타내면 다음과 같다.
마스터 노드(Control Plane Node)는 다음과 같이 구성되어 있다.
- etcd : 모든 클러스터 데이터를 담는 쿠버네티스의 저장소이다.
- kube-apiserver : Kubernetes API를 노출한다. 모든 컴포넌트는 이 컴포넌트를 통해서 통신한다.
- kube-scheduler : 생성된 Pod를 어떤 Node에 배치하고 실핼할 것인지를 선택한다.
- kube-controller-manager : 실제 리소스를 관리하는 컴포넌트 다음과 같이 크게 4가지로 구성된다.
- 노드 컨트롤러 : 노드 상태 관리
- 레플리케이션 컨트롤러 : Pod 개수를 조절
- 엔드포인트 컨트롤러 : Service와 Pod을 연결
- 서비스 어카운트 & 토큰 컨트롤러 : 인증/인가를 담당
슬레이브 노드(Data Node)는 다음과 같이 구성되어 있다.
- kubelet : 마스터 노드의 명령에 따라서 CRT(Container Run Time - Docker)를 관리한다.
- kube-proxy : 노드 - 컨테이너, 컨테이너-컨테이너간 통신을 담당한다.
이번 장에서는
VM
에서 실습을 진행한다. 마스터 노드에서 다음 명령어를 실행해보자.$ kubectl get pod -n kube-system NAME READY STATUS RESTARTS AGE coredns-558bd4d5db-5z4jv 1/1 Running 1 5d coredns-558bd4d5db-g9nhg 1/1 Running 1 5d etcd-master 1/1 Running 2 5d kube-apiserver-master 1/1 Running 2 5d kube-controller-manager-master 1/1 Running 2 5d kube-proxy-hvpz5 1/1 Running 2 5d kube-proxy-kdtb5 1/1 Running 1 5d kube-proxy-qthkm 1/1 Running 1 5d kube-scheduler-master 1/1 Running 2 5d weave-net-46bsq 2/2 Running 3 5d weave-net-fgxbv 2/2 Running 4 5d weave-net-qr5v6 2/2 Running 5 5d
-n
옵션은 네임스페이스를 지정하는 옵션이다.Kubernetes
클러스터를 구성하면 기본적으로 큐브 시스템이 뒤에서Pod
의 형태로 돌아가게 된다.etcd
,kube-apiserver
,kube-controller-manager
,kube-scheduler
가 동작되는 것을 확인할 수 있다.이제
/etc/kubernetes/manifests/
경로로 이동해서 어떤 파일들을 가지고 있는지 확인해보자.$ cd /etc/kubernetes/manifests/ $ ll total 24 drwxr-xr-x 2 root root 4096 7월 3 18:50 ./ drwxr-xr-x 4 root root 4096 7월 3 18:50 ../ -rw------- 1 root root 2126 7월 3 18:50 etcd.yaml -rw------- 1 root root 3947 7월 3 18:50 kube-apiserver.yaml -rw------- 1 root root 3350 7월 3 18:50 kube-controller-manager.yaml -rw------- 1 root root 1384 7월 3 18:50 kube-scheduler.yaml
이 디렉토리에 존재하는 파일을 가지고 마스터 노드에서 동작하는 큐브 시스템에 대한 커스텀한 설정을 할 수 있다는 것을 알아두자. 이번엔 슬레이브 노드에서 다음을 입력해보자.
$ ps -ef | grep "kube" root 698 1 1 19:06 ? 00:00:18 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.4.1 root 2562 2523 0 19:07 ? 00:00:00 /usr/local/bin/kube-proxy --config=/var/lib/kube-proxy/config.conf --hostname-override=slave2 root 3174 2796 0 19:07 ? 00:00:00 /home/weave/kube-utils -run-reclaim-daemon -node-name=slave2 -peer-name=6e:85:ad:af:a7:bb -log-level=debug gurumee 11764 5641 0 19:25 pts/0 00:00:00 grep --color=auto kube
위의 명령어 두 줄을 보면,
kubelet
과kube-proxy
가 실행되고 있음을 확인할 수 있다.Etcd란?
Etcd
는Kubernetes
클러스터의 저장소로 사용되며, 원래는 키-값 쌍으로 데이터를 저장하는NoSQL
데이터베이스이다. 분산 환경에서 자주 쓰인다고 한다.그냥 어떻게 쓰는지 확인하기 위해서 이를 간단하게 조작할 수 있는
etcdctl
을 설치한다.# 압축 파일 다운로드 $ wget https://github.com/etcd-io/etcd/releases/download/v3.5.0/etcd-v3.5.0-linux-amd64.tar.gz # 압축 파일 해제 $ tar -xf etcd-v3.5.0-linux-amd64.tar.gz
이제 압축된 파일로 들어가보자.
etcd
,etcdctl
등이 설치된 것을 확인할 수 있다.$ cd etcd-v3.5.0-linux-amd64 $ ll total 56312 drwxr-xr-x 3 gurumee gurumee 4096 6월 16 06:51 ./ drwxrwxr-x 3 gurumee gurumee 4096 7월 8 19:44 ../ drwxr-xr-x 3 gurumee gurumee 4096 6월 16 06:51 Documentation/ -rwxr-xr-x 1 gurumee gurumee 23560192 6월 16 06:51 etcd* -rwxr-xr-x 1 gurumee gurumee 17969152 6월 16 06:51 etcdctl* -rwxr-xr-x 1 gurumee gurumee 16048128 6월 16 06:51 etcdutl* -rw-r--r-- 1 gurumee gurumee 42066 6월 16 06:51 README-etcdctl.md -rw-r--r-- 1 gurumee gurumee 7359 6월 16 06:51 README-etcdutl.md -rw-r--r-- 1 gurumee gurumee 9394 6월 16 06:51 README.md -rw-r--r-- 1 gurumee gurumee 7896 6월 16 06:51 READMEv2-etcdctl.md
etcd
바이너리 파일을 이용해서 실행할 수 있지만 이미kubernetes
클러스터를 운영하면서 실행되고 있는 상태이다. 클러스터가 이용하고 있는etcd
를 이용해서 키를 조회할 수 있다. 터미널에 다음을 입력한다.$ sudo ETCDCTL_API=3 ./etcdctl --endpoints 127.0.0.1:2379 --cacert /etc/kubernetes/pki/etcd/ca.crt --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key get / --prefix --keys-only ... /registry/services/endpoints/default/kubernetes /registry/services/endpoints/kube-system/kube-dns /registry/services/specs/default/kubernetes /registry/services/specs/kube-system/kube-dns
그럼 가지고 있는 키 목록이 쭉 나열될 것이다. 위 명령어에서 뒤에
get
부터가 실제 명령어다. 이제 이etcd
에 키-값 쌍을 한 번 저장해보고 꺼내보도록 하자 매우. 쉽다. 먼저 터미널에 다음을 입력한다.$ sudo ETCDCTL_API=3 ./etcdctl --endpoints 127.0.0.1:2379 --cacert /etc/kubernetes/pki/etcd/ca.crt --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key put test foo OK
키 "test" 값 "foo"를
etcd
에 저장했다. 이를 가져와보자. 터미널에 다음을 입력한다.$ sudo ETCDCTL_API=3 ./etcdctl --endpoints 127.0.0.1:2379 --cacert /etc/kubernetes/pki/etcd/ca.crt --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key get test test foo
첫 번째 줄에 키가, 두 번째 줄에 값이 출력될 수 있음을 확인할 수 있다. 우리는
etcd
가 키-값 쌍으로 저장하는 데이터베이스이며kubernetes
가 저장소로 사용하는 것만 알고 있으면 된다.Pod이란?
Pod
이란Kubernetes
과 관리하는 가장 기본이 되는 요소이다.위 그림처럼 노드 내부에 생성이 된다. 단, 노드에 걸쳐서
Pod
이 생성되지는 않는다. 하나의Pod
에는 여러 컨테이너가 실행될 수 있으나 모니터링 등의 이유가 아니라면1 Pod 1 Container
가 원칙이다. 또한Pod
은NAT
로 구성된 것 처럼 외부와 격리되어 있다. 외부와 연결하려면Service
가 필요하다.Pod
은 명령어로 만들 수 있지만 보통yaml
파일로 작성하는 것이 일반적이다. 다음과 같이simple-app-pod-v1.yaml
을 작성해보자.src/ch06/simple-app-pod-v1.yaml
apiVersion: v1 kind: Pod metadata: name: simple-app spec: containers: - name: simple-app image: gurumee92/simple-app ports: - containerPort: 8080
그 후 터미널에 다음을 입력해보자.
$ kubectl create -f simple-app-pod-v1.yaml job.batch/simple-app created
그 다음 다음 명령어로 잘 실행이 되나 확인을 해보자.
$ kubectl get pod -w NAME READY STATUS RESTARTS AGE simple-app-5r4fb 0/1 ContainerCreating 0 3s simple-app-5r4fb 1/1 Running 0 4s
실행이 되면
kubectl describe
명령어를 통해서 더 자세한 내용을 살펴볼 수 있다.$ kubectl describe pod simple-app-zkh2m Name: simple-app-zkh2m Namespace: default Priority: 0 Node: slave2/10.0.2.5 Start Time: Thu, 08 Jul 2021 20:13:08 +0900 Labels: controller-uid=06d6338a-c41d-4a88-a6c4-fef094c539e0 job-name=simple-app Annotations: <none> Status: Running IP: 10.32.0.3 IPs: IP: 10.32.0.3 Controlled By: Job/simple-app Containers: simple-app: Container ID: docker://20b5995bc8c7339f79740c7a6391b313a789f672dd527b97590598ed1b4f6dca Image: gurumee92/simple-app Image ID: docker-pullable://gurumee92/simple-app@sha256:baf83add38ca5429adb80edc8e1647179d1771e853e00ae95c274bccc3b0dcd1 Port: 8080/TCP Host Port: 0/TCP State: Running Started: Thu, 08 Jul 2021 20:15:40 +0900 Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-xh6pc (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: kube-api-access-xh6pc: Type: Projected (a volume that contains injected data from multiple sources) TokenExpirationSeconds: 3607 ConfigMapName: kube-root-ca.crt ConfigMapOptional: <nil> DownwardAPI: true QoS Class: BestEffort Node-Selectors: <none> 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 7m36s default-scheduler Successfully assigned default/simple-app-zkh2m to slave2 Normal Pulling 7m35s kubelet Pulling image "gurumee92/simple-app" Normal Pulled 5m4s kubelet Successfully pulled image "gurumee92/simple-app" in 2m31.03551003s Normal Created 5m4s kubelet Created container simple-app Normal Started 5m4s kubelet Started container simple-app
이미지 정보, 어떤 노드에 생성되었는지, 컨테이너 실행 이력 등 여러 정보를 확인할 수 있다. 이제 포트 포워딩을 통해서 외부로 노출시켜보자
$ kubectl port-forward simple-app-zkh2m 8080:8080 Forwarding from 127.0.0.1:8080 -> 8080 Forwarding from [::1]:8080 -> 8080 Handling connection for 8080 Handling connection for 8080 E0708 20:17:48.868587 66425 portforward.go:385] error copying from local connection to remote stream: read tcp4 127.0.0.1:8080->127.0.0.1:36710: read: connection reset by peer E0708 20:17:48.876150 66425 portforward.go:385] error copying from local connection to remote stream: read tcp4 127.0.0.1:8080->127.0.0.1:36712: read: connection reset by peer Handling connection for 8080 E0708 20:17:52.900618 66425 portforward.go:385] error copying from local connection to remote stream: read tcp4 127.0.0.1:8080->127.0.0.1:36726: read: connection reset by peer Handling connection for 8080
터미널을 새로 열어 다음을 입력해보자.
$ curl localhost:8080 Hello World simple-app-zkh2
굳! 그 후 삭제는 다음으로 할 수 있다.
$ kubectl delete -f simple-app-pod-v1.yaml job.batch "simple-app" deleted
Probe란?
Probe
란 컨테이너에서kubelet
에 의해 주기적으로 수행되는 자가진단 및 회복을 작업을 뜻한다. 다음과 같이 세 가지의Probe
가 있다.- livenessProbe : 컨테이너가 동작 중인지 여부를 나타냄. 실패하면 컨테이너를 죽이고 다시 재시작.
- readinessProbe : 컨테이너가 요청을 처리할 준비가 되었는지 여부를 나타냄. 만약 실패하면, 로드 밸런서에서 해당 Pod의 IP 주소를 제거함.
- startupProbe : 컨테이너 내 애플리케이션이 시작 여부를 나타냄. 이 프로브가 활성화되면 나머지 두 프로브는 비활성화됨. 실패하면 멐ㄴ테이너를 죽이고 재시작함.
여기서는 HTTP 엔드 포인트에 대한 헬스 체크를 하는
livenessProbe
를 간단하게 작성해보자. 다음을 작성한다.apiVersion: v1 kind: Pod metadata: labels: test: liveness name: liveness-http spec: containers: - name: liveness image: k8s.gcr.io/liveness args: - /server livenessProbe: httpGet: path: /healthz port: 8080 httpHeaders: - name: Custom-Header value: Awesome initialDelaySeconds: 3 periodSeconds: 3
이제 터미널에 다음을 입력해서
Pod
을 만든다.$ kubectl create -f http-liveness.yaml
그 후
Pod
을 쭉 관찰해보자.$ kubectl get pod -w NAME READY STATUS RESTARTS AGE liveness-http 1/1 Running 0 6s liveness-http 1/1 Running 1 24s liveness-http 1/1 Running 2 45s liveness-http 1/1 Running 3 65s liveness-http 0/1 CrashLoopBackOff 3 81s liveness-http 1/1 Running 4 112s liveness-http 1/1 Running 5 2m12s liveness-http 0/1 CrashLoopBackOff 5 2m28s ...
처음 빼놓고 약 20초 간격으로 재시작하는 것을 확인할 수 있다. 그렇게 3번을 실행하면
Pod
이 종료된다. 그 후 다시 재시작한다. 이게 계속 반복된다.실제
k8s.gcr.io/liveness
이미지로 작성된 컨테이너는 다음 코드가 들어있다.http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { duration := time.Now().Sub(started) if duration.Seconds() > 10 { w.WriteHeader(500) w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds()))) } else { w.WriteHeader(200) w.Write([]byte("ok")) } })
위 코드는 시작 시 처음 10초간 200 상태코드를 내뱉다가 그 이후부터는 500 상태 코드를 내뱉는 것이다. 그래서 계속 10초 이후에 에러로 판단해서 계속
Pod
을 종료했다가 재시작하게 되는 것이다. 다시 한 번 기억하자. 이런 자가 진단 작업 + 자가 회복 과정이Probe
이다.Label이란?
레이블이란 모든 리소스를 구성하는 매우 간단하면서도 강력한 쿠버네티스의 기능이다. 키-값 쌍으로 리소스에 레이블을 지정해서 부가적인 정보를 나타낼 수 있다. 조회/추가/수정/삭제가 가능하며 심지어 리소스가 생성된 이후에도 추가/수정/삭제를 할 수는 있지만 권장하지는 않는다.
보통 이런식으로 붙여서 레이블 단위로 리소스들을 관리할 수 있다.
또한 사내에 정책이 없다면 다음 레이블들의 사용을 고려해보자.
이제 직접 레이블을 만들어보자. 다음과 같이
simple-app-pod-v2.yaml
을 만들어보자.src/ch06/simple-app-pod-v2.yaml
apiVersion: v1 kind: Pod metadata: name: simple-app-v2 labels: creation_method: manual env: prod spec: containers: - name: simple-app image: gurumee92/simple-app ports: - containerPort: 8080
여기서
metadata
필드 밑에labels
하위 필드들이 모두 레이블들이다. 그리고 이제 실습을 위해서 v1, v2를 모두 생성해두자.# v1 생성 $ kubectl create -f simple-app-pod-v1.yaml pod/simple-app created # v2 생성 $ kubectl create -f simple-app-pod-v2.yaml pod/simple-app-v2 created # pod 조회 $ kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES simple-app 1/1 Running 0 3m32s 10.32.0.3 slave2 <none> <none> simple-app-v2 1/1 Running 0 3m27s 10.32.0.4 slave2 <none> <none>
이제 레이블을 검색해보자.
$ kubectl get pod --show-labels NAME READY STATUS RESTARTS AGE LABELS simple-app 1/1 Running 0 8m37s <none> simple-app-v2 1/1 Running 0 8m32s creation_method=manual,env=prod
v1에는 어떤 레이블도 확인되지 않고 v2에 레이블들이 붙은 것을 확인할 수 있다. 이제 v1에 레이블을 추가해보자.
# v1에 label 추가 env=test, creation_method=manual $ kubectl label pod simple-app env=test creation_method=manual pod/simple-app labeled # 라벨 확인 $ kubectl get pod --show-labels NAME READY STATUS RESTARTS AGE LABELS simple-app 1/1 Running 0 10m creation_method=manual,env=test simple-app-v2 1/1 Running 0 10m creation_method=manual,env=prod
그 후, v2에 creation_method의 값을 automation으로 변경해보자.
# v2 라벨 업데이트 $ kubectl label pod simple-app-v2 creation_method=automation error: 'creation_method' already has a value (manual), and --overwrite is false
이렇게 에러가 뜬다. 수정하려면
--overwrite
옵션을 켜주어야 한다. 다시 한 번 다음과 같이 입력해보자.# v2 라벨 업데이트 $ kubectl label pod simple-app-v2 creation_method=automation --overwrite pod/simple-app-v2 labeled # 업데이트 내용 확인 $ kubectl get pod --show-labels NAME READY STATUS RESTARTS AGE LABELS simple-app 1/1 Running 0 13m creation_method=manual,env=test simple-app-v2 1/1 Running 0 13m creation_method=automation,env=prod
이제 v2의 레이블 creation_method를 제거해보자. 터미널에 다음을 입력한다.
# v2 라벨 제거 $ kubectl label pod simple-app-v2 creation_method- pod/simple-app-v2 labeled # 라벨 확인 v2에 creation_method 제거됨 $ kubectl get pod --show-labels NAME READY STATUS RESTARTS AGE LABELS simple-app 1/1 Running 0 18m creation_method=manual,env=test simple-app-v2 1/1 Running 0 18m env=prod
또한 레이블을 필터링해서 검색할 수 있다. 먼저 터미널에 다음을 입력한다.
$ kubectl get pod -l creation_method NAME READY STATUS RESTARTS AGE simple-app 1/1 Running 0 24m
위의 명령어는
creation_method
레이블이 붙어 있는Pod
들을 필터링해서 보여준다. 이와는 반대로 다음과 같이 작성도 가능하다.$ kubectl get pod -l '!creation_method' NAME READY STATUS RESTARTS AGE simple-app-v2 1/1 Running 0 25m
그럼 조건이 반전되서
creation_method
레이블이 붙지 않은Pod
들만 필터링해서 볼 수 있다. 위의 명령어들은 레이블 유무로 필터링했다면, 아래 명령어를 이용하면 다음과 같이 레이블 값 별로 필터링할 수 있다.$ kubectl get pod -l 'env=prod' NAME READY STATUS RESTARTS AGE simple-app-v2 1/1 Running 0 26m
레이블을 여러 조건들로 필터링하고 싶다면, 다음과 같이 작성할 수 있다.
$ kubectl get pod -l "env=test,creation_method=manual" NAME READY STATUS RESTARTS AGE simple-app 1/1 Running 0 28m
728x90'레거시 > 데브옵스(DevOps)를 위한 쿠버네티스 마스터' 카테고리의 다른 글
08. 쿠버네티스 핵심 개념 (3) (0) 2021.07.25 07. 쿠버네티스 핵심 개념 (2) (0) 2021.07.14 05. 쿠버네티스 들어가기 (2) (0) 2021.07.06 04. 쿠버네티스 들어가기 (1) (5) 2021.07.03 03. (쿠버네티스 들어가기 앞서) 왕초보도 따라하는 도커 기초 (2) (0) 2021.06.30