在 AWS 用户数据运行后启动服务

在 AWS 用户数据运行后启动服务

我正在构建基于 Ubuntu 16.04 AMI 的 AMI。

当我从我的 AMI 启动实例时,我想要传递一个在 AMI 上启动服务之前运行的用户数据脚本。

看起来用户数据在 中运行cloud-final.service。如果我systemctl status cloud-finaljournalctl -u cloud-final我看到我的用户数据脚本的输出。

我尝试设置我的 .service 文件以在 cloud-final.service 之后启动该服务

[Unit]
Description=My Service
After=network.service
After=cloud-final.service

...

但是 cloud-final 有RemainAfterExit=yes,这意味着它永远不会完成,所以我的服务永远不会启动。

如何配置 AWS Ubuntu 来启动我的服务用户数据脚本已经运行了吗?

答案1

使用

[Unit]
After=cloud-final.service
[Install]
WantedBy=cloud-init.target

我也遇到过这种情况。显示在达到目标journalctl之后和之前运行的用户数据。multi-usercloud-init

<timestamp> <ip_addr> systemd[1]: Reached target Multi-User System.
[snip]
<timestamp> <ip_addr> systemd[1]: Starting Execute cloud user/final scripts...
<timestamp> <ip_addr> user-data[1592]: my user data stuff
[snip]
<timestamp> <ip_addr> systemd[1]: Started Execute cloud user/final scripts.
[snip]
<timestamp> <ip_addr> systemd[1]: Reached target Cloud-init target.

因此,我认为应该让它成为需要/想要的,cloud-init而不是通常的multi-user目标(可能就像 op 所拥有的一样,它就起作用了。

答案2

提出的解决方案维格有效。但我认为可以改进。

在我的示例中,我尝试在 cloud-init 完成后运行 Puppet 代理。

在我的例子中,我们希望 Puppet 仅在 Cloud Init 完成设置后运行。为了实现这一点,我们需要修改其systemd单元的设置。

我们感兴趣的服务和目标的默认执行顺序如下:1. cloud-init-local.service 2. cloud-init.service 3. cloud-config.target 4. basic.target 5. cloud-config.service 6. puppet.service 7. multi-user.target 8. cloud-final.service 9. cloud-init.target

(stag) dki@appbackend-i-0f0d3f6abd8520f12:~$ systemd-analyze --no-pager critical-chain puppet.service
The time after the unit is active or started is printed after the "@" character.
The time the unit takes to start is printed after the "+" character.

puppet.service @17.737s
└─basic.target @17.291s
  └─paths.target @17.290s
    └─resolvconf-pull-resolved.path @17.290s
      └─sysinit.target @17.282s
        └─cloud-init.service @14.709s +2.572s
          └─systemd-networkd-wait-online.service @13.872s +832ms
            └─systemd-networkd.service @13.487s +377ms
              └─network-pre.target @13.482s
                └─cloud-init-local.service @6.983s +6.495s
                  └─var-lib.mount @11.888s
                    └─local-fs-pre.target @10.584s
                      └─keyboard-setup.service @6.506s +4.072s
                        └─systemd-journald.socket @6.430s
                          └─system.slice @6.416s
                            └─-.slice @3.772s

依赖关系图

Systemd 服务依赖图
笔记:绿色箭头表示After=,灰色箭头表示Wants=

通过包含puppet.service/etc/systemd/system/multi-user.target.wants自动 根据systemd创建依赖顺序类型After=puppet.servicehttps://www.freedesktop.org/software/systemd/man/systemd.target.html#Default%20Dependencies

依赖关系图

Puppet 服务依赖关系图原版
笔记:绿色箭头表示After=,灰色箭头表示Wants=

因此,如果我们尝试让它运行After=cloud-init.target,它会创建一个依赖循环并且根本无法启动。

[Mon Jul  9 12:49:01 2019] systemd[1]: multi-user.target: Found ordering cycle on puppet.service/start
[Mon Jul  9 12:49:01 2019] systemd[1]: multi-user.target: Found dependency on cloud-init.target/start
[Mon Jul  9 12:49:01 2019] systemd[1]: multi-user.target: Found dependency on cloud-final.service/start
[Mon Jul  9 12:49:01 2019] systemd[1]: multi-user.target: Found dependency on multi-user.target/start
[Mon Jul  9 12:49:01 2019] systemd[1]: multi-user.target: Job puppet.service/start deleted to break ordering cycle starting with multi-user.target/start

为了打破这种循环,我们需要禁用该DefaultDependencies指令。通过这样做,我们能够将添加After=cloud-init.target到 Puppet 单元,以确保它等待 Cloud-Init 完成后再开始运行。这两个指令都是通过创建文件来完成的/etc/systemd/system/puppet.service.d/override.conf ,该文件会覆盖包的原始配置而不更改其原始内容。这样做的好处是,我们可以升级包,只保留我们实际需要的指令的更改。

依赖关系图

之后的 Puppet 服务依赖关系图
笔记:绿色箭头表示After=,灰色箭头表示Wants=

最终的执行顺序为:1. cloud-init-local.service 2. cloud-init.service 3. cloud-config.target 4. basic.target 5. cloud-config.service 6. multi-user.target 7. cloud-final.service 8. cloud-init.target 9. puppet.service

(sand) dki@supplier-integrations-i-035c65e75762aaabd:~$ systemd-analyze --no-pager critical-chain puppet.service
The time after the unit is active or started is printed after the "@" character.
The time the unit takes to start is printed after the "+" character.

puppet.service @43.300s
└─cloud-init.target @43.298s
  └─cloud-final.service @33.272s +10.025s
    └─multi-user.target @33.246s
      └─splunk.service @13.815s +19.429s
        └─basic.target @13.463s
          └─sockets.target @13.463s
            └─docker.socket @13.453s +10ms
              └─sysinit.target @13.436s
                └─cloud-init.service @10.873s +2.557s
                  └─systemd-networkd-wait-online.service @9.182s +1.689s
                    └─systemd-networkd.service @9.034s +143ms
                      └─network-pre.target @9.032s
                        └─cloud-init-local.service @854ms +8.177s
                          └─var-lib.mount @7.587s
                            └─local-fs-pre.target @1.391s
                              └─keyboard-setup.service @569ms +822ms
                                └─systemd-journald.socket @564ms
                                  └─system.slice @564ms
                                    └─-.slice @423ms

答案3

您可能要做的是让用户数据脚本写入一个文件以表明它已完成(在脚本末尾),并让其他服务在接近末尾的某个地方启动,并让它首先监视文件。当它注意到文件正在创建(或时间戳正在更新,或内容已更改,等等)时,然后启动其余服务并正常退出。

答案4

构建于维格

我尝试用 来做这件事pm2。它有一个创建的启动脚本,pm2-ubuntu.service所以我对其进行了修改。

但我还发现里面还有一个符号链接/etc/systemd/system/multi-user.target.wants需要移动到/etc/systemd/system/cloud-init.target.wants。所以可能还有其他类似的阻塞。

希望有所帮助。

相关内容