cloud-init/userdata/metadata概述
cloud-init是一个运行在实例里面用来初始化实例的服务,它能够在云主机启动时加载和执行用户提供的数据,在实例启动的时候设置主机Hostname, 修改网络配置,下载一些包并进行安装等。这个服务在自动部署或者部署大规模实例的时候给用户提供了极大便捷性。
userdata即云主机启动时用户提供的数据,它是实现云主机个性化定制的基础,在userdata出现之前,可以认为我们购买的云主机环境和配置都是相同的,而企业或个人根据自身的使用场景和需求来输入有效的userdata后,我们的云主机在初次启动之后便是你需要的云主机,免去了用户自己手动配置的麻烦。
metadata是云平台提供的云主机属性信息,在创建云主机的时候做默认配置,目前包括hostname、镜像名称、网络类型、ip地址等18个属性值,以键值对的形式给出。
Datasource是userdata/metadata的出处,阿里云是通过一个http服务(IP:100.100.100.200)来提供数据源。在vpc网络下云服务器可以访问这个数据源获取相关的metadata和userdata信息。
userdata格式
userdata的格式具体的可见官方文档,这里主要说明userdata-scripts和cloud-config两种常用的格式。
userdata-scripts:适用于需要通过执行shell脚本初始化实例的用户,以“#!/bin/sh”开头,从用户数据来看目前大部分用户都是直接通过这种格式输入userdata的, 也适用于较复杂的部署场景。
cloud-config: 是cloud-init支持的特有格式,它把常用的个性化配置包装成YAML文件格式提供出来,通过这种形式可以更方便的完成常用配置,以“#cloud-config”为首行区分,紧随其后的是一个关联数组,提供的键包括ssh_authorized_keys、hostname、write_files、manage_etc_hosts等。
典型使用场景
场景一:ssh认证
由于目前阿里云主机暂不支持key pairs,用户可以通过userdata做ssh认证,将本地已生成的ssh公共秘钥置入到ECS中,免密登陆在批量操作云服务器时能够提供较高的便捷性。如:
#!/bin/sh
export ssh_directory="/root/.ssh"
export authorized_keys=${ssh_directory}/authorized_keys
echo ${user_public_key} >> ${ssh_directory}/authorized_keys
user_public_key='ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEA3FSyQwBI6Z+nCSjUUk8EEAnnkhXlukKoUPND/RRClWz2s5TCzIkd3Ou5+Cyz71X0XmazM3l5WgeErvtIwQMyT1KjNoMhoJMrJnWqQPOt5Q8zWd9qG7PBl9+eiH5qV7NZ mykey@host'
Cloud-config也提供了key支持ssh的认证,使用起来更便捷:
#cloud-config:
ssh_authorized_keys:
- ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEA3FSyQwBI6Z+nCSjUUk8EEAnnkhXlukKoUPND/RRClWz2s5TCzIkd3Ou5+Cyz71X0XmazM3l5WgeErvtIwQMyT1KjNoMhoJMrJnWqQPOt5Q8zWd9qG7PBl9+eiH5qV7NZ mykey@host
场景二:更新和配置软件源
这个场景也同样具有普适性,包括增加yum/apt的仓库,yum/apt源的更新和配置等。yum/apt源的更新通过cloud-config非常简单地完成。
更新yum/apt源:#cloud-config
package_upgrade: true
添加yum仓库:
yum_repos:
# 仓库名称
epel-testing:
baseurl: http://download.fedoraproject.org/pub/epel/testing/5/$basearch
enabled: false
failovermethod: priority
gpgcheck: true
gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL
name: Extra Packages for Enterprise Linux 5 - Testing
添加apt仓库:
apt:
primary:
- arches: [default]
uri: http://us.archive.ubuntu.com/ubuntu/
场景三:DNS配置
cloud-init启动方式下dns地址默认是由dhcp server来自动配置的,某些情况下用户需要配置自己的dns服务器,例如有一个用户场景是:对windows服务器的运维使用到加域操作,一般会使用局域网内部的域控服务器作为dns,那么对于需要加域操作的windows服务器即可统一使用userdata来配置。
#!bin/bash
export dns_directory="/etc/resolvconf/resolv.conf.d/base"
export dhcp_dicrectory="/etc/dhcp/dhclient.conf"
export user_dns = "nameserver 8.8.8.8"
echo ${user_dns} >> ${dns_directory}
export "supersede domain-name-servers 8.8.8.8" >> ${dhcp_directory}
上面是ubuntu中的一个例子,dhcpclient中supersede的配置是为了避免再次启动时dhcp重写了本地配置的dns地址。也可以使用cloud-config格式的userdata,cloud-config提供了manage-resolve-conf键来支持修改resolve-conf中的配置。
manage-resolv-conf: true
resolv_conf:
nameservers: ['8.8.4.4', '8.8.8.8']
searchdomains:
- foo.example.com
- bar.example.com
domain: example.com
options:
rotate: true
timeout: 1
场景四:安装配置应用
如果只是安装软件源仓库中的软件可以直接使用cloud-config格式的userdata,安装包以列表形式给出,也可以指定特定的版本即[<package>,<version>]的格式:
packages:
- pwgen
- pastebinit
- [libpython2.7, 2.7.3-0ubuntu3.1]
大部分的应用安装和部署需要一个流程化的步骤,例如使用场景比较多的docker,针对docker应用编写出该流程对应的shell脚本,可以通过userdata-scripts来安装配置。如果安装脚本比较复杂,通常不直接写在userdata-scripts中,而是部署在远程服务器上,通过curl下载到云服务器中再执行。
场景五:磁盘操作
#!/bin/sh
mkfs.ext4 /dev/vd1
mkdir $mountpoint
/dev/vd1 $mountpoint ext4 defaults 0 0
mount -a
chmod -R 777 $mountpoint
fdisk -S 56 /dev/vd1
cat ~/test_ftab >> /etc/fstab
touch ~/test_ftab
用户案例
下面以两个典型的案例为切入点,说明在为用户提供服务的过程使用userdata的好处:
案例一:userdata for 容器服务
容器服务是一种高性能可伸缩的容器管理服务,它支持在一组阿里云云服务器上通过Docker容器来运行或编排应用。其中一个重要的特性是支持多种服务托管方式:支持授权容器服务创建云服务器加入到指定集群也支持将已购买的云服务器添加到指定集群。这里云服务器的配置便是利用userdata实现,借此真正意义上地完成了服务器的一键托管。
容器服务在userdata的使用上已经比较成熟,实现的操作涵盖以上典型场景,包括:
安装内核更新,安装文件传输工具curl,设置集群内部节点的路由规则,安装、配置、启动docker等,所有的配置都在userdata中完成,所以服务器在初次启动之后便能完成它在集群管理中的功能,承担集群中的角色,省去了初始化的配置且在新建服务器添加到指定集群时,对用户基本是无感知的。
#!bin/bash
tokens='{"tokens": ["", ""]}'
ucp_controller_ip='192.168.33.*'
ip_addr=ifconfig eth0 | awk '/inet addr:/{print $2}' | tr -d 'addr:'
host_name=hostname
#更新软件源并安装依赖的软件包
apt-get update
apt-get install -y apt-transport-https,linux-image-extra-virtual,curl,unzip,jq
#通过keyserver拿到publickey做sshkey认证
curl -s 'https://sks-keyservers.net/***' | apt-key add --import
#从oss上获取docker安装脚本并执行
curl -sSL https://***.com/install.sh | sh
#配置自己的registry mirror
echo DOCKER_OPTS="'--registry-mirror https://***.aliyuncs.com'" > /etc/default/docker
service docker restart
usermod -aG docker $USER
echo tokens > /tmp/tokens token=`echo "tokens>/tmp/tokenstoken=‘echo"tokens" | jq '.tokens'[1] | xargs echo `
echo token > /tmp/manager_token cmd="curl -i -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'x-acs-region-id: cn-beijing' http://100.100.100.* -d '{\"data\" : \"token"}'"
eval $cmd
#swarm集群部署,将ECS节点添加到集群中
docker swarm join --token=$token ${ucp_controller_ip}:2377
echo $token > /tmp/fin_manager_token
案例二:userdata for 资源编排(ROS)
通过阿里云的资源编排服务,ROS,可以很方便的创建一组资源。但是创建资源只是第一步,需要把应用部署上去,userdata便是实现对应用一键构建的关键。
例如:用户需要在云服务器中搭建一个WordPress平台,首先需要安装 WordPress 所依赖的基础服务:Apache、MySQL 以及 PHP,然后下载最新版本的 WordPress 包并进行安装,最后根据 WordPress的搭建需求,对基础依赖服务进行相应的配置。用户只需要针对应用编写出该流程对应的 Shell 脚本,ROS也提供了相应的脚本模版,只将数据库的名称、用户名及其密码作为用户的输入参数, 一键生成usredata模版再配置ROS模版样例中。
#!/bin/bash
#用户输入参数
DatabaseUser=DatabaseUser DatabasePwd=DatabaseUserDatabasePwd=DatabasePwd
DatabaseName=$DatabaseName
WebRootPath='/var/www/html'
ApacheIndex='Options Indexes FollowSymLinks'
ApacheIndexReplace='Options -Indexes FollowSymLinks'
#安装Wordpress所依赖的服务
yum install -y curl httpd mysql-server php php-common php-mysql
yum install -y php-gd php-imap php-ldap php-odbc php-pear php-xml php-xmlrpc
#设置apache和mysql服务为开机自启动
chkconfig httpd on
chkconfig mysqld on
#下载Wordpress最新安装包,并配置其对数据库的访问
wget http://wordpress.org/latest.tar.gz
tar -xzvf latest.tar.gz
sed -i "s/database_name_here/DatabaseName/" wordpress/wp-config-sample.php sed -i "s/username_here/DatabaseName/"wordpress/wp−config−sample.phpsed−i"s/usernamehere/DatabaseUser/" wordpress/wp-config-sample.php
sed -i "s/password_here/{DatabasePwd:-DatabasePwdDef}/" wordpress/wp-config-sample.php
#设置WordPress安装位置
mv wordpress/wp-config-sample.php wordpress/wp-config.php
cp -a wordpress/ $WebRootPath
rm -rf wordpress* latest.tar.gz
#将Wordpress目录及其里面文件的所有者和所有组更改为 apache 用户和 apache 组
service httpd stop
usermod -d $WebRootPath apache
chown apache:apache -R $WebRootPath
#为了安全起见,关闭目录浏览功能
sed -i "s/ApacheIndex/ApacheIndex/ApacheIndexReplace/" /etc/httpd/conf/httpd.conf
service httpd start
#新建wordpress数据库,新增mysql用户,并赋权给它对应为 wordpress 数据库全部权限
service mysqld start
chmod 400 /etc/my.cnf
mysql -u root << EOF
CREATE DATABASE $DatabaseName default charset utf8 COLLATE utf8_general_ci;
CREATE USER DatabaseUser IDENTIFIED by 'DatabaseUserIDENTIFIEDby′DababasePwd';
grant all on $DatabaseName.* to DatabaseUser@localhost identified by 'DatabaseUser@localhostidentifiedby′DatabasePwd';
利用metadata来配置userdata
利用metadata来配置userdata在需要获取云服务器相关配置的时候比较便捷,可以实现云服务器的动态配置。例如某个场景下需要配置一条路由或者防火墙规则,为了得到云服务器的ip地址,我看到大多用户常规的做法是通过系统命令和正则表达式来提取ip信息:
ifconfig eth0 | awk '/inet addr:/{print $2}' | tr -d 'addr:'
但其实只需要在userdata-scripts中先安装curl,再去访问数据源,这些信息在meta-data中都可以轻松获取,ip地址的在metadata键为private-ipv4:
curl http://100.100.100.200/meta-data/private-ipv4
所有meta-data的种类可以通过访问数据源得到,如果metadata已经包括了你在动态配置中用到的云主机相关属性,则可以利用metadata编写userdata。
curl http://100.100.100.200/latest/meta-data
此外,对于创建云主机的时候设置过User-Data的实例,可以通过访问下面的地址查询userdata信息:
curl http://100.100.100.200/latest/usre-date
FAQ:
Q1:使用userdata有哪些限制?
A1:目前ECS的userdata功能支持vpc+io优化的实例,在购买这类实例时,可以使用userdata功能。此外,由于userdata依赖于cloud-init服务,镜像中需要安装cloud-init。
Q2:如何知道阿里云提供的镜像是否支持cloud-init?
A2:对于从购买页面购买ECS的用户,当您选择的实例属性满足vpc+io优化条件的情况下,选择了支持cloud-init的镜像,购买页面会有userdata输入框供您输入。对于使用OpenAPI购买ECS的用户,建议先调用查询可用镜像接口,可以在入参添加IsSupportCloudInit=true来查询支持cloud-init的镜像。
Q3:userdata只能在初次启动的时候输入么?
A3:不是。除了在购买ECS的时候就可以输入userdata ,对于已经使用的ECS,停机之后也可以选择"设置用户数据"操作,在下一次启动的时候生效,当然这部分userdata的功能不能够依赖于初次启动的逻辑,否则不会生效。
总结:
定制化云服务器已然成为云服务器的发展趋势,目前ECS大部分的系统镜像都支持cloud-init,同时也能够支持基于系统镜像创建自定义镜像的userdata功能,不过从目前的数据来看对cloud-init有感知的用户还比较少,然而其实userdata的使用场景非常广,只要你有配置云服务器的需求,尤其是在这种需求批量化模版化的情况下,userdata是再好不过的选择,希望大家可以多多结合自身的应用场景,使用userdata功能定制只属于你的云主机。