brunch

You can make anything
by writing

C.S.Lewis

by Master Seo Apr 30. 2023

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

EKS 8탄 - 2주차.

본 내용은 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 


실행 결과


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




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 과 연결되어 있다






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






이해 완료???






<6> 노드간 파드 통신


파드간 통신 흐름 : 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





<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개까지 가능.




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



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



감사합니다.

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari