使用Packer构建AWS AMI镜像

  PackerHashicorp(没错,就是 Terraform、Vault 的那家公司。) 公司推出的开源的轻量级自动化打包镜像工具。它允许你通过一套模板代码同时为多个平台构建相同的镜像, 其工作模式也是 Infrastructure as Code 的一种体现。 本文以 AWS 上的 AMI 为例,初始化一个用做 Jenkins node 的基础镜像。

需求

  使用 Packer 创建一个 AMI,该 AMI 需要以官方 Ubuntu LTS20.04 为底包,预安装一些必要的软件包,并做一些初始化操作(如修改SSH端口等)。

安装 Packer

  推荐使用 asdf 管理多版本运行环境。 更多请参考: asdf管理多版本Terraform|Alliot’s blog
在前文的基础下,只需要执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 列出可用packer版本  
asdf list-all packer

# 安装指定版本
asdf install packer 1.9.2

# 设置全局版本, 该参数会在当前用户HOME下生成 .tool-version 文档来标识版本
asdf global packer 1.9.2

# 如果只是为了在某路径下使用特定版本,可以通过local参数来指定,该参数会在当前目录下生成 .tool-version
# asdf local packer 1.9.2
# 如果项目下已有 .tool-version,可以直接执行 asdf install来自动安装指定版本的工具

# 如果只是为了当前shell下临时切换,可以通过shell参数来指定
# asdf shell packer 1.9.2

# 查看当前版本(可能需要你重新登录终端生效)
asdf current

# 卸载asdf指定的packer版本 (区别于remove,uninstall仅仅是去掉环境变量,让你可以用其他途径安装的packer)
# asdf uninstall packer

创建镜像配置

main.pkr.hcl:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
packer {
required_plugins {
amazon = {
version = ">= 0.0.2"
source = "github.com/hashicorp/amazon"
}
}
}

# 以下可以通过官方示例文档https://developer.hashicorp.com/packer/plugins/builders/amazon/ebs#owners 获得更多信息

# 定义EBS磁盘
source "amazon-ebs" "ubuntu" {
ami_name = "jenkins-ec2-slave"
instance_type = "t3.micro"
region = "ap-southeast-1"
source_ami_filter {
filters = {
name = "ubuntu/images/*ubuntu-focal-20.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["099720109477"] #
}
ssh_username = "ubuntu"
}


# 构建阶段预处理
build {
name = "jenkins-ec2-slave"
sources = [
"source.amazon-ebs.ubuntu"
]

provisioner "shell" {
script = "./init.sh"

# 使用sudo执行 init.sh 脚本
execute_command = "sudo -S sh -c '{{ .Vars }} {{ .Path }}'"

start_retry_timeout = "5m"
skip_clean = true
}
}

对应前文,在构建阶段执行一个系统初始化脚本,用来提供给 Packer 对镜像做预处理。
在同路径下创建: init.sh, 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#!/usr/bin/env bash

set -o errexit
set -o pipefail
set -o xtrace

# 等待服务完全启动
sleep 10
cat /etc/apt/sources.list
apt-get update

sudo apt-get install software-properties-common
sudo apt-add-repository universe

# 取消交互模式, 非交互模式会选择默认的选项并以最快的速度完成构建,Debian系尽量指定一下这个变量, apt安装包时静默。
export DEBIAN_FRONTEND=noninteractive

# 添加nodejs 18仓库,后面安装 nodejs 的时候要用,不需要可以去掉
curl -fsSL https://deb.nodesource.com/setup_18.x | bash -
# Install OpenSSH
apt-get install -y --no-install-recommends openssh-server

# 根据需求增减需要安装的软件包
apt-get install -y ubuntu-standard \
cloud-init \
ubuntu-server \
acpid \
ec2-hibinit-agent \
ec2-instance-connect \
hibagent \
krb5-locales \
ncurses-term \
ssh-import-id \
xauth dialog \
bash \
curl \
git \
unzip \
rsync \
ssh \
vim \
openjdk-11-jdk-headless \
maven \
nodejs

apt-get clean

# 如果你还需要做一些ssh端口更改等操作,可以参考如下:

# sudo sed -i '/^PasswordAuthentication/s/yes/no/g' /etc/ssh/sshd_config
# sudo sed -i '/^PermitRootLogin/s/without-password/no/g' /etc/ssh/sshd_config

# sudo echo "Port 1234" >> /etc/ssh/sshd_config
# sudo echo "ClientAliveInterval 300" >> /etc/ssh/sshd_config
# sudo echo "ClientAliveCountMax 3" >> /etc/ssh/sshd_config

# sudo echo "PubkeyAcceptedKeyTypes=+ssh-rsa" >> /etc/ssh/sshd_config
# sudo /etc/init.d/ssh restart