# Step Functions で EC2 インスタンスを立ち上げる


published: 2025-08-17

インスタンスを立ち上げて開発することがたまにあるのですが、
その立ち上げを自動化したく、Step Functions に処理をまとめました。

雑記としてステートマシンの ASL を載せます。


## 構成

Step Functions で EC2 インスタンスを立ち上げます。
そして Systems Manager 経由でコマンドを実行し、インスタンスをセットアップします。


![architecture.png](https://lab.enuesaa.dev/prototype/aws-ec2-instance-setup-with-stepfunctions/architecture.png)

インスタンスのセットアップが完了したら、SNS で通知します。
10分待機している間に ssh して、必要な処理をするイメージです。


## コード

### `stepfunctions.asl.json`

```json
{
  "QueryLanguage": "JSONata",
  "StartAt": "StartEC2Instance",
  "States": {
    "StartEC2Instance": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:ec2:runInstances",
      "Arguments": {
        "ImageId": "<AMIID>",
        "InstanceType": "<InstanceType>",
        "MinCount": 1,
        "MaxCount": 1,
        "SecurityGroupIds": [
          "<SecurityGroupId>"
        ],
        "SubnetId": "<SubnetID>",
        "IamInstanceProfile": {
          "Name": "<InstanceProfileName>"
        },
        "TagSpecifications": [
          {
            "ResourceType": "instance",
            "Tags": [
              {
                "Key": "Name",
                "Value": "dev"
              }
            ]
          }
        ]
      },
      "Assign": {
        "instanceId": "{% $states.result.Instances[0].InstanceId %}"
      },
      "Next": "WaitEC2InstanceStartUp"
    },
    "WaitEC2InstanceStartUp": {
      "Type": "Wait",
      "Seconds": 60,
      "Next": "RunCommand"
    },
    "RunCommand": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:ssm:sendCommand",
      "Arguments": {
        "DocumentName": "AWS-RunShellScript",
        "InstanceIds": "{% [$instanceId] %}",
        "Parameters": {
          "commands": [
            "apt update",
            "apt install -y git"
          ]
        }
      },
      "Assign": {
        "commandId": "{% $states.result.Command.CommandId %}"
      },
      "Next": "WaitCommand"
    },
    "WaitCommand": {
      "Type": "Wait",
      "Next": "GetCommandStatus",
      "Seconds": 30
    },
    "GetCommandStatus": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:ssm:getCommandInvocation",
      "Arguments": {
        "CommandId": "{% $commandId %}",
        "InstanceId": "{% $instanceId %}"
      },
      "Next": "CheckCommandStatus"
    },
    "CheckCommandStatus": {
      "Type": "Choice",
      "Choices": [
        {
          "Next": "WaitCommand",
          "Condition": "{% $states.input.Status = \"InProgress\" %}",
          "Comment": "InProgress"
        },
        {
          "Next": "TerminateInstance",
          "Condition": "{% $states.input.Status = \"Failed\" %}",
          "Comment": "Failed"
        }
      ],
      "Default": "Notify"
    },
    "Notify": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sns:publish",
      "Arguments": {
        "TopicArn": "<SNSTopicArn>",
        "Message": {
          "message": "EC2インスタンスが立ち上がりました"
        }
      },
      "Next": "Wait10minutes"
    },
    "Wait10minutes": {
      "Type": "Wait",
      "Seconds": 600,
      "Next": "TerminateInstance"
    },
    "TerminateInstance": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:ec2:terminateInstances",
      "Arguments": {
        "InstanceIds": "{% [$instanceId] %}"
      },
      "End": true
    }
  }
}

```

### memos

AMI の ID へ置き換えます
例: ami-xxx


mark: `stepfunctions.asl.json:9`

インスタンスタイプを埋めます
例: t4g.small


mark: `stepfunctions.asl.json:10`

Security Group の ID へ置き換えます
例: sg-xxx


mark: `stepfunctions.asl.json:14`

Subnet の ID へ置き換えます
例: subnet-xxx


mark: `stepfunctions.asl.json:16`

Instance Profile の名前へ置き換えます

なお Systems Manager でコマンドを実行するには、
AmazonSSMManagedInstanceCore ポリシーが必要です


mark: `stepfunctions.asl.json:18`

- [AmazonSSMManagedInstanceCore](https://docs.aws.amazon.com/ja_jp/aws-managed-policy/latest/reference/AmazonSSMManagedInstanceCore.html)
EC2 インスタンスの名前です

mark: `stepfunctions.asl.json:26`

通知先の SNS トピックの ARN を埋めます

mark: `stepfunctions.asl.json:94`

## おわり


EC2 インスタンスをセットアップするだけであれば、
例えばユーザーデータでシェルスクリプトを実行したり、AMI を取得したほうが手軽です。

私の場合は、インスタンスの起動・終了まで制御したかったので、Step Functions に寄せちゃいました。


