EKS 8탄 - 2주차.
본 내용은 CloudNet 주말 스터디 내용을 참고로 작성되었습니다.
https://gasidaseo.notion.site/gasidaseo/CloudNet-Blog-c9dfa44a27ff431dafdd2edacc8a1863
계속 테스트하며 내용과 설명이 업데이트 됩니다.
원클릭 배포로 네트워크와 EKS한번에 구축 이해
AWS VPC CNI 특징 이해
보조 프라이빗 IP 사용 이해
노드간 파드 통신 이해하자
파드에서 외부 통신하는것 이해
노드의 파드 생성 갯수 제한 이해
노드의 파드 생성 갯수 제한 테스트
1
AWS콘솔로 로그인하자. 서울리전 으로 변경
https://console.aws.amazon.com/
사전 준비?
ec2 키페이 필요
access-key / secret-key 필요
설치?
Cloudformation 파일로 한번에 네트워크 VPC와 EKS 한번에 설치해보자.
스택이름 myeks
(변경하지 마세요. 필터링하거나 스택이름으로 명령어를 myyeks로 사용합니다.)
https://vclock.kr/timer/#countdown=00:10:00&enabled=0&seconds=0&sound=xylophone&loop=1
2
설치 파일 참고
1.28
1.24
CloudFormation 에 EC2의 UserData 부분(Script 실행)으로
Amazon EKS 설치(with OIDC, Endpoint Public)를 진행합니다.
설명:
OpenID Connect(OIDC) 자격 증명 공급자 생성 = 클러스터의 IAM OIDC 제공업체 생성
AWS Identity and Access Management에서는 OpenID Connect(OIDC)를 사용하여 페더레이션형 ID를 지원하는 기능을 추가했습니다. 이 기능을 사용하면 지원되는 ID 제공업체를 이용해 AWS API 호출을 인증하고 유효한 OIDC JSON 웹 토큰(JWT)을 수신할 수 있습니다.
이 토큰을 AWS STS AssumeRoleWithWebIdentity API 작업에 전달하고 IAM 임시 역할 자격 증명을 수신할 수 있습니다. 이 자격 증명을 사용하여 Amazon S3 및 DynamoDB와 같은 AWS 서비스와 상호 작용할 수 있습니다.
https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/iam-roles-for-service-accounts.html
3
Add-on 같이 설치 됨 :
최신 버전의 kube-proxy, coredns, aws vpc cni
4
쿠버네티스 1.28 로 설치.
최신버전 2단계 전 정도가 addon이 가장 많음.
비용이 나오므로 NAT는 설치 안함.
bastion ec2 생성
subnet pub3 ,private 3
실행 결과
5
(선택)
다음은 CLI로 설치하는 법이다.
# YAML 파일 다운로드
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/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
예시) aws cloudformation deploy --template-file eks-oneclick.yaml --stack-name myeks --parameter-overrides KeyName=kp-gasida SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 MyIamUserAccessKeyID=AKIA5... MyIamUserSecretAccessKey='CVNa2...' ClusterBaseName=myeks --region ap-northeast-2
# CloudFormation 스택 배포 완료 후 작업용 EC2 IP 출력
aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[0].OutputValue' --output text
# 마스터노드 SSH 접속
ssh -i ~/.ssh/xxxxxxxx.pem ec2-user@$(aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[0].OutputValue' --output text)
6
CloudFormation 파일 내용
AWSTemplateFormatVersion: '2010-09-09'
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "<<<<< Deploy EC2 >>>>>"
Parameters:
- KeyName
- MyIamUserAccessKeyID
- MyIamUserSecretAccessKey
- SgIngressSshCidr
- MyInstanceType
- LatestAmiId
:
Parameters:
KeyName:
Description: Name of an existing EC2 KeyPair to enable SSH access to the instances. Linked to AWS Parameter
Type: AWS::EC2::KeyPair::KeyName
ConstraintDescription: must be the name of an existing EC2 KeyPair.
MyIamUserAccessKeyID:
Description: IAM User - AWS Access Key ID (won't be echoed)
Type: String
NoEcho: true
MyIamUserSecretAccessKey:
Description: IAM User - AWS Secret Access Key (won't be echoed)
Type: String
NoEcho: true
SgIngressSshCidr:
Description: The IP address range that can be used to communicate to the EC2 instances
Type: String
MinLength: '9'
MaxLength: '18'
Default: 0.0.0.0/0
AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
:
KubernetesVersion:
Description: Enter Kubernetes Version, 1.23 ~ 1.26
Type: String
Default: 1.24
WorkerNodeInstanceType:
Description: Enter EC2 Instance Type. Default is t3.medium.
Type: String
Default: t3.medium
WorkerNodeCount:
Description: Worker Node Counts
Type: String
Default: 3
:
VpcBlock:
Type: String
Default: 192.168.0.0/16
PublicSubnet1Block:
Type: String
Default: 192.168.1.0/24
PublicSubnet2Block:
Type: String
Default: 192.168.2.0/24
PublicSubnet3Block:
Type: String
Default: 192.168.3.0/24
PrivateSubnet1Block:
Type: String
Default: 192.168.11.0/24
PrivateSubnet2Block:
Type: String
Default: 192.168.12.0/24
PrivateSubnet3Block:
Type: String
Default: 192.168.13.0/24
:
# EKSCTL-Host
EKSEC2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: eksctl-host Security Group
VpcId: !Ref EksVPC
Tags:
- Key: Name
Value: !Sub ${ClusterBaseName}-HOST-SG
SecurityGroupIngress:
- IpProtocol: '-1'
#FromPort: '22'
#ToPort: '22'
CidrIp: !Ref SgIngressSshCidr
// EC2 서버 IP는 100번으로 고정 지정한다.
EKSEC2:
Type: AWS::EC2::Instance
:
AssociatePublicIpAddress: true
PrivateIpAddress: 192.168.1.100
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeType: gp3
VolumeSize: 30
DeleteOnTermination: true
UserData:
Fn::Base64:
!Sub |
#!/bin/bash
hostnamectl --static set-hostname "${ClusterBaseName}-bastion-EC2"
# Config convenience
echo 'alias vi=vim' >> /etc/profile
echo "sudo su -" >> /home/ec2-user/.bashrc
# Change Timezone
sed -i "s/UTC/Asia\/Seoul/g" /etc/sysconfig/clock
ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
# Install Packages
cd /root
yum -y install tree jq git htop lynx
# Install kubectl & helm
#curl -O https://s3.us-west-2.amazonaws.com/amazon-eks/1.26.2/2023-03-17/bin/linux/amd64/kubectl
curl -O https://s3.us-west-2.amazonaws.com/amazon-eks/1.25.7/2023-03-17/bin/linux/amd64/kubectl
install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
curl -s https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
# Install eksctl
curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
mv /tmp/eksctl /usr/local/bin
# Install aws cli v2
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip >/dev/null 2>&1
sudo ./aws/install
complete -C '/usr/local/bin/aws_completer' aws
echo 'export AWS_PAGER=""' >>/etc/profile
export AWS_DEFAULT_REGION=${AWS::Region}
echo "export AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION" >> /etc/profile
# Install YAML Highlighter
wget https://github.com/andreazorzetto/yh/releases/download/v0.4.0/yh-linux-amd64.zip
unzip yh-linux-amd64.zip
mv yh /usr/local/bin/
# Install krew
curl -LO https://github.com/kubernetes-sigs/krew/releases/download/v0.4.3/krew-linux_amd64.tar.gz
tar zxvf krew-linux_amd64.tar.gz
./krew-linux_amd64 install krew
export PATH="$PATH:/root/.krew/bin"
echo 'export PATH="$PATH:/root/.krew/bin"' >> /etc/profile
# Install krew plugin
kubectl krew install ctx ns get-all df-pv # ktop mtail tree
# Install kube-ps1
echo 'source <(kubectl completion bash)' >> /etc/profile
echo 'alias k=kubectl' >> /etc/profile
echo 'complete -F __start_kubectl k' >> /etc/profile
git clone https://github.com/jonmosco/kube-ps1.git /root/kube-ps1
cat <<"EOT" >> /root/.bash_profile
source /root/kube-ps1/kube-ps1.sh
KUBE_PS1_SYMBOL_ENABLE=false
function get_cluster_short() {
echo "$1" | cut -d . -f1
}
KUBE_PS1_CLUSTER_FUNCTION=get_cluster_short
KUBE_PS1_SUFFIX=') '
PS1='$(kube_ps1)'$PS1
EOT
# Install Docker
amazon-linux-extras install docker -y
systemctl start docker && systemctl enable docker
# Create SSH Keypair
ssh-keygen -t rsa -N "" -f /root/.ssh/id_rsa
# IAM User Credentials
export AWS_ACCESS_KEY_ID=${MyIamUserAccessKeyID}
export AWS_SECRET_ACCESS_KEY=${MyIamUserSecretAccessKey}
export AWS_DEFAULT_REGION=${AWS::Region}
export ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
echo "export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" >> /etc/profile
echo "export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" >> /etc/profile
echo "export AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION" >> /etc/profile
echo "export ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)" >> /etc/profile
# CLUSTER_NAME
export CLUSTER_NAME=${ClusterBaseName}
echo "export CLUSTER_NAME=$CLUSTER_NAME" >> /etc/profile
# K8S Version
export KUBERNETES_VERSION=${KubernetesVersion}
echo "export KUBERNETES_VERSION=$KUBERNETES_VERSION" >> /etc/profile
# Create EKS Cluster & Nodegroup
#eksctl create cluster --name $CLUSTER_NAME --region=$AWS_DEFAULT_REGION --nodegroup-name=ng1 --node-type=${WorkerNodeInstanceType} --nodes ${WorkerNodeCount} --node-volume-size=${WorkerNodeVolumesize} --vpc-public-subnets "$PubSubnet1","$PubSubnet2","$PubSubnet3" --version ${KubernetesVersion} --ssh-access --ssh-public-key ${KeyName} --with-oidc --external-dns-access --full-ecr-access --dry-run > myeks.yaml
eksctl create cluster --name $CLUSTER_NAME --region=$AWS_DEFAULT_REGION --nodegroup-name=ng1 --node-type=${WorkerNodeInstanceType} --nodes ${WorkerNodeCount} --node-volume-size=${WorkerNodeVolumesize} --vpc-public-subnets "$PubSubnet1","$PubSubnet2","$PubSubnet3" --version ${KubernetesVersion} --ssh-access --ssh-public-key /root/.ssh/id_rsa.pub --with-oidc --external-dns-access --full-ecr-access --dry-run > myeks.yaml
sed -i 's/certManager: false/certManager: true/g' myeks.yaml
sed -i 's/ebs: false/ebs: true/g' myeks.yaml
cat <<EOT >> myeks.yaml
addons:
- name: vpc-cni # no version is specified so it deploys the default version
version: v1.12.6-eksbuild.1
attachPolicyARNs:
- arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
- name: kube-proxy
version: latest # auto discovers the latest available
- name: coredns
version: latest # v1.9.3-eksbuild.2
EOT
nohup eksctl create cluster -f myeks.yaml --verbose 4 --kubeconfig "/root/.kube/config" 1> /root/create-eks.log 2>&1 &
echo 'cloudinit End!'
Outputs:
eksctlhost:
Value: !GetAtt EKSEC2.PublicIp
(20분후 설치 완료)
7
브라우저 -> 새탭에서 보기
8
myeks-bastion-EC2 에 로그인 하여 클러스터 생성 모니터링 하자.
9
(노드 서버 생성 1분후 노드로 kubectl 명령어로 조회가 가능하다.)
while true ; do kubectl get nodes ;echo "-----------";date; sleep 2 ;done
10
이해 완료??
설치완료 확인!
이후 테스트를 위해 pod, node등을 변수로 지정한다.
1
k get nodes
[[A(eks5-access@myeks:N/A) [root@myeks-bastion-EC2 ~]# k get nodes
NAME STATUS ROLES AGE VERSION
ip-192-168-1-251.ap-northeast-2.compute.internal Ready > 15h v1.24.11-eks-a59e1f0
ip-192-168-2-25.ap-northeast-2.compute.internal Ready > 15h v1.24.11-eks-a59e1f0
ip-192-168-3-163.ap-northeast-2.compute.internal Ready > 15h v1.24.11-eks-a59e1f0
2
# default 네임스페이스 적용
kubectl ns default
3
# 노드 IP 확인 및 PrivateIP 변수 지정
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
-------------
192.168.1.251, 192.168.2.25, 192.168.3.163
4
# 노드 보안그룹 ID 확인
NGSGID=$(aws ec2 describe-security-groups --filters Name=group-name,Values=*ng1* --query "SecurityGroups[*].[GroupId]" --output text)
aws ec2 authorize-security-group-ingress --group-id $NGSGID --protocol '-1' --cidr 192.168.1.100/32
// 192.168.1.100 에서 ping 되게 하기
# 워커 노드 SSH 접속
ssh ec2-user@$N1 hostname
ssh ec2-user@$N2 hostname
ssh ec2-user@$N3 hostname
5
addon으로 설치된 이미지 정보 확인
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-k8s-cni:v1.12.6-eksbuild.1
2 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/eks/coredns:v1.9.3-eksbuild.3
3 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/eks/kube-proxy:v1.24.10-minimal-eksbuild.2
eksctl 설치/업데이트 addon 확인
eksctl get addon --cluster $CLUSTER_NAME
----------------
NAME VERSION STATUS ISSUES IAMROLE UPDATE AVAILABLE CONFIGURATION VALUES
coredns v1.9.3-eksbuild.3 ACTIVE 0
kube-proxy v1.24.10-eksbuild.2 ACTIVE 0
vpc-cni v1.12.6-eksbuild.1 ACTIVE 0 arn:aws:iam::319485572629:role/eksctl-myeks-addon-vpc-cni-Role1-VZQZBS1G4IX8
ㅎ//vpc-cni는 iam role도 연결되어 있음
// 설치시 addon 포함 시킴
(eks5-access@myeks:default) [root@myeks-bastion-EC2 ~]# tail myeks.yaml yh
==> myeks.yaml <==
id: subnet-085aee2bea2da5071
addons:
- name: vpc-cni # no version is specified so it deploys the default version
version: v1.12.6-eksbuild.1
attachPolicyARNs:
- arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
- name: kube-proxy
version: latest # auto discovers the latest available
- name: coredns
version: latest # v1.9.3-eksbuild.2
// EKS는 2023년 6월 현재 1.24버전이 addon을 가장 많이 지원함.
1
AWS VPC CNI ?
파드의 IP 네트워크 대역과 노드(워커)의 IP 대역이 같아서 직접 통신이 가능하다
VPC 와 통합 : VPC Flow logs , VPC 라우팅 정책, 보안 그룹(Security group) 을 사용 가능함.
VPC ENI 에 미리 할당된 IP(=Local-IPAM Warm IP Pool)를 파드에서 사용할 수 있음.
2
K8s CNI플러그인(Calico) CNI와 AWS VPC CNI 차이?
AWS VPC CNI는 노드와 파드의 네트워크 대역이 같다.
3
워커 노드에 생성 가능한 최대 파드 갯수 제한이 있다.
https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/cni-increase-ip-addresses.html
기본
1) Secondary IPv4 addresses : 인스턴스 유형에 최대 ENI 갯수와 할당 가능 IP 수를 조합하여 선정
늘리기
2) IPv4 Prefix Delegation : IPv4 28bit 서브넷(prefix)를 위임하여 할당 가능 IP 수와 인스턴스 유형에 권장하는 최대 갯수로 선정
이해 완료??
1
# 노드 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
--------------------------------------------------------------------
| DescribeInstances |
+-------------------+-----------------+-----------------+----------+
| InstanceName | PrivateIPAdd | PublicIPAdd | Status |
+-------------------+-----------------+-----------------+----------+
| myeks-ng1-Node | 192.168.3.163 | 13.124.28.125 | running |
| myeks-ng1-Node | 192.168.2.25 | 3.37.45.216 | running |
| myeks-ng1-Node | 192.168.1.251 | 3.35.25.161 | running |
| myeks-bastion-EC2| 192.168.1.100 | 52.78.156.220 | running |
2
# 파드 IP 확인
kubectl get pod -n kube-system -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase
NAME IP STATUS
aws-node-bfrv9 192.168.1.251 Running
aws-node-gtk94 192.168.2.25 Running
aws-node-r6spn 192.168.3.163 Running
coredns-6777fcd775-2xfgg 192.168.2.55 Running
coredns-6777fcd775-ftgxw 192.168.3.225 Running
kube-proxy-hqfrl 192.168.1.251 Running
kube-proxy-jg2nz 192.168.2.25 Running
kube-proxy-xmtkn 192.168.3.163 Running
3
# 파드 이름 확인
kubectl get pod -A -o name
4
# 파드 갯수 확인
kubectl get pod -A -o name | wc -l
-----
8
5
노드에 툴 설치
# 노드에 툴 설치
ssh ec2-user@$N1 sudo yum install links tree jq tcpdump -y
ssh ec2-user@$N2 sudo yum install links tree jq tcpdump -y
ssh ec2-user@$N3 sudo yum install links tree jq tcpdump -y
6
# CNI 정보 확인
파일들이 보임.
ssh ec2-user@$N1 tree /var/log/aws-routed-eni
/var/log/aws-routed-eni
├── egress-v4-plugin.log
├── ipamd.log
└── plugin.log
ssh ec2-user@$N1 cat /var/log/aws-routed-eni/plugin.log | jq
ssh ec2-user@$N1 cat /var/log/aws-routed-eni/ipamd.log | jq
ssh ec2-user@$N1 cat /var/log/aws-routed-eni/egress-v4-plugin.log | jq
7
# 네트워크 정보 확인
: eniY는 pod network 네임스페이스와 veth pair
ssh ec2-user@$N1 sudo ip -br -c addr
------------------
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 192.168.1.251/24 fe80::88:34ff:fed9:c2bc/64
ssh ec2-user@$N1 sudo ip -c addr
ssh ec2-user@$N1 sudo ip -c route
ssh ec2-user@$N1 sudo iptables -t nat -S
ssh ec2-user@$N1 sudo iptables -t nat -L -n -v
다시 네트워크 IP 블럭이 동일하다는것에 대해 알아보자~
1
core dns 네트워크 보자.
kubectl get pod -n kube-system -l k8s-app=kube-dns -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-6777fcd775-2xfgg 1/1 Running 0 19h 192.168.2.55 ip-192-168-2-25.ap-northeast-2.compute.internal <none> <none>
coredns-6777fcd775-ftgxw 1/1 Running 0 19h 192.168.3.225 ip-192-168-3-163.ap-northeast-2.compute.internal <none> <none>
2
ENI0, ENI1 으로 2개의 ENI는 자신의 IP 이외에 추가적으로 5개의 보조 프라이빗 IP를 가질수 있다
coredns 파드는 veth 으로 호스트에는 eniY@ifN 인터페이스와 파드에 eth0 과 연결되어 있다
3
VPC ENI 에 미리 할당된 IP(=Local-IPAM Warm IP Pool)를 파드에서 사용할 수 있음
4
확인?
# [터미널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"
테스트전 eth 모니터링
eth0 , eth1 , eth1 존재
5
# 테스트용 파드 netshoot-pod 생성
cat <<EOF | kubectl create -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
eth1이 추가 됨.
eth1이 추가됨.
6
# 파드 이름 변수 지정
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
(eks5-access@myeks:default) [root@myeks-bastion-EC2 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
netshoot-pod-7757d5dd99-5zg9b 1/1 Running 0 2m49s 192.168.2.243 ip-192-168-2-25.ap-northeast-2.compute.internal <none> <none>
netshoot-pod-7757d5dd99-tx58z 1/1 Running 0 2m49s 192.168.1.74 ip-192-168-1-251.ap-northeast-2.compute.internal <none> <none>
netshoot-pod-7757d5dd99-zw4ss 1/1 Running 0 2m49s 192.168.3.30 ip-192-168-3-163.ap-northeast-2.compute.internal <none> <none>
// 3번 node보면 192.168.3.30 라우팅 테이블이 올라와 있다.
(eks5-access@myeks:default) [root@myeks-bastion-EC2 ~]# kubectl get pod -o=custom-columns=NAME:.metadata.name,IP:.status.podIP
NAME IP
netshoot-pod-7757d5dd99-5zg9b 192.168.2.243
netshoot-pod-7757d5dd99-tx58z 192.168.1.74
netshoot-pod-7757d5dd99-zw4ss 192.168.3.30
이해 완료???
파드간 통신 흐름 : AWS VPC CNI 경우 별도의 오버레이(Overlay) 통신 기술 없이, VPC Native 하게 파드간 직접 통신이 가능하다.
1
# 파드 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
echo $PODIP1
echo $PODIP2
echo $PODIP3
192.168.2.243
192.168.1.74
192.168.3.30
# 파드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 확인 - 왜지???? 패킷 덤프 확인이 되나요?
sudo tcpdump -i any -nn icmp
sudo tcpdump -i eth1 -nn icmp
sudo tcpdump -i eth0 -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
2
노드 IP 확인 !!
k get nodes -owide
(eks5-access@myeks:default) [root@myeks-bastion-EC2 ~]# k get nodes -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
ip-192-168-1-251.ap-northeast-2.compute.internal Ready <none> 20h v1.24.11-eks-a59e1f0 192.168.1.251 3.35.25.161 Amazon Linux 2 5.10.176-157.645.amzn2.x86_64 containerd://1.6.19
ip-192-168-2-25.ap-northeast-2.compute.internal Ready <none> 20h v1.24.11-eks-a59e1f0 192.168.2.25 3.37.45.216 Amazon Linux 2 5.10.176-157.645.amzn2.x86_64 containerd://1.6.19
ip-192-168-3-163.ap-northeast-2.compute.internal Ready <none> 20h v1.24.11-eks-a59e1f0 192.168.3.163 13.124.28.125 Amazon Linux 2 5.10.176-157.645.amzn2.x86_64 containerd://1.6.19
3
POD IP 확인
pod ip가 직접 통신 한다.
파드간 통신 흐름 : AWS VPC CNI 경우 별도의 오버레이(Overlay) 통신 기술 없이, VPC Native 하게 파드간 직접 통신이 가능하다.
별도의 NAT 동작 없이 통신 가능!
echo $PODIP1
echo $PODIP2
echo $PODIP3
이해 완료????
1
파드에서 외부 통신 흐름 :
iptable 에 SNAT 을 통하여 노드의 eth0 IP로 변경되어서 외부와 통신됨
pod가 접속하는 공인IP = work node의 유동 퍼블릭 IP를 통해 외부 통신한다.
1
# 워커 노드 EC2 : 퍼블릭IP 확인
curl -s ipinfo.io/ip ; echo
# 모니터링
워커 노드 3대 EC2 로그인
: TCPDUMP 확인
sudo tcpdump -i any -nn icmp
sudo tcpdump -i eth0 -nn icmp
2
# 작업용 EC2 : pod Shell 에서 외부로 ping
kubectl exec -it $PODNAME1 -- ping -c 1 www.google.com
kubectl exec -it $PODNAME1 -- ping -i 0.1 www.google.com
pod ip
192.168.2.243
192.168.1.74
192.168.3.30
3
pod가 접속하는 공인IP = work node의 유동 퍼블릭 IP를 통해 외부 통신한다.
3.35.25.161
3.37.45.216
13.124.28.125
10:14:23.098409 IP 192.168.2.243 > 142.251.222.4: ICMP echo request, id 6011, seq 1, length 64
10:14:23.098430 IP 192.168.2.25 > 142.251.222.4: ICMP echo request, id 38163, seq 1, length 64
10:14:23.126944 IP 142.251.222.4 > 192.168.2.25: ICMP echo reply, id 38163, seq 1, length 64
10:14:23.126991 IP 142.251.222.4 > 192.168.2.243: ICMP echo reply, id 6011, seq 1, length 64
4
# 작업용 EC2 : pod-1 Shell 에서 외부 접속 확인 - 공인IP는 어떤 주소인가?
kubectl exec -it $PODNAME1 -- curl -s ipinfo.io/ip ; echo
k get nodes -owide
(eks5-access@myeks:game-2048) [root@myeks-bastion-EC2 ~]# k get nodes -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
ip-192-168-1-251.ap-northeast-2.compute.internal Ready <none> 40h v1.24.11-eks-a59e1f0 192.168.1.251 3.35.25.161 Amazon Linux 2 5.10.176-157.645.amzn2.x86_64 containerd://1.6.19
ip-192-168-2-25.ap-northeast-2.compute.internal Ready <none> 40h v1.24.11-eks-a59e1f0 192.168.2.25 3.37.45.216 Amazon Linux 2 5.10.176-157.645.amzn2.x86_64 containerd://1.6.19
ip-192-168-3-163.ap-northeast-2.compute.internal Ready <none> 40h v1.24.11-eks-a59e1f0 192.168.3.163 13.124.28.125 Amazon Linux 2 5.10.176-157.645.amzn2.x86_64 containerd://1.6.19
5
# 워커 노드 EC2
## 출력된 결과를 보고 어떻게 빠져나가는지 고민해보자!
ip rule
ip route show table main
sudo iptables -L -n -v -t nat
sudo iptables -t nat -S
IPTALBE 을 일부 사용한다!!!
# 파드가 외부와 통신시에는 아래 처럼 'AWS-SNAT-CHAIN-0, AWS-SNAT-CHAIN-1' 룰(rule)에 의해서 SNAT 되어서 외부와 통신!
# 참고로 뒤 IP는 eth0(ENI 첫번째)의 IP 주소이다
# --random-fully 동작 - 링크1 링크2
sudo iptables -t nat -S | grep 'A AWS-SNAT-CHAIN'
[ec2-user@ip-192-168-2-25 ~]$ 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 AWS-SNAT-CHAIN-1
-A AWS-SNAT-CHAIN-1 ! -o vlan+ -m comment --comment "AWS, SNAT" -m addrtype ! --dst-type LOCAL -j SNAT --to-source 192.168.2.25 --random-fully
[ec2-user@ip-192-168-2-25 ~]$
// 동작은?
// 192.168.0.0/16 은 그대로 pod ip를 사용한다.
192.168.0.0/16가 아니면 소스 나트를 한다. "AWS, SNAT
이해 완료???
시각화 유틸 설치 ?
1
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set env.TZ="Asia/Seoul" --namespace kube-system
kubectl patch svc -n kube-system kube-ops-view -p '{"spec":{"type":"LoadBalancer"}}'
2
8080으로 접속 하기
k ns kube-system
3
모니터링
kubectl get svc,deploy,rs,pod -A
총 pod 9개
node 3개
coredns 2개
kube-ops-view 1개
kube-proxy 3개
1
인스턴스 유향에 따라 기본값이 있다 ?
Secondary IPv4 addresses (기본값)
인스턴스 유형에 최대 ENI 갯수와 할당 가능 IP 수를 조합하여 선정
2
t3.medium 최대 할당 가능 IP 15개까지만 가능.
3대이므포 최대 할당가능 ip는 45개.
pod도 45개까지 가능.
3
60개 Pod를 못띠운다.
확인해보자~
노드서버 로그인
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 |
| 15 | 4 | t3.xlarge |
| 6 | 3 | t3.medium |
| 12 | 3 | t3.large |
| 2 | 2 | t3.nano |
| 2 | 2 | t3.micro |
| 4 | 3 | t3.small |
3 * (6-1) = 3 * 5 = 15 개 정도
4
파드 사용 가능 계산 예시 : aws-node 와 kube-proxy 파드는 host-networking 사용으로 IP 2개 남음 ((MaxENI * (IPv4addr-1)) + 2) t3.medium 경우
((3 * (6 - 1) + 2 ) = 17개
>> aws-node 와 kube-proxy 2개 제외하면 15개
5
명령서버에서
kubectl describe node | grep Allocatable: -A7
(eks5-access@myeks:default) [root@myeks-bastion-EC2 ~]# kubectl describe node | grep Allocatable: -A7
Allocatable:
attachable-volumes-aws-ebs: 25
cpu: 1930m
ephemeral-storage: 27905944324
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 3388360Ki
pods: 17
--
Allocatable:
attachable-volumes-aws-ebs: 25
cpu: 1930m
ephemeral-storage: 27905944324
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 3388360Ki
pods: 17
--
Allocatable:
attachable-volumes-aws-ebs: 25
cpu: 1930m
ephemeral-storage: 27905944324
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 3388360Ki
pods: 17
1
pod 만들어보자
2
# 워커 노드 EC2 - 모니터링
while true; do ip -br -c addr show && echo "--------------" ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; done
2023-05-01 10:45:53
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 192.168.2.25/24 fe80::4cb:6cff:feec:76fe/64
eni141ecaa749b@if3 UP fe80::e8f6:4ff:fe43:5790/64
eth1 UP 192.168.2.171/24 fe80::405:c7ff:fe6f:424a/64
eni8397fc40833@if3 UP fe80::f07e:8cff:fe19:f373/64
3
# 작업용 EC2 - 터미널1
watch -d 'kubectl get pods -o wide'
4
# 작업용 EC2 - 터미널2
# nginx pod 2개를 가진 디플로이먼트 생성
curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/2/nginx-dp.yaml
kubectl apply -f nginx-dp.yaml
(admin@myeks:N/A) [root@myeks-bastion-EC2 ~]# more nginx-dp.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
(admin@myeks:N/A) [root@myeks-bastion-EC2 ~]#
# 파드 확인
kubectl get pod -o wide
kubectl get pod -o=custom-columns=NAME:.metadata.name,IP:.status.podIP
NAME IP
netshoot-pod-7757d5dd99-4zpls 192.168.3.214
netshoot-pod-7757d5dd99-6dkw6 192.168.1.74
netshoot-pod-7757d5dd99-cbc7h 192.168.2.66
nginx-deployment-6fb79bc456-7rp8g 192.168.3.30
nginx-deployment-6fb79bc456-c56l7 192.168.1.167
5
# 파드 증가 테스트
>> 파드 정상 생성 확인, 워커 노드에서 eth, eni 갯수 확인
--------------
2023-05-01 10:52:13
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 192.168.2.25/24 fe80::4cb:6cff:feec:76fe/64
eni141ecaa749b@if3 UP fe80::e8f6:4ff:fe43:5790/64
eth1 UP 192.168.2.171/24 fe80::405:c7ff:fe6f:424a/64
eni8b7ff9e05e7@if3 UP fe80::5ccb:44ff:febc:df07/64
eni0fdae80f1b6@if3 UP fe80::f438:dcff:fe75:2816/64
enie895f1138db@if3 UP fe80::3cd2:a3ff:feb9:7cb6/64
enib79c64cf33c@if3 UP fe80::e873:d3ff:feab:974d/64
enif1f951c3b33@if3 UP fe80::e03e:50ff:fee4:2097/64
eni50e55e1b054@if3 UP fe80::c424:f8ff:feb0:a64f/64
eni87487acc549@if3 UP fe80::18fc:a0ff:fe06:6f98/64
eni9ea216d2139@if3 UP fe80::44dc:59ff:fe16:1c09/64
eni5645896a362@if3 UP fe80::f41b:69ff:fe16:ebb5/64
eth2 UP 192.168.2.107/24 fe80::419:ffff:fe9e:2bc4/64
eni82e277dd975@if3 UP fe80::b84c:dcff:fe41:3159/64
eni55c9ed76f47@if3 UP fe80::9070:ceff:fe7e:1fc7/64
enib379335ece7@if3 UP fe80::5007:a9ff:fe53:5777/64
eni1e3f35e11ef@if3 UP fe80::b016:6fff:feec:12c7/64
eni47b93dee5ac@if3 UP fe80::3c63:9cff:fe23:84c4/64
--------------
6
# 파드 증가 테스트 >> 파드 정상 생성 확인, 워커 노드에서 eth, eni 갯수 확인 >> 어떤일이 벌어졌는가?
kubectl scale deployment nginx-deployment --replicas=10
kubectl scale deployment nginx-deployment --replicas=40
7
# 파드 생성 실패!
kubectl get pods | grep Pending
(eks5-access@myeks:default) [root@myeks-bastion-EC2 ~]# kubectl get pods | grep Pending
nginx-deployment-6fb79bc456-49nnq 0/1 Pending 0 2m39s
nginx-deployment-6fb79bc456-67pnh 0/1 Pending 0 2m39s
nginx-deployment-6fb79bc456-dkfzx 0/1 Pending 0 7s
nginx-deployment-6fb79bc456-dpn86 0/1 Pending 0 7s
nginx-deployment-6fb79bc456-f2s96 0/1 Pending 0 7s
nginx-deployment-6fb79bc456-g6xxf 0/1 Pending 0 7s
nginx-deployment-6fb79bc456-j58g6 0/1 Pending 0 2m39s
nginx-deployment-6fb79bc456-jdsgm 0/1 Pending 0 2m39s
8
원인 확인은 describe ?
kubectl describe pod <Pending 파드> | grep Events: -A5
kubectl describe pod nginx-deployment-xxxxxxxxxxxxx | grep Events: -A5
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 96s default-scheduler 0/3 nodes are available: 3 Too many pods. preemption: 0/3 nodes are available: 3 No preemption victims found for incoming pod.
9
c5.large서버 사용시는 ?
10
# 디플로이먼트 삭제
kubectl delete deploy nginx-deployment
이해 완료 ???
참고 자료 ~
1
해결책
Prefix Delegation + WARM & MIN IP/Prefix Targets
2
추가 자료
workshop
https://www.eksworkshop.com/docs/networking/prefix/
3
https://aws.github.io/aws-eks-best-practices/networking/prefix-mode/
원클릭 배포로 네트워크와 EKS한번에 구축 이해
AWS VPC CNI 특정을 알아보자.
보조 프라이빗 IP
노드간 파드 통신 이해하자
파드에서 외부 통신하는것 알아보자
노드의 파드 생성 갯수 제한 알아보자
노드의 파드 생성 갯수 제한 테스트 해보자
https://brunch.co.kr/@topasvga/3216
전체 보기
https://brunch.co.kr/@topasvga/3217
감사합니다.