这可能会有点复杂,但我会尽量简化。
我有一个CloudFormation模板,它设置了3个相同的EC2机器,在UserData脚本中使用cfn-init ,它从S3 cfn-init一些自动化代码,并运行它来将这些机器设置为产品特定的高可用性configuration这里有关。
它看起来像这样:
"commands" : { "0-Tester" : { "command" : "echo \"I am OK.\" > \"d:\\test.txt\"", "waitAfterCompletion": 5 }, "1-Pullcode" : { "command" : "aws s3 cp s3://some-bucket/code.zip d:/code.zip > d:/s3sync.log", "waitAfterCompletion": 5 }, "2-UnpackCode" : { "command" : "powershell Expand-Archive -Path d:\\code.zip -DestinationPath d:\\dev", "waitAfterCompletion": 5 }, "3-ResetLicensing" : { "command" : "\"C:/Program Files/something/iisnodeModule/node.exe\" d:/dev/aws-automation/service.js --service Licensing.Service --action restart > d:/oxy_restart.log", "waitAfterCompletion": 5 }, "4-RunAutomation" : { "command" : "\"C:/Program Files/something/iisnodeModule/node.exe\" d:/dev/aws-automation/automate.js --config c:/servers.conf --all > d:/automation.log", "waitAfterCompletion": 5 } }
为了实现这种自动化,每台计算机都需要知道所有3台计算机的IP或DNS名称(例如,考虑创build一个mongodb副本集),并实现这个模板,在Route53为这些EC2创build3个DNSlogging(在私有托pipe区域),并在每个EC2实例的文件中生成这3个可预测的DNS名称。
发生这样的事情:
"config": { "files": { "c:\\servers.conf": { "content": { "role": "app", "servers": [ {"Fn::Join": [".",["build1",{"Ref": "AWS::StackName"},{"Ref": "HostedZone"}]]}, {"Fn::Join": [".",["app1",{"Ref": "AWS::StackName"},{"Ref": "HostedZone"}]]}, {"Fn::Join": [".",["app2",{"Ref": "AWS::StackName"},{"Ref": "HostedZone"}]]} ], "replSetName": { "Ref": "ReplicaSetName" }, "ecFolder": { "Ref": "ElasticubeFolder" } } } },
而且当然
"DNSRecordBuild1": { "Type": "AWS::Route53::RecordSet", "Properties": { "HostedZoneName": {"Ref": "HostedZone"}, "Name": { "Fn::Join": [".",["build1",{"Ref": "AWS::StackName"},{"Ref": "HostedZone"}]] }, "Type": "A", "TTL": "900", "ResourceRecords": [{"Fn::GetAtt": ["build1","PrivateIp"]}] } }
创buildDNSlogging。
所以在这一点上,堆栈被完美地创buildCFN旋转了3个实例,使用最终将存在的DNS名称在每个实例上呈现configurationjson ,从S3拉取代码,并开始运行脚本。 现在R53logging显然依赖于这些实例,但是只要实例准备就绪,即在脚本开始运行之前就创build它们 – 因此在脚本引用所述DNS名称的时候,它们已经存在于R53 。 这个设置工作正常。
现在,我想添加一个ELB到堆栈,并且我希望只在3台机器完全configuration好并且可以通信时才能创build。 所以我已经为ELB资源添加了一个DependsOn属性,这个属性工作正常,然后将cfn-signal和CreationPolicy添加到每个实例,以确保只有在自动化脚本完成时才标记为已完成:
"cfn-signal.exe -e %ERRORLEVEL% --stack ", { "Ref" : "AWS::StackName" }, " --resource build1 --region ", { "Ref" : "AWS::Region" }
和
"CreationPolicy" : { "ResourceSignal" : { "Timeout" : "PT10M" } }
但是,这立刻破坏了整个过程 – 因为现在R53logging在机器发送signal之前不会被创build – 而机器将不会发送它,因为它试图运行依赖这些DNS名称的脚本,从而失败。
现在我只是删除了signal和policy ,让ELB在实例联机后立即启动,但这并不理想。 所以问题是: 在完成脚本之后,如何延迟ELB的创build,而不延迟R53资源或创build如上所述的依赖循环?
目前我的想法是:
wait资源到模板,发信号给它,并有ELB资源DependsOn这个wait – 不知道这甚至是可能的,或者它可能有什么副作用 CFN创buildELB ,而是通过其中一台机器上的AWS CLI创build,可以validation所有其他机器已准备就绪。 真的不喜欢这种方法,因为它需要我的自动化脚本中有很多额外的代码,并且使这个资源更难pipe理(即,当删除堆栈时需要手动删除ELB) lambda对它做出反应并创buildELB,但这与#2有相同的缺点。 如何从完全不同的angular度攻击它,并在创build所有资源(即3x EC2,DNS和ELB)后使用AWS EC2 System Manager(SSM)configuration实例?
SSM将取决于所有上述的创build,然后login到每个实例,并启动应用程序。 这应该解决依赖问题。
查看AWS :: SSM :: Association和AWS :: SSM :: Document ,了解EC2 Systems Manager的CloudFormation支持。
希望帮助:)