[Kubernetes] Amazon EKS 클러스터에서 Multus CNI 설정하기

Jade·2022년 3월 1일
0

Multus CNI

Multus CNI를 사용하면 Kubernetes의 파드에 여러 네트워크 인터페이스를 연결할 수 있다.

작동원리

  • Multus CNI는 여러 네트워크 인터페이스를 파드에 연결할 수 있는 Kubernetes용 컨테이너 네트워크 인터페이스(CNI) 플러그인이다.
  • 일반적으로 Kubernetes에서 각 파드는 하나의 네트워크 인터페이스만 존재한다.(루프백 제외) Multus를 사용하면 여러 인터페이스가 있는 Multi-Homed pod를 만들 수 있다. 이것은 Multus가 여러 개의 다른 CNI 플러그인을 호출할 수 있는 CNI 플러그인인 "meta-plugin" 역할을 함으로써 수행된다.

Multi-Homed pod

  • 다음은 Multus CNI에서 제공한 파드에 부착된 네트워크 인터페이스 예시 그림이다.
  • eth0, net0, net1 세 가지 인터페이스를 가진 파드가 있다.
    • eth0은 kubernetes 서버/서비스(예: kubernetes api-server, kubelet 등)에 연결하기 위해 kubernetes 클러스터 네트워크를 연결한다.
    • net0, net1은 추가 네트워크 연결이며 다른 CNI 플러그인(예: vlan/vxlan/ptp)을 사용하여 다른 네트워크에 연결한다.

AWS Multi-Heomd Pod 동작방식

  • 위 그림은 eth0, net1이라는 두 개의 네트워크 인터페이스가 있는 두 개의 파드를 보여주는 예시다.
    • eth0의 경우, 두 인터페이스 모두 Amazon VPC CNI가 관리한다.
    • net1은 k8s 컨트롤 플레인 트래픽과 분리된 사용자 플레인(예: 음성, 비디오) 트래픽을 처리하는 pod1 전용 ipvlan CNI 플러그인을 통해 Multus에서 관리한다.
    • pod2 net1이 host-device CNI 플러그인을 통해 host elastic network interface에 연결되고 DPDK가 패킷 처리를 가속화할 수 있도록 한다.

Multus in EKS

  • Amazon EKS에서는 2021년 8월부터 Multus Container Networking Interface (CNI) 플러그인을 지원하여 EKS 클러스터에서 Pod를 실행함으로써 어드밴스드 네트워킹 구성을 지원하기 위해 다중 네트워크 인터페이스를 사용할 수 있게 되었다.
  • 파드에 대한 다중 네트워크 인터페이스는 다양한 사용 사례에서 유용하다.
    • 트래픽 분할: 제어/관리 분리가 필요한 Network Functions(NF)와 데이터/사용자 평면 네트워크 트래픽을 실행하여 짧은 대기 시간 QoS(Quality of Service) 요구사항을 충족할 수 있다.
    • 성능: 추가 인터페이스는 종종 SR-IOV(Single Root I/O Virtualization) 및 DPDK(Data Plane Development Kit)와 같은 전문 하드웨어 사양을 활용하며, 이를 통해 대역폭 및 네트워크 성능을 높일 수 있다.
    • 보안: 엄격한 트래픽 격리 요구 사항이 있는 멀티 테넌트 네트워크를 지원한다. 규정 준수 요구 사항을 충족하기 위해 여러 서브넷을 파드에 연결한다.
  • 현재 모든 글로벌 AWS 리전에서 사용할 수 있고 AWS Local Zones 및 AWS Outposts와 같은 엣지 로케이션에서 지원된다.

고려사항

  • Amazon EKS는 single root I/O virtualization(SR-IOV) 및 Data Plane Development Kit(DPDK) CNI 플러그인을 구축하지도 게시하지도 않는다. 그러나 Multus Managed Host-Device 및 IPvLan 플러그인을 통해 Amazon EC2 Elastic Network Adapters (ENA)에 직접 연결하여 패킷 가속을 얻을 수 있다.
  • Amazon EKS는 추가 CNI 플러그인을 간단하게 연결할 수 있는 일반 프로세스를 제공하는 Multus를 지원한다. Multus 및 연결 프로세스가 지원되지만 AWS는 연결될 수 있는 모든 호환 가능한 CNI 플러그인 또는 연결 구성과 관련이 없는 해당 CNI 플러그인에서 발생할 수 있는 문제에 대한 지원을 제공하지 않는다.
  • Amazon EKS는 Multus 플러그인에 대한 지원 및 수명 주기 관리를 제공하지만 추가 네트워크 인터페이스와 관련된 IP 주소 또는 추가 관리에 대해서는 책임을 지지 않는다. Amazon VPC CNI 플러그인을 사용하는 기본 네트워크 인터페이스의 IP 주소 및 관리는 변경되지 않는다.
  • Amazon VPC CNI 플러그인만 공식적으로 기본 위임 플러그인으로 지원된다. 기본 네트워킹에 Amazon VPC CNI 플러그인을 사용하지 않기로 선택한 경우 기본 위임 플러그인을 대체 CNI로 재구성하려면 게시된 Multus 설치 매니페스트를 수정해야 한다.
  • Multus는 Amazon VPC CNI를 기본 CNI로 사용할 때만 지원된다. 보조 또는 기타 고차 인터페이스에 사용되는 경우 Amazon VPC CNI를 지원하지 않는다.
  • Amazon VPC CNI 플러그인이 파드에 할당된 추가 네트워크 인터페이스를 관리하지 못하도록 하려면 node.k8s.amazonaws.com/no_manage으로 네트워크 인터페이스에 태그를 지정해야 한다.
  • Multus는 네트워크 정책과 호환되지만 파드에 연결된 추가 네트워크 인터페이스의 일부일 수 있는 포트 및 IP 주소를 포함하도록 정책을 강화해야 한다.

실습 시나리오

  • 본 실습에서는 두 개의 샘플 애플리케이션에서 간단한 Ping Test를 통한 트래픽 분할 시나리오를 시연한다. Pod의 보조 인터페이스를 관리하기 위해 ipvlan CNI를 설정한다. ping 테스트는 ipvlan 플러그인에서 제공하고 Multus에서 관리하는 네트워크에 대해 수행된다.
  • 설정은 CloudFormation 템플릿을 사용하여 인프라, EKS 클러스터 및 자체 관리형 노드 그룹을 생성하게 된다.
    • 인프라 템플릿은 Amazon Virtual Private Cloud(VPC), 클러스터 및 Multus용 퍼블릭 및 프라이빗 서브넷, EKS 작업을 수행하기 위한 배스천 호스트를 프로비저닝한다.
    • 노드 템플릿은 멀티홈 파드를 실행하기 위해 추가 ENI가 연결된 작업자 노드를 생성한다.

전제 조건

  • 관리자 권한이 있는 AWS 계정이 있어야 한다.
  • EC2 키 페어를 생성해야 한다.
  • 최신 버전의 AWS CLI, aws-iam-authenticator 및 git이 설치되어 있어야 한다.
  • Clone this repo
    git clone https://github.com/aws-samples/eks-install-guide-for-multus
  • S3 버킷 생성 후, lambda_function.zip 업로드. 이 단계에서 생성된 S3 버킷 명은 'Provision Worker Node Groups' 섹션에 설명된 작업자 노드 그룹의 CloudFormation을 실행할 때 입력 매개변수 중 하나로 사용된다.

실습 진행

1단계: VPC 및 EKS 클러스터 생성

인프라 생성을 위해 CloudFormation 실행

  1. 관리자 권한으로 AWS 콘솔에 로그인하고 Cloudformation 메뉴로 이동

  2. 스택 생성, 새 리소스 사용(표준) 선택

  3. 템플릿 파일 업로드: eks-install-guide-for-multus/cfn/templates/infra/eks-infra.yaml

  4. 스택 이름 입력: eks-multus-cluster

  5. 기본 VPC CIDR(10.0.0.0/16) 블록 및 서브넷 범위 사용

  6. 2개의 availability zone 선택

  7. 베스천 인스턴스 유형 선택

  8. EC2 키 페어 이름 선택

  9. 나머지는 기본 값으로 유지한 채 [다음] 클릭, 아래 부분 승인 체크 후 [스택생성]

  10. CloudFormation 스택이 완료될 때까지 기다린다. (다소 시간이 소요될 수 있음)

    총 2개의 퍼블릭 및 프라이빗 EKS 서브넷, 4개의 Multus 서브넷(AZ당 2개), EKS 클러스터, IGW 및 NAT-GW가 있는 Amazon VPC가 생성된다. 또한 Multus 서브넷 및 컨트롤 플레인 보안 그룹에 대한 보안 그룹도 생성된다.

  11. 'eks-multus-cluster'라는 스택에 대한 CloudFormation 콘솔 출력 값을 확인한다. 특히 BastionPublicIp는 다음 섹션에서 필요한 IP이므로 기록해두자.

배스천 호스트 구성

  • 터미널 창에서 SSH 명령을 사용하여 Bastion Host 인스턴스에 연결한다. 직전 단계에서 기록된 퍼블릭 IP와 프라이빗 키를 이용한다.
  • AWS CLI 구성(참고)
  • kubectl 설치 및 구성
    curl -o kubectl https://amazon-eks.s3-us-west-2.amazonaws.com/1.21.2/2021-07-05/bin/linux/amd64/kubectl curl -o kubectl.sha256 https://amazon-eks.s3.us-west-2.amazonaws.com/1.21.2/2021-07-05/bin/linux/amd64/kubectl.sha256 openssl sha1 -sha256 kubectl chmod +x ./kubectl mkdir -p $HOME/bin && cp ./kubectl $HOME/bin/kubectl && export PATH=$PATH:$HOME/bin echo 'export PATH=$PATH:$HOME/bin' >> ~/.bashrc kubectl version —short —client
  • AWS CLI를 사용하여 kubeconfig 파일 생성
    aws eks update-kubeconfig --name eks-multus-cluster
    kubectl get svc

2단계: 노드 그룹 프로비저닝

  • 이 단계의 일부로 자체 관리형 노드 그룹을 생성한다.
  • 이 단계에서는 전제 조건에 따라 생성된 S3 버킷과 인프라 스택이 완료되어야 한다. 또는 새 탭에서 인프라 스택 CloudFormation 출력 콘솔을 연다.

노드 그룹 생성을 위한 CloudFormation 템플릿 실행

  1. 관리자 권한으로 AWS 콘솔에 로그인하고 Cloudformation 메뉴로 이동

  2. 스택 생성, 새 리소스 사용(표준) 선택

  3. 템플릿 파일 업로드: eks-install-guide-for-multus/cfn/templates/node-group/eks-nodegroup-multus.yaml

  4. 스택 이름 지정: multus-cluster-ng01

  5. 1단계에서 생성했던 EKS ClusterName(eks-multus-cluster) 입력 및 ClusterControlPlaneSecurityGroup(eks-multus-cluster-EksControlSecurityGroup-xxxx 형태) 선택

  6. NodeGroupName 입력: multus-cluster-ng01

  7. 노드 Autoscaling 그룹 원하는 용량, 최대 및 최소 크기에 대해 1 지정

  8. 인스턴스 유형으로 c5.large를 선택하고 볼륨 크기로 20 선택

  9. 1단계에서 사용한 키 페어 네임 선택

  10. VPC ID(vpc-eks-multus-cluster) 및 Subnet(privateAz1-eks-multus-cluster) 선택

  11. MultusSubnets(multus1Az1-eks-multus-cluster, multus2Az1-eks-multus-cluster) 선택

  12. MultusSecurityGroups(eks-multus-cluster-MultusSecurityGroup*) 선택

  13. LambdaS3Bucket(이전에 생성한 S3 버킷명) 및 LambdaS3Key(lambda_function.zip) 입력

  14. 다음 → I Acknowledge → 스택 생성 클릭

  15. CloudFormation 스택이 완료될 때까지 기다린다.

    정의된 Multus 서브넷에서 ENI를 연결하기 위해 노드 그룹 스택은 AWS Lambda 함수와 Amazon CloudWatch 이벤트 규칙을 배포한다. 스택은 no_manage: true 태그와 함께 Multus 서브넷에서 연결된 ENI로 EC2 인스턴스를 시작한다.

    AWS VPC CNI는 ENI의 태그가 지정된 no_manage: true를 관리하지 않는다. 이것은 Multus가 파드에 대한 추가 네트워크를 관리하기 위한 필수 단계이다.

  16. 스택이 완료되면 출력에서 NodeInstanceRole 값을 기록해둔다.

K8s ConfigMap 업데이트 적용

  • Bastion Host 로그인

AWS authenticator configuration map 다운로드, 편집 및 적용

  • 다운로드
    curl -o aws-auth-cm.yaml https://s3.us-west-2.amazonaws.com/amazon-eks/cloudformation/2020-10-29/aws-auth-cm.yaml
  • 다운로드 된 yaml 파일을 열어 'rolearn'을 NodeInstanceRole(작업자 노드 그룹 CloudFormation 스택의 출력)으로 바꾸고 파일 저장
  • 구성 적용(이 명령을 완료하는 데 몇 분 정도 걸릴 수 있음)
    kubectl apply -f aws-auth-cm.yaml
  • 노드의 상태를 관찰하고 Ready 상태에 도달할 때까지 기다린다.
    kubectl get nodes --watch

3단계: Multus 설치 및 구성

데몬셋을 사용하여 Multus CNI 설치

  • 다음 명령을 실행하여 Multus 데몬셋 다운로드 및 설치
    kubectl apply -f https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/master/config/multus/v3.7.2-eksbuild.1/aws-k8s-multus.yaml

  • 다음 명령을 실행하여 배포된 내용 확인
    kubectl get pods -n kube-system
    각 노드에는 kube-multus-ds라는 하나의 파드가 있어야 한다.

추가 인터페이스 생성

  • 다음으로 파드에 추가하는 각 추가 인터페이스에 대한 구성 생성하기. Multus는 NetworkAttachmentDefinition이라는 사용자 지정 리소스 정의(CRD)를 제공한다. 이 CRD를 사용하여 추가 인터페이스 설정을 구성한다.
  1. ipvlan-conf-1 생성
    ipvlan CNI를 사용하여 파드에 대한 추가 인터페이스(Multus 서브넷 10.0.4.0/24에서)구성
cat <<EOF | kubectl apply -f -
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: ipvlan-conf-1
spec:
  config: '{
      "cniVersion": "0.3.0",
      "type": "ipvlan",
      "master": "eth1",
      "mode": "l3",
      "ipam": {
        "type": "host-local",
        "subnet": "10.0.4.0/24",
        "rangeStart": "10.0.4.70",
        "rangeEnd": "10.0.4.80",
        "gateway": "10.0.4.1"
      }
    }'
EOF
  1. ipvlan-conf-2 생성
    두 번째 Multus 서브넷(10.0.6.0/24)에 대해 다른 ipvlan CNI 생성
cat <<EOF | kubectl apply -f -
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: ipvlan-conf-2
spec:
  config: '{
      "cniVersion": "0.3.0",
      "type": "ipvlan",
      "master": "eth2",
      "mode": "l3",
      "ipam": {
        "type": "host-local",
        "subnet": "10.0.6.0/24",
        "rangeStart": "10.0.6.70",
        "rangeEnd": "10.0.6.80",
        "gateway": "10.0.6.1"
      }
    }'
EOF
  1. 구성된 내용 확인: kubectl describe network-attachment-definitions
[ec2-user@ip-10-0-0-188 ~]$ kubectl describe network-attachment-definitions
Name:         ipvlan-conf-1
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  k8s.cni.cncf.io/v1
Kind:         NetworkAttachmentDefinition
Metadata:
  Creation Timestamp:  2022-03-01T08:30:03Z
  Generation:          1
  Managed Fields:
    API Version:  k8s.cni.cncf.io/v1
    Fields Type:  FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .:
          f:kubectl.kubernetes.io/last-applied-configuration:
      f:spec:
        .:
        f:config:
    Manager:         kubectl-client-side-apply
    Operation:       Update
    Time:            2022-03-01T08:30:03Z
  Resource Version:  7916
  UID:               0a07351d-1e49-4e25-a70c-88f089dc5a7f
Spec:
  Config:  { "cniVersion": "0.3.0", "type": "ipvlan", "master": "eth1", "mode": "l3", "ipam": { "type": "host-local", "subnet": "10.0.4.0/24", "rangeStart": "10.0.4.70", "rangeEnd": "10.0.4.80", "gateway": "10.0.4.1" } }
Events:    <none>


Name:         ipvlan-conf-2
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  k8s.cni.cncf.io/v1
Kind:         NetworkAttachmentDefinition
Metadata:
  Creation Timestamp:  2022-03-01T08:31:09Z
  Generation:          1
  Managed Fields:
    API Version:  k8s.cni.cncf.io/v1
    Fields Type:  FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .:
          f:kubectl.kubernetes.io/last-applied-configuration:
      f:spec:
        .:
        f:config:
    Manager:         kubectl-client-side-apply
    Operation:       Update
    Time:            2022-03-01T08:31:09Z
  Resource Version:  8061
  UID:               f5673daf-0c0b-4c8b-9c5c-ea923c17b896
Spec:
  Config:  { "cniVersion": "0.3.0", "type": "ipvlan", "master": "eth2", "mode": "l3", "ipam": { "type": "host-local", "subnet": "10.0.6.0/24", "rangeStart": "10.0.6.70", "rangeEnd": "10.0.6.80", "gateway": "10.0.6.1" } }
Events:    <none>

4단계: 샘플 애플리케이션 배포

Single ipvlan attachment로 샘플 애플리케이션 배포

  • 이전 단계에서 생성한 network annotation으로 샘플 애플리케이션 sampleapp-1 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: sampleapp-1
  annotations:
      k8s.v1.cni.cncf.io/networks: ipvlan-conf-1
spec:
  containers:
  - name: multitool
    command: ["sh", "-c", "trap : TERM INT; sleep infinity & wait"]
    image: praqma/network-multitool
EOF
  • 파드 네트워크 확인: kubectl exec -it sampleapp-1 -- ip -d address

    AWS VPC CNI는 인터페이스 eth0을 관리하는 반면 ipvlan CNI는 Multus 네트워크 연결 정의(ipvlan-conf-1)를 통해 인터페이스 net1을 관리한다.

Dual ipvlan attachment로 샘플 애플리케이션 배포

  • Dual network annotations ipvlan-conf-1과 ipvlan-conf-2를 사용하여 샘플 애플리케이션 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: sampleapp-dual
  annotations:
      k8s.v1.cni.cncf.io/networks: ipvlan-conf-1, ipvlan-conf-2
spec:
  containers:
  - name: multitool
    command: ["sh", "-c", "trap : TERM INT; sleep infinity & wait"]
    image: praqma/network-multitool
EOF
  • 파드 네트워크 확인: kubectl exec -it sampleapp-dual -- ip -d address

  • Multus 인터페이스에 대한 파드 간의 연결 테스트: kubectl exec -it sampleapp-dual -- ping -I net1 <sampleapp-net1-ipaddress>

리소스 삭제

향후 요금이 발생하지 않도록 CloudFormation 서비스를 사용하여 생성된 모든 리소스를 삭제한다. CloudFormation으로 이동하여 생성한 두 개의 스택을 하나씩 삭제한다.
추가로 앞서 생성한 S3 버킷도 함께 삭제한다.

참고

profile
우당탕탕 좌충우돌 인프라 여행기

0개의 댓글