Comment puis-je empêcher mon instance Windows Amazon EC2 de signaler CREATE_COMPLETE avant que l’instance n’ait terminé son démarrage ?

Lecture de 4 minute(s)
0

J’essaie de démarrer une instance Windows Amazon Elastic Compute Cloud (Amazon EC2) avec les scripts d’assistance cfn-init et cfn-signal dans AWS CloudFormation. Cependant, le script cfn-init renvoie un signal avant que l’instance ne termine de démarrer.

Brève description

Dans une instance Windows Amazon EC2, le processus Ec2ConfigService invoque les scripts UserData. UserData invoque ensuite cfn-init.exe, de sorte que cfn-init s’exécute en tant que processus enfant de Ec2ConfigService.

Votre instance peut renvoyer le signal CREATE_COMPLETE pour les raisons suivantes :

  • Si l’une des étapes de cfn-init.exe nécessite un redémarrage du système, ce dernier peut s’arrêter et revenir au processus Ec2ConfigService. Le système continue de traiter le script UserData, puis exécute cfn-signal.exe pour renvoyer un signal à AWS CloudFormation.
  • Le fichier cfn-signal.exe ne renvoie pas de signal après un redémarrage, car le script UserData ne s’exécute qu’une seule fois.

Dans les exemples de code suivants, cfn-signal.exe est invoqué directement à partir du script UserData. Si le processus cfn-init.exe redémarre, la commande cfn-signal.exe ne peut pas être invoquée, car le script UserData ne s’exécute qu’une seule fois.

Exemple JSON :

"UserData": {
  "Fn::Base64": {
    "Fn::Join": [
      "",
      [
        "<script>\n",
        "cfn-init.exe -v -s ",
        {
          "Ref": "AWS::StackId"
        },
        " -r WindowsInstance",
        " --configsets ascending",
        " --region ",
        {
          "Ref": "AWS::Region"
        },
        "\n",
        "cfn-signal.exe -e %ERRORLEVEL% --stack ",
        {
          "Ref": "AWS::StackId"
        },
        " --resource WindowsInstance --region ",
        {
          "Ref": "AWS::Region"
        },
        "\n",
        "</script>"
      ]
    ]
  }
}

Exemple YAML :

UserData:
  Fn::Base64: !Sub |
    <script>
    cfn-init.exe -v -s ${AWS::StackId} -r WindowsInstance --configsets ascending --region ${AWS::Region}
    cfn-signal.exe -e %ERRORLEVEL% --stack ${AWS::StackId} --resource WindowsInstance --region ${AWS::Region}
    </script>

Résolution

  1. Utilisez configsets dans la section cfn-init Metadata de votre modèle pour séparer les configurations qui nécessitent un redémarrage de celles qui n’en nécessitent pas.

  2. Déplacez cfn-signal.exe de la section UserData de la ressource AWS::EC2::Instance ou AWS::AutoScaling::LaunchConfiguration vers la section AWS::CloudFormation::Init Métadonnées du modèle.

  3. Exécutez cfn-signal.exe comme étant la dernière commande exécutée par le dernier configset.

  4. Dans votre modèle JSON ou YAML, remplacez UserData par cfn-init et spécifiez le configset croissant.
    Exemple JSON :

    {
      "AWSTemplateFormatVersion": "2010-09-09",
      "Description": "cfn-init example using configsets",
      "Parameters": {
        "AMI": {
          "Type": "AWS::EC2::Image::Id"
        }
      },
      "Resources": {
        "WindowsInstance": {
          "Type": "AWS::EC2::Instance",
          "Metadata": {
            "AWS::CloudFormation::Init": {
              "configSets": {
                "ascending": [
                  "config1",
                  "config2",
                  "config3"
                ]
              },
              "config1": {
                "files": {
                  "C:\\setup\\setenvironment.ps1": {
                    "content": {
                      "Fn::Join": [
                        "",
                        [
                          "$Folder = 'C:\\Program Files\\Server\\packages\\bin.20182.18.0826.0815\\'\n",
                          "$OldPath = [System.Environment]::GetEnvironmentVariable('path')\n",
                          "$NewPath = $OldPath + ';' + $Folder\n",
                          "[System.Environment]::SetEnvironmentVariable('path',$NewPath,'Machine')"
                        ]
                      ]
                    }
                  }
                }
              },
              "config2": {
                "commands": {
                  "0-restart": {
                    "command": "powershell.exe -Command Restart-Computer",
                    "waitAfterCompletion": "forever"
                  }
                }
              },
              "config3": {
                "commands": {
                  "01-setenvironment": {
                    "command": "powershell.exe -ExecutionPolicy Unrestricted C:\\setup\\setenvironment.ps1",
                    "waitAfterCompletion": "0"
                  },
                  "02-signal-resource": {
                    "command": {
                      "Fn::Join": [
                        "",
                        [
                          "cfn-signal.exe -e %ERRORLEVEL% --resource WindowsInstance --stack ",
                          {
                            "Ref": "AWS::StackName"
                          },
                          " --region ",
                          {
                            "Ref": "AWS::Region"
                          }
                        ]
                      ]
                    }
                  }
                }
              }
            }
          },
          "Properties": {
            "ImageId": {
              "Ref": "AMI"
            },
            "InstanceType": "t2.medium",
            "UserData": {
              "Fn::Base64": {
                "Fn::Join": [
                  "",
                  [
                    "<script>\n",
                    "cfn-init.exe -v -s ",
                    {
                      "Ref": "AWS::StackId"
                    },
                    " -r WindowsInstance",
                    " --configsets ascending",
                    " --region ",
                    {
                      "Ref": "AWS::Region"
                    },
                    "</script>"
                  ]
                ]
              }
            }
          },
          "CreationPolicy": {
            "ResourceSignal": {
              "Count": "1",
              "Timeout": "PT30M"
            }
          }
        }
      }
    }

    Exemple YAML :

    AWSTemplateFormatVersion: '2010-09-09'
    Description: cfn-init example using configsets
    Parameters:
      AMI:
        Type: 'AWS::EC2::Image::Id'
    Resources:
      WindowsInstance:
        Type: 'AWS::EC2::Instance'
        Metadata:
          AWS::CloudFormation::Init:
            configSets:
              ascending:
                - config1
                - config2
                - config3
            config1:
              files:
                C:\setup\setenvironment.ps1:
                  content: !Sub |
                    $Folder = 'C:\Program Files\Server\packages\bin.20182.18.0826.0815\'
                    $OldPath = [System.Environment]::GetEnvironmentVariable('path')
                    $NewPath = $OldPath + ';' + $Folder
                    [System.Environment]::SetEnvironmentVariable('path',$NewPath,'Machine')
            config2:
              commands:
                0-restart:
                  command: powershell.exe -Command Restart-Computer
                  waitAfterCompletion: forever
            config3:
              commands:
                01-setenvironment:
                  command: powershell.exe -ExecutionPolicy Unrestricted C:\setup\setenvironment.ps1
                  waitAfterCompletion: '0'
                02-signal-resource:
                    command: !Sub >
                      cfn-signal.exe -e %ERRORLEVEL% --resource WindowsInstance --stack ${AWS::StackName} --region ${AWS::Region}
        Properties:
          ImageId: !Ref AMI
          InstanceType: t2.medium
          UserData:
            Fn::Base64: !Sub |
              <script>
              cfn-init.exe -v -s ${AWS::StackId} -r WindowsInstance --configsets ascending --region ${AWS::Region}
              </script>
        CreationPolicy:
          ResourceSignal:
            Count: 1
            Timeout: PT30M

    Dans les modèles précédents, le signal ne s’exécute pas dans UserData. Par ailleurs, vous ne pouvez pas récupérer le code de sortie fourni par le processus cfn-init. Par défaut, CloudFormation ne parvient pas à créer ou à mettre à jour une pile sans un signal provenant de UserData ou Métadonnées. Dans ce cas, la pile renvoie une erreur « Timeout exceeded ».
    Conseil : pour résoudre les problèmes éventuels, utilisez les journaux à c:\cfn\log dans l’instance Windows.

  5. Définissez le paramètre waitAfterCompletion sur forever.
    Remarque : la valeur par défaut de waitAfterCompletion est de 60 secondes. Si vous modifiez la valeur en forever, cfn-init se ferme et ne reprend qu’une fois le redémarrage terminé.

Informations connexes

Démarrage des piles Windows AWS CloudFormation

AWS OFFICIEL
AWS OFFICIELA mis à jour il y a un an