Kubernetes의 네트워크 구성
쿠버네티스의 네트워크 구성에서 중요한 4가지 항목은 다음과 같다.
- 고도로 결합된(Highly-coupled) 컨테이너 간의 통신
- 파드와 파드 사이의 통신
- 파드와 서비스 사이의 통신
- 외부와의 통신
이 중 파드와 파드 사이의 통신을 위한 CNI의 역할에 대해 정리해보자
CNI 플러그인이란?
컨테이너 간 통신을 위한 인터페이스를 설정하는 플러그인이다.
쿠버네티스는 kubenet이라는 자체 CNI 플러그인을 기본제공하고
Calico, Weave, Cilium 등과 같은 다양한 서드파티 CNI 플러그인들이 존재함
→ 보통 서드 파티 플러그인을 사용하는데, 기본 제공 kubenet의 기능이 상당히 제한적이기 때문임
본 스터디 실습에서는 AWS 기반 클러스터를 사용하므로 AWS에서 제공하는 VPC CNI를 사용한다.
VPC CNI가 다른 CNI와 다른 점이 있다면,
네트워크의 원활한 성능 보장을 위해 노드와 파드가 같은 대역대의 IP 주소를 사용한다는 점이다.

Calico CNI의 경우 오버레이 네트워크(VXLAN, IP-IP)을 사용한다.
오버레이 네트워크란 노드끼리 통신할 때 데이터를 캡슐화하여 같은 LAN처럼 통신하는 기술이다.
기존 네트워크 환경에 영향 없이 CNI 환경을 구성할 수 있지만, 캡슐화를 위해 사용하는 영역 만큼 패킷 당 송/수신 할 수 있는 데이터의 양이 줄어들고 캡슐화 자체에도 리소스가 투입되므로 상대적으로 비효율적이다
AWS VPC CNI 의 경우 동일 노드와 파드가 동일 대역의 주소를 사용, 바로 통신할 수 있다.
별도의 캡슐화 과정이 없으므로 좀 더 나은 네트워크 성능을 보여주지만 반대로 동일 대역대를 사용하므로 사용 가능한 IP 주소가 부족할 수도 있다.
노드의 기본 네트워크 정보 확인

AWS VPC CNI의 경우 파드와 노드가 같은 IP 대역을 공유한다.
하지만 그렇다고 해서 파드의 인터페이스 == 노드의 인터페이스 인 것은 아님
같은 노드에서도 파드가 위치한 네임스페이스와 노드만 사용하는 네임스페이스는 분리되어 있음. 파드는 가상 인터페이스(veth)를 통해 노드 인터페이스와 연결되어 통신하게 됨
(위 그림의 eniY@ifN와 노드 인터페이스인 ENI0은 연결되어 있음)이 때 인터페이스 하나 당 여러개의 보조 주소를 가질 수 있다.
클러스터 워커 노드의 네트워크 정보를 확인해보자
현재 실행 중인 워커 노드에 해당하는 EC2의 네트워크 정보를 콘솔에서 확인한다

두 개의 인터페이스에 각각 IP 주소 총 2개와 보조 IP 주소가 5개씩 10개가 할당된 것을 확인할 수 있다!
워커 노드의 IP는 172.30.79.119 이다.
NAME STATUS ROLES AGE INTERNAL-IP EXTERNAL-IP KERNEL-VERSION CONTAINER-RUNTIME
i-00201bbb4579776d8 Ready node 45m 172.30.79.119 54.180.159.208 5.15.0-1026-aws containerd://1.6.10
i-012d887d296a74bb7 Ready node 45m 172.30.55.175 43.201.63.165 5.15.0-1026-aws containerd://1.6.10
i-06895778bbf804dac Ready control-plane 46m 172.30.59.239 3.36.90.199 5.15.0-1026-aws containerd://1.6.10
노드의 IP 주소와 EC2 인스턴스의 주소가 같은 것을 확인할 수 있다
k get pod -n kube-system -owide | grep .239
aws-cloud-controller-manager-ks52l 172.30.59.239 i-06895778bbf804dac <none> <none>
aws-node-7ng2c 172.30.59.239 i-06895778bbf804dac <none> <none>
dns-controller-5bb6b86f54-96dp5 172.30.59.239 i-06895778bbf804dac <none> <none>
etcd-manager-events-i-06895778bbf804dac 172.30.59.239 i-06895778bbf804dac <none> <none>
etcd-manager-main-i-06895778bbf804dac 172.30.59.239 i-06895778bbf804dac <none> <none>
kops-controller-qsw57 172.30.59.239 i-06895778bbf804dac <none> <none>
kube-apiserver-i-06895778bbf804dac 172.30.59.239 i-06895778bbf804dac <none> <none>
kube-controller-manager-i-06895778bbf804dac 172.30.59.239 i-06895778bbf804dac <none> <none>
kube-proxy-i-06895778bbf804dac 172.30.59.239 i-06895778bbf804dac <none> <none>
kube-scheduler-i-06895778bbf804dac 172.30.59.239 i-06895778bbf804dac <none> <none>
컨트롤플레인 kube-system에 있는 일부 파드는 컨트롤 플레인과 같은 주소를 공유하기도 한다
테스트용 파드 생성
https://github.com/nicolaka/netshoot
- 도커와 쿠버네티스용 네트워크 디버깅용 컨테이너 이미지
테스트를 위해 추가 터미널을 띄운 뒤 아래 명령어로 로그를 계속 확인한다
# 워커 노드 Public IP 확인
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value}" --filters Name=instance-state-name,Values=running --output table
****# 워커 노드 Public IP 변수 지정
W1PIP=<워커 노드 1 Public IP>
W2PIP=<워커 노드 2 Public IP>
#[터미널1] 워커 노드 1 모니터링
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP
**watch -d "ip link | egrep 'ens5|eni' ;echo;echo "[ROUTE TABLE]"; route -n | grep eni"**
#[터미널2] 워커 노드 2 모니터링
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP
**watch -d "ip link | egrep 'ens5|eni' ;echo;echo "[ROUTE TABLE]"; route -n | grep eni"**
# 컨트롤플레인에서 테스트 파드 yaml 파일을 수정한다
# 설정이 없는 경우 클러스터는 노드 1에 파드 2개를 모두 설치하기 때문에 노드를 지정한다
apiVersion: v1
kind: Pod
metadata:
name: pod-1
labels:
app: pod
spec:
containers:
- name: netshoot-pod
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Pod
metadata:
name: pod-2
labels:
app: pod
spec:
nodeName: i-012d887d296a74bb7 # 워커 노드 2의 id
containers:
- name: netshoot-pod
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
# 작업용 EC2 파드 2개 생성
kubectl create -f ~/pkos/2/netshoot-2pods.yam
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-1 1/1 Running 0 15m 172.30.76.167 i-00201bbb4579776d8 <none> <none>
pod-2 1/1 Running 0 4m36s 172.30.54.244 i-012d887d296a74bb7 <none> <none>
- 정상적으로 각 워커 노드 당 1개씩 파드가 생성된 것을 확인한다
- 파드가 생성되면, 워커 노드에 eniY@ifN 추가되고 라우팅 테이블에도 정보가 추가된다
각 파드에 접속하여 네트워크 정보를 확인해보자
# 테스트용 파드 접근
**kubectl exec -it pod-1 -- zsh**
# 네트워크 정보 확인
**ip -c addr**
>>1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
>>3: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc noqueue state UP group default
link/ether 6e:cb:ea:3a:fa:e7 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet **172.30.76.167/32** scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::6ccb:eaff:fe3a:fae7/64 scope link
valid_lft forever preferred_lft forever
**ip -c route**
>> default via 169.254.1.1 dev eth0
169.254.1.1 dev eth0 scope link
**route -n**
>> Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 169.254.1.1 0.0.0.0 UG 0 0 0 eth0
169.254.1.1 0.0.0.0 255.255.255.255 UH 0 0 0 eth0
**ping -c 1 172.30.54.244 # Pod-2주소**
>> PING 172.30.54.244 (172.30.54.244) 56(84) bytes of data.
64 bytes from 172.30.54.244: icmp_seq=1 ttl=62 time=1.25 ms
--- 172.30.54.244 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.253/1.253/1.253/0.000 ms
**ps**
>> PID USER TIME COMMAND
1 root 0:00 tail -f /dev/null
7 root 0:01 zsh
84 root 0:00 ps
**cat /etc/resolv.conf**
>> search default.svc.cluster.local svc.cluster.local cluster.local ap-northeast-2.compute.internal
nameserver 100.64.0.10
options ndots:5
exit
----------------------------
# 파드2 Shell 실행
**kubectl exec -it pod-2 -- ip -c addr**
>> 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
3: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc noqueue state UP group default
link/ether 1e:00:f5:9b:b2:16 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet **172.30.54.244/32** scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::1c00:f5ff:fe9b:b216/64 scope link
valid_lft forever preferred_lft forever
노드-파드 간 통신 구성
AWS VPC CNI에서 파드와 노드는 모든 같은 대역대를 사용하므로 캡슐화 없이 바로 통신이 가능하다
파드 간 통신 실습
# 각 파드 IP를 변수로 선언한다
POD1=$(kubectl get pod pod-1 -o jsonpath={.status.podIP})
POD2=$(kubectl get pod pod-2 -o jsonpath={.status.podIP})
터미널을 추가로 열어놓고 node로 접근하여 tcpdump를 확인한다

# 각각의 워커 노드에 터미널로 접속한 뒤 TCPDUMP 확인
sudo tcpdump -i any -nn icmp
# 파드 1에서 파드2로 PING을 찍어본다
kubectl exec -it pod-1 -- ping -c 2 $POD2

파드1에서 파드2로 핑이 찍히는 것을 TCPDUMP로 확인할 수 있다.


위 그림을 보면 ens6(그림상 ENI1)을 통하지 않고 ens5(ENI0)을 통해 패킷이 다른 노드로 전달된다.
ens6은 물리 인터페이스가 있음에도 불구하고 실제로는 사용하지 않는다
파드에서 외부로 통신

파드가 보낸 패킷은 veth를 통해 노드의 물리 인터페이스로 향한다. 이때 파드의 IP는 노드의 IP로 SNAT 된다.
VPC CNI의 경우에는 설정에 따라 SNAT 없이 통신도 가능함
PKOS-2주차) 파드 생성 제한 해제하기
파드 생성 갯수 제한
노드의 인터페이스(ENI)와 보조 IP 주소 수에 따라 최대 생성할 수 있는 파드의 갯수가 달라진다.
- aws-node 와 kube-proxy 파드는 호스트의 IP를 사용함으로 최대 갯수에서 제외
kubectl describe node | grep Allocatable: -A6
>> Allocatable:
cpu: 2
ephemeral-storage: 59763732382
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 3854320Ki
pods: 17
--
Allocatable:
cpu: 2
ephemeral-storage: 119703055367
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 3854328Ki
pods: 17
--
Allocatable:
cpu: 2
ephemeral-storage: 119703055367
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 3854320Ki
pods: 17
# 총 갯수가 17개임을 확인할 수 있다
Deployment를 이용한 파드 생성 실습
# deployment를 생성한
kubectl apply -f ~/pkos/2/nginx-dp.yaml
# 파드를 30개로 늘려본다
kubectl scale deployment nginx-deployment --replicas=30
# 30개가 전부 생성되지 못하는 것을 확인
kubectl get pods | grep Pending
nginx-deployment-6fb79bc456-8f7hj 0/1 Pending 0 93s
nginx-deployment-6fb79bc456-fpd26 0/1 Pending 0 93s
nginx-deployment-6fb79bc456-g4xln 0/1 Pending 0 93s
nginx-deployment-6fb79bc456-lp6t8 0/1 Pending 0 93s
nginx-deployment-6fb79bc456-z949p 0/1 Pending 0 93s
IPv4 Prefix Delegation : IPv4 28bit 서브넷(prefix)를 위임하여 할당 가능 IP 수와 인스턴스 유형에 권장하는 최대 갯수로 선정
AWS VPC CNI prefix assignment mode : IPv4 Prefix Delegation 대역의 IP를 파드가 사용할 수 있다…고 한다
공식 문서를 보고 이것저것 찾아보는데 이해하기가 어려워서 조금 고생중이다.
일단 AWS Nitro 베이스 가상 머신이 필요하다고 하는데 Nitro가 뭘까?
AWS Nitro System
- 차세대 EC2 인스턴스를 위한 기본 플랫폼
- NVMe와 ENA(Elastic Network Adapter) 도입
- 노드당 더 많은 파드를 실행할 수 있도록 “접두사(prefix) 할당 모드”를 추가
- ENI의 최대 수는 동일, 대신 개별 IPv4 주소 대신에 /28 (16개의 IP주소) IPv4 주소를 사용 가능함
파드에 사용할 수 있는 단일 IP를 부여하지 않고 /28 로 되어있는 IP 주소 범위를 할당해서 더 많은 파드를 생성할 수 있다는 의미!
일단 현재 t3.medium인 클러스터 인스턴스를 c5 large 인스턴스로 교체한다
# C5.Large 인스턴스 1개 생성
aws cloudformation deploy --template-file **kops-oneclick.yaml** --stack-name **mykops2** --parameter-overrides KeyName=**daso** SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 MyIamUserAccessKeyID=AKI~~~ MyIamUserSecretAccessKey=**'v~~~'** ClusterBaseName=**'play-board.net'** S3StateStore=**'pkos-daso-s3'** **WorkerNodeInstanceType=c5.large WorkerNodeCount=1** --region ap-northeast-2
# 가용한 파드 생성 갯수 확인하기
kubectl describe node | grep Allocatable: -A6
Allocatable:
cpu: 2
ephemeral-storage: 59763732382
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 3854328Ki
pods: 17
--
Allocatable:
cpu: 2
ephemeral-storage: 119703055367
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 3698676Ki
pods: 29
# deployment를 생성한 뒤 30개로 늘리기
kubectl apply -f ~/pkos/2/nginx-dp.yaml
kubectl scale deployment nginx-deployment --replicas=30
# 생성된 파드 갯수 확인
k get deployments.apps nginx-deployment
>NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 16/30 30 16 38s
30개 파드를 생성하는 deployment를 생성하고 세부 내용을 확인해보자
# 노드 세부내용 확인하기
Non-terminated Pods: (22 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits Age
--------- ---- ------------ ---------- --------------- ------------- ---
default nginx-deployment-6fb79bc456-4bbsv 100m (5%) 0 (0%) 0 (0%) 0 (0%) 101s
default nginx-deployment-6fb79bc456-6fdz7 100m (5%) 0 (0%) 0 (0%) 0 (0%) 101s
default nginx-deployment-6fb79bc456-8j76l 100m (5%) 0 (0%) 0 (0%) 0 (0%) 101s
default nginx-deployment-6fb79bc456-8l9xc 100m (5%) 0 (0%) 0 (0%) 0 (0%) 101s
default nginx-deployment-6fb79bc456-8wzqh 100m (5%) 0 (0%) 0 (0%) 0 (0%) 101s
default nginx-deployment-6fb79bc456-b2hw6 100m (5%) 0 (0%) 0 (0%) 0 (0%) 101s
default nginx-deployment-6fb79bc456-hppvg 100m (5%) 0 (0%) 0 (0%) 0 (0%) 101s
default nginx-deployment-6fb79bc456-jkj8r 100m (5%) 0 (0%) 0 (0%) 0 (0%) 101s
default nginx-deployment-6fb79bc456-kc7ql 100m (5%) 0 (0%) 0 (0%) 0 (0%) 107s
default nginx-deployment-6fb79bc456-kt42l 100m (5%) 0 (0%) 0 (0%) 0 (0%) 101s
default nginx-deployment-6fb79bc456-lc66s 100m (5%) 0 (0%) 0 (0%) 0 (0%) 101s
default nginx-deployment-6fb79bc456-pfm5v 100m (5%) 0 (0%) 0 (0%) 0 (0%) 107s
default nginx-deployment-6fb79bc456-pzxwd 100m (5%) 0 (0%) 0 (0%) 0 (0%) 101s
default nginx-deployment-6fb79bc456-q7gpx 100m (5%) 0 (0%) 0 (0%) 0 (0%) 101s
default nginx-deployment-6fb79bc456-t649w 100m (5%) 0 (0%) 0 (0%) 0 (0%) 101s
default nginx-deployment-6fb79bc456-zhnkj 100m (5%) 0 (0%) 0 (0%) 0 (0%) 101s
kube-system aws-node-xwxqp 25m (1%) 0 (0%) 0 (0%) 0 (0%) 14m
kube-system coredns-6897c49dc4-6k5d8 100m (5%) 0 (0%) 70Mi (1%) 170Mi (4%) 13m
kube-system coredns-6897c49dc4-mvdz8 100m (5%) 0 (0%) 70Mi (1%) 170Mi (4%) 15m
kube-system coredns-autoscaler-5685d4f67b-drblg 20m (1%) 0 (0%) 10Mi (0%) 0 (0%) 15m
kube-system ebs-csi-node-z7zkh 0 (0%) 0 (0%) 0 (0%) 0 (0%) 14m
kube-system kube-proxy-i-09e153e15590ea358 100m (5%) 0 (0%) 0 (0%) 0 (0%) 13m
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 1945m (97%) 0 (0%)
memory 150Mi (4%) 340Mi (9%)
ephemeral-storage 0 (0%) 0 (0%)
hugepages-1Gi 0 (0%) 0 (0%)
hugepages-2Mi 0 (0%) 0 (0%)
늘어나긴 헀지만 그래도 원하는 수량 30개를 다 만들어내지는 못하고 있다.
그렇다면 파드 생성 갯수를 늘리기 위한 작업을 하나씩 해보자!
링크)Limit Ranges
링크)Amazon EC2 노드에 사용 가능한 IP 주소의 양 늘리기
- 컨테이너 최소 CPU 제한 해제하기
# 쿠버네티스에서 컨테이너를 생성할 때 마다 최소 0.1 CPU를 보장한다(100M)
# LimitRange를 확인한다
kubectl describe limitranges
Name: limits
Namespace: default
Type Resource Min Max **Default Request** Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
**Container** **cpu** - - **100m** - -
# 파드 갯수 0으로 줄이기
kubectl scale deployment nginx-deployment --replicas=0
# LimitRanges 기본 정책 삭제
kubectl delete limitranges limits
kubectl get limitranges
- kops 클러스터 수정하기
# 클러스터의 aws-node 상세 정보를 확인한다
kubectl describe ds -n kube-system aws-node
>
ADDITIONAL_ENI_TAGS: {"KubernetesCluster":"play-board.net","kubernetes.io/cluster/play-board.net":"owned"}
AWS_VPC_CNI_NODE_PORT_SUPPORT: true
AWS_VPC_ENI_MTU: 9001
AWS_VPC_K8S_CNI_CONFIGURE_RPFILTER: false
AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG: false
AWS_VPC_K8S_CNI_EXTERNALSNAT: false
AWS_VPC_K8S_CNI_LOGLEVEL: DEBUG
AWS_VPC_K8S_CNI_LOG_FILE: /host/var/log/aws-routed-eni/ipamd.log
AWS_VPC_K8S_CNI_RANDOMIZESNAT: prng
AWS_VPC_K8S_CNI_VETHPREFIX: eni
AWS_VPC_K8S_PLUGIN_LOG_FILE: /var/log/aws-routed-eni/plugin.log
AWS_VPC_K8S_PLUGIN_LOG_LEVEL: DEBUG
DISABLE_INTROSPECTION: false
DISABLE_METRICS: false
DISABLE_NETWORK_RESOURCE_PROVISIONING: false
ENABLE_IPv4: true
ENABLE_IPv6: false
ENABLE_POD_ENI: false
**ENABLE_PREFIX_DELEGATION: false # 네트워크 인터페이스에 Prefix를 할당하지 않은 상태**
WARM_ENI_TARGET: 1
**WARM_PREFIX_TARGET: 1 # 체크**
MY_NODE_NAME: (v1:spec.nodeName)
CLUSTER_NAME: play-board.net
# kops에서 클러스터를 수정한다: maxPods 110개로 수정, Prefix Assign 활성화
kops edit cluster
>
...
kubelet:
anonymousAuth: false
maxPods: 110
...
networking:
amazonvpc:
env:
- name: ENABLE_PREFIX_DELEGATION
value: "true"
# 클러스터를 업데이트한다
kops update cluster --yes && echo && sleep 5 && kops rolling-update cluster --yes
# Deployment 생성
kubectl scale deployment nginx-deployment **--replicas=110**
인스턴스 타입을 바꾸고, Limitrange 제한을 풀고, Prefix 할당을 허용한 후에 파드를 100개 생성할 수 있었다.
Kubernetes 서비스
서비스(Service)의 종류
파드에서 실행중인 애플리케이션을 네트워크 서비스로 노출하기 위한 것
ClusterIP
- 클러스터 내부에서만 접근 가능하며 외부에서 접근하기 위해서는 port forwarding/proxy를 통해 접근해야 함 접근할 때는 Cluster-IP로만 접근할 수 있음
- 서비스(ClusterIP) 생성 시, apiserver → kube-proxy → iptables 에 rule이 생성
- iptables rule 이 설정되므로, 파드에서 접속 시 해당 노드에 존재하는 iptables rule 에 의해서 분산 접속이 됨
NodePort
- 노드의 특정 포트(NodrPort)를 이용하여 접근할 수 있도록 설정하는 방법
- 외부에서 노드 IP:노드포트 로 접근할 수 있다.
- 해당 노드의 iptables 룰에 의해서 SNAT/DNAT 되어 목적지 파드와 통신 후 리턴 트래픽은 최초 인입 노드를 경유해서 외부로 되돌아감
LoadBalancer
- 앞단에 Loadbalancer가 붙어서 살아있는 노드를 체크하여 트래픽을 전달
- 외부에선 노드에 직접 접속할 수 없고 로드밸런서에만 접속할 수 있다
- 파드가 있는 노드들에만 로드밸런싱을 하며 iptables 룰에서는 자신의 노드에 있는 파드만 연결 로드밸런서와 iptables에서 각각 한 번씩 DNAT가 실시된다.
EC2 instance profiles 설정
마스터/워커 노드에 EC2 IAM Role Policy (AWSLoadBalancerControllerIAMPolicy) 추가
curl -o **iam_policy.json** <https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/**v2.4.5**/docs/install/iam_policy.json>
aws iam create-policy --policy-name **AWSLoadBalancerControllerIAMPolicy** --policy-document file://**iam_policy.json**
계정 Account ID 변수 지정
ACCOUNT_ID=`aws sts get-caller-identity --query 'Account' --output text`
echo $ACCOUNT_ID
>> 859621957271
생성된 IAM Policy 확인
aws iam get-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/**AWSLoadBalancerControllerIAMPolicy** --query 'Policy.Arn'
>> "arn:aws:iam::859621957271:policy/AWSLoadBalancerControllerIAMPolicy"
EC2 instance profiles 이름 확인
aws iam list-instance-profiles --query 'InstanceProfiles[*].InstanceProfileName'
>> [
"aws-elasticbeanstalk-ec2-role",
"ecr-full",
"ecsInstanceRole",
"eksworkspace-admin",
**"masters.play-board.net",
"nodes.play-board.net"**
]
EC2 instance profiles 에 IAM Policy 추가
– 위에 만든 로드밸런스IAM에 마스터와 워커 노드 클러스터 네임을 바인딩한다
aws iam attach-role-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy --role-name masters.$**KOPS_CLUSTER_NAME**
aws iam attach-role-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy --role-name nodes.$**KOPS_CLUSTER_NAME**
kOps 클러스터 인증서 구성을 위한 cert-manager를 설치
kops edit cluster --name ${KOPS_CLUSTER_NAME}
# 아래 내용을 추가한다
spec:
**certManager:
enabled: true
awsLoadBalancerController:
enabled: true**
AWS LoadBalancer 배포
앞서 IAM을 포함한 설정이 완료되었다면 클러스터를 다시 기동하여 업데이트를 적용한다
kops update cluster --yes && echo && sleep 5 && kops rolling-update cluster
NLB 배포 테스트
테스트를 위해 서비스와 Deployment를 생성한다
kubectl apply -f ~/pkos/2/echo-service-nlb.yaml
echo-service-nlb.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-echo
spec:
replicas: 2
selector:
matchLabels:
app: deploy-websrv
template:
metadata:
labels:
app: deploy-websrv
spec:
terminationGracePeriodSeconds: 0
containers:
- name: akos-websrv
image: k8s.gcr.io/echoserver:1.5
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: svc-nlb-ip-type
annotations:
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
service.beta.kubernetes.io/aws-load-balancer-healthcheck-port: "8080"
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
type: LoadBalancer
loadBalancerClass: service.k8s.aws/nlb
selector:
app: deploy-websrv
로드밸런스 상태 확인
aws elbv2 describe-load-balancers
> "State": {
"Code": "active"
},
aws elbv2 describe-load-balancers --query 'LoadBalancers[*].State.Code' --output text 을 치면 Provisioning인지 Active인지 알 수 있음. 스터디 자료에 이런식으로 친절하게 정리되어 있는데, 나는 아직 원시인 레벨이라서 이런 쿼리에 익숙하지 않아 더 열심히 해야겠다는 생각이 막 들었다 이상 잡담 끝
해당 로드밸런서의 웹 주소 확인
# 아래의 명령어를 입력하고 External IP를 복사하여 사용하거나
kubectl get svc svc-nlb-ip-type
# 아래 명령어를 실행한다
kubectl get svc svc-nlb-ip-type -o jsonpath={.status.loadBalancer.ingress[0].hostname} | awk '{ print "http://"$1 }'
> <http://k8s-default-svcnlbip-cf064ae967-c9bfbe1079f59c4c.elb.ap-northeast-2.amazonaws.com>
# 로드밸런서 주소를 변수로 선언
NLB=$(kubectl get svc svc-nlb-ip-type -o jsonpath={.status.loadBalancer.ingress[0].hostname})
로드밸런서로 요청(curl)을 보내고 파드의 로그를 확인해본다
while true; do curl -s --connect-timeout 1 $NLB | egrep 'Hostname|client_address'; echo "----------" ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; done
1초 단위로 계속 curl을 보낼 경우 두 개의 파드에 트래픽이 정상적으로 분기되는 것을 확인할 수 있다.
만약 파드 수를 늘리거나 줄이면 어떻게될까?
# 파드 수를 줄이는 경우
kubectl scale deployment deploy-echo --replicas=1
# 테스트
for i in {1..100}; do curl -s $NLB | grep Hostname ; done | sort | uniq -c | sort -nr
# 파드 수를 늘리는 경우
kubectl scale deployment deploy-echo --replicas=3
# 테스트
for i in {1..100}; do curl -s $NLB | grep Hostname ; done | sort | uniq -c | sort -nr
분기가 잘 되는 것을 확인할 수 있다
ExternalDNS
ExternalDNS란?
Public한 도메인서버(AWS Route53, GCP DNS 등)를 사용하여 쿠버네티스의 리소스를 쿼리할 수 있게 해주는 오픈소스 솔루션
ExternalDNS 설치하기
기본 DNS 서버 수량을 조정한다
kubectl delete deploy -n kube-system coredns-autoscaler
kubectl scale deploy -n kube-system coredns --replicas 1
관련 IAM 정책을 생성한 뒤 마스터/워커 노드에 바인딩한다
curl -s -O <https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/AKOS/externaldns/externaldns-aws-r53-policy.json>
aws iam create-policy --policy-name AllowExternalDNSUpdates --policy-document file://externaldns-aws-r53-policy.json
export POLICY_ARN=$(aws iam list-policies --query 'Policies[?PolicyName==`AllowExternalDNSUpdates`].Arn' --output text)
EC2에 정책을 바인딩한다
aws iam attach-role-policy --policy-arn $POLICY_ARN --role-name masters.$**KOPS_CLUSTER_NAME**
aws iam attach-role-policy --policy-arn $POLICY_ARN --role-name nodes.$**KOPS_CLUSTER_NAME**
프로그램 설치(kops edit cluster) : 아래 내용을 추가한다
spec:
externalDns:
provider: external-dns
서버 재설정 및 업데이트 시작
kops update cluster --yes && echo && sleep 5 && kops rolling-update cluster
ExternalDNS 설정하기
# 테스트용 파드를 생성한다
kubectl apply -f ~/pkos/2/echo-service-nlb.yaml
도메인 정보 입력
# 변수로 도메인 이름을 입력한다
MyDOMAIN1=nginx.play-board.net
# 서비스 Annotation에 도메인이 추가된 것을 확인한다
kubectl annotate service svc-nlb-ip-type "external-dns.alpha.kubernetes.io/hostname=$MyDOMAIN1."
분산 접속을 확인한다
for i in {1..100}; do curl -s $MyDOMAIN1 | grep Hostname ; done | sort | uniq -c | sort -nr
>> for i in {1..100}; do curl -s $MyDOMAIN1 | grep Hostname ; done | sort | uniq -c | sort -nr
50 Hostname: deploy-echo-5c4856dfd6-zvcnf
50 Hostname: deploy-echo-5c4856dfd6-cqh74


'K8s' 카테고리의 다른 글
PKOS 4주차) Harbor란?, Gitlab?, ArgoCD?, Prometheus? (0) | 2023.07.09 |
---|---|
PKOS-3주차) Instance Store, Ingress, Storage (0) | 2023.07.09 |
Persistent Volume과 PersistentVolumeClaim (0) | 2023.07.09 |
PKOS 1주차 ) kOps를 이용한 쿠버네티스 클러스터 구성 (0) | 2023.07.09 |
쿠버네티스 Service 생성 시 포트 설정 (0) | 2023.07.09 |