[2章] GitHub ActionsでDockerイメージを、AWS ECRへPUSHする
目次
- はじめに
- 概要
- 処理の確認
- おわりに
1. はじめに
こんにちは、ネクストビートの富永です。
本ブログは前回の1章で紹介した構成を、実際に作成していく内容になります。
これから作成を行う構成の概要を知りたい方は、前回の1章を先に読むことをおすすめします。
今回は、タイトルにあるようにGitHub Actionsの処理の中で、DockerイメージをAWS ECRへPUSHさせるところまでを行います。
構成図
2. 概要
以下の項目を行っていきます。
- 事前準備
- SBT Native Packagerの設定
- sbt-ecrの設定
- sbt-releaseの設定
- GitHub Actionsの設定
2.1 事前準備
今回は、Play Framework(Scala)で作成したアプリを使用します。
以下コマンドを実行して、アプリの初期化を行っておきましょう。
$ sbt new playframework/play-scala-seed.g8
今回は、masterブランチにPUSHを行った時に、処理を行うように設定します。
なので、masterとは別にブランチを作成して、設定は作成したブランチで行います。
※筆者は、developブランチを作成して実装を進めます。
AWS ECRの作成
今回の実装で、DockerイメージをPUSHするECRを作成します。
※今回作成するECRは、テスト用です。最終的にはCDK for Terraformで作成したものを使用します。
まずは、AWSのECRの設定を行うページへいきます。
次に、「リポジトリを作成」を選択します。
リポジトリの種類は、プライベートを選択します。
そして、リポジトリ名を入力し「リポジトリを作成」を選択します。
※イメージスキャンの設定や暗号化設定は今回行いません。
以下のように作成されていれば、ECRの設定は完了です。
GitHubにAWS用の環境変数を作成
GitHub ActionsでAWS APIを使用できるように、アクセスキーとシークレットアクセスキーを環境変数に登録します。
アクセスキーとシークレットアクセスキーの取得方法に関しては、AWSのIAM ユーザーのアクセスキーの管理を参照してください。
※ECRへのアクセス許可のあるIAMユーザーを使用してください。
アプリのGitHubへいき、上タブの「Settings」を選択し、左側のタブから「Secrets」を選択します。
そして、「New repository secret」を選択しアクセスキーとシークレットアクセスキーの登録を行います。
アクセスキーの環境変数は、以下のように「AWS_ACCESS_KEY_ID」とします。
valueにアクセスキーを入力し、「Add secret」で作成します。
シークレットアクセスキーの環境変数は、以下のように「AWS_SECRET_ACCESS_KEY」とします。
先ほどと同じように、valueにシークレットアクセスキーを入力し、「Add secret」で作成します。
両方作成できると以下のように表示されているはずです。
これでAWS用の環境変数の設定は完了です。
2.2 SBT Native Packagerの設定
今回使用するバージョンは、以下です。
sbt-native-packager: v1.7.6
今回使用するSBT Native Packagerはsbtのプラグインであり、プロジェクトをDockerイメージとしてビルドできるようにしてくれるものです。
※実際には、Dockerイメージ以外もできます。
筆者は、これ以外の方法でプロジェクトをDockerイメージ化したことはありませんが、本来はalpineなりdebianなりのベースイメージにjdkとsbtをインストールしたりして生成を行うようです。
先ほど作成したアプリに、SBT Native Packagerの設定を追記していきます。
記述ファイル: アプリ名/project/plugins.sbt
plugins.sbtに以下設定を追記します。
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.7.6")
プラグインの追加はできましたので、次はbuild.sbtに設定を追記していきます。Docker用の設定は、Keys.scalaで確認できます
まずは、SBT Native PackagerでのビルドをDockerイメージとして出力するために以下を追記します。
enablePlugins(DockerPlugin)
次は、Dockerイメージのために以下を設定します
maintainer in Docker := "Dockerアクセス用のメールアドレス"
SBT Native Packagerのデフォルトベースイメージの設定です。
デフォルトでは、openJdkですが今回はAmazon Correttoを使用します。
dockerBaseImage := "amazoncorretto:8"
Dockerで使用するポート番号を設定します。
Play Frameworkのデフォルトポートが9000なので、同じにしてみました。
dockerExposedPorts in Docker := Seq(9000, 9000)
SBT Native Packagerは、UIDが1001に設定されたdemiourgos728というデーモンユーザーをデフォルトで作成し、USER 1001をエミットします。
ただ今回設定したデフォルトベースイメージのamazoncorrettoは、amazonlinuxをベースにしており、amazonlinuxではaddgroupやadduserが使えません。
なので、代わりにUSERデーモンをエミットするように以下を追記します。
daemonUser in Docker := "daemon"
追記完了後は、以下のようになっています。
enablePlugins(DockerPlugin)
maintainer in Docker := "メールアドレス"
dockerBaseImage := "amazoncorretto:8"
dockerExposedPorts in Docker := Seq(9000, 9000)
daemonUser in Docker := "daemon"
これで、SBT Native Packagerの設定は完了です。
ちゃんとDockerイメージとしてビルドできるか気になる方は、以下コマンドを実行してみてください。
$ sbt docker:publishLocal
2.3 sbt-ecrの設定
今回使用するバージョンは、以下です。
sbt-ecr: v0.15.0
sbt-ecrも先ほどのSBT Native Packagerと同じsbtのプラグインです。
sbt-ecrは、AWS ECRへDockerイメージをPUSHすることができるプラグインです。
先ほどと同じようにplugins.sbtに、以下を追記してアプリにプラグインを追加します。
addSbtPlugin("com.mintbeans" % "sbt-ecr" % "0.15.0")
次は、sbt-ecrのためにbuild.sbtに設定を追記していきます。
まずは、以下をインポートしてリージョンの情報を取得できるようにします。
import com.amazonaws.regions.{Region, Regions}
次に、sbt-ecrを使用できるように以下を追記します。
enablePlugins(EcrPlugin)
以下設定を追加し、どこのリージョンを使用するか指定します。
今回は、ap-northeast-1を使用します。
※事前準備で作成したECRと同じリージョンを指定してください。
region in Ecr := Region.getRegion(Regions.AP_NORTHEAST_1)
以下は、PUSH先のリポジトリの設定です。
事前準備で作成したECRのリポジトリ名を指定します。
repositoryName in Ecr := "AWS ECRリポジトリ名"
以下は、ECRへPUSHする際のバージョンを指定します。
今回は、任意のバージョンと固定のlatestを指定します。
※version.valueは、この後sbt-releaseで設定するversionの値です。
repositoryTags in Ecr := Seq(version.value, "latest")
以下で、Dockerイメージにタグを紐付けます。
localDockerImage in Ecr := (packageName in Docker).value + ":" + (version in Docker).value
追記完了後は、以下のようになっています。
import com.amazonaws.regions.{Region, Regions}
enablePlugins(EcrPlugin)
region in Ecr := Region.getRegion(Regions.AP_NORTHEAST_1)
repositoryName in Ecr := "AWS ECRリポジトリ名"
repositoryTags in Ecr := Seq(version.value, "latest")
localDockerImage in Ecr := (packageName in Docker).value + ":" + (version in Docker).value
これで、sbt-ecrの設定は完了です。
2.4 sbt-releaseの設定
今回使用するバージョンは、以下です。
sbt-release: v1.0.13
sbt-releaseもsbtのプラグインです。
sbt-releaseは、プロジェクトをリリースする際に登録している処理を自動で行ってくれるものです。
デフォルトの設定では、gitタグを生成し、リポジトリに公開、開発用にバージョンを上げてくれたり、テストをしたりといった処理が登録されています。
このsbt-releaseを利用して、Dockerイメージの生成、ECRへのPUSHを自動でやってもらいます。
それでは、他のプラグインと同じようにplugins.sbtに以下を追記して、アプリにプラグインを追加します。
addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.13")
今回使用したPlay Frameworkの初期化方法では、build.sbtに以下のようなversionが記載されています。
version := "1.0-SNAPSHOT"
sbt-releaseの設定では、上記のversionは使用せずversion.sbtというファイルを作成し、このファイルでversionの管理を行っていきます。
build.sbtに記載されている上記versionは削除します。
次にversion.sbtというファイルをbuild.sbtと同じ階層に作成します。
アプリ名
∟build.sbt
∟version.sbt
作成したversion.sbtのファイルに以下のようにversion情報を追記します。
version in ThisBuild := "1.0.0-SNAPSHOT"
これで、sbt-releaseのversionに関する設定は完了です。
次は、リリース時に行う処理の設定を行っていきます。
まずは、build.sbtに以下を追記します。
これで、sbt-releaseに定義されているメソッド達を使用可能になります。
import ReleaseTransformations._
次に、以下を追記します。
releaseVersionBump := sbtrelease.Version.Bump.Bugfix
これは、versionをあげる際にどのレベルでバージョンをあげるかの設定です。
versionのレベルに関しては、READMEのConvenient versioningに記載されています。
今回は、バグフィクスのversionをあげる設定にしています。
例: 1.0.0 -> 1.0.1
次は以下を追記します。
このSeq[ReleaseStep]()の中に行いたい処理を順番に追記していきます。
releaseProcess := Seq[ReleaseStep](
)
デフォルトの設定は、以下のようになっています。
デフォルトの設定に関しては、READMEのRelease Processを確認してください。
releaseProcess := Seq[ReleaseStep](
checkSnapshotDependencies,
inquireVersions,
runClean,
runTest,
setReleaseVersion,
commitReleaseVersion,
tagRelease,
publishArtifacts,
setNextVersion,
commitNextVersion,
pushChanges
)
今回は、行いたい処理のみを追記していきます。
まずは、ECRへのログインを行う処理を追記します。
releaseProcess := Seq[ReleaseStep](
ReleaseStep(state => Project.extract(state).runTask(login in Ecr, state)._1),
)
このReleaseStepは、独自に行いたい処理をカスタマイズして作成できるものです。
こちらも詳細な説明はREADMEのCustomizing the release processに記載されています。
次は、以下を追記します。
releaseProcess := Seq[ReleaseStep](
...
inquireVersions,
runClean,
setReleaseVersion,
)
inquireVersionsでリリースバージョンと次の開発バージョンの確認を行い、クロスビルド用にクリーンを行い、version.sbtに記載されているバージョンをこのビルドに反映させます。
次は、先ほどと同じように独自のリリース項目を追記します。
以下の処理は、SBT Native Packagerを使用したDockerイメージの生成を行います。
releaseProcess := Seq[ReleaseStep](
...
ReleaseStep(state => Project.extract(state).runTask(publishLocal in Docker, state)._1),
)
sbt-releaseの処理の中で、dockerイメージを生成する sbt docker:publishLocalを行っていると考えてください。
そして、次は以下を追記して生成したDockerイメージをECRへPUSHします。
releaseProcess := Seq[ReleaseStep](
...
ReleaseStep(state => Project.extract(state).runTask(push in Ecr, state)._1),
)
こちらもsbt-releaseの処理の中で、sbt ecr:pushコマンドを実行していると考えてください。
最後に以下を追記します。
releaseProcess := Seq[ReleaseStep](
...
commitReleaseVersion,
tagRelease,
setNextVersion,
commitNextVersion,
pushChanges
)
上から順番に、version.sbtのversionでtagのコミット・リリースを行い、version.sbtに次のバージョンをセット・コミット、プッシュして反映を行います。
上記全てを追記したら以下のようになっているはずです。
releaseProcess := Seq[ReleaseStep](
ReleaseStep(state => Project.extract(state).runTask(login in Ecr, state)._1),
inquireVersions,
runClean,
setReleaseVersion,
ReleaseStep(state => Project.extract(state).runTask(publishLocal in Docker, state)._1),
ReleaseStep(state => Project.extract(state).runTask(push in Ecr, state)._1),
commitReleaseVersion,
tagRelease,
setNextVersion,
commitNextVersion,
pushChanges
)
上記と同じになっていれば、sbt-releaseの設定は完了です。
2.5 GitHub Actionsの設定
次は、これまで設定してきた実装をGitHub Actionsで使用できるように設定を行っていきます。
まず、作成したアプリのGitHubにいきます。
以下画像のように、「Actions」のタブを選択するとworkflow templateの一覧が表示されています。
今回Scalaでアプリを作成しているので、Scala用のテンプレートを使用します。
「Set up this workflow」を選択して、設定を行います。
設定画面では、以下のようにデフォルトの設定が記載されているはずです。
まずは、ファイル名を「scala.yml」から「deploy.yml」に変更します。
※名前はなんでも大丈夫です。
次は以下のように、GitHub ActionsをmasterブランチにPUSHした時のみ、起動するように設定します。
on:
push:
branches: master
次は、GitHub ActionsでAWSへアクセスできるように設定を追記します。
secretsで、事前準備で登録しておいた環境変数を使用します。
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
以下Javaの設定に関しては、何も変更を行いません。
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
最後にsbt-releaseの設定を追記します。
sbt-releaseコマンドを実行するために、ユーザーの設定とGitHubトークンの設定を追記します。
- name: Run sbt release
env:
GITHUB_USER: ${{ github.actor }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git config --global user.email "メールアドレス"
git config --global user.name ${{ github.actor }}
sbt "release with-defaults"
※GITHUB_TOKENもsecretsを使用していますが、これはGitHub 側で提供されている Actions 用 bot アカウントの認証トークンです。このトークンを利用することで GitHub を API で操作することができるようになります。
actions/checkout@v2では、nameとemailを設定する必要があるので、以下の様にgit configで設定します。
git config --global user.email "メールアドレス"
git config --global user.name ${{ github.actor }}
全ての設定が終わると下記のようになっているはずです。
コミットを行い設定を完了させましょう。
3. 処理の確認
本ブログで行う設定は、全て完了しました。
最後に、masterブランチにPUSHを行い、DockerイメージをECRへPUSHできるかを確認していきます。
今まで設定を行ってきたブランチで、masterブランチに向けてプルリクエストを作成します。
設定に漏れがないかを確認して、「Merge pull request」でマージします。
マージ後に、上タブ「Actions」を選択しGitHub Actionsのページへ行くと以下のようにGitHub Actionsの処理が動いているのを確認できるはずです。
この処理が正常に終了したら、事前準備で作成したECRを確認しにいきましょう。
リポジトリを選択し、以下のようにイメージタグが生成されていれば成功です。
4. おわりに
最後まで読んでいただき、ありがとうございます。
今回はいろいろなプラグインを使用して、一連の処理作成を行いました。
個人的にsbt-releaseがとても便利だなと感じました。
なぜなら筆者は最初sbt-releaseの存在を知らず、GitHub Actionsの中でタグの生成、取得、Dockerイメージへの紐付けを自力でやろとしていました。
色々試行錯誤して最後は、物理的に不可能じゃねという結論に至りましたが…
その後に、このsbt-releaseというものを知って軽く感動を覚えました。
ゆくゆくは、こんな便利なプラグインを作ってみたいものです。
今回の処理で、DockerイメージをECRへPUSHすることができましたので、次はこのPUSHを検知して、ECRの更新内容をSlackへ通知する設定を行っていきます!
それでは、次の3章でお会いしましょう。
参考文献
ScalaのPlayアプリケーションをsbt-native-packagerの力を借りてDockerで動かす
sbt-native-packager のベースイメージに amazoncorretto を指定して脆弱性を解決する
sbt-native-packager Docker Plugin
GitHub Actions を用いて bot から Pull-Request にコメントをする方法
ワークフローで認証する
We are hiring!
「人口減少社会において必要とされるインターネット事業を創造し、ニッポンを元気にする。」
を理念に掲げ一緒に働く仲間を募集しております。