ページの先頭です

ページ内を移動するためのリンク
本文へ (c)

ここから本文です。

GitLab CIでAmazon ECSのコンテナデプロイを自動化する

ライター:吉田 将大
システムインテグレータでソフトウェア開発業務を経験した後、2018年にネットワンシステムズに入社。
前職での経験を活かした開発案件の支援や、データ分析基盤製品・パブリッククラウドの導入を支援する業務に従事。
保有資格: AWS認定ソリューションアーキテクトプロフェッショナル

目次

ネットワンシステムズの吉田です。

AWS のコンテナオーケストレーションサービスである Amazon Elastic Container Service(ECS)にデプロイするアプリケーションのコードを、オンプレミスにホストしたGitLabリポジトリで管理している方々も多くいると思います。
そんなエンジニアの方々向けに、GitLab CI の機能を使って、ECS へのコンテナデプロイを自動化する方法の一例をご紹介します。

ECS へのコンテナアプリケーションデプロイの流れ

ECS にコンテナをデプロイする際には、一般的に下記のような手順が必要です。

  • ソースコードのテスト
  • コンテナイメージのビルド
  • コンテナレジストリにイメージをプッシュ
  • タスク定義の更新
  • サービス定義の更新、サービス再起動

これらの手順は Docker CLI や AWS CLI を使って手動で実行することが可能ですが、ソースコードが更新されるたびに、毎回人間が実行するのは非常に大変で、コマンドの入力ミス等のリスクもあり、現実的ではありません。
今回紹介するのは、「コンテナイメージのビルド」「コンテナレジストリにイメージをプッシュ」「タスク定義の更新」という3つのステップを自動化する方法になります。

自動化アーキテクチャイメージ

前述の3つのステップを GitLab リポジトリへの Git Push をトリガーに、GitLab CI でこれらの手順を自動化します。
下記に実装イメージを示します。

開発者は、開発したソースコードを GitLab のリポジトリに Push するだけです。
そこから先のイメージのビルドや、タスク定義の更新などのステップは、GitLab CI によって実行されます。
今回はコンテナレジストリとして Amazon ECR を使用しています。

GitLabのCI/CD 設定

事前に GitLab のリポジトリの CI/CD 設定で、以下の環境変数を設定しておきます。

  • ECR_REPOSITORY: イメージをプッシュする ECR リポジトリ名
  • AWS_ACCESS_KEY_ID: AWS認証アクセスキーID
  • AWS_SECRET_ACCESS_KEY: AWS 認証シークレットアクセスキー
  • AWS_DEFAULT_REGION: AWS デフォルトリージョン

本ブログでは、Docker ExecutorをRunner として使用するケースを想定しています。
今回はGitLab CI環境自体(GitLab、GitLab Runner)の構築については割愛させて頂きます。

AWS の認証に使う IAM ユーザの権限は、ECR リポジトリへのプッシュ・ECS のデプロイに関連するものに限定し、必要最低限の権限を付与するよう気を付けてください。

プロジェクトの構成

実際に CI の設定をする前に、まずソースコードプロジェクト内のファイル構成についてご説明します。

./
├── app
│   ├── Dockerfile
│   └── src
└── task-definition.json

app ディレクトリ配下には Dockerfile とビルドに含めるアプリケーションソースコードなどを格納します。

task-definition.json は、タスク定義を json 形式で記述したものです。
タスク定義の詳細についてはこちらを参照してください。

GitLab CI のDocker Executor 環境では、Runner となるコンテナ起動時に、リポジトリ内のソースツリーがコンテナのワーキングディレクトリにコピーされます。

.gitlab-ci.yml の作成

GitLab CI を設定するためには、.gitlab-ci.yml ファイルを作成し、ソースコードリポジトリのトップディレクトリ配下に配置します。

variables:
  # Docker in Dockerでbuildするために必要な設定
  DOCKER_HOST: tcp://docker:2375
  DOCKER_TLS_CERTDIR: ""
stages:
  - build
  - deploy
# イメージのビルドとプッシュ
build-image:
  stage: build
  services:
    - name: docker:stable-dind # Docker in Dockerコンテナをサービスとして起動
  image: docker:stable
  before_script:
    # AWS CLIをインストール
    - apk add --update py-pip
    - pip install awscli
  script:
    # イメージのビルド
    - docker build app -t $ECR_REPOSITORY:latest
    # IAM認証情報を使用してECRリポジトリのログインパスワードを取得
    - aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_REPOSITORY
   # イメージのプッシュ
    - docker push $ECR_REPOSITORY:latest
# タスク定義更新
register-task-definition:
  stage: deploy
  image: python:3.8-slim-buster
  before_script:
    - pip install awscli
  script:
    - aws ecs register-task-definition --cli-input-json file://task-definition.json

コンテナイメージのビルド

まずイメージビルドの箇所を見ていきます。

build-image:
  stage: build
  services:
    - name: docker:stable-dind # Docker in Dockerコンテナをサービスとして起動
  image: docker:stable
  before_script:
    # AWS CLIをインストール
    - apk add --update py-pip
    - pip install awscli
  script:
    # イメージのビルド
    - docker build app -t $ECR_REPOSITORY:latest
    # IAM認証情報を使用してECRリポジトリのログインパスワードを取得
    - aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_REPOSITORY
   # イメージのプッシュ
    - docker push $ECR_REPOSITORY:latest

今回は Docker Executor 環境で、かつ Docker を使用してアプリケーションコンテナイメージをビルドするため、Docker in Docker コンテナを services セクションで起動しています。

また、前工程として before_script セクションで AWS CLI をインストールしています。これは、ECR リポジトリにイメージを push する際にリポジトリの認証情報を取得するために使用します。

script セクションで、実際にイメージのビルドとプッシュを実行する処理を記述しています。
今回は便宜上イメージのタグを latest としていますが、実際の運用ではプッシュされたソースコードリポジトリのタグ名やコミットハッシュなどを指定し、task-definition.json 側でイメージタグの指定箇所をテンプレート化して、動的に指定できるようにすることを推奨します。

タスク定義更新

続いてタスク定義を更新している箇所を見ていきます。

build-image:
# タスク定義更新
register-task-definition:
  stage: deploy
  image: python:3.8-slim-buster
  before_script:
    - pip install awscli
  script:
    - aws ecs register-task-definition --cli-input-json file://task-definition.json

こちらのジョブでは、ビルドの時と同様に before_script セクションで AWS CLI をインストールしています。script セクションでは AWS CLI の "ecs register-task-definition" コマンドで、リポジトリ内の task-definition.json をインプットに指定して実行しています。
これにより ECS のタスク定義がソースコードリポジトリ内の task-definition.json の情報と同期されます。

まとめ

今回は GitLab CI を使用して Amazon ECS へのコンテナアプリケーションデプロイを自動化する方法をご紹介しました。
ご紹介したテクノロジーは弊社の大手金融企業のお客様に提供しているサービス開発でも使用しています。

ECS タスクをサービスとして常駐させる場合は、後段のジョブでサービス定義の更新やサービス更新を実行することで同様にデプロイ自動化が可能です。

Amazon ECS をコンテナアプリケーション基盤として利用しているエンジニアの方々のお役に立てれば幸いです。

※本記事の内容は執筆者個人の見解であり、所属する組織の見解を代表するものではありません。

RECOMMEND