1. 서비스
1.1 클러스터 외부 트래픽 받는 방법
Nodeport | |
Load Balancer | |
Ingress |
1.2 서비스 개념
파드를 통해 사용자에게 서비스를 제공을 할 수 있으나, 파드에 장애가 발생했을 경우 서비스에 가용성을 보장할 수가 없기 때문에, Service를 통해 가용성을 보장합니다
Kubernetes Service를 통해 파드의 로드밸런싱이 가능하며, 파드에 문제가 발생하여 정상적으로 구동시킬 수 없는 경우에는 Service가 자동으로 문제가 발생한 파드는 Service의 EndPoint에서 제외됩니다.
문제가 생겼던 Pod는 Deployment를 통해 다른 IP, Name으로 다시 구동되며, Service의 EndPoint에 자동으로 추가되어, 기존상태를 유지합니다.
(1) ClusterIP
서비스를 클러스터 내부 IP에 노출합니다.
클러스터 내에서만 서비스에 도달할 수 있으며, 서비스 타입의 기본값입니다.
6/00-svc-clusterip.yaml
apiVersion: v1 kind: Pod metadata: name: nginx labels: app.kubernetes.io/name: proxy spec: containers: - name: nginx image: nginx:stable ports: - containerPort: 80 name: http-web-svc --- apiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: app.kubernetes.io/name: proxy ports: - name: name-of-service-port protocol: TCP port: 80 targetPort: http-web-svc
root@cp-k8s:~/2024_k8s/edu/6# k get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3h16m nginx-service ClusterIP 10.103.98.179 <none> 80/TCP 99s root@cp-k8s:~/2024_k8s/edu/6# curl 10.103.98.179 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
(2) NodePort
고정포트로 각 노드의 IP에 서비스를 노출합니다.
NodePort 서비스가 라우팅되는 ClusterIP가 자동으로 생성되며 NodeIP:NodePort를 요청하며, 서비스 외수에서 NodePort 서비스에 접속할 수 있습니다.
6/01-svc-nodeport.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: my-service-nodeport spec: type: NodePort selector: app: nginx ports: # 기본적으로 그리고 편의상 `targetPort` 는 `port` 필드와 동일한 값으로 설정된다. - port: 80 targetPort: 80 # 선택적 필드 # 기본적으로 그리고 편의상 쿠버네티스 컨트롤 플레인은 포트 범위에서 할당한다(기본값: 30000-32767) nodePort: 30007
root@cp-k8s:~/2024_k8s/edu# curl localhost:30007 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto;
root@cp-k8s:~/2024_k8s/edu# cat /etc/hosts 127.0.0.1 localhost 192.168.1.10 cp-k8s 192.168.1.101 w1-k8s 192.168.1.102 w2-k8s 192.168.1.103 w3-k8s root@cp-k8s:~/2024_k8s/edu# curl 192.168.1.102:30007 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p>
(3) LoadBalancer
클라우드 공급자의 로드 밸런서를 사용하여 서비스를 외부에 노출시킵니다.
클러스터 외부 IP를 가지고 있기 때문에, 클러스터 외부에서 접근 가능합니다.
외부 로드 밸런서가 라우팅되는 NodePort와 ClusterIP 서비스가 자동으로 생성됩니다.
프라이빗 클라우드 환경에서는 MetalLB를 이용하여 LoadBalancer 타입의 서비스를 이용 할 수 있습니다.
6/02-svc-loadbalancer.yaml
--- apiVersion: apps/v1 kind: Deployment metadata: name: nginx2-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx2-service spec: type: LoadBalancer selector: app: nginx ports: - protocol: TCP port: 8088 targetPort: 80
root@cp-k8s:~/2024_k8s/edu/6# k get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3h22m my-service-nodeport NodePort 10.100.38.132 <none> 80:30007/TCP 5m1s nginx-service ClusterIP 10.103.98.179 <none> 80/TCP 8m1s nginx2-service LoadBalancer 10.100.170.165 192.168.1.11 8088:30843/TCP 7s
(4) ExternalName
값과 함께 CNAME 레코드를 리턴하여, 서비스를 externalName 필드의 콘텐츠에 매핑합니다.
클러스터 내에서 외부 서비스를 이름으로 참조할 수 있게 해주는 서비스 타입입니다.
내부 클러스터에서 외부 DNS 이름을 내부 서비스로 변환하여 접근 가능하게 됩니다.
6/03-svc-externalname.yaml
apiVersion: v1 kind: Service metadata: name: my-database spec: type: ExternalName externalName: db.example.com
이 서비스는
my-database
라는 이름으로 정의되며, 실제로는db.example.com
에 대한 DNS 쿼리로 변환됩니다.클러스터 내부의 애플리케이션에서
my-database
라는 이름을 사용하여 외부의db.example.com
에 접근할 수 있습니다.
1.3 MetalLB 설치(Private 환경에서의 로드 밸런서)
(1) metallb 네임스페이스 생성 (이미 생성해 두었음)
[root@m-k8s vagrant]# kubectl create ns metallb-system
(2) metallb 설치 (이미 생성해 두었음)
6/04-metallb-install.txt
[root@m-k8s vagrant]# kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.11/config/manifests/metallb-native.yaml namespace/metallb-system configured customresourcedefinition.apiextensions.k8s.io/addresspools.metallb.io created customresourcedefinition.apiextensions.k8s.io/bfdprofiles.metallb.io created customresourcedefinition.apiextensions.k8s.io/bgpadvertisements.metallb.io created customresourcedefinition.apiextensions.k8s.io/bgppeers.metallb.io created customresourcedefinition.apiextensions.k8s.io/communities.metallb.io created customresourcedefinition.apiextensions.k8s.io/ipaddresspools.metallb.io created customresourcedefinition.apiextensions.k8s.io/l2advertisements.metallb.io created serviceaccount/controller created serviceaccount/speaker created role.rbac.authorization.k8s.io/controller created role.rbac.authorization.k8s.io/pod-lister created clusterrole.rbac.authorization.k8s.io/metallb-system:controller created clusterrole.rbac.authorization.k8s.io/metallb-system:speaker created rolebinding.rbac.authorization.k8s.io/controller created rolebinding.rbac.authorization.k8s.io/pod-lister created clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller created clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker created configmap/metallb-excludel2 created
(3) 설치 확인
[root@m-k8s vagrant]# kubectl get all -n metallb-system NAME READY STATUS RESTARTS AGE pod/controller-5567fb94fd-mn6jg 1/1 Running 0 2m4s pod/speaker-2pxpd 1/1 Running 0 2m3s pod/speaker-lpnmf 1/1 Running 0 2m3s pod/speaker-q8hvp 1/1 Running 0 2m3s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/webhook-service ClusterIP 10.108.47.177 <none> 443/TCP 2m4s NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE daemonset.apps/speaker 3 3 3 3 3 kubernetes.io/os=linux 2m4s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/controller 1/1 1 1 2m4s NAME DESIRED CURRENT READY AGE replicaset.apps/controller-5567fb94fd 1 1 1 2m4s [root@m-k8s vagrant]# kubectl get pod -n metallb-system -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES controller-5567fb94fd-mn6jg 1/1 Running 0 2m13s 172.16.221.164 w1-k8s <none> <none> speaker-2pxpd 1/1 Running 0 2m12s 192.168.1.102 w2-k8s <none> <none> speaker-lpnmf 1/1 Running 0 2m12s 192.168.1.10 m-k8s <none> <none> speaker-q8hvp 1/1 Running 0 2m12s 192.168.1.101 w1-k8s <none> <none>
(4) IPAddressPool 생성
외부로 노출할 VIP에 대한 범위를 지정합니다.
아이피 대역은 실제 External IP로 사용할 IP를 적어줍니다. (노드에서 할당이 가능하여야 함)
6/05-metallb-ipaddresspool.yaml
apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: first-pool namespace: metallb-system spec: addresses: - 192.168.1.150-192.168.1.200 --- apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: first-pool-advertisement namespace: metallb-system spec: ipAddressPools: - first-pool
root@cp-k8s:~/2024_k8s/edu/6# k get IPAddressPool -n metallb-system NAME AUTO ASSIGN AVOID BUGGY IPS ADDRESSES first-pool true false ["192.168.1.150-192.168.1.200"]
생성
kubectl apply -f 05-metallb-ipaddresspool.yaml ipaddresspool.metallb.io/first-pool created l2advertisement.metallb.io/first-pool-advertisement created
Loadbalancer 타입으로 서비스를 생성해보고, External IP가 할당되었는지 확인해봅니다.
2. Ingress
2.1 Ingress Controller
인그레스 리소스를 해석하고, 이를 실제 네트워크 트래픽 관리로 변환하는 쿠버네티스 구성 요소입니다.
다양한 종류의 인그레스 컨트롤러가 존재하며, 각 컨트롤러는 특정 구현 및 기능을 제공합니다.
2.2 Ingress
클러스터 내의 서비스에 대한 외부 접근을 관리하는 API 오브젝트이며, 일반적으로 HTTP를 관리합니다.
인그레스는 클러스터 외부에서 클러스터 내부 서비스로 HTTP와 HTTPS 경로를 노출시킵니다.
인그레스 컨트롤러가 있어야 인그레스를 충족할 수 있으며, 인그레스 리소스만 생성한다면 효과가 없습니다.
대표적인 인그레스 컨트롤러: ingress-nginx
(1) Ingress의 필요성
ingress를 이용하면 한 가지의 외부 Service로 도메인, 서브도메인 기반의 여러가지 백엔드 서비스에 연결 할 수 있는 장점이 있습니다.
ingress를 이용하면 ClusterIP 타입으로 외부에서 접근 할 수 있습니다.
ingress는 도메인기반, 서브도메인기반 등을 이용할 수 있으며 SSL을 지원합니다.
(2) Nginx Ingress Controller 설치
Private 환경에서 인그레스를 사용하기 위해 컨트롤러를 설치합니다.
6/06-ingress-nginx-install.txt
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.2/deploy/static/provider/cloud/deploy.yaml namespace/ingress-nginx created serviceaccount/ingress-nginx created serviceaccount/ingress-nginx-admission created role.rbac.authorization.k8s.io/ingress-nginx created role.rbac.authorization.k8s.io/ingress-nginx-admission created clusterrole.rbac.authorization.k8s.io/ingress-nginx created clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created rolebinding.rbac.authorization.k8s.io/ingress-nginx created rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created configmap/ingress-nginx-controller created service/ingress-nginx-controller created service/ingress-nginx-controller-admission created deployment.apps/ingress-nginx-controller created job.batch/ingress-nginx-admission-create created job.batch/ingress-nginx-admission-patch created ingressclass.networking.k8s.io/nginx created validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created
(3) 서비스 LoadBalancer 타입 설정
nginx의 svc는 편의상 이전단계에서 생성한 LoadBalancer 타입으로 지정해주도록 합니다
kubectl edit svc/ingress-nginx-controller -n ingress-nginx (version이 올라오면서 LoadBalncer가 바로 잡힘) spec: type: LoadBalancer // ClusterIP -> LoadBalancer 확인 kubectl get svc -A ingress-nginx ingress-nginx-controller LoadBalancer 10.109.69.139 192.168.1.151 80:31100/TCP,443:31761/TCP 83s
(4) 생성된 lb의 Externel IP를 이용하여 통신을 시도 합니다.
현재 연결된 백엔드 svc가 없으므로 404 Not Found를 확인 할 수 있습니다.
C:\Users\khoj>curl 192.168.1.151 <html> <head><title>404 Not Found</title></head> <body> <center><h1>404 Not Found</h1></center> <hr><center>nginx</center> </body> </html>
(5) Ingress 백엔드로 사용 할 서비스 생성
테스트를 위하여 총 2가지의 pod와 ClusterIP 타입의 Service를 생성합니다.
아래 deployment는 podname을 확인하도록 nginx 가 아닌 echoserver 이미지를 사용 합니다.
6/07-ingress-backend.yml
--- apiVersion: apps/v1 kind: Deployment metadata: name: nginx1-deployment spec: selector: matchLabels: app: nginx1 replicas: 1 template: metadata: labels: app: nginx1 spec: containers: - name: my-echo image: jmalloc/echo-server --- apiVersion: v1 kind: Service metadata: name: nginx-service-clusterip labels: name: nginx-service-clusterip spec: type: ClusterIP ports: - port: 80 # Cluster IP targetPort: 8080 # Application port protocol: TCP name: http selector: app: nginx1 --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx2-deployment spec: selector: matchLabels: app: nginx2 replicas: 1 template: metadata: labels: app: nginx2 spec: containers: - name: my-echo image: jmalloc/echo-server --- apiVersion: v1 kind: Service metadata: name: nginx2-service-clusterip labels: name: nginx2-service-clusterip spec: type: ClusterIP ports: - port: 80 # Cluster IP targetPort: 8080 # Application port protocol: TCP name: http selector: app: nginx2
(6) 위에서 만든 yaml을 이용하여 pod 및 svc를 생성 합니다
[root@m-k8s vagrant]# k apply -f 07-ingress-backend.yml deployment.apps/nginx1-deployment created service/nginx-service-clusterip created deployment.apps/nginx2-deployment created service/nginx2-service-clusterip created
pod와 Service가 잘 생성되었으며, 생성된 Service로 통신 시도 시 연결된 Pod 이름을 확인합니다.
kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-service-clusterip ClusterIP 10.105.151.217 <none> 80/TCP 20s nginx2-service-clusterip ClusterIP 10.106.195.22 <none> 80/TCP 20s kubectl get pod NAME READY STATUS RESTARTS AGE nginx1-deployment-545749bf4d-h7qfx 1/1 Running 0 29s nginx2-deployment-56d6f87fc9-9m7h2 1/1 Running 0 29s [root@m-k8s vagrant]# curl 10.105.151.217 Request served by nginx1-deployment-8458b98748-75hlx GET / HTTP/1.1 Host: 10.105.151.217 Accept: */* User-Agent: curl/7.29.0 curl 10.98.154.210 [root@m-k8s vagrant]# curl 10.106.195.22 Request served by nginx2-deployment-767fbbfc95-g42jr GET / HTTP/1.1 Host: 10.106.195.22 Accept: */* User-Agent: curl/7.29.0
(7) L7기반의 라우팅을 해주는 ingress정책을 생성 합니다
ingress svc로 들어온 패킷의 L7레이어 즉 도메인 주소를 체크하여 트래픽을 전달합니다.
도메인 주소가 a.com이라면 nginx-service-clusterip로 연결합니다.
도메인 주소가 b.com이라면 nginx2-service.clusterip로 연결합니다.
6/08-ingress.yaml
--- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress spec: ingressClassName: nginx rules: - host: "a.com" http: paths: - pathType: Prefix path: "/" backend: service: name: nginx-service-clusterip port: number: 80 - host: "b.com" http: paths: - pathType: Prefix path: "/" backend: service: name: nginx2-service-clusterip port: number: 80
(8) ingress정책을 생성 합니다
[root@m-k8s ~]# kubectl create -f 08-ingress.yaml ingress.networking.k8s.io/ingress created
(9) ingress가 제대로 설정되어있는지 확인 합니다.
[root@m-k8s vagrant]# k get ing NAME CLASS HOSTS ADDRESS PORTS AGE ingress nginx a.com,b.com 172.20.200.101 80 5m23s
(10) 클러스터 외부에서 host파일을 변조하여 a.com과 b.com의 주소를 LB external ip로 지정한 후 접속을 시도하여 L7 기반의 로드밸런싱+라우팅이 제대로 작동되는지 확인 합니다.
노트북의 host파일에 아래와 같은 설정을 합니다
노트패드를 관리자권한으로 열어서 아래폴더를 수정하면 됩니다.
c:Windows/System32/drivers/etc/hosts
cat /etc/hosts |grep com 192.168.1.101 a.com 192.168.1.101 b.com
이제 노트북에서 a.com와 b.com을 호출 합니다/
$curl a.com Hostname: nginx1-deployment-545749bf4d-h7qfx Pod Information: -no pod information available- Server values: server_version=nginx: 1.13.3 - lua: 10008 Request Information: client_address=10.233.235.153 method=GET real path=/ query= request_version=1.1 request_uri=http://a.com:8080/ Request Headers: accept=*/* host=a.com user-agent=curl/7.71.1 x-forwarded-for=192.168.9.237 x-forwarded-host=a.com x-forwarded-port=80 x-forwarded-proto=http x-real-ip=192.168.9.237 x-request-id=6b0169dcff0fd35fa780b600967dffb1 x-scheme=http Request Body: -no body in request- $ curl b.com Hostname: nginx2-deployment-56d6f87fc9-9m7h2 Pod Information: -no pod information available- Server values: server_version=nginx: 1.13.3 - lua: 10008 Request Information: client_address=10.233.235.153 method=GET real path=/ query= request_version=1.1 request_uri=http://b.com:8080/ Request Headers: accept=*/* host=b.com user-agent=curl/7.71.1 x-forwarded-for=192.168.9.237 x-forwarded-host=b.com x-forwarded-port=80 x-forwarded-proto=http x-real-ip=192.168.9.237 x-request-id=2a6b6ffa72efe6b80cae87dcaa51db98 x-scheme=http Request Body: -no body in request-
nginx ip로 직접 호출을 해봅니다
레이어상 도메인정보가 없으므로 분기되지 않고 404 페이지가 나타 납니다.
curl 172.20.200.101 <html> <head><title>404 Not Found</title></head> <body> <center><h1>404 Not Found</h1></center> <hr><center>nginx</center> </body> </html>
ingress 설정 시 아래와 같이 서브도메인으로 분기도 가능하므로 활용하도록 합니다
009.ing2.yaml
--- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress2 namespace: default spec: ingressClassName: nginx rules: - host: a.com http: paths: - pathType: Prefix path: /a backend: service: name: nginx-service-clusterip port: number: 80 - pathType: Prefix path: /b backend: service: name: nginx2-service-clusterip port: number: 80
kubectl apply -f 009.ing2.yaml
위와같이 설정한다면 a.com/a 로 들어온 패킷은 nginx-service-clusterip로 라우팅 됩니다.
a.com/b 로 들어온 패킷은 nginx2.service-clusterip로 라우팅 됩니다
curl a.com/a Hostname: nginx1-deployment-545749bf4d-mgnt8 Pod Information: -no pod information available- Server values: server_version=nginx: 1.13.3 - lua: 10008 Request Information: client_address=10.233.228.72 method=GET real path=/a query= request_version=1.1 request_uri=http://a.com:8080/a Request Headers: accept=*/* host=a.com user-agent=curl/7.71.1 x-forwarded-for=192.168.9.38 x-forwarded-host=a.com x-forwarded-port=80 x-forwarded-proto=http x-real-ip=192.168.9.38 x-request-id=6c98f42fba35104849f57ce30a57b2c3 x-scheme=http Request Body: -no body in request- curl a.com/b Hostname: nginx2-deployment-56d6f87fc9-55gsg Pod Information: -no pod information available- Server values: server_version=nginx: 1.13.3 - lua: 10008 Request Information: client_address=10.233.228.72 method=GET real path=/b query= request_version=1.1 request_uri=http://a.com:8080/b Request Headers: accept=*/* host=a.com user-agent=curl/7.71.1 x-forwarded-for=192.168.9.38 x-forwarded-host=a.com x-forwarded-port=80 x-forwarded-proto=http x-real-ip=192.168.9.38 x-request-id=b5c8a4dfef21d5acc50763232a7f02c1 x-scheme=http Request Body: -no body in request-
ingress의 기능은 msa아키텍처에 많은 도움을 줄 수 있습니다
ingress를 잘 활용 하면 웹서버에 페이지 별로 다른 deploy나 pod그룹을 이용하여 효율적으로 자원을 분배하고 서비스를 배치 하여 관리 할 수 있습니다
ingress의 기능은 msa아키텍처에 많은 도움을 줄 수 있으며, 웹서버에 페이지 별로 다른 deploy나 pod그룹을 이용하여 효율적으로 자원을 분배하고 서비스를 배치 하여 관리 할 수 있습니다.
3. 파드 네트워크
참고) 문서 상 노드 이름 및 역할
CNI 종류 및 구성방식에 따라 트래픽 전송 방식에 차이가 있습니다.
어떤 식으로 트래픽이 전달되는지 확인하는 방법을 설명합니다.
sung-ubuntu01 - Control Plane #1
sung-ubuntu02 - Control Plane #2
sung-ubuntu03 - Control Plane #3
sung-ubuntu04 - Worker Node #1
sung-ubuntu05 - Worker Node #2
3.1 파드 네크워크
도커에서 POD 네트워크 설명할 경우와 인터페이스 이름이 다릅니다.
도커의 역할
참고1) https://www.docker.com/products/container-runtime/
3.2 단일 컨테이너 파드
Pod (Single Container)의 네트워크 설정을 확인합니다.
6/09-pod-network-ubuntu.yaml
apiVersion: v1 kind: Pod metadata: name: ubuntu-test spec: containers: - name: ubuntu image: ubuntu:20.04 command: ["/bin/sleep", "3650d"] imagePullPolicy: IfNotPresent volumeMounts: - mountPath: /cache name: cache-volume volumes: - name: cache-volume emptyDir: {} restartPolicy: Always dnsConfig: nameservers: - 8.8.8.8
파드 네트워크 구성에 대해 알아봅니다.
root@sung-ubuntu01:~/tmp# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES ubuntu-test 1/1 Running 0 6m20s 10.233.99.1 sung-ubuntu04 <none> <none> ###POD 접속 root@sung-ubuntu01:~/tmp# kubectl exec -it ubuntu-test -- bash root@ubuntu-test:/# root@ubuntu-test:/# ping 8.8.8.8 PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_seq=1 ttl=54 time=39.6 ms 64 bytes from 8.8.8.8: icmp_seq=2 ttl=54 time=38.1 ms 64 bytes from 8.8.8.8: icmp_seq=3 ttl=54 time=38.8 ms 64 bytes from 8.8.8.8: icmp_seq=4 ttl=54 time=39.3 ms # apt update # apt install -y net-tools iputils-ping **# 컨테이너의 네트워크 인터페이스 확인** # root@ubuntu-test:/# ifconfig -a eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1480 inet 10.233.99.1 netmask 255.255.255.255 broadcast 0.0.0.0 ether 06:55:84:5a:ac:6b txqueuelen 0 (Ethernet) RX packets 5718 bytes 24026416 (24.0 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3690 bytes 250168 (250.1 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 loop txqueuelen 1000 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 #노드와 파드 사이를 연결하는 인터페이스입니다. tunl0: flags=128<NOARP> mtu 1480 tunnel txqueuelen 1000 (IPIP Tunnel) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 * loopback ip : host 자신을 가리키는 논리적인 인터페이스 **#노드 네트워크 확인** root@sung-ubuntu04:~# ifconfig -a ... tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480 inet 10.233.99.0 netmask 255.255.255.255 tunnel txqueuelen 1000 (IPIP Tunnel) RX packets 60 bytes 8528 (8.5 KB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 66 bytes 4476 (4.4 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 *mtu 1480인 이유? IPIP 터널을 사용하고 있기 때문에, 캡슐화된 패킷의 크기는 원래 패킷보다 더 크기 때문에 MTU 조절이 필요하다 1480인 이유는 캡슐화된 패킷이 Ethernet 패킷에 포함될 때 전체 크기가 1500을 초과하지 않도록 하기 위해서이다.
3.3 멀티 컨테이너 파드
Pod (Multi Container)의 네트워크 설정 확인을 확인합니다.
6/10-pod-network-multicon.yaml
apiVersion: v1 kind: Pod metadata: name: multi-container spec: containers: - name: ubuntu image: ubuntu:20.04 command: ["/bin/sleep", "3650d"] imagePullPolicy: IfNotPresent volumeMounts: - mountPath: /cache name: cache-volume - name: nginx image: nginx ports: - containerPort: 80 volumes: - name: cache-volume emptyDir: {} restartPolicy: Always dnsConfig: nameservers: - 8.8.8.8 root@sung-ubuntu01:~/tmp# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES multi-container 2/2 Running 0 25m 10.233.78.3 sung-ubuntu05 <none> <none> ubuntu-test 1/1 Running 0 57m 10.233.99.1 sung-ubuntu04 <none> <none>
컨테이너 내부에서 네트워크 흐름을 알아봅니다.
**#ubuntu 컨테이너 접속** root@sung-ubuntu01:~/tmp# kubectl exec -it multi-container -c ubuntu -- bash ### POD 안에서 # apt update # apt install -y net-tools iputils-ping root@multi-container:/# ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1480 inet 10.233.78.3 netmask 255.255.255.255 broadcast 0.0.0.0 ether ce:de:b3:90:c1:a7 txqueuelen 0 (Ethernet) RX packets 5206 bytes 23989810 (23.9 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3160 bytes 213900 (213.9 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 loop txqueuelen 1000 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 **# nginx 컨테이너 접속** root@sung-ubuntu01:~/tmp# kubectl exec -it multi-container -c nginx -- bash ### POD 안에서 실행 # apt update # apt install -y net-tools iputils-ping root@multi-container:/# ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1480 inet 10.233.78.3 netmask 255.255.255.255 broadcast 0.0.0.0 ether ce:de:b3:90:c1:a7 txqueuelen 0 (Ethernet) RX packets 6287 bytes 33013014 (31.4 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3935 bytes 267591 (261.3 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 loop txqueuelen 1000 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
노드 네트워크 확인
root@sung-ubuntu05:~# ifconfig -a calib4cfe5eb958: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1480 inet6 fe80::ecee:eeff:feee:eeee prefixlen 64 scopeid 0x20<link> ether ee:ee:ee:ee:ee:ee txqueuelen 0 (Ethernet) RX packets 3935 bytes 267591 (267.5 KB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 6287 bytes 33013014 (33.0 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255 ether 02:42:6a:17:c5:80 txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 ens3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.110.104 netmask 255.255.0.0 broadcast 192.168.255.255 inet6 fe80::f816:3eff:fe54:bc4 prefixlen 64 scopeid 0x20<link> ether fa:16:3e:54:0b:c4 txqueuelen 1000 (Ethernet) RX packets 1353299 bytes 1304887824 (1.3 GB) RX errors 0 dropped 88603 overruns 0 frame 0 TX packets 191206 bytes 20789350 (20.7 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 kube-ipvs0: flags=130<BROADCAST,NOARP> mtu 1500 inet 10.233.0.1 netmask 255.255.255.255 broadcast 0.0.0.0 ether 66:2d:b3:6c:50:9a txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 162061 bytes 22298211 (22.2 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 162061 bytes 22298211 (22.2 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 nodelocaldns: flags=130<BROADCAST,NOARP> mtu 1500 inet 169.254.25.10 netmask 255.255.255.255 broadcast 0.0.0.0 ether 16:84:53:46:fe:65 txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480 #터널 인터페이스 inet 10.233.78.0 netmask 255.255.255.255 tunnel txqueuelen 1000 (IPIP Tunnel) RX packets 69 bytes 9380 (9.3 KB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 76 bytes 5125 (5.1 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
multi-container 관련 컨테이너 확인
root@sung-ubuntu05:~# docker ps | grep multi-container 64c1938850a2 nginx "/docker-entrypoint.…" 26 minutes ago Up 25 minutes k8s_nginx_multi-container_default_1d0e0776-18b1-4c7f-b05f-20b8c54fb230_0 b4c4045ac777 ubuntu "/bin/sleep 3650d" 26 minutes ago Up 26 minutes k8s_ubuntu_multi-container_default_1d0e0776-18b1-4c7f-b05f-20b8c54fb230_0 1eaedb9c9d55 k8s.gcr.io/pause:3.5 "/pause" 27 minutes ago Up 26 minutes k8s_POD_multi-container_default_1d0e0776-18b1-4c7f-b05f-20b8c54fb230_0
Pause Container
파드 내부의 container들을 위한 일종의 '부모 container' 로서의 역할을 수행합니다.
파드가 실행될 때 Pause Container가 먼저 실행되고 Pause Container의 리눅스 네임스페이스를 파드 내부의 모든 컨테이너들이 상속받아서 사용합니다.
Container들의 부모 프로세스가 Pause Container인 리눅스 네임스페이스에 속하기 때문에 localhost 통신이 가능합니다.
리눅스 namespace
리눅스 커널에서 제공 기능으로 Container의 기반이 되는 기술. 하나의 시스템에서 프로세스를 격리시킬 수 있는 가상화 기술입니다.
3.4 파드 간 통신
Pod 간 route 경로 확인
root@sung-ubuntu01:~/tmp# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES multi-container 2/2 Running 0 25m 10.233.78.3 sung-ubuntu05 <none> <none> ubuntu-test 1/1 Running 0 57m 10.233.99.1 sung-ubuntu04 <none> <none> #ubuntu-test root@ubuntu-test:/# apt install traceroute root@ubuntu-test:/# traceroute 10.233.78.3 traceroute to 10.233.78.3 (10.233.78.3), 30 hops max, 60 byte packets 1 192.168.110.103 (192.168.110.103) 0.202 ms 0.032 ms 0.028 ms #sung-ubuntu04 ens3 2 10.233.78.0 (10.233.78.0) 1.169 ms 0.990 ms 0.928 ms #sung-ubuntu05 tunl0 3 10.233.78.3 (10.233.78.3) 1.096 ms 1.111 ms 1.087 ms #multi-container IP
노드 route table 확인
root@sung-ubuntu04:~# route Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface default _gateway 0.0.0.0 UG 100 0 0 ens3 10.233.78.0 sung-ubuntu05.c 255.255.255.0 UG 0 0 0 tunl0 10.233.91.0 sung-ubuntu02.c 255.255.255.0 UG 0 0 0 tunl0 10.233.95.0 sung-ubuntu01.c 255.255.255.0 UG 0 0 0 tunl0 10.233.99.0 0.0.0.0 255.255.255.0 U 0 0 0 * 10.233.99.1 0.0.0.0 255.255.255.255 UH 0 0 0 calie3df4d89b13 10.233.99.2 0.0.0.0 255.255.255.255 UH 0 0 0 calia85a668c715 10.233.112.0 sung-ubuntu03.c 255.255.255.0 UG 0 0 0 tunl0 169.254.169.254 192.168.51.110 255.255.255.255 UGH 100 0 0 ens3 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0 192.168.0.0 0.0.0.0 255.255.0.0 U 0 0 0 ens3 root@sung-ubuntu04:~# cat /etc/hosts ... # Ansible inventory hosts BEGIN 192.168.110.100 sung-ubuntu01.cluster.local sung-ubuntu01 192.168.110.101 sung-ubuntu02.cluster.local sung-ubuntu02 192.168.110.102 sung-ubuntu03.cluster.local sung-ubuntu03 192.168.110.103 sung-ubuntu04.cluster.local sung-ubuntu04 192.168.110.104 sung-ubuntu05.cluster.local sung-ubuntu05
참고
https://kubernetes.io/ko/docs/concepts/cluster-administration/networking/
4. CoreDNS
4.1 CoreDNS 주요 플러그인
(1) kubernetes
Kubernetes 클러스터 내의 서비스와 파드를 위한 DNS 서비스를 제공합니다.
(2) forward
DNS 요청을 외부 DNS 서버로 포워딩합니다.
(3) cache
DNS 응답을 캐싱하여 성능을 향상시킵니다.
(4) loadbalance
DNS 응답을 라운드 로빈 방식으로 로드 밸런싱합니다.
CoreDNS 기본 설정
6/11-coredns-cm.yaml
apiVersion: v1 kind: ConfigMap metadata: name: coredns namespace: kube-system data: Corefile: | .:53 { errors health ready kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa } prometheus :9153 forward . /etc/resolv.conf cache 30 loop reload loadbalance }
4.2 CoreDNS 설정에서 외부 DNS 서버 추가
(1) 설정 수정
kubectl -n kube-system edit configmap coredns
(2) 외부 DNS 서버 추가
forward . 192.168.255.100:53
apiVersion: v1 kind: ConfigMap metadata: name: coredns namespace: kube-system data: Corefile: | .:53 { errors health ready kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa } prometheus :9153 forward . 192.168.255.100:53 cache 30 loop reload loadbalance }
(3) 설정 적용을 위한 coredns 파드 재시작
kubectl -n kube-system rollout restart deployment coredns
4.3 특정 도메인 호출 시 외부 IP로 포워딩
webservice1.com 도메인 호출시 클러스터 외부IP(172.16.0.3)로 포워딩 설정
(1) 설정 수정
kubectl -n kube-system edit configmap coredns
(2) 특정 도메인 목적지 추가
host {} 항목을 추가합니다.
apiVersion: v1 kind: ConfigMap metadata: name: coredns namespace: kube-system data: Corefile: | .:53 { errors health ready kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa } prometheus :9153 forward . /etc/resolv.conf cache 30 loop reload loadbalance hosts { 172.16.0.3 webservice1.com fallthrough } }
(3) 설정 적용을 위한 coredns 파드 재시작
kubectl -n kube-system rollout restart deployment coredns
4.4 특정 도메인 호출 시 도메인 이름 변경
webservice1.com 도메인 호출시 클러스터 외부IP(172.16.0.3)로 포워딩 설정
(1) 설정 수정
kubectl -n kube-system edit configmap coredns
(2) rewrite 플러그인 내용 추가
[
web-service.cluster.local
] 요청을 [webservice1.com
]로 변경하여 처리
apiVersion: v1 kind: ConfigMap metadata: name: coredns namespace: kube-system data: Corefile: | .:53 { errors health ready kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa } prometheus :9153 forward . /etc/resolv.conf cache 30 loop reload loadbalance rewrite name web-service.cluster.local webservice1.com }
(3) 설정 적용을 위한 coredns 파드 재시작
kubectl -n kube-system rollout restart deployment coredns