阿里云镜像制作踩坑记。
此文章主要记录按照阿里云 Customized Linux 制作 VPC 镜像的过程。一些部分也可用作制作其他平台镜像的参考。
当然记录的原因主要是 Arch 上的 cloud-init 打死无法在阿里云上修改 root 密码,就很气。
建立虚拟机因为要制作 Customized Linux,所以第一步无法在阿里云平台上使用公共镜像制作。本机启动一个 Virtual Box,新建虚拟机,虚拟磁盘选择 RAW/IMG 格式即可。
按照一般步骤安装 Arch Linux,需要整个磁盘仅有一个分区。虽然很多平台支持多分区的镜像文件,但是莫名在这里踩了坑所以。
(另外吐槽:vps2arch 居然不帮我把 base-devel 装全了?!)
系统配置安装一些必需的包。
1 # pacman -S qemu-guest-ga openssh
启用服务。
1 2 3 # systemctl enable qemu-ga # systemctl enable sshd # systemctl enable systemd-networkd
网络配置哪个魂淡跟我讲 VPC 是 DHCP?装着 cloud-init 的 Arch 就可以自动设置内网 IP,这个没装的就 GG。
修改文件 /etc/systemd/network/default.network
1 2 3 4 5 [Match] Name =en*[Network] DHCP =ipv4
总之先这样放着。
定制脚本根据阿里云的文档,cloud init 不生效的时候需要用约定好的配置文件和脚本完成各种兼容动作。
新建目录 /aliyun_custom_image
新建文件 /usr/bin/aliyun-custom-os,写入内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 #!/bin/bash os_conf_dir=/aliyun_custom_image os_conf_file=${os_conf_dir} /os.conf load_os_conf () { if [[ -f $os_conf_file ]]; then . $os_conf_file echo $password return 0 else return 1 fi } cleanup () { rm $os_conf_file >& /dev/null mkdir -p $os_conf_dir } config_password () { if [[ -n $password ]]; then password=$(echo $password | base64 -d) if [[ $? == 0 && -n $password ]]; then echo "root:$password " echo "root:$password " | chpasswd fi fi } config_hostname () { if [[ -n $hostname ]]; then echo "$hostname " > /etc/hostname hostnamectl set-hostname $hostname fi } config_network () { if [[ -n $eth0_ip_addr ]]; then config_interface systemctl restart systemd-networkd fi } config_interface () { mask2cdr $eth0_netmask cat << EOF > /etc/systemd/network/default.network [Match] Name=$(ip link | awk -F: '$0 !~ "lo|vir|wl|^[^0-9]"{print $2a;getline}' | sed -e 's/^[[:space:]]*//' ) [Network] Address=$eth0_ip_addr /$netmask Gateway=$eth0_gateway [Link] MACAddress=$eth0_mac_address [Address] Address=$eth0_ip_addr /$netmask EOF echo "nameserver 1.1.1.1" > /etc/resolv.conf for ns in $dns_nameserver do echo "nameserver $ns " >> /etc/resolv.conf done } mask2cdr () { local x=${1##*255.} set -- 0^^^128^192^224^240^248^252^254^ $(( (${#1} - ${#x} )*2 )) ${x%%.*} x=${1%%$3*} netmask=$(( $2 + (${#x} /4 ) )) } if load_os_conf ; then config_password config_hostname config_network cleanup else echo "not load $os_conf_file " fi
赋予执行权限
1 # chmod +x /usr/ bin/aliyun-custom-os
新建 systemd unit 文件 /usr/lib/systemd/system/aliyun-custom-os.service 写入内容
1 2 3 4 5 6 7 8 9 10 11 12 [Unit] Description =Aliyun Custom OS Helper Script[Service] Type =oneshotExecStart =/usr/bin/aliyun-custom-osTimeoutSec =30StandardInput =ttyRemainAfterExit =yes [Install] WantedBy =multi-user.target
然后启用这个服务
1 systemctl enable aliyun-custom-os
挂载镜像正常 shutdown 虚拟机,然后拿到镜像文件的路径。例如 ~/vm/archlinux.img。
接下来需要将此镜像挂载到宿主机系统中修改、清理文件。首先确定镜像文件中的分区位置:
1 2 $ file ~/vm/archlinux.img archlinux.img: x86 boot sector; partition 1 : ID=0x83 , active, starthead 32 , startsector 2048 , 41938944 sectors, code offset 0x63
得知 startsector 为 2048
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $ fdisk -l ~/vm/archlinux.img You must set cylinders. You can do this from the extra functions menu. Disk archlinux.img: 0 MB, 0 bytes 255 heads, 63 sectors/track, 0 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x91d8e293 Device Boot Start End Blocks Id System archlinux.img1 * 1 2611 20969472 83 Linux Partition 1 has different physical/logical endings: phys=(1023, 254 , 63 ) logical=(2610, 180 , 2 )
得知 sectorsize 为 512。
使用 mount 命令带 offset 参数挂载镜像中的分区:
1 2 $ sudo mkdir -p /mnt/img $ sudo mount -t ext4 -o loop,offset=$((2048 *512 )) /path/ to/archlinux.img /m nt/img/
就可以 cd /mnt/img 看到镜像里的 rootfs 啦。
清理/检查文件要删除的:
1 2 3 4 5 # rm /root/.bash_history # rm /etc/ssh/ssh_host_* # rm -r /var/log /* # rm -r /var/cache/* # rm /etc/resolv.conf.bak
要检查的:
/etc/hosts - 我不知道为什么,第一次的时候把这个文件留空了(:з」∠)
/etc/resolv.conf - 鉴于总是有人喜欢手动修改这个文件,所以直接把它写成静态文件好了。内容例如
1 2 nameserver 8.8 .8 .8 nameserver 8.8 .4 .4
/etc/ssh/sshd_config 中是否允许 root 密码登陆。
准备镜像退出 /mnt/img 目录,然后卸载镜像
(可选)使用 qemu-img 转换镜像格式到 VHD,减少镜像文件大小。特别是对国内的小水管上传(心疼
1 $ qemu-img convert -f raw -O vpc archlinux.img archlinux.vhd
上传镜像在相同的 region 创建一个 OSS bucket,然后创建一个 RAM 子用户赋予 OSS 写权限并创建 Access Key,使用 OSSBrowser 上传准备好的 VHD 文件。
上传完毕后,在 ECS 标签下的镜像标签即可导入镜像。如果是第一次操作,需要给 ECS 授权访问 OSS。在导入的页面提示中提供了授权的链接。镜像内容配置如下:
OSS Object 地址:镜像文件在 OSS 中的 URL
Image 名称:archlinux-2018.1-x86_64 … 等符合要求即可
操作系统:Linux
系统盘大小:40GB
系统架构:x86_64
系统平台:Customized Linux
镜像格式:VHD(如果是 img 就选 RAW)
镜像描述:随便写啦。
确定后应该就会开始制作镜像了。
测试因为没有做经典实例的兼容,这个镜像只能用于 VPC 的实例。总体而言,cloud-init 本来兼容的 Arch 却无法更改 root 密码(其他的倒是没问题),所以才选择了用一个 dirty 的方案来实现。
不知道应该说阿里云的工程师对自定义镜像的考虑周到还是对不同发行版的考虑欠妥…?
最后庆幸倒腾来去上传了好多遍 20G 的文件,日本运营商家宽带宽对等真的是帮了大忙,不然一个镜像制作不知道要到什么时候 > > (斜眼看国内三大运营商
参考: