基于 Ansible 的项目自动化部署管理
abbshr opened this issue · comments
正式走入工作岗位一个月, 接着实习的工作内容继续, 还是承担团队的 Develop & Operation & Research 任务, 恰好我个人也比较喜欢什么都接触一些. 目前在应用开发部门设计了一套包括日志处理, 监控报警, 持续集成, 版本发布与回滚, 自动化管理在内的基础平台的架构, 当然这套体系肯定还尚未成熟, 这里经过老大的许可先把项目的部署与回滚架构发上来, 做个记录也方便日后 tuning.
为什么是 ansible?
8月初刚过来时我压根没听过 ansible 只知道 puppet, 正好那时团队准备做项目自动化管理相关的工作, 也就把自动化配置管理工具搜了一遍, 列了个优缺点比较表, 发现 ansible 完胜. 至于为什么, 我就一句话: "没有 agent, 没有 server, 用 ssh 批量管理主机". 玩过 puppet 和 chef 的同学应该秒懂了.
另外, ansible 也是 Devops 工具集中蹿升速度最快的配置管理工具之一. 截止至本年度7月份, Devops 使用度&接受度排行榜中前四位分别是 Puppet, Chef, Docker, Ansible. 而后者预计很快将超越前两个工具.
以其配置上的简洁, 使用上的顺手, 功能上的强大, 好了继续下一节.
自动化管理
ansible 的细节这里略过, 单说这套架构, 目前包括如下功能:
- 开发者机器上集中管理所有远程主机
- 对主机选择性管理
- 要求规范化的项目基本目录结构
- 线上机发布版本与回滚
- 代理机模拟成线上机便于测试
- 管理线上机服务的启动/停止/重启
接下来从整套机制的架构到细节逐步介绍.
规范化项目目录结构
在未引入 Docker 情况下, 为了做到项目(应用程序, 配置信息, 状态数据, 依赖工具链等)之间的隔离, 这里定义了一种项目的目录规范.
线上项目一般都是位于某个目录(比如/opt/app
)下面, 不同的子目录用以区分不同的项目, 每个项目目录的基本结构如下:
/uopt/app/example-project
├── current # 指向项目最新发布的版本的软链接 ** 重要 **
├── releases # 包含所有的历史发布版本(以及当前版本) ** 重要 **
├── tmp # rsync 临时目录
├── shared # 发布工具使用的目录 ** 重要 **
├── log # 日志存放
├── run # 运行时数据
├── util # 外部工具
└── node_modules # Node.js Package 形式的外部工具, 如 pm2 ** 重要 **
每个项目可以在这个目录结构上进行扩展, 比如添加其他目录, 但上述标注 ** 重要 ** 的目录不建议删除或修改.
其中 current 目录指向的就是该项目的原代码, 即开发阶段所熟悉的目录结构.
Ansible Playbook 目录结构
在使用 ansible 时, current 所指代的代码目录中, 应包含 ansible playbook 的配置目录, 举个例子:
/opt/app/my_app/current/deploy ❯❯❯ tree -a -L 4
# 以下结构参考 ansible 官方给出的最佳实践
.
├── group_vars
│ ├── all
│ ├── nodes
│ │ └── vars
│ └── proxy
│ └── vars
├── host_vars # 测试环境下只需增加对应主机的变量文件即可覆盖预设变量
│ ├── 10.0.5.130
│ ├── 192.168.1.17
│ │ ├── vars
│ │ └── vault # 加密变量
│ ├── 192.168.5.68
│ │ ├── vars
│ │ └── vault
│ └── 192.168.5.69
│ ├── vars
│ └── vault
├── production # 线上环境 inventory
├── roles
│ ├── config
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── templates
│ │ ├── config.json.j2
│ │ ├── logstash.conf.j2
│ │ └── macros.j2
│ ├── node
│ │ └── tasks
│ │ └── main.yml
│ ├── proxy
│ │ └── tasks
│ │ └── main.yml
│ ├── schedule
│ │ └── tasks
│ │ └── main.yml
│ └── worker
│ └── tasks
│ └── main.yml
├── rollback.yml
├── .rsync_ignore # 从代理机到线上机同步时需要忽略的文件/目录列表
├── site.yml
└── staging # 测试环境 inventory
其余文件的解释和作用见 ansible 官方文档.
发布和回滚
在执行发布回滚操作上, 我在开源 roles ansistrano 的基础上做了不少改动以适配我们的应用场景, 并以新的 roles 发布在 ansible galaxy 上 (https://github.com/upyun-dev/ansistrano-deploy | https://github.com/upyun-dev/ansistrano-rollback), 具体的代码实现这里就不说了.
来看看怎么用吧:
# 安装依赖 roles
$ ansible-galaxy install upyun-dev.ansistrano-deploy
$ ansible-galaxy install upyun-dev.ansistrano-rollback
# 在所有机器上执行项目部署, 发布版本并重启服务任务
ansible-playbook -i <staging | production> site.yml
# 在所有机器上执行项目回滚并重启服务任务
ansible-playbook -i <staging | production> rollback.yml
但是同构化 proxy 和 nodes 往往不是我们想要的结果, 多数情况下我们可能只把 proxy 作为纯粹的代理机使用, 并不需要模拟线上机器执行部署/回滚. 这种情况可以通过指定 --tag 或者 --limit 来选择要执行的任务:
# tag: proxy, nodes, config
# 仅在 proxy 上执行部署发布
ansible-playbook -i hosts site.yml --tag="proxy"
# 仅在 proxy 上执行回滚
ansible-playbook -i hosts rollback.yml --tag="proxy"
# 仅在 nodes 上执行部署发布以及服务启动
ansible-playbook -i hosts site.yml --tag="nodes"
# 只在属于proxy group的主机上执行tasks
ansible-playbook -i <staging | production> site.yml --limit=proxy
本地测试/开发
-
在本地测试与开发上, ansible playbook 配置目录中的一些变量可能需要稍做修改, 因此你可以创建一个host_var文件,比如:
# 文件: host_vars/localhost # 项目名 app_name: my_app_test # 项目的父级目录 dest_prefix: "/tmp" # 分支/版本 version: test # 代理机的地址 sync_host: ran@127.0.0.1
-
此外, inventory 内容也可能根据测试主机的地址及ssh的配置不同而需要修改.
-
确保以下正常
- proxy和node上启动 sshd (确保nodes 可以通过 ssh 访问)
- 保证本地 shell 没有多余 ouput (确保以 ssh 方式同步数据时没有误差产生)
- 安装外部 roles
注意当你选择使用 rsync 的 ssh 模式同步数据时, 一定要保证代理机上的 登录 shell 没有多余的输出(当时被这个坑了...).
项目启动脚本
由于引入规范化项目结构, 导致了冗余目录的产生以及项目状态数据路径(如 pm2)的变化. 为了屏蔽本地以及线上部署差异, 透明化本地开发, 这里对项目的启动脚本做了修改, 使其根据不同的开发环境判断如何启动项目, 如:
PRJ_DIR=$(cd $APP_ROOT_DIR/../.. && pwd)
APP_DIR_PARENT=$(cd $APP_ROOT_DIR/.. && pwd)
if [[ -L $APP_DIR_PARENT/current ]]; then
PRJ_DIR=$APP_DIR_PARENT
elif [[ ! -d $PRJ_DIR/releases || ! -L $PRJ_DIR/current ]]; then
PRJ_DIR=${APP_ROOT_DIR}
fi
PM2_BIN="$PRJ_DIR/node_modules/pm2/bin/pm2" # 指定新的pm2可执行文件路径
最终结果体现为: 如果并没有遵循如上所述的规范化目录结构, 那么将之后的部署作为本地开发环境下的部署. 否则作为线上/测试环境下的部署.
[WIP] - 执行流程
小哥,github怎么404了
@zhuima oh, my fault.. 我把项目名字改了..
https://github.com/upyun-dev/deploy
https://github.com/upyun-dev/rollback
谢谢,我去look look
666