什么是持续交付?
持续交付 CD
意味着经常向您的软件应用程序提供更新。
这个想法是,通过更频繁地更新,您不必等待特定的时间段,并且您的组织可以更好地响应变化。
一些 Ansible
用户每小时甚至更频繁地向最终用户部署更新 - 有时每次有批准的代码更改时。为了实现这一目标,您需要能够以零停机方式快速应用这些更新的工具。
本文档使用 Ansible
最完整的示例 playbook
之一作为模板,详细描述了如何实现此目标:lamp_haproxy
。此示例使用了许多 Ansible
功能:角色
、模板
和组变量
,并且它还附带了一个编排剧本,可以对 Web
应用程序堆栈进行零停机滚动升级。
playbook
将 Apache
、PHP
、MySQL
、Nagios
和 HAProxy
部署到一组基于 CentOS
的服务器上。
如果你要编写上面这些的 playbook
,可以参考相关手册。
站点部署
让我们从 site.yml
.这是我们的站点范围部署手册。它可用于初始部署站点,以及将更新推送到所有服务器:
---
# 此playbook将整个应用程序堆栈部署在此站点中。
# 将通用配置应用于所有主机
- hosts: all
roles:
- common
# 配置和部署数据库服务器。
- hosts: dbservers
roles:
- db
# 配置和部署web服务器。请注意,我们包括两个角色
# 这里,“基本apache”角色,它只是设置apache和“web”
# 其中包括我们的示例web应用程序。
- hosts: webservers
roles:
- base-apache
- web
# 配置和部署负载平衡器。
- hosts: lbservers
roles:
- haproxy
# 配置和部署Nagios监控节点。
- hosts: monitoring
roles:
- base-apache
- nagios
在这个playbook中,我们有 5 个任务。第一个以主机为目标 all
,并将角色 common
应用于所有主机。这适用于站点范围的内容,例如 yum
存储库配置、防火墙配置以及需要应用于所有服务器的任何其他内容。
接下来的四个任务针对特定的主机组运行,并将特定角色应用于这些服务器。除了 Nagios
监视、数据库和 Web
应用程序的角色外,我们还实现了一个 base-apache
角色,用于安装和配置基本的 Apache
设置。示例 Web
应用程序和 Nagios
主机都使用它。
可重用内容:角色
到目前为止,我们应该对角色以及它们在 Ansible
中的工作方式有一定的了解。角色是一种组织方式内容:任务、处理程序、模板和文件,转化为可重用的组件。
此示例有六个角色: common
, base-apache
, db
, haproxy
, nagios
和 web
。如何组织这些角色取决于我们的应用程序,但大多数站点都会有一个或多个适用于的常见角色所有系统,然后是一系列特定于应用程序的角色,用于安装和配置站点的特定部分。
您可以在角色文档具有变量和依赖项,您可以将参数传递给角色来修改其行为。 部分阅读有关角色的更多信息。
配置:组变量
组变量是应用于服务器组的变量。它们可以在模板中使用 playbook
来自定义行为并提供易于更改的设置和参数。它们存储在与库存位于同一位置的目录。 这是 lamp_haproxy
的文件。正如我们所期望的,这些变量将应用于您库存中的所有机器:
---
httpd_port: 80
ntpserver: 192.0.2.23
这是一个 YAML
文件,我们可以为更复杂的变量结构创建列表和字典。 在本例中,我们只需设置两个变量,一个用于 Web
服务器的端口,另一个用于 我们的机器应该使用 NTP
服务器来进行时间同步。
这是另一个组变量文件。这适用于组中的主机:
代码语言:javascript复制---
mysqlservice: mysqld
mysql_port: 3306
dbuser: root
dbname: foodb
upassword: usersecret
如果查看示例,会发现组和组都有组变量,很类似。这些变量被用在很多地方。我们可以在playbook
中使用它们,如下所示:
- 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
我们还可以在模板中使用这些变量,如下所示:roles/common/templates/ntp.conf.j2
drift file /var/lib/ntp/drift
restrict 127.0.0.1
restrict -6 ::1
server {{ ntpserver }}
include file /etc/ntp/crypto/pw
keys /etc/ntp/keys
可以看到,模板和变量的变量替换语法 {{ }} 是相同的。语法 大括号内是 Jinja2,我们可以执行各种操作并对其应用不同的过滤器里面的数据。在模板中,还可以使用 for
循环和 if
语句来处理更复杂的情况,像这样,在:roles/common/templates/iptables.j2
{% if inventory_hostname in groups['dbservers'] %}
-A INPUT -p tcp --dport 3306 -j ACCEPT
{% endif %}
这是测试,以查看我们当前正在操作的计算机的清单名称是否存在于清单组中。如果是这样,该机器将获得端口 3306
的 iptables ACCEPT 行。inventory_hostname
dbservers
下面是来自同一模板的另一个示例:
代码语言:javascript复制{% for host in groups['monitoring'] %}
-A INPUT -p tcp -s {{ hostvars[host].ansible_default_ipv4.address }} --dport 5666 -j ACCEPT
{% endfor %}
这将遍历名为 的所有主机,并为每个监控主机的默认 IPv4
地址到当前机器的 iptables
配置,以便 Nagios
可以监控这些主机。monitoring
滚动升级
现在,我们拥有一个完全部署的站点,其中包含 Web
服务器、负载平衡器和监视功能。你如何更新它?这就是 Ansible
的 编排功能开始发挥作用。
Ansible
能够以协调的方式对多层应用程序执行操作,从而可以轻松编排 Web 应用程序的复杂零停机滚动升级。这是在一个名为 的单独 playbook
中实现的。rolling_update.yml
看看playbook
,你可以看到它由两个剧本组成。第一个任务很简单,是这样的:
- hosts: monitoring
tasks: []
这是怎么回事,为什么没有任务?我们可能知道 Ansible
在对服务器进行操作之前会从服务器收集“事实”。 这些事实对各种事情都很有用:网络信息、操作系统/发行版版本等。在我们的例子中,在执行更新之前,我们需要了解环境中所有监控服务器的一些信息,因此这个简单的操作会强制在我们的监控服务器上执行事实收集步骤。您有时会看到这种模式,这是一个有用的技巧。
第一部分如下所示:
代码语言:javascript复制- hosts: webservers
user: root
serial: 1
这只是一个正常的定义,在组上运行。该关键字告诉 Ansible
一次要运行多少台服务器。如果未指定,Ansible
会将这些操作并行化,直至达到配置文件中指定的默认“forks”限制。但是,对于零停机时间滚动升级,我们更多的可能不希望同时在这么多主机上操作。如果只有少数几个 Web
服务器,则可能需要一次为一台主机设置为 1。如果你有 100,也许你可以设置为 10,一次。
这是更新的下一部分:
代码语言:javascript复制pre_tasks:
- name: disable nagios alerts for this host webserver service
nagios:
action: disable_alerts
host: "{{ inventory_hostname }}"
services: webserver
delegate_to: "{{ item }}"
loop: "{{ groups.monitoring }}"
- name: disable the server in haproxy
shell: echo "disable server myapplb/{{ inventory_hostname }}" | socat stdio /var/lib/haproxy/stats
delegate_to: "{{ item }}"
loop: "{{ groups.lbservers }}"
该关键字只允许您列出在调用角色之前要运行的任务。这在一分钟内会更有意义。如果查看这些任务的名称,可以看到我们正在禁用 Nagios
警报,然后从 HAProxy
负载平衡池中删除我们当前正在更新的 Web
服务器。
pre_tasks
和参数一起使用会导致 Ansible
遍历每个监控服务器和负载平衡器,并代表Web
服务器在监控或负载平衡服务器上执行该操作(委托该操作)。部循环是 Web
服务器的列表,内部循环是监控服务器的列表。
HAProxy
步骤看起来有点复杂。在此示例中,我们使用 HAProxy
,因为它是免费提供的,但是如果您的基础设施中有 F5
或 Netscaler
(或者您有 AWS 弹性 IP 设置),则可以使用 Ansible
模块与它们进行通信。可能还希望使用其他监视模块而不是 nagios
,但这只是显示了“前期任务”部分的主要目标 - 将服务器从监视中移除,并将其从轮换中移除。
下一步只是将适当的角色重新应用于 Web
服务器。这将导致将任何配置管理声明和角色应用于 Web 服务器,包括 Web
应用程序代码本身的更新。我们不必这样做——我们可以纯粹地更新 Web
应用程序,但这是一个很好的例子,说明如何使用角色来重用任务:web
base-apache
roles:
- common
- base-apache
- web
最后,我们将撤消对 Nagios
配置的更改,并将 Web
服务器放回负载均衡池中:post_tasks
post_tasks:
- name: Enable the server in haproxy
shell: echo "enable server myapplb/{{ inventory_hostname }}" | socat stdio /var/lib/haproxy/stats
delegate_to: "{{ item }}"
loop: "{{ groups.lbservers }}"
- name: re-enable nagios alerts
nagios:
action: enable_alerts
host: "{{ inventory_hostname }}"
services: webserver
delegate_to: "{{ item }}"
loop: "{{ groups.monitoring }}"
同样,如果您使用的是 Netscaler、F5 或 Elastic Load Balancer,则只需替换相应的模块即可。
管理其他负载均衡器
在此示例中,我们使用简单的 HAProxy
负载均衡器来前端 Web
服务器。它易于配置和管理。正如我们所提到的,Ansible
支持各种其他负载均衡器,例如 Citrix NetScaler
、F5 BigIP
、Amazon Elastic Load Balancers
等。
对于其他负载均衡器,可能需要向它们发送 shell
命令或者调用 API。对于 Ansible
具有模块的负载均衡器,可能希望在它们联系 API 时将其作为 a 运行。如果你为一些没有模块的硬件开发任何有趣的东西,它可能会做出很好的贡献!local_action
端到端持续交付
现在,我们已经拥有了一种自动化的方式来将更新部署到应用程序,如何将它们结合在一起?许多组织使用 Jenkins
或 Atlassian Bamboo
等持续集成工具将开发、测试、发布和部署步骤捆绑在一起。我们可能还希望使用像 Gerrit
这样的工具添加代码审查步骤,以提交到应用程序代码本身和Ansible playbook
。
根据环境,我们可能会持续部署到测试环境,针对该环境运行集成测试,然后自动部署到生产环境中。或者,可以保持简单,只使用滚动更新来按需部署到测试或生产中。
为了与持续集成系统集成,可以使用命令行工具轻松触发 playbook
运行,或者,如果您使用的是 AWX
,则使用命令或内置 REST API
。
这应该可以很好地了解如何使用 Ansible
构建多层应用程序,并在该应用程序上编排操作,最终目标是持续交付给客户。
我们可以将滚动升级的想法扩展到应用程序的几个不同部分;也许将前端 Web
服务器与应用程序服务器一起添加,或者将 SQL
数据库替换为 NoSQL
数据库。借助 Ansible
,可以轻松管理复杂的环境并自动执行常见操作。
总结
Ansiable 是新出现的自动化运维工具,基于 Python 开发,集合了众多运维工具(puppet、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。
它的功能很多,很强大。使用 Python
编写,但是它更像一个编程语言框架一样,内置类很多功能(角色,组,模板等)。
如果不是很熟悉的情况下使用起来还是有很多坑,所以在使用 Ansiable 的时候可以多做些练习,更多的去参考官方文档。
参考资料:
Ansible 官方文档: https://docs.ansible.com/