应用部署和升级能够用各类不一样的策略来实现。最好的方法取决于应用程序自己、应用程序运行的基础设施的能力、以及用户应用程序的承诺的全部服务等级协议。无论你使用什么策略,ansible都很是适合部署。本章中, 咱们将介绍一些经常使用的部署策略以及ansible特性在这些策略中展露头脚的案例。咱们还讨论两种其余部署,考虑两种部署策略之间的共性,也就是:nginx
咱们讲的第一种部署类型就是就地升级。这种类型的部署就是在现有的基础设施上操做来更新原有应用程序。这种模型能够看做是传统的模型,建立新的基础设施的时候存在时间和金钱上的高额开销。git
在这种类型的升级过程当中,要减小宕机时间,通常的设计模式是经过在负载均衡后面的多个主机上部署应用。负载均衡扮演了一种在应用用户和应用程序服务器之间的网关。对应用的请求会抵达负载均衡,依赖于具体配置,负载均衡会决定具体哪一个后端服务器来服务请求。shell
要对这种模式部署的应用执行就地升级滚动,每一个服务器(或服务器的一部分)会在负载均衡后面先禁用,而后升级、而后从新启用来接受新请求。对池子中的剩余机器重复作这样的操做,直到全部的服务器都升级了。正由于只有部分可用应用服务器下线升级,应用总体上仍是保持对请求可用。固然,这里须要有个假设前提,就是同时存在不一样版本的应用的状况下,应用执行OK。后端
让咱们构建一个剧原本升级一个虚构的应用。咱们虚构的应用程序会运行在foo-app01到foo-app08这8台服务器上,它们位于分组foo-app。这些服务器上面有一个简单经过nginx服务的网站,应用内容来自git仓库foo-app,经过变量foo-app.repo来定义。还有一个负载均衡服务器foo-lb,运行haproxy软件,前置在这些应用服务器以前。设计模式
为了操做foo-app服务器的子集,咱们须要利用serial模式。 这个模式会改变ansible如何执行剧情。默认状况下,ansible会按顺序遍历任务中列举的主机列表来执行剧本任务。剧本的每一个任务都要跨越全部主机执行完才会执行下一个任务。若是咱们使用默认的模式,咱们第一个任务是移除负载均衡后面的每个应用服务,这样就会致使咱们应用彻底的断供(outage of our application)。而serial模式,可让咱们对主机子集进行操做,这样应用总体上来讲仍是可用的,即使部分红员下线了。在咱们的例子中,咱们使用serial数量2,为了保持应用成员的大部分都是在线状态:服务器
--- - name: Upgrade foo-app in place hosts: foo-app serial: 2
接下来咱们能够建立咱们的任务了。第一个任务就是禁用负载均衡后面的主机。负载均衡运行在foo-lb主机上;然而,咱们是在foo-app主机上操做。所以,咱们须要使用delegate_to任务操做符代理任务。这个操做符指示ansible将链接到哪里来执行任务,可是保持全部的原始主机上下文变量。咱们使用haproxy模块来禁用来自foo-app后端池的当前主机。app
tasks: - name: disable member in balancer haproxy: backend: foo-app host: "{{ inventory_hostname }}" state: disabled delegate_to: foo-lb
主机禁用后,咱们就能够升级foo-app内容了。咱们使用git模块使用在foo-version变量中定义的指望版本号来更新内容路径。咱们还会给这个任务添加一个notify处理器,若是内容更新结果改变的时候,来重启nginx服务器。这个能够每次都执行,这里咱们使用这个做为notify的例子:负载均衡
- name: pull stable foo-app git: repo: "{{ foo-app.repo }}" dest: /srv/foo-app/ version: "{{ foo-version }}" notify: - reload nginx
接下来,咱们须要在负载均衡里边从新启用这个主机;然而,若是咱们接下来作这个任务的话,咱们会将旧版本就地退回,由于通知处理器尚未运行呢。所以,咱们须要提早触发咱们的处理器,能够经过meta: flush_handlers调用来实现,这点咱们前面已经了解过。less
- meta: flush_handlers
接下来,咱们能够重启启用负载均衡后面的这个主机了。咱们能够直接启用它,并依赖负载均衡,在发送请求过去以前,一直等待直到机器健康。 然而,由于咱们运行的主机数量较少了,因此咱们须要确保剩下的主机都是健康的。咱们能够利用wait_for任务等待,直到nginx服务再次服务链接。wait_for模块会等待一个基于端口或文件路径的条件。在咱们这个例子中,咱们等待端口80,以及那个端口应该在里边。若是它启动了(默认状况), 这就意味着它能够接受请求了。ssh
- name: ensure healthy service wait_for: port: 80
最后,咱们能够在haproxy中从新启用这个成员。再一次,咱们委托任务给foo-lb:
- name: enable member in balancer haproxy: backend: foo-app host: "{{ inventory_hostname }}" state: enabled delegate_to: foo-lb
固然,咱们还须要定义咱们的reload nginx处理器:
handlers: - name: reload nginx service: name: nginx state: restarted
这个剧本运行的时候,就会对咱们的应用执行一个就地升级滚动。
就地升级策略的一个代替方案是扩容和缩容策略。这个策略已经变得后期流行了,得益于按需设施的自助特性,例如云计算或虚拟化池子。具备从大的可用池中按需建立新的服务器的能力,意味着每个应用的部署均可以在全新的系统上发生。这种策略就避免了一个主机的问题。这些包含在长期运行系统上构建讨厌的东西,例如:
每次从新全新的也能够消除初始化部署和升级中的差别。可使用一样的代码路径,下降升级应用时的意外风险。这种类型的安装也能够很是方便回滚,若是新版本执行没达到预期的话。此外,随着新系统取代旧系统,应用在升级过程当中不须要进入降级状态。
接下来咱们再用扩容和缩容策略来实现咱们以前的升级剧本。咱们的模式是建立新的服务器、部署咱们的应用、验证应用、将新服务器添加到负载均衡后面、而后从负载均衡里边移除旧服务器。 对于这个例子来讲,咱们使用OpenStack Compute Cloud来启动新实例:
--- - name: Create new foo servers hosts: localhost tasks: - name: launch instances os_server: name: foo-appv{{ version }}-{{ item }} image: foo-appv{{ version }} flavor: 4 key_name: ansible-prod security_groups: foo-app auto_floating_ip: false state: present auth: auth_url: https://me.openstack.blueboxgrid.com:5001/v2.0 username: jlk password: FAKEPASSW0RD project_name: mastery register: launch with_sequence: count=8
在这个任务中,咱们使用with_sequence在数量8个上循环。每一个循环上item会替换为对应数字。这样容许咱们能够基于版本和数字来为咱们应用建立8个全新实例。咱们也假设能够有一个提早构建好的映像文件可使用,这样咱们就无需作任何更多的实例配置了。为了在未来的剧情中使用这些服务器,咱们须要将它们的细节添加到inventory中。 要实现这点,咱们注册运行结果到启动变量中,咱们将使用它们来建立运行时inventory实体:
- name: add hosts add_host: name: "{{ item.openstack.name }}" ansible_ssh_host: "{{ item.openstack.private_v4 }}" groups: new-foo-app with_items: launch.results
Deployment and upgrade strategies are a matter of taste. Each come with distinct advantages and disadvantages. Ansible does not possess an opinion on which is better, and therefore is well suited to perform deployments and upgrades regardless of the strategy. Ansible provides features and design patterns that facilitate a variety of styles with ease. Understanding the nature of each strategy and how Ansible can be tuned for that strategy will empower you to decide and design deployments for each of your applications.
In the next chapter, we'll cover topics that will help when things don't quite go as expected when executing Ansible playbooks.