當您的鏡像作業系統不在阿里雲所支援的已有平台類型中時,您可以在 ECS 控制台匯入鏡像頁面選擇 Customized Linux(定製版鏡像)的平台類型,如下圖所示。



對於定製版鏡像,阿里雲會將它當作未知的作業系統類型,無法識別作業系統的各種資訊,只能利用約定好的方法把執行個體運行所需要的必要的配置資訊傳入到執行個體中,然後執行個體啟動時運行預定義的指令碼或直譯式程式處理這些配置資訊。

配置方法及限制條件

限制條件
  • 定製版鏡像的第一個分區必須可以被寫入。

  • 定製版鏡像的第一個分區類型支援 FAT32/EXT2/EXT3/EXT4/UFS。

  • 鏡像的虛擬檔案大小必須大於 5 GB。

配置方法
  1. 在鏡像的第一個分區的根目錄下建立目錄 aliyun_custom_image
  2. 使用該鏡像所建立的執行個體在啟動時,阿里雲會在 aliyun_custom_image 目錄的 os.conf 檔案中寫入執行個體相關配置資訊。如果不存在這個檔案,則會自動建立。
  3. 鏡像中需要有一個預定義的啟動指令碼或直譯式程式,該指令碼或直譯式程式用來解析 os.conf 檔案的各項配置,並進行相關配置,詳見 配置解析指令碼或直譯式程式 − 注意事項指令碼或直譯式程式樣本

安全要求

定製版鏡像的基本安全要求如下:

  • 不得存在可被遠程利用的高危漏洞。
  • 使用控制台的 管理終端 功能登入時如果存在初始預設密碼,則必須在首次登入時修改,修改之前不允許進入系統做任何操作。
  • SSH 不允許有初始預設密碼,初始密碼必須隨機生成(通過阿里雲 ECS 控制系統下發)。

os.conf 設定檔樣本

經典網路執行個體的 os.conf 設定檔樣本
hostname=iZ23r29djmjZ
password=cXdlcjEyMzQK
eth0_ip_addr=10.171.254.123
eth0_mac_addr=00:8c:fa:5e:14:23
eth0_netmask=255.255.255.0
eth0_gateway=10.171.254.1
eth0_route="10.0.0.0/8 10.171.254.1;172.16.0.0/12 10.171.254.1"
eth1_ip_addr=42.120.74.105
eth1_mac_addr=00:8c:fa:5e:14:24
eth1_netmask=255.255.255.0
eth1_gateway=42.120.74.1
eth1_route="0.0.0.0/0 42.120.74.1"
dns_nameserver="7.7.7.7 8.8.8.8"

其中各個參數的說明如下表所示。

參數名稱 參數說明
hostname 主機名稱參數。
password 密碼參數,Base 64 編碼的字元串。
eth0_ip_addr eth0 網卡 IP 位址。
eth0_mac_addr eth0 網卡 MAC 位址。
eth0_netmask eth0 網卡掩碼。
eth0_gateway eth0 網卡預設閘道。
eth0_route eth0 路由列表(內網路由列表),預設用半形分號分隔。
eth1_ip_addr eth1 網卡 IP 位址。
eth1_mac_addr eth1 網卡 MAC 位址。
eth1_netmask eth1 網卡掩碼。
eth1_gateway eth1 網卡預設閘道。
eth1_route eth1 路由(預設外網路由)列表,預設用半形分號分隔。
dns_nameserver DNS 地址清單,預設用空格分隔。
VPC 網路的執行個體設定檔樣本
hostname=iZ23r29djmjZ
password=cXdlcjEyMzQK
eth0_ip_addr=10.171.254.123
eth0_mac_addr=00:8c:fa:5e:14:23
eth0_netmask=255.255.255.0
eth0_gateway=10.171.254.1
eth0_route="0.0.0.0/0 10.171.254.1"
dns_nameserver="7.7.7.7 8.8.8.8"

其中各個參數的說明如下表所示。

參數名稱 參數說明
hostname 主機名稱參數。
password 密碼參數,Base 64 編碼的字元串。
eth0_ip_addr eth0 網卡 IP 位址。
eth0_mac_addr eth0 網卡 MAC 位址。
eth0_netmask eth0 網卡掩碼。
eth0_gateway eth0 網卡預設閘道。
eth0_route eth0 路由列表,預設用半形分號分隔。
dns_nameserver DNS 地址清單,預設用空格分隔。

配置解析指令碼或直譯式程式 − 注意事項

建立執行個體時阿里雲會將配置項的相關資訊寫入第一個分區的 aliyun_custom_image 目錄的os.conf檔案中。配置定製版鏡像的關鍵是要在鏡像中預定義指令碼或直譯式程式,該指令碼或直譯式程式將從os.conf中讀取相關配置資訊並執行這些配置。下面是設計該指令碼或直譯式程式時的一些注意事項。

  • 各配置項設值規則:如 os.conf 設定檔樣本 的配置項所述,VPC 與經典網路執行個體的配置項數量和部分配置項的取值規則均有所不同。
  • 開機啟動:該指令碼或直譯式程式需要設定成開機自動運行。
  • 設定檔讀取路徑:鏡像在建立 I/O 優化執行個體或非 I/O 優化執行個體時,為第一個分區所分配的裝置名稱預設不一樣;所以在指令碼或直譯式程式中最好可以以 uuidlabel 來識別第一個分區的裝置。使用者密碼為 Base64 編碼的字元串,所以在設定密碼時需要進行相關處理。
  • 對於 VPC 及經典網路的判斷:需要在指令碼或直譯式程式中判斷該執行個體是經典網路還是 VPC 網路。目前最簡單的方法是判斷配置項中是否存在 eth1_route 或其他 eth1 相關的配置項。
  • VPC 及經典網路的配置項不同之處:
    • 對於 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 鏡像為例的樣本指令碼或直譯式程式,需要注意如下事項:

  • 該指令碼或直譯式程式僅供參考,您需要根據實際的作業系統類型進行調整從而得到具體的指令碼或直譯式程式。
  • 在使用指令碼或直譯式程式前,請先在鏡像中調試指令碼或直譯式程式,並保證調試通過。
  • 該指令碼或直譯式程式必須配置為開機自動執行,比如將這個指令碼或直譯式程式放到 /etc/init.d/ 目錄下。

#!/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 is exitst
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
inteface_cfg="/etc/sysconfig/network-scripts/ifcfg-${interface}"
cat << EOF > $inteface_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