-
09. 쿠버네티스 핵심 개념 (4)24년 11월 이전/데브옵스(DevOps)를 위한 쿠버네티스 마스터 2021. 8. 5. 07:28반응형
이 문서는 인프런 강의 "데브옵스를 위한 쿠버네티스 마스터"을 듣고 작성되었습니다. 최대한 요약해서 강의 내용을 최소로 하는데 목표를 두고 있어서, 더 친절하고 정확한 내용을 원하신다면 강의를 구매하시는 것을 추천드립니다. => 강의 링크
쿠버네티스 네트워크 (1) Pod - Container 통신
일반적으로 컨테이너 간 통신을 위한 도커 네트워크 구조는 다음과 같다.
각 컨테이너는
veth
라는 가상의 네트워크 인터페이스를 통해서 통신을 한다. 반면에,쿠버네티스
에서 컨테이너 간 통신 구조는 살짝 다르다.하나의
veth
가상 네트워크 인터페이스에 여러 컨테이너가 연결되어 있다. 그리고pause
라는 녀석이 옆에 붙어서 이들 통신을 지원해준다.VM
에 다음을 입력해보자.$ sudo docker ps | grep pause 7cec7bbcfd41 k8s.gcr.io/pause:3.4.1 "/pause" 3 minutes ago Up 3 minutes k8s_POD_weave-net-qr5v6_kube-system_52d850d7-c8e4-4b75-93c5-2dd97237b818_8 55878c1c9fbe k8s.gcr.io/pause:3.4.1 "/pause" 3 minutes ago Up 3 minutes k8s_POD_kube-proxy-hvpz5_kube-system_676e7f6d-825c-43b6-92ea-a1b891092eb4_8 e149257efdfe k8s.gcr.io/pause:3.4.1 "/pause" 3 minutes ago Up 3 minutes k8s_POD_kube-controller-manager-master_kube-system_683f32b0119799727621446455e8d131_8 ee74476df7aa k8s.gcr.io/pause:3.4.1 "/pause" 3 minutes ago Up 3 minutes k8s_POD_kube-apiserver-master_kube-system_4497338b493c596567d3c3eb86085559_8 5b7c5e79e66a k8s.gcr.io/pause:3.4.1 "/pause" 3 minutes ago Up 3 minutes k8s_POD_etcd-master_kube-system_d0eb798391c9389c9721c4631c28dc9a_8 3ec62d452070 k8s.gcr.io/pause:3.4.1 "/pause" 3 minutes ago Up 3 minutes k8s_POD_kube-scheduler-master_kube-system_35ae2ec46407146c0fe6281c2c3292ce_8
수 많은
pause
가 이미 떠 있는 것을 알 수 있다. 이puase
들은kube-apiserver
,kube-scheduler-master
등의 컴포넌트에 붙어서 네트워크 통신을 지원한다. 마스터 노드에 있는pod
들을 한 번 확인해보자.$ kubectl get pod --all-namespaces -o wide | grep master kube-system etcd-master 1/1 Running 8 25d 10.0.2.15 master <none> <none> kube-system kube-apiserver-master 1/1 Running 8 25d 10.0.2.15 master <none> <none> kube-system kube-controller-manager-master 1/1 Running 8 25d 10.0.2.15 master <none> <none> kube-system kube-proxy-hvpz5 1/1 Running 8 25d 10.0.2.15 master <none> <none> kube-system kube-scheduler-master 1/1 Running 8 25d 10.0.2.15 master <none> <none> kube-system weave-net-qr5v6 2/2 Running 17 25d 10.0.2.15 master <none> <none>
이 중
apiserver
관련만 추출해서 보자.$ sudo docker ps | grep "apiserver" 58bc8ecf485a 106ff58d4308 "kube-apiserver --ad…" 9 minutes ago Up 9 minutes k8s_kube-apiserver_kube-apiserver-master_kube-system_4497338b493c596567d3c3eb86085559_8 ee74476df7aa k8s.gcr.io/pause:3.4.1 "/pause" 9 minutes ago Up 9 minutes k8s_POD_kube-apiserver-master_kube-system_4497338b493c596567d3c3eb86085559_8
이렇게 각 컴포넌트를 수행하는
pod
과 옆에 붙어서 컨테이너 간 통신을 지원하는pause pod
이 같이 떠 있는 것을 확인할 수 있다.쿠버네티스 네트워크 (2) Pod - Pod 통신
쿠버네티스
에서pod
끼리의 통신은CNI(Container Network Interface) 플러그인
을 통해서 이루어진다. 다음은 우리가 함께 설치한Weavenet
의 구조이다.이를 확인하기 위해서는
VM
에서 다음을 입력한다.$ sudo netstat -antp | grep weave tcp 0 0 127.0.0.1:6784 0.0.0.0:* LISTEN 4229/weaver tcp 0 0 10.0.2.15:43560 10.96.0.1:443 ESTABLISHED 4159/weave-npc tcp6 0 0 :::6781 :::* LISTEN 4159/weave-npc tcp6 0 0 :::6782 :::* LISTEN 4229/weaver tcp6 0 0 :::6783 :::* LISTEN 4229/weaver tcp6 0 0 10.0.2.15:6783 10.0.2.5:54483 ESTABLISHED 4229/weaver tcp6 0 0 10.0.2.15:6783 10.0.2.4:37053 ESTABLISHED 4229/weaver
위 명령어는
weavenet
에 통하는 네트워크 입출력을 보여준다. 자세히 보면 master node(10.0.2.15)에서 slave node들(10.0.2.4, 10.0.2.5)로 통신하는 것을 확인할 수 있다. 여기서weaver
의 노드 ip/port 확인해보자.$ ps -eaf | grep 4229 root 4229 4090 0 18:48 ? 00:00:01 /home/weave/weaver --port=6783 --datapath=datapath --name=5a:cd:9a:0c:b3:54 --http-addr=127.0.0.1:6784 --metrics-addr=0.0.0.0:6782 --docker-api= --no-dns --db-prefix=/weavedb/weave-net --ipalloc-range=10.32.0.0/12 --nickname=master --ipalloc-init consensus=2 --conn-limit=200 --expect-npc --no-masq-local 10.0.2.4 10.0.2.5 gurumee 13287 4862 0 19:06 pts/0 00:00:00 grep --color=auto 4229
역시 master -> slave 통신을 확인할 수 있다. 한 가지 더 알아둘 것은 이
CNI 플러그인
역시pod
으로 구성되어 동작한다는 것이다. 터미널에 다음을 입력한다.$ sudo docker ps | grep weave 21216183cb68 7f92d556d4ff "/usr/bin/launch.sh" 19 minutes ago Up 19 minutes k8s_weave-npc_weave-net-qr5v6_kube-system_52d850d7-c8e4-4b75-93c5-2dd97237b818_8 978cef952fea df29c0a4002c "/home/weave/launch.…" 19 minutes ago Up 19 minutes k8s_weave_weave-net-qr5v6_kube-system_52d850d7-c8e4-4b75-93c5-2dd97237b818_9 7cec7bbcfd41 k8s.gcr.io/pause:3.4.1 "/pause" 19 minutes ago Up 19 minutes k8s_POD_weave-net-qr5v6_kube-system_52d850d7-c8e4-4b75-93c5-2dd97237b818_8
여기서
weave-net
은daemon-set
이라는 리소스로 구성되어 있다. 자세한 설명을 보려면 다음을 입력해보자.$ kubectl get ds weave-net -n kube-system -o yaml apiVersion: apps/v1 kind: DaemonSet metadata: annotations: cloud.weave.works/launcher-info: |- { "original-request": { "url": "/k8s/v1.16/net.yaml?k8s-version=Q2xpZW50IFZlcnNpb246IHZlcnNpb24uSW5mb3tNYWpvcjoiMSIsIE1pbm9yOiIyMSIsIEdpdFZlcnNpb246InYxLjIxLjIiLCBHaXRDb21taXQ6IjA5MmZiZmJmNTM0MjdkZTY3Y2FjMWU5ZmE1NGFhYTA5YTI4MzcxZDciLCBHaXRUcmVlU3RhdGU6ImNsZWFuIiwgQnVpbGREYXRlOiIyMDIxLTA2LTE2VDEyOjU5OjExWiIsIEdvVmVyc2lvbjoiZ28xLjE2LjUiLCBDb21waWxlcjoiZ2MiLCBQbGF0Zm9ybToibGludXgvYW1kNjQifQpTZXJ2ZXIgVmVyc2lvbjogdmVyc2lvbi5JbmZve01ham9yOiIxIiwgTWlub3I6IjIxIiwgR2l0VmVyc2lvbjoidjEuMjEuMiIsIEdpdENvbW1pdDoiMDkyZmJmYmY1MzQyN2RlNjdjYWMxZTlmYTU0YWFhMDlhMjgzNzFkNyIsIEdpdFRyZWVTdGF0ZToiY2xlYW4iLCBCdWlsZERhdGU6IjIwMjEtMDYtMTZUMTI6NTM6MTRaIiwgR29WZXJzaW9uOiJnbzEuMTYuNSIsIENvbXBpbGVyOiJnYyIsIFBsYXRmb3JtOiJsaW51eC9hbWQ2NCJ9Cg==", "date": "Sat Jul 03 2021 09:55:33 GMT+0000 (UTC)" }, "email-address": "support@weave.works" } deprecated.daemonset.template.generation: "1" kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"apps/v1","kind":"DaemonSet","metadata":{"annotations":{"cloud.weave.works/launcher-info":"{\n \"original-request\": {\n \"url\": \"/k8s/v1.16/net.yaml?k8s-version=Q2xpZW50IFZlcnNpb246IHZlcnNpb24uSW5mb3tNYWpvcjoiMSIsIE1pbm9yOiIyMSIsIEdpdFZlcnNpb246InYxLjIxLjIiLCBHaXRDb21taXQ6IjA5MmZiZmJmNTM0MjdkZTY3Y2FjMWU5ZmE1NGFhYTA5YTI4MzcxZDciLCBHaXRUcmVlU3RhdGU6ImNsZWFuIiwgQnVpbGREYXRlOiIyMDIxLTA2LTE2VDEyOjU5OjExWiIsIEdvVmVyc2lvbjoiZ28xLjE2LjUiLCBDb21waWxlcjoiZ2MiLCBQbGF0Zm9ybToibGludXgvYW1kNjQifQpTZXJ2ZXIgVmVyc2lvbjogdmVyc2lvbi5JbmZve01ham9yOiIxIiwgTWlub3I6IjIxIiwgR2l0VmVyc2lvbjoidjEuMjEuMiIsIEdpdENvbW1pdDoiMDkyZmJmYmY1MzQyN2RlNjdjYWMxZTlmYTU0YWFhMDlhMjgzNzFkNyIsIEdpdFRyZWVTdGF0ZToiY2xlYW4iLCBCdWlsZERhdGU6IjIwMjEtMDYtMTZUMTI6NTM6MTRaIiwgR29WZXJzaW9uOiJnbzEuMTYuNSIsIENvbXBpbGVyOiJnYyIsIFBsYXRmb3JtOiJsaW51eC9hbWQ2NCJ9Cg==\",\n \"date\": \"Sat Jul 03 2021 09:55:33 GMT+0000 (UTC)\"\n },\n \"email-address\": \"support@weave.works\"\n}"},"labels":{"name":"weave-net"},"name":"weave-net","namespace":"kube-system"},"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"name":"weave-net"}},"template":{"metadata":{"labels":{"name":"weave-net"}},"spec":{"containers":[{"command":["/home/weave/launch.sh"],"env":[{"name":"HOSTNAME","valueFrom":{"fieldRef":{"apiVersion":"v1","fieldPath":"spec.nodeName"}}},{"name":"INIT_CONTAINER","value":"true"}],"image":"docker.io/weaveworks/weave-kube:2.8.1","name":"weave","readinessProbe":{"httpGet":{"host":"127.0.0.1","path":"/status","port":6784}},"resources":{"requests":{"cpu":"50m","memory":"100Mi"}},"securityContext":{"privileged":true},"volumeMounts":[{"mountPath":"/weavedb","name":"weavedb"},{"mountPath":"/host/var/lib/dbus","name":"dbus"},{"mountPath":"/host/etc/machine-id","name":"machine-id","readOnly":true},{"mountPath":"/run/xtables.lock","name":"xtables-lock"}]},{"env":[{"name":"HOSTNAME","valueFrom":{"fieldRef":{"apiVersion":"v1","fieldPath":"spec.nodeName"}}}],"image":"docker.io/weaveworks/weave-npc:2.8.1","name":"weave-npc","resources":{"requests":{"cpu":"50m","memory":"100Mi"}},"securityContext":{"privileged":true},"volumeMounts":[{"mountPath":"/run/xtables.lock","name":"xtables-lock"}]}],"dnsPolicy":"ClusterFirstWithHostNet","hostNetwork":true,"initContainers":[{"command":["/home/weave/init.sh"],"image":"docker.io/weaveworks/weave-kube:2.8.1","name":"weave-init","securityContext":{"privileged":true},"volumeMounts":[{"mountPath":"/host/opt","name":"cni-bin"},{"mountPath":"/host/home","name":"cni-bin2"},{"mountPath":"/host/etc","name":"cni-conf"},{"mountPath":"/lib/modules","name":"lib-modules"},{"mountPath":"/run/xtables.lock","name":"xtables-lock"}]}],"priorityClassName":"system-node-critical","restartPolicy":"Always","securityContext":{"seLinuxOptions":{}},"serviceAccountName":"weave-net","tolerations":[{"effect":"NoSchedule","operator":"Exists"},{"effect":"NoExecute","operator":"Exists"}],"volumes":[{"hostPath":{"path":"/var/lib/weave"},"name":"weavedb"},{"hostPath":{"path":"/opt"},"name":"cni-bin"},{"hostPath":{"path":"/home"},"name":"cni-bin2"},{"hostPath":{"path":"/etc"},"name":"cni-conf"},{"hostPath":{"path":"/var/lib/dbus"},"name":"dbus"},{"hostPath":{"path":"/lib/modules"},"name":"lib-modules"},{"hostPath":{"path":"/etc/machine-id","type":"FileOrCreate"},"name":"machine-id"},{"hostPath":{"path":"/run/xtables.lock","type":"FileOrCreate"},"name":"xtables-lock"}]}},"updateStrategy":{"type":"RollingUpdate"}}} creationTimestamp: "2021-07-03T09:55:33Z" generation: 1 labels: name: weave-net name: weave-net namespace: kube-system # ...
쿠버네티스 네트워크 (3) Pod - Svc 통신
아래 그림은
pod
과service
가 통신을 나타내는 구조이다.service
생성 시 ClusterIP를 할당 받으면 iptables에 적용한다. 그래서 각pod
으로 통신을 연결해줄 수 있다.쿠버네티스
는netfilter
를 통해 2-7계층까지 네트워크 통신을 지원한다. 한 번 이를 확인해보자. 터미널에 다음을 입력한다.$ kubectl get svc --all-namespaces NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 25d
"CLUSTER-IP" 대역대인
10.96.x.x
은service
리소스가 사용하는 대역이다. 이 대역대의 iptables를 확인해보자.$ sudo iptables -S -t nat | grep 10.96 # 53은 DNS 포트 -A KUBE-SERVICES -d 10.96.0.10/32 -p tcp -m comment --comment "kube-system/kube-dns:dns-tcp cluster IP" -m tcp --dport 53 -j KUBE-SVC-ERIFXISQEP7F7OF4 -A KUBE-SERVICES -d 10.96.0.10/32 -p tcp -m comment --comment "kube-system/kube-dns:metrics cluster IP" -m tcp --dport 9153 -j KUBE-SVC-JD5MR3NA4I4DYORP -A KUBE-SERVICES -d 10.96.0.1/32 -p tcp -m comment --comment "default/kubernetes:https cluster IP" -m tcp --dport 443 -j KUBE-SVC-NPX46M4PTMTKRN6Y -A KUBE-SERVICES -d 10.96.0.10/32 -p udp -m comment --comment "kube-system/kube-dns:dns cluster IP" -m udp --dport 53 -j KUBE-SVC-TCOU7JCQXEZGVUNU
여러 개가 체인처럼 엮여 있는 것을 볼 수 있는데, 그냥 이는 내부 구현이고 중요한 것은
pod
에서service
를 호출하게 되면,쿠버네티스
에 존재하는 내부 DNS 시스템에 의해서 연결된 다른pod
이 호출된다는 것이다.쿠버네티스 네트워크 (4) 외부 물리 클라이언트 통신
다음은 외부 클라이언트에서 서비스를 호출했을 때 나타나는 플로우이다.
클라이언트에서
LoadBalancer
를 통해 호출하게 되면 그 안에route table
에 의해서node
로, 그 후 안에 네트워크 인터페이스(eth0
)와netfilter
를 통해서service
가 호출되고 그 후pod
이 호출된다. 외부에서는 node와 연결되고 node 내에서는 pod-svc의 플로우가 동작하는 것이다.쿠버네티스 네트워크 (5) CoreDNS
pod
에서service
를 호출할 수 있는 이유는 바로CoreDNS
라는쿠버네티스
의 DNS 서버 역할을 하는 컴포넌트가 있기 때문이다.즉
CoreDNS
는 쿠버네티스 클러스터의 DNS 서버 역할을 수행한다. 역시pod
으로 구성되어서 동작하고 있으며. 각 미들웨어를 통해 로깅, 캐시, 쿠버네티스 질의하는 기능을 수행한다.일반적으로
service
를 다음과 같이 호출할 수 있다.<svc_name>.<ns_name>.svc.cluster.local 형식으로 도메인 획득 가능
이에 대한 실습을 진행한다. 먼저 "gurumee"라는 네임스페이스를 생성한다.
src/ch09/k8s/coredns-ns-gurumee.yaml)
apiVersion: v1 kind: Namespace metadata: creationTimestamp: null name: gurumee spec: {} status: {}
그 후,
Deployment
를 생성한다.src/ch09/k8s/coredns-simple-app-dep.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: simple-app-dep namespace: gurumee labels: app: simple-app spec: replicas: 3 selector: matchLabels: app: simple-app template: metadata: labels: app: simple-app spec: containers: - name: simple-app image: gurumee92/simple-app:v1 ports: - containerPort: 8080
그 다음
ClusterIP
형태로Service
를 통해Deployment
를 연결해준다.src/ch09/k8s/coredns-simple-app-svc.yaml
apiVersion: v1 kind: Service metadata: name: simple-app-svc namespace: gurumee spec: ports: - port: 8080 targetPort: 8080 selector: app: simple-app
그 후
nginx
를 기반으로pod
1개를 실행한다.$ kubectl run nginx --image=nginx
그 후 그
pod
에서curl
로svc_name.ns_name:8080
으로 호출해보자.$ kubectl exec -it nginx -- curl simple-app-svc.gurumee:8080 Hello World v1
이렇게 떴다면 성공이다.
쿠버네티스 스토리지 (1) 볼륨
"볼륨"은 컨테이너가 외부 스토리지에 액세스하고 공유하는 방법이다. 다음과 같은 방법이 있다.
- 임시 볼륨 : emptyDir (컨테이너 볼륨 공유)
- 로컬 볼륨 : hostPath, local (노드 관리 목적)
- 네트워크 볼륨 : NFS, glusterFS (외부 자원 공유 목적)
- 네트워크 볼륨 (클라우드) : awsEBS, gcePersistentDisk
이외에도 pvc, configMap 등이 있다.
쿠버네티스 스토리지 (2) EmptyDir
볼륨
EmptyDir
을 통해pod
간 볼륨을 공유하게끔 만들 수 있다. 이제 다음과 같이 스크립트를 하나 작성한다.#!/bin/sh trap "exit" SIGINT mkdir /var/htdocs SET=$(seq 0 99999) for i in $SET do echo "RUNNING loop seq $i" > /var/htdocs/index.html sleep 10 done
그리고 build 하기 전에
chmod 777
명령어를 주어서 실행 파일 권한을 주자Dockerfile
을 다음과 같이 만든다.FROM busybox:latest ADD count.sh /bin/count.sh ENTRYPOINT /bin/count.sh
그 후 자신의 ID로 이미지를 만들어서 push한다. 그 후 다음과 같이 리소스를 생성한다.
src/ch09/k8s/volume-empty-dir.yaml
... apiVersion: v1 kind: Pod metadata: name: volume-empty-dir spec: containers: - image: gurumee92/count name: html-generator volumeMounts: - mountPath: /var/htdocs/ name: html - image: httpd name: web-server volumeMounts: - mountPath: /usr/local/apache2/htdocs name: html readOnly: true ports: - containerPort: 80 volumes: - name: html emptyDir: {}
그 후
nginx
를 기반으로pod
1개를 실행한다.$ kubectl run nginx --image=nginx
그러면 다음의
pod
들이 생성되어진다.$ kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx 1/1 Running 0 2m55s 10.32.0.3 slave2 <none> <none> volume-empty-dir 2/2 Running 0 6m34s 10.32.0.2 slave2 <none> <none>
이제
nginx
포드에서volume-empty-dir
포드로curl
을 요청해보자.# 10.32.0.2 = volume-empty-dir IP $ kubectl exec -it nginx -- curl 10.32.0.2 RUNNING loop seq 48
이제 만들어진지 480초가 지났다는 의미이다. 10초 간격으로 계속
curl
을 요청하면 "seq" 값이 변하는 것을 확인할 수 있다.쿠버네티스 스토리지 (3) Hostpath
hostPath
볼륨은 노드와 포드간 데이터 공유를 위해서 만들어지는 볼륨이다. 해당 노드의 파일 시스템에 있는 파일 혹은 디렉토리를 지정하기 때문에 노드에 떠 있는 포드들하고만 연결이 가능하다.주로 노드의 모니터링을 위해서 많이 사용된다. 이제 실습을 진행해보자. 먼저 워커 노드에서 다음을 명령한다.
## sudo 권한 획득 $ sudo -i ## 디렉토리 생성 # mkdir -p /var/htdocs # echo "$HOSTNAME" > /var/htdocs/index.html
그 후 다음 리소스를 생성한다.
apiVersion: v1 kind: Pod metadata: name: volume-hostpath spec: containers: - image: httpd name: web-server volumeMounts: - mountPath: /usr/local/apache2/htdocs name: html readOnly: true ports: - containerPort: 80 volumes: - name: html hostPath: path: /var/htdocs type: Directory
그 다음 아래 명령어를 입력하여 포드가 어디 노드에 생성되었는지 확인한다.
$ kubectl get pod -o wide -w NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES volume-hostpath 1/1 Running 0 15s 10.40.0.3 slave1 <none> <none>
워커 노드 1("slave1")에 포드가 위치하고 있다. 이제 이 포드를 접속할 수 있도록
port-forward
로 포트를 개방한다.$ kubectl port-forward hostpath-http 8888:80 Forwarding from 127.0.0.1:8888 -> 80 Forwarding from [::1]:8888 -> 80 Handling connection for 8888
이제 새 탭을 열어 다음을 입력한다.
$ curl localhost:8888 slave1
"slave1"이 뜨는 것을 확인할 수 있다.
728x90'레거시 > 데브옵스(DevOps)를 위한 쿠버네티스 마스터' 카테고리의 다른 글
11. 애플리케이션 스케줄링과 라이프사이클 관리 (1) (0) 2021.08.17 10. 쿠버네티스 핵심 개념 (5) (0) 2021.08.14 08. 쿠버네티스 핵심 개념 (3) (0) 2021.07.25 07. 쿠버네티스 핵심 개념 (2) (0) 2021.07.14 06. 쿠버네티스 핵심 개념 (1) (0) 2021.07.09