AWS AMI 全称是 Amazon Machine Image, 就是启动 EC2 节点时指定的操作系统的镜像, 可以简单理解为 AWS 上的 Ghost 镜像(什么是 Ghost? 嗯, 少年你知道什么是 XP 么). 打个比方, AWS AMI 就是重量级的 Docker: 你可以按照 Docker 的方式使用 AMI, 只不过 AMI 不能跑在你本机和 Kubernetes 上. 总结几个关于 AWS AMI 的事儿.
为什么要 Build 自己的 AMI
AWS 官方提供了很多现成的 AMI, 就跟 Docker Registry 提供了很多 Base Image 一样, 为了一些定制的需求(比如跨墙安装一些依赖), 提前 Build 好 AMI 可以提升很多效率, 当然, 你也可以像使用 Docker 一样, 每次发布时将自己的代码打包到一个最新的 AMI 中直接部署
如何 Build 一个自己的 AMI
鼠标流
最简单的方式是在 AWS Console 上面点击鼠标, 这个可以查看 AWS 官方的文档, 但是如果你是个鼠标流, 你用 AWS 干啥呢?
AWS cli/API
还有一个办法就是使用 AWS Cli 中的 aws ec2 create-image 命令或者 boto 中相关的 API, 这种方法在"鄙视链"中更上了一层楼, 但跟鼠标流一样, 这个仅仅能满足的场景是你已经在一个 running 的 EC2 instance 上 setup 好了所有的东西的场景, 就好比你使用 docker commit
的方式 Build 了一个 docker image. 平时玩玩儿可以, 但对于一个成熟的技术团队来说, 需要打造一个标准化的 CI/CD Pipeline 来 Build AMI 才行.
Hashicorp 公司出品的 packer
这时候就不得不提到 Hashicorp 出品的 packer. packer 核心是如下几个组件:
- Builder: 就是实际启动虚拟机并执行你的业务逻辑的一层. 支持 AWS, GoogleCloud Aliyun VirtualBox 等很多种方式
- Provisioner: 初始化的脚本. 可以是 shell, 也可以是 ansible/chef 等其他工具
- Post-Processors: build 完成后的钩子任务, 例如可以使用 VirtualBox builder build 任务, 然后再 Post-Processors 中将 VirtualBox 的虚拟机镜像 Export 成 OVF 在使用 Amazon Import 功能直接导入到 AWS
例如下面这个 packer 官方的例子:
{
"variables": {
"aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}",
"aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}",
"region": "us-east-1"
},
"builders": [
{
"access_key": "{{user `aws_access_key`}}",
"ami_name": "packer-linux-aws-demo-{{timestamp}}",
"instance_type": "t2.micro",
"region": "us-east-1",
"secret_key": "{{user `aws_secret_key`}}",
"source_ami_filter": {
"filters": {
"virtualization-type": "hvm",
"name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*",
"root-device-type": "ebs"
},
"owners": ["099720109477"],
"most_recent": true
},
"ssh_username": "ubuntu",
"type": "amazon-ebs"
}
],
"provisioners": [
{
"type": "file",
"source": "./welcome.txt",
"destination": "/home/ubuntu/"
},
{
"type": "shell",
"inline":[
"ls -al /home/ubuntu",
"cat /home/ubuntu/welcome.txt"
]
},
{
"type": "shell",
"script": "./example.sh"
}
]
}
"正规军"方式 build AMI
回到我们 Build AMI 的问题上来, 作为一个"专业"的技术团队, 那么方案就变成:
- 一律使用 packer 构建 AMI
- 通过 gitlab 进行 code review
- CI 过程中可以使用
packer validate
方法检验 packer 构建文件语法
# .gitlab-ci.yml 示例
# 使用 `packer validate` 验证文件语法
image:
hashicorp/packer:latest
stages:
- config_check
packer-config-check:
tags:
- docker
stage: config_check
retry: 2
script:
- packer validate java-ami.json
We can be Better
即便使用了 packer, 依旧有几个问题没有解决:
- 开发过程中如何测试 AMI
- 多个环境如何共享 AMI
开发过程如何测试 AMI
开发过程中一定是要测试 AMI 是否符合需求的, 如果简单的使用 AWS builder 来构建 AMI, 那么流程就变成了:
- 开发 packer 配置, build 一个新的 AMI
- 使用新的 AMI 启动一个 instance, 上去查看该版本的 AMI 是否符合需求
- 如何符合需求, 就提交代码进行 code review, 并不要忘记 terminate 刚刚的测试 instance
- 如果不符合需求, 跳到第一步继续修改 packer 文件
能否在本地测试 AMI, 省的 AMI 开发人员需要各种 AWS 账号的权限?
还真有, 一种方法是使用 VirtualBox 的 Builder 在开发过程中构建 Image, 如果符合需求再提交代码, 将 Builder 修改成 AWS, 或者依旧使用 VirtualBox 的 builder, 但 post-processor 使用 Amazon-import 将 OVF 导入到 AWS
多个环境如何共享 AMI
通常情况下, 我们都是使用多个环境(开发测试和生产环境), 为了隔离性也会分别使用不同的 AWS Account, 如何确保构建的 AMI 能够在多个环境/AWS Account 中使用? 其实也简单, 使用 ami_users
指定需要共享的 AWS Account ID.
AMI 使用注意事项
AMI 就是用来在 AWS 上启动虚拟机 EC2 的, 无论是自己手动启动还是使用 Autoscaling Group 启动. 需要注意的是在使用 Autoscaling Group 时, 如果 Autoscaling Group 的 Launch Configuration 中指定的 AMI 被你误删了, Autoscaling Group 启动 EC2 instance 会失败, 这个问题根源其实是 AWS 在做 AMI 删除时没有检查 AMI 是否正在被其他服务依赖. 避免的办法也不难:
- 添加 Autoscaling Group 的告警, 在启动 instance 失败时尽快告知开发人员
- 构建 AMI 时使用
tags
标记好 AMI, 避免在别人不知道的情况下误删 - 自动化清理过期的 AMI, 并添加上述依赖检查的逻辑, 避免误删
总结
构建 AMI 也不是什么高科技, 但这种简单的事情往往能看出一个技术团队的"工艺水平". 当然, Hashicorp 这种公司就更上了一层楼: 不爽的东西写一个工具让你爽, 而且还做了多平台支持, 方便大家随时跑路换云服务商(当然, 跑路也不是那么容易的事情).
-- EOF --
网友评论