全部產品
Search
文件中心

Elastic Compute Service:定製Linux自訂鏡像

更新時間:Feb 28, 2024

當鏡像的作業系統不在阿里雲所支援的平台列表中,並且不能安裝cloud-init時,您可以在匯入自訂鏡像時選擇Customized Linux(定製版鏡像)。阿里雲將定製版Linux鏡像當作無法識別的作業系統,您需要在匯入鏡像前,根據本文描述在鏡像中添加解析指令碼,便於初次啟動時自動化配置執行個體。

限制要求

Customized Linux鏡像具有如下限制條件:
  • 第一個分區必須可以被寫入。
  • 第一個分區的檔案類型只能是FAT32、EXT2、EXT3、EXT4或UFS。
  • 虛擬檔案的大小必須大於5GiB。
Customized Linux鏡像具有如下安全要求:
  • 不能存在可被遠程利用的高危漏洞。
  • 使用控制台的管理終端(VNC)登入執行個體時,如果存在初始預設密碼,您必須在首次登入時修改,修改密碼之前不允許進入執行個體做任何操作。詳情請參見使用VNC登入執行個體
  • 不支援預設SSH金鑰組,初始SSH金鑰組必須由阿里雲產生。

配置方法

製作並匯入Customized Linux自訂鏡像前,您需要進行如下配置。
  1. 在鏡像的第一個分區的根目錄下建立目錄aliyun_custom_image

    使用該Customized Linux鏡像所建立的執行個體初次啟動時,阿里雲會在aliyun_custom_image目錄的os.conf檔案中寫入執行個體相關配置資訊。如果不存在os.conf檔案,則系統自動建立。

  2. 在鏡像中建立一份解析指令碼,用以解析os.conf檔案的系統配置。

    編寫指令碼,請參見解析指令碼注意事項解析指令碼樣本

os.conf檔案樣本

  • 傳統網路類型執行個體os.conf檔案樣本。
    hostname=<yourHostName>
    password=<yourPassword>
    eth0_ip_addr=10.0.0.2
    eth0_mac_addr=00:xx:xx:xx:xx:23
    eth0_netmask=255.255.255.0
    eth0_gateway=10.0.0.1
    eth0_route="10.0.0.0/8 10.0.0.1;172.16.0.0/12 10.0.0.1"
    eth1_ip_addr=42.0.0.2
    eth1_mac_addr=00:xx:xx:xx:xx:24
    eth1_netmask=255.255.255.0
    eth1_gateway=42.0.0.1
    eth1_route="0.0.0.0/0 42.0.0.1"
    dns_nameserver="7.7.7.7 8.8.8.8"
    樣本中各參數說明如下表所示。
    參數名稱參數說明
    hostname主機名稱參數
    password密碼參數,Base64編碼的字串
    eth0_ip_addreth0網卡IP地址
    eth0_mac_addreth0網卡MAC地址
    eth0_netmasketh0網卡掩碼
    eth0_gatewayeth0網卡預設閘道
    eth0_routeeth0內網路由列表,預設用半形分號分隔
    eth1_ip_addreth1網卡IP地址
    eth1_mac_addreth1網卡MAC地址
    eth1_netmasketh1網卡掩碼
    eth1_gatewayeth1網卡預設閘道
    eth1_routeeth1公網路由列表,預設用半形分號分隔
    dns_nameserverDNS地址清單,預設用空格分隔
  • Virtual Private Cloud類型執行個體os.conf檔案樣本。
    hostname=<yourHostName>
    password=<yourPassword>
    eth0_ip_addr=10.0.0.2
    eth0_mac_addr=00:xx:xx:xx:xx:23
    eth0_netmask=255.255.255.0
    eth0_gateway=10.0.0.1
    eth0_route="0.0.0.0/0 10.0.0.1"
    dns_nameserver="7.7.7.7 8.8.8.8"
    樣本中各參數說明如下表所示。
    參數名稱參數說明
    hostname主機名稱參數
    password密碼參數,Base64編碼的字串
    eth0_ip_addreth0網卡IP地址
    eth0_mac_addreth0網卡MAC地址
    eth0_netmasketh0網卡掩碼
    eth0_gatewayeth0網卡預設閘道
    eth0_routeeth0內網路由列表,預設用半形分號分隔
    dns_nameserverDNS地址清單,預設用空格分隔

解析指令碼注意事項

執行個體初次啟動時,正常情況下阿里雲自動將配置項的相關資訊寫入第一個分區的根目錄下aliyun_custom_image目錄的os.conf檔案中。配置Customized Linux鏡像必須要在鏡像中建立預定義解析指令碼,用以從os.conf檔案中讀取執行個體配置資訊並完成執行個體配置。

解析指令碼需要滿足的條件,如下表所示。
需滿足的條件配置說明
開機啟動解析指令碼需要設定成開機自啟動,例如,將解析指令碼存放在/etc/init.d/目錄下。
配置項取值規則os.conf 檔案樣本的配置項所述,VPC與傳統網路類型執行個體的配置項數量和部分配置項的取值規則均有所不同。
設定檔讀取路徑Customized Linux鏡像在建立I/O最佳化執行個體或非I/O最佳化執行個體時,為第一個分區所分配的裝置名稱預設不一樣。所以在解析指令碼中建議使用uuidlabel識別第一個分區的裝置。使用者密碼為Base64編碼的字串,設定密碼時需要做相關處理。
判斷VPC或傳統網路解析指令碼判斷該網路類型時,可以查看是否存在eth1_route或其他eth1相關的配置項。判斷出當前執行個體的網路類型後再有針對性地解析和處理。
  • VPC類型執行個體在os.conf檔案的eth0_route參數中配置預設公網路由。
  • 傳統網路類型執行個體在os.conf檔案的eth1_route參數中配置預設公網路由,內網路由配置在eth0_route中。
配置最佳化os.conf檔案中的配置在執行個體的整個生命週期中執行一次即可,解析指令碼執行成功後建議刪除os.conf檔案。同時解析指令碼如果沒有讀取到os.conf檔案配置,則不執行檔案中的配置。
自訂鏡像處理根據Customized Linux鏡像建立的執行個體再製作自訂鏡像時,鏡像中也會包含這個開機啟動指令碼。阿里雲會在執行個體第一次啟動時寫入os.conf配置,解析指令碼在檢測到該配置時即可執行相關配置。
修改相關配置時的處理當執行個體的配置資訊通過阿里雲的控制台或API發生變更時,阿里雲將相關資訊寫入到os.conf檔案中,解析指令碼將被再次執行從而下發這些更改。

解析指令碼樣本

解析指令碼以CentOS作業系統為例,僅供您參考。實際操作時,請根據作業系統類型調整指令碼內容。使用指令碼前,務必在鏡像中調試指令碼,並保證調試通過。
#!/bin/bash

### BEGIN INIT INFO
# Provides:          os-conf
# Required-Start:    $local_fs $network $named $remote_fs
# Required-Stop:
# Should-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: The initial os-conf job, config the system.
### END INIT INFO

first_partition_dir='/boot/'
os_conf_dir=${first_partition_dir}/aliyun_custom_image
os_conf_file=${os_conf_dir}/os.conf

load_os_conf() {
    if [[ -f $os_conf_file ]]; then
        . $os_conf_file
        return 0
    else
        return 1
    fi
}

cleanup() {
    # ensure $os_conf_file is deleted, to avoid repeating config system
    rm $os_conf_file >& /dev/null
    # ensure $os_conf_dir exists
    mkdir -p $os_conf_dir
}

config_password() {
    if [[ -n $password ]]; then
        password=$(echo $password | base64 -d)
        if [[ $? == 0 && -n $password ]]; then
            echo "root:$password" | chpasswd
        fi
    fi
}

config_hostname() {
    if [[ -n $hostname ]]; then
        sed -i "s/^HOSTNAME=.*/HOSTNAME=$hostname/" /etc/sysconfig/network
        hostname $hostname
    fi
}

config_dns() {
    if [[ -n $dns_nameserver ]]; then
        dns_conf=/etc/resolv.conf
        sed -i '/^nameserver.*/d' $dns_conf
        for i in $dns_nameserver; do
            echo "nameserver $i" >> $dns_conf
        done
    fi
}

is_classic_network() {
    # vpc: eth0
    # classic: eth0 eth1
    grep -q 'eth1' $os_conf_file
}

config_network() {
    /etc/init.d/network stop
    config_interface eth0 ${eth0_ip_addr} ${eth0_netmask} ${eth0_mac_addr}
    config_route eth0 "${eth0_route}"
    if is_classic_network ; then
        config_interface eth1 ${eth1_ip_addr} ${eth1_netmask} ${eth1_mac_addr}
        config_route eth1 "${eth1_route}"
    fi
    /etc/init.d/network start
}

config_interface() {
    local interface=$1
    local ip=$2
    local netmask=$3
    local mac=$4
    interface_cfg="/etc/sysconfig/network-scripts/ifcfg-${interface}"
    cat << EOF > $interface_cfg
DEVICE=$interface
IPADDR=$ip
NETMASK=$netmask
HWADDR=$mac
ONBOOT=yes
BOOTPROTO=static
EOF
}

config_default_gateway() {
    local gateway=$1
    sed -i "s/^GATEWAY=.*/GATEWAY=$gateway/" /etc/sysconfig/network
}

config_route() {
    local interface=$1
    local route="$2"
    route_conf=/etc/sysconfig/network-scripts/route-${interface}
    > $route_conf
    echo $route | sed 's/;/\n/' | \
        while read line; do
            dst=$(echo $line | awk '{print $1}')
            gw=$(echo $line | awk '{print $2}')
            if ! grep -q "$dst" $route_conf 2> /dev/null; then
                echo "$dst via $gw dev $interface" >> $route_conf
            fi
            if [[ "$dst" == "0.0.0.0/0" ]]; then
                config_default_gateway $gw
            fi
        done
}

################## sysvinit service portal ####################

start() {
    if load_os_conf ; then
        config_password
        config_network
        config_hostname
        config_dns
        cleanup
        return 0
    else
        echo "not load $os_conf_file"
        return 0
    fi
}

RETVAL=0

case "$1" in
    start)
        start
        RETVAL=$?
    ;;
    *)
        echo "Usage: $0 {start}"
        RETVAL=3
    ;;
esac

exit $RETVAL