在 Elastic Kubernetes Service 中要使用 Docker Image 還是可以考慮用 Code Pipeline + Code Build 把 Docker image 編譯到 Elastic Container Repository (ECR) 中充當 Docker Hub 使用。
整體架構
先備條件:
- 假設你的專案已經有 Code Pipeline (CI/CD, Code Build) 可以自動讀取專案目錄下的 buildspec.yaml
在這個專案中要實現幾件事情:
- 使用 Terraform 開 ECR
- 套用一些權限到 Code Build, EKS 上
- 把專案的 Docker Image 自動 Build 到 ECR 上
- 讓 EKS 可以存取這個 Image
專案的 Build Spec
由於我的整個專案都在 Code Commit 上,基本上狀況都會簡單一些,程式專案下應該在根目錄要有一個 buildspec.yaml ,然後在 CodeBuild 執行的時候可以讀到這個檔案,自動跑 CI/CD。
buildspec.yaml
version: 0.2 phases: pre_build: commands: # push docker to ECR (這裡都是 AWS CodeBuild 上預設的變數,不用改) - echo Logging in to Amazon ECR... - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com install: commands: # for monolith app - go mod download build: commands: # for monolith app, first build then image can be compile # - go build (部署單體應用程式才需要用) # push docker to ECR ($YOUR_REPO_NAME, $IMAGE_TAG 要設定 CodeBuild 的 Tags) - echo Build docker image... - docker build . -t $YOUR_REPO_NAME:$IMAGE_TAG -f dockerfiles/你的dockefile.dockerfile - echo Build docker image completed... - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG post_build: commands: - echo Build completed on `date` # push docker to ECR (有些是預設的,有些要設定到 tag) - echo Push image... - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$YOUR_REPO_NAME:$IMAGE_TAG - echo Push image completed... # for monolith app (這是部署單體應用程式才有的) #artifacts: # files: ## - xxxxbinary # - appspec.yml # - scripts/deploy-clean.sh # - scripts/deploy-install.sh # - .env # name: "go-server-$(date +%Y-%m-%d)" # discard-paths: yes # somethime buildspec cache will store the legacy changes cache: paths: - /go/pkg/**/*
這個設定檔中有很多變數是 Code Build 中的 Tag,這可能會需要在 Terraform 一開始就給定,現在這個檔案應該會自動 Build 了,但目前還沒有 ECR,要使用 Terraform 建立一個,然後套用相關權限。
*關於 Code Pipeline, CodeBuild terraform 應該會在另一篇文章提及,本篇即當作已知。
目錄結構
- terraform
- modules
- ecr <- 重點
- main.tf
- vars.tf
- pipeline
- eks
- policies
- build_role_policy.tpl
- node_instance_role_policy.tpl
- main.tf
首先,這是一個 ECR 建立的 Terraform:
ecr/main.tf:
resource "aws_ecr_repository" "_" { name = "${var.repo_name}" image_tag_mutability = "MUTABLE" image_scanning_configuration { scan_on_push = true } }
ecr/vars.tf:
variable "repo_name" { type = string description = "ecr repo name" }
建立之後,現在要調整已知 pipeline 中,建立一個 iam.tf ,裡面給他套用 build_role_policy.tpl 這個設定:
resource "aws_iam_role_policy" "codebuild_role" { name = "${local.codebuild_role_name}-policy" role = aws_iam_role.codebuild_role.id # 套用現有的 codebuild_role policy = templatefile("./policies/build_role_policy.tpl") }
其中 build_role_policy 檔案的內容是:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Resource": [ "${public_bucket}", "${public_bucket}/*" ], "Action": [ "s3:*" ] }, { "Effect": "Allow", "Resource": ["*"], "Action": "cloudfront:CreateInvalidation" }, { "Effect": "Allow", "Resource": ["*"], "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ] }, { "Effect": "Allow", "Resource": [ "arn:aws:s3:::codepipeline-${aws_region}-*", "${artifact_bucket}/*", "${artifact_bucket}" ], "Action": [ "s3:PutObject", "s3:GetObject", "s3:GetObjectVersion", "s3:GetBucketAcl", "s3:GetBucketLocation" ] }, { "Effect": "Allow", "Action": [ "codebuild:CreateReportGroup", "codebuild:CreateReport", "codebuild:UpdateReport", "codebuild:BatchPutTestCases", "codebuild:BatchPutCodeCoverages", "ecr:BatchCheckLayerAvailability", # 這裡以下才是給予 ecr 權限的列表 "ecr:CompleteLayerUpload", "ecr:GetAuthorizationToken", "ecr:InitiateLayerUpload", "ecr:PutImage", "ecr:UploadLayerPart" ], "Resource": [ "*" ] } ] }
用同一個方法可以對 EKS 做一樣的權限套用,但是要注意,這個 policy 要套用到 EKS 的 worker 或是 node 級的權限 role:
{ "Effect": "Allow", "Action": [ "ecr:BatchCheckLayerAvailability", "ecr:BatchGetImage", "ecr:GetDownloadUrlForLayer", "ecr:GetAuthorizationToken", "ecr:*", "cloudtrail:LookupEvents" ], "Resource": "*" }
然後,在 k8s 的 deployment 中就可以使用網址直接下載 ECR 的東西:
... template: metadata: name: test namespace: test labels: app: test spec: containers: - image: (你的帳號ID).dkr.ecr.(你的區域ID).amazonaws.com/(你的ECR專案名稱):latest #imagePullPolicy: Always ...
References:
https://docs.aws.amazon.com/codebuild/latest/userguide/sample-ecr.html
https://docs.aws.amazon.com/AmazonECR/latest/userguide/ECR_on_EKS.html
沒有留言:
張貼留言