네트워크
Mont Kim / January 2023 (867 Words, 5 Minutes)
2주차 네트워크
실습 환경 구성
실습환경은 KOPS를 이용하며
저번주와 다르게 원클릭 배포코드를 공유해주셨다.
Cloudformation 링크에 들어가 파라미터들을 입력하면
KOPS-EC2가 생성되고, KOPS-EC2에서 KOPS 클러스터를 프로비저닝한다
약 6분정도 소요되니 돌려놓고 다음 실습 개념을 익힐쯤이면 프로비저닝이 완료될거같다.
CNI
쿠버네티스에서 생성된 컨테이너들은 CNI 를 통해 통신을 한다.
하지만 온프레미스 말고 클라우드를 사용할경우
쿠버네티스에서 자체적으로 제공하는 CNI가 아닌
클라우드에서 자체적으로 제공하는 CNI를 이용할 수 있다.
AWS VPC CNI
AWS VPC CNI를 이용하면 Pod의 네트워크 IP대역과 워커의 네트워크 IP대역이 동일하게 설정된다.
https://github.com/aws/amazon-vpc-cni-k8s
쿠버네티스에서 제공하는 CNI와 다른점이라면
일반 쿠버네티스 CNI의 경우 POD1에서 POD2로 통신을 시도할떄
노드간 통신을 위해 패킷 오버레이가 발생해 한번의 오버헤드가 발생된다.
반면에 AWS VPC CNI의 경우
같은 네트워크 대역을 공유하기때문에 원본패킷을 POD1에서 2로 보낼 수 있다.
POD간 통신
AWS VPC CNI를 이용한 파드간 통신을 확인하기 위해
TCP DUMP를 이용해본다.
# 파드 IP 변수 지정
POD1=$(kubectl get pod pod-1 -o jsonpath={.status.podIP})
POD2=$(kubectl get pod pod-2 -o jsonpath={.status.podIP})
# 파드1 Shell 에서 파드2로 ping 테스트
kubectl exec -it pod-1 -- ping -c 2 $POD2
# 파드2 Shell 에서 파드1로 ping 테스트
kubectl exec -it pod-2 -- ping -c 2 $POD1
POD1, 2의 IP를 kubectl 명령어로 파싱해 변수로 저장하여
pod1에서 pod2로 핑을 보내보고
pod2에서 pod1로 핑을 보내본다.
# 워커 노드 EC2 : TCPDUMP 확인
sudo tcpdump -i any -nn icmp
sudo tcpdump -i ens5 -nn icmp
sudo tcpdump -i ens6 -nn icmp
각 pod들이 할당되어있는 노드(node1 / node2) 에서
tcpdump 명령어들로 ping을 시도했을때 오가는 패킷의 정보들을 확인 할 수 있다
좌하단, 우하단은
다만 AWS VPC CNI를 이용할경우
워커노드에 생성 가능한 최대 파드갯수가 제한된다.
aws ec2 describe-instance-types --filters Name=instance-type,Values=t3.* \
--query "InstanceTypes[].{Type: InstanceType, MaxENI: NetworkInfo.MaximumNetworkInterfaces, IPv4addr: NetworkInfo.Ipv4AddressesPerInterface}" \
--output table
--------------------------------------
| DescribeInstanceTypes |
+----------+----------+--------------+
| IPv4addr | MaxENI | Type |
+----------+----------+--------------+
| 15 | 4 | t3.2xlarge |
| 6 | 3 | t3.medium |
| 12 | 3 | t3.large |
| 15 | 4 | t3.xlarge |
| 2 | 2 | t3.micro |
| 2 | 2 | t3.nano |
| 4 | 3 | t3.small |
+----------+----------+--------------+
현재 KOPS에서 실습중인 t3.medium 노드의경우
ENI를 3개까지 사용 할 수 있고
ENI당 Private IP를 6개까지 사용할수있어
3*(6-1) +2 =17개의 POD를 배치할수있는것을 확인 할 수 있다.
(17개중에 aws-node와 kube-proxy가 포함되어있어 사실상 15개만 할당이 가능하다)
kubectl apply -f ~/pkos/2/nginx-dp.yaml
kubectl scale deployment nginx-deployment --replicas=30
프로비저닝한 KOPS-EC2의 하위 폴더에 예제 파일들이 담겨있는데
nginx deployment를 생성한후, scale 명령어로 30개로 올려보면
15개만 생성이되고 나머지는 pending 상태로 대기중인것을 볼 수 있다.
과제2
MAX POD 100개 지정하기
따라서 해당 인스턴스 타입에서는 노드당 pod의 갯수가 제한된다.
AWS VPC CNI prefix assignment mode를 통해 노드당 파드제한증가가 가능하다
https://aws.amazon.com/ko/blogs/containers/amazon-vpc-cni-increases-pods-per-node-limits/
따라서 Nitro Based 인스턴스를 이용하여 MAX POD갯수를 증가시키는 실습을 진행한다.
우선 KOPS 프로비저닝할때 C5.large로 생성하거나,
AWS 콘솔에서 AutoScaling그룹을 수정하거나,
방법은 다양하다
kops edit cluster
...
kubelet:
anonymousAuth: false
maxPods: 110
...
networking:
amazonvpc:
env:
- name: WARM_PRENFIX_TARGET
value: "1"
- name: ENABLE_PREFIX_DELEGATION
value: "true"
...
kops 정보를 수정한후 업데이트를 진행한다.
kops update cluster --yes && echo && sleep 5 && kops rolling-update cluster --yes
업데이트가 진행될때 인스턴스들이 재생성되면서 control plane의 public IP가 변경된다.
따라서 재시작될때 Route53에서 public IP를 새로 생성된 control plane의 public IP로 변경해준다.
노드당 각 5-8분정도씩 소요되기때문에 약 20분정도 기다리면 새로 프로비저닝된 인스턴스들로 교환이 끝난다.
마지막으로
Cluster 설정에 limit range라는 값이 설정되어있어
pod이 할당될때 최소 cpu request를 100m으로 설정되어있다.
이 값이 설정되어있을경우, 각 pod에 할당된 cpu가 너무 커서 한 노드에 pod를 많이 띄울수 없다.
이부분을 삭제하거나 5m정도로 수정하면 100개는 쉽게띄울수 있을것이다.
워커 노드 한개를 cordon하고 다른 워커노드에서 replicaset을 100개로 증가시켜본다
kubectl scale deployment nginx-deployment --replicas=100
성공적으로 값이 증가된것 확인 할 수 있다.
서비스
쿠버네티스 POD을 내부/외부로 통신하기위해서 서비스가 존재한다.
서비스는 ClusterIP, NodePort, LoadBalancer 가 존재하며
추가적으로 Service( LoadBalncer Controller)가 존재한다.
ClusterIP는 내부적인 통신을 위한 서비스 타입이다
NodePort는 pod가 할당되어있는 node의 특정 포트를 open하여 외부로 통신이 가능하게 하는 서비스 타입이다
LoadBalancer는 일반적으로 클라우드에서 사용되는 방법으로
서비스를 외부에 노출시키는 표준 방법이다.
과제3
NLB를 이용해 ExternalDNS를 이용해 POD로 접속하기
nginx pod를 배포하고
kubectl expose pod nginx --type LoadBalancer --port 80 --target-port 8080 --name nginx-svc
service를 loadbalancer로 생성하면 LB가 생성된다.
kubectl describe svc nginx-svc
loadbalancer ingress 값을 통해 접속할 주소를 확인한다.
이제 External DNS를 이용해본다
MyDOMAIN=mont-kim.com
kubectl annotate service nginx-svc"external-dns.alpha.kubernetes.io/hostname=$MyDOMAIN."
명령어를 통해 external dns에 등록을 진행한다.
nginx.mont-kim.com 에서 접속 가능한것 확인완료!
과제4
NLB에 TLS 적용하기
미리 준비해야하는것 : 공인도메인, 도메인 등록(Route 53), NLB 인증서 발급완료, External DNS 준비
AWS Cert Manger 콘솔에 들어가 인증서 발급을 받는다
도메인은 제 도메인 기준으로
*.mont-kim.com 두개를 모두 등록해줍니다.
등록에는 약 30분이 소요된다고하는데 저는 한시간이 좀 넘어걸린거같네
KOPS에서 확인해봅니다.
aws acm list-certificates --max-items 10
저는 ACM에 예전에 Lets Encrypt로 발급받은 인증서도 등록을 같이해놔서 두개가 뜬다.
하단에
“*.mont-kim.com”,
“mont-kim.com” 이 모두 등록되어있는것이 확인되었다.
이제 해당 ARN 등록을 위해 조회를 한다.
aws acm list-certificates --query 'CertificateSummaryList[].CertificateArn[]' --output text
CERT_ARN='aws acm list-certificates --query 'CertificateSummaryList[].CertificateArn[]' --output text'
MyDomain=websrv.mont-kim.com
변수에 등록을 진행
app, 서비스 생성
cat <<EOF | kubectl create -f -
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:
external-dns.alpha.kubernetes.io/hostname: "${MyDomain}"
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-ssl-ports: "https"
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: ${CERT_ARN}
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "http"
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
- port: 443
targetPort: 8080
protocol: TCP
name: https
type: LoadBalancer
loadBalancerClass: service.k8s.aws/nlb
selector:
app: deploy-websrv
EOF