詳細検索

AWS CodePipeline + EKS 액션: 컨테이너를 배포하는 가장 쉬운 방법!

아바타
글쓴이 Jatin Mehrotra

AWS CodePipeline + EKS 액션: 컨테이너를 배포하는 가장 쉬운 방법!
English에서 번역 • 원문 보기

아마존 웹 서비스(AWS) CodePipeline 팀은 개발자와 DevOps 엔지니어의 운영 오버헤드를 단순화하고, EKS 클러스터에 직접 배포할 수 있는 CodePipeline 액션을 도입하여 배포 과정을 간소화했습니다.

왜 그게 너한테 중요해?

예전에는 DevOps 방식으로 EKS에 자원을 배포해야 할 때, codebuild 프로젝트, eks 접근 권한, kubectl, helm 명령어, 그리고 다른 끔찍한 shell 명령어들을 관리해야 했는데도 한 번에 완벽하지는 않았습니다.

오늘 이 방법을 시도해봤으니, EKS 배포 파이프라인을 100% 단순화하는 방법을 보여드리겠습니다. 코드빌드는 이제 그만두고 복잡한 프로세스, 스크립트, 명령어를 모두 제거하세요!!

건축

선수 조건

  • 공개 엔드포인트를 가진 EKS 클러스터.
  • deployment.yaml 파일과 같은 Kubernetes 자원
  • 원한다면 차트 조종도 할 수 있습니다.

참고: EKS 프라이빗 엔드포인트로 이 업데이트를 시도해보고 싶다면 AWS 히어로 Arshad Zackeriya블로그를 확인해 보세요.

원하는 대로 이 저장소에 helm chart와 deployment.yaml을 모두 제공했습니다.

비하인드 신

쿠버네트 명단 파일 사용 시

 

  • 이 동작은 eks 클러스터에 로그인, kubeconfig context 설정에 해당합니다.
  • kubectl 설치
  • 쿠버네티스 매니페스트 적용
  • 롤아웃 리소스

조타 차트의 경우

codepipeline bts with helm chart
  • 이 동작은 eks 클러스터에 로그인, kubeconfig context 설정에 해당합니다.
  • 인스타르 헬름
  • 인스탈 헬름 차트

EKS 클러스터 생성

클러스터는 퍼블릭 또는 프라이빗(프라이빗 VPC 포함)일 수 있습니다. 파이프라인은 추가 인프라 없이도 자동으로 프라이빗 네트워크에 연결하여 컨테이너 애플리케이션을 배포합니다.

  • 저는 EKS Auto를 사용해 Terraform eks 모듈을 사용했는데, EKS 엔드포인트를 공개 상태로 두면 빠르고 쉽습니다.

eks.tf

# EKS 클러스터

모듈 "EKS" { 
source = "terraform-aws-modules/eks/aws" 
version = "~> 20.31" 

cluster_name = local.cluster_name
cluster_version = "1.32" 
cluster_endpoint_public_access = 참


vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets

cluster_compute_config = { 
enabled = 참
node_pools = ["범용"]
  }

# 클러스터 액세스 진입
# 현재 발신자 신원을 관리자로 추가하기
enable_cluster_creator_admin_permissions = 참


태그 = { 
환경 = "개발" 
테라포름 = "진리" 
  }
}

vpc.tf

모듈 "VPC" { 
source = "terraform-aws-modules/vpc/aws" 
버전 = "5.19.0" 

이름 = "codepipeline-eks-action" 
cidr = "10.0.0.0/16" 

azs = ["us-east-1a", "us-east-1b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.4.0/24", "10.0.5.0/24"]

enable_nat_gateway = 참
single_nat_gateway = 참
one_nat_gateway_per_az = 거짓

enable_dns_hostnames = 참
enable_dns_support = 참

public_subnet_tags = { 
"kubernetes.io/role/elb" = "1" 
  }
private_subnet_tags = { 
"kubernetes.io/role/internal-elb" = "1" 
  }

태그 = { 
환경 = "테라포밍-놀이터" 
  }
}

포드_identity.tf

데이터 "aws_iam_policy_document" "allow_pod_identity" { 
진술서 { 
효과 = "허용" 

원칙들 { 
type = "서비스" 
식별자 = ["pods.eks.amazonaws.com"]
    }

행동 = [ 
"sts:AssumeRole", 
"sts:TagSession" 
    ]
  }
}

리소스 "aws_iam_role" "read_ecr" { 
이름 = "read-ecr-role" 
assume_role_policy = data.aws_iam_policy_document.allow_pod_identity.json
}

리소스 "aws_iam_role_policy_attachment" "read_ecr" { 
role = aws_iam_role.read_ecr.name
policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" 
}

리소스 "aws_eks_pod_identity_association" "read_ecr" { 
cluster_name = local.cluster_name
네임스페이스 = "기본값" 
service_account = "ecr-sa" 
role_arn = aws_iam_role.read_ecr.arn
}

 

참고: 저는 pod identity와 ecr 저장소 권한을 사용하여 deploy.yaml용 ecr 이미지를 얻고 있습니다.

클러스터 전체 코드를 원한다면 이 저장소를 따라가면 됩니다

EKS 배포 동작으로 파이프라인 생성

사례 1: kubectl 구성이 사용되는 경우.

저는 소스 소스를 GitHub로 사용하고, 코드 시작(code, start) 연결을 사용하고 있으며, 코드는 이 저장소에 있습니다.codepipeline helm config

  • 클러스터 선택
  • deployment.yaml 파일 경로(제 경우는 deployment.yaml 파일)를 제공하세요.

사례 2: 헬름 차트 사용 시

codepipeline helm config
  • 발매 제목을 입력하세요
  • 헬름 차트를 입력하세요 (제 경우는 테스트 차트입니다)

중요한 단계야

참고: 파이프라인이 생성되면 오류를 피하려면 파이프라인 서비스 역할을 편집하거나 기존 역할을 업데이트하고 다음 권한을 추가해야 합니다.

{ 
"성명": [ 
        { 
"액션": [ 
"iam:PassRole" 
            ], 
"자원": "*", 
"효과": "허용", 
"조건": { 
"StringEqualsIfExists": { 
"iam:PassedToService": [ 
"cloudformation.amazonaws.com", 
"elasticbeanstalk.amazonaws.com", 
"ec2.amazonaws.com", 
"ecs-tasks.amazonaws.com" 
                    ]
                }
            }
        }, 
        { 
"액션": [ 
"codecommit:CancelUploadArchive", 
"codecommit:GetBranch", 
"codecommit:GetCommit", 
"codecommit:GetRepository", 
"codecommit:GetUploadArchiveStatus", 
"codecommit:업로드 아카이브" 
            ], 
"자원": "*", 
"효과": "허용" 
        }, 
        { 
"액션": [ 
"codedeploy:CreateDeployment", 
"codedeploy:GetApplication", 
"codedeploy:GetApplicationRevision", 
"codedeploy:GetDeployment", 
"codedeploy:GetDeploymentConfig", 
"codedeploy:RegisterApplicationRevision" 
            ], 
"자원": "*", 
"효과": "허용" 
        }, 
        { 
"액션": [ 
"codestar-connections:UseConnection" 
            ], 
"자원": "*", 
"효과": "허용" 
        }, 
        { 
"액션": [ 
"elasticbeanstalk:*", 
"ec2:*", 
"elasticloadbalancing:*", 
"자동 스케일링:*", 
"cloudwatch:*", 
"s3:*", 
"sns:*", 
"cloudformation:*", 
"rds:*", 
"sqs:*", 
"ecs:*" 
            ], 
"자원": "*", 
"효과": "허용" 
        }, 
        { 
"액션": [ 
"lambda:InvokeFunction", 
"lambda:ListFunctions" 
            ], 
"자원": "*", 
"효과": "허용" 
        }, 
        { 
"액션": [ 
"opsworks:CreateDeployment", 
"opsworks:DescribeApps", 
"opsworks:DescribeCommands", 
"opsworks:DescribeDeployments", 
"opsworks:DescribeInstances", 
"opsworks:DescribeStacks", 
"opsworks:UpdateApp", 
"opsworks:UpdateStack" 
            ], 
"자원": "*", 
"효과": "허용" 
        }, 
        { 
"액션": [ 
"cloudformation:CreateStack", 
"cloudformation:DeleteStack", 
"cloudformation:DescribeStacks", 
"cloudformation:UpdateStack", 
"cloudformation:CreateChangeSet", 
"cloudformation:DeleteChangeSet", 
"cloudformation:DescribeChangeSet", 
"cloudformation:ExecuteChangeSet", 
"cloudformation:SetStackPolicy", 
"cloudformation:ValidateTemplate" 
            ], 
"자원": "*", 
"효과": "허용" 
        }, 
        { 
"액션": [ 
"codebuild:BatchGetBuilds", 
"codebuild:StartBuild", 
"codebuild:BatchGetBuildBatches", 
"codebuild:StartBuildBatch" 
            ], 
"자원": "*", 
"효과": "허용" 
        }, 
        { 
"효과": "허용", 
"액션": [ 
"devicefarm:ListProjects", 
"devicefarm:ListDevicePools", 
"devicefarm:GetRun", 
"devicefarm:GetUpload", 
"devicefarm:CreateUpload", 
"devicefarm:ScheduleRun" 
            ], 
"자원": "*" 
        }, 
        { 
"효과": "허용", 
"액션": [ 
"servicecatalog:ListProvisioningArtifacts", 
"servicecatalog:CreateProvisioningArtifact", 
"servicecatalog:DescribeProvisioningArtifact", 
"servicecatalog:DeleteProvisioningArtifact", 
"servicecatalog:UpdateProduct" 
            ], 
"자원": "*" 
        }, 
        { 
"효과": "허용", 
"액션": [ 
"cloudformation:ValidateTemplate" 
            ], 
"자원": "*" 
        }, 
        { 
"효과": "허용", 
"액션": [ 
"ecr:DescribeImages" 
            ], 
"자원": "*" 
        }, 
        { 
"효과": "허용", 
"액션": [ 
"states:DescribeExecution", 
"states:DescribeStateMachine", 
"states:StartExecution" 
            ], 
"자원": "*" 
        }, 
        { 
"효과": "허용", 
"액션": [ 
"appconfig:StartDeployment", 
"appconfig:StopDeployment", 
"appconfig:GetDeployment" 
            ], 
"자원": "*" 
        }, 
        { 
"효과": "허용", 
"액션": [ 
"logs:CreateLogGroup", 
"logs:CreateLogStream", 
"logs:PutLogEvents" 
            ], 
"자원": [ 
"arn:aws:logs:us-east-1:xxxx:log-group:/aws/codepipeline/eks-deploy-codepipeline", 
"arn:aws:logs:us-east-1:xxxxx:log-group:/aws/codepipeline/eks-deploy-codepipeline:log-stream:*" 
            ]
        }, 
        { 
"Sid": "EksClusterPolicy", 
"효과": "허용", 
"Action": "eks:DescribeCluster", 
"자원": [ 
                "*" 
            ]
        }, 
        { 
"Sid": "EksVpcClusterPolicy", 
"효과": "허용", 
"액션": [ 
"ec2:DescribeDhcpOptions", 
"ec2:DescribeNetworkInterfaces", 
"ec2:DescribeRouteTables", 
"ec2:서브넷 설명", 
"ec2:DescribeSecurityGroups", 
"ec2:DescribeVpcs" 
            ], 
"자원": [ 
                "*" 
            ]
        }, 
        { 
"효과": "허용", 
"Action": "ec2:CreateNetworkInterface", 
"자원": "*", 
"조건": { 
"StringEqualsIfExists": { 
"ec2:Subnet": [ 
"arn:aws:ec2:us-east-1:292170836962:subnet/subnet-example1", 
"arn:aws:ec2:us-east-1:292170836962:subnet/subnet-example2" 
                    ]
                }
            }
        }, 
        { 
"효과": "허용", 
"액션": "ec2:CreateNetworkInterfacePermission", 
"자원": "*", 
"조건": { 
"ArnEquals": { 
"ec2:Subnet": [ 
"arn:aws:ec2:us-east-1:xxxx:subnet/subnet-example1", 
"arn:aws:ec2:us-east-1:xxxx:subnet/subnet-example2" 
                    ]
                }
            }
        }, 
        { 
"효과": "허용", 
"액션": "ec2:DeleteNetworkInterface", 
"자원": "*", 
"조건": { 
"StringEqualsIfExists": { 
"ec2:Subnet": [ 
"arn:aws:ec2:us-east-1:xxxxx:subnet/subnet-example1", 
"arn:aws:ec2:us-east-1:xxxx:subnet/subnet-example2" 
                    ]
                }
            }
        }
    ], 
"Version": "2012-10-17" 
}

 

  • 위 코드파이프라인 서비스 역할에 대해 AmazonEKSClusterAdminPolicy로 eks 클러스터에 접근 항목을 생성합니다.

파이프라인을 돌려라

쿠벡틀 매니페스트가 업데이트되는 경우입니다

codepipeline execution

 

(base) jatin.mehrotra@CK0662-001 codepipeline-eks-deployment-no-github % kubectl get pods
이름 준비 상태 재시작 연령
hello-k8s-74fd98b69b-2pwrv 1/1 러닝 0 2분 37초
hello-k8s-74fd98b69b-g876f 1/1 Running 0 2m37s
hello-k8s-74fd98b69b-phs77 1/1 런닝 0 2m37s

 

조타도 매니큐멘트가 업데이트되는 경우입니다

codepipeline execution
(base) jatin.mehrotra@CK0662-001 codepipeline-eks-deployment-no-github % kubectl get pods
이름 준비 상태 재시작 연령
test-67cbfddc66-2gcvj 1/1 running 0 10m

 

개발자, DevOps 관점에서

  • 이번 업데이트로 코드빌드 프로젝트나 어떤 종류의 컴퓨팅 환경을 관리하거나 복잡한 스크립트, 권한, 도구 설치를 관리할 필요가 없어졌습니다.
  • 다음은 이 업데이트 이전에 Codebuild로 사용했던 설정 이미지입니다. 정말 복잡한 난장판입니다.
before this update config
  • 이는 비즈니스 문제, 애플리케이션, 모니터링 및 확장과 같은 쿠버네티스 이슈에 집중하고자 하는 개발자, 데브옵스 엔지니어, 인프라 엔지니어에게 분명히 게임 체인저가 될 것입니다.

이것은 Flux/ArgoCD가 따르는 GitOps 방식이 아니지만, 제 생각에 EKS 클러스터에서 가장 좋은 DevOps 접근법입니다.

저는 매일 Linkedin, * X에서 DevOps, Kubernetes, GenAI 관련 놀라운 AWS 업데이트를 공유합니다. 저를 팔로우해 주세요. 여러분의 삶을 더 편하게 만들어 드리겠습니다.




Related Articles