If the selected OS is not supported by Alibaba Cloud and cloud-int cannot be installed, you can select Customized Linux when importing a custom image. Alibaba Cloud regards customized Linux images as an unrecognized OS type. You must add a parsing script to the custom image before the import to automatically configure the instance when it is first started.

Limits

Customized Linux images have the following limits:
  • The first partition must be writable.
  • The type of the first partition must be FAT32, ext2, ext3, ext4, or UFS.
  • The size of the virtual file of the customized Linux image must be larger than 5 GiB.
Customized Linux images have the following security requirements:
  • No important vulnerabilities can be remotely exploited.
  • When logging on to an instance for the first time through the Management terminal of the ECS console, you are required to change the initial password (if there is any) before you can perform any other actions.
  • There is no default SSH key pair. The initial SSH private key pair must be randomly generated by Alibaba Cloud.

Procedure

Before creating and importing a customized Linux image, you must make the following configurations:
  1. Create the aliyun_custom_image directory in the root directory of the first partition of the server from which the image is created.

    When the instance created from the customized Linux image is started for the first time, Alibaba Cloud writes instance configurations to the os.conf file in the aliyun_custom_image directory. If the os.conf file does not exist, Alibaba Cloud will automatically create one.

  2. Create a parsing script in the image to parse the os.conf file to implement instance configurations. For more information about how to compile a script, see Considerations for the parsing script and Example of the parsing script.

Example of the os.conf file

The following section shows examples of the os.conf files for instances in classic networks and instances in VPCs.
  • Instances in classic networks:
    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"
    The following table describes the parameters in the preceding example.
    Parameter Description
    hostname The hostname.
    password The password, which is a Base64-encoded string.
    eth0_ip_addr The IP address of the eth0 NIC.
    eth0_mac_addr The MAC address of the eth0 NIC.
    eth0_netmask The network mask of the eth0 NIC.
    eth0_gateway The default gateway of the eth0 NIC.
    eth0_route The eth0 internal routes that are separated by semicolons (;) by default.
    eth1_ip_addr The IP address of the eth1 NIC.
    eth1_mac_addr The MAC address of the eth1 NIC.
    eth1_netmask The network mask of the eth1 NIC.
    eth1_gateway The default gateway of the eth1 NIC.
    eth1_route The eth1 Internet routes that are separated by semicolons (;) by default.
    dns_nameserver The DNS address list, in which addresses are separated by spaces by default.
  • Instances in VPCs:
    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"
    The following table describes the parameters in the preceding example.
    Parameter Description
    hostname The hostname.
    password The password, which is a Base64-encoded string.
    eth0_ip_addr The IP address of the eth0 NIC.
    eth0_mac_addr The MAC address of the eth0 NIC.
    eth0_netmask The network mask of the eth0 NIC.
    eth0_gateway The default gateway of the eth0 NIC.
    eth0_route The eth0 internal and internet routes that are separated by semicolons (;) by default.
    dns_nameserver The DNS address list, in which addresses are separated by spaces by default.

Considerations for the parsing script

In normal cases, when an instance is started for the first time, Alibaba Cloud automatically writes instance configurations to the os.conf file. The os.conf file is in the aliyun_custom_image directory in the root directory of the first partition. However, you must create a predefined parsing script for a customized Linux image. The script will read the configurations from the os.conf file to configure the instance.

The parsing script must meet the following conditions:
Condition Description
Automatic start at system startup Set the parsing script to be automatically started at system startup by placing the script in the /etc/init.d/ directory.
Values for configuration items As shown in Example of the os.conf file, instances in classic networks and instances in VPCs differ in the number of configuration items and values of some configuration items.
Path for the configuration file Device names allocated to the first partition for instances created from the customized Linux image vary depending on whether the instances are I/O optimized. As a best practice, include uuid or label in your parsing code to identify the device allocated for the first partition. Because the user password is a Base64-encoded string, it must also be Base64-encoded in the parsing script.
Network type When determining the network type, the parsing script can check whether there are eth1_route or other eth1-related configuration items. The script will parse and process the instance accordingly based on the network type.
  • Instances in VPCs are configured with the default Internet route and default internal route that are specified by the eth0_route parameter in the os.conf file.
  • Instances in classic networks are configured with the default Internet route that is specified by the eth1_route parameter in the os.conf file, and with the default internal route that is specified by the eth0_route parameter.
Configuration optimization Configurations in the os.conf file are executed only once during the instance lifecycle. We recommend that you delete the os.conf file after the parsing script is executed. The parsing script will not execute the configurations in the os.conf file if the script does not read any.
Customized image processing When a custom image is created based on a customized Linux image, the automatic startup script is also included. Alibaba Cloud will write configurations to the os.conf file when the instance is started for the first time. Then, the parsing script immediately executes the configurations upon detection.
Configuration change processing When instance configurations are changed through the Alibaba Cloud console or API operations, Alibaba Cloud writes new configurations to the os.conf file. Then, the parsing script runs again to issue the changes.

Example of the parsing script

This section uses a parsing script for CentOS as an example. You must change the script content based on your operating system. Make sure to debug the script before you execute it.
#! /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
    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