ご無沙汰しております。クラウドソリューション事業部の本田です。
前回から随分と間が空いてしまいました。その間子供が産まれまして育休を取ったりしてました。
復帰後第一弾ということで、今回は弊社の事業で行っている保守運用で実際にあったトラブルシューティグを題材にしたいと思います。
発生した事象
とある環境でAmazon ECSを使ってアプリを運用していますが、ある日突然以下のエラーでタスクの起動が行えなくなってしまいました。
1CannotPullContainerError: pull image manifest has been retried 1 time(s): failed to resolve ref xxxxxx: not found
ヘルスチェックに失敗してタスクが停止しており、起動台数の設定をしているので自動で起動されるはずなのですが、上記エラーによって起動できない状態になっていました。
前提
運用している環境の要件などを明記しておきます。
- AmazonECSで複数のクラスターがある
- クラスター内で複数のサービスを作成している
- 運用上の要件として、複数のサービスで同じイメージを使いたい
- 本番環境と同じイメージを使って別の環境でサービスを立ち上げておきたい
- タグのないイメージはライフサイクルポリシーで消える
- CI/CDはAWS CodePipelineで行っていて、変更がプッシュされるとAWS CodeBuildでイメージを作成、Amazon ECRへプッシュ、Amazon ECSにてデプロイ実行
結論
下記に調査していったステップを書いていくのですが、忙しい人向けに結論を先に書いておきます。
- 同じイメージを使うため同じタグのイメージを複数回プッシュしていた
- AWS CodePipelineは複数あり環境毎でビルド、プッシュが行われていた
- ソースコードの変更に合わせて実行されていたので同タイミングで処理が走る
- 同じタグのイメージをプッシュした場合に競合してしまって意図せずタグが取れていた
- タグのないイメージがライフサイクルポリシーで消えてしまっていたためイメージが存在しないというエラーが発生していた
同じイメージを使いたいという要件を満たすために、同じタグを使って複数イメージをプッシュしていたことで意図せずタグがついていないイメージとなってしまっていて、削除されてしまっていました。
対応
幸い元々複数台のタスクが実行していたので、サービスが運用できなくなるなどの障害は起きませんでしたが以下のような対応を行って事象を解決しています。
一時対応
再度AWS CodePipelineを実行してイメージを作り直すことでイメージが存在しないという状況は解消、ただしこの時点ではタグのないイメージができてしまっています。
恒久対応
同じイメージを使うという要件は満たせるように環境に合わせてタグを変えるようにして、タグのないイメージが作成されてしまうという事象も解消して、恒久対応を行いました。
なぜ運用開始前に気づけなかったか
この環境ですが、運用を開始してから1年以上は経っているので途中で何か変更を加えたわけでもありませんので構築時から今回の事象が発生するリスクは潜んでいた訳です。気づけなかった理由としては以下が挙げられます。
- ライフサイクルポリシーで対象イメージが消えてからタスクが停止するという事象がほぼなかった
タスク自体が何らかの理由で停止しているということが運用を開始してからほぼほぼなく安定して稼働をしていました、また停止をしてもイメージがライフサイクルポリシーで消える前であって正常に起動することができていたようだった。今回ライフサイクルポリシーで消えてしまう、何らかの理由で停止するというタイミングが重なったことで初めて発生した。
一見問題なく稼働しているサービスでも、今回のような事象が発生するリスクが潜んでいることは勉強になりました。運用前のテストで気づくことができたかは微妙でありますが、作成されるイメージがどうなっているか、と言うのは今後チェックしていく点かと思います。
原因究明のステップ
先に結論を書いてしまいましたが、問題発生時は以下のようなステップで調査を行いました。やはりこういう時はAWS CloudTrailですね。
調査ステップ1 -該当のイメージは存在するのか?-
タスク起動時に以下のような形で、イメージを参照していました。
1AWSアカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/リポジトリ名:タグ名@sha256:xxxxxxxxx
AWSアカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/リポジトリ名:タグ名
ここまでだと、イメージは存在しているのですが、@sha256以降のダイジェストで見ると該当のイメージは存在していないことがわかりました。
調査ステップ2 -どのタイミングで消えた?—
次に該当のイメージがどのタイミングで消されてしまったかをAWS CloudTrailから探ります。今回ライフサイクルポリシーが設定されているので、意図的に手で消さない限りはそちらで消えますので、イベント名をPolicyExecutionEventとして、検索してみます。
ログを検索していると、該当のイメージがライフサイクルポリシーで消えてしまっていることを確認できました。ここで出てこないとなると、何か別の要因で消えてしまっている可能性があります。
調査ステップ3 -なぜ消える対象になっていたのか?-
次になぜ消える対象になっていたかをAWS CloudTrailから探ります。
一時対応として行ったAWS CodePipelineによって、タグのついているイメージとついていないイメージができていたので、そちらのログをAWS CloudTrailで確認します。
今回はイベント名を PutImageで探します。同じタイミングで2回分のPutImageが走っていて、それぞれ同じタグでプッシュされていることが確認できました。
こちらの結果とbuildspec.ymlを照らし合わせ、同じタグでプッシュしていることが原因でタグがないイメージができてしまっていることを究明しました。
最後に
途中で書きましたが一見安定して稼働しているシステムでも、実は問題が起きていないだけで色んなタイミングが重なると今回のような事象が発生するリスクが潜んでいたりします。何かしらアラートを仕込んでいくことも一つですが、定期的に見直しをしていくのもいいですね。
弊社ではそういったシステムの見直し、または保守運用のご相談なども大歓迎ですのでお困りの方は是非お声がけくださいませ。