brunch

EKS 8탄-2. EKS-Networking -2/17

EKS 8탄 - 2주차.

by Master Seo

본 내용은 CloudNet 주말 스터디 내용을 참고로 작성되었습니다.

https://gasidaseo.notion.site/gasidaseo/CloudNet-Blog-c9dfa44a27ff431dafdd2edacc8a1863

계속 테스트하며 내용과 설명이 업데이트 됩니다.



목표

원클릭 배포로 네트워크와 EKS한번에 구축 이해

AWS VPC CNI 특징 이해

보조 프라이빗 IP 사용 이해

노드간 파드 통신 이해하자

파드에서 외부 통신하는것 이해

노드의 파드 생성 갯수 제한 이해

노드의 파드 생성 갯수 제한 테스트



<1> Amazon EKS 윈클릭 배포 & 기본 설정

<2> 설치 완료 확인, 변수 지정

<3> AWS VPC CNI 이해

<4> 네트워크 기본 정보 확인

<5> 보조 프라이빗 IP를 파드에서 사용

<6> 노드간 파드 통신

<7> 파드에서 외부 통신

<8> kube-ops-view로 시각화 하기

<9> 노드의 파드 생성 갯수 제한

<10> 노드의 파드 생성 갯수 제한 테스트

<11> 확인




<1> Amazon EKS 윈클릭 배포 & 기본 설정


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 파일


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

addon 같이 설치됨.



4

쿠버네티스 1.28 로 설치.

최신버전 2단계 전 정도가 addon이 가장 많음.


비용이 나오므로 NAT는 설치 안함.

bastion ec2 생성

subnet pub3 ,private 3


실행 결과

10 oneclick.png


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 에 로그인 하여 클러스터 생성 모니터링 하자.


# EC2 인스턴스 모니터링

while true; do aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --output text | sort; echo "------------------------------" ;date; sleep 1; done



9

(노드 서버 생성 1분후 노드로 kubectl 명령어로 조회가 가능하다.)

while true ; do kubectl get nodes ;echo "-----------";date; sleep 2 ;done



10

이해 완료??





<2> 설치 완료 확인, 변수 지정


설치완료 확인!

이후 테스트를 위해 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을 가장 많이 지원함.








<3> AWS VPC CNI


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는 노드와 파드의 네트워크 대역이 같다.


20 calico.png



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 수와 인스턴스 유형에 권장하는 최대 갯수로 선정



이해 완료??






<4> 네트워크 기본 정보 확인


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













<5> 보조 프라이빗 IP를 파드에서 사용


다시 네트워크 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 과 연결되어 있다


30 pod.png





3

VPC ENI 에 미리 할당된 IP(=Local-IPAM Warm IP Pool)를 파드에서 사용할 수 있음


40 add eth.png



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 존재

100 1 2 3.png




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이 추가 됨.

110 1 2 3 add.png

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






이해 완료???






<6> 노드간 파드 통신


파드간 통신 흐름 : AWS VPC CNI 경우 별도의 오버레이(Overlay) 통신 기술 없이, VPC Native 하게 파드간 직접 통신이 가능하다.


410 NODE간 파드 통신.png



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


200 1 2.png



# 파드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


300 node.png






이해 완료????


1





<7> 파드에서 외부 통신



파드에서 외부 통신 흐름 :

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




이해 완료???





<8> kube-ops-view로 시각화 하기


시각화 유틸 설치 ?


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개





<9> 노드의 파드 생성 갯수 제한


1

인스턴스 유향에 따라 기본값이 있다 ?

Secondary IPv4 addresses (기본값)

인스턴스 유형에 최대 ENI 갯수와 할당 가능 IP 수를 조합하여 선정


2

t3.medium 최대 할당 가능 IP 15개까지만 가능.

3대이므포 최대 할당가능 ip는 45개.

pod도 45개까지 가능.


310 t3.png



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





<10> 노드의 파드 생성 갯수 제한 테스트


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서버 사용시는 ?

400 ip.png



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/



<11> 확인


원클릭 배포로 네트워크와 EKS한번에 구축 이해

AWS VPC CNI 특정을 알아보자.

보조 프라이빗 IP

노드간 파드 통신 이해하자

파드에서 외부 통신하는것 알아보자

노드의 파드 생성 갯수 제한 알아보자

노드의 파드 생성 갯수 제한 테스트 해보자



다음

https://brunch.co.kr/@topasvga/3216



전체 보기

https://brunch.co.kr/@topasvga/3217



감사합니다.

매거진의 이전글EKS 8탄-1.Amazon EKS 설치-1/17