Running Containers on Amazon Elastic Kubernetes Service(Amazon EKS) - 2

Hyun·2025년 11월 10일

모듈 4 : Amazon EKS 클러스터에 애플리케이션 배포

애플리케이션 배포 방법

  • Amazon EKS 내에서 애플리케이션 Deployment를 확장 가능한 솔루션으로 만들기 위해선 3단계를 완료해야 한다.
    1. 추가 컨테이너 배포를 위해 관리하고 있는 사용할 수 있는 이미지 리포지토리 설정
    2. 애플리케이션을 일관되게 배포하고 배포 오류를 줄이며 롤백을 활성화할 수 있는 패키지 관리자 또는 애플리케이션 배포 도구를 선택
    3. 지속적 통합(CI) 및 지속적 관리(CD) 파이프라인을 자동화

Amazon EKS 애플리케이션 배포 자동화를 위한 도구 선택

  • 컨테이너 이미지 리포지토리에는 Amazon Elastic Container Registry(ECR)를, 패키지 관리자에는 Helm을, CI/CD 파이프라인 자동화에는 AWS CodePipeline 또는 ArgoCD 또는 GitOps 을 사용한다.

Amazon ECR 사용

  • 개발자가 코드를 변경후 코드 리포지토리에 올리는 것처럼 컨테이너 이미지를 중앙에서 저장하고 제공 할 수 있는 방법이 필요하다.
  • 컨테이너 이미지는 컨테이너 이미지의 신뢰할 수 있는 정보 소스가 된다. 이는 개발 또는 프로덕션 환경에 컨테이너식 애플리케이션을 배포하는데 중심적인 역할을 제공한다.
  • 이점은 어디서든 동일한 코드를 실행할 수 있으면서도 코드가 모든 대상 환경에서 실행될 것을 확신한다.
    • 컨테이너 이미지가 개발자 워크스테이션에서 이미지 레지스트리로 이동, kubelet을 이용해 컨테이너 런타임에게 컨테이너 이미지를 가져오도록 지시하는 과정이다. 최종적으로 Pod에서 컨테이너가 실행된다.
    • 이과정이 CI/CD 자동화 파이프라인의 일부분이다.

컨테이너 이미지 저장

  • 컨테이너 이미지를 레지스터리(ECR)에 저장할 때 퍼블릭과 프라이빗 중에서 선택할 수 있다.
  • 퍼블릭 리포지토리의 기본 목적은 컨테이너 이미지를 누구와도 공유하는 것, 오픈 소스 소프트웨어를 위한 커뮤니티 참여를 높이는 것이 목적이라면 퍼블릭 리포지토리가 좋은 방법이다.
  • 프라이빗 리포지토리는 일반적으로 조직의 보안 및 규정 준수 요구 사항을 충족하기 위한 옵션이 존재한다. 즉, 이미지에 대한 액세스를 권한이 있는 사용자로 제한 할 수 있다.

Helm을 사용하여 애플리케이션 배포

  • Helm은 kubernetes의 패키지 관리자이다. kubernetes 클러스터에 애플리케이션을 설치하고 관리하는 데 도움이 된다.

일반적인 Helm 작업

애플리케이션 설치
1. localhost에 Amazon EKS 차트 리포지토리를 추가한다.
2. 설치할 애플리케이션을 검색한다.
3. 애플리케이션을 설치한다.
설치된 애플리케이션 업그레이드
1. 업그레이드 실행한다.
2. 필요한 경우 롤백한다.
애플리케이션 게시
1. 새 차트를 생성한다.
2. 샘플 파일을 삭제한다.
3. 새 chart.yaml 파일을 생성한다.
4. deployment 및 service manifest를 위한 디렉터리를 생성한다.
5. manifest를 복사한다.
6. 템플릿을 테스트한다.
7. 차트를 배포한다.

Helm 차트

  • Helm 차트는 애플리케이션을 설명하고, 반복 가능한 애플리케이션 설치 지침을 제공하며, 단일 인증 원본 역할을 수행한다.
  • 차트를 사용하면 애플리케이션을 더 쉽게 설치, 업그레이드 또는 제거할 수 있다.
  • 차트는 파일 자체가 아니라 helm에 애플리케이션 설치 방법을 알려주는 특정 하위 디렉터리와 파일을 포함하는 디렉토리이다.
  • 기본 차트 예시
    • charts/ : 차트가 종속된 모든 차트가 포함된 디렉터리
    • Chart.yaml : 차트에 대한 정보가 들어있는 yaml 파일
    • README.md : 사람이 읽을 수 있는 README 파일(선택사항)
    • values.yaml : 차트의 기본 구성 값, templates 디렉터리의 manifest는 이 파일에서 값을 가져오므로 mainfest 템필릿을 지속적으로 업데이트할 필요가 없다.
    • templates/ : values의 값과 결하되면 유효한 kubernetes manifest 파일을 생성하는 템플릿의 디렉터리이다.

Helm 차트 액세스

  • Helm 차트 패키지는 차트 리포지토리에 저장된다. helm 클라이언트를 다양한 차트 리포지토리에서 검색 및 배포하도록 구성할 수 있다.
    • Artifact Hub
      • 개발자가 자시의 차트 리포지토리를 다른 개발자에게 공개할수 있는 퍼블릭 Helm 차트 리포지토리의 중앙 목록이다.
      • 필요한 대부분의 오픈소스 애플리케이션 차트를 이곳에서 검색하고 helm repo add 명령어로 추가하여 사용할 수 있다.
    • Amazon ECR
      • 도커 이미지를 저장하는 것처럼 Helm 차트도 OCI(Open Container Initative) 형식으로 저장할 수 있는 프라이빗(Private) 리포지토리입니다.
      • 보안이 중요하고, 컨테이너 이미지와 차트의 버전과 함께 관리하고 싶을 때 사용된다.
    • Amazon S3
      • 정적 파일을 호스팅하는 기능을 이용해 전통적인 방식의 Helm 리포지토리를 구축하는 방법이다.
      • index.yaml 파일과 차트 패키지(.tgz)를 S3 버킷에 업로드하여 구성하며, 간단한 프라이빗 리포지토리를 만들 때 여전히 유용한 옵션이다.

실습 2 : Helm 및 Amazon S3를 사용하여 애플리케이션 배포

  • Amazon S3를 helm 리포지토리로 구성
  • S3 Helm 리포지토리에 차트를 패키징 및 로드
  • Helm를 사용하여 애플리케이션 배포
  • 차트 및 values.yaml 파일 검토

Helm을 설치하고 Amazon S3 버킷을 Helm 리포지토리로 생성

  • Helm을 설치하고 Amazon S3 버킷을 Helm 리포지토리로 구성한다.
  • Helm을 사용하여 Kubernetes 애플리케이션을 Helm 차트라는 재사용 가능한 번들로 패키징 할 수 있다. 차트는 Pod, 서비스, 수신 등 앱이 실행하는 데 필요한 모든 리소스를 정의한다.
  • 환경 간 공유 및 재사용을 위해 차트를 Helm 차트 리포지토리에 저장한다. Helm-s3 플러그 인을 사용하면 S3 버킷을 차트 리포지토리로 사용할 수 있다.
  • Amazon S3를 Helm 리포지토리로 사용하면 다음과 같은 여러 이점이 존재한다.
    • Amazon S3는 보안, 내구성 및 확장성이 뛰어난 객체 스토리지를 제공한다. Helm 차트 패키지 저장소로 이상적이다.
    • Amazon S3는 차트를 구성하고, 권한을 관리하고, 백업을 생성하는 데 유용하다.
    • S3 버킷에 대한 액세스 권한이 있는 모든 환경에서 차트에 액세스할 수 있다.
    • S3의 버전 관리 기능은 경시적으로 차트 변경 사항을 추적하는 데 도움이 된다.
  • bastion server 인스턴스에 접속 후 helm을 설치 : curl -sSL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
  • helm 설치 유무 확인 : helm version
  • helm 플러그인 설치 : helm plugin install https://github.com/hypnoglow/helm-s3.git
  • 호스팅된 Helm 리포지토리를 위한 Amazon S3 버킷이 미리 생성되었으며 해당 이름이 환경 변수로 배스천 호스트에 저장되어 있다. 이 버킷을 Helm 리포지토리로 초기화한다.
    	echo "Configuring $S3_BUCKET_NAME as a private Helm repository..."
    	helm s3 init s3://$S3_BUCKET_NAME
  • index.yaml 파일이 포함되어 있는지 확인하여 Helm 리포지토리가 초기화 확인 : aws s3 ls $S3_BUCKET_NAME
  • 버킷을 Helm 클라이언트용 차트 리포지토리로 추가 : helm repo add productcatalog s3://$S3_BUCKET_NAME

제품 카탈로그 차트를 패키징하고 Amazon S3로 푸시

  • 샘플 애플리케이션을 Helm 차트로 패키징하고 앞서 생성한 Amazon S3 리포지토리에 푸시
  1. 먼저 GitHub에서 애플리케이션 코드를 복제한다. 해당 코드에는 애플리케이션 배포하는데 필요한 kubernetes 리소스 manifest가 포함되어있다.
  2. Helm CLI를 사용하여 해당 리소스를 단일 helm 차트 아카이브로 패키징한다.
  3. 이 후 애플리케이션을 재사용 간으한 형식으로 실행하는 데 필요한 모든 것이 번들로 제공된다.
  • helm package 명령은 차트 파일을 버전이 지정된 .tgz 파일로 압축한다. 차트 번호는 차트에 포함된 Chart.yaml 파일에서 가져온다.

  • 차트패키징을 할 경우 아래 경우에 유용하게 사용된다.

    • S3 버킷과 같은 Helm 차트 리포지토리에서 차트를 공유
    • 단일 Helm instal 명령으로 패키징된 차트를 설치
    • 환경 간에 업데이트 및 롤백을 관리
  • helm 리포지토리 목록을 확인해보자. helm repo list

  • AWS 기반 컨테이너 Github 페이지에서 애플리케이션 Helm 차트를 복제 수행 : git clone https://github.com/aws-containers/eks-app-mesh-polyglot-demo.git

  • Helm 차트 디렉터리의 구조 및 그 안에 포함된 파일을 확인

    	cd eks-app-mesh-polyglot-demo/workshop
    	printf "The chart contains the following directory structure and files...\n \n" && tree helm-chart/

    • 차트는 디렉터리 내부 파일 모음으로 구성되어 있다.
      • Chart.yaml : 차트에 대한 정보가 들어 있는 YAML 파일
      • productcatalog_workshop-1.0.0.tgz: Kubernetes 클러스터에 적용할 수 있는 버전이 지정된 차트 아카이브
      • security/: Pod 보안 그룹에 대한 매니페스트가 포함된 디렉터리
      • templates/: 값과 결합되면 유효한 Kubernetes 매니페스트 파일을 생성하는 템플릿의 디렉터리
      • templates/NOTES.txt: 선택 사항: 간단한 사용 노트가 포함된 일반 텍스트 파일
      • values.yaml: 기본 구성 값을 정의하는 일련의 YAML 파일
  • 실습에 필요한 모든 이미지는 미리 빌드되어 있다. 공개 ECR에서 가져오는 대신 다음 명령을 실행하여 이미지 경로를 업데이트해야한다.

    	export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
    	export AWS_REGION=$(aws configure get region)
    	sed -i "s|public.ecr.aws/[^/]*/eks-workshop-demo|${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/eks-workshop-demo|g" ./helm-chart/values.yaml
  • 애플리케이션 Helm 차트를 패키징 : helm package helm-chart/

  • 애플리케이션 Helm 차트가 생성되었는지 확인 : ls -ltr

  • 패키징된 애플리케이션 Helm 차트를 S3 Helm 리포지토리로 푸시 : helm s3 push ./productcatalog_workshop-1.0.0.tgz productcatalog

  • AWS 콘솔 창에서 확인

Amazon S3 리포지토리에서 Helm 차트를 검색 및 설치

  • 이전 단계에서 Amazon S3에 푸시한 Helm 차트를 배포하여 샘플 애플리케이션을 설치
  1. Helm 명령줄 인터페이스(CLI)를 사용하여 S3 Helm 리포지토리에서 특정 차트 버전을 검색
  2. helm install 명령을 사용하여 EKS 클러스터에 차트를 설치
  3. S3에서 차트 패키지를 가져와 애플리케이션을 배포
  • 이 단계를 완료하면 EKS 클러스터의 Pod에서 실행되는 Frontend, Productcatalog 및 Productdetail 서비스가 포함된 샘플 애플리케이션을 얻게 된다.

  • S3 버킷에 저장된 Helm 차트의 버전 수를 확인 : helm search repo

  • 리소스를 배포하지 않고 차트 설치를 테스트하기 위해 다음 helm install 명령을 –dry-run 플래그와 함께 입력 : helm install productcatalog s3://$S3_BUCKET_NAME/productcatalog_workshop-1.0.0.tgz --version 1.0.0 --dry-run --debug

    • productcatalog: 이 설치에 부여하는 릴리스 이름
    • s3://$S3_BUCKET_NAME/productcatalog_workshop-1.0.0.tgz: S3 버킷 리포지토리에서 차트 아카이브의 위치를 지정
    • --version 1.0.0: 설치할 차트 버전을 1.0.0으로 고정
    • --dry--run: Helm에게 차트를 검증하고 실제로 배포하지 않고 리소스 매니페스트를 생성하도록 지시
    • --debug: 설치 프로세스에 대한 자세한 디버깅 정보를 출력
  • Helm 차트를 설치 : helm install productcatalog s3://$S3_BUCKET_NAME/productcatalog_workshop-1.0.0.tgz --version 1.0.0

  • 차트가 배포한 리소스를 나열 : kubectl get pod,svc,deploy -n workshop -o name
    차트는 애플리케이션의 frontend, productcatalog, productdetail 구성 요소를 나타내는 3개의 Pod, 3개의 서비스 및 3개의 배포를 설치

  • 프런트엔드 서비스를 셸 변수에 저장하고 터미널에 출력

    FRONTEND_URL=http://$(kubectl get svc -n workshop frontend -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
    echo "The URL pointing to the frontend is: $FRONTEND_URL"
  • 출력된 링크 주소를 새 창에서 열면 아래와 같이 나온다.

애플리케이션 Helm 차트 편집 및 재배포

  • values.yaml 파일을 편집한 다음 Helm 차트 애플리케이션을 업그레이드 한다. 그런 다음 변경 사항을 롤백할 때 어떻게 새 Pod가 배포되고 나중에 종료되는지 관찰한다.

  • value.yaml 파일을 편집 수행한다. 아래 명령은 values.yaml 파일에서 기존 replicaCount 값을 새 값 3으로 변경한다. 이 새로운 Helm 차트가 배포되면 애플리케이션은 추가 Pod 복제본을 생성한다.

    cd /home/ssm-user/eks-app-mesh-polyglot-demo/workshop/helm-chart
    sed -i "s/replicaCount:.*/replicaCount: 3/g" values.yaml
  • 업데이트된 Helm 값을 사용하여 애플리케이션을 구성 : helm upgrade productcatalog /home/ssm-user/eks-app-mesh-polyglot-demo/workshop/helm-chart/버전이 업데이트 된것을 확인 가능하다.

  • 현재 동작하는 파드를 확인해본다. : kubectl get pod -n workshop
    각 파드의 수가 3개씩으로 증가한것을 볼 수 있다.

  • 다시 변경 사항을 롤백 하고 이전 차트를 다시 적용한다. : helm rollback productcatalog 1 롤백을 통해서 늘어난 파드가 종료되는 것을 다시 볼 수 있다.


모듈 5 : Amazon EKS를 사용하여 대규모 애플리케이션 관리

Amazon EKS에서 수요에 맞게 크기 조정

  • 수평(리소스 수) 및 수직적(리소스 크기) 조정을 통해서 서버의 확장 또는 축소를 수행했다.
  • 기존 서버의 경우 수평적 크기 조정이 가능한 시스템은 수직적 크기 조정만 가능한 시스템보다 성능이 뛰어난 경우가 많았다.
  • 클라우드 컴퓨팅과 kubernetes에서는 그렇지는 않다. kubernetes에는 수직 및 수평으로 크기를 조정할 수 있는 메커니즘이 존재한다.
  • 수평적으로 확장시키는 방법으로는 Pod의 수를 늘리는 방법이 존재하고, 수직적으로 확장시키는 경우에는 Pod의 크기(할당된 CPU 및 메모리 리소스)를 늘린다.

kubernetes 자동 크기 조정

  • kubernetes 지표는 수요 변동에 대응하는 자동 크기 조정에 필요한 데이터를 제공한다.
  • Horizontal Pod Autoscaler(HPA)Pod 수를 확장하거나 축소한다. 기본적으로 HPA는 kubernetes 지표 서버의 지표를 사용한다. 이 지표 서버는 CPU 및 RAM과 같은 컴퓨팅 리소스를 모니터링 한다.
  • Vertical Pod Autoscaler(VPA)는 Pod에 사용 할 수 있는 리소스 수를 조절한다. VPA는 kubernetes 지표 서버 및 Prometheus 지표의 지표를 사용한다.
  • Cluser Autoscaler(CA)는 클러스터의 현재 상태에 대해 수집한 지표를 기반으로 클러스터의 노드 수를 확장하거나 축소 한다.
  • karpenter는 CA와 달리 Auto Scaling Group(ASG)에 의존하지 않고 직접 EC2 인스턴스를 프로비저닝한다.

Horizontal Pod Autoscaler(HPA)

  • 컨테이너 사용의 이점 중 하나는 애플리케이션을 빠르게 자동으로 크기 조정할 수 있다는 점이다.
  • 많은 워크로드의 경우 인바운드 연결 요청 또는 작업 대기열 길이와 같은 사용자 정의 지표를 기반으로 애플리케이션 크기 조정을 정의할 수 있는 것이 중요하다.
  • HPA는 다음을 수행하여 서비스를 개선한다.
    • 과도한 수의 Pod로 인해 낭비될 수 있는 하드웨어 리소스를 해제한다.
    • 서비스 수준 계약을 달성하기 위해 필요에 따라 성능을 높이거나 낮출 수 있다.
  • 위의 예시는 HPA가 생성될 때 50%의 CPU 비율이 지정되어 있다. CPU 사용량이 할당된 컨테이너 리소스의 50%를 초과하면 HPA는 지정된 최소값(3)에서 구성된 최댓값(10)으로 스케일-아웃 한다.이는 CPU 평균이 목표(50%)보다 낮아질 때까지 스케일-아웃한다. 로드가 감소하면 Amazon EKS는 최종적으로 최소 개수까지 Pod 수를 감소한다.
  • CPU 비율 이외에도 메모리에 따라 크기를 조정하도록 구성가능하다. CPUmemory로 변경하면 된다.

Vertical Pod Autoscaler(VPA)

  • kubernetes Vertical Pod Autoscaler는 Pod에 예약된 CPU 및 메모리를 자동으로 조정하여 애플리케이션의 크기를 적절히 조정하도록 지원한다. 이를 통해 클러스터 리소스 사용률을 개선하고 다른 Pod를 위한 CPU 및 메모리를 확보 할 수 있다.
  • 아래는 VPA를 사용하는 예이다.
    • Pod가 스케줄링 되기를 기다리고 있다. Pod가 실행되지 못하는 이유는 Pod에 수용할 CPU 리소스가 부족하기 때문이다. 현재 노드 0,1은 각각 요청 600m 씩 예약되어있기 때문에 dbAPP 요청을 처리할 수가 없다.
    • 여기서 노드 1은 사용량이 200m 이기 때문에 kubernetes VPA는 실제 사용률에 맞춰서 WebApp 리소스 스케줄링을 수행한다. 리소스 스케줄링을 조정하려면 Pod를 제거하고 다시 스케줄링해야한다.
    • 이제 dbApp Pod가 노드 1에서 실행 중이다.

VPA 구성요소

  • VPA는 kubernetes 클러스터에서 3개의 pod를 배포한다.
    • Recommender : 현재 및 과거 리소스 소비를 모니터링하고 컨테이너의 CPU 및 메모리 요청에 대한 권장 값을 제공
    • Updater : 올바른 리소스 세트가 있는 관리형 Pod를 확인, 리소스가 잘못 할당된 pod를 종료하여 컨트롤러가 업데이트된 요청으로 다시 생성할 수 있도록 한다.
    • Admission Plugin : 방금 생성되었거나 updater의 활동으로 인해 컨트롤러에 의해 다시 생성된 새 Pod에 올바른 리소스 요청을 설정한다.

VPA 고려 사항

  • Off(권장 사항 전용)
    • 권장되는 Pod 크기만 게시하며 실제로는 아무것도 변경되지 않는다.
    • 권장 사항 전용 모드로 시작(kubectl get vpa myvpa --output yaml)
  • Initial(초기화 전용)
    • Pod가 생성될 때만 Pod의 크기를 조정한다.
  • Auto
    • 기존 Pod를 재싲가하여 Pod 크기를 조정한다.
    • 자동 모드 사용시 Pod 중단 예산 정의
  • 고려사항
    • VPA에서 최소 및 최대 컨테이너 크기 설정
    • VPA는 컨트롤러에서 실행되는 Pod를 제거하기도 한다. 이러한 Pod의 경우 자동 모드는 현재 초기화 모드와 동일하다.
    • CPU 또는 메모리의 HPA와 함께 VPA를 사용하지 않는 것을 권장한다. 그러나 사용자 정의 및 외부 지표에는 HPA와 함께 VPA를 사용할 수 있다.
    • VPA는 대부분의 메모리 부족 이벤트에서 반응하지만 모든 상황에서 그런 것은 아니다.
    • VPA 성능은 대규모 클러스터에서 테스트되지 않는다.
    • VPA 권장 사항이 사용 가능한 리소스 (예: 노드 크기, 사용 가능한 크기, 사용 가능한 할당량)를 초과하여 Pod가 보류될 수도 있다. 이 문제는 Cluster Autoscaler와 함께 Vertical Pod Autoscaler를 사용하여 부분적으로 해결할 수 있다.
    • 동일한 Pod와 일치하는 여러 VPA 리소스에 정의되지 않는 동작이 있다.

Cluster Autoscaler 및 Amazon EKS

  • Kubernetes Cluster Autoscaler는 클러스터를 분석하고 노드 수를 자동으로 조정한다.
  • 리소스 부족으로 인해 현재 노드에서 스케줄링할 수 없는 Pod가 있는 경우 Cluster Autoscaler는 더 많은 노드를 추가하도록 요청한다.
  • 만일 많은 시간 동안, 잉여자원의 노드가 있는 경우 Cluster Autoscaler는 노드 그룹을 축소하도록 요청한다.
  • Amazon EKS에서 Cluster Autoscaler는 EC2 Auto scaling 글부을 사용하여 확장하거나 축소한다.

Karpenter

  • AWS에서 관리하는 오픈 소스 Cluster Autoscaler이다.
  • Karpenter는 스케줄링 불가능 Pod를 처리하기 위해 노드를 추가하고, 해당 노드에서 pod를 스케줄링하고, 필요하지 않는 노드를 제거한다.
  • Karpenter는 kubernetes 프로젝트의 Cluster Autoscaler와 유사하게 작동한다. 하지만, Karpenter는 기존 Auto Scaling 그룹의 다른 노드를 사용하는 대신 적정 규모의 컴퓨팅 리소스를 시작한다. 쉽게 말하자면, Cluster Autoscaler는 사전에 미리 정의 된 그룹(Auto scaling)를 통해서 스케일링을 하는 방식인 반면, Karpenter는 리소스를 분석하고 필요한 만큼만 제공해준다고 생각하면 된다.
  • 하지만, 필요한 조건이 프로비저닝의 제약 조건을 벗어나는 경우 Pod는 스케줄링되지 않는 상태로 유지된다.

Amazon EKS에 지속적 배포

  • 어플리케이션을 배포하기 위해서는 6단계 과정(코딩, 빌드, 테스트, 프로비저닝, 배포, 모니터링)을 거쳐야 한다.

release process (CI/CD)

  • 지속적 통합(CI)를 사용하면 개발자는 Git과 같은 버전 관리 시스템을 사용하여 공유 리포지토리에 커밋하는 경우가 많다. 각 커밋 전 개발자는 통합하기 전에 추가 검증 계층으로 코드에서 로컬 단위 테스트를 실행 할 수 있다.
  • 지속적 통합 서비스는 새로운 코드 변경사항에 대한 단위 테스트를 자동으로 구축하고 실행하여 모든 오류를 즉시 표시한다.

지속적 전달과 지속적 배포 차이

  • 지속적 전달과 지속적 배포의 차이점은 프롣거션 업데이트에 대한 수동 승인의 존재 여부이다.
  • 지속적 배포의 경우 명시적 승인 없이 프로덕션으로 자동 업데이트 된다. 지속적 전달은 전체 소프트웨어 릴리스 프로세스를 자동화한다. 커밋되는 모든 개정 버전은 업데이트를 빌드, 테스트, 단계별로 진행하는 자동화된 흐름을 시작한다. 개발자는 라이브 프롣거션 환경에 배포하는 최종 결정을 수행한다.

CI/CD 도구

  • kubernetes 환경에서는 DevOps 방법론과 CI/CD 파이프라인을 사용하는 것이 일반적이다.
  • 아래는 일반적으로 사용되는 CI/CD 제품들이다.

AWS 서비스를 사용한 지속적 배포

  • 위 예시는 다른 AWS 서비스와 Amazon EKS를 통합한 예시이다. kubernets와 AWS를 함께 사용하여 컨테이너 기반 애플리케이션용 오나전관리형 지속적 배포 파이프라인을 생성한다.
  • 이 접근 방식에서는 AWS 개발자 도구를 활용하여 소스 코드, 빌드, 파이프라인을 관리한다.
  1. Commit: 개발자가 코드를 Git 리포지토리에 커밋한다.
  2. Build: CodePipeline이 변경을 감지하고 CodeBuild를 실행한다. CodeBuild는 코드를 빌드하고 테스트하며 컨테이너 이미지를 생성한다.
  3. Push to ECR: 빌드된 이미지를 Amazon ECR에 푸시한다.
  4. Deploy: CodeBuild가 kubectl이나 Helm 같은 도구를 사용하여 ECR에 있는 최신 이미지를 참조하도록 Kubernetes 매니페스트를 업데이트하고 EKS 클러스터에 직접 배포를 수행한다.
  5. Result: 업데이트된 애플리케이션이 Amazon EKS에서 실행한다.

Amazon EKS 지속적 배포 파이프라인

  • 이 다이어그램은 애플리케이션 코드의 라이프사이클과 인프라 구성 코드의 라이프사이클을 분리한 이중 파이프라인 모델이다.
  • 이 파이프라인을 통해 애플리케이션 개발자는 애플리케이션이 실행될 인프라에 대한 걱정 없이 코드 작성에 집중할 수 있다.
  • 개발자 파이프라인
    1. Commit: 개발자가 애플리케이션 코드를 Git 리포지토리에 푸시
    2. Build: AWS CodeBuild가 코드를 가져와 유닛 테스트를 실행하고, Dockerfile을 사용해 컨테이너 이미지를 빌드
    3. Push to ECR: 빌드가 성공하면, 생성된 컨테이너 이미지는 버전 태그와 함께 Amazon ECR(Elastic Container Registry)에 저장한다.이로써 애플리케이션의 '실행 파일' 준비는 마쳤다.
  • DevOps 엔지니어 파이프라인
    1. Commit: DevOps 엔지니어가 쿠버네티스 배포 방법을 정의하는 Helm 차트를 Git 리포지토리에 푸시
    2. Test Chart: AWS CodeBuild가 차트를 가져와 helm lint (문법 검사), kubeval (쿠버네티스 정책 검사) 등의 테스트를 통해 차트의 정합성을 검증
    3. Push to Helm Repo: 테스트를 통과한 Helm 차트는 버전과 함께 S3 버킷을 기반으로 하는 Helm 리포지토리에 패키징되어 저장된다. 이로써 애플리케이션의 인프라 즉, '설치 설명서' 준비가 끝났다.
  • 통합 배포 파이프라인
    1. Trigger: AWS CodePipeline이 ECR과 S3 Helm 리포지토리를 감시하다가, 새로운 이미지나 차트가 등록되면 배포 프로세스를 시작한다.
    2. Deploy: CodePipeline은 CodeBuild를 실행시킨다. CodeBuild는 S3에서 최신 Helm 차트를, ECR에서 최신 컨테이너 이미지를 가져온다. 그 후 helm upgrade --install 명령을 통해 EKS 클러스터에 애플리케이션을 배포하거나 업그레이드한다. 이 때 Helm 차트는 "이 컨테이너 이미지를 사용해줘"라고 ECR의 이미지 버전을 참조한다.

GitOps 및 Amazon EKS

GitOps 원칙

  • 모든 것은 소스 제어에 있다. : 인프라 및 애플리케이션 구성이 전적으로 소스제어에서 표현된다. 소스 제어는 원하는 시스템 상태에 대한 단일 정보 소스이다.
  • 명령적이기보다 선언적 : 설치 명령을 실행하는 대신 원하는 인프라 및 애플리케이션 상태를 설명한다. 즉, '어떻게'는 정의하지 않고'무엇을' 원하는지에 대한 최종 결과물 만 정의한다.
  • 승인된 변경 사항을 자동으로 적용 : 원하는 상태로 지속적으로 수렴한다.
  • 일관된 상태를 보장하기 위한 소프트웨어 에이전트 : Argo 또는 Flux와 같은 소프트웨어 에이전트는 클러스터에서 실행중인 애플리케이션의 원하는 상태가 Git 리포지토리에 저장된 것과 일치하는지 확인하기 위해 자동으로 수정 조치를 취할 수 있다.
  • Push vs. Pull 모델 비교
    • 기존 CI/CD (Push 방식): Jenkins나 GitLab CI 같은 CI/CD 서버가 테스트 완료 후 kubectl apply 같은 명령어를 직접 실행하여 변경 사항을 클러스터에 밀어 넣는다(Push). CI/CD 서버가 클러스터에 접근할 수 있는 강력한 권한을 가져야 한다.
    • GitOps (Pull 방식): 클러스터 내부에 있는 Argo CD 같은 에이전트가 Git 리포지토리의 변경 사항을 가져와서(Pull) 스스로 상태를 업데이트한다. 외부 시스템이 클러스터에 직접 접근할 필요가 없어 보안적으로 더 안전하다.

Git

  • 인프라 및 애플리케이션 코드에 대한 전체 변경 내역을 추적한다.
  • 하나의 진입점에서 하나의 파이프라인으로 변경 사항을 강제로 적용하면 변경사항을 제어하기 더 쉽다. 승인된 pull 요청과 필수 보안 테스트를 요구하면 파이프라인이 유일한 통로인 DevSecOps 환경이 조성된다.

GitOps 예시 : Amazon EKS 및 Argo CD

  • 앞의 이중 파이프라인과의 차이점은 명령적이 아닌 선언적이라는 것이다. 일련의 명령을 실행하는 대신 GitOps 환경은 Git 기반 리포지토리에서 애플리케이션 및 지원 코드형 인프라의 원하는 상태를 유지한다.
  • Amazon EKS 클러스터에서 실행되는 애플리케이션의 상태 또는 Amazon EKS 클러스터의 상태가 Git에서 원하는 상태와 다르다고 가정해본다. 이 상태를 구성 드리프트라 한다.
  • 일반적으로 구성 드리프트를 수정하기 위해서는 수동 작업이 필요하다. 하지만 GitOps 환경에서는 구성 드리프트가 자동으로 수정된다.
  • 이번 예시에서는 Argo를 사용해 Git를 지속적으로 모니터링하여 변경사항을 감지하게 한다. 변경사항이 발견되면 ArgoCD는 Amazon EKS 클러스터에서 kubernets 객체를 업데이트 한다.
  • ArgoCD는 기존 CI/CD 파이프라인에 비해 몇 가지 이점이 존재한다.
    • 보안이 뛰어나다. 클러스터에서 실행되는 kubernetes 컨트롤러(Argo)가 배포를 처리하기 때문이다. 클러스터에 컨트롤러가 있으면 CI 도구에 클러스터 API 자격증명을 제공할 필요가 없다.
    • 문제로부터 복구하기 쉽다. 클러스터의 일부 또는 전부에 장애가 발생하여 손상이 일어날 경우 클러스터의 올바른 상태가 Git에 저장되어있기 때문에 기존 파이프라인보다 복구하기 쉽다.
  • 다음은 위 예시의 파이프라인이다.
    1. 애플리케이션 개발자는 새 버전의 코드를 Git 리포지토리에 push 하고, 이미지에 태그를 지정한다.
    2. 단위 테스트를 실행하는 Jenkins 파이프라인이 트리거되고, 테스트 성공시 자동으로 이미지를 Amazon ECR에 Push하고 kubernets 관리자에게 알린다.
    3. 동시에 Jenkins는 이미지 태그를 kubernetes 관리자가 관리하고 있는 매니패스트 리포지토리에 업데이트한다.
    4. ArgoCD는 kubenetes 매니패스트 리포지토리를 지속적으로 모니터링하여 변경 사항을 찾는다.
    5. 변경 사항이 발견되면 ArgoCD는 kubernets API 서버를 업데이트 한다. 이제 새 버전을 클러스터에 배포하는 프로세스가 시작된다.
  • 기존 CI/CD 파이프라인과 GitOps의 차이점은 배포 단계에 있다. 전통적인 방식이 CI 서버에서 클러스터로 '어떻게' 배포할지 직접 명령(Push) 하는 반면, GitOps는 Git에 '무엇을' 원하는지 최종 상태를 선언하고 클러스터가 이를 스스로 당겨와(Pull) 동기화 한다.

실습 3 : 지속적 배포 및 GitOps

실습 환경

  • 실습 3에서는 2개의 파이프라인을 생성한다. 한 파이프라인은 Git 리포지토리, Jeknins 및 Amazon ECR를 사용하여 컨테이너 이미지를 빌드하고 저장한다. 또 다른 파이프라인은 다른 Git 리포지토리, Argo CD 및 Amazon EKS를 사용하여 컨테이너 이미지를 Amazon EKS 클러스터에 지속적으로 배포한다.
  • 실습에 사용되는 주요 리소스
    • AWS CodeCommit : 클라우드에서 자산(문서, 소스 코드, 바이너리 파일 등)을 비공개로 저장하고 관리하는 데 사용할 수 있는 Amazon Web Services(AWS)의 버전 제어 서비스
    • Amazon ECR : 안전하고, 확장 가능하며, 신뢰할 수 있는 AWS 관리형 컨테이너 이미지 레지스터리 서비스
    • AMazon EKS : AWS에서 자체 kubernets 제어 영역을 설치, 운영, 유지 관리할 필요가 없는 관리형 서비스

과제 1 : CodeCommit 리포지토리 생성

  • CodeCommit 을 검색하여 2개의 레포지토리를 생성한다.
    • 1번째 리포지토리(AppCodeRepo) : Dockerfile, Jenkinsfile 및 애플리케이션 코드
    • 2번째 리포지토리(ManifestRepo) : Argo가 Amazon EKS에 배포하는 Kubernetes 매니패스트 파일 저장

과제 2 : 실습용 배스천 호스트에 연결하고 AWS CodeCommit 및 Amazon ECR 연결을 위한 SSH 키 검토

  • 과제에 미리 생성되어 있는 bastion host 인스턴스에 접속 후 SSH 키 검토 수행 : aws iam list-ssh-public-keys --user-name gitUser
  • 키를 셸 변수에 저장
    KEYID=$(aws iam list-ssh-public-keys --user-name gitUser | jq -r '.[] | .[] | .SSHPublicKeyId')
    echo $KEYID
    • 해당 keyid는 따로 저장해놓자.
  • 퍼블릭 키와 프라이빗 키를 연결하는 SSH 구성 파일 검토 : cat ~/.ssh/config
  • 프라이빗 키 확인 : cat ~/.ssh/id_rsa
    • 해당 키 전문도 따로 저장 해놓자.
  • AWS CodeCommit에 인증할 수 있는지 확인하기 위해 다음 명령을 입력한다. 참고로 환경변수는 미리 설정되어 있다. : ssh git-codecommit.$AWS_REGION.amazonaws.com
  • ecrUser에 할당된 액세스 키를 확인 : aws iam list-access-keys --user-name ecrUser

과제 3 : 애플리케이션 코드를 검토한 후 AWS CodeCommit 리포지토리에 푸시

  • 코드 검토를 위해 해당 디렉토리로 이동 : cd ~/appcode && ls

    • Dockerfile: 샘플 애플리케이션에 대한 컨테이너 이미지를 생성하는 데 사용되는 명령을 나열하는 파일
    • Dockerfile-Final: 샘플 애플리케이션에 대한 수정된 컨테이너 이미지를 생성하는 데 사용되는 명령을 나열하는 파일
    • Jenkinsfile: 초기 Jenkins 파이프라인의 단계를 정의하는 파일
    • Jenkinsfile-Final: 최종 Jenkins 파이프라인의 단계를 정의하는 파일
    • src: nginx를 사용하는 샘플 Hello World 애플리케이션의 애플리케이션 파일이 포함된 폴더
  • Jenkinsfile을 본인의 계정 ID 및 AWS 리전으로 업데이트 수행

    sed -i "s|ACCOUNTID|${ACCOUNT_ID}|g" Jenkinsfile
    sed -i "s|REGION|${AWS_REGION}|g" Jenkinsfile
  • 실습 Git 구성을 업데이트 진행

    git config --global user.email "eks@example.com"
    git config --global user.name "ekscourse"
    git config --global init.defaultBranch main
  • appcode 디렉토리에서 로컬 Git 리포지토리로 변환 수행 : cd ~/appcode/ && git init

  • 앞서 과제 2번에서 확인한 SSH 키를 사용하여 코드를 AppCodeRepo 리포지토리의 main 브랜치에 푸쉬

    git add .
    git commit -m "initial commit"
    git push --set-upstream ssh://git-codecommit.ap-southeast-2.amazonaws.com/v1/repos/AppCodeRepo main

    • 레포지토리에 코드가 올라간 것을 콘솔창에서 확인

과제 4 : Jenkins 서버 구성

  • 이번 과제에서는 Jenkins 자동화 서버에 로그인하고 SSH 및 액세스 키를 사용하여 자격 증명을 생성한다. 또한 AppCodeRepo CodeCommit 리포지토리를 모니터링하고 새 코드가 리포지토리에 커밋될 때마다 새 컨테이너 이미지를 빌드하는 파이프라인을 생성한다.

  • 배스천 호스트 세션에서 Jenkins 자격 증명을 검색

    • aws secretsmanager get-secret-value --secret-id JenkinsPassword --query SecretString --output text | tr -d '{}' | tr -d '"' | sed 's/:/: /g' | awk -F, '{print $1"\n"$2}'
  • 실습 지침에 존재하는 탐색 패널에 있는 JenkinsServer 주소를 Url 창에 입력 후 해당 ID/password를 입력

  • Jenkins 사용자에게 자격 증명을 할당하기 위해서 Manage Jenkins 페이지의 Security 세션에서 Credentials를 선택한다.

    • 현재 Jenkins에 저장된 자격 증명은 없다.
  • Credentials 페이지의 Stores scoped to Jenkins 섹션에서 (global) 을 선택 후 2개의 IAM 자격증명을 사용하여 자격 증명을 구성한다.이러한 액세스 관리 접근 방식은 문제 분리 원칙을 따르며 보안 상태를 개선한다. 프로덕션 환경에서는 Jenkinsfile에 적시 사용자 프로비저닝을 구축하여 파이프라인의 보안을 더욱 강화할 수 있다.

    • gitUser

    • ecrUser

  • 생성 후
  • 자격증명 구성 후 대시보드로 가서 새로운 파이프라인 구축 수행 : [New item]-[pipeline] 선택 후 생성
  • 파이프라인에 대한 소스 제어 관리(SCM)를 구성하기 위해 Build Triggers 세션에서 Poll SCM 선택 매 2시간마다 새로운 커밋을 확인하는 cronjob을 입력(H/2 * * * *)
  • Pipeline 섹션의 Definition 드롭다운 목록에서 Pipeline script from SCM을 선택, SCM 드롭다운 목록에서 Git을 선택
  • pipeline이 성공적으로 빌드된다면 아래 사진과 같이 나온다.
  • ECR 리포지터리에 가서 생성되어있는지 확인해본다.

    성공적으로 Push가 되어있음을 확인했다.

과제 5: Kubernetes 매니페스트 파일을 생성하고 AWS CodeCommit 리포지토리에 Push

  • manifest 디렉토리 생성 : mkdir ~/manifests && cd ~/manifests

  • 매니패스트 파일 작성

    cat << EOF > deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: eks-sample-linux-deployment
    namespace: eks-sample-app
    labels:
      app: eks-sample-linux-app
    spec:
    replicas: 3
    selector:
      matchLabels:
        app: eks-sample-linux-app
    template:
      metadata:
        labels:
          app: eks-sample-linux-app
      spec:
        affinity:
          nodeAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
              nodeSelectorTerms:
              - matchExpressions:
                - key: kubernetes.io/arch
                  operator: In
                  values:
                  - amd64
                  - arm64
        containers:
        - name: sample
          image: ACCOUNTID.dkr.ecr.REGION.amazonaws.com/eks-gitops-demo:1.0
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 80
            name: http
        nodeSelector:
          kubernetes.io/os: linux
    EOF
  • deployment.yaml 파일을 본인의 계정 ID 및 AWS 리전으로 업데이트

    sed -i "s|ACCOUNTID|${ACCOUNT_ID}|g" deployment.yaml
    sed -i "s|REGION|${AWS_REGION}|g" deployment.yaml
  • service.yaml 파일 생성

    cat << EOF > service.yaml
    apiVersion: v1
    kind: Service
    metadata:
    name: eks-sample-linux-service
    namespace: eks-sample-app
    labels:
      app: eks-sample-linux-app
    spec:
    type: LoadBalancer
    ports:
      - port: 80
        targetPort: 80
        protocol: TCP
    selector:
      app: eks-sample-linux-app
    EOF
  • manifests 디렉터리를 로컬 Git 리포지토리로 변환 수행 : cd ~/manifests && git init

  • 앞서 생성한 SSH 키를 사용하고 애플리케이션 코드를 ManifestRepo CodeCommit 리포지토리의 기본 브랜치로 Push

    git add .
    git commit -m "initial commit"
    git push --set-upstream ssh://git-codecommit.$AWS_REGION.amazonaws.com/v1/repos/ManifestRepo main



과제 6: Argo CD 설치 및 AWS CodeCommit 연결 설정

  • Argo CD를 설치하기 전에 Argo CD 서비스 및 애플리케이션 프로그램 리소스가 상주할 argocd라는 네임스페이스를 생성 : kubectl create namespace argocd

  • Argo 설치 : kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/951656f08338a0eaf10c0b1d4022056baf4c635c/manifests/install.yaml

  • API 서버에 액세스하기 위해 argocd-server를 가리키는 로드 밸런서를 배포하여 Argo CD를 외부화 : kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'

  • 패치 후 ArgoCD 서버 서비스의 상태 확인 : kubectl get service argocd-server -n argocd

  • external-ip 에 있는 DNS 주소를 웹 페이지에 입력 수행

  • admin 계정의 초기 암호는 자동 생성되어 Argo CD 설치 네임스페이스에 있는 argocd-initial-admin-secret이라는 Secret의 password 필드에 일반 텍스트로 저장되어있다. 관리자의 비밀번호를 찾기 위해 다음 명령을 입력한다.
    : kubectl get secret argocd-initial-admin-secret -n argocd -o yaml | grep -i password && printf "\n"

  • 해당 값을 디코딩 해야 한다. : echo <ENCODED_PASSWORD> | base64 --decode && echo

  • 이후 admin/[디코딩 값] 을 입력하면 로그인이 성공한다.

  • Argo CD Applications 페이지의 왼쪽 탐색 창에서 [Settings] - [Project] 탭에서 새로운 프로젝트로 gitops-project 를 만든다. 설명은 자유롭게 작성

  • [Settings] - [Repository certificates and known hosts] 탭 선택 후 SSH 호스트를 새로 생성한다. 이 때 cat ~/.ssh/known_hosts 으로 나온 값을 입력한다.

  • [Settings] - [Repository] 탭에서 레포지토리를 연결한다.

    • ssh://<KEY_ID>@git-codecommit.<AWS_REGION>.amazonaws.com/v1/repos/ManifestRepo를 입력합니다. <KEY_ID> 자리 표시자 값을 GitUserSSHKeyID 값으로 바꾸고, <AWS_REGION> 자리 표시자 값을 이 지침 왼쪽에 있는 AWSRegion 값으로 바꾼다.

  • 다시 생성한 gitops-project 에 들어가서 소스 레포지토리 경로를 추가한다.

  • 목적지도 추가 해준다.

  • 클러스터 리소스와 네임스페이스 리소스도 허용해주는 경로 설정

과제 7: Argo CD 애플리케이션 배포 생성 및 탐색

  • [Application] 탭에서 새로운 어플리케이션을 생성한다.
  • General 설정은 다음과 같다.
    • PRUNE RESOURCES는 Git 리포지토리에 더 이상 지정되지 않은 리소스를 클러스터에서 제거하는 프로세스를 나타낸다. 이는 더 이상 선언된 구성의 일부가 아닌 리소스를 삭제하여 GitOps 리포지토리에 정의된 원하는 상태를 유지하는 데 도움이 된다.
    • SELF HEAL은 자동 조정과 관련이 있다. Argo CD는 Git 리포지토리에서 원하는 상태를 지속적으로 모니터링하고, 클러스터의 실제 상태가 원하는 상태를 벗어나면 자가 복구 메커니즘이 변경 사항을 조정 및 적용하여 클러스터를 지정된 구성으로 되돌리려고 시도한다.
  • 어플리케이션의 소스 경로이다.
  • 어플리케이션의 목적지 경로이다.
  • 생성 결과 사진
  • Applications 페이지에서 새로 생성된 eks-sample-linux-app을 선택하여 Argo CD 애플리케이션에 배포된 리소스를 탐색한다.
    • 위 다이어그램은 Argo CD에서 eks-sample-linux-app 애플리케이션에 배포된 리소스를 보여준다.
  • eks-sample-linux-app 애플리케이션의 구성요소이다.
    • 서비스 유형의 eks-sample-linux-service
      • 엔드포인트 유형의 eks-sample-linux-service
      • EndpointSlice 종류의 eks-sample-linux-service-xxxxx
    • 배포 유형의 eks-sample-linux-deployment
      • ReplicaSet 유형의 eks-sample-linux-deployment-xxxxxxxxxx
        • Pod 유형의 eks-sample-linux-deployment-xxxxxxxxxx-xxxxx(3개의 Pod)
  • 배포된 서비스에 접속하기 위해 DNS 주소를 확인 : kubectl get service -n eks-sample-app
  • 접속 확인 사진
  • 클러스터가 자가 복구를 수행하는지 확인하기 위해 임의로 리소스를 삭제해본다. : cd ~/manifests/ && kubectl delete -f . --ignore-not-found=true
  • 리소스를 삭제했음에도 여전히 서비스가 잘 동작되는 것을 확인할 수 있다. 이는 디플로이먼트가 자가 복구했다는 것을 볼수 있다.

과제 8: CI/CD 파이프라인을 통해 애플리케이션 업데이트

  • Jenkinsfile 및 애플리케이션 코드 업데이트 수행
    cd ~/appcode
    cp Jenkinsfile-Final Jenkinsfile
    cp Dockerfile-Final Dockerfile
    cd ~/appcode/src/
    cp v2_index.html index.html
  • Jenkinsfile을 본인의 계정 ID, AWS 리전 및 SSH 키 ID로 업데이트
    KEYID=$(aws iam list-ssh-public-keys --user-name gitUser | jq -r '.[] | .[] | .SSHPublicKeyId')
    sed -i "s|ACCOUNTID|${ACCOUNT_ID}|g" Jenkinsfile
    sed -i "s|REGION|${AWS_REGION}|g" Jenkinsfile
    sed -i "s|KEYID|${KEYID}|g" Jenkinsfile
  • 변경사항을 레포지토리에 업데이트
    cd ~/appcode/
    git commit -a -m "Updated application to version 2.0"
    git push
  • Jenkins에서 빌드 확인
  • Amazon ECR에서 업데이트된 이미지 태그 확인
  • Argo CD에서 업데이트된 애플리케이션 배포 확인
  • 업데이트된 서비스 확인

모듈 6 : Amazon EKS에서 네트워킹 관리

Amazon EKS의 통신

  • 분산 컨테이너 오케스트레이션 시스템용 네트워킹 솔루션을 설계할 때는 3가지 통신라인을 고려해야 한다.
    • Pod 내부의 컨테이너 간 통신
    • 동일한 노드에 있는 pod 또는 다른 노드에 있는 Pod 간 통신
    • 클러스터 외부로부터 수신 연결

Pod 내부의 컨테이너 간 통신

  • kubernetes는 아래 측면에서 VM이나 물리적 호스트와 동일한 방식으로 Pod를 처리한다.

    • 포트 할당
    • 네트워킹
    • 이름 지정
    • 서비스 선택
    • 로드 밸런싱
    • 애플리케이션 구성
    • 컨테이너화되지 않은 워크로드에서 마이그레이션
  • Pod는 kuberntes의 기본 빌딩 블록이므로 kubernetes는 네트워크의 IP 주소를 각 애플리케이션 컨테이너가 아니라 Pod에 적용한다.

  • Pod의 컨테이너는 네트워크 네임스페이스를 공유하며 localhosts(127.0.0.1)를 사용하여 서로 통신 할 수 있다. 쉽게 말해, Pod 안에 있는 여러 컨테이너들은 마치 하나의 컴퓨터(또는 VM) 안에서 실행되는 여러 프로세스처럼 서로를 인식하고 통신할 수 있다.

Kubernetes 호스트 내 통신

  • 동일한 Pod 내의 컨테이너는 공유 네트워크 네임스페이스를 통해 통신한다. Pod 간 통신은 Pod가 네트워크 네임스페이스를 공유하지 않기 때문에 다른 방식으로 동작한다.
  • 각 Pod에 네트워크 네임스페이스가 있을 뿐아니라 호스트 노드에도 네트워크 네임스페이스가 존재한다. 각 네트워크 네임스페이스에는 자체 라우팅 테이블이 있다.
  • 각 Pod 네임스페이스와 호스트 네임스페이스는 한쌍의 Linux 가상 이더넷(veth) 디바이스를 통해 연결된다. 각 veth 상은 기본 호스트 네트워크 네임스페이스와 Pod 네트워크 네임스페이스 간에 터널을 생성한다.
  • 아래 예시는 각 자체 veth가 있는 2개의 Pod를 보여준다. Pod A에는 veth0b가 있고, Pod B에는 veth1b가 있다. 노드 네트워크 네임스페이스에 해당 veth가 표시되어 있다. 즉, 노드의 veth0a는 Pod A의 쌍을 이루는 veth0b로 터널링되고, veth1a는 Pod B의 쌍을 이루는 veth1b로 터널링된다.
  • 동일한 Pod에 있는 컨테이너 간 통신은 해당 컨테이너의 적절한 프로세스에 대한 포트 번호 기반 방향에 의존한다. 각 Pod의 기본 경로는 노드 네트워크 네임 스페이스의 해당 veth로 터널링되는 Pod의 veth를 통해 다른 대상 위치(동일한 클러스터의 다른 Pod 또는 다른 위치)로 향하는 트래픽을 전달한다.
  • 실제로는 노드 라우팅 테이블에 있는 대상 위치 'PodA' 'PodB' 는 실제 Pod의 IP 주소로 나타내며, 대상 veth는 이러한 인위적 이름 대신 CNI(Container Network Interface)에 할당된 이름을 사용한다.
  • Amazon EKS는 kubernetes 용 VPC CNI 플러그인을 통해 AMazon VPC 네트워킹을 kubernetes에 통합 할 수 있다. 즉, 하나의 메인 IP 주소'와 '여러 개의 보조 IP 주소'가 하나의 동일한 네트워크 카드(ENI)에 함께 할당되고, 이 보조 IP들이 각 Pod에 하나씩 나뉘어 할당되는 방식이 된다.

Amazon EKS 호스트 간의 통신

  • 노드 간 통신을 단순화하기 위해 Amazon EKS는 기본적으로 Amazon VPC CNI를 사용한다. 따라서 모든 Pod에는 Amazon VPC에 할당된 라우팅 가능한 실제 IP 주소가 있으며, 다른 Pod, 노드 또는 AWS 서비스와 통신할 수 있다.
  • 기본적으로 모든 Pod는 Amazon EKS 클러스터의 다른 모든 Pod와 통신 할 수 있다.
  • 서브넷, 라우팅 테이블, 보안 그룹, 네트워크 액세스 제어 목록, VPC 엔드포인트, VPC 피어링, 게이트웨이를 포함하여 Amazon VPC 아키텍처는 Amazon EKS 클러스터에 있는 Pod와의 노드 간 통신에 영향을 미칠 수 있다.
  • 여기에는 다른 Amazon EKS 클러스터, Amazon ECS, Amazon EC2 등이 포함 될 수 있다.
  • 클러스터 설계는 VPC의 서브넷에서 모든 노드 및 Pod 에 충분한 양의 IP 주소를 확보해야 한다.

Pod 수준 보안 개선

Pod 네트워크 통신 보안

  • 기본적으로 kubernetes는 모든 Pod가 제한 없이 서로 통신할 수 있도록 허용한다.
  • Kubernetes 네트워크 정책을 사용하면 pod 간 트래픽 흐름에 대한 규칙을 정의 및 적용 할 수 있다.
  • 이는 Pod 레이블, 네임스페이스, IP 주소, IP 블록(CIDR 범위), 포트와 같은 다양한 기준에 따라 수신 및 송신 네트워크 트래픽 규칙을 지정하여 클러스터를 세분화하고 보호할 수 있는 가상 방화벽 역할을 수행한다.
  • Amazon VPC CNI(Container Networking Interface)는 네트워크 정책을 기본 지원하기 때문에 AWS 에서 kubernetes를 실행 할 때 민감한 워크로드를 격리하고 무단 액세스로 부터 보호 하는 정책을 생성할 수 있다.

Pod 용 보안 그룹

  • 컨테이너식 애플리케이션은 클러스터 내에서 실행되는 다른 서비스뿐만 아니라 Amaozn RDS 또는 Amazon ElastiCache와 같은 외부 AWS 서비스에 액세스해야 하는 경우가 자주 있다.
  • AWS에서는 서비스 간 네트워크 수준 액세스 제어가 흔히 EC2 보안 그룹을 통해 수행된다.
  • VPC CNI 플러그인을 사용하면 Pod용 보안 그룹을 통해 단순화 할 수 있다.
  • Pod 용 보안 그룹을 사용하면 공유 컴퓨팅 리소스에서 다양한 네트워크 보안 요구 사항이 있는 애플리케이션을 실행하여 컴퓨팅 효율성을 향상 시 킬 수 있다.

서비스를 사용한 로드 밸런싱

Kubernetes 서비스 유형

  • kubernetes 서비스(Service)일관된 접근점(Access Point)을 제공하여, 자주 생성되고 사라지며 IP 주소가 바뀌는 Pod들을 안정적으로 연결해 주는 핵심 구성 요소이다.
  • 서비스를 이용하면 복잡한 IP 주소 대신 DNS으로 통신하여 애플리케이션 구성을 단순화 할 수 있다.
  • kubernetes는 Pod 상태를 추적하고 적절한 Pod로 트래픽을 전송하기 위해 4가지 유형의 서비스를 사용한다.
    • ClusterIP : 클러스터 내부에서만 사용
    • NodePort : 정적 포트(NodePort)에 있는 각 노드의 IP에 노출되며 :를 요청하여 클러스터 외부에서 액세스 할 수 있다.
    • LoadBalancer : 클러스터 제공업체의 로드 밸런서를 이용해 외부적으로 노출된다. 이를 이용해 자동으로 생성되는 NodePort 및 ClusterIP에 모두 연결된다.
    • ExternalName : CNAME 레코드를 해당 외부 DNS 이름 값과 함께 반환하여 내부 클러스터 DNS 이름에 매핑한다.

ClusterIP 서비스

  • Cluster 서비스는 클러스터 내에서만 액세스 할 수 있다.
profile
DevSecOps & Cloud Engineer를 꿈꾸는 엔지니어

0개의 댓글