DevOps エンジニアの 根本 征 です。
7月からエクサウィザーズ にジョインし、CI / CD パイプラインの改善や自動テストの布教などを行っています。
今回は GitHub Actions の self-hosted runners を AWS ECS 上に構築し運用してみたので、その試行錯誤について紹介したいと思います。
- GitHub Actions と self-hosted runners
- self-hosted runners を Docker で動かす
- self-hosted runners を AWS ECS で動かす
- アプリケーションを AWS ECS へデプロイする Workflow を作る
- おわりに
GitHub Actions と self-hosted runners
GitHub Actions は GitHub ユーザーであれば現在多くの方がご存知・ご活用されているかと思います。
GitHub Marketplace で公開されている Actions と組み合わせることによって、簡単に様々な CI / CD パイプラインを構築することができます。
そんな GitHub Actions ですが、GitHubが提供する Runner を使う代わりに自前で用意することもできます(self-hosted runners)。
GitHub が提供する Runner で GitHub Actionsを利用する場合、無料利用枠 + 従量課金の課金体制になります。
しかし、self-hosted runners で GitHub Actions を利用する場合には別途料金がかかることはありません。
Repository または Organization の設定からself-hosted runners をセットアップすることができます(Linux / MacOS / Windows 毎に手順が示されます)。
セットアップが完了すると、Runner として追加されていることが確認できます。
Repository で設定した Runner はその Repository で、そして Organization で設定した Runner はその Organization 内の全ての Repository で実行することができます。
最後に GitHub Actions の設定ファイルにおいて、self-hosted runners で実行することを記述します。
self-hosted runners はマシン自体は自分たちで調達・メンテナンスをしないといけないですが、ワークフローを管理する部分(Jenkins でいう master)を自前で用意せず無料で利用できる点は魅力的だと感じます。
self-hosted runners を Docker で動かす
self-hosted runners 自体はオープンソースとして公開されていますが、現在 Docker イメージは提供されていません。
調べたところ、Docker・Kubernetes で self-hosted runners 動かすためにオープンソースプロジェクトで様々な試行錯誤が行われているみたいです。
本記事では AWS ECS をメインに下記の手順で解説します。
self-hosted runners を Docker で動かす
self-hosted runners を AWS ECS で動かす
その self-hosted runners を用い、アプリケーションを AWS ECS にデプロイするパイプラインを作る
まず下記の Docker イメージを使い、手元で self-hosted runners を立ち上げてみます。
Organization に対して Runner を立ち上げるためには下記 docker コマンドを実行します。
GitHub Actions では Docker の操作(ビルドなど)を行うため、このコンテナ内でも Docker コマンドが使えることが必要になります。
そのため、ホストマシン上の Docker daemon を共有することで解決しています(-v /var/run/docker.sock:/var/run/docker.sock
の部分、Docker outside of Docker)
Using Docker-in-Docker for your CI or testing environment? Think twice.
self-hosted runners を AWS ECS で動かす
次に先ほどの Docker イメージを使って、AWS ECSで動かしてみます。
今回は AWS CDK(Typescript) をベースに3つのポイントに絞って解説します。
1つ目に AWS ECS で Docker outside of Docker(DooD) をどう実現するかについてです(-v /var/run/docker.sock:/var/run/docker.sock
の部分)。
AWS ECS だと Task 側に Volume を追加し、Container 側にその Volume をマウントすることで解決することができます。
AWS ECS では起動タイプとして Fargate と EC2 がありますが、現状 Fargate で上記を行うことがサポートされていなかったため、今回はEC2起動タイプを選択しました。
2つ目に ECS Task に与える Role についてです。
今回の GitHub Actions 上でのパイプラインでは、Docker ビルド ・ECRへのイメージのアップロード・ECSへのデプロイまで行おうとしています。
もちろん GitHub 側に AWS アクセスキーを保存し、それを GitHub Action に渡すことで上記を実現することができます。
しかし、self-hosted runners のコンテナ自体に上記に必要な Role を与えることによって、GitHub側に AWS アクセスキーを保存する必要自体をなくすことができます。
3つ目に、スポットインスタンスについてです。
self-hosted runners は CI / CD として使うため、スポットインスタンスを活用してコストを抑えることができます。
AWS CDK の場合、spotInstanceDraining
プロパティを true にすることでスポットインスタンスを利用することができます。
アプリケーションを AWS ECS へデプロイする Workflow を作る
今回はこの GitHub Actions と self-hosted runners を活用して、アプリケーションを AWS ECS へデプロイする Workflow を作りたいと思います。
同じ AWS ECS なのでややこしくなってしまいますが、self-hosted runners を動かすクラスタとアプリケーションを動かすクラスタは別という想定です。
具体的には下記のような手順になります。
Docker build して ECR にPushする ↓ Task Definition ファイルを編集する(Dockerイメージの部分を新しくする) ↓ Task Definition を新たに登録し、Service が更新されるまで待つ
AWSで提供されている GitHub Actions の Step と組み合わせると下記のようになります。
先ほども述べましたが、本来は aws-actions/configure-aws-credentials
の Step で下記のように AWS アクセスキーを GitHub に保存し渡してあげる必要があります。
しかし、今回は self-hosted runners に必要な権限を渡してあげているのでこの必要はありません。
おわりに
今回はGitHub Actions の self-hosted runners を AWS ECS 上に構築してみましたが、下記のような状況でメリットがあると考えています。
GitHub Action を使ってアプリケーションをAWSへデプロイする際、GitHub 側に不必要に AWS アクセスキーを渡したくない
スポットインスタンスや活用することによって、コストパフォーマンスよく CI / CD 環境を運用したい(特に無料枠を大幅に超えることが予想される場合)
GitHub が提供する Runner よりスペックの高いマシンで CI / CD 環境を運用したい
今後、この GitHub Actions をベースにより良い CI / CD パイプラインが作れたら良いと考えています。