LoginSignup
2
0

More than 1 year has passed since last update.

【CodePipeline】ECRにpushしてECSに最新イメージをデプロイするパイプラインを構築

Posted at

概要

ECRにイメージをpushしたら、ECSサービスが更新され、最新イメージがデプロイされるパイプラインをCodePipelineで実装します。
Code Build, Code Commitなどは今回は使わず、シンプルな構成で作ってみます。

ECR / コンテナの用意

ECRでリポジトリを作成する

ローカルでDockerfileを作成

(今回はapacheのイメージを使って簡単に作成します)

FROM httpd:latest

ECRにプッシュ
プッシュコマンドはECRのリポジトリで見られます。

スクリーンショット 2022-12-17 12.57.59.png

aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin [AWSアカウントID].dkr.ecr.ap-northeast-1.amazonaws.com
docker build -t [リポジトリ名] .
docker tag [リポジトリURI]
docker push [リポジトリURI]

(M1 Macを使っている場合、うまくデプロイできないことがあるので--platformオプションをつける)

dockerファイルを編集

FROM --platform=amd64 httpd:latest

もしくはビルドコマンドにオプションをつける

docker build -t [リポジトリ名] . --platform amd64

ECS

クラスター・サービス・タスクを作成する

Terraformでパパッと作成すると楽です

# タスク定義
resource "aws_ecs_task_definition" "task" {
  family                   = "sandbox-cicd-task"
  #0.25vCPU
  cpu                      = "256"
  #0.5GB
  memory                   = "512"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  container_definitions    = file("./container_definitions.json")
  execution_role_arn       = aws_iam_role.ecs_task_execution_role.arn
}

# クラスター
resource "aws_ecs_cluster" "cluster" {
  name = "sandbox-cicd-cluster"
}

# サービス
resource "aws_ecs_service" "service" {
  name                              = "sandbox-cicd-service"
  cluster                           = aws_ecs_cluster.cluster.arn
  task_definition                   = aws_ecs_task_definition.task.arn
  desired_count                     = 1
  launch_type                       = "FARGATE"
  platform_version                  = "1.4.0"

  network_configuration {
    assign_public_ip = true
    security_groups  = [aws_security_group.service.id]
    subnets = module.vpc.public_subnets
  }

  lifecycle {
    ignore_changes = [task_definition]
  }
}

resource "aws_security_group" "service" {
  name        = "httpd-sg"
  description = "httpd-sg"
  vpc_id      = module.vpc.vpc_id
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "httpd-sg"
  }
}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "3.10.0"

  name = "sandbox-cicd-vpc"
  cidr                 = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true

  azs             = ["ap-northeast-1a", "ap-northeast-1c"]
  public_subnets  = ["10.0.11.0/24", "10.0.12.0/24"]

  manage_default_security_group  = true
  default_security_group_ingress = []
  default_security_group_egress  = []
}

コンテナ定義

[
    {
        "name": "httpd-container",
        "image": "httpd:latest",
        "essential": true,
        "memory": 128,
        "portMappings": [
            {
                "protocol": "tcp",
                "containerPort": 80
            }
        ],
        "logConfiguration": {
            "logDriver": "awslogs",
            "options": {
                "awslogs-group": "sandbox-cicd-container-log",
                "awslogs-region": "ap-northeast-1",
                "awslogs-create-group": "true",
                "awslogs-stream-prefix": "firelens"
            }
        }
    }
]

タスク実行ロールの作成

data "aws_iam_policy" "ecs_task_execution_role_policy_source" {
    arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

# ロググループを生成するポリシーをアタッチする
data "aws_iam_policy_document" "ecs_task_execution_role_policy_document" {
    source_json = data.aws_iam_policy.ecs_task_execution_role_policy_source.policy
    statement {
        effect    = "Allow"
        actions   = ["logs:CreateLogGroup"]
        resources = ["*"]
    }
}


resource "aws_iam_role" "ecs_task_execution_role" {
    name               = "sandbox-cicd-task-execution-role"
    assume_role_policy = data.aws_iam_policy_document.assume_role.json
}

resource "aws_iam_policy" "ecs_task_execution_role_policy" {
    name   = "sandbox-cicd-task-execution-role-policy"
    policy = data.aws_iam_policy_document.ecs_task_execution_role_policy_document.json
}

data "aws_iam_policy_document" "assume_role" {
    statement {
        actions = ["sts:AssumeRole"]
        principals {
        type        = "Service"
        identifiers = ["ecs-tasks.amazonaws.com"]
        }
    }
}

resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_attachment" {
    role       = aws_iam_role.ecs_task_execution_role.name
    policy_arn = aws_iam_policy.ecs_task_execution_role_policy.arn
}

CodePipeline

ECRへのプッシュをトリガーに作動するパイプラインを作成します。

サービスロールの作成

今回作成するパイプラインはS3バケットのオブジェクトにアクセスする必要があるため、S3へのアクセスポリシーを付与したサービスロールを作成します。

Source

スクリーンショット 2022-12-17 13.06.58.png

SourceとしてECRのリポジトリを指定します。
また、デプロイ対象のコンテナとイメージURIを紐づけるためにimagedefinition.jsonを用意します。

imagedefinition.json
[
    {
        "name":"httpd-container",
        "imageUri":"XXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/cicd-sandbox-ecr:latest"
    }
]

上記のjsonファイルを格納する用のS3バケットを作成し、上記jsonファイルをzipで圧縮してアップロードします。
この時作成するバケットはバージョニングを有効化してください。

Deploy

スクリーンショット 2022-12-17 13.15.32.png

Deploy StageではECSで最新イメージをデプロイするアクションを定義し、以下の設定を行います。

入力アーティファクト
SourceステージのS3バケットの出力アーティファクト

イメージ定義ファイル
imagedefinitions.json

イメージを更新してECRにpush

docker-compose.ymlを作っておくとリビルドができて便利

docker-compose.yml
services:
  httpd:
    image: XXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/cicd-sandbox-ecr # ECRのリポジトリURI
    platform: amd64
    build:
      context: .
      dockerfile: Dockerfile

ECRにpushするとパイプラインが作動するのを確認できる
スクリーンショット 2022-12-17 13.40.24.png

ECS > サービスで新規リビジョンが作成されているのを確認
スクリーンショット 2022-12-17 11.39.07.png

サービスが新規リビジョンに切り替わったらデプロイ成功

スクリーンショット 2022-12-17 12.09.35.png

うまくいかない時確認すること

  • imagedefinitions.jsonが正しく圧縮されているか
  • 権限周りのエラー
    • CodePipelineのサービスロールにS3バケットのオブジェクトに対するアクセス権限が付与されているか
    • ECRへのアクセス権限を持つタスク実行ロールがタスク定義にアタッチされているか
  • デプロイに何度も失敗する
    • コンテナログを確認する

参考

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0