LoginSignup
9
0

More than 1 year has passed since last update.

GitLab RunnerでECR/ECSにデプロイする

Last updated at Posted at 2021-12-14

はじめに

昨日GitLabとRunnerをコンテナで手軽に構築する記事を書きましたが、今回はそれを使ってAWSのECRとECSにデプロイをしてみることにします。

ECS上で動作するアプリケーションは以下の記事を参考にしました。

環境

  • Amazon Linux2
  • Windows10(SSH用)
  • WSL

作業手順

リポジトリ作成

以下のURLを実行して、前回構築したGitLabにログインします。
初期パスワードがわからなければ前回の記事を見てください。
- http://<グローバルIP>/

image.png

New Projectから新しいプロジェクト(リポジトリ)を作成します。
image.png
image.png
image.png

プロジェクトが作成されました。
image.png

ECRリポジトリ作成

コンソールからECRのリポジトリとECSクラスターを作成しておきます。
ECSクラスターは"ネットワーキングのみ"で作成しています。
image.png
image.png

ファイル作成

リポジトリページのCloneからHTTP URLをコピーします。
image.png

ローカルPCでWSLを起動し、作業フォルダに移動したら以下のコマンドを実行します。
※コピーしたままのURLだとhttpの後ろがランダムな文字列が含まれているので、その部分をEC2のグローバルIPに置き換えておきます。

$ git clone http://<グローバルIP>/root/qiita-test-pj.git
Cloning into 'qiita-test-pj'...
Username for 'http://XXX.XXX.XXX.XXX': root
Password for 'http://root@XXX.XXX.XXX.XXX':
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 210 bytes | 3.00 KiB/s, done.

git cloneしたフォルダに移動します。
今はリポジトリ作成時に生成されたREADME.mdファイルしかありません。

$ cd qiita-test-pj; ls
README.md

こちらに従って、以下のファイルを作成します。
※詳細は参考サイトを見てください

  • Dockerfile
  • default.conf
  • app/index.html

タスク定義作成

次にECSのタスク定義を作成します。
タスク定義はコンソールで作成すると手順が多いので、jsonファイルを作成してCLIで作ります。
初回作成のみCLIで行いますが、更新はGitLab Runnerで行います。
尚、タスク定義のJSONは地味につらかったので、この記事を参考に作成しました。

task-definition.json
{
    "executionRoleArn": "arn:aws:iam::999999999999:role/ecsTaskExecutionRole",
    "containerDefinitions": [
        {
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "/ecs/task-qiita-ecr",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "ecs"
                }
            },
            "portMappings": [
                {
                    "hostPort": 80,
                    "protocol": "tcp",
                    "containerPort": 80
                }
            ],
            "cpu": 0,
            "environment": [],
            "mountPoints": [],
            "memoryReservation": 128,
            "volumesFrom": [],
            "image": "999999999999.dkr.ecr.ap-northeast-1.amazonaws.com/qiita-test-pj-repo",
            "essential": true,
            "name": "qiita-test-container"
        }
    ],
    "memory": "512",
    "family": "task-qiita-ecr",
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "networkMode": "awsvpc",
    "cpu": "256",
    "inferenceAccelerators": [],
    "volumes": []
}

上記の設定の中で主に設定が必要なパラメータは以下の5つです。
後は構築したい環境によってパラメータを追加、削除してください。

パラメータ名 設定内容
executionRoleArn タスク実行ロールのARNを指定
containerDefinitions.logConfiguration.options.awslogs-group ECSログの出力先ロググループ名を指定
containerDefinitions.image ECSで利用するECRリポジトリを指定
containerDefinitions.name ECSで実行されるコンテナの名前を設定
family タスク定義の名前を指定

以下のコマンドを実行し、タスク定義を作成します。

$ aws ecs register-task-definition --family task-qiita-ecr --cli-inpu
t-json file://task-definition.json
{
    "taskDefinition": {
        "taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:941996685139:task-definition/task-qiita-ecr:1",
        "containerDefinitions": [
            {
                "name": "qiita-test-container",
                "image": "999999999999.dkr.ecr.ap-northeast-1.amazonaws.com/qiita-test-pj-repo",
                "cpu": 0,
                "memoryReservation": 128,
                "portMappings": [
                    {
                        "containerPort": 80,
                        "hostPort": 80,
                        "protocol": "tcp"
                    }
                ],
                "essential": true,
                "environment": [],
                "mountPoints": [],
                "volumesFrom": [],
                "logConfiguration": {
                    "logDriver": "awslogs",
                    "options": {
                        "awslogs-group": "/ecs/task-qiita-ecr",
                        "awslogs-region": "ap-northeast-1",
                        "awslogs-stream-prefix": "ecs"
                    }
                }
            }
        ],
        "family": "task-qiita-ecr",
        "executionRoleArn": "arn:aws:iam::999999999999:role/ecsTaskExecutionRole",
        "networkMode": "awsvpc",
        "revision": 1,
        "volumes": [],
        "status": "ACTIVE",
        "requiresAttributes": [
            {
                "name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
            },
            {
                "name": "ecs.capability.execution-role-awslogs"
            },
            {
                "name": "com.amazonaws.ecs.capability.ecr-auth"
            },
            {
                "name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
            },
            {
                "name": "com.amazonaws.ecs.capability.docker-remote-api.1.21"
            },
            {
                "name": "ecs.capability.execution-role-ecr-pull"
            },
            {
                "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
            },
            {
                "name": "ecs.capability.task-eni"
            }
        ],
        "placementConstraints": [],
        "compatibilities": [
            "EC2",
            "FARGATE"
        ],
        "requiresCompatibilities": [
            "FARGATE"
        ],
        "cpu": "256",
        "memory": "512",
        "registeredAt": "2021-12-14T13:02:50.681000+00:00",
        "registeredBy": "arn:aws:iam::999999999999:user/user"
    }
}

コンソールから確認するとタスク定義が作成されています。
image.png

ECSサービス作成

今回の設定ではECSサービスの更新しかしないため、更新対象のECSサービスをあらかじめ作成しておく必要があります。

対象のクラスターのサービスタブから作成を押下します。
image.png

以下の内容で設定します。
タスクの数は敢えて0で設定しており、この後のRunnerで変更するように設定しています。
image.png
image.png
image.png
image.png
image.png
image.png

設定したサービスが作成されます。
image.png

.gitlab-ci.ymlファイル作成

GitLab Runnerを実行するには、.gitlab-ci.ymlファイルが必要です。
.gitlab-ci.ymlファイルにはECRへのイメージのPushを行うBuildステージとECSのタスク定義の更新、ECSサービスの更新を行うデプロイステージを記述します。

今回は手順削減のためにIAMユーザのキーを利用しますが、本来は環境変数に入れたり、EC2のIAMロールを利用することを推奨します。

gitlab-ci.yml
variables:
  DOCKER_DRIVER: overlay2
  DOCKER_TLS_CERTDIR: ""
  AWS_ACCOUNT_ID: 999999999999
  AWS_ACCESS_KEY_ID: ABCDEFGHIJKLMNOPQRSTU
  AWS_SECRET_ACCESS_KEY: ABCDEFGHIJKLMNOPQRSTUABCDEFGHIJKLMNOPQRSTU
  AWS_DEFAULT_REGION: ap-northeast-1
stages:
  - build
  - deploy
build-image:
  stage: build
  tags:
    - test-runner
  image: docker:18.09.7
  services:
    - docker:18.09.7-dind
  script:
    - apk add --update py-pip
    - pip install awscli
    - aws sts get-caller-identity
    - aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com
    - docker build -t alpine ./repository
    - docker tag alpine:latest ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/qiita-test-pj-repo:latest
    - docker push ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/qiita-test-pj-repo:latest
deploy-task-definition:
  stage: deploy
  tags:
    - test-runner
  image: docker:18.09.7
  services:
    - docker:18.09.7-dind
  script:
    - apk add --update py-pip
    - pip install awscli
    - aws ecs register-task-definition --cli-input-json file://task-definition.json
    - aws ecs update-service --cluster qiita-test-pj-cluster --service qiita-test-service --task-definition task-qiita-ecr --desired-count 2

一つだけ補足すると、最後の2つのコマンドはタスク定義とサービスの更新を行っており、update-serviceを実行することでタスク定義を最新のものに更新しています。
サービスで実行されるコンテナ数もここで更新をしています。

    - aws ecs register-task-definition --cli-input-json file://task-definition.json
    - aws ecs update-service --cluster nginx-ecs --service service-nginx-ecs --task-definition task-nginx-ecr --desired-count 2

タスク定義には以下のようなリビジョン番号があり、update-serviceをしないと更新されません。
image.png

.gitlab-ci.ymlファイル内の「tags」には登録したRunnerのタグを設定します。
Runnerのタグは以下から確認が可能です。
image.png
image.png

GitLabリポジトリへPush

ここまでできたら以下のコマンドを実行し、GitLab上のリポジトリにPushをします。

$ git add .
$ git commit -m "commit"
$ git push origin main

リポジトリにファイルがアップロードされます。
image.png

Pipeline実行確認

Pushが成功するとすぐにPipelineが実行されます。

以下の手順で実行されていることを確認します。
image.png
image.png
image.png
image.png

BuildとDeployが正常終了していることを確認します。
image.png

デプロイ結果確認

コンソールからECSクラスターを確認したところ、何故かコンテナが起動していませんでした。
出力されたメッセージを見ると、どうやらロググループが存在しないためエラーとなっていたようです。
(自動で作成されると記憶していましたが作成されていませんでした)

今回は手動で「/ecs/task-qiita-ecr」ロググループを作成しました。

 ResourceInitializationError: failed to validate logger args: create stream has been retried 1 times: failed to create Cloudwatch log stream: ResourceNotFoundException: The specified log group does not exist. : exit status 1

ロググループを作成してしばらくするとコンテナが起動してきました。
image.png

コンテナに設定されたパブリックIPをブラウザで確認するとデプロイしたアプリケーションが表示されたので、これでECSのデプロイまで完了しました。
image.png

※もし権限関係でコンテナの実行に失敗する場合は、タスク実行ロールにこのあたりのポリシーを付与するとうまくいくかもしれません。
image.png

おわりに

一度設定した仕組みなのでサッと作れるかと思いましたが、設定漏れが見つかったりして思ったよりも時間がかかりました。
GitLabはほとんど使ったことないのでイケてない記述があったかもしれませんが、とりあえずCICDまで動かせたのでOKでしょう。

長くなってしまいましたが、この記事がどなたかの参考になれば幸いです。

9
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
9
0