GitHub ActionsとECSタスク定義の循環依存を解消した話
ECSタスク定義とECRリポジトリの設定で苦戦したため、その解決の記録を共有します。
起こった問題
インフラ側
ECSタスク定義を作成する際、指定するECRリポジトリが空の場合、タスク定義の作成が失敗する問題が発生しました。
このため、事前にリポジトリに最低1つのDockerイメージをプッシュする必要がありました。
アプリ側
GitHub Actionsでは、ECSタスク定義のイメージURI(ECRリポジトリ)を参照しますが、タスク定義が存在しない場合にイメージをプッシュする処理が失敗する問題がありました。
これにより、以下のような循環依存が発生しました:
- タスク定義がないとGitHub Actionsでイメージをプッシュできない。
- イメージがないとタスク定義を作成できない。
試したアプローチ
試したこと 1: Terraformのlocal-execでDockerイメージをビルドしてPush
local-execとは、Terraformが実行される環境でコマンドを実行できるものです。
私はTerraform Cloudを使用しているので、実行はTerraform Cloud上で実行されます。
以下の記事のように、ECRリポジトリの作成をトリガーに、local-execで適当なDockerfileでビルドしてリポジトリにプッシュするのを試しました。
結果・問題点
Terraform Cloud環境では、local-execが実行される環境でsudoが使えません。そのため、apt-getでDockerをインストールできず、Dockerコマンドを使用することができませんでした。
試したこと 2: AWS CLIでイメージをコピー
他のECRリポジトリからAWS CLIを使ってイメージをコピーするアプローチを試みました。以下のコマンドを参考にしました:
結果・問題点
- クロスアカウントでのリポジトリコピーは許可設定を行っても実現できませんでした。
- さらに、この方法はイメージのタグ変更が目的であり、別のリポジトリから直接コピーする用途ではありませんでした。AWS CLIのputコマンドを使用すると以下のようなエラーが起きました。
エラー:
(local-exec): An error occurred (LayersNotFoundException) when calling the PutImage operation: Layers with digests '[sha256:abcdefghijklmnopqrstuvwxyz]' required for pushing image into repository with name 'sample/php-fpm' in the registry with id '12345667' do not exist
試したこと 3: LambdaでDocker BuildとPush
AWS Lambda関数を利用して以下を試しました:
- Terraformの
aws_lambda_invocationというLambda関数を呼び出せるリソースを使用し、ECRリポジトリ作成をトリガーにLambda関数を呼び出す。 - Lambda関数内でDocker CLIをインストールし、Docker BuildおよびPushを実行。
問題点
Lambda実行環境では、以下の制約がありました:
-
sudoが使用できない。 -
suで別ユーザーに切り替えも不可(Lambda環境ではユーザー管理が制限されている)。 - ファイルシステムが読み取り専用で、
docker loginやdocker buildが失敗。
エラー:
Command error: ERROR: mkdir /home/sbx_user1051: read-only file system
試したこと 4: GitHub Actionsの修正
最終的に、タスク定義に依存していていたGitHub Actionsのワークフローを以下のように分割しました:
- ビルドとプッシュ: イメージをECRにプッシュする専用のジョブを作成。
- サービス更新: ビルドされたイメージを利用してECSサービスを更新。
これにより、循環依存を解消できました。
まとめ
解決策を見つけるまでに想定以上の時間を要しました。当初は「簡単に実現できる方法」を優先して試行錯誤しましたが、結果的に複雑化し、最終的には根本原因に立ち返って解決しました。
教訓: 問題の根本的な解決に注力し、最初から全体設計を見直すことの重要性を再認識しました。
このブログが同様の課題に直面している方の参考になれば幸いです!
Discussion