Kubernetes/EKS Study

[1주차] EKS 설치 및 기본 사용

백곰곰 2023. 4. 24. 11:30
728x90
반응형

좋은 기회로 EKS 워크샵 스터디에 참여해서 전체 과정과 과제를 남겨보려고 합니다.

 

1주차 주제

  • EKS 아키텍처
    • Public/Private endpoint 사용 별 Cluster endpoint로의 접근 방식
    • Control Plane <-> Data Plane 통신 경로
  • 클러스터 생성 실습
    • CloudFormation을 통한 bastion host, VPC 배포
    • eksctl cli를 사용한 클러스터 생성

EKS 아키텍처

EKS Cluster 생성 시 Managed VPC에 Control Plane이 배포되고 통신을 위한 eni가 설정한 VPC의 각 subnet에 생성됩니다.

EKS API server endpoint(NLB)에 연결하여 kubectl 명령어를 수행할 수 있습니다.

 

EKS Control Plane은 아래 컴포넌트로 이루어져 있습니다.

  • API server
  • 컨트롤러
  • 스케쥴러
  • etcd

이 중 etcd는 별도 노드로 배포됩니다(external etcd).

통신 방식

1) public endpoint만 사용 시 :

kubectl (client) <-> API server endpoint뿐만 아니라 kube-proxy <-> API Server 간 통신도 인터넷을 통하는 것을 볼 수 있습니다.

 

2) public + private endpoint 사용 시 :

kubectl (client) <-> API server endpoint는 인터넷 kube-proxy <-> API server는 Private 도메인을 활용해 VPC 간 통신합니다.

 

3) private endpoint만 사용 시 :

kubectl (client) <-> API server 통신이 EKS 소유 eni를 통해 이루어집니다.


 

[실습] 클러스터 생성하기

CloudFormation yaml파일을 통해  VPC와 bastion host 등을 생성한 후에 eksctl 명령어를 사용하여 클러스터를 생성합니다.

클러스터 생성 전에 dry-run을 통해서 어떤 설정으로 클러스터가 생길 예정인지 확인할 수 있습니다.

이번 실습에서는 NAT G/W 비용을 절약하기 위해 public subnet에 클러스터를 만들었습니다.

## dry-run
eksctl create cluster --name $CLUSTER_NAME --region=$AWS_DEFAULT_REGION --nodegroup-name=$CLUSTER_NAME-nodegroup --node-type=t3.medium \
> --node-volume-size=30 --vpc-public-subnets "$PubSubnet1,$PubSubnet2" --version 1.24 --ssh-access --external-dns-access --dry-run | yh
apiVersion: eksctl.io/v1alpha5
cloudWatch:
  clusterLogging: {}
iam:
  vpcResourceControllerPolicy: true
  withOIDC: false
kind: ClusterConfig
kubernetesNetworkConfig:
  ipFamily: IPv4
managedNodeGroups:
- amiFamily: AmazonLinux2
  desiredCapacity: 2
  disableIMDSv1: false
  disablePodIMDS: false
  iam:
    withAddonPolicies:
      albIngress: false
      appMesh: false
      appMeshPreview: false
      autoScaler: false
      awsLoadBalancerController: false
      certManager: false
      cloudWatch: false
      ebs: false
      efs: false
      externalDNS: true
      fsx: false
      imageBuilder: false
      xRay: false
  instanceSelector: {}
  instanceType: t3.medium
  labels:
    alpha.eksctl.io/cluster-name: myeks
    alpha.eksctl.io/nodegroup-name: myeks-nodegroup
  maxSize: 2
  minSize: 2
  name: myeks-nodegroup
  privateNetworking: false
  releaseVersion: ""
  securityGroups:
    withLocal: null
    withShared: null
  ssh:
    allow: true
    publicKeyPath: ~/.ssh/id_rsa.pub
  tags:
    alpha.eksctl.io/nodegroup-name: myeks-nodegroup
    alpha.eksctl.io/nodegroup-type: managed
  volumeIOPS: 3000
  volumeSize: 30
  volumeThroughput: 125
  volumeType: gp3
metadata:
  name: myeks
  region: ap-northeast-2
  version: "1.24"
privateCluster:
  enabled: false
  skipEndpointCreation: false
vpc:
  autoAllocateIPv6: false
  cidr: 192.168.0.0/16
  clusterEndpoints:
    privateAccess: false
    publicAccess: true
  id: vpc-07ab2103bf53ee970
  manageSharedNodeSecurityGroupRules: true
  nat:
    gateway: Disable
  subnets:
    public:
      ap-northeast-2a:
        az: ap-northeast-2a
        cidr: 192.168.1.0/24
        id: subnet-09d11f7d57d0df9ad
      ap-northeast-2c:
        az: ap-northeast-2c
        cidr: 192.168.2.0/24
        id: subnet-04c78c245f54c56ab
        
## 클러스터 생성
eksctl create cluster --name $CLUSTER_NAME --region=$AWS_DEFAULT_REGION --nodegroup-name=$CLUSTER_NAME-nodegroup --node-type=t3.medium \
--node-volume-size=30 --vpc-public-subnets "$PubSubnet1,$PubSubnet2" --version 1.24 --ssh-access --external-dns-access --verbose 4

클러스터 endpoint 설정은 아래와 같습니다.

  clusterEndpoints:
    privateAccess: false
    publicAccess: true

명령어 실행 후 10~15분 정도 기다리면 EKS 클러스터가 생성된 것을 확인할 수 있습니다.

 


[실습] 노드에서 확인하기

eksctl을 사용하여 클러스터 배포 후에 생성된 노드에 접속해서 여러 가지 설정을 살펴보았습니다.

eksctl로 배포 후에 kubeconfig가 자동으로 설정되어 클러스터에 바로 접근할 수 있었습니다.

 

실제 실행 중인 프로세스를 확인했을 때 containerd가 사용되는 것을 볼 수 있습니다.

ssh -i ~/.ssh/id_rsa ec2-user@$N1 sudo pstree
systemd-+-2*[agetty]
        |-amazon-ssm-agen-+-ssm-agent-worke---8*[{ssm-agent-worke}]
        |                 `-8*[{amazon-ssm-agen}]
        |-auditd---{auditd}
        |-chronyd
        |-containerd---15*[{containerd}]
        |-containerd-shim-+-bash-+-aws-k8s-agent---7*[{aws-k8s-agent}]
        |                 |      `-tee
        |                 |-pause
        |                 `-11*[{containerd-shim}]
        |-containerd-shim-+-kube-proxy---6*[{kube-proxy}]
        |                 |-pause
        |                 `-11*[{containerd-shim}]
        |-containerd-shim-+-coredns---7*[{coredns}]
        |                 |-pause
        |                 `-12*[{containerd-shim}]
        |-containerd-shim-+-coredns---7*[{coredns}]
        |                 |-pause
        |                 `-11*[{containerd-shim}]
        |-crond
        |-dbus-daemon
        |-2*[dhclient]
        |-gssproxy---5*[{gssproxy}]
        |-irqbalance---{irqbalance}
        |-kubelet---14*[{kubelet}]
        |-lvmetad
        |-master-+-pickup
        |        `-qmgr
        |-rngd
        |-rpcbind
        |-rsyslogd---2*[{rsyslogd}]
        |-sshd---sshd---sshd---sudo---pstree
        |-systemd-journal
        |-systemd-logind
        `-systemd-udevd

프로세스를 조금 더 자세히 보면, 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com 와 같은 주소를 확인할 수 있습니다.

이는 AWS에서 제공하는 컨테이너 이미지 레지스트리로 각 리전마다 다른 주소를 갖고 있습니다. (참고)

kube-proxy 이미지 또는 각종 add-on도 해당 레지스트리를 통해 다운로드 받습니다.

root      2842  1.1  2.5 1905692 101352 ?      Ssl  11:49   1:20 /usr/bin/kubelet --config /etc/kubernetes/kubelet/kubelet-config.json --kubeconfig /var/lib/kubelet/kubeconfig --container-runtime-endpoint unix:///run/containerd/containerd.sock --image-credential-provider-config /etc/eks/ecr-credential-provider/ecr-credential-provider-config --image-credential-provider-bin-dir /etc/eks/ecr-credential-provider --node-ip=192.168.2.96 --pod-infra-container-image=602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/eks/pause:3.5 --v=2 --cloud-provider=aws --container-runtime=remote --node-labels=eks.amazonaws.com/sourceLaunchTemplateVersion=1,alpha.eksctl.io/cluster-name=myeks,alpha.eksctl.io/nodegroup-name=myeks-nodegroup,eks.amazonaws.com/nodegroup-image=ami-0d6ea2d1e34171e07,eks.amazonaws.com/capacityType=ON_DEMAND,eks.amazonaws.com/nodegroup=myeks-nodegroup,eks.amazonaws.com/sourceLaunchTemplateId=lt-0e181e733a4e23753 --max-pods=17

 

또한, 각 노드의 /etc/kubernetes/manifests/ 디렉터리 하위에 파일이 없는 것을 봤을 때, static pod는 생성되지 않는 것을 알 수 있었습니다.

 

노드의 kubeletkube-proxy가 어떤 ip와 통신하는지를 확인해 보면, 클러스터 endpoint의 ip인 것을 확인할 수 있습니다.

kubelet과 kube-proxy는 클러스터 endpoint를 통해서 API Server와 통신을 합니다.

현재는 Public endpoint만 사용 중이므로 인터넷을 통해 통신하는 것을 볼 수 있습니다.

ssh -i ~/.ssh/id_rsa ec2-user@$N1 sudo ss -tnp
State Recv-Q Send-Q Local Address:Port    Peer Address:Port Process
ESTAB 0      0       192.168.2.96:44428      3.xx.xx.81:443   users:(("kubelet",pid=2842,fd=42))
ESTAB 0      0       192.168.2.96:40936 13.xx.xx.157:443   users:(("kube-proxy",pid=3088,fd=11))
...
## 클러스터 엔드포인트 ip
$ nslookup Cxxxxxxxx2.gr7.ap-northeast-2.eks.amazonaws.com
Server:		192.168.0.2
Address:	192.168.0.2#53

Non-authoritative answer:
Name:	Cxxxxxxxx2.gr7.ap-northeast-2.eks.amazonaws.com
Address: 3.xx.xx.81
Name:	Cxxxxxxxx2.gr7.ap-northeast-2.eks.amazonaws.com
Address: 13.xx.xx.157

 

추가로, kubectl exec 명령어로 pod에서 bash 명령어를 수행한 뒤 다시 소켓을 확인했을 때 아래와 같은 결과를 볼 수 있습니다.

ssh -i ~/.ssh/id_rsa ec2-user@$N1 sudo ss -tnp
State Recv-Q Send-Q         Local Address:Port           Peer Address:Port Process
ESTAB 0      56              192.168.2.96:22            192.168.1.100:58562 users:(("sshd",pid=17729,fd=3),("sshd",pid=17697,fd=3))
ESTAB 0      0               192.168.2.96:44428             3.xx.xx.81:443   users:(("kubelet",pid=2842,fd=42))
ESTAB 0      0               192.168.2.96:33064          52.95.195.99:443   users:(("ssm-agent-worke",pid=2444,fd=16))
ESTAB 0      0                  127.0.0.1:36106             127.0.0.1:33833 users:(("kubelet",pid=2842,fd=17))
ESTAB 0      0               192.168.2.96:52960            10.100.0.1:443   users:(("aws-k8s-agent",pid=3344,fd=7))
ESTAB 0      0                  127.0.0.1:33833             127.0.0.1:36106 users:(("containerd",pid=2733,fd=55))
ESTAB 0      0               192.168.2.96:40936        13.xx.xx.157:443   users:(("kube-proxy",pid=3088,fd=11))
ESTAB 0      0               192.168.2.96:45660          52.95.194.65:443   users:(("ssm-agent-worke",pid=2444,fd=13))
ESTAB 0      0      [::ffff:192.168.2.96]:10250 [::ffff:192.168.2.51]:53884 users:(("kubelet",pid=2842,fd=7))

제일 마지막 줄인 ESTAB 0      0      [::ffff:192.168.2.96]:10250 [::ffff:192.168.2.51]:53884 ... 를 보면 192.168.2.51 ip가 보이고, 해당 ip를 eni 메뉴에서 확인하면 Owner와 Requester ID가 다른 것을 볼 수 있습니다.

해당 eni가 EKS Control Plane과 Data Plane이 통신하기 위해 자동으로 생성되는 EKS 소유 eni 입니다.

 

이론으로만 알고 있었던 점들을 직접 소켓 상태에서 ip를 찾고 확인해 보니 노드가 어디와 통신하는지를 확실하게 알아볼 수 있었습니다.

기타

  • kubectl exec / logs 명령어의 실행과 요청 과정은 어떻게 될까요?
    • client (kubectl) 요청 -> API server -> Node의 kubelet (CRI를 통해 컨테이너와 통신하여 컨테이너에서 명령어 수행 후 결과 전송)-> API server -> client

 

 

이상으로 1주차 스터디 내용을 마칩니다. 🙂

 

 

출처)

728x90

'Kubernetes > EKS Study' 카테고리의 다른 글

[4주차] EKS Observability  (0) 2023.05.21
[3주차] EKS Storage  (0) 2023.05.09
EKS에서 볼륨 snapscheduler 설치하기  (0) 2023.05.09
EKS에서 pvc로 생성한 ebs에 태그 추가하기  (0) 2023.05.09
[2주차] EKS Networking  (0) 2023.05.01