들어가며
이번 포스팅은 CloudNet@ 커뮤니티에서 주최하는 KANS 스터디 9주 차 주제인 "AWS EKS : VPC CNI"에 대해서 정리한 내용입니다.
실습환경 설치
실습환경은 VPC 1개(퍼블릭 서브넷 3개, 프라이빗 서브넷 3개), EKS 클러스터(Control Plane), 관리형 노드 그룹(EC2 3대), Add-on으로 구성되어 있습니다.
# YAML 파일 다운로드
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/kans/eks-oneclick.yaml
# CloudFormation 스택 배포
aws cloudformation deploy --template-file eks-oneclick.yaml --stack-name myeks --parameter-overrides KeyName=<My SSH Keyname> SgIngressSshCidr=<My Home Public IP Address>/32 MyIamUserAccessKeyID=<IAM User의 액세스키> MyIamUserSecretAccessKey=<IAM User의 시크릿 키> ClusterBaseName='<eks 이름>' --region ap-northeast-2
# CloudFormation 이후 약 20분간 정상적인 배포를 위하여 대기..
#접속
ssh -i ~/.ssh/devlos.pem ec2-user@$(aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[0].OutputValue' --output text)
클러스터의 정보들을 확인합니다.
# default 네임스페이스 적용
kubectl ns default
# 설치 확인
kubectl cluster-info
eksctl get cluster
eksctl get nodegroup --cluster $CLUSTER_NAME
# 환경변수 정보 확인
export | egrep 'ACCOUNT|AWS_|CLUSTER|KUBERNETES|VPC|Subnet'
export | egrep 'ACCOUNT|AWS_|CLUSTER|KUBERNETES|VPC|Subnet' | egrep -v 'SECRET|KEY'
# 인증 정보 확인
cat /root/.kube/config
kubectl config view
kubectl ctx
# 노드 정보 확인
kubectl get node --label-columns=node.kubernetes.io/instance-type,eks.amazonaws.com/capacityType,topology.kubernetes.io/zone
eksctl get iamidentitymapping --cluster myeks
# krew 플러그인 확인
kubectl krew list
# 모든 네임스페이스에서 모든 리소스 확인
kubectl get-all
노드의 정보를 확인하고 SSH 접속이 정상적으로 잘 되는지 확인합니다.
# 노드 IP 확인 및 PrivateIP 변수 지정
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,PrivateIPAdd:PrivateIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output table
N1=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2a -o jsonpath={.items[0].status.addresses[0].address})
N2=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2b -o jsonpath={.items[0].status.addresses[0].address})
N3=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2c -o jsonpath={.items[0].status.addresses[0].address})
echo "export N1=$N1" >> /etc/profile
echo "export N2=$N2" >> /etc/profile
echo "export N3=$N3" >> /etc/profile
echo $N1, $N2, $N3
# 보안그룹 ID와 보안그룹 이름(Name아님을 주의!) 확인
aws ec2 describe-security-groups --query 'SecurityGroups[*].[GroupId, GroupName]' --output text
# 노드 보안그룹 ID 확인
aws ec2 describe-security-groups --filters Name=group-name,Values=*ng1* --query "SecurityGroups[*].[GroupId]" --output text
NGSGID=$(aws ec2 describe-security-groups --filters Name=group-name,Values=*ng1* --query "SecurityGroups[*].[GroupId]" --output text)
echo $NGSGID
echo "export NGSGID=$NGSGID" >> /etc/profile
# 노드 보안그룹에 eksctl-host 에서 노드(파드)에 접속 가능하게 룰(Rule) 추가 설정
aws ec2 authorize-security-group-ingress --group-id $NGSGID --protocol '-1' --cidr 192.168.1.100/32
# eksctl-host 에서 노드의IP나 coredns 파드IP로 ping 테스트
ping -c 1 $N1
ping -c 1 $N2
ping -c 1 $N3
# 워커 노드 SSH 접속 : '-i ~/.ssh/id_rsa' 생략 가능
for node in $N1 $N2 $N3; do ssh -o StrictHostKeyChecking=no ec2-user@$node hostname; done
ssh ec2-user@$N1
exit
ssh ec2-user@$N2
exit
ssh ec2-user@$N3
exit
Addon 정보에 kube-proxy, coredns, aws vpc cni가 정상적으로 설치되어 있음을 확인할 수 있습니다.
# 모든 파드의 컨테이너 이미지 정보 확인
kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | sort | uniq -c
# 위 버전은 Add-on 으로 최신 버전 설치
kubectl get pods -A
kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | sort | uniq -c
3 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/amazon/aws-network-policy-agent:v1.0.8-eksbuild.1
3 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/amazon-k8s-cni:v1.16.4-eksbuild.2
2 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/eks/coredns:v1.10.1-eksbuild.7
3 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/eks/kube-proxy:v1.28.6-minimal-eksbuild.
# 아래는 기본 설치 시 버전
2 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/amazon-k8s-cni:v1.15.1-eksbuild.1
2 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/eks/coredns:v1.10.1-eksbuild.4
2 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/eks/kube-proxy:v1.28.2-minimal-eksbuild.2
# eksctl 설치/업데이트 addon 확인
eksctl get addon --cluster $CLUSTER_NAME
NAME VERSION STATUS ISSUES IAMROLE UPDATE AVAILABLE CONFIGURATION VALUES
coredns v1.10.1-eksbuild.7 ACTIVE 0
kube-proxy v1.28.6-eksbuild.2 ACTIVE 0
vpc-cni v1.16.4-eksbuild.2 ACTIVE 0 arn:aws:iam::911283464785:role/eksctl-myeks-addon-vpc-cni-Role1-tGXXZMjRWrW3 enableNetworkPolicy: "true"
# (참고) eks 설치 yaml 중 addon 내용
tail -n11 myeks.yaml
addons:
- name: vpc-cni # no version is specified so it deploys the default version
version: latest # auto discovers the latest available
attachPolicyARNs:
- arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
configurationValues: |-
enableNetworkPolicy: "true"
- name: kube-proxy
version: latest
- name: coredns
version: latest
AWS VPC CNI 소개
AWS VPC CNI를 이해하기 위한 키워드입니다.
- k8s CNI(Container Network Interface)
Kubernetes에서 컨테이너 네트워크를 관리하기 위한 표준 인터페이스로써 인터페이스에 맞는 여러 가지 플러그인들이 있습니다. 그중 스터디에 다룬 플러그인은 AWS에서 kubernetes CNI 규격에 맞게 제공하는 AWS VPC CNI입니다. - AWS VPC CNI(Amazon Web Service Virtual Private Cluster Container Network Interface)
AWS VPC CNI는 Kubernetes 컨테이너 네트워크에 대한 보안, 관리, 성능 등을 고려하여 설계된 CNI 플러그인입니다.
AWS VPC CNI는 클러스터 내의 모든 Pod와 통신할 때 오버레이 네트워크를 거치지 않고 직접 통신이 가능합니다. 이는 VPC ENI에 미리 할당된 IP를 파드에서 사용할 수 있기 때문입니다.
VPC CNI 플러그인은 노드에서 ENI를 관리한다. 노드가 프로비저닝 될 때 CNI 플러그인은 노드의 서브넷에서 기본 ENI로 슬롯 풀을 자동으로 할당합니다. 이 크기는 Node의 인스턴스 타입에 따라 다릅니다.
기본 ENI 슬롯이 할당되면 CNI는 추가 ENI를 노드에 연결할 수 있는데, 이 때 추가되는 ENI는 보조 ENI라고 합니다. 이 ENI 역시 인스턴스 유형에 따라 특정 수의 슬롯(로컬 IP 할당 개수)이 있습니다.
CNI가 동작하는 메커니즘은 아래의 플로우 차트와 같습니다.
플로우 차트를 간략히 설명하면 CNI는 Pod에 로컬 private IP를 할당할 때 Primary ENI에서 할당된 슬롯을 사용할 수 없으면 Secondary ENI에서 사용할 수 있는 IP를 찾습니다. Secondary ENI에도 사용할 수 있는 IP가 없으면 가용범위 내에서 새로운 ENI를 생성하여 IP를 할당합니다.
AWS VPC CNI Plugin의 공식 설명에 보면 각 kubernetes 노드(ec2 인스턴스)에 대해 기본 ENI와 보조 ENI를 생성하고 보조 IP 주소를 할당한다는 내용이 나온다. 그리고 이 보조 IP 주소는 쿠버네티스 node IP 대역과 동일하게 설정되어 있습니다.
이것을 관리하는 것은 L-IPAM이라는 로컬 IP 주소 관리자입니다. L-IPAM은 노드마다 DaemonSet으로 실행되어 있고, kubelet이 ADD Pod 요청을 수신할 때 CNI 플러그인을 통해 즉시 웜풀에서 사용가능한 보조 UP 주소를 하나 가져와 Pod에 할당합니다.
L-IPAM: IP풀을 관리하는 것으로 Pod 기동시 API호출수를 줄이고, 빠르게 실행할 수 있도록 합니다.
하지만 EC2 인스턴스 종류 별로 ENI 할당 개수가 정해져 있기 때문에 Pod를 무한정 생성할 수 없습니다.
(다음의 주소에서 인스턴스 유형별 ENI 최대 개수와 Private IP 주소를 확인할 수 있습니다.)
참고: https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/using-eni.html
첫 번째 방법은 ENI 최대 개수가 많은 인스턴스 유형을 사용하는 것이다. ENI 개수와 IP 슬롯 수를 조합해서 더 많은 Pod를 이용할 수 있다. 최대 Pod 생성 개수는 다음과 같이 산정됩니다.
(ENI 갯수 * (ENI에서 제공하는 Private IP Address 개수 - 1)) + 2개
두 번째 방법은 IPv4 Prefix Delegation을 이용하는 방법으로 IPv4 28bit 서브넷을 위임하여 할당 가능한 IP 수와 인스턴스 유형에 권장하는 최대 개수로 선정하는 방법입니다. 워크숍에서 언급된 Prefix Deletegation 모드를 활성화하는 방법은 kOps기반 Kubernetes Cluster에서 적용했던 방식과 비슷하게, aws-node의 환경설정을 변경하여 세팅 가능합니다.
kubectl set env daemonset aws-node -n kube-system ENABLE_PREFIX_DELEGATION=true
참고: https://trans.yonghochoi.com/translations/aws_vpc_cni_increase_pods_per_node_limits.ko
AWS CNI는 여타 CNI와 다르게 노드와 파드 대역을 동일하게 설정할 수 있습니다.
K8S Calico CNI와 AWS VPC CNI 차이
네트워크 통신의 최적화(성능, 지연)를 위해서 노드와 파드의 네트워크 대역을 동일하게 설정할 수 있습니다.
그림 - 일반적인 K8S CNI 플러그인(Calico)과 AWS VPC CNI 간 노드와 파드 네트워크 대역 비교
파드간 통신 시 일반적으로 K8S CNI는 오버레이(VXLAN, IP-IP 등) 통신을 하고, AWS VPC CNI는 동일 대역으로 직접 통신을 합니다.
원본패킷이 오버레이 과정 필요 없이 그대로 다른 Pod와 통신이 가능하기 때문에 성능이 훨씬 좋습니다. (5~10%의 성능 향상!)
실습 - 네트워크 기본 정보 확인
# CNI 정보 확인
kubectl describe daemonset aws-node --namespace kube-system | grep Image | cut -d "/" -f 2
# kube-proxy config 확인 : 모드 iptables 사용 >> ipvs 모드 사용하지 않는 이유???
kubectl describe cm -n kube-system kube-proxy-config
...
mode: "iptables"
...
# 노드 IP 확인
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,PrivateIPAdd:PrivateIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output table
# 파드 IP 확인
kubectl get pod -n kube-system -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase
# 파드 이름 확인
kubectl get pod -A -o name
# 파드 갯수 확인
kubectl get pod -A -o name | wc -l
# CNI 정보 확인
for i in $N1 $N2 $N3; do echo ">> node $i <<"; ssh ec2-user@$i tree /var/log/aws-routed-eni; echo; done
ssh ec2-user@$N1 sudo cat /var/log/aws-routed-eni/plugin.log | jq
ssh ec2-user@$N1 sudo cat /var/log/aws-routed-eni/ipamd.log | jq
ssh ec2-user@$N1 sudo cat /var/log/aws-routed-eni/egress-v6-plugin.log | jq
ssh ec2-user@$N1 sudo cat /var/log/aws-routed-eni/ebpf-sdk.log | jq
ssh ec2-user@$N1 sudo cat /var/log/aws-routed-eni/network-policy-agent.log | jq
# 네트워크 정보 확인 : eniY는 pod network 네임스페이스와 veth pair
for i in $N1 $N2 $N3; do echo ">> node $i <<"; ssh ec2-user@$i sudo ip -br -c addr; echo; done
for i in $N1 $N2 $N3; do echo ">> node $i <<"; ssh ec2-user@$i sudo ip -c addr; echo; done
for i in $N1 $N2 $N3; do echo ">> node $i <<"; ssh ec2-user@$i sudo ip -c route; echo; done
ssh ec2-user@$N1 sudo iptables -t nat -S
ssh ec2-user@$N1 sudo iptables -t nat -L -n -v
노드의 Private IP와 Public IP를 확인할 수 있습니다. 이 중에서 Private IP 대역과 Pod IP를 확인해 보면 동일한 IP 대역을 사용하고 있는 것을 확인할 수 있습니다.
실습 - 노드에서 기본 네트워크 정보 확인
IP tables 모드로 CNI를 구성하면 다음과 같이 warm pool이 구성되는 것을 확인할 수 있습니다. 콘솔상에도 다음과 같이 각 노드별 warm pool 정보를 확인할 수 있습니다.
실습 - 보조 IPv4 주소를 파드가 사용하는지 확인
# coredns 파드 IP 정보 확인
kubectl get pod -n kube-system -l k8s-app=kube-dns -owide
# 노드의 라우팅 정보 확인 >> EC2 네트워크 정보의 '보조 프라이빗 IPv4 주소'와 비교해보자
for i in $N1 $N2 $N3; do echo ">> node $i <<"; ssh ec2-user@$i sudo ip -c route; echo; done
# [터미널1~3] 노드 모니터링
ssh ec2-user@$N1
watch -d "ip link | egrep 'eth|eni' ;echo;echo "[ROUTE TABLE]"; route -n | grep eni"
ssh ec2-user@$N2
watch -d "ip link | egrep 'eth|eni' ;echo;echo "[ROUTE TABLE]"; route -n | grep eni"
ssh ec2-user@$N3
watch -d "ip link | egrep 'eth|eni' ;echo;echo "[ROUTE TABLE]"; route -n | grep eni"
# 테스트용 파드 netshoot-pod 생성
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: netshoot-pod
spec:
replicas: 3
selector:
matchLabels:
app: netshoot-pod
template:
metadata:
labels:
app: netshoot-pod
spec:
containers:
- name: netshoot-pod
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
# 파드 이름 변수 지정
PODNAME1=$(kubectl get pod -l app=netshoot-pod -o jsonpath={.items[0].metadata.name})
PODNAME2=$(kubectl get pod -l app=netshoot-pod -o jsonpath={.items[1].metadata.name})
PODNAME3=$(kubectl get pod -l app=netshoot-pod -o jsonpath={.items[2].metadata.name})
# 파드 확인
kubectl get pod -o wide
kubectl get pod -o=custom-columns=NAME:.metadata.name,IP:.status.podIP
# 노드에 라우팅 정보 확인
for i in $N1 $N2 $N3; do echo ">> node $i <<"; ssh ec2-user@$i sudo ip -c route; echo; done
다른 워커 노드에 eniY@ifN 추가되고 라우팅 테이블에도 정보가 추가됩니다.
테스트용 파드에서 통신 테스트를 수행합니다.
# 테스트용 파드 접속(exec) 후 Shell 실행
kubectl exec -it $PODNAME1 -- zsh
# 아래부터는 pod-1 Shell 에서 실행 : 네트워크 정보 확인
----------------------------
ip -c addr
ip -c route
route -n
ping -c 1 <pod-2 IP>
ps
cat /etc/resolv.conf
exit
실습 - 노드 간 파드 통신
파드간 통신 흐름 : AWS VPC CNI 경우 별도의 오버레이(Overlay) 통신 기술 없이, VPC Native 하게 파드간 직접 통신이 가능한 점을 실습을 통해 확인합니다.
# 파드 IP 변수 지정
PODIP1=$(kubectl get pod -l app=netshoot-pod -o jsonpath={.items[0].status.podIP})
PODIP2=$(kubectl get pod -l app=netshoot-pod -o jsonpath={.items[1].status.podIP})
PODIP3=$(kubectl get pod -l app=netshoot-pod -o jsonpath={.items[2].status.podIP})
# 파드1 Shell 에서 파드2로 ping 테스트
kubectl exec -it $PODNAME1 -- ping -c 2 $PODIP2
# 파드2 Shell 에서 파드3로 ping 테스트
kubectl exec -it $PODNAME2 -- ping -c 2 $PODIP3
# 파드3 Shell 에서 파드1로 ping 테스트
kubectl exec -it $PODNAME3 -- ping -c 2 $PODIP1
# 워커 노드 EC2 : TCPDUMP 확인
## For Pod to external (outside VPC) traffic, we will program iptables to SNAT using Primary IP address on the Primary ENI.
sudo tcpdump -i any -nn icmp
sudo tcpdump -i eth1 -nn icmp
sudo tcpdump -i eth0 -nn icmp
sudo tcpdump -i eniYYYYYYYY -nn icmp
[워커 노드1]
# routing policy database management 확인
ip rule
# routing table management 확인
ip route show table local
# 디폴트 네트워크 정보를 eth0 을 통해서 빠져나간다
ip route show table main
default via 192.168.1.1 dev eth0
...
실습 - 파드에서 외부 통신
파드에서 외부 통신 흐름 : iptable에 SNAT을 통하여 노드의 eth0 IP로 변경되어서 외부와 통신되는 것을 실습을 통해 확인합니다.
출처 - https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/cni-proposal.md
# 작업용 EC2 : pod-1 Shell 에서 외부로 ping
kubectl exec -it $PODNAME1 -- ping -c 1 www.google.com
kubectl exec -it $PODNAME1 -- ping -i 0.1 www.google.com
# 워커 노드 EC2 : TCPDUMP 확인
sudo tcpdump -i any -nn icmp
sudo tcpdump -i eth0 -nn icmp
# 작업용 EC2 : 퍼블릭IP 확인
for i in $N1 $N2 $N3; do echo ">> node $i <<"; ssh ec2-user@$i curl -s ipinfo.io/ip; echo; echo; done
# 작업용 EC2 : pod-1 Shell 에서 외부 접속 확인 - 공인IP는 어떤 주소인가?
## The right way to check the weather - 링크
for i in $PODNAME1 $PODNAME2 $PODNAME3; do echo ">> Pod : $i <<"; kubectl exec -it $i -- curl -s ipinfo.io/ip; echo; echo; done
kubectl exec -it $PODNAME1 -- curl -s wttr.in/seoul
kubectl exec -it $PODNAME1 -- curl -s wttr.in/seoul?format=3
kubectl exec -it $PODNAME1 -- curl -s wttr.in/Moon
kubectl exec -it $PODNAME1 -- curl -s wttr.in/:help
# 워커 노드 EC2
## 출력된 결과를 보고 어떻게 빠져나가는지 고민해보자!
ip rule
ip route show table main
sudo iptables -L -n -v -t nat
sudo iptables -t nat -S
# 파드가 외부와 통신시에는 아래 처럼 'AWS-SNAT-CHAIN-0' 룰(rule)에 의해서 SNAT 되어서 외부와 통신!
# 참고로 뒤 IP는 eth0(ENI 첫번째)의 IP 주소이다
# --random-fully 동작 - 링크1 링크2
sudo iptables -t nat -S | grep 'A AWS-SNAT-CHAIN'
-A AWS-SNAT-CHAIN-0 ! -d 192.168.0.0/16 -m comment --comment "AWS SNAT CHAIN" -j RETURN
-A AWS-SNAT-CHAIN-0 ! -o vlan+ -m comment --comment "AWS, SNAT" -m addrtype ! --dst-type LOCAL -j SNAT --to-source 192.168.1.251 --random-fully
## 아래 'mark 0x4000/0x4000' 매칭되지 않아서 RETURN 됨!
-A KUBE-POSTROUTING -m mark ! --mark 0x4000/0x4000 -j RETURN
-A KUBE-POSTROUTING -j MARK --set-xmark 0x4000/0x0
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE --random-fully
...
# 카운트 확인 시 AWS-SNAT-CHAIN-0에 매칭되어, 목적지가 192.168.0.0/16 아니고 외부 빠져나갈때 SNAT 192.168.1.251(EC2 노드1 IP) 변경되어 나간다!
sudo iptables -t filter --zero; sudo iptables -t nat --zero; sudo iptables -t mangle --zero; sudo iptables -t raw --zero
watch -d 'sudo iptables -v --numeric --table nat --list AWS-SNAT-CHAIN-0; echo ; sudo iptables -v --numeric --table nat --list KUBE-POSTROUTING; echo ; sudo iptables -v --numeric --table nat --list POSTROUTING'
# conntrack 확인
for i in $N1 $N2 $N3; do echo ">> node $i <<"; ssh ec2-user@$i sudo conntrack -L -n |grep -v '169.254.169'; echo; done
conntrack v1.4.5 (conntrack-tools):
icmp 1 28 src=172.30.66.58 dst=8.8.8.8 type=8 code=0 id=34392 src=8.8.8.8 dst=172.30.85.242 type=0 code=0 id=50705 mark=128 use=1
tcp 6 23 TIME_WAIT src=172.30.66.58 dst=34.117.59.81 sport=58144 dport=80 src=34.117.59.81 dst=172.30.85.242 sport=80 dport=44768 [ASSURED] mark=128 use=1
Pod의 공인 IP를 확인합니다.
Pod의 통신은 유동 공인 IP를 이용하여 통신합니다.
실습 - 노드에 파드 생성 개수 제한
# 워커 노드 EC2 - 모니터링
while true; do ip -br -c addr show && echo "--------------" ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; done
# 작업용 EC2 - 터미널1
watch -d 'kubectl get pods -o wide'
# 작업용 EC2 - 터미널2
# 디플로이먼트 생성
curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/2/nginx-dp.yaml
kubectl apply -f nginx-dp.yaml
# 파드 확인
kubectl get pod -o wide
kubectl get pod -o=custom-columns=NAME:.metadata.name,IP:.status.podIP
# 파드 증가 테스트 >> 파드 정상 생성 확인, 워커 노드에서 eth, eni 갯수 확인
kubectl scale deployment nginx-deployment --replicas=8
# 파드 증가 테스트 >> 파드 정상 생성 확인, 워커 노드에서 eth, eni 갯수 확인 >> 어떤일이 벌어졌는가?
kubectl scale deployment nginx-deployment --replicas=15
# 파드 증가 테스트 >> 파드 정상 생성 확인, 워커 노드에서 eth, eni 갯수 확인 >> 어떤일이 벌어졌는가?
kubectl scale deployment nginx-deployment --replicas=30
# 파드 증가 테스트 >> 파드 정상 생성 확인, 워커 노드에서 eth, eni 갯수 확인 >> 어떤일이 벌어졌는가?
kubectl scale deployment nginx-deployment --replicas=50
# 파드 생성 실패!
kubectl get pods | grep Pending
nginx-deployment-7fb7fd49b4-d4bk9 0/1 Pending 0 3m37s
nginx-deployment-7fb7fd49b4-qpqbm 0/1 Pending 0 3m37s
...
kubectl describe pod <Pending 파드> | grep Events: -A5
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 45s default-scheduler 0/3 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }, 2 Too many pods. preemption: 0/3 nodes are available: 1 Preemption is not helpful for scheduling, 2 No preemption victims found for incoming pod.
# 디플로이먼트 삭제
kubectl delete deploy nginx-deployment
8개
15개
30개
50개 (파드 배포 시 장애 발생)
이를 해결하는 방안은 Prefix Delegation, WARM & MIN IP/Prefix Targets, Custom Network 등이 있습니다. Prefix Deleation 관련 실습은 이전 블로그 글을 참고하시기 바랍니다!
참고 - https://devlos.tistory.com/60
AWS LoadBalancer Controller
로드밸런서 서비스는 클라우드 공급자의 로드 밸런서를 사용하여 서비스를 자동으로 노출합니다. 이 서비스는 외부에서 클러스터 내의 서비스에 접근할 수 있는 로드밸런스된 IP 주소를 제공합니다. 로드 밸런서는 들어오는 트래픽을 적절한 파드로 분산시킵니다.
C/NLB 등의 로드밸런서를 사용하게 되면 Node Port를 타고 해당 노드에 분산된 후 iptables의 분산룰에 따라 Pod로 통신합니다.
AW의 NLB는 두 가지의 모드를 제공하는데, 주로 사용되는 모드는 IP 유형입니다.
인스턴스 유형
- externalTrafficPolicy : ClusterIP ⇒ 2번 분산 및 SNAT으로 Client IP 확인 불가능 ← LoadBalancer 타입 (기본 모드) 동작
- externalTrafficPolicy : Local ⇒ 1번 분산 및 ClientIP 유지, 워커 노드의 iptables 사용함
- 상세 설명 : 외부 클라이언트가 '로드밸런서' 접속 시 부하분산 되어 노드 도달 후 iptables 룰로 목적지 파드와 통신됨
- 노드는 외부에 공개되지 않고 로드밸런서만 외부에 공개되어, 외부 클라이언트는 로드밸랜서에 접속을 할 뿐 내부 노드의 정보를 알 수 없음
- 로드밸런서가 부하분산하여 파드가 존재하는 노드들에게 전달한다, iptables 룰에서는 자신의 노드에 있는 파드만 연결 (externalTrafficPolicy: local)
- DNAT 2번 동작 : 첫 번째(로드밸런서 접속 후 빠져나갈 때), 두 번째(노드의 iptables 룰에서 파드 IP 전달 시)
- 외부 클라이언트 IP 보존(유지) : AWS NLB는 타깃이 인스턴스일 경우 클라이언트 IP를 유지, iptables 룰 경우도 externalTrafficPolicy로 클라이언트 IP를 보존함
IP 유형 (반드시 AWS LoadBalancer 컨트롤러 파드 및 정책 설정이 필요)
- Proxy Protocol v2 비활성화 ⇒ NLB에서 바로 파드로 인입, 단 ClientIP가 NLB로 SNAT 되어 Client IP 확인 불가능
- Proxy Protocol v2 활성화 ⇒ NLB에서 바로 파드로 인입 및 ClientIP 확인 가능(→ 단 PPv2를 애플리케이션이 인지할 수 있게 설정 필요)
- 인스턴스 유형
- externalTrafficPolicy : ClusterIP ⇒ 2번 분산 및 SNAT으로 Client IP 확인 불가능 ← LoadBalancer 타입 (기본 모드) 동작
- externalTrafficPolicy : Local ⇒ 1번 분산 및 ClientIP 유지, 워커 노드의 iptables 사용함
- 상세 설명 : 외부 클라이언트가 '로드밸런서' 접속 시 부하분산 되어 노드 도달 후 iptables 룰로 목적지 파드와 통신됨
- 노드는 외부에 공개되지 않고 로드밸런서만 외부에 공개되어, 외부 클라이언트는 로드밸랜서에 접속을 할 뿐 내부 노드의 정보를 알 수 없음
- 로드밸런서가 부하분산하여 파드가 존재하는 노드들에게 전달한다, iptables 룰에서는 자신의 노드에 있는 파드만 연결 (externalTrafficPolicy: local)
- DNAT 2번 동작 : 첫 번째(로드밸런서 접속 후 빠져나갈 때), 두 번째(노드의 iptables 룰에서 파드 IP 전달 시)
- 외부 클라이언트 IP 보존(유지) : AWS NLB는인스턴스일 경우 클라이언트 IP를 유지, iptables 룰 경우도 externalTrafficPolicy로 클라이언트 IP를 보존함
실습 - AWS LoadBalancer Controller 배포
# Helm Chart 설치
helm repo add eks https://aws.github.io/eks-charts
helm repo update
helm install aws-load-balancer-controller eks/aws-load-balancer-controller -n kube-system --set clusterName=$CLUSTER_NAME
## 설치 확인
kubectl get crd
kubectl get deployment -n kube-system aws-load-balancer-controller
kubectl describe deploy -n kube-system aws-load-balancer-controller
kubectl describe deploy -n kube-system aws-load-balancer-controller | grep 'Service Account'
Service Account: aws-load-balancer-controller
# 클러스터롤, 롤 확인
kubectl describe clusterrolebindings.rbac.authorization.k8s.io aws-load-balancer-controller-rolebinding
kubectl describe clusterroles.rbac.authorization.k8s.io aws-load-balancer-controller-role
# 모니터링
watch -d kubectl get pod,svc,ep
# 작업용 EC2 - 디플로이먼트 & 서비스 생성
curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/2/echo-service-nlb.yaml
cat echo-service-nlb.yaml
kubectl apply -f echo-service-nlb.yaml
# 확인
kubectl get deploy,pod
kubectl get svc,ep,ingressclassparams,targetgroupbindings
kubectl get targetgroupbindings -o json | jq
# (옵션) 빠른 실습을 위해서 등록 취소 지연(드레이닝 간격) 수정 : 기본값 300초
vi echo-service-nlb.yaml
..
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"
service.beta.kubernetes.io/aws-load-balancer-target-group-attributes: deregistration_delay.timeout_seconds=60
...
:wq!
kubectl apply -f echo-service-nlb.yaml
# AWS ELB(NLB) 정보 확인
aws elbv2 describe-load-balancers | jq
aws elbv2 describe-load-balancers --query 'LoadBalancers[*].State.Code' --output text
ALB_ARN=$(aws elbv2 describe-load-balancers --query 'LoadBalancers[?contains(LoadBalancerName, `k8s-default-svcnlbip`) == `true`].LoadBalancerArn' | jq -r '.[0]')
aws elbv2 describe-target-groups --load-balancer-arn $ALB_ARN | jq
TARGET_GROUP_ARN=$(aws elbv2 describe-target-groups --load-balancer-arn $ALB_ARN | jq -r '.TargetGroups[0].TargetGroupArn')
aws elbv2 describe-target-health --target-group-arn $TARGET_GROUP_ARN | jq
{
"TargetHealthDescriptions": [
{
"Target": {
"Id": "192.168.2.153",
"Port": 8080,
"AvailabilityZone": "ap-northeast-2b"
},
"HealthCheckPort": "8080",
"TargetHealth": {
"State": "initial",
"Reason": "Elb.RegistrationInProgress",
"Description": "Target registration is in progress"
}
},
...
# 웹 접속 주소 확인
kubectl get svc svc-nlb-ip-type -o jsonpath={.status.loadBalancer.ingress[0].hostname} | awk '{ print "Pod Web URL = http://"$1 }'
# 파드 로깅 모니터링
kubectl logs -l app=deploy-websrv -f
# 분산 접속 확인
NLB=$(kubectl get svc svc-nlb-ip-type -o jsonpath={.status.loadBalancer.ingress[0].hostname})
curl -s $NLB
for i in {1..100}; do curl -s $NLB | grep Hostname ; done | sort | uniq -c | sort -nr
52 Hostname: deploy-echo-55456fc798-2w65p
48 Hostname: deploy-echo-55456fc798-cxl7z
# 지속적인 접속 시도 : 아래 상세 동작 확인 시 유용(패킷 덤프 등)
while true; do curl -s --connect-timeout 1 $NLB | egrep 'Hostname|client_address'; echo "----------" ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; done
다음과 같이 kubernetes 명령어를 통해 pod를 제어하며 AWS의 Target Group 리소스와 연동하여 자동적으로 관리가 가능합니다.
# (신규 터미널) 모니터링
while true; do aws elbv2 describe-target-health --target-group-arn $TARGET_GROUP_ARN --output text; echo; done
# 작업용 EC2 - 파드 1개 설정
kubectl scale deployment deploy-echo --replicas=1
# 확인
kubectl get deploy,pod,svc,ep
curl -s $NLB
for i in {1..100}; do curl -s --connect-timeout 1 $NLB | grep Hostname ; done | sort | uniq -c | sort -nr
# 작업용 EC2 - 파드 3개 설정
kubectl scale deployment deploy-echo --replicas=3
# 확인 : NLB 대상 타켓이 아직 initial 일 때 100번 반복 접속 시 어떻게 되는지 확인해보자!
kubectl get deploy,pod,svc,ep
curl -s $NLB
for i in {1..100}; do curl -s --connect-timeout 1 $NLB | grep Hostname ; done | sort | uniq -c | sort -nr
#
kubectl describe deploy -n kube-system aws-load-balancer-controller | grep -i 'Service Account'
Service Account: aws-load-balancer-controller
# [AWS LB Ctrl] 클러스터 롤 바인딩 정보 확인
kubectl describe clusterrolebindings.rbac.authorization.k8s.io aws-load-balancer-controller-rolebinding
# [AWS LB Ctrl] 클러스터롤 확인
kubectl describe clusterroles.rbac.authorization.k8s.io aws-load-balancer-controller-role
리소스를 제어하는 role들을 확인합니다.
Ingress + ALB
Ingress는 Web Proxy 형태로 HTTP/HTTPS만 지원합니다. 다른 서비스들처럼 Load Balancer Controller와 함께 사용하면 Port로 바로 통신할 수 있습니다.
# 게임 파드와 Service, Ingress 배포
curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/3/ingress1.yaml
cat ingress1.yaml
kubectl apply -f ingress1.yaml
# 모니터링
watch -d kubectl get pod,ingress,svc,ep -n game-2048
# 생성 확인
kubectl get-all -n game-2048
kubectl get ingress,svc,ep,pod -n game-2048
kubectl get targetgroupbindings -n game-2048
# ALB 생성 확인
aws elbv2 describe-load-balancers --query 'LoadBalancers[?contains(LoadBalancerName, `k8s-game2048`) == `true`]' | jq
ALB_ARN=$(aws elbv2 describe-load-balancers --query 'LoadBalancers[?contains(LoadBalancerName, `k8s-game2048`) == `true`].LoadBalancerArn' | jq -r '.[0]')
aws elbv2 describe-target-groups --load-balancer-arn $ALB_ARN
TARGET_GROUP_ARN=$(aws elbv2 describe-target-groups --load-balancer-arn $ALB_ARN | jq -r '.TargetGroups[0].TargetGroupArn')
aws elbv2 describe-target-health --target-group-arn $TARGET_GROUP_ARN | jq
# Ingress 확인
kubectl describe ingress -n game-2048 ingress-2048
kubectl get ingress -n game-2048 ingress-2048 -o jsonpath="{.status.loadBalancer.ingress[*].hostname}{'\n'}"
# 게임 접속 : ALB 주소로 웹 접속
kubectl get ingress -n game-2048 ingress-2048 -o jsonpath={.status.loadBalancer.ingress[0].hostname} | awk '{ print "Game URL = http://"$1 }'
# 파드 IP 확인
kubectl get pod -n game-2048 -owide
다음과 같이 ALB에서 파드로 직접 트래픽을 전달합니다.
# 터미널2 : 파드 3개로 증가
kubectl scale deployment -n game-2048 deployment-2048 --replicas 3
Topology Aware Routing
힌트를 등록하여 같은 존 에 있는 파드로 통신되도록 하여 AZ 트래픽을 줄이는 로컬 라우팅 기법입니다.
아래와 같이 3개의 다른 AZ로 파드가 분산 접속되는 것을 확인할 수 있습니다.
Topology Mode
Topology Mode는 같은 AZ(zone)의 목적지 파드로만 접속시키는 기능입니다.
# Topology Aware Routing 설정 : 서비스에 annotate에 아래처럼 추가
kubectl annotate service svc-clusterip "service.kubernetes.io/topology-mode=auto"
# 100번 반복 접속 : 테스트 파드(netshoot-pod)와 같은 AZ(zone)의 목적지 파드로만 접속
kubectl exec -it netshoot-pod -- zsh -c "for i in {1..100}; do curl -s svc-clusterip | grep Hostname; done | sort | uniq -c | sort -nr"
100 Hostname: deploy-echo-7f67d598dc-45trg
# endpointslices 확인 시, 기존에 없던 hints 가 추가되어 있음 >> 참고로 describe로는 hints 정보가 출력되지 않음
kubectl get endpointslices -l kubernetes.io/service-name=svc-clusterip -o yaml
apiVersion: v1
items:
- addressType: IPv4
apiVersion: discovery.k8s.io/v1
endpoints:
- addresses:
- 192.168.3.13
conditions:
ready: true
serving: true
terminating: false
hints:
forZones:
- name: ap-northeast-2c
nodeName: ip-192-168-3-228.ap-northeast-2.compute.internal
targetRef:
kind: Pod
name: deploy-echo-7f67d598dc-hg995
namespace: default
uid: c1ce0e9c-14e7-417d-a1b9-2dfd54da8d4a
zone: ap-northeast-2c
- addresses:
- 192.168.2.65
conditions:
ready: true
serving: true
terminating: false
hints:
forZones:
- name: ap-northeast-2b
nodeName: ip-192-168-2-248.ap-northeast-2.compute.internal
targetRef:
kind: Pod
name: deploy-echo-7f67d598dc-h9vst
namespace: default
uid: 77af6a1b-c600-456c-96f3-e1af621be2af
zone: ap-northeast-2b
- addresses:
- 192.168.1.240
conditions:
ready: true
serving: true
terminating: false
hints:
forZones:
- name: ap-northeast-2a
nodeName: ip-192-168-1-225.ap-northeast-2.compute.internal
targetRef:
kind: Pod
name: deploy-echo-7f67d598dc-45trg
namespace: default
uid: 53ca3ac7-b9fb-4d98-a3f5-c312e60b1e67
zone: ap-northeast-2a
kind: EndpointSlice
...
ssh ec2-user@$N1 sudo iptables -v --numeric --table nat --list KUBE-SERVICES
# 노드1에서 SVC 정책 확인 : SEP(Endpoint) 파드 1개 확인(해당 노드와 같은 AZ에 배포된 파드만 출력) >> 동일 AZ간 접속
ssh ec2-user@$N1 sudo iptables -v --numeric --table nat --list KUBE-SVC-KBDEBIL6IU6WL7RF
Chain KUBE-SVC-KBDEBIL6IU6WL7RF (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SEP-WC4ARU3RZJKCUD7M all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/svc-clusterip:svc-webport -> 192.168.1.240:8080 */
# 노드2에서 SVC 정책 확인 : SEP(Endpoint) 파드 1개 확인(해당 노드와 같은 AZ에 배포된 파드만 출력) >> 동일 AZ간 접속
ssh ec2-user@$N2 sudo iptables -v --numeric --table nat --list KUBE-SVC-KBDEBIL6IU6WL7RF
Chain KUBE-SVC-KBDEBIL6IU6WL7RF (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SEP-3HFAJH523NG6SBCX all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/svc-clusterip:svc-webport -> 192.168.2.36:8080 */
# 노드3에서 SVC 정책 확인 : SEP(Endpoint) 파드 1개 확인(해당 노드와 같은 AZ에 배포된 파드만 출력) >> 동일 AZ간 접속
ssh ec2-user@$N3 sudo iptables -v --numeric --table nat --list KUBE-SVC-KBDEBIL6IU6WL7RF
Chain KUBE-SVC-KBDEBIL6IU6WL7RF (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SEP-H37XIVQWZO52OMNP all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/svc-clusterip:svc-webport -> 192.168.3.13:8080 */
# 같은 AZ에 파드가 없는 경우에는 ? 파드 갯수를 1개로 줄이기
kubectl scale deployment deploy-echo --replicas 1
# 동일 AZ일 경우 0 -> 1 시도
kubectl scale deployment deploy-echo --replicas 0
kubectl scale deployment deploy-echo --replicas 1
# 파드 AZ 확인 : 아래 처럼 현재 다른 AZ에 배포
kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-echo-7f67d598dc-h9vst 1/1 Running 0 18m 192.168.2.65 ip-192-168-2-248.ap-northeast-2.compute.internal <none> <none>
netshoot-pod 1/1 Running 0 66m 192.168.1.137 ip-192-168-1-225.ap-northeast-2.compute.internal <none> <none>
# 100번 반복 접속 : 다른 AZ이지만 목적지파드로 접속됨!
kubectl exec -it netshoot-pod -- zsh -c "for i in {1..100}; do curl -s svc-clusterip | grep Hostname; done | sort | uniq -c | sort -nr"
100 Hostname: deploy-echo-7f67d598dc-h9vst
ssh ec2-user@$N1 sudo iptables -v --numeric --table nat --list KUBE-SERVICES
# 아래 3개 노드 모두 SVC에 1개의 SEP 정책 존재
ssh ec2-user@$N1 sudo iptables -v --numeric --table nat --list KUBE-SVC-KBDEBIL6IU6WL7RF
Chain KUBE-SVC-KBDEBIL6IU6WL7RF (1 references)
pkts bytes target prot opt in out source destination
100 6000 KUBE-SEP-XFCOE5ZRIDUONHHN all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/svc-clusterip:svc-webport -> 192.168.2.65:8080 */
ssh ec2-user@$N2 sudo iptables -v --numeric --table nat --list KUBE-SVC-KBDEBIL6IU6WL7RF
Chain KUBE-SVC-KBDEBIL6IU6WL7RF (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SEP-XFCOE5ZRIDUONHHN all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/svc-clusterip:svc-webport -> 192.168.2.65:8080 */
ssh ec2-user@$N3 sudo iptables -v --numeric --table nat --list KUBE-SVC-KBDEBIL6IU6WL7RF
Chain KUBE-SVC-KBDEBIL6IU6WL7RF (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SEP-XFCOE5ZRIDUONHHN all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/svc-clusterip:svc-webport -> 192.168.2.65:8080 */
# endpointslices 확인 : hint 정보 없음
kubectl get endpointslices -l kubernetes.io/service-name=svc-clusterip -o yaml
같은 AZ에 목적지 파드가 없어도 목적지 파드로 접속은 되지만, 추천하지 않는 방법입니다.
Using AWS Load Balancer Controller for blue/green deployment, canary deployment and A/B testing
AWS Load Balancer Controller (이전 명칭 ALB Ingress Controller)를 사용하면 EKS 사용자가 AWS Application Load Balancer의 기본 지원을 통해 Kubernetes 인그레스 리소스를 통해 블루/그린 배포, A/B 테스트 및 카나리아 배포를 수행할 수 있습니다.
- Weighted target group 가중치가 적용된 대상 그룹
- AWS 고객이 블루/그린 및 카나리아 배포와 A/B 테스트 전략을 채택할 수 있도록 돕기 위해 AWS는 2019년 11월에 애플리케이션 로드 밸런서에 대한 가중 대상 그룹을 발표했습니다. 여러 대상 그룹을 리스너 규칙의 동일한 전달 작업에 연결하고 각 그룹에 대한 가중치를 지정할 수 있습니다.
- 이를 통해 개발자는 트래픽을 여러 버전의 애플리케이션에 분산하는 방법을 제어할 수 있습니다. 예를 들어, 가중치가 8과 2인 두 개의 대상 그룹이 있는 규칙을 정의하면 로드 밸런서는 트래픽의 80%를 첫 번째 대상 그룹으로, 20%를 다른 대상 그룹으로 라우팅 합니다.
- Advanced request routing 고급 요청 라우팅
- AWS는 가중치가 적용된 대상 그룹 외에도 2019년에 고급 요청 라우팅 기능을 발표했습니다. 고급 요청 라우팅은 개발자에게 표준 및 사용자 지정 HTTP 헤더와 메서드, 요청 경로, 쿼리 문자열, 소스 IP 주소를 기반으로 규칙을 작성하고 트래픽을 라우팅 할 수 있는 기능을 제공합니다.
- 이 새로운 기능은 라우팅을 위한 프락시 플릿의 필요성을 없애 애플리케이션 아키텍처를 간소화하고, 로드 밸런서에서 원치 않는 트래픽을 차단하며, A/B 테스트를 구현할 수 있도록 합니다.
마치며
이번 스터디에서는 AWS EKS VPC CNI에 대해 학습했습니다. EKS는 여타 다른 CSP에서 제공하는 쿠버네티스 서비스에 비해 Kubernetes의 기본 오브젝트를 이용하여 AWS 상의 리소스를 손쉽게 활용할 수 있고, 이에 따라 성능을 높이고 관리할 수 있다는 점이 매력적인 것 같습니다.
이제 9주 동안의 스터디가 마무리되었네요.. 따라가는 것도 쉽지 않았지만, 스터디를 이끌어 주신 가시다님께서 고생을 많이 하신 것 같습니다. 그리고 장시간의 스터디를 체계적으로 이끌어 가시는 모습은 여러 가지 개념을 기반으로 엄청난 내공이 없다면 불가능한 것이겠지요..
많이 모자람을 느끼고, 더 노력해야겠다는 생각이 듭니다.
이번주에는 제가 다니고 있는 위니텍에서 50회 과학기술정보통신부의 디지털 서비스 심사에 통과하는 쾌거가 있었습니다.
다양한 심사내용들 중에서 가장 중요했던 것은 2년이 넘는 기간동안 CloudNet@ 의 스터디를 통해 학습한 내용들을 통해 구축한 EKS기반 글로벌 홍수 모니터링 시스템이었습니다. 혼자서는 이렇게 학습하지 못했을 텐데, 스터디를 통해 꾸준히 지식들을 쌓을 수 있었습니다.
지금까지 배운 것들을 기반으로, 다시 복기하고 내년부터는 이러한 지식들을 확산하는 것을 목표로 잡았습니다! 대구에서도 생태계가 더욱 활성화되고, 이러한 기술들이 많은 시스템에 적용될 수 있도록 분발하겠습니다.
이상으로 이번 포스팅을 마치도록 하겠습니다.
감사합니다.
'클라우드 컴퓨팅 & NoSQL > [KANS] 쿠버네티스 네트워크 심화 스터디' 카테고리의 다른 글
[8주차 - Cilium CNI] KANS 스터디 (24.10.20) (7) | 2024.10.25 |
---|---|
[7주차 - Service Mesh(Istio)] KANS 스터디 (24.10.13) (0) | 2024.10.17 |
[6주차 - Ingress & Gateway API] KANS 스터디 (24.10.06) (7) | 2024.10.13 |
[5주차 - Service : LoadBalancer] KANS 스터디 (24.09.29) (3) | 2024.10.05 |
[4주차 - Service : ClusterIP, NodePort] KANS 스터디 (24.09.22) (2) | 2024.09.26 |