cloud-init在安装的时候会在system-generators目录(例如:/usr/lib/systemd/system-generators/)下创建一个cloud-init-generator可执行文件,实际上是一个shell脚本。systemd在启动初期会执行该generator(目录下所有的generators都会在同一时间被并行执行 )。在cloud-init-generator脚本中判断了当前是否需要启动cloud-init.target,一般会检查一下几点:

  • 是否存在文件/etc/cloud/cloud-init.disabled
  • kernel_cmdline中是否指定了禁止cloud-init的命令参数
  • datasource是否被指定

相关逻辑如下:

 for search in kernel_cmdline etc_file default; do
        if $search; then
            debug 1 "$search found $_RET"
            [ "$_RET" = "$ENABLE" -o "$_RET" = "$DISABLE" ] &&
                result=$_RET && break
        else
            ret=$?
            debug 0 "search $search returned $ret"
        fi
    done
if [ "$result" = "$ENABLE" ]; then
        debug 1 "checking for datasource"
        check_for_datasource
        ds=$_RET
        if [ "$ds" = "$NOTFOUND" ]; then
            debug 1 "cloud-init is enabled but no datasource found, disabling"
            result="$DISABLE"
        fi
    fi

如果需要启动cloud-init.target,会创建一个cloud-init.target的软链接到multi-user.target.wants目录下,这个目录下的target都是需要开机自启动的。(target是一个服务组,启动时系统会启动该服务组中的所有服务)。

相关逻辑:

    if [ "$result" = "$ENABLE" ]; then
        if [ -e "$link_path" ]; then
                debug 1 "already enabled: no change needed"
        else
            [ -d "${link_path%/*}" ] || mkdir -p "${link_path%/*}" ||
                debug 0 "failed to make dir $link_path"
            if ln -snf "$CLOUD_SYSTEM_TARGET" "$link_path"; then
                debug 1 "enabled via $link_path -> $CLOUD_SYSTEM_TARGET"
            else
                ret=$?
                debug 0 "[$ret] enable failed:" \
                    "ln $CLOUD_SYSTEM_TARGET $link_path"
            fi
        fi
        : > "$RUN_ENABLED_FILE"

cloud-init.target中包含了以下服务:

  • cloud-init-local.service(对应5个boot stages中的Local阶段)
  • cloud-init.service(对应5个boot stages中的Network阶段)
  • cloud-config.service(对应5个boot stages中的Config阶段)
  • cloud-final.service(对应5个boot stages中的Final阶段)

分析到这里,我们就能知道,所谓的启动cloud-init,其实是启动了上述四个服务,这四个服务是按照一定顺序one by one的方式来执行的。

cloud-init-local.service

服务启动脚本中的start方法:

start() {
    [ -x $cloud_init ] || return 5
    [ -f $conf ] || return 6

    echo -n $"Starting $prog: "
    $cloud_init $CLOUDINITARGS init --local
    RETVAL=$?
    return $RETVAL
}

实际上执行了cloud-init init --local命令

cloud-init.service

服务启动脚本中的start方法:

start() {
    [ -x $cloud_init ] || return 5
    [ -f $conf ] || return 6

    echo -n $"Starting $prog: "
    $cloud_init $CLOUDINITARGS init
    RETVAL=$?
    return $RETVAL
}

实际上是执行了cloud-init init命令

cloud-config.service

服务启动脚本中的start方法:

start() {
    [ -x $cloud_init ] || return 5
    [ -f $conf ] || return 6

    echo -n $"Starting $prog: "
    $cloud_init $CLOUDINITARGS modules --mode config
    RETVAL=$?
    return $RETVAL
}

实际上执行了cloud-init mudules --mode config命令

cloud-final.service

服务启动脚本中的start方法:

start() {
    [ -x $cloud_init ] || return 5
    [ -f $conf ] || return 6

    echo -n $"Starting $prog: "
    $cloud_init $CLOUDINITARGS modules --mode final
    RETVAL=$?
    return $RETVAL
}

实际上执行了cloud-init mudules --mode final命令

这四个服务依次执行完成之后,cloud-init相关的工作也就完成了。