You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让AWS::CloudFormation::Init在堆栈更新时重新执行?

解决AWS CloudFormation Init更新不生效的问题:区分初始化与更新操作

这个问题我帮不少开发者踩过坑——本质是AWS::CloudFormation::Init的默认逻辑就是仅在EC2实例首次启动时执行初始化动作,堆栈更新时除非你主动触发,否则不会自动重新应用变更。下面给你几个分场景的实用方案,从简单到进阶都有:

方案1:用ConfigSet区分初始化与更新任务

你可以在Metadata里定义两组配置集(ConfigSet),一组仅在首次运行时执行,另一组用于堆栈更新时触发,再通过实例内的标记文件判断执行逻辑。

模板配置示例

Resources:
  MyEC2Instance:
    Type: AWS::EC2::Instance
    Metadata:
      AWS::CloudFormation::Init:
        configSets:
          # 首次启动执行的配置序列
          initial:
            - initial_config
            - mark_initial_done
          # 堆栈更新时执行的配置序列
          update:
            - update_config
        initial_config:
          files:
            /etc/initial_config.conf:
              content: "首次初始化配置"
              mode: '0644'
          commands:
            01_first_run_only:
              command: echo "首次执行日志" >> /var/log/initial.log
        mark_initial_done:
          commands:
            01_create_marker:
              command: touch /var/lib/cloud/instance/initial_run_completed
        update_config:
          files:
            /etc/updated_config.conf:
              content: "更新后的配置内容"
              mode: '0644'
          commands:
            01_run_on_update:
              command: echo "堆栈更新执行日志:$(date)" >> /var/log/update.log
    Properties:
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          INIT_MARKER="/var/lib/cloud/instance/initial_run_completed"
          if [ -f $INIT_MARKER ]; then
            # 已完成首次初始化,执行更新配置
            /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource MyEC2Instance --region ${AWS::Region} --configset update
          else
            # 首次启动,执行初始化配置
            /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource MyEC2Instance --region ${AWS::Region} --configset initial
          fi
          # 向CloudFormation发送执行完成信号
          /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource MyEC2Instance --region ${AWS::Region}

工作逻辑

  • 首次启动:执行initial配置集,生成标记文件;
  • 堆栈更新时:只要触发实例重新运行UserData(比如修改UserData内容、重启实例),就会检测到标记文件,执行update配置集。

方案2:用cfn-hup自动检测配置变更

cfn-hup是CloudFormation官方提供的守护进程,会定期检测实例元数据的变化,自动触发cfn-init更新配置,无需手动重启实例。

配置步骤

  1. 在UserData中安装并配置cfn-hup:
#!/bin/bash
# 安装cfn-bootstrap工具
yum install -y aws-cfn-bootstrap

# 配置cfn-hup的堆栈信息
cat > /etc/cfn/cfn-hup.conf <<EOF
[main]
stack=${AWS::StackName}
region=${AWS::Region}
EOF

# 设置钩子:当Init配置变更时,自动执行更新配置集
cat > /etc/cfn/hooks.d/cfn-auto-reloader.conf <<EOF
[cfn-auto-reloader-hook]
triggers=post.update
path=Resources.MyEC2Instance.Metadata.AWS::CloudFormation::Init
action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource MyEC2Instance --region ${AWS::Region} --configset update
runas=root
EOF

# 启动并开机自启cfn-hup
service cfn-hup start
chkconfig cfn-hup on
  1. 对应模板的Metadata里,保留initial和update配置集(同方案1)。

优势

  • 完全自动化:修改Init配置后,cfn-hup会在几分钟内自动检测到变更并执行更新;
  • 无需重启实例:在现有实例上直接应用配置,适合不能中断服务的场景。

方案3:Auto Scaling组滚动更新(适合集群场景)

如果你的EC2实例属于Auto Scaling Group(ASG),可以通过UpdatePolicy让CloudFormation自动滚动替换实例,新实例会应用最新的Init配置。

模板示例

MyASG:
  Type: AWS::AutoScaling::AutoScalingGroup
  Properties:
    LaunchConfigurationName: !Ref MyLaunchConfig
    MinSize: 2
    MaxSize: 3
  UpdatePolicy:
    AutoScalingRollingUpdate:
      MinInstancesInService: 1 # 滚动更新时保留的最小可用实例数
      MaxBatchSize: 1 # 每次替换的实例数
      PauseTime: PT5M # 等待实例初始化的时间
      WaitOnResourceSignals: true # 等待实例发送cfn-signal信号

适用场景

  • 允许短暂替换实例的集群场景;
  • 适合配置变更需要完全重建实例生效的情况(比如依赖系统级初始化的配置)。

方案4:自定义Lambda+SSM RunCommand(复杂场景)

对于需要精确控制更新流程的场景,你可以:

  1. 在堆栈更新时触发Lambda函数;
  2. Lambda通过SSM RunCommand在目标EC2实例上执行cfn-init --update;
  3. 等待命令执行完成后,向CloudFormation发送信号继续堆栈更新。

这种方式适合跨资源协调、需要批量更新多台实例的复杂场景。


内容的提问来源于stack exchange,提问作者DenCowboy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 02:32:51