在 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
沒有留言:
張貼留言