持续交付是频繁对软件应用程序持续更新的概念.html
这个想法使在大量频繁的更新面前, 你没必要等待在一个指定的特殊时间点, 而且使你的组织在响应过程当中变得更好.前端
一些 Ansible 用户每小时都在部署更新给他们的最终用户甚至更加频繁 – 每时每刻都有代码修改的批准. 要实现这一点, 你须要工具能在零停机的时间内快速的应用这些更新.python
本文档详细介绍了如何现实这一目标, 使用 Ansible playbooks 做为一个完整例子的模板: lamp_haproxy. 这个例子使用了大量的 Ansible 特性: roles, templates 和 group variables, 而且它还配备了一个业务流程的 playbook 能够作到零停机滚动升级 web 应用程序栈.mysql
Noteios
这个 playbooks 基于 CentOS 部署 Apache, PHP, MySQL, Nagios, 和 HAProxy 这些服务.github
在这里咱们不去讨论如何运行这些 playbooks. 阅读包含在 github 项目中关于这个例子的 README 信息. 相反的, 咱们将进一步观察这些 playbook 而且去解释它们.web
让咱们首先使用 site.yml
. 这是咱们网站部署的 playbook. 它被用来部署咱们最初的网站以及推送更新到全部的服务器:sql
---
# 这个 playbook 在这个网站上部署整个应用程序.
# 应用通用的配置到全部的主机上
- hosts: all
roles:
- common
# 配置和部署数据库服务器.
- hosts: dbservers
roles:
- db
# 配置和部署 web 服务器. 注意这里咱们包含了两个 roles, 这个 'base-apache' role 用来简单设置 Apache, 而 'web' 则包含了咱们的 web 应用程序.
- hosts: webservers
roles:
- base-apache
- web
# 配置和部署 load balancer(s).
- hosts: lbservers
roles:
- haproxy
# 配置和部署 Nagios 监控节点(s).
- hosts: monitoring
roles:
- base-apache
- nagios
Noteshell
若是你不熟悉 playbooks 和 plays, 你应该回顾 Playbooks.
在这个 palybook 咱们有 5 个 plays. 首先第一个目标 all
(全部)主机和适用于全部主机的 common
role. 这是整个网站要作的事像 yum 仓库的配置, 防火墙的配置, 和其余任何须要适用于全部服务器的配置.
接下来的这四个 plays 将运行于指定的主机组并特定的角色应用于这些服务器. 随着对 Nagios monitoring, 数据库角色, 和 web应用程序的应用, 咱们能够经过 base-apache
角色安装和配置一个基本的 Apache. 这是 Nagios 主机和 web 应用程序所须要的.
关于 roles 你如今应该有一点了解以及它们是如何工做的. Roles 是组织: tasks, handlers, templates, 和 files, 到可重用的组件中的方法.
这个例子有 6 个 roles: common
, base-apache
, db
, haproxy
, nagios
, 和 web
. 你如何组织你的 roles 是由你和你的应用程序所决定, 可是大部分网站都将适用一个或多个共同的 roles, 和一些列关于应用程序特定的 roles 来安装和配置这个网站的特定部分.
Roles 能够用变量和依赖关系, 你能够经过参数来调整它们的行为. 你能够在 Playbook Roles and Include Statements 章节中阅读更多关于 roles
Group variables 是应用在服务器组上的. 经过设置和修改参数将他们应用在 templates 中来定义 playbooks 的行为. 他们被存储在和你的 inventory 相同目录下名为 group_vars
的目录中. 下面是 lamp_haproxy 的 group_vars/all
文件内容. 正如你所指望的, 这些变量将会应用到 inventory 中的全部服务器上:
---
httpd_port: 80
ntpserver: 192.168.1.2
这是一个 YAML 文件, 而且你能够建立列表和字典等更加复杂的变量结构. 在这种状况下, 咱们只设置了两个变量, 一个作为 web server 的端口, 一个做为咱们服务器所使用的时间同步 NTP 服务的地址.
这是另一个 group variables 文件. 这个 group_vars/dbservers
适用于在 dbservers
组中的主机:
---
mysqlservice: mysqld
mysql_port: 3306
dbuser: root
dbname: foodb
upassword: usersecret
若是你看了这个例子, 你会发现对于 webservers
组合 lbservers
组的 group variables 十分类似.
这些变量能够用于任何地方. 你能够在 playbooks 中使用它们, 像这样, 在 roles/db/tasks/main.yml
:
- name: Create Application Database
mysql_db: name={{ dbname }} state=present
- name: Create Application DB User
mysql_user: name={{ dbuser }} password={{ upassword }}
priv=*.*:ALL host='%' state=present
你也能够在 templates 中使用这些变量, 想这样, 在 roles/common/templates/ntp.conf.j2
:
driftfile /var/lib/ntp/drift
restrict 127.0.0.1
restrict -6 ::1
server {{ ntpserver }}
includefile /etc/ntp/crypto/pw
keys /etc/ntp/keys
你能够看到这些变量替换的语法 {{ and }} 和 templates 中的变量是相同的. 这种花括号格式是采用的jinj2语法, 你在对于内部的数据作各类操做及应用不一样的过滤器. 在 templates, 你也可使用循环和 if 语句来处理更加复杂的状况, 想这样, 在 roles/common/templates/iptables.j2
:
{% if inventory_hostname in groups['dbservers'] %}
-A INPUT -p tcp --dport 3306 -j ACCEPT
{% endif %}
这是用来判断, 名为 (inventory_hostname
) 的机器是否存在于组 dbservers
. 若是这样的话, 该机器将会添加一条 目标端口为 3306 的 iptables 容许规则.
这有一些其余的例子, 来自相同的模板:
{% for host in groups['monitoring'] %}
-A INPUT -p tcp -s {{ hostvars[host].ansible_default_ipv4.address }} --dport 5666 -j ACCEPT
{% endfor %}
这里循环了一个组名为 monitoring
中的全部主机, 而且配置了源地址为全部监控主机的 IPV4 地址目标端口为 5666 的 iptables 容许规则到当前主机上, 正由于如此 Nagios 才能够监控这些主机.
你能够学到更多关于 Jinja2 的功能 here, 而且你能够读到更多关于 Ansible 全部的变量在这个 Variables 章节
如今你有了一个全面的网站包含 web servers, 一个 load balancer, 和 monitoring. 如何更新它? 这就是 Ansible 的特殊功能发挥做用. 尽管一些应用程序使用’业务流程’来编排命令执行的逻辑, Ansible将指挥编排这些机器, 而且拥有一个至关复杂的引擎.
Ansible 有能力在一次操做中协调多种应用程序, 使在进行更新升级咱们的 web 应用程序时更加实现零停机时间. 这是一个单独的 playbook, 叫作 roleing_upgrade.yml
.
看这个 playbook, 你能够看到它是由两个 plays 组成. 首先第一个看起来十分简单像这样:
- hosts: monitoring
tasks: []
这里要作什么, 为何没有 tasks? 你可能知道 Ansible 在运行以前会从服务上收集 “facts”. 这些 facts 是不少种有用的信息: 网络信息, OS/发行版本, 配置. 在咱们的方案中, 在更新以前咱们须要了解关于全部监控服务器的环境信息, 所以这个简单的 paly 将会在咱们的所监控的服务器上强制收集 fact 信息. 你有时会见到这种模式, 这是一个有用的技巧.
接下来的部分是更新 play. 第一部分看起来是这样:
- hosts: webservers
user: root
serial: 1
咱们仅仅是像一般同样在 webservers
组中定义了 play. 这个 serial
关键字告诉 Ansible 每次操做多少服务器. 若是它没有被指定, Ansible 默认根据配置文件中 “forks” 限制指定的值进行并发操做. 可是对于零停机时间的更新, 你可能不但愿一次操做多个主机. 若是你仅仅有少数的 web 服务器, 你可能但愿设置 serial
为 1, 在同一时间只执行一台主机. 若是你有 100 台, 你能够设置 serial
为 10, 同一时间执行 10 台.
下面是更新 play 接下来的部分:
pre_tasks:
- name: disable nagios alerts for this host webserver service
nagios: action=disable_alerts host={{ inventory_hostname }} services=webserver
delegate_to: "{{ item }}"
with_items: groups.monitoring
- name: disable the server in haproxy
shell: echo "disable server myapplb/{{ inventory_hostname }}" | socat stdio /var/lib/haproxy/stats
delegate_to: "{{ item }}"
with_items: groups.lbservers
这个 pre_tasks
关键字仅仅是让在 roles 调用前列出运行的 tasks. 这段时间将十分有用. 若是你看到这些 tasks 的名称, 你会发现咱们禁用了 Nagios 的报警而且将当前更新的服务器从 HAProxy load balancing pool 中移除.
参数``delegate_to`` 和 with_items
一块儿来使用, 由于 Ansible 循环每个 monitoring 服务器和 load balancer, 而且针对循环的值在 monitoring 或 load balancing 上操做(delegate 表明操做). 从编程方面来讲, 外部的循环是 web 服务器列表, 内部的循环是 monitoring 服务器列表.
请注意 HAProxy 的步骤看起来有点复杂. 咱们使用它做为例子是由于它是免费的, 但若是你有(例如)一个 F5 或 Netscaler 在你的基础设施上(或者你有一个 AWS 弹性 IP 的设置?), 你可使用 Ansible 的模块而不是直接和他们进行交互. 你也可能但愿使用其余的 monitoring 模块来代替 nagios, 可是这仅仅是展现了在任务开始前的部分 – 把服务从监控中移除而且轮换它们.
下一步从新简单的使正确的角色应用在 web 服务器上. 这将致使一些名为 web
和 base-apache
的配置管理角色应用到 web 服务器上, 包含一个更新 web 应用程序自身代码. 咱们不须要这样作 – 咱们仅须要将其修改成纯碎的更新 web 程序, 可是这是一个很好的例子关于如何经过 roles 来重用这些任务:
roles:
- common
- base-apache
- web
最后, 在 post_tasks
部分, 咱们反向的改变 Nagios 的配置而且将 web 服务器从新添加到 load balancing pool:
post_tasks:
- name: Enable the server in haproxy
shell: echo "enable server myapplb/{{ inventory_hostname }}" | socat stdio /var/lib/haproxy/stats
delegate_to: "{{ item }}"
with_items: groups.lbservers
- name: re-enable nagios alerts
nagios: action=enable_alerts host={{ inventory_hostname }} services=webserver
delegate_to: "{{ item }}"
with_items: groups.monitoring
再一次说明, 若是你在使用一个 Netscaler 或 F5 或 Elastic 的负载均衡器, 你仅仅须要替换为适合的模块对象.
在这个例子中, 咱们使用了简单的 HAProxy 负载均衡到后端的 web 服务器. 它是很是容易配置和管理的. 正如咱们所提到的, Ansible 已经为其余的负载均衡器像 Citrix NetScaler, F5 BigIP, Amazon Elastic Load Balancers 等提供了内建的支持.阅读更多信息 模块相关
对于其余的负载均衡器, 若是公开一个负载均衡时, 你可能须要向它们发送 shell 命令 (像上面咱们对 HAProxy 同样), 或者调用一些 API. 你能够越多更多关于 local actions 在这个 委托,滚动更新,本地动做章节中. 对于一些硬件的开发将更加有趣, 他们没有一个核心模块, 因此你可使用更好的模块将他们封装起来!
如今你有一个自动化的方式来部署更新你的应用程序, 你将如何将他们绑定在一块儿? 许多组织使用持续集成的工具像 Jenkins 或 Atlassian Bamboo 来完成开发, 测试, 发布, 和部署这样的流程步骤. 你也可使用这些工具像 Gerrit 来添加一个 code review 的步骤来审查提交的应用程序的自己或者 Ansible playbooks.
根据你的环境, 你可能会部署到一个测试环境, 在这个环境中运行一些集成测试, 而后自动部署到生产环境. 你能够保持他们的简单性仅按需来进行滚动升级到测试或者指定的生产环境中. 这些你都随你决定.
与持续集成工具的结合, 你能够经过 ansible-playbook
命令行工具很容易的触发 playbook 的运行, 或者, 若是你使用 Ansible Tower, tower-cli
或者内置的 REST API. (这个 tower-cli 命令的 ‘joblaunch’ 将经过 REST API 远程产生一个 job 这很是棒).
Ansible 对于如何组合多层应用程序在任务编排和持续交付给客户的最终目标上给了你很好的主意. 你可使用滚动升级的思路来扩展一些应用程序之间的不一样部分; 也许向前端 web 服务器添加后端应用服务, 例如, 使用 MongoDB 或 Riak 来替换 SQL 数据库. Ansible 能够给你在复杂的环境中轻松完成常见的自动化操做.
See also