AWS CloudFormationで循環依存エラーを解決する書き方を整理してみた
AWS CloudFormationで循環依存エラーを解決したい
おのやんです。
みなさん、AWS CloudFormation (以下、CFn) で循環依存エラーに遭遇したことはありませんか?私は何度かあります。
セキュリティグループなどのリソースでは、CFnで記述する際に自らを参照するケースが多々あります。この際、CFnの仕様によってリソースの作成が失敗する場合があります。この解消方法についていくつか試行錯誤してみたので、今回はそちらを紹介したいと思います。
循環依存によるエラーとは?
循環依存とは、1つのリソースがそれ自体に依存していること、あるいは2つのリソースが互いに依存していることを指します。
まず例として、リソースAとリソースBがお互いに依存しているケースを考えます。
テンプレートで複数のリソースを定義すると、CFnはそれらのリソースを並列に作成しようとします。ここで、リソース内のDependsOn
属性を利用することで、リソースの作成順序を制御できます。DependsOn
を使用すると、リソースBの前にリソースAを作成することが可能です。また組み込み関数Ref
などを使用して別のリソースを参照する場合にも、暗黙の依存関係が生まれます。リソースAのプロパティにリソースBへのRef
がある場合、リソースBはリソースAより先に作成されます。
この依存関係が2つのリソース間でお互いに存在している場合、どちらのリソースを最初に作成すべきかCFnが判断できなくなります。これにより、循環依存エラーが発生するというわけです。
1つのリソースがそれ自体に依存しているケース
それでは、実際に循環依存エラーが出るケースと、それに対する対処法をまとめていきたと思います。
こちらの画像のように1つのリソースの設定にそれ自身をしていている場合、CFnでは循環依存エラーになります。
CFnテンプレートの例がこちらです。あるセキュリティグループのインバウンドルールで、セキュリティグループそれ自体を許可しています。
Resources: SecurityGroupA: # Circular Dependencies! Type: AWS::EC2::SecurityGroup Properties: GroupName: security-group-a GroupDescription: security-group-a SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !GetAtt SecurityGroupA.GroupId # Circular Dependencies!
CFnの仕様を考えると、インバウンドルールが適用されるSecurityGroupA
よりも、インバウンドルールで許可する接続元のリソースSecurityGroupA
が先に作成されるはずです。しかしSecurityGroupA
が作成されようとしても、SecurityGroupA
が作成されていないのでSecurityGroupA
は作成されません (以下無限ループ) ...
このように、1つのリソースがそれ自体に依存している場合は、循環依存が発生して永遠にリソースが作成されません。こちらのようにCircular Dependencies for resource SecurityGroupA
エラーが出て作成に失敗します。
E3004: Circular Dependencies for resource SecurityGroupA. Circular dependency with [SecurityGroupA]
こちらを解決する書き方がこちらです。AWS::EC2::SecurityGroupIngress
を別途追加し、そこにルールを記述しています。
Resources: SecurityGroupA: Type: AWS::EC2::SecurityGroup Properties: GroupName: security-group-a GroupDescription: security-group-a SecurityGroupAIngress: # インバウンドルールを外に出す Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref SecurityGroupA IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !GetAtt SecurityGroupA.GroupId
この書き方で記述すれば、SecurityGroupA
が作成された後に、SecurityGroupA
に依存しているSecurityGroupAIngress
が作成されます。循環依存も発生せずに、正常にリソースが作成されます。
2つのリソースが互いに依存しているケース
こちらの画像のように2つのリソースの設定にお互いを指定している場合、CFnでは循環依存としてエラーになります。
CFnテンプレートの例がこちらです。SecurityGroupA
のルールにてSecurityGroupB
からのアクセスを許可しています。同時に、SecurityGroupB
のルールにてSecurityGroupA
からのアクセスを許可しています
Resources: SecurityGroupA: Type: AWS::EC2::SecurityGroup Properties: GroupName: security-group-a GroupDescription: security-group-a SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !GetAtt SecurityGroupB.GroupId # Circular Dependencies! SecurityGroupB: Type: AWS::EC2::SecurityGroup Properties: GroupName: security-group-b GroupDescription: security-group-b SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !GetAtt SecurityGroupA.GroupId # Circular Dependencies!
SecurityGroupA・B
の間で双方向の暗黙的な依存関係が生まれています。そのため、どちらを先に作成するべきかCFnが判断できなくなります。結果、Circular Dependencies for resource SecurityGroupX
の循環依存エラーとなります。
E3004: Circular Dependencies for resource SecurityGroupA. Circular dependency with [SecurityGroupB] E3004: Circular Dependencies for resource SecurityGroupB. Circular dependency with [SecurityGroupA]
こちらも同様の書き方で修正できます。AWS::EC2::SecurityGroupIngress
を外に出して記述することで、循環依存を断ち切っています。
Resources: SecurityGroupA: Type: AWS::EC2::SecurityGroup Properties: GroupName: security-group-a GroupDescription: security-group-a SecurityGroupB: Type: AWS::EC2::SecurityGroup Properties: GroupName: security-group-b GroupDescription: security-group-b SecurityGroupAIngress: # インバウンドルールを外に出す Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref SecurityGroupA IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !GetAtt SecurityGroupB.GroupId SecurityGroupBIngress: # インバウンドルールを外に出す Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref SecurityGroupB IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !GetAtt SecurityGroupA.GroupId
この場合、何にも依存していないSecurityGroupB
が先に作成されます。その後に、SecurityGroupB
に依存しているSecurityGroupA
が作成されます。
循環依存エラーは、依存関係を断ち切ることで解決できる
セキュリティグループを作っているときあるあるのネタですが、意外と情報が少なかったのでまとめてみました。
AWSの公式ブログにも循環依存エラーについて紹介されていますので、参考になれば幸いです。
では!