使用Packer创建自定义镜像

Packer是一款轻量级的镜像定义工具,能够运行在常用的主流操作系统(例如Windows、Linux和macOS)上,并行高效地创建多平台的虚拟机镜像。本文为您介绍如何在ECS实例中安装Packer、定义Packer模板并使用Packer创建自定义镜像。

前提条件

已创建AccessKey,并获取AccessKey ID和AccessKey Secret。具体操作,请参见创建AccessKey

说明
  • 由于AccessKey权限过大,为防止数据泄露,建议您先创建RAM用户,再使用RAM用户创建AccessKey。创建RAM用户的具体操作,请参见创建RAM用户

  • RAM用户的AccessKey Secret只在创建时显示,不支持查看,请妥善保管。

背景信息

Packer工具包含Builders(生成器)Provisioners(配置器)Post-Processors(后处理器)等组件,通过HCL(HashiCorp Configuration Language)或者JSON格式的模板文件较大地降低了创建自定义镜像的难度,并且将创建镜像的过程从人工的随机过程变成可以配置管理代码,从而减少了用户应用上云的障碍。关于Packer的更多信息,请参见Packer官方文档

操作步骤

步骤一:安装Packer

  1. 远程连接ECS实例。

    具体操作,请参见通过密码认证登录Linux实例

  2. 运行以下命令,进入/usr/local/bin目录。

    cd /usr/local/bin
    说明

    /usr/local/bin目录为环境变量目录,您可以将Packer安装到该目录下或其他已添加到环境变量的目录下。

  3. 运行以下命令,获取Packer安装包。

    您也可以访问Packer下载页面获取与云服务器ECS操作系统及架构类型相对应的Packer安装包,本操作以packer_1.8.5_linux_amd64.zip为例。

    wget https://releases.hashicorp.com/packer/1.8.5/packer_1.8.5_linux_amd64.zip
  4. 运行以下命令,解压Packer安装包。

    unzip packer_1.8.5_linux_amd64.zip
  5. 运行以下命令查询Packer版本号,验证Packer的安装状态。

    packer -v
    • 如果返回Packer版本号,表示您已正确安装Packer。

    • 如果返回信息提示command not found,表示Packer未正确安装,请检查Packer所在目录是否被添加到环境变量中。

步骤二:定义Packer模板

使用Packer创建自定义镜像时,需要创建一个HCL格式或者JSON格式的模板文件。在该模板文件中,您需要指定创建自定义镜像的生成器和配置器。更多信息,请参见Builders(生成器)Provisioners(配置器)。Packer具有多种配置器类型可用于配置自定义镜像的内容生成方式,以下操作以常用的Shell配置器为例,定义Packer模板。

  1. 运行以下命令,导入您的AccessKey ID。

    export ALICLOUD_ACCESS_KEY=<AccessKey ID>

    请将<AccessKey ID>替换为您实际的AccessKey ID。查询RAM用户AccessKey ID的具体操作,请参见查看RAM用户的AccessKey信息

  2. 运行以下命令,导入您的AccessKey Secret。

    export ALICLOUD_SECRET_KEY=<AccessKey Secret>

    请将<AccessKey Secret>替换为您实际的AccessKey Secret。RAM用户的AccessKey Secret只在创建时显示,不支持查询。更多信息,请参见创建AccessKey

  3. 运行以下命令,创建名为alicloud的文件。

    说明

    您可以选择以下任意一种文件格式来创建alicloud文件,如果创建HCL格式的文件,后续就需要按照HCL模板来执行。

    HCL文件

    vi alicloud.pkr.hcl

    JSON文件

    vi alicloud.json
  4. i键进入编辑模式,将以下示例Packer模板内容复制到alicloud文件并根据实际情况修改参数。

    HCL文件

    variable "access_key" {
      type    = string
      default = "${env("ALICLOUD_ACCESS_KEY")}"
    }
    
    variable "secret_key" {
      type    = string
      default = "${env("ALICLOUD_SECRET_KEY")}"
    }
    
    source "alicloud-ecs" "autogenerated_1" {
      associate_public_ip_address = true
      image_name                  = "packer_basic"
      instance_type               = "ecs.g6.large"
      internet_charge_type        = "PayByTraffic"
      io_optimized                = true
      region                      = "cn-qingdao"
      skip_image_validation       = true
      source_image                = "aliyun_3_x64_20G_alibase_20220907.vhd"
      ssh_username                = "root"
    }
    
    build {
      sources = ["source.alicloud-ecs.autogenerated_1"]
      provisioner "shell" {
        inline = ["sleep 30", "yum install redis.x86_64 -y"]
      }
    }

    JSON文件

    {
         "variables": {
           "access_key": "{{env `ALICLOUD_ACCESS_KEY`}}",
           "secret_key": "{{env `ALICLOUD_SECRET_KEY`}}"
         },
         "builders": [{
           "type":"alicloud-ecs",
           "region":"cn-qingdao",
           "image_name":"packer_basic",
           "source_image":"aliyun_3_x64_20G_alibase_20220907.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
         }],
         "provisioners": [{
           "type": "shell",
           "inline": [
             "sleep 30",
             "yum install redis.x86_64 -y"
           ]
         }]
       }

    Packer模板支持自定义的参数说明如下。 更多参数说明,请参见Packer官网

    参数

    类型

    是否必填

    描述

    region

    string

    指定创建自定义镜像时使用临时资源的地域,例如cn-qingdao

    image_name

    string

    指定创建的自定义镜像名称,例如packer_basic

    instance_type

    string

    创建自定义镜像时生成的临时ECS实例的类型,例如ecs.g6.large规格。镜像创建完成后,该实例会被自动释放。

    说明

    使用Packer创建自定义镜像过程中,会调用CreateInstance接口创建ECS实例,该实例包含了用于创建自定义镜像的操作系统和预装软件等。该实例类型为按量付费,因此会产生部分费用。请确保您的阿里云账户余额(即现金余额)和代金券的总值不得小于100.00元人民币。

    ssh_username

    string

    SSH连接实例的用户名。

    internet_charge_type

    string

    创建自定义镜像时临时实例的公网带宽付费类型。

    • PayByBandwidth:按固定带宽计费。

    • PayByTraffic:按使用流量计费。

    source_image

    string

    二选一必填

    基础镜像的ID,该镜像用于创建临时ECS实例。可以从ECS控制台公共镜像列表获得,也可以通过DescribeImages接口查询获得。

    重要

    配置时需注意所选镜像类型需支持ECS实例的类型,例如ARM镜像(镜像ID携带_arm64_)需选用ARM类型的实例,否则无法成功创建自定义镜像。

    image_family

    string

    镜像族系名称,通过设置该参数来获取当前镜像族系内最新可用镜像来创建实例。

    说明

    镜像族系的名称长度为2~128 个字符。镜像族系名称不能以特殊字符、数字、http://、https://开头,只可包含特殊字符中的"."、"_"、"-"和":"。

    target_image_family

    string

    指定创建的自定义镜像的镜像族系。

    说明

    镜像族系的名称长度为2~128 个字符。镜像族系名称不能以特殊字符、数字、http://、https://开头,只可包含特殊字符中的"."、"_"、"-"和":"。

    ssh_private_ip

    boolean

    三选一必填

    是否通过私网SSH连接实例。默认值:false。

    • false:分配公网IP,通过公网连接实例。

    • true:不会分配EIP或公网IP,而是通过私网IP连接实例。

    说明

    运行Packer的机器需要和Packer创建的机器在同一个网络环境,即同一个交换机下,才能使用私网连接。

    associate_public_ip_address

    boolean

    是否绑定公网IP。

    eip_id

    string

    弹性公网ID。

    skip_image_validation

    boolean

    是否跳过镜像检查。默认值:false。

    system_disk_mapping

    object

    系统盘配置。例如:

    "system_disk_mapping": {
     "disk_name": "sysdisk",
     "disk_category": "cloud_essd",
     "disk_size": 40
    }

    详细配置信息,请参见云盘配置

    image_disk_mappings

    list

    镜像数据盘配置。例如:

    "image_disk_mappings": {
     "disk_name": "datadisk",
     "disk_snapshot_id": "s-bp1xxxxxx",
     "disk_device": "dev/xvdb"
    }

    详细配置信息,请参见云盘配置

    image_ignore_data_disks

    boolean

    创建的镜像是否包含数据盘快照。默认值:false。

    • false:创建的镜像会同时包含数据盘快照。

    • true:创建镜像不需要包含数据盘,只基于系统盘创建镜像。

    profile

    string

    执行Packer的配置文件,如果配置了该参数,会优先从该配置中获取配置。

    ram_role_name

    string

    RAM角色名称。获取本机RAM角色的临时AK,执行Packer模板。

    说明

    仅适用于绑定了RAM角色的ECS实例执行Packer的场景。

    ram_role_arn

    string

    RAM角色ARN。与ram_session_name组合使用,A账号扮演B账号创建镜像。

    ram_session_name

    string

    RAM角色名称。与ram_role_arn组合使用,A账号扮演B账号创建镜像。

    ecs_ram_role_name

    string

    实例RAM角色名称。您可以使用RAM的API接口ListRoles查询您已创建的实例RAM角色。

    ssh_keypair_name

    string

    SSH连接的密钥对名称。

    ssh_private_key_file

    string

    SSH连接的密钥对的私钥文件路径。

    custom_endpoint_ecs

    string

    用自定义创建ECS的Endpoint。

    security_group_id

    string

    创建临时ECS实例所属于的安全组ID。

    security_group_name

    string

    安全组名称。若不指定安全组ID,则会按这个名称创建一个安全组。

    vpc_id

    string

    VPC的ID。

    vpc_name

    string

    VPC名称。若不指定vpc_id,则会按这个名称创建一个VPC。

    vswitch_id

    string

    虚拟交换机ID。

    vswitch_name

    string

    交换机名称。若不指定vswitch_id,则会按这个名称创建一个交换机。

    user_data

    string

    实例自定义数据。必须填写已采用Base64编码后的数据,且在进行Base64编码前自定义数据内容的大小不能超过32 KB。有关实例自定义数据的使用限制、格式以及运行频率的详细信息,请参见自定义实例初始化配置

    说明

    为保证传输过程中UserData的安全性,请避免直接以明文形式传送敏感数据,如密码和私钥。若需传送此类信息,建议先行加密处理,并采用Base64编码方式,随后在实例内部进行解密以确保信息安全。

    user_data_file

    string

    实例自定义数据文件,UserData文件形式。

    boot_mode

    string

    指定镜像的启动模式。取值范围:BIOS,UEFI,UEFI-Preferred。

    wait_snapshot_ready_timeout

    Integer

    设置快照超时时间。默认值为3600(秒)。

    instance_name

    string

    创建临时ECS实例的名称,默认值为实例的InstanceId

    说明

    名称长度为 2~128 个字符,支持Unicode中letter分类下的字符(其中包括英文、中文和数字等)。可以包含半角冒号(:)、下划线(_)、半角句号(.)或者短划线(-)。

    image_force_delete

    boolean

    是否删除同名镜像。默认值:false。

    • true:如果存在同名镜像,则先删除已有镜像,然后创建目标镜像。

    • false:如果存在同名镜像,创建目标镜像失败。

    image_force_delete_snapshots

    boolean

    是否删除同名镜像关联的快照。默认值:false。

    • true:如果存在同名镜像,则先删除已有镜像和已有镜像关联的快照,然后创建目标镜像。

    • false:如果存在同名镜像,创建目标镜像失败。

    image_version

    string

    创建的自定义镜像的版本。

    resource_group_id

    string

    资源组ID。

    force_stop_instance

    boolean

    强制停机。默认值:false。

    disable_stop_instance

    boolean

    默认情况下,Packer执行完provisioners后,会先停止实例再创建镜像。某些特殊场景,如在Windows实例中运行Sysprep,需要实例处于运行状态。默认值:false。

    run_tags

    object

    镜像标签。例如{"key":"value"}

    image_description

    string

    镜像描述。

    image_share_account

    []string

    创建的自定义镜像需要共享的用户列表。例如["123456"]

    image_copy_regions

    []string

    创建的自定义镜像需要复制的目标地域。例如["cn-beijing"]

    provisioners

    string

    创建自定义镜像时使用的Packer配置器类型。主要包括:

    • File

    • PowerShell

    • Shell

    • Local Shell

    • Windows Shell

    更多信息,请参见Provisioners(配置器)

    云盘配置

    参数

    类型

    是否必填

    描述

    disk_name

    string

    云盘名称。

    说明

    名称长度为 2~128 个字符,支持Unicode中letter分类下的字符(其中包括英文、中文和数字等)。可以包含半角冒号(:)、下划线(_)、半角句号(.)或者短划线(-)。

    disk_category

    string

    云盘类型。取值范围:

    • cloud_efficiency:高效云盘。

    • cloud_ssd:SSD 云盘。

    • cloud_essd:ESSD 云盘。

    • cloud:普通云盘。

    disk_size

    int

    云盘大小,单位为 GiB。该参数的取值必须大于或者等于 max{20, ImageSize}。默认值:max{40, ImageSize}。

    disk_description

    string

    云盘的描述,默认为空。

    说明

    长度为 2~256 个英文或中文字符,不能以http://https://开头。

    disk_snapshot_id

    string

    创建数据盘使用的快照。

    disk_delete_with_instance

    boolean

    表示数据盘是否随实例释放。取值范围:

    • true:数据盘随实例释放。

    • false:数据盘不随实例释放。

    默认值为 true。

    disk_device

    string

    数据盘的挂载点。

    disk_encrypted

    boolean

    数据盘是否加密。取值范围:

    • true:加密。

    • false:不加密。

    默认值:false。

  5. Esc键,并输入:wq后按下回车键,保存并退出。

步骤三:使用Packer创建自定义镜像

使用Packer模板文件生成自定义镜像的操作步骤如下:

  1. 运行以下命令,创建自定义镜像。

    HCL文件

    packer build alicloud.pkr.hcl

    示例运行结果如下,以下示例表示将在华北1(青岛)地域创建镜像ID为m-m5e3f0gu2dxs4z0s****的自定义镜像。

    alicloud-ecs.autogenerated_1: output will be in this color.
    
    ==> alicloud-ecs.autogenerated_1: Prevalidating source region and copied regions...
    ==> alicloud-ecs.autogenerated_1: Prevalidating image name...
        alicloud-ecs.autogenerated_1: Found image ID: aliyun_3_x64_20G_alibase_20220907.vhd
    ==> alicloud-ecs.autogenerated_1: Creating temporary keypair: packer_64bf3d40-2fe7-8251-276d-df59a0bb****
    ---------------------------
    ==> alicloud-ecs.autogenerated_1: Provisioning with shell script: /tmp/packer-shell3356722207
        alicloud-ecs.autogenerated_1: Last metadata expiration check: 0:00:11 ago on Tue 25 Jul 2023 11:12:18 AM CST.
    ---------------------------
        alicloud-ecs.autogenerated_1: Complete!
    ==> alicloud-ecs.autogenerated_1: Stopping instance: i-m5e87pt498pr8zv0****
    ==> alicloud-ecs.autogenerated_1: Waiting instance stopped: i-m5e87pt498pr8zv0****
    ==> alicloud-ecs.autogenerated_1: Creating image: packer_basic
        alicloud-ecs.autogenerated_1: Detach keypair packer_64bf3d40-2fe7-8251-276d-df59a0bb**** from instance: i-m5e87pt498pr8zv0****
    ==> alicloud-ecs.autogenerated_1: Cleaning up 'EIP'
    ==> alicloud-ecs.autogenerated_1: Cleaning up 'instance'
    ==> alicloud-ecs.autogenerated_1: Cleaning up 'security group'
    ==> alicloud-ecs.autogenerated_1: Cleaning up 'vSwitch'
    ==> alicloud-ecs.autogenerated_1: Cleaning up 'VPC'
    ==> alicloud-ecs.autogenerated_1: Deleting temporary keypair...
    Build 'alicloud-ecs.autogenerated_1' finished after 4 minutes 32 seconds.
    
    ==> Wait completed after 4 minutes 32 seconds
    
    ==> Builds finished. The artifacts of successful builds are:
    --> alicloud-ecs.autogenerated_1: Alicloud images were created:
    
    cn-qingdao: m-m5e3f0gu2dxs4z0s****

    JSON文件

    packer build alicloud.json

    示例运行结果如下,以下示例表示将在华北1(青岛)地域创建镜像ID为m-m5e3f0gu2dxs4z0s****的自定义镜像。

    alicloud-ecs output will be in this color.
    
    ==> alicloud-ecs: Prevalidating image name...
        alicloud-ecs: Found image ID: aliyun_3_x64_20G_alibase_20220907.vhd
    ==> alicloud-ecs: Creating temporary keypair: packer_6345090e-ec1f-8ea0-348c-f85ba047****
    ==> alicloud-ecs: Creating vpc
    ---------------------------
    ==> alicloud-ecs: Provisioning with shell script: /tmp/packer-shell090019677
        alicloud-ecs: Last metadata expiration check: 0:00:15 ago on Tue 11 Oct 2022 02:12:51 PM CST.
    ---------------------------
        alicloud-ecs: Complete!
    ==> alicloud-ecs: Deleting image snapshots.
    ==> alicloud-ecs: Creating image: packer_basic
        alicloud-ecs: Detach keypair packer_6345090e-ec1f-8ea0-348c-f85ba047**** from instance: i-m5e7it5p4dpwetfr****
    ==> alicloud-ecs: Cleaning up 'EIP'
    ==> alicloud-ecs: Cleaning up 'instance'
    ==> alicloud-ecs: Cleaning up 'security group'
    ==> alicloud-ecs: Cleaning up 'vSwitch'
    ==> alicloud-ecs: Cleaning up 'VPC'
    ==> alicloud-ecs: Deleting temporary keypair...
    Build 'alicloud-ecs' finished.
    
    ==> Builds finished. The artifacts of successful builds are:
    --> alicloud-ecs: Alicloud images were created:
    
    cn-qingdao: m-m5e3f0gu2dxs4z0s****
  2. 查看已创建的自定义镜像。

    1. 登录ECS管理控制台

    2. 在左侧导航栏,选择实例与镜像 > 镜像

    3. 在顶部菜单栏左上角处,选择alicloud文件中指定的地域,例如华北1(青岛)。

    4. 自定义镜像页签下,镜像列表中查看生成的名称为packer_basic的自定义镜像。