Packer是由HashiCorp出品的一个开源工具,用于创建相同配置的机器镜像,以供多个平台使用。在DevOps(开发运维一体化)实践中,Packer可以帮助自动化构建和部署过程,通过预先定义的模板来创建可移植和可重复使用的基础镜像,有助于保证在开发、测试和生产环境中的一致性。本文介绍在阿里云ECS使用Packer创建自定义镜像的DevOps常用配置(绑定镜像标签、配置只基于系统盘创建镜像、设置快照超时时间等),适用于使用Packer创建ECS自定义镜像的场景。
绑定镜像标签
适用场景:当您的自定义镜像达到一定的数量时,适当地标记镜像有利于镜像管理和检索。例如,记录镜像版本号和镜像包含的应用类型等。阿里云Builder提供了tags参数,支持为镜像绑定标签。生成的镜像自动包含阿里云ECS标签,更多有关标签的详情,请参见标签。
Packer字段名称:tags{"key":"value"}。
配置作用:ECS管理控制台镜像列表页面和API接口DescribeImages均支持查询镜像时返回标签以及根据标签过滤镜像。为镜像绑定标签能够和Terraform一起为企业级标准化DevOps流程提供支持。
配置示例:以下配置文件为最终生成的镜像和对应的快照绑定
version=v1.0.0
和app=web
两个标签。{ "variables": { "access_key": "{{env `ALICLOUD_ACCESS_KEY`}}", "secret_key": "{{env `ALICLOUD_SECRET_KEY`}}" }, "builders": [{ "type":"alicloud-ecs", "access_key":"{{user `access_key`}}", "secret_key":"{{user `secret_key`}}", "region":"cn-beijing", "image_name":"packer_basic", "source_image":"centos_7_03_64_20G_alibase_20170818.vhd", "ssh_username":"root", "instance_type":"ecs.t5-lc1m1.small", "internet_charge_type":"PayByTraffic", "io_optimized":"true", "tags": { "version": "v1.0.0", "app": "web" } }] }
配置只基于系统盘创建镜像
适用场景:默认情况下,Packer直接从ECS实例创建镜像。如果实例包含了数据盘,则创建的镜像会同时包含数据盘快照。
说明创建包含数据盘的实例通常有两种方式:
方式一:通过image_disk_mappings设置数据盘相关参数。更多信息,请参见《Packer文档》Alicloud Image Builder。
方式二:选择默认带有数据盘的实例规格。该类实例规格包含的数据盘大多为本地盘,例如ecs.d1ne.2xlarge。但是本地盘并不支持创建快照,所以无法直接通过此类实例创建镜像。
Packer字段名称:image_ignore_data_disks,数据类型为Boolean。
配置作用:如果您需要通过包含数据盘的实例创建镜像,但实际上创建镜像时不需要包含数据盘,可以在配置文件中加上
"image_ignore_data_disks": "true"
实现只基于系统盘创建镜像。配置示例:
{ "variables": { "access_key": "{{env `ALICLOUD_ACCESS_KEY`}}", "secret_key": "{{env `ALICLOUD_SECRET_KEY`}}" }, "builders": [ { "type":"alicloud-ecs", "access_key":"{{user `access_key`}}", "secret_key":"{{user `secret_key`}}", "region":"cn-hangzhou", "image_name":"packer_basic", "source_image":"aliyun_3_9_x64_20G_alibase_20231219.vhd", "associate_public_ip_address":true, "ssh_username":"root", "instance_type":"ecs.s6-c1m2.large", "internet_charge_type":"PayByTraffic", "io_optimized":true, "skip_image_validation":true, "image_disk_mappings": [ { "disk_snapshot_id": "s-bp1xxxxxx", "disk_device": "dev/xvdb" }], "image_ignore_data_disks": "true" } ] }
设置快照超时时间
适用场景:创建镜像依赖于快照,快照的创建时间依赖于磁盘大小。如果您的磁盘较大,创建快照所需时间会相应增加导致超时错误时,您可以设置
wait_snapshot_ready_timeout
字段调大超时时间。Packer字段名称:wait_snapshot_ready_timeout,数据类型为Integer,默认值为3600(秒)。
配置作用:将
wait_snapshot_ready_timeout
设置为7200秒。配置示例:
{ "variables": { "access_key": "{{env `ALICLOUD_ACCESS_KEY`}}", "secret_key": "{{env `ALICLOUD_SECRET_KEY`}}" }, "builders": [ { "type":"alicloud-ecs", "access_key":"{{user `access_key`}}", "secret_key":"{{user `secret_key`}}", "region":"cn-hangzhou", "image_name":"packer_basic", "source_image":"aliyun_3_9_x64_20G_alibase_20231219.vhd", "associate_public_ip_address":true, "ssh_username":"root", "instance_type":"ecs.s6-c1m2.large", "internet_charge_type":"PayByTraffic", "io_optimized":true, "skip_image_validation":true, "wait_snapshot_ready_timeout": 7200 } ] }
通过私网IP连接实例
适用场景:通过私网IP连接实例,可以省去公网IP。
Packer字段名称:ssh_private_ip,数据类型为Boolean。
配置作用:通过设置
"ssh_private_ip": true
,Packer不会分配EIP或者公网IP,而是通过私网IP连接实例。重要运行Packer的机器需要和Packer创建的机器在同一个网络环境,即同一个交换机下,才能使用私网连接。
配置示例:
{ "variables": { "access_key": "{{env `ALICLOUD_ACCESS_KEY`}}", "secret_key": "{{env `ALICLOUD_SECRET_KEY`}}" }, "builders": [ { "type":"alicloud-ecs", "access_key":"{{user `access_key`}}", "secret_key":"{{user `secret_key`}}", "region":"cn-hangzhou", "image_name":"packer_basic", "source_image":"aliyun_3_9_x64_20G_alibase_20231219.vhd", "ssh_username":"root", "instance_type":"ecs.s6-c1m2.large", "internet_charge_type":"PayByTraffic", "io_optimized":true, "skip_image_validation":true, "ssh_private_ip": true, "vpc_id":"vpc-xxxx", "vswitch_id":"vsw-xxxx" } ] }
设置停止实例选项
适用场景:默认情况下,Packer执行完provisioners后,会先停止实例再创建镜像。某些特殊场景,如在Windows实例中运行Sysprep,需要实例处于运行状态。
Sysprep的使用场景示例,请参见实例之间无法互相访问AD域或同时加入AD域怎么办?
Packer字段名称:disable_stop_instance,数据类型为Boolean。
配置作用:通过设置
"disable_stop_instance": true
,Packer不会主动停止实例,需要在provisioners中提供停止实例的命令或手动停止实例。配置示例:
{ "variables": { "access_key": "{{env `ALICLOUD_ACCESS_KEY`}}", "secret_key": "{{env `ALICLOUD_SECRET_KEY`}}" }, "builders": [ { "type":"alicloud-ecs", "access_key":"{{user `access_key`}}", "secret_key":"{{user `secret_key`}}", "region":"cn-hangzhou", "image_name":"packer_basic", "source_image":"aliyun_3_9_x64_20G_alibase_20231219.vhd", "ssh_username":"root", "instance_type":"ecs.s6-c1m2.large", "internet_charge_type":"PayByTraffic", "io_optimized":true, "skip_image_validation":true, "associate_public_ip_address":true, "disable_stop_instance": true } ] }
通过UserData启用WinRM
适用场景:出于安全考虑,Windows镜像默认关闭了WinRM(Windows Remote Management)。但连接Windows实例及之后在实例内部执行命令都依赖于WinRM。在实例创建时,您可以通过UserData启用WinRM。
Packer字段名称:user_data_file。
配置作用:通过配置
"user_data_file":"examples.ps1"
指定UserData文件的路径。配置示例:本示例假定UserData文件在给定的相对路径examples/alicloud/basic/winrm_enable_userdata.ps1下。
{ "variables": { "access_key": "{{env `ALICLOUD_ACCESS_KEY`}}", "secret_key": "{{env `ALICLOUD_SECRET_KEY`}}" }, "builders": [{ "type":"alicloud-ecs", "access_key":"{{user `access_key`}}", "secret_key":"{{user `secret_key`}}", "region":"cn-beijing", "image_name":"packer_test", "source_image":"win2008r2_64_ent_sp1_zh-cn_40G_alibase_20181220.vhd", "instance_type":"ecs.n1.tiny", "io_optimized":"true", "internet_charge_type":"PayByTraffic", "image_force_delete":"true", "communicator": "winrm", "winrm_port": 5985, "winrm_username": "Administrator", "winrm_password": "Test1234", "user_data_file": "examples/alicloud/basic/winrm_enable_userdata.ps1" }], "provisioners": [{ "type": "powershell", "inline": ["dir c:\\"] }] }
说明示例中与WinRM相关的参数含义如下:
"communicator": "winrm"
表示通过WinRM连接实例。"winrm_port": 5985
表示通信端口为5985。"winrm_username": "Administrator"
表示连接时使用Administrator账户。"winrm_password": "Test1234"
表示密码采用Test1234。
image_force_delete
表示如果存在同名镜像,则先删除已有镜像。
基于本地ISO文件制作镜像
适用场景:如果线下ISO文件环境为其他虚拟化环境,也可以通过Packer完成操作。
Packer字段名称:builders{"type":"qemu"},post-processors{"type":"alicloud-import"}。
配置示例:如果线下环境使用的是QEMU,请参见使用Packer创建并导入本地镜像。文档中包含两个重要的部分:
您需要使用本地虚拟化环境或软件对应的Builder,如QEMU Builder。
请通过定义Alicloud Import Post-Processor将生成的本地镜像文件导入阿里云ECS。
如果您采用导入自定义镜像流程,请在本地安装虚拟化环境,将ISO文件制作成阿里云支持的镜像文件格式后再导入,如QCOW2、VHD和RAW。导入流程请参见导入镜像流程。
通过SSH密钥对私网连接实例
适用场景:通过SSH密钥对私网连接实例。
Packer字段名称:ssh_keypair_name和ssh_private_key_file。
说明需要在控制台创建ssh_keypair_name,并保存好私钥。具体操作,请参见创建SSH密钥对。
配置作用:通过设置
ssh_private_key_file
,并将下载的私钥文件拷贝到执行Packer的机器上。其值为密钥的绝对路径。配置示例:
{ "variables": { "access_key": "{{env `ALICLOUD_ACCESS_KEY`}}", "secret_key": "{{env `ALICLOUD_SECRET_KEY`}}" }, "builders": [ { "type": "alicloud-ecs", "region": "cn-hangzhou", "image_name": "packer_basic", "source_image": "aliyun_3_x64_20G_alibase_20240819.vhd", "ssh_private_ip": true, "ssh_username": "root", "instance_type": "ecs.g6.large", "internet_charge_type": "PayByTraffic", "io_optimized": true, "skip_image_validation": true, "ssh_keypair_name": "{{user `ssh_keypair_name`}}", "ssh_private_key_file": "{{user `ssh_private_key_file`}}", "vpc_id": "{{user `vpc_id`}}", "vswitch_id": "{{user `vswitch_id`}}", "security_group_id": "{{user `security_group_id`}}" } ], "provisioners": [ { "type": "shell", "inline": [ "sleep 30", "yum install redis.x86_64 -y" ] } ] }
设置系统盘和数据盘
适用场景:自行选择系统盘类型和大小,并将某些快照数据作为数据盘挂载在临时ECS实例上,创建自定义镜像。
Packer字段名称:system_disk_mapping(系统盘配置)和image_disk_mappings(数据盘配置)。
配置作用:通过设置
system_disk_mapping
和image_disk_mappings
信息,新创建的自定义镜像会包含系统盘类型、容量大小、是否随实例释放、数据盘类型、数据盘分区名称等详细信息。配置示例:
{ "variables": { "access_key": "{{env `ALICLOUD_ACCESS_KEY`}}", "secret_key": "{{env `ALICLOUD_SECRET_KEY`}}" }, "builders": [ { "type": "alicloud-ecs", "region": "cn-hangzhou", "image_name": "packer_basic", "source_image": "aliyun_3_x64_20G_alibase_20240819.vhd", "associate_public_ip_address":true, "ssh_username": "root", "instance_type": "ecs.g6.large", "internet_charge_type": "PayByTraffic", "io_optimized": true, "skip_image_validation": true, "system_disk_mapping":{ "disk_category":"cloud_essd", "disk_size":20, "disk_delete_with_instance":true }, "image_disk_mappings":[{ "disk_snapshot_id":"s-xxxxxxxxxxxxxxx", "disk_device":"dev/xvdb", "disk_category":"cloud_essd" }] } ], "provisioners": [ { "type": "shell", "inline": [ "sleep 30", "yum install redis.x86_64 -y" ] } ] }
使用镜像族系创建和定义目标镜像的镜像族系
适用场景:无需关注
source_image
迭代变化,通过镜像族系即可实现镜像迭代更新。Packer字段名称:image_family和target_image_family。
配置作用:通过设置
image_family
获取最新版本的镜像创建ECS实例,并为新创建的自定义镜像赋值target_image_family
绑定镜像族系。配置示例:
{ "variables": { "access_key": "{{env `ALICLOUD_ACCESS_KEY`}}", "secret_key": "{{env `ALICLOUD_SECRET_KEY`}}" }, "builders": [ { "type": "alicloud-ecs", "region": "cn-hangzhou", "image_name": "packer_basic", "associate_public_ip_address":true, "ssh_username": "root", "instance_type": "ecs.g6.large", "internet_charge_type": "PayByTraffic", "io_optimized": true, "skip_image_validation": true, "image_family":"acs:centos_7_9_x64", "target_image_family":"test_packer_basic" } ], "provisioners": [ { "type": "shell", "inline": [ "sleep 30", "yum install redis.x86_64 -y" ] } ] }
profile配置
适用场景:适用于多套环境配置,且互不干扰,例如多地域多账号配置。
Packer字段名称:profile。
配置作用:Packer的配置文件,如果配置了该字段,会优先从配置文件中获取配置。例如在配置文件配置的参数在Packer模板中也有配置,该配置文件的配置会优先生效。文件路径必须是
~/.aliyun/config.json
。配置示例:
{ "builders": [ { "type": "alicloud-ecs", "profile": "packer_sk", "region": "cn-hangzhou", "image_name": "packer_basic", "source_image": "aliyun_3_x64_20G_alibase_20240819.vhd", "ssh_username": "root", "instance_type": "ecs.g6.large", "internet_charge_type": "PayByTraffic", "io_optimized": true, "skip_image_validation": true, "associate_public_ip_address":true } ], "provisioners": [ { "type": "shell", "inline": [ "sleep 30", "yum install redis.x86_64 -y" ] } ] }
其中
"profile": "packer_sk"
中的packer_sk
是配置文件的名称,该配置文件的路径必须是~/.aliyun/config.json
。配置文件内容如下:{ "current": "ALI", "profiles": [ { "name": "packer_sk", "mode": "AK", "access_key_id": "xxxxxxxxxxxxxxxxxxxxxxx", "access_key_secret": "xxxxxxxxxxxxxxxxxxxx", "sts_token":"", "sts_region": "", "ram_role_name": "", "ram_role_arn": "", "ram_session_name": "", "source_profile": "", "private_key": "", "key_pair_name": "", "expired_seconds": 0, "verified": "", "output_format": "json", "language": "en", "site": "", "retry_timeout": 0, "connect_timeout": 0, "retry_count": 0, "process_command": "", "credentials_uri": "" } ], "meta_path": "" }
通过RAM角色实现无AccessKey调用
适用场景:如果您不期望在模板或环境变量中配置AccessKey,可以为ECS实例绑定RAM角色获取临时AccessKey。为ECS实例绑定RAM角色的操作,请参见实例RAM角色。
说明该场景不支持本地操作,必须在ECS实例中执行。
RAM角色必须授予以下权限。为RAM角色的授权操作,请参见RAM角色。
Packer字段名称:ram_role_name。
配置作用:获取ECS绑定RAM角色的临时AccessKey执行Packer,实现无AccessKey调用。
配置示例:
{ "builders": [ { "type": "alicloud-ecs", "region": "cn-hangzhou", "image_name": "packer_basic", "source_image": "aliyun_3_x64_20G_alibase_20240819.vhd", "associate_public_ip_address": true, "ssh_username": "root", "instance_type": "ecs.g6.large", "internet_charge_type": "PayByTraffic", "io_optimized": true, "ram_role_name": "ImageTestAle", "skip_image_validation": true } ], "provisioners": [ { "type": "shell", "inline": [ "sleep 30", "yum install redis.x86_64 -y" ] } ] }
给临时ECS绑定RAM角色
适用场景:给临时实例绑定RAM角色,在Shell脚本中获取临时AccessKey做业务处理。为ECS实例绑定RAM角色的操作,请参见实例RAM角色。
说明如果您是RAM用户,还需要授予RAM用户
ram:PassRole
权限。授权操作可参见3. 为RAM用户授权。授权的策略内容如下:Packer字段名称:ecs_ram_role_name。
配置作用:获取临时AccessKey做业务处理。
配置示例:
{ "variables": { "access_key": "{{env `ALICLOUD_ACCESS_KEY`}}", "secret_key": "{{env `ALICLOUD_SECRET_KEY`}}" }, "builders": [ { "type": "alicloud-ecs", "region": "cn-hangzhou", "image_name": "packer_basic", "source_image": "aliyun_3_x64_20G_alibase_20240819.vhd", "ssh_username": "root", "instance_type": "ecs.g6.large", "internet_charge_type": "PayByTraffic", "io_optimized": true, "ecs_ram_role_name": "packer-test", "skip_image_validation": true, "associate_public_ip_address": true } ], "provisioners": [ { "type": "shell", "inline": [ "sleep 30", "yum install redis.x86_64 -y" ] } ] }
B账号扮演A账号创建镜像
适用场景:跨账号访问、临时授权等场景。
说明该场景有如下要求:
A账号已对B账号创建了一个可信实体类型的RAM角色,并为RAM角色授予相应的资源操作权限。操作步骤可参考账号A创建RAM角色并授权。授权的策略内容如下:
如果B账号是RAM用户,还需要授予RAM用户
sts:AssumeRole
权限。授权的策略内容如下:不可配置
ssh_private_ip: true
,必须配置associate_public_ip_address:true
,通过公网连接。此模板在本地和阿里云ECS实例中皆可运行。在阿里云ECS实例中运行时,必须配置ECS实例的公网带宽大于0,否则访问RAM服务获取临时AccessKey失败。
Packer字段名称:ram_role_arn(RAM角色的ARN)和ram_session_name(RAM角色的名称)。
配置作用:B账号扮演A账号创建自定义镜像。
配置示例:
{ "variables": { "access_key": "{{env `ALICLOUD_ACCESS_KEY`}}", "secret_key": "{{env `ALICLOUD_SECRET_KEY`}}" }, "builders": [ { "type": "alicloud-ecs", "region": "cn-hangzhou", "image_name": "packer_basic", "source_image": "aliyun_3_x64_20G_alibase_20240819.vhd", "associate_public_ip_address":true, "ssh_username": "root", "ram_role_arn": "acs:ram::186xxxxxxxxxx07:role/packer-test", "ram_session_name": "packer-test", "instance_type": "ecs.g6.large", "internet_charge_type": "PayByTraffic", "io_optimized": true, "skip_image_validation": true } ], "provisioners": [ { "type": "shell", "inline": [ "sleep 30", "yum install redis.x86_64 -y" ] } ] }
相关文档
更多参数和样例,请参见Packer官方文档Alicloud Image Builder和Examples。