CloudFormation GUI Переопределение параметра - PullRequest
0 голосов
/ 13 июля 2020

У меня есть шаблон CloudFormation с 2 параметрами. Один для имени EC2 и второй для URL-адреса. UserData скручивает необходимый URL-адрес на EC2 после того, как он раскручивается. Этот URL изменяется в зависимости от потребностей пользователя. Я добавил теги, чтобы убедиться, что CloudFormation улавливает изменения. Когда делаю обновление через GUI, оба тега обновляются. Однако URL-адрес в curl UserData - нет. Я пытаюсь создать инструкции, как обновить этот шаблон через CloudFormation GUI. Можно ли переопределить параметр в разделе UserData для параметра URL через GUI? Вот фрагмент моего шаблона CloudFormation.

{
"Parameters":{
    "ArtifactURL" : {
        "Type" : "String",
        "Default" : "https://stuff.war",
        "Description": "Enter the Artifact's URL to be installed on this EC2.  Default is the latest stuff"
    },
    "EC2Name" : {
        "Type" : "String",
        "Default" : "MyCloudFormationInstance"
    }
},
"Resources" : {
    "MyCloudFormationInstance" : {
        "Type" : "AWS::EC2::Instance",
        "Properties" : {
            "AvailabilityZone" : "...",
            "ImageId" : "...",
            "SecurityGroupIds" :[ "..." ],
            "KeyName" : "...",
            "Tags" : [
                {
                    "Key" : "Name",
                    "Value" : { "Ref": "EC2Name"}
                },
                {
                    "Key" : "Url",
                    "Value" : { "Ref": "ArtifactURL"}
                }
            ],
            "IamInstanceProfile" : "...",
            "InstanceType" : "t2.micro",
            "UserData" : {"Fn::Base64": {"Fn::Join" : ["", [
                "#!/bin/bash","\n",
                "warlink=\"", { "Ref": "ArtifactURL" },"\"\n",
                "echo \"warlink: $warlink\" > myFile.txt","\n",
                "\n","curl \"$warlink\" -O","\n",

Ответы [ 2 ]

1 голос
/ 13 июля 2020

Я собираюсь сделать некоторые предположения здесь:

  • Я предполагаю, что ваша цель состоит в том, чтобы обновление параметра CloudFormation ArtifactURL заставило экземпляр загрузить новый URL;
  • Кроме того, я предполагаю, что вы не напрямую проверяли, были ли обновлены UserData или нет, но вы косвенно подтвердили это, заметив, что новый URL-адрес не был Не скачал и подумал, что причина в том, что UserData не обновлялась.

Если эти предположения неверны, пожалуйста, поясните в вопросе, какова ваша конечная цель и что именно вы наблюдали.

ArtifactURL в скрипте UserData, скорее всего, обновляется - именно так должен работать CloudFormation. Вы, вероятно, заметили, что новый URL-адрес не загружается , что совсем другое и ожидаемое.

Экземпляры EC2 поддерживают изменение своих UserData, и CloudFormation поддерживает внесение этого изменения. Однако по умолчанию в большинстве AMI ОС (и, в частности, пакет cloud-init) настроена только на запуск сценария UserData once-per-instance (вместо once-per-boot).

Это означает, что по умолчанию изменения, внесенные в сценарий UserData, не будут выполняться .

Если посмотрите документацию CloudFormation для типа ресурса AWS::EC2::Instance, вы увидите, что оба свойства Tags и UserData могут быть обновлены без замены . В частности, Tags обновляется без каких-либо прерываний, а UserData обновляется с помощью цикла Stop -> Start . Когда экземпляр перезагружается, пакет cloud-init проверяет, что он уже выполнил UserData для этого экземпляра один раз, поэтому он не выполняет его снова - независимо от того, что он был изменен.

Итак, вам нужно запускать повторное выполнение UserData при его изменении.

Есть множество способов сделать это возможным. Поскольку вы используете CloudFormation, я бы посоветовал вам использовать cfn-hup:

Помощник cfn-hup - это демон, который обнаруживает изменения в метаданных ресурсов и запускает указанные пользователем действия при обнаружении изменения.

Этот инструмент был специально разработан для обнаружения изменений в UserData и их повторного запуска. На странице документации по ссылкам есть пример, и вы также найдете множество других примеров, выполнив поиск по cfn-hup.

В заключение, есть несколько других способов достижения той же цели ( повторное выполнение сценариев UserData, если они были изменены, или при каждой загрузке и т. д. c). Еще один хороший вариант - узнать больше о cloud-init и изменить его конфигурацию. Всегда убедитесь, что вариант, о котором вы читаете, задокументирован и поддерживается инфраструктурой или программным обеспечением, которое вы используете (например, вы найдете множество мест, предлагающих удалить файл блокировки для принудительного повторного выполнения UserData, но это плохой совет).

0 голосов
/ 15 июля 2020

Вот отредактированный окончательный код

    {
"Parameters":{
    "ArtifactURL" : {
        "Type" : "String",
        "Default" : "https://stuff.war",
        "Description": "Enter the Artifact's URL"
    },
    "EC2Name" : {
        "Type" : "String",
        "Default" : "MyCloudFormationInstance"
    }
},
"Resources" : {
    "WaitHandle" : { 
        "Type" : "AWS::CloudFormation::WaitConditionHandle"
     },
    "MyCloudFormationInstance" : {
        "Type" : "AWS::EC2::Instance",
        "Metadata" : {
            "ArtifactURL": { "Ref": "ArtifactURL"},
            "AWS::CloudFormation::Init" : {
                "configSets": {
                    "myconfigs" : ["config-cfn-hup","install-artifact"]
                },
                "install-artifact" : {
                    "commands": {
                        "1-run-script" : {
                            "command" : { "Fn::Join" : [ "", [
                                "/bin/bash /etc/downloadandinstallfile.sh"
                            ]]}
                        }
                    }
                },
                "config-cfn-hup" : {
                    "files" : {
                        "/etc/downloadandinstallfile.sh" : {
                            "content" : { "Fn::Join" : ["", [
                                "#!/bin/bash","\n",
                                "warlink=\"", { "Ref": "ArtifactURL" },"\"\n",
                                "echo \"warlink: $warlink\" > myFile.txt","\n",
                                "\n","curl \"$warlink\" -O","\n"]]},
                            "mode" : "000777",
                            "owner" : "root",
                            "group" : "root"
                        },
                        "/etc/cfn/cfn-hup.conf" : {
                            "content" : { "Fn::Join" : ["", [
                                "[main]\n",
                                "stack=", { "Ref" : "AWS::StackId" }, "\n",
                                "region=", { "Ref" : "AWS::Region" }, "\n",
                                "interval=1\n"
                            ]]},
                            "mode"  : "000400",
                            "owner" : "root",
                            "group" : "root"
                        },
                        "/etc/cfn/hooks.d/cfn-auto-reloader.conf" : {
                            "content" : { "Fn::Join" : ["", [
                                "[cfn-auto-reloader-hook]\n",
                                "triggers=post.update\n",
                                "path=Resources.MyCloudFormationInstance.Metadata.AWS::CloudFormation::Init\n",
                                "action=cfn-init -v --configsets myconfigs --stack ", { "Ref" : "AWS::StackId" }, " --resource MyCloudFormationInstance ", " --region ", { "Ref" : "AWS::Region"},"\n",
                                "runas=root\n"
                            ]]}
                        },
                        "/etc/systemd/system/cfn-hup.service" : {
                            "content" : { "Fn::Join" : ["", [
                                "[Unit]\n",
                                "Description=CloudFormation helper daemon\n",
                                "\n",
                                "[Service]\n",
                                "ExecStart=/bin/cfn-hup\n",
                                "Restart=always\n",
                                "Type=simple\n",
                                "\n",
                                "[Install]\n",
                                "WantedBy=multi-user.target"
                            ]]}
                        }
                    },
                    "commands" : {
                        "01-install-set" : {
                            "command" : { "Fn::Join" : [ "", [
                                "set -xe\n"
                            ]]}
                        },
                        "02-daemon-reload" : {
                            "command" : { "Fn::Join" : [ "", [
                                "systemctl daemon-reload"
                            ]]}
                        },
                        "03-enable-service" : {
                            "command" : { "Fn::Join" : [ "", [
                                "systemctl enable cfn-hup.service\n"
                            ]]}
                        },
                        "04-start-service" : {
                            "command" : { "Fn::Join" : [ "", [
                                "service cfn-hup.service start\n"
                            ]]}
                        }
                    }
                }
            }
        },
        "Properties" : {
            "AvailabilityZone" : "xxxxxxxx",
            "ImageId" : "xxxxxxxxxx",
            "SecurityGroupIds" :[ "xxxxxxx" ],
            "KeyName" : "xxx.pem",
            "Tags" : [
                {
                    "Key" : "Name",
                    "Value" : { "Ref": "EC2Name"}
                },
                {
                    "Key" : "Url",
                    "Value" : { "Ref": "NexusArtifactURL"}
                }
            ],
            "IamInstanceProfile" : "ec2LoggingRole",
            "InstanceType" : "t2.micro",
            "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
                "#!/bin/bash -v\n",
                "# Function to return error code to the wait handle\n",
                "function handle_error\n",
                "{\n",
                " cfn-signal -e 1 -r \"$1\" '", { "Ref" : "WaitHandle"}, "'\n",
                " exit 1\n",
                "}\n",

                "yum update -y \n",
                "pip3 install pystache\n",
                "pip3 install argparse\n",
                "pip3 install python-daemon\n",
                "pip3 install requests\n",
                "curl -sSL https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz -O\n",
                "# tar -xpf aws-cfn-bootstrap-latest.tar.gz -C /opt\n",
                "# cd /opt/aws-cfn-bootstrap-1.4/\n",
                "# sudo python setup.py build\n",
                "# sudo python setup.py install\n",
                "easy_install aws-cfn-bootstrap-latest.tar.gz\n",
                "#ln -s /usr/init/redhat/cfn-hup /etc/init.d/cfn-hup\n",
                "#chmod 775 /usr/init/redhat/cfn-hup\n",
                "#cd /opt\n",
                "#mkdir aws\n",
                "#cd aws\n",
                "#mkdir bin\n",
                "#ln -s /usr/bin/cfn-hup /opt/aws/bin/cfn-hup\n",
                
                "sudo cfn-init -v -c myconfigs -s ", { "Ref" : "AWS::StackId" }, " -r MyCloudFormationInstance ", " --region ", { "Ref" : "AWS::Region" }, " || handle_error 'Failed to run cfn-init'\n",

                "# Return success\n",

                "cfn-signal -e 0 -r \"Stack Complete\" '", { "Ref" : "WaitHandle" }, "'\n"
                ]]}
            }
        }
    }
},
"Outputs":{
    "InstanceID" : {
        "Description" : "The Instance ID",
        "Value": { "Ref" : "MyCloudFormationInstance" }
    },
    "PublicIp" : {
        "Description" : "Instance's Public Ip",
        "Value" : { "Fn::GetAtt" : [ "MyCloudFormationInstance", "PublicIp"]}
    },
    "SSHLogin" : {
        "Description" : "SSH command to log into your instance",
        "Value" : {"Fn::Join" : ["", ["ssh -i \"xxx.pem\" ec2-user@", {"Fn::GetAtt": ["MyCloudFormationInstance","PublicDnsName"]}]]}
    }
}}
...