iT邦幫忙

2023 iThome 鐵人賽

DAY 19
0
DevOps

AWS ECS + Gitlab + Laravel + Terraform 從入門到摔坑系列 第 19

Day 19 完整驗證 & EventBridge

  • 分享至 

  • xImage
  •  

昨天我們在 region ap-northeast-2 用 terraform 建立起一套 infrastructure,現在要從 Gitlab deploy Laravel web application 上去確認 web 跟 deployment 都能正常運作。(本日程式碼

修改 Gitlab Pipeline & CI/CD Variable

換了 region,ECR repository 的 URI 會不同,我們要修改 Gitlab CI/CD variable 的 ECR_BASExxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com

還有 .gitlab-ci.yml 的這行:

aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin $ECR_BASE

把寫死的 ap-northeast-1 改成 $AWS_DEFAULT_REGION ,然後在 CI/CD variable 設定變數值為 ap-northeast-2

增加 push image 到首爾的 IAM policy

記得在 push docker image 上 ECR 時有設定一組 AWS credential 來 push image 到 ECR repository 嗎?我們要找到那個 IAM user(可以用 AWS key id 直接在 IAM user 介面搜尋),幫他的 policy 加上可以 push image 到 ap-northeast-2 的 ECR repo,這部份的 policy 會變成像這樣:

...(ignore)
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "ecr:CompleteLayerUpload",
                "ecr:GetAuthorizationToken",
                "ecr:UploadLayerPart",
                "ecr:InitiateLayerUpload",
                "ecr:BatchCheckLayerAvailability",
                "ecr:PutImage"
            ],
            "Resource": [
                "arn:aws:ecr:ap-northeast-1:[YOUR_ACCOUNT_ID]:repository/my-app",
                "arn:aws:ecr:ap-northeast-2:[YOUR_ACCOUNT_ID]:repository/my-app"
            ]
        }
...(ignore)

這些修改完成後就能夠從 Gitlab trigger pipeline 啦~

觀察 CodePipeline

Gitlab 成功推 image 上 ap-northeast-2 的 ECR repository 後,我們觀察 CodePipeline 的運作:

https://ithelp.ithome.com.tw/upload/images/20230929/20160671qvvLuSlvIl.png

嗯,毫無反應,就是個不會動的 CodePipeline。

為什麼勒~?

CodePipeline 是什麼時候要開始做事?當然是 ECR repository 有新的 image 的時候~那 CodePipeline 又是怎麼知道要開始做事呢?顯然 ECR repository 跟 CodePipeline 之間有某種魔法機制讓 CodePipeline 知道 ECR repository 有新的 image、可以開始進行 deploy。

這個機制就是 EventBridge(以前叫 CloudWatch Event),它可以建立 event rule,在收到 AWS service 的 event 時去做某些事情。讓我們回到東京 region 偷看(?) EventBridge 的 rules:

https://ithelp.ithome.com.tw/upload/images/20230929/20160671xivJOEStxs.png

web console 自動建立了一個 rule,從描述看起來是在 ECR image tag 改變的時候會去 trigger CodePipeline 開始做事。進去可以看到 event pattern:

{
  "source": ["aws.ecr"],
  "detail": {
    "action-type": ["PUSH"],
    "image-tag": ["latest"],
    "repository-name": ["my-app"],
    "result": ["SUCCESS"]
  },
  "detail-type": ["ECR Image Action"]
}

這段 event pattern 的意思是 ECR repository my-app 的 image tag latest 被 push 成功時,會觸發這個 event rule 去 trigger 另一個動作。event rule 會 trigger 誰、做什麼動作由 target 設定:

https://ithelp.ithome.com.tw/upload/images/20230929/201606717lzVJIKkgw.png

這邊的 target 當然是 CodePipeline 了~

用 Terraform 在首爾建立 EventBridge rule

知道機制後,要在 terraform configuration 補上 EventBridge 的 rule。(對辣~就是 import resource 的時候又漏了辣~)

首先是 target 需要的 IAM role 及 policy:

resource "aws_iam_role" "codepipeline_trigger" {
    name = "codepipeline-my-app"
    assume_role_policy = jsonencode({
        Version   = "2012-10-17"
        Statement = [
            {
                Action    = "sts:AssumeRole"
                Effect    = "Allow"
                Principal = {
                    Service = "events.amazonaws.com"
                }
            },
        ]
    })
}

resource "aws_iam_role_policy" "codepipeline_trigger" {
  name = "codepipeline-my-app"
  role = aws_iam_role.codepipeline_trigger.id
  policy = jsonencode({
    Version   = "2012-10-17"
    Statement = [
      {
        Effect   = "Allow"
        Action = [
          "codepipeline:StartPipelineExecution",
        ]
        Resource = aws_codepipeline.pipeline.arn
      },
    ]
  })
}

接著是 event rule 跟 target:

resource "aws_cloudwatch_event_rule" "codepipeline_trigger" {
  name        = var.trigger_name
  description = var.trigger_desc
  role_arn    = aws_iam_role.codepipeline_trigger.arn

  event_pattern = jsonencode(
    {
      detail = {
        action-type     = ["PUSH"]
        image-tag       = ["latest"]
        repository-name = [var.source_ecr_repo_name]
        result          = ["SUCCESS"]
      }
      detail-type = [
        "ECR Image Action",
      ]
      source = [
        "aws.ecr",
      ]
    }
  )
}

resource "aws_cloudwatch_event_target" "codepipeline_trigger" {
  rule     = aws_cloudwatch_event_rule.codepipeline_trigger.name
  arn      = var.target_codepipeline_arn
  role_arn = aws_iam_role.codepipeline_trigger.arn
}

apply 這些 resource 上去,Gitlab pipeline 再執行一次,發現 CodePipeline 開始動了!🥳

https://ithelp.ithome.com.tw/upload/images/20230929/20160671CnD60Sx2tq.png

然後它就壞掉了 😐

https://ithelp.ithome.com.tw/upload/images/20230929/20160671APtQn8QAS6.png

點進去看它又怎麼了,在 phase details 看到:

https://ithelp.ithome.com.tw/upload/images/20230929/20160671mf6SxcpLZZ.png

看起來是 codebuild 對存放 artifact 的 s3 bucket 缺乏權限,這邊 artifact 的觀念跟 Gitlab pipeline 的一樣,是 pipeline 過程中產生的各種產出物,codebuild project 會把 artifact 放在 s3 某個 bucket。我們在 resource aws_iam_policycode_build_project 幫它補上:

...
        {
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:GetBucketAcl",
                "s3:GetBucketLocation"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::codepipeline-${var.region}-*",
                "${aws_s3_bucket.codepipeline_artifact.arn}",
                "${aws_s3_bucket.codepipeline_artifact.arn}/*"
            ]
        },
...

接著從 CodePipeline 按右上角的 Release change 讓它重跑,因為這邊跟 Gitlab Pipeline 無關了,我們重跑 CodePipeline 就可以了:

https://ithelp.ithome.com.tw/upload/images/20230929/20160671WCVaSRfGJK.png

終於成功!

https://ithelp.ithome.com.tw/upload/images/20230929/20160671JXIYad4HgV.png

確認 ECS service 正常運作

終於來到最後確認——確定 ECS service 正常運作、可以看到 Laravel 歡迎頁。

aws_autoscaling_group.asgdesired_capacitymax_sizemin_size 都設成 1,還有 aws_ecs_service.servicedesired_count 也設成 1 然後 apply。

一樣到 ECS service 的 deployment 觀察 service 的 deploy 狀況,service 穩定之後就可以用 ALB 的 DNS name 看看是不是能看到 Laravel 歡迎頁囉!

如果可以看到 Laravel 歡迎頁,表示我們的 terraform 是正確的,可喜可賀可口可樂!

刪除首爾 region 的 resource 們

測試完當然要把首爾 region 的 resource 刪掉啦~用 terraform 就非常簡單,只要下 terraform destroy 指令並且 yes 即可!

會出現 error 的常常是 s3 bucket 跟 ECR repository,它們會說 bucket 或 repository 不是空的所以刪不掉,這種時候筆者通常手動把東西砍了再跑一次 destroy。

最後祝大家中秋節快樂~


上一篇
Day 18 Terraform variable & 驗證 configuration
下一篇
Day 20 讓 Terraform configuration 與 cloud resource 保持一致
系列文
AWS ECS + Gitlab + Laravel + Terraform 從入門到摔坑30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言