12-镜像制作
通过KVM安装虚Centos 和Windwos 2008 R2_x86_64操作系统步骤并将磁盘文件作为镜像上传到openstack glance , 作为批量创建虚拟机的镜像文件 , 其中windowsn 2008安装virtio 半虚拟化驱动 , 以实现网络IO和磁盘IO的半虚拟化提升速度 , Centos 7默认即支持半虚拟化 , 不需要安装驱动 , Virtio最初由澳大利亚的一个天才级程序员Rusty Russell编写 , 是一个在hypervisor之上的抽象API接口 , 让客户机知道自己运行在虚拟化环境中 , 从而与hypervisor根据 virtio 标准协作 , 从而在客户机中达到更好的性能(特别是I/O性能) 。目前 , 有不少虚拟机都采用了virtio半虚拟化驱动来提高性能。
1. 环境准备
这里单独用一台服务器来实现镜像制作。这里镜像是通过kvm实现的
安装
kvm[root@image ~]# qemu-kvm qemu-kvm-tools libvirt libvirt-client virt-manager virt-install开机启动
libvirtdsystemctl enable libvirtd systemctl start libvirtd单网卡绑定方法:
eth0的配置:
# cd /etc/sysconfig/network-scripts/ # cp ifcfg-eth0 ifcfg-br0 # vim ifcfg-eth0 BOOTPROTO=static DEVICE=eth0 ONBOOT=yes BRIDGE=br0 #删除其他的IP/MAC/网关信息 , 增加一行桥接的配置 NM_CONTROLLED=no #不使用NetworkManager管理服务br0的配置:# vim ifcfg-br0 #编辑桥接网卡配置 TYPE=Bridge #类型为桥接 BOOTPROTO=static #静态获取IP IPV4_FAILURE_FATAL=no NAME=br0 #网卡名称 DEVICE=br0 #设备名称 ONBOOT=yes IPADDR=192.168.10.128 NETMASK=255.255.255.0 GATEWAY=192.168.10.2 DNS1=192.168.10.2双网卡绑定方法:
第一组配置 , 将
eth1和eth5绑定为bond0:先创建
bond0配置那文件步骤及内容如下:[root@linux-host1 ~]# cd /etc/sysconfig/network-scripts/ [root@linux-host1 network-scripts]# cp ifcfg-eth0 ifcfg-bond0 [root@linux-host1 network-scripts]# cat ifcfg-bond0 #内容如下: BOOTPROTO=static NAME=bond0 DEVICE=bond0 ONBOOT=yes BONDING_MASTER=yes BONDING_OPTS="mode=1 miimon=100" #指定绑定类型为1及链路状态监测间隔时间 BRIDGE=br0 #桥接到br0配置
br0:TYPE=Bridge BOOTPROTO=static IPV4_FAILURE_FATAL=no NAME=br0 DEVICE=br0 ONBOOT=yes IPADDR=X.X.X.X NETMASK=255.255.255.0 GATEWAY=X.X.X.Xeth1配置:[root@linux-host1 network-scripts]# vim ifcfg-eth1 BOOTPROTO=static NAME=eth1 DEVICE=eth1 ONBOOT=yes NM_CONTROLLED=no MASTER=bond0 USERCTL=no SLAVE=yeseth5的配置:[root@linux-host1 network-scripts]# cp ifcfg-eth1 ifcfg-eth5 [root@linux-host1 network-scripts]# vim ifcfg-eth5 BOOTPROTO=static NAME=eth5 DEVICE=eth5 ONBOOT=yes NM_CONTROLLED=no MASTER=bond0 USERCTL=no SLAVE=yes重启网络服务:
[root@linux-host1 network-scripts]``# systemctl restart network
2. 配置centos虚拟机
2.1 镜像准备
创建
qcow2格式的磁盘qemu-img create -f qcow2 /var/lib/libvirt/images/CentOS-7.2.qcow2 10G创建
KVM虚拟机virt-install --virt-type kvm --name CentOS7-7.2 \ --ram 1024 \ --cdrom=/usr/local/src/CentOS-7.2-x86_64-Minimal-1511.iso \ --disk path=/var/lib/libvirt/images/CentOS-7.2.qcow2 \ --network bridge=br0 \ --graphics vnc,listen=0.0.0.0 \ --noautoconsole
2.2 安装必要软件
启用电源管理工具,为了支持软操作
yum install -y acpid systemctl enable acpid安装
cloud-init一个实例必须与元数据服务进行交互 , 以便在启动时执行几个任务。例如 , 实例必须获取ssh公钥并运行用户数据脚本。
yum install -y cloud-init && systemctl start cloud-init && systemctl enable cloud-init安装
QGA, 为了支持OpenStack平台动态修改虚拟机密码功能 , 需要安装qemu-guest-agent:yum -y install qemu-guest-agent安装
cloud-utils-growpart(注意约束条件)。以支持虚拟机系统盘自动扩容:yum install cloud-utils-growpart -y约束条件:
根分区文件系统为xfs的镜像不支持自动扩容。
有
LVM分区的镜像不支持自动扩容。推荐使用文件系统为
ext3、ext4的单分区镜像。Windows系统不支持。
需要注意如果是centos6配置分区自动拉伸, 需要使用以下git项目
git下载地址 https://github.com/flegmatik/linux-rootfs-resize
[root@image ~]# cd /usr/local/src/
[root@image src]# yum install parted cloud-utils
[root@image src]#unzip /usr/local/src/linux-rootfs-resize-master.zip
[root@image src]# unzip linux-rootfs-resize-master.zip
[root@image src]# cd linux-rootfs-resize-master
[root@image linux-rootfs-resize-master]# ./install 
2.3 调整系统配置
配置网卡开机自启动
# vi /etc/sysconfig/network-scripts/ifcfg-ens3 ... ONBOOT=yessystemctl restart network.service这里需要注意, centos6的网卡名默认就是
eth0,如果需要自动修改网卡名称, 可以使用以下脚本来修改rule规则#!/bin/bash ifconfig eth2 &> /dev/null if [ $? -eq 0 ];then MAC=`ifconfig eth2 | grep -F "HWaddr" | awk '{print $5}'` echo "# PCI device 0x1af4:0x1000 (virtio-pci)" > /etc/udev/rules.d/70-persistent-net.rules echo "SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="${MAC}", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"" >> /etc/udev/rules.d/70-persistent-net.rules fi ifconfig eth3 &> /dev/null if [ $? -eq 0 ];then MAC=`ifconfig eth3 | grep -F "HWaddr" | awk '{print $5}'` echo "# PCI device 0x1af4:0x1000 (virtio-pci)" >> /etc/udev/rules.d/70-persistent-net.rules echo "SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="${MAC}", ATTR{type}=="1", KERNEL=="eth*", NAME="eth1"" >> /etc/udev/rules.d/70-persistent-net.rules reboot fi如果云主机需要支持
root ssh远程登录 , 需要开启root远程ssh登录功能 , 修改配置文件/etc/ssh/sshd_config中 的PermitRootLogin值为yes, 重启ssh服务生效:关闭关闭防火墙及
selinux:# systemctl disable firewalld.service # vi /etc/sysconfig/selinux 将 SELINUX=enforcing 改为 SELINUX=disabledCentOS系列的系统 , 其虚拟机的主机名默认会自动生成xxx.novalocal格式的hostname。若要取消 , 则执行如下 命令进入cloudinit/sources文件夹。编辑文件 , 修改画圈的地方与图中一致:#vim /usr/lib/python2.7/site-packages/cloudinit/sources/__init__.py
执行如下命令 , 删除
init.pyc文件和优化编译后的init.pyo文件:#rm -f __init__.pyc #rm -f init.pyo修改
cloud-init的配置文件cloud.cfg确保可以使用ssh密码登陆:vim /etc/cloud/cloud.cfg disable_root: 0 ssh_pwauth: 1检查
Cloud-init工具相关配置是否成功。执行以下命令 , 无错误发生 , 说明Cloud-init配置成功:#cloud-init init --local正确安装的
Cloud-init会显示Cloud-init的版本详细信息 , 并且无任何错误信息,执行如下命令 , 清理日志信息:#rm -rf /var/lib/cloud/* #rm -rf /var/log/cloud-init*为了虚拟机能够访问
metadata服务 , 必须禁止zeroconf服务:# echo "NOZEROCONF=yes" >> /etc/sysconfig/network配置
console, 修改/etc/default/grub文件添加如下内容:# vim /etc/default/grub GRUB_CMDLINE_LINUX="crashkernel=auto console=tty0 console=ttyS0,115200n8"更新
grub配置生效:# grub2-mkconfig -o /boot/grub2/grub.cfg删除一些无用文件 , 清理history命令后执行关机:
# history -c # poweroff
2.4 镜像上传
在制作镜像的服务器上进行下面操作
清除虚拟机内部的
MAC地址信息:# virt-sysprep -d centos使虚拟机脱离
libvirt管理:# virsh undefine centos压缩镜像:
qemu-img convert -c -O qcow2 <源文件> <目标文件> # qemu-img convert -c -O qcow2 centos.qcow2 Centos.qcow2
之后在
openstack上传镜像即可openstack image create "centos" --file /root/centos72.qcow2 --disk-format qcow2 --container-format bare --public
3. cloud-init
cloud-init 是一个软件包 , 可在系统引导期间自动初始化云实例,cloud-init 可从 nova metadata 服务或者 config drive 中获取 metadata。您可以配置 cloud-init 来执行各种任务。可以通过 cloud-init 执行的一些任务示例包括:
设置
default locale设置
hostname添加
ssh keys到.ssh/authorized_keys设置用户密码
配置网络
安装软件包
3.1 cloud-init 配置
cloud-init 使用 YAML 格式的文件指令执行任务。您可以通过在 YAML 文件中提供说明来确定您希望 cloud-init 执行的初始配置。当实例启动时 , cloud-init 服务将启动并执行指令。根据 cloud-init 配置 , 在第一次引导或后续启动虚拟机时完成任务。
您可以通过配置 /etc/cloud/cloud.cfg 文件并在 /etc/cloud/cloud.cfg.d/ 目录下添加指令来定义任务。
cloud.cfg文件包含指令 , 如用于用户访问和验证以及系统信息的指令。文件还包括
cloud-init的默认和可选模块。模块在三个阶段内按顺序执行 , 这些阶段包括cloud-init初始化阶段、配置阶段和最终阶段。在cloud.cfg文件中 , 这三个阶段的模块分别列在cloud_init_modules、cloud_config_modules和cloud_final_modules下。cloud.cfg.d目录 , 您可以在其中为cloud-init添加附加指令。当您向cloud.cfg.d目录添加指令时 , 通常会将它们添加到名为*.cfg的文件中 , 您需要在每个文顶部包含#cloud-config。
3.2 cloud-init 以阶段形式运行

在系统引导期间 , cloud-init 分五个阶段运行。不同阶段会决定是否运行 cloud-init , 找到其数据源的位置 , 以及其他一些任务。这些阶段包括:
cloud-init生成器(generator)阶段 , 通过systemd服务决定是否在引导时运行cloud-init。在本地(
local)阶段 ,cloud-init找到本地数据源并应用网络配置。作为
cloud-init执行的第一个阶段 , 此时instance还不知道该如何配置网卡 ,cloud-init的任务就是从config drive中获取配置信息 , 然后写入/etc/network/interfaces文件(如果是centos则写入/etc/sysconfig/network-scripts/ifcfg-xxx)。如果没有
config drive, 则将所有网卡配置成dhcp模式。这是非常关键的一步 , 只有当网卡正确配置后 , 才能获取到metadata。openstack提供了命令行参数–config-drive用于配置是否在创建虚拟机时使用config drive机制nova boot --config-drive=true --image image-name --key-name mykey --flavor 1 --user-data \ ./my-user-data.txt myinstance --file /etc/network/interfaces=/home/myuser/instance-interfaces在
/etc/nova/nova.conf中配置,直接使OpenStack计算服务在创建虚拟机时默认使用config drive机制注意
如果镜像没有设置
cloud_init,即使在计算节点的/etc/nova/nova.conf中配置force_config_drive = true,也不会调用元数据信息如果镜像设置了
cloud_init,在计算节点的/etc/nova/nova.conf中没有配置force_config_drive = true,依然会调用元数据信息
而此时因为不知道怎么去调,所以会有一些报错信息,这样会导致开机比较久,而且每次开机都会读取元数据信息
[DEFAULT] force_config_drive=true在网络(
network)阶段 ,cloud-init处理用户数据并运行cloud.cfg文件中的cloud_init_modules下列出的模块。您可以在cloud_init_modules部分启用、禁用或添加模块。在配置(
config)阶段 ,cloud-init运行cloud.cfg文件中的cloud_config_modules下列出的模块。您可以在cloud_config_modules部分启用、禁用或添加模块。在最后(
final)阶段中 ,cloud-init可以运行cloud.cfg文件中的cloud_final_modules中包含的内容。您可以包括通常在系统引导后运行的软件包安装 , 也可以包括配置管理插件和用户脚本。您可以在cloud_final_modules部分启用、禁用或添加模块
cloud-init 安装时会将这 4 个阶段执行的任务以服务的形式注册到系统中 , 比如在 systemd 的环境下 , 我们能够看到这4个阶段分别对应的服务:
local-cloud-init-local.serviceinit-cloud-init.serviceconfig-cloud-config.servicefinal-cloud-final.service

3.3 cloud-init 模块分阶段执行
当 cloud-init 运行时 , 它会在三个阶段中按顺序执行 cloud.cfg 中的模块:
网络阶段(
cloud_init_modules)配置阶段(
cloud_config_modules)最终阶段(
cloud_final_modules)
当首次在虚拟机上运行 cloud-init 时 , 您配置的所有模块都会在相应的阶段中运行。在后续的 cloud-init 运行中 , 某个模块是否在一个阶段中运行取决于单独模块中的模块频率。有些模块在每次运行 cloud-init 时都会运行 , 一些模块只在 cloud-init 第一次运行时运行 , 即使实例 ID 发生了变化。
注意 : 用于唯一标识实例的实例
ID。当实例ID发生变化时 ,cloud-init将实例视为新实例。
可能的模块频率值如下:
Per instance意味着该模块在实例的第一次引导时运行。例如 , 如果您克隆一个实例或从保存的镜像创建了一个新实例 , 指定为per instance的模块会再次运行。Per once表示该模块只运行一次。例如 , 如果您克隆实例或从保存的镜像创建新实例 , 指定为 “Per once” 的实例不会在这些实例上再次运行。per always表示该模块在每次引导时都运行。
3.4 模块
模块(Modules)是cloud-init运行的主体,所有我们需要的用来初始化云服务器的功能都是通过执行模块而实现的。以set_hostname模块为例,该模块的功能是设置主机名,当运行该模块时,它会读取cloud-config中的hostname参数,并将其中值设置为云实例的主机名。

每个模块都有名称、运行频率、配置参数这三大要素,其中运行频率表示一个模块该在什么时候运行,通常有两种运行频率:1. once-per-instance,表示仅在实例首次启动时运行;2. always,表示实例每次启动都运行。
是否运行某个模块、何时运行模块、怎么运行模块,这些都可以在cloud-config中配置,下面截取部分cloud-config,可以看到在这个云实例中:
network阶段将运行ssh模块,config阶段将运行mounts、locale等模块,final阶段将运行scripts开头的一些模块;set-passwords模块默认的运行频率是once-per-instance,可将其调整为always,表示每次启动云实例时都会设置密码;ssh_pwauth是set-passwords模块的配置项,ssh_deletekeys、ssh_genkeytypes是ssh模块的配置项,它们描述了该如何运行模块。
# /etc/cloud/cloud.cfg
ssh_pwauth: 1
ssh_deletekeys: 1
ssh_genkeytypes: ['rsa', 'ecdsa', 'ed25519']
cloud_init_modules:
- ssh
cloud_config_modules:
- mounts
- locale
- [set-passwords,always]
cloud_final_modules:
- scripts-per-once
- scripts-per-boot
- scripts-per-instance
- scripts-user所有模块的参考文档:https://cloudinit.readthedocs.io/en/latest/topics/modules.html
3.5 文件配置说明
Cloud-init的配置文件通常为YAML格式 , 位于/etc/cloud/cloud.cfg或/etc/cloud/cloud.cfg.d/*等路径。配置文件包含多个模块的配置 , 如cloud_init_modules、cloud_config_modules、cloud_final_modules等。部分内容如下所示:
设置开放root密码远程登录并开启root用户的ssh权限。配置文件中的disable_root字段为1表示为禁用,为0表示不禁用。设置disable_root值为0,ssh_pwauth为1,lock_passwd设置为false,false表示不锁住用户密码。
users:
- name: root
ssh_authorized_keys:
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCzU9H5oJxgPpWhtXPwETEpFx425UdirDrTBRt6K/kfx7T6AcnuxzIQ6T64TmGhi72FTz7KtfYUtoIzq7specBthD8X8DTA8C9A6nIEwuHgAh12i0OugmdMmzs8g1QvKxZknFOiX32dlWQBZqU1z9V0NmaMRAxvgvYK6YR5GrHFr5QfSr3rPCMOE1qmZ7QQwfxcEFcmwz1xK65LK1VZh1TPzj7DmW97Clr0F/a11a86ekw8uXsMeowSbdGH546y9FbJlopAPZyprS7kEcwUOaj9VcfF+1LxNjjeHuPsfoquYPElgd52GIC0HE+sW5f+9otbZt2GKZUFBeuehC7g05f root@controller
disable_root: 0
ssh_pwauth: 1
#datasource_list: [ 'OpenStack' ]
#datasource:
# OpenStack:
# metadata_urls: ["http://169.254.169.254"]
# timeout: 5
# max_wait: 60
preserve_hostname: flase
manage_etc_hosts: true
runcmd:
- [ sh, -c, echo "=========Welcome To OpenStack'=========" >> /root/runcmd.log ]
mount_default_fields: [~, ~, 'auto', 'defaults,nofail,x-systemd.requires=cloud-init.service', '0', '2']
ssh_deletekeys: 1
ssh_genkeytypes: ['rsa', 'ecdsa', 'ed25519']
syslog_fix_perms: ~
disable_vmware_customization: false
cloud_init_modules:
- disk_setup
- migrator
- bootcmd
- write-files
- growpart
- resizefs
- set_hostname
- update_hostname
- update_etc_hosts
- rsyslog
- users-groups
- ssh
cloud_config_modules:
- mounts
- locale
- set-passwords
- rh_subscription
- yum-add-repo
- package-update-upgrade-install
- timezone
- puppet
- chef
- salt-minion
- mcollective
- disable-ec2-metadata
- runcmd
cloud_final_modules:
- rightscale_userdata
- scripts-per-once
- scripts-per-boot
- scripts-per-instance
- scripts-user
- ssh-authkey-fingerprints
- keys-to-console
- phone-home
- final-message
- power-state-change
system_info:
default_user:
name: cloud-user
lock_passwd: true
gecos: Cloud User
groups: [adm, systemd-journal]
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
shell: /bin/bash
distro: rhel
paths:
cloud_dir: /var/lib/cloud
templates_dir: /etc/cloud/templates
ssh_svcname: sshd 1
# vim:syntax=yaml
chpasswd:
list: |
root:XXXX@2019 #设置要修改的密码
expire: False3.5.1 数据源
metadata:cloud-init初始化依赖的数据 , 比如要设置成什么hostname , 网络详细信息如ip、掩码、dns , 密码等是由nova提供的 , 这些数据我们称之为元数据(metadata) 。
datasource:数据来源。元数据存在的载体我们叫做datasource。比如nova可以将这些元数据放到一个iso里 , 以cdrom的形式挂载到虚拟机上 , 我们把这样的iso叫做configdrive , configdrive就是一种datasource;同样的 , nova还支持通过网路地址的方式访问nova api获取到metadata , 这样的方式叫做metadata service , metadata service也是一种datasource。简而言之 , datasource就是包含metadata的一种媒介。
userdata: metadata是openstack根据虚拟机实际情况自动生成的 , 但有时候用户需要一些自定义的数据 , 例如创建虚拟机时 , 自动创建一个XXX用户等操作 , 就需要通过userdata的方式传到虚拟机里。userdata的载体也是datasource。
vendordata:云基座传入的数据(全局数据)
在openstack中,metadata、userdata均在用户创建实例时通过相应参数传入,而vendordata则由nova-api-metadata服务启动时指定。

这些数据可能来源于许多地方,cloud-init使用数据源一词表示实例数据的来源,目前内置的数据源有:OpenStack、ConfigDrive、Amazon EC2、Azure等等,不同的数据源也表明了不同的实例数据搜索方式。cloud-init在实例内部启动时并不知道从哪里才能够找到实例数据,它会根据预设的一个数据源的列表一个一个查找实例数据,而首个能够找到实例数据的数据源将成为这次启动的数据源。

如果cloud-init指定了OpenStack数据源,那么实例数据将均通过HTTP API请求获取,不同类别的实例数据有着不同的获取方式:
metadata:http://169.254.169.254/openstack/latest/meta_data.jsonvendordata:http://169.254.169.254/openstack/latest/vendor_data.json、http://169.254.169.254/openstack/latest/network_data.json
而如果指定了ConfigDrive数据源,那么实例数据将均通过文件获取,cloud-init会搜索标记有CONFIG-2标签的分区,随后将该分区挂载至临时目录中,并读取其中包含实例数据的文件:
metadata:file://TMPDIR/openstack/latest/meta_data.jsonuserdata:file://TMPDIR/openstack/latest/user_datavendordata:file://TMPDIR/openstack/latest/vendor_data.json、file://TMPDIR/openstack/latest/network_data.json
3.5.2 cloud-init缓存目录
cloud-init在运行过一次之后 , 会在/var/lib/cloud/生成缓存目录。目录里用来记录datasource和metadata信息、模块的运行记录以及用户的自定义脚本等等。

3.5.3 cloud-init如何设置网络
cloud-init是通过cloud-init-local.service中配置网络的 , 网络的配置依赖于configdrive , 如果没有configdrive , cloud-init-local.service会生成一个dhcp方式的网卡eth0的配置文件 , 以保证后面的初始化过程可以访问nova metadata service。
当使用configdrive时 , cloud-init会读取network_data.json,并根据mac地址和本地的网卡设备互相匹配 , 然后生成网卡配置文件。注意:cloud-init配置网络只会在每个实例首次开机时配置一次 , 后续不会再配置网络。
如果想禁止cloud-init修改网络配置文件(比如用户作镜像时已经配死了网络 , 不希望别人修改) , 那么可以在/etc/cloud.cfg.d/里新建一个名为"99-disable-network-config.cfg"的配置文件 , 内容如下:
99-disable-network-config.cfg network: {config: disabled}
或者在/etc/cloud/cloud.cfg中配置
network:
config: disabled3.5.4 cloud-init如何进行自动扩盘和文件系统
cloud-init扩展分区是通过"growpart"模块来做的 , 分区扩展后 , 文件系统的扩展是通过"resizefs"模块来做的 , 这两个模块都位于/etc/cloud/cloud.cfg的"cloud_init_modules"部分。
说明:
"
growpart"模块依赖于growpart的命令 , 对centos7以上的系统 , 需要安装cloud-utils-growpart包;对centos6而言 , 要安装"linux-rootfs-resize-master.zip"包;对ubuntu16.04而言 , 要安装cloud-utils包,没有这些包 , 无法对系统分区进行扩展。growpart默认只能扩展"/"分区 , 而且"/"分区必须位于磁盘的最末一个分区。否则也无法扩展磁盘 , 或者需要手动修改/etc/cloud/cloud.cfg文件。
该功能依赖growpart,所以需要在开始前,在镜像中安装包:
yum install –y cloud-utils-growpart查看需要扩容的磁盘分区
# mount |grep /dev/vd
/dev/vda1 on / type ext4 (rw,relatime,seclabel,data=ordered)
如上所示:/dev/vda1为我们需要进行扩容的磁盘分区。
cloud-init配置
cloud-init配置开机启动命令:
# cat /etc/cloud/cloud.cfg
….
bootcmd:
- [ cloud-init-per, once, grow-partition, growpart, /dev/vda, 1]
- [ cloud-init-per, once, resize-filesystem, xfs_growfs, /dev/vda1 ]
简单来说就是,在系统第一次启动的时候,执行命令:
growpart /dev/vda 1
xfs_growfs /dev/vda1
即可。lvm类型的系统盘扩容脚本
如果是lvm类型的系统盘,可以通过如下脚本扩容:
# cat extend_root_fs
echo "[] linux-rootfs-resize ..."
lvm vgchange --sysinit -an
#lvm_lv_root=$( echo $(df -h | grep '/$') | sed " ")
lvm_lv_root=$(echo $(df -h | grep '/$') | awk -F ' ' '{print $1}')
lvm_pv_path=$(lvm pvs --noheadings |awk '{print $1}')
lvm_pv_temp=$(echo ${lvm_pv_path}|sed "s/dev//g")
lvm_pv_dev=$(echo ${lvm_pv_temp}| sed "s/[^a-z]//g")
lvm_pv_part=$(echo ${lvm_pv_temp}| sed "s/[^0-9]//g")
growpart -v /dev/${lvm_pv_dev} ${lvm_pv_part}
partprobe -s /dev/${lvm_pv_dev}
lvm pvresize -v ${lvm_pv_path}
lvm vgchange --sysinit -ay
lvm lvextend -v -l +100%FREE ${lvm_lv_root}3.6 基础用法
我们在使用cloud-init时一般不会特别地去执行cloud-init相关的命令,在云实例的启动过程中操作系统会按正常流程去执行cloud-init,不过当需要开发/调试cloud-init的时候,这些命令会带来很大的帮助。
执行cloud-init的四个阶段:
# local阶段
cloud-init init --local
# network阶段
cloud-init init
# config阶段
cloud-init modules --mode=config
# final阶段
cloud-init modules --mode=final查询相关:
# 查询cloud-id
cloud-id
# 查询cloud-init执行状态
cloud-init status -l
# 查询metadata
cloud-init query <variable>
cloud-init query -l其他命令:
# 创建一个包含cloud-config(config.yaml)和shell脚本(script.sh)的userdata
cloud-init devel make-mime -a config.yaml:cloud-config -a script.sh:x-shellscript > userdata3.7 使用案例
3.7.1 重置密码
cloud-config方式:
##template: jinja
#cloud-config
runcmd:
# OpenStack数据源在local阶段无法获取数据,network阶段由于是trust模式,直接从缓存读取数据,无法获取更新后metadata,因此需要事先删除缓存。
- DIR=/var/lib/cloud/scripts/per-boot/ && mkdir -p $DIR && cd $DIR && echo '#!/bin/bash' > 99-clean-cloudinit-cache.sh && echo 'rm -f /var/lib/cloud/instance/obj.pkl' >> 99-clean-cloudinit-cache.sh && chmod +x 99-clean-cloudinit-cache.sh
# ConfigDrive数据源无法获取更新后metadata,需在首次启动后修改为OpenStack数据源。
- echo 'datasource_list: [OpenStack]' > /etc/cloud/cloud.cfg.d/90_openstack_datasource.cfg
# 首次启动后禁止写入网络配置,防止ConfigDrive中的bond配置被覆盖。
- touch /var/lib/cloud/data/upgraded-network
{% if ds.meta_data.meta.admin_pass is defined %}
chpasswd:
list: |
root:{{ds.meta_data.meta.admin_pass}}
expire: false
ssh_pwauth: [true]
phone_home:
url: http://169.254.169.254/openstack/latest/phone_home?unset=admin_pass
post:
- instance_id
tries: 5
cloud_config_modules:
- [set-passwords,always]
- [phone_home,always]
- ssh
- runcmd
{% endif %}
{% endif %}获取更新后metadata的方法,除删除缓存之外,也可实现setup方法,在该方法中获取metadata并填充进数据源中(参考azure数据源)。
将set-passwords和phone_home模块设为always的方法,出了在vendor-data中指定外,也可在activate方法中实现,删除执行这两个模块的信号(参考exoscale数据源)。
3.7.2 ssh公钥注入
使用如下userdata注入ssh公钥:
##template: jinja
#cloud-config
ssh_authorized_keys:
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDIe6oWYfMB4m9TDSmyVlONj2UakYKkAnpTsZnYXWHUd6zLQDvCLkeXmLiBTuJ51Dh6nolL4rZETj1wLJpXqcMvDhhOZyA0Ji3ENbeJj0URWNjDpRUc3eUApDOzpa3gHm8yRwXDZsZbFMpqcL5vQjlZJ9K+SmLCvbfk6sG04uJWLsIFrjSkxlRxdWwHwdvMH9tAo3UeQGnzRxdnF4zxrob+vAV7PPqJ9u4J6GwXWykTtS+cmvoPOBWQHL5gULxp2FVt/xTF5xY2IRHpzfNmJlCd4G7HGow/PVD+jsIN57iNwvxU7dvTzg0PVUXGQImJvQ8pkHD6//ghXcLleUQz3f+7Brlc6yEZuDdEy2NFEnYW8CoEymPSXVZaBykiggP2XSGp6gQa1gtT7yy44EEB5kjX9epi+jAwiCRaLDrgSLBWQmJp8435dtoOALZOXb1Br0uOA0a3G3KZr+7v11f09NZgFPzJTrY2d4ZNtOUILOcQkUAhtW6yOwuCiuxVeKM8cjE= webssh@hikcloud3.7.3 用户密码过期设置
可以强制 cloud-user 在第一次登录时更改 cloud-user 密码。执行以下步骤使密码过期。
根据数据源的要求,打开您的
user-data文件进行编辑,或者在cloud.cfg.d目录中添加以下指令。所有用户指令都包括文件顶部的
#cloud-config,以便cloud-init将文件识别为包含用户指令。当您在cloud.cfg.d目录中包含指令时,将该文件命名为*.cfg,且始终在文件的顶部包含#cloud-config。将行
chpasswd: {expire: False}更改为chpasswd: {expire: True}。
#cloud-config
password: mypassword
chpasswd: {expire: True}
ssh_pwauth: True
ssh_authorized_keys:
- ssh-rsa AAA...SDvz user1@yourdomain.com
- ssh-rsa AAB...QTuo user2@yourdomain.com这可让密码过期,因为除非您另有说明,否则 password 和 chpasswd 只针对默认的用户执行操作。
这是一个全局设置。当您将 chpasswd 设置为 True 时,您创建的所有用户都需要在登录时更改其密码。
3.7.4 更改默认用户名
您可以将默认用户名更改为 cloud-user 以外的名称。
根据数据源的要求,打开您的
user-data文件进行编辑,或者在cloud.cfg.d目录中添加以下指令。所有用户指令都包括文件顶部的
#cloud-config,以便cloud-init将文件识别为包含用户指令。当您在cloud.cfg.d目录中包含指令时,将该文件命名为*.cfg,且始终在文件的顶部包含#cloud-config。添加
user: <username>行,将 替换为新的默认用户名。#cloud-config user: username password: mypassword chpasswd: {expire: False} ssh_pwauth: True ssh_authorized_keys: - ssh-rsa AAA...SDvz user1@yourdomain.com - ssh-rsa AAB...QTuo user2@yourdomain.com
3.7.5 设置root密码
要设置根密码,创建一个用户列表。
根据数据源的要求,打开您的
user-data文件进行编辑,或者在cloud.cfg.d目录中添加以下指令。注意 : 所有用户指令都包括文件顶部的
#cloud-config,以便cloud-init将文件识别为包含用户指令。当您在cloud.cfg.d目录中包含指令时,将该文件命名为*.cfg,且始终在文件的顶部包含#cloud-config。在文件的
chpasswd部分中创建用户列表。格式在以下示例中显示。注:空格很重要。请勿在您的用户列表的冒号之前或之后包括空格。如果您包含空格,密码会被设置为包括空格。
#cloud-config
ssh_pwauth: True
ssh_authorized_keys:
- ssh-rsa AAA...SDvz user1@yourdomain.com
- ssh-rsa AAB...QTuo user2@yourdomain.com
chpasswd:
list: |
root:myrootpassword
cloud-user:mypassword
expire: False如果使用这个方法设定用户密码,您必须在这个部分中设置 all passwords。
3.7.6 添加用户和用户选项
您可以在 users 部分中创建和描述用户。您可以修改这个部分,以在初始系统配置中添加更多用户,也可以设置其他用户选项。
如果添加 users 部分,还必须在本节中设置默认用户选项。
根据数据源的要求,打开您的
user-data文件进行编辑,或者在cloud.cfg.d目录中添加以下指令。所有用户指令都包括文件顶部的
#cloud-config,以便cloud-init将文件识别为包含用户指令。当您在cloud.cfg.d目录中包含指令时,将该文件命名为*.cfg,且始终在文件的顶部包含#cloud-config。
添加或修改
users部分以添加用户。如果您希望
cloud-user与您指定的其他用户一起创建的默认用户,请确保将default添加为这个部分中的第一个条目。如果这不是第一个条目,则不会创建cloud-user。默认情况下,如果没有
selinux-user值,用户会被标记为unconfined_u。
#cloud-config
users:
- default
- name: user2
gecos: User N. Ame
selinux-user: staff_u
groups: users,wheel
ssh_pwauth: True
ssh_authorized_keys:
- ssh-rsa AA..vz user@domain.com
chpasswd:
list: |
root:password
cloud-user:mypassword
user2:mypassword2
expire: False将用户 user2 放入两个组,即 users 和 wheel。
3.7.7 运行第一个引导命令
您可以使用 runcmd 和 bootcmd 部分在启动和初始化过程中执行命令。
bootcmd 部分在初始化过程早期执行,并且在每次引导时默认运行。runcmd 部分在进程末尾附近执行,且仅在第一次引导和初始化时执行。
根据数据源的要求,打开您的
user-data文件进行编辑,或者在cloud.cfg.d目录中添加以下指令。所有用户指令都包括文件顶部的
#cloud-config,以便cloud-init将文件识别为包含用户指令。当您在cloud.cfg.d目录中包含指令时,将该文件命名为*.cfg,且始终在文件的顶部包含#cloud-config。添加
bootcmd和runcmd部分;包含您希望cloud-init执行的命令。
#cloud-config
users:
- default
- name: user2
gecos: User N. Ame
groups: users
chpasswd:
list: |
root:password
fedora:myfedpassword
user2:mypassword2
expire: False
bootcmd:
- echo New MOTD >> /etc/motd
runcmd:
- echo New MOTD2 >> /etc/motd3.7.8 添加额外的 sudoers
您可以通过在 users 部分添加 sudo 和 groups 条目,将用户配置为 sudoer。
根据数据源的要求,打开您的
user-data文件进行编辑,或者在cloud.cfg.d目录中添加以下指令。所有用户指令都包括文件顶部的
#cloud-config,以便cloud-init将文件识别为包含用户指令。当您在cloud.cfg.d目录中包含指令时,将该文件命名为*.cfg,且始终在文件的顶部包含#cloud-config。添加
sudo条目并指定用户访问权限。例如,sudo: ALL=(ALL)NOPASSWD:ALL允许用户不受限制的用户访问。添加
groups条目并指定包含用户的组。
#cloud-config
users:
- default
- name: user2
gecos: User D. Two
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
groups: wheel,adm,systemd-journal
ssh_pwauth: True
ssh_authorized_keys:
- ssh-rsa AA...vz user@domain.com
chpasswd:
list: |
root:password
cloud-user:mypassword
user2:mypassword2
expire: False3.7.9 仅配置 root 用户
您可以配置用户数据,以便您有一个 root 用户,而没有其他用户。
根据数据源的要求,打开您的
user-data文件进行编辑,或者在cloud.cfg.d目录中添加以下指令。所有用户指令都包括文件顶部的
#cloud-config,以便cloud-init将文件识别为包含用户指令。当您在cloud.cfg.d目录中包含指令时,将该文件命名为*.cfg,且始终在文件的顶部包含#cloud-config。在
users部分中,为root用户创建一个条目。以下示例中包含了一个
users部分,其中仅包含name选项。users: - name: root chpasswd: list: | root:password expire: False另外,还可为
root用户设置SSH密钥。users: - name: root ssh_pwauth: True ssh_authorized_keys: - ssh-rsa AA..vz user@domain.com
3.7.10 使用 container-storage-setup 设置存储
您可以通过引用 write_files 模块中的 container-storage-setup 实用程序来设置存储。
根据数据源的要求,打开您的
user-data文件进行编辑,或者在cloud.cfg.d目录中添加以下指令。所有用户指令都包括文件顶部的
#cloud-config,以便cloud-init将文件识别为包含用户指令。当您在cloud.cfg.d目录中包含指令时,将该文件命名为*.cfg,且始终在文件的顶部包含#cloud-config。添加或修改
write_files模块,使其包含container-storage-setup实用程序的路径。下面的例子将根逻辑卷大小设定为
6GB,而不是默认的3GB。write_files: - path: /etc/sysconfig/docker-storage-setup permissions: 0644 owner: root content: | ROOT_SIZE=6G
在 RHEL 7.4 之前,container-storage-setup 的名称为 docker-storage-setup。如果您使用 OverlayFS 进行存储,从 RHEL 7.4 开始,您现在可以使用 SELinux 处于 enforcing 模式的文件系统。
3.7.11 更改系统区域设置
您可以使用 locale 模块配置系统位置。
根据数据源的要求,打开您的 meta-data 文件进行编辑,或者在
cloud.cfg文件或cloud.cfg.d目录中添加以下指令。添加
locale指令,指定位置。以下示例将locale设置设置为使用UTF-8编码的ja_JP(日本)。
#cloud-config
locale: ja_JP.UTF-83.7.12 cloud-init 和 shell 脚本
您可以将列表值或字符串值添加到 bootcmd 或 runcmd。您还可以在 userdata 中提供一个 shell 脚本。
如果您的
bootcmd或runcmd使用一个列表值,则每个列表项都会依次运行,使用execve。如果您使用字符串值,则整个字符串将作为 shell 脚本运行。
如果要使用
cloud-init运行shell脚本,您可以提供一个shell脚本(使用shebang(#!)完成),而不是提供带有一个.yaml文件的cloud-init。
#cloud-config
# boot commands
# default: none
# This is very similar to runcmd, but commands run very early
# in the boot process, only slightly after a 'boothook' would run.
# - bootcmd will run on every boot
# - 'cloud-init-per' command can be used to make bootcmd run exactly once
bootcmd:
- echo 192.168.1.130 us.archive.ubuntu.com >> /etc/hosts
- [ cloud-init-per, once, mymkfs, mkfs, /dev/vdb ]#cloud-config
# run commands
# default: none
# runcmd contains a list of either lists or a string
# each item will be executed in order at rc.local like level with
# output to the console
# - runcmd only runs during the first boot
# - if the item is a list, the items will be properly executed as if
# passed to execve(3) (with the first arg as the command).
# - if the item is a string, it will be simply written to the file and
# will be interpreted by 'sh'
#
# Note, that the list has to be proper yaml, so you have to quote
# any characters yaml would eat (':' can be problematic)
runcmd:
- [ ls, -l, / ]
- [ sh, -xc, "echo $(date) ': hello world!'" ]
- [ sh, -c, echo "=========hello world=========" ]
- ls -l /root
# Note: Don't write files to /tmp from cloud-init use /run/somedir instead.
# Early boot environments can race systemd-tmpfiles-clean LP: #1707222.
- mkdir /run/mydir
- [ wget, "http://slashdot.org", -O, /run/mydir/index.html ]3.7.13 防止 cloud-init 更新配置文件
从备份镜像创建或恢复实例时,实例 ID 会改变。实例 ID 中的更改可能会导致 cloud-init 更新配置文件。
执行以下步骤以确保 cloud-init 在从备份创建或恢复时不会更新某些配置文件。
打开
/etc/cloud/cloud.cfg文件进行编辑。注释或删除在恢复实例时不需要
cloud-init更新的配置。例如,为了避免更新 SSH 密钥文件,请从
cloud_init_modules部分删除-ssh。
cloud_init_modules:
- disk_setup
- migrator
- bootcmd
- write-files
- growpart
- resizefs
- set_hostname
- update_hostname
- update_etc_hosts
- rsyslog
- users-groups
# - ssh验证
您可以检查查看 cloud-init 已更新的配置文件。为此,请检查 /var/log/cloud/cloud-init.log 文件。在实例启动期间记录更新的文件,消息以 Writing to 开始。例如:
2019-09-03 00:16:07,XXX - util.py[DEBUG]: Writing to /root/.ssh/authorized_keys - wb: [XXX] 554 bytes
2019-09-03 00:16:08,XXX - util.py[DEBUG]: Writing to /etc/ssh/sshd_config - wb: [XXX] 3905 bytes3.7.14 在 cloud-init 运行后修改从 KVM 客户机镜像创建的虚拟机
本节提供了在重新运行 cloud-init 前要修改 cloud-init 配置时的步骤示例。当您启动包含安装并启用 cloud-init 软件包的虚拟机时,cloud-init 会在虚拟机的初始引导时以默认状态运行。
登录到您的虚拟机。
添加或更改指令,例如修改
/etc/cloud目录中的cloud.cfg文件,或在/etc/cloud/cloud.cfg.d目录中添加指令。运行
cloud-init clean命令以清理目录,以便cloud-init可以再次运行。您也可以以root身份运行以下命令来清理虚拟机:`rm -Rf /var/lib/cloud/instances/*` `rm -Rf /var/lib/cloud/instance` `rm -Rf /var/lib/cloud/data/*`您可以将清理的镜像保存为新镜像,并将该镜像用于多个虚拟机。新虚拟机使用更新的
cloud-init配置运行cloud-init。重新运行
cloud-init或重新引导虚拟机。cloud-init重新运行,实现您所做的配置更改。
参考连接
云实例初始化工具cloud-init简介 - frankming - 博客园 (cnblogs.com)
Module reference - cloud-init 24.3.1 documentation (cloudinit.readthedocs.io)
cloud-init 中文手册,最全手册,比官网讲得好_cloud-init 文档-CSDN博客