我在 Amazon CloudFormation 模板中有多个实例,并尝试通过 UserData 将它们连接在一起,即互相告知对方机器的 IP 地址。
该模板看起来像这样:
"Instance1" : {
"Type" : "AWS::EC2::Instance",
...
"UserData" : {
"Fn::Base64" : {
"Fn::Join" : [ "\n", [
{ "Fn::Join" : [ "=", [ "Instance2", { "Fn::GetAtt" : [ "Instance2" , "PrivateIp"] } ] ] }
] ]
} }
}
},
"Instance2" : {
"Type" : "AWS::EC2::Instance",
...
"UserData" : {
"Fn::Base64" : {
"Fn::Join" : [ "\n", [
{ "Fn::Join" : [ "=", [ "Instance1", { "Fn::GetAtt" : [ "Instance1" , "PrivateIp"] } ] ] }
] ]
} }
}
},
Amazon CloudFormation 拒绝处理此 CloudFormation 并报告它无法处理两个实例之间的循环依赖关系。
有没有办法解决这个问题,而不必自己构建任何东西。例如,我希望两个实例上的 UserData 都反映另一台机器的 IP 地址,而无需事后手动更改 UserData。
答案1
我实际上找到了一种通过使用 ElasticIPs 单独使用 Cloud Formation 模板来实现此目的的方法。
我创建了一个 ElasticIP(在这种情况下您不能直接将其分配给实例!)
"ServerEIP" : {
"Type" : "AWS::EC2::EIP",
"Properties" : {
}
},
然后我在 UserData 中引用该 IP
"Client" : {
...
"UserData" : {
{ "Fn::Join" : [ "=", [ "Server", { "Ref" : "ServerEIP" } ] ] }
服务器可以直接引用客户端
"Server" : {
"Type" : "AWS::EC2::Instance",
...
"UserData" : {
...
{ "Fn::Join" : [ "=", [ "Client", { "Fn::GetAtt" : [ "Client" , "PrivateIp"] } ] ] },
稍后我将 Elastic 与实际服务器关联起来,以使 Cloud Formation 正确处理依赖关系:
"ServerIPAssoc" : {
"Type" : "AWS::EC2::EIPAssociation",
"Properties" : {
"InstanceId" : { "Ref" : "Server" },
"EIP" : { "Ref" : "ServerEIP" }
}
},
完成!我现在有两个知道另一个节点的 IP 地址的实例。
唯一的缺点是,现在的流量是通过公共 IP 地址进行的,因此会产生流量成本并且可能不太安全。
更新:我现在遇到了所描述的问题这里,不确定我是否可以在这里解决这个问题。
答案2
您可以实现您的高级目标,但不能满足您列出的限制(即,在两个实例中都包含用户数据中的原始 IP 地址)。原因很简单:
必须在实例启动之前指定用户数据。
实例启动后才知道 IP 地址。
CloudFormation 可以启动一个实例并将其 IP 地址提供给第二个实例,但不能同时提供两者(循环依赖)。
您可以使用多种方法和技术来解决这种双向沟通问题。从高层次来看:
您可以将 A 的 IP 地址传递给 B,然后让 B 联系 A 并让其知道它的 IP 地址是什么(注意安全)。
您可以将每个实例的 IP 地址存储在外部存储(例如,Route53、SimpleDB)中,然后每个实例在启动时查询该外部存储以找到其伙伴。
推荐
这是一种可与 CloudFormation 和可靠的 AWS 服务一起使用的简单方法:
在 Route53 中设置一个域(托管区域)。这可能与您当前使用的任何公共域完全不同,但是如果您已经在使用 Route53,则可以将此功能插入同一域中。
在您的 CloudFormation 模板中,为每个实例生成一个唯一的名称,可能基于当前的 CloudFormation 堆栈名称(例如,“MYSTACK-server-a.example.com”和“MYSTACK-server-b.example.com”)
在 CloudFormation 模板中,将实例名称传递到每个服务器各自的用户数据中。
向您的 CloudFormation 模板添加指令,将这些新的 DNS 名称(记录集)注入 Route53,将它们映射到实例的 IP 地址。
CloudFormation 将启动实例,并传入用户数据。当为实例分配 IP 地址后,CloudFormation 会将它们映射到 Route53 DNS 中的主机名。然后,您的实例可以使用主机名相互查找。
如果您的实例需要在启动时找到其合作伙伴,则它们将需要持续轮询 DNS,直到合作伙伴进入运行状态并被分配 IP 地址。请谨慎使用缓存 DNS“未命中”的软件。