Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

基于 Ansible 的项目自动化部署管理 #57

Open
abbshr opened this issue Sep 4, 2016 · 4 comments
Open

基于 Ansible 的项目自动化部署管理 #57

abbshr opened this issue Sep 4, 2016 · 4 comments

Comments

@abbshr
Copy link
Owner

abbshr commented Sep 4, 2016

正式走入工作岗位一个月, 接着实习的工作内容继续, 还是承担团队的 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

本地测试/开发

  1. 在本地测试与开发上, ansible playbook 配置目录中的一些变量可能需要稍做修改, 因此你可以创建一个host_var文件,比如:

    # 文件: host_vars/localhost
    
    # 项目名
    app_name: my_app_test
    # 项目的父级目录
    dest_prefix: "/tmp"
    # 分支/版本
    version:  test
    # 代理机的地址
    sync_host: ran@127.0.0.1
    
  2. 此外, inventory 内容也可能根据测试主机的地址及ssh的配置不同而需要修改.

  3. 确保以下正常

    • 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] - 执行流程

image

@zhuima
Copy link

zhuima commented May 17, 2017

小哥,github怎么404了

@abbshr
Copy link
Owner Author

abbshr commented May 17, 2017

@zhuima oh, my fault.. 我把项目名字改了..

https://github.com/upyun-dev/deploy
https://github.com/upyun-dev/rollback

@zhuima
Copy link

zhuima commented May 18, 2017

谢谢,我去look look

@cuidan
Copy link

cuidan commented Aug 31, 2017

666

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants