用Packer自动构建公有云系统镜像

2,764 阅读2分钟

背景

 公司现在用到的公有云有腾讯云金山云阿里云华为云,最近想把作业平台的agent内置进镜像里面,发现运维同事还是在手动操作,因为以前学习terraform的时候,了解过packer,觉得这些工作可以用packer来做自动化打包,通过了解现在的镜像制作过程如下

手动制作镜像.png 这只是一个镜像的制作过程,现在的镜像制作是,根据不同的用户,创建多个镜像,比如给数据库管理用的,里面要有一个dba用户,给业务运维的要有一个sa用户,IDC运维要有一个sre用户

未命名文件(29).png

也就是说,假如我要制作 4 个云的镜像,图1的流程最少要执行 12 次, 交互时间严重不确定

自动打包镜像

source "tencentcloud-cvm" "root" {
  region                      = "ap-guangzhou"
  zone                        = "ap-guangzhou-7"
  source_image_id             = "img-l8og963d"
  secret_id                   = var.TENCENT_AK
  secret_key                  = var.TENCENT_SK
  instance_type               = "S6.MEDIUM2"
  ssh_username                = "root"
  ssh_port                    = 22
  force_poweroff              = true
  associate_public_ip_address = true
  internet_max_bandwidth_out  = 10
  security_group_name         = "sg-${local.USER}-${var.JOB_ID}"
  vpc_name                    = "vpc-${local.USER}-${var.JOB_ID}"
  subnet_name                 = "subnet-${local.USER}-${var.JOB_ID}"
  image_name                  = "centos79-${local.USER}"
  instance_name               = "centos79-${local.USER}-${var.JOB_ID}"
  image_copy_regions          = ["ap-beijing", "ap-shanghai"]
}

build {
  sources = [
    "source.tencentcloud-cvm.root"
  ]
  provisioner "file" {
    source      = "../scripts.tar.gz"
    destination = "/opt/"
  }
  provisioner "shell" {
    script = "../setup.sh"
    env    = {
      "SERVER_USER" : var.SERVER_USER
    }
  }
}

只要执行 packer build . ,大概10分钟左右就可以构建出一个镜像,并复制到 上海北京

根据用户配置打包多个镜像

上述打包只是打包了一个用户,如果要打包多个用户,我们只要同时运行多个 packer build . 就好了,这里可以用 GitLab 的动态流水线功能

将用户信息写到一个配置文件中,用 python 生成多个 job,然后用 trigger 指令触发

这些作业都是并行执行的,所以时间不会累加

build.pkr.hcl 文件有几个问题点要提一下,为什么 instance_namevpc, subnet, security_group都加了一些变量,在测试的时候发现,并行执行多个构建的时候,packer 有的时候会共享一台主机,原因还没查

镜像跨区域复制

有人会问了,腾讯云不是有 image_copy_regions 吗,怎么还要 BB 一下镜像复制呢?

跨区域复制不是标配,腾讯云是有,金山云没有,所以金山云的复制功能,要自己用金山云的SDK来实现

镜像共享

镜像功能也是,腾讯云虽然有 image_share_accounts ,假如你是在广州构建的,把镜像复制到上海北京,这个账号共享,只是共享了广州的镜像给用户,上海北京的没有,所以这个要用腾讯去的SDK自己实现,遍历地区,根据镜像名查找镜像ID,然后调用镜像共享接口,金山云同理

腾讯云

金山云

全自动化执行

上面这个功能都做完后,假如镜像名称在云厂商不存在,第一次执行应该是没有问题的,但是第二次执行,你会发现,流水报错了

==> tencentcloud-cvm.root: Image name centos79-user1 has exists

腾讯云的镜像不允许名称重复,金山云没这个问题

所以为了整个过程的自动化,你可能会想,把镜像名重命名一下就好了,这是个好想法

但是你执行个4次左右,你又会发现报错了,腾讯云某个地区下,镜像最多只可以是10

所以还是删除镜像吧,金山云的也删了,多个同名的镜像,在创建主机的时候,也容易把自己整蒙

镜像删除流程

未命名文件(30).png

腾讯云

金山云

构建环境清除

在实际执行过程中,发现腾讯云的安全组有可能会删除失败

==> tencentcloud-cvm.root: Failed to delete securitygroup(sg-jf5bd2ar), please delete it manually: retry count exhausted. Last err: [TencentCloudSDKError] Code=ResourceInUse, Message=The specified resource `sg-jf5bd2ar` is already in use., RequestId=

为了保证构建环境的干净,最后调用了腾讯云的SDK,删除安全组

$ python3 clear.py

detect security group: sg-packer-gitlab-user1-26063

remove security group: sg-packer-gitlab-user1-26063

遇到的一些问题

  1. 金山云 public_ip_charge_type 不可以用 DailyTrafficMonthly

会报这个错

Error creating new eip: PackageNotExists: You do not have the approprivate permissions

DailyPaidByTransfer, 别问我为什么,我也不知道

  1. 金山云 system_disk_typeinstance_type 有一定的依赖,一开始 instance_type 用的是 S3.2Asystem_disk_typeSSD3.0,老是报
SystemDiskTypeInvalid: An invalid or out-of-range value was supplied for the "SystemDisk.DiskType" parameter.

找了半天不知道原因,后面在网页上创建资源,才发现 S3.2A 不可以选 SSD3.0,把 instance_type 换成 C5.2B 就好了

自动化流程

自动构建公有云系统镜像.png

思考

packer + terraform 感觉就像 Docker + Kubernetes

packer 像是 Docker

docker build出来的是 docker镜像

packer build出来的是 虚拟机镜像

terraform 像是 Kubernetesdeployment

如果我们把JDK打包到镜像上,是不是就像一个PaaS了,是不是JAVA应用的运行环境就有了

如果我们再激进一点,把应用程序代码也打包进去,是不是就是一个SaaS,镜像即代码,应用启动代码放到开机启动,配合云厂商的弹性伸缩,是不是也能做到像 Kubernetes 一样了,应用的更新,只要重装一个系统就好了

对于一些用不了Kubernetes 的应用,或许 terraform + packer 会是一个不错的方案,比如:一些依赖 windows 运行环境应用,或者依赖GPU的应用