Perl Hackers Hub

第61回 GitHub ActionsとAmazon ECSを使ったDockerアプリケーションの自動デプロイ(3)

この記事を読むのに必要な時間:およそ 3 分

(1)こちら⁠2)こちらから。

GitHub Actions─⁠─ ビルドとデプロイプロセスの自動化

(3)では,先ほど作成したECS環境に,GitHub Actionsを用いて自動的にアプリケーションをビルドしてデプロイするしくみを構築します。

GitHub Actionsとは,GitHubがgithub.comに統合した形で提供するCIContinuous Integration継続的インテグレーション)/CDContinuous Delivery継続的デリバリ)環境です。GitHub Actionsには,ソースコードのpullやPull Requestのアサインといった豊富な機能(アクション)が用意されています。ユーザーは,アクションと実行タイミングや実行環境などを組み合わせ,ワークフローと呼ばれるYAMLYAML Ain't Markup Languageファイルにまとめます。リポジトリの所定の位置にこのYAMLファイルを配置すると,GitHubがそのとおりにワークフローを実行してくれます。

今回はブランチモデルとして,git-flow方式に似た構成を採用します。すなわち,デプロイ用のブランチとしてmasterを使い,デプロイの前段階としての開発用ブランチにdevelブランチを使います。

cpanfile.snapshotを自動で生成しよう

cpanfile.snapshotは,carton installを実行する環境によっては異なるものが生成されます。そのため,各開発者の手もとでcpanfileとともにcpanfile.snapshotをコミットする方法で開発している場合,cpafile.snapshotが頻繁に変化してしまうことがあります。これを防ぐために,GitHub Actionsを使ってcpanfile.snapshotを集中的に生成しましょう。

ワークフローの定義

では,.github/workflows/perl.ymlにワークフローを定義しましょう。

on:
  push:
    branches:
      - devel
  pull_request:
    branches:
      - devel
jobs:
  cpan:
    runs-on: ubuntu-latest
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
    - uses: actions/checkout@v2
    - name: Generate cpanfile.snapshot
      working-directory: ./application
      run: |
        ./generate-cpanfile-snapshot.sh
    - uses: stefanzweifel/git-auto-commit-action@v3.0.0
      with:
        commit_message: Updated cpanfile.snapshot
        file_pattern: application/cpanfile.snapshot

前半のonブロックでは,ワークフローの実行条件を指定します。今回は,develブランチにpushされたときと,devel宛てのPull Requestで変更を検知したときを指定しています。

後半のjobsブロックが,実際の処理を記述する部分です。ワークフローは複数のジョブから成り立っており,ジョブはさらに複数のステップから成り立っています。個々のアクションはステップで実行されます。今回は,1つのジョブを作成しています。そのジョブの中で,まずcheckoutアクションを使ってソースコードをGitHub Actions上の仮想環境にチェックアウトしたあと,cpanfile.snapshotを生成するgeneratecpanfile-snapshot.shというシェルスクリプトを呼び出します。そして,git-auto-commit-actionアクションによって,cpanfile.snapshotが変更されていればコミットし,pushしています。

cpanfile.snapshotを生成するシェルスクリプトの作成

前述したgenerate-cpanfile-snapshot.shでは,cpanmやCartonをインストールし,carton installを実行してcpanfile.snapshotを生成しています。簡潔なコードなのでここでは割愛します。WEB+DB PRESS Vol.116のサポートサイトのサンプルコードを参照してください。

いざ生成

これで,自動的にcpanfile.snapshotを生成する準備ができました。perl.ymlgenerate-cpanfilesnapshot.shをコミットしてpushすると,ワークフローが起動してcpanfile.snapshotが生成されます。

Amazon ECSへデプロイしよう

GitHubには,ECSにアプリケーションをデプロイする公式アクションが用意されています。これにより,⁠特定のブランチにコミットがpushされたとき」といったタイミングでECSにイメージをデプロイできます。

ワークフローの定義

GitHubのテンプレートを使ってワークフローを作成しましょう。GitHubでリポジトリを開き,⁠Actions」タブの「New workflow」ボタンをクリックすると,⁠Deploy to Amazon ECS」という項目が表示されるので,これを選択します。すると,あらかじめ項目が埋められたYAMLファイルを編集する画面が現れます。

編集を行う前に,あらかじめ,次のリソースを用意しておきましょう。それぞれについて詳しくは,YAMLファイルのコメント(英語)をご覧ください。

  • アプリケーションのイメージが格納されるECRリポジトリ(URIではなく名前を記入する)
  • リポジトリのリージョン名
  • ECSクラスタ

YAMLファイルの各項目を次のように埋め,.github/workflows/aws.ymlとして保存します。

(省略)
- name: Build, tag, and push image to Amazon ECR
  id: build-image
  env:
    ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
    ECR_REPOSITORY: ECRリポジトリ
    IMAGE_TAG: ${{ github.sha }}
  run: |
    docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_T
AG ./application/
    docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
    echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPO
SITORY:$IMAGE_TAG"
- name: Fill in the new image ID in the Amazon ECS task de
finition
  id: task-def
  uses: aws-actions/amazon-ecs-render-task-definition@v1
  with:
    task-definition: task-definition.json
    container-name: app # ここではコンテナ名をappとする
    image: ${{ steps.build-image.outputs.image }}
- name: Deploy Amazon ECS task definition
  uses: aws-actions/amazon-ecs-deploy-task-definition@v1
  with:
    task-definition: ${{ steps.task-def.outputs.task-defin
ition }}
    service: サービス名
    cluster: クラスタ名
    wait-for-service-stability: true
(省略)

今回は,masterブランチにマージなどの変更が発生したときにデプロイしたいので,masterブランチへのpushかマージがあったときにワークフローを起動するよう,デフォルトのまま指定しました。

Amazon ECSタスク定義の作成

GitHub Actionsを使ってデプロイする場合,タスク定義としてtask-definition.jsonを用意する必要があります。手動で作成することもできますが,あらかじめブラウザ上のGUIGraphical User Interfaceでひな型を作成しておき,編集画面からコピーできるJSONを保存すると簡単です。

Amazon ECSのトップ画面から「タスク定義」タブを開き,⁠新しいタスク定義の作成」をクリックし,ウィザードにしたがってタスク定義を設定します。⁠起動タイプ」「FARGATE」を選択し,⁠コンテナの追加」をクリックしてコンテナ定義を1つ作成します。ここではコンテナ名やイメージを,ecs-cliコマンドを使ったときと同じに設定しておきます。こうして作成したタスク定義を「タスク定義」タブから開くと,JSONをコピーできます。JSONにはrequiresAttributesといったプロパティが自動で追加されていますが,これは不要なので削除します。そのほかにもデプロイ時に不要なパラメータを指摘されることがあるため,その場合は該当するプロパティを都度削除しましょう。

IAMユーザーのクレデンシャルの登録

イメージのpushやデプロイにはIAMIdentity and Access Managementユーザーが必要です。IAMユーザーを作成して,各種権限を割り当てましょう。ここでは割愛しますが,ECSのサービスを更新する権限と,ECRにアップロードする権限などを設定します。

そして,GitHubがこのIAMユーザーとして振る舞えるようにするために,作成したIAMユーザーのアクセスキーIDとシークレットアクセスキーをGitHubに登録します。これはYAMLファイルにではなく,GitHub Actions Secretsとして別画面から保存します。リポジトリの「Settings」「Secrets」を開くとクレデンシャルを追加できますので,アクセスキーIDはAWS_ACCESS_KEY_IDという名前で,シークレットアクセスキーはAWS_SECRET_ACCESS_KEYという名前で保存しましょう。

いざデプロイ

これで準備ができました。develブランチからのPullRequestをmasterブランチにマージすると,ECSクラスタにPerlアプリケーションが自動的にデプロイされます。

まとめ

今回は,ECSとGitHub Actionsを用いて,Dockerアプリケーションをすばやくビルド,デプロイする方法を解説しました。

さて,次回の執筆者は清水隆博さんで,テーマは「Perl歴史散策」です。お楽しみに。

WEB+DB PRESS

本誌最新号をチェック!
WEB+DB PRESS Vol.119

2020年10月24日発売
B5判/160ページ
定価(本体1,480円+税)
ISBN978-4-297-11669-9

  • 特集1
    [古い技術,コードの重複,密結合]
    フロントエンド脱レガシー
    長く愛されるプロダクトをさらに改善していくために
  • 特集2
    インフラ障害対応演習
    「避難訓練」でいざに備える!
  • 特集3
    深層学習入門以前
    チュートリアルを動かす前に知っておくこと

著者プロフィール

野口啓介(のぐちけいすけ)

大学在学中に『はてなサマーインターン』に参加し,卒業後の2016年に株式会社はてなに入社。型のパワフルさを活かした開発が得意。

入社後はScalaによる『はてなブックマーク』のリプレイスメントプロジェクトや,『はてなブログ』の開発に参加。

アプリケーションエンジニアとしてバックエンド部分を主に担当しつつも,趣味で運用している自宅サーバで培ったインフラ寄りの知識でチームをサポートしている。

2018年8月より同社のマンガビューワの開発に携わっている。

GitHub:windymelt
Twitter:@windymelt
Hatena:id:Windymelt