Ansible 快速指南



Ansible - 简介

Ansible 是一个简单的开源 IT 引擎,它可以自动化应用程序部署、内部服务编排、云配置以及许多其他 IT 工具。

Ansible 易于部署,因为它不使用任何代理或自定义安全基础设施。

Ansible 使用 playbook 来描述自动化作业,playbook 使用非常简单的语言,即 YAML(这是一种人类可读的数据序列化语言,通常用于配置文件,但可用于许多存储数据的应用程序),易于人类理解、阅读和编写。因此,即使是 IT 基础设施支持人员也可以阅读和理解 playbook,并在需要时进行调试(YAML – 它以人类可读的形式存在)。

Ansible 旨在用于多层部署。Ansible 并非一次管理一个系统,而是通过描述所有系统之间的相互关系来模拟 IT 基础设施。Ansible 完全是无代理的,这意味着 Ansible 通过连接您的节点来工作 ssh(默认情况下)。但是,如果您想要其他连接方法,例如 Kerberos,Ansible 也提供此选项。

连接到节点后,Ansible 会推送称为“Ansible 模块”的小程序。Ansible 在您的节点上运行这些模块,并在完成后将其删除。Ansible 在简单的文本文件中管理您的清单(这些是主机文件)。Ansible 使用主机文件,可以在其中对主机进行分组,并可以控制 playbook 中特定组的操作。

主机文件示例

这是主机文件的内容:

#File name: hosts
#Description: Inventory file for your application. Defines machine type abc
node to deploy specific artifacts
# Defines machine type def node to upload
metadata.

[abc-node]
#server1 ansible_host = <target machine for DU deployment> ansible_user = <Ansible
user> ansible_connection = ssh
server1 ansible_host = <your host name> ansible_user = <your unix user>
ansible_connection = ssh

[def-node]
#server2 ansible_host = <target machine for artifact upload>
ansible_user = <Ansible user> ansible_connection = ssh
server2 ansible_host = <host> ansible_user = <user> ansible_connection = ssh

什么是配置管理

就 Ansible 而言,配置管理意味着它通过记录和更新描述企业硬件和软件的详细信息来维护产品性能的配置。

此类信息通常包括已应用于已安装软件包的确切版本和更新,以及硬件设备的位置和网络地址。例如,如果您想在企业中所有机器上安装新版本的 WebLogic/WebSphere 服务器,手动更新每台机器是不可行的。

您可以使用 Ansible playbook 和以最简单方式编写的清单,一次性在所有机器上安装 WebLogic/WebSphere。您只需列出清单中节点的 IP 地址,并编写一个 playbook 来安装 WebLogic/WebSphere。从您的控制机器运行 playbook,它将在所有节点上安装。

Ansible 如何工作?

下图显示了 Ansible 的工作原理。

Ansible 的工作原理是连接到您的节点并向其推送称为“Ansible 模块”的小程序。Ansible 然后执行这些模块(默认情况下通过 SSH),并在完成后将其删除。您的模块库可以驻留在任何机器上,不需要服务器、守护程序或数据库。

Ansible Works

上图中的管理节点是控制节点(管理节点),它控制 playbook 的整个执行。这是您运行安装的节点。清单文件提供 Ansible 模块需要运行的主机列表,管理节点进行 SSH 连接并在主机机器上执行小型模块并安装产品/软件。

Ansible 的优势在于它在安装模块后会将其删除,因此它有效地连接到主机,执行指令,如果成功安装,则删除复制到主机并已执行的代码。

Ansible - 环境搭建

在本章中,我们将学习 Ansible 的环境设置。

安装过程

当我们讨论部署时,主要有两种类型的机器:

  • 控制机器 - 可以管理其他机器的机器。

  • 远程机器 - 由控制机器处理/控制的机器。

一台控制机器可以处理多台远程机器。因此,为了管理远程机器,我们必须在控制机器上安装 Ansible。

控制机器要求

Ansible 可以从任何安装了 Python 2(版本 2.6 或 2.7)或 Python 3(版本 3.5 及更高版本)的机器上运行。

注意 - Windows 不支持控制机器。

默认情况下,Ansible 使用 ssh 来管理远程机器。

Ansible 不会添加任何数据库。它不需要启动或保持运行的任何守护程序。在管理远程机器时,Ansible 不会留下任何已安装或正在运行的软件。因此,升级到新版本的问题不存在。

Ansible 可以安装在具有上述要求的控制机器上,方法有很多种。您可以通过 Apt、yum、pkg、pip、OpenCSW、pacman 等安装最新版本。

在 Ubuntu 机器上通过 Apt 安装

要安装 Ansible,您必须在您的机器上配置 PPA。为此,您必须运行以下代码行:

$ sudo apt-get update 
$ sudo apt-get install software-properties-common 
$ sudo apt-add-repository ppa:ansible/ansible $ sudo apt-get update 
$ sudo apt-get install ansible

运行上述代码行后,您就可以通过 Ansible 管理远程机器了。只需运行 Ansible–version 来检查版本,并检查 Ansible 是否已正确安装。

Ansible - YAML 基础

Ansible 使用 YAML 语法来表达 Ansible playbook。本章概述了 YAML。Ansible 使用 YAML 是因为它与 XML 和 JSON 等其他数据格式相比,更易于人类理解、阅读和编写。

每个 YAML 文件可以选择以“---”开头,并以“... ”结尾。

理解 YAML

在本节中,我们将学习表示 YAML 数据的不同方法。

键值对

YAML 使用简单的键值对来表示数据。字典以键:值对的形式表示。

注意 - 冒号 : 和值之间应该有空格。

示例:学生记录

--- #Optional YAML start syntax 
james: 
   name: james john 
   rollNo: 34 
   div: B 
   sex: male 
… #Optional YAML end syntax 

缩写

您还可以使用缩写来表示字典。

示例

James: {name: james john, rollNo: 34, div: B, sex: male}

表示列表

我们也可以在 YAML 中表示列表。列表的每个元素(成员)都应在新行中写入,并具有相同的缩进,以“-”(- 和空格)开头。

示例

---
countries:  
   - America 
   - China 
   - Canada 
   - Iceland 
…

缩写

您还可以使用缩写来表示列表。

示例

Countries: [‘America’, ‘China’, ‘Canada’, ‘Iceland’] 

字典内的列表

我们可以在字典内使用列表,即键的值是列表。

示例

---  
james: 
   name: james john 
   rollNo: 34 
   div: B 
   sex: male 
   likes: 
      - maths 
      - physics 
      - english 
… 

字典列表

我们也可以创建字典列表。

示例

---  
- james: 
   name: james john 
   rollNo: 34 
      div: B 
   sex: male 
   likes: 
      - maths 
      - physics 
      - english 

- robert: 
      name: robert richardson 
      rollNo: 53 
      div: B 
      sex: male 
   likes: 
      - biology 
      - chemistry 
…  

YAML 使用“|”在显示多行时包含换行符,并使用“>”在显示多行时抑制换行符。因此,我们可以阅读和编辑长行。在这两种情况下,缩进都将被忽略。

我们也可以在 YAML 中表示布尔(True/false)值,其中布尔值可以不区分大小写。

示例

---  
- james: 
   name: james john 
   rollNo: 34 
   div: B 
   sex: male 
   likes: 
      - maths 
      - physics 
      - english 
   
   result: 
      maths: 87 
      chemistry: 45 
      biology: 56 
      physics: 70 
      english: 80 
   
   passed: TRUE 
   
   messageIncludeNewLines: | 
      Congratulation!! 
      You passed with 79% 
   
   messageExcludeNewLines: > 
      Congratulation!! 
      You passed with 79% 

一些与 Ansible 相关的常用词。

服务/服务器 - 机器上提供服务的进程。

机器 - 物理服务器、虚拟机 (vm) 或容器。

目标机器 - 我们即将使用 Ansible 配置的机器。

任务 - Ansible 管理的操作(运行这个,删除那个)等。

Playbook - 编写 Ansible 命令的 yml 文件,yml 在机器上执行。

Ansible - Ad hoc 命令

Ad hoc 命令是可以单独运行以执行快速功能的命令。这些命令不需要以后执行。

例如,您必须重新启动所有公司服务器。为此,您将从“/usr/bin/ansible”运行 Ad hoc 命令。

这些 ad-hoc 命令不用于配置管理和部署,因为这些命令是一次性使用的。

ansible-playbook 用于配置管理和部署。

并行性和 Shell 命令

一次以 12 个并行分支重新启动您的公司服务器。为此,我们需要设置 SSHagent 用于连接。

$ ssh-agent bash 
$ ssh-add ~/.ssh/id_rsa 

要在组“abc”中以 12 个并行分支为所有公司服务器运行重新启动:

$ Ansible abc -a "/sbin/reboot" -f 12

默认情况下,Ansible 将从当前用户帐户运行上述 Ad-hoc 命令。如果要更改此行为,则必须在 Ad-hoc 命令中传递用户名,如下所示:

$ Ansible abc -a "/sbin/reboot" -f 12 -u username

文件传输

您可以使用 Ad-hoc 命令在多台机器上并行执行大量 SCP(安全复制协议)文件。

将文件传输到许多服务器/机器

$ Ansible abc -m copy -a "src = /etc/yum.conf dest = /tmp/yum.conf"

创建新目录

$ Ansible abc -m file -a "dest = /path/user1/new mode = 777 owner = user1 group = user1 state = directory" 

删除整个目录和文件

$ Ansible abc -m file -a "dest = /path/user1/new state = absent"

管理软件包

Ad-hoc 命令可用于 yum 和 apt。以下是使用 yum 的一些 Ad-hoc 命令。

以下命令检查 yum 软件包是否已安装,但不更新它。

$ Ansible abc -m yum -a "name = demo-tomcat-1 state = present"

以下命令检查软件包是否未安装。

$ Ansible abc -m yum -a "name = demo-tomcat-1 state = absent" 

以下命令检查是否安装了最新版本的软件包。

$ Ansible abc -m yum -a "name = demo-tomcat-1 state = latest" 

收集事实

事实可用于在 playbook 中实现条件语句。您可以通过以下 Ad-hoc 命令找到所有事实的 adhoc 信息:

$ Ansible all -m setup 

Ansible - Playbook

在本章中,我们将学习 Ansible 中的 Playbook。

Playbook 是编写 Ansible 代码的文件。Playbook 使用 YAML 格式编写。YAML 代表 Yet Another Markup Language。Playbook 是 Ansible 的核心功能之一,它告诉 Ansible 执行什么操作。它们就像 Ansible 的待办事项列表,其中包含一系列任务。

Playbook 包含用户希望在特定机器上执行的步骤。Playbook 按顺序运行。Playbook 是 Ansible 所有用例的构建块。

Playbook 结构

每个 playbook 都包含一个或多个 play。Playbook 使用 Play 进行结构化。一个 playbook 中可以有多个 play。

play 的功能是将针对特定主机定义的一组指令进行映射。

YAML 是一种强类型语言;因此,编写 YAML 文件时需要格外小心。有不同的 YAML 编辑器,但我们更倾向于使用简单的编辑器,例如 notepad++。只需打开 notepad++ 并复制粘贴下面的 yaml,并将语言更改为 YAML(语言→YAML)。

YAML 以 ---(3 个连字符)开头

创建 Playbook

让我们从编写一个示例 YAML 文件开始。我们将逐步介绍 yaml 文件中编写的每一部分。

--- 
   name: install and configure DB
   hosts: testServer
   become: yes

   vars: 
      oracle_db_port_value : 1521
   
   tasks:
   -name: Install the Oracle DB
      yum: <code to install the DB>
    
   -name: Ensure the installed service is enabled and running
   service:
      name: <your service name>

以上是一个示例 Playbook,我们试图涵盖 playbook 的基本语法。将上述内容保存到文件中,例如 test.yml。YAML 语法需要遵循正确的缩进,编写语法时需要小心。

不同的 YAML 标签

现在让我们来看一下不同的 YAML 标签。以下是不同标签的描述:

name

此标签指定 Ansible playbook 的名称。也就是这个 playbook 将做什么。可以为 playbook 指定任何逻辑名称。

hosts

此标签指定要针对其运行任务的主机或主机组列表。hosts 字段/标签是必需的。它告诉 Ansible 在哪些主机上运行列出的任务。任务可以在同一台机器上运行,也可以在远程机器上运行。可以在多台机器上运行任务,因此 hosts 标签也可以包含一组主机的条目。

变量 (vars)

vars 标签允许您定义可在剧本中使用的变量。用法类似于任何编程语言中的变量。

任务 (tasks)

所有剧本都应包含要执行的任务或任务列表。任务是要执行的一系列操作。tasks 字段包含任务的名称。这作为用户的帮助文本。它不是必需的,但在调试剧本时非常有用。每个任务内部都链接到一段称为模块的代码。应该执行的模块以及要执行的模块所需的参数。

Ansible - 角色 (Roles)

角色提供了一个框架,用于完全独立或相互依赖的变量、任务、文件、模板和模块集合。

在 Ansible 中,角色是将剧本分解为多个文件的首要机制。这简化了编写**复杂剧本**的过程,并使其更易于重用。剧本的分解允许您将剧本逻辑地分解为可重用的组件。

每个角色基本上都限于特定功能或预期输出,所有必要的步骤都在该角色本身或列为依赖项的其他角色中提供该结果。

角色不是剧本。角色是小的功能,可以独立使用,但必须在剧本中使用。无法直接执行角色。角色没有关于角色将应用于哪个主机的显式设置。

顶级剧本是连接清单文件中的主机与应应用于这些主机的角色的桥梁。

创建新角色

角色的目录结构对于创建新角色至关重要。

角色结构

角色在文件系统上具有结构化布局。默认结构可以更改,但现在让我们坚持使用默认设置。

每个角色本身就是一个目录树。角色名称是 /roles 目录中的目录名称。

$ ansible-galaxy -h 

用法

ansible-galaxy [delete|import|info|init|install|list|login|remove|search|setup] [--help] [options] ... 

选项

  • -h, --help − 显示此帮助消息并退出。

  • -v, --verbose − 详细模式 (-vvv 用于更多信息,-vvvv 用于启用连接调试)

  • --version − 显示程序的版本号并退出。

创建角色目录

上述命令已创建角色目录。

$ ansible-galaxy init vivekrole 
ERROR! The API server (https://galaxy.ansible.com/api/) is not responding, please try again later. 

$ ansible-galaxy init --force --offline vivekrole 
- vivekrole was created successfully 

$ tree vivekrole/ 
vivekrole/ 
├── defaults 
│   └── main.yml 
├── files ├── handlers 
│   └── main.yml 
├── meta 
│   └── main.yml 
├── README.md ├── tasks 
│   └── main.yml 
├── templates ├── tests │   ├── inventory 
│   └── test.yml 
└── vars 
    └── main.yml 
 
8 directories, 8 files

并非所有目录都将在示例中使用,我们将在示例中显示其中一些目录的用法。

在剧本中使用角色

这是我们为演示目的编写的剧本代码。此代码是剧本 vivek_orchestrate.yml 的代码。我们已定义主机:tomcat-node 并调用了两个角色 – install-tomcatstart-tomcat

问题陈述是:我们有一个需要通过 Ansible 部署到机器上的 war 文件。

--- 
- hosts: tomcat-node 
roles: 
   - {role: install-tomcat} 
   - {role: start-tomcat} 

我们运行剧本的目录结构的内容。

Directory
$ ls 
ansible.cfg  hosts  roles  vivek_orchestrate.retry vivek_orchestrate.yml 

Roles

每个目录下都有一个 tasks 目录,其中包含一个 main.yml。install-tomcat 的 main.yml 内容为:

--- 
#Install vivek artifacts 
-  
   block: 
      - name: Install Tomcat artifacts
         action: > 
            yum name = "demo-tomcat-1" state = present 
         register: Output 
          
   always: 
      - debug: 
         msg: 
            - "Install Tomcat artifacts task ended with message: {{Output}}" 
            - "Installed Tomcat artifacts - {{Output.changed}}" 

start tomcat 的 main.yml 内容为:

#Start Tomcat          
-  
   block: 
      - name: Start Tomcat 
      command: <path of tomcat>/bin/startup.sh" 
      register: output 
      become: true 
   
   always: 
      - debug: 
         msg: 
            - "Start Tomcat task ended with message: {{output}}" 
            - "Tomcat started - {{output.changed}}" 

将剧本分解为角色的优点是,任何想要使用“安装 tomcat”功能的人都可调用“安装 Tomcat”角色。

将剧本分解为角色

如果不是角色,则可以将相应角色的 main.yml 内容复制到剧本 yml 文件中。但为了模块化,创建了角色。

任何可以作为可重用函数重用的逻辑实体都可以移动到角色。上面的例子展示了这一点。

运行命令来运行剧本。

-vvv option for verbose output – verbose output 
$ cd vivek-playbook/

这是运行剧本的命令。

$ sudo ansible-playbook -i hosts vivek_orchestrate.yml –vvv 
-----------------------------------------------------------------
----------------------------------------------------------------------- 

输出

生成的输出如屏幕上所示:

使用 /users/demo/vivek-playbook/ansible.cfg 作为配置文件。

PLAYBOOK: vivek_orchestrate.yml *********************************************************
*********************************************************** 
1 plays in vivek_orchestrate.yml 

PLAY [tomcat-node] **********************************************************************
******** ************************************************* 
 
TASK [Gathering Facts] *************************************************
****************************** ********************************************* 
Tuesday 21 November 2017  13:02:05 +0530 (0:00:00.056) 0:00:00.056 ****** 
Using module file /usr/lib/python2.7/sitepackages/ansible/modules/system/setup.py 
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: root 
<localhost> EXEC /bin/sh -c 'echo ~ && sleep 0' 
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo 
   /root/.ansible/tmp/ansible-tmp-1511249525.88-259535494116870 `" && 
   echo ansible-tmp-1511249525.88-259535494116870="` 
   echo /root/.ansible/tmp/ansibletmp-1511249525.88-259535494116870 `" ) && sleep 0' 
<localhost> PUT /tmp/tmpPEPrkd TO 
   /root/.ansible/tmp/ansible-tmp-1511249525.88259535494116870/setup.py 
<localhost> EXEC /bin/sh -c 'chmod u+x 
   /root/.ansible/tmp/ansible-tmp1511249525.88-259535494116870/ 
   /root/.ansible/tmp/ansible-tmp-1511249525.88259535494116870/setup.py && sleep 0' 
<localhost> EXEC /bin/sh -c '/usr/bin/python 
   /root/.ansible/tmp/ansible-tmp1511249525.88-259535494116870/setup.py; rm -rf 
   "/root/.ansible/tmp/ansible-tmp1511249525.88-259535494116870/" > /dev/null 2>&1 && sleep 0' 
ok: [server1] 
META: ran handlers 
 
TASK [install-tomcat : Install Tomcat artifacts] ***********************************
*************************************************************** 
task path: /users/demo/vivek-playbook/roles/install-tomcat/tasks/main.yml:5 
Tuesday 21 November 2017  13:02:07 +0530 (0:00:01.515)       0:00:01.572 ****** 
Using module file /usr/lib/python2.7/sitepackages/ansible/modules/packaging/os/yum.py 
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: root 
<localhost> EXEC /bin/sh -c 'echo ~ && sleep 0' 
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo 
   /root/.ansible/tmp/ansible-tmp-1511249527.34-40247177825302 `" && echo 
   ansibletmp-1511249527.34-40247177825302="` echo 
   /root/.ansible/tmp/ansible-tmp1511249527.34-40247177825302 `" ) && sleep 0' 
<localhost> PUT /tmp/tmpu83chg TO 
   /root/.ansible/tmp/ansible-tmp-1511249527.3440247177825302/yum.py 
<localhost> EXEC /bin/sh -c 'chmod u+x 
   /root/.ansible/tmp/ansible-tmp1511249527.34-40247177825302/ 
   /root/.ansible/tmp/ansible-tmp-1511249527.3440247177825302/yum.py && sleep 0' 
<localhost> EXEC /bin/sh -c '/usr/bin/python 
   /root/.ansible/tmp/ansible-tmp1511249527.34-40247177825302/yum.py; rm -rf 
   "/root/.ansible/tmp/ansible-tmp1511249527.34-40247177825302/" > /dev/null 2>
   &1 && sleep 0' 
changed: [server1] => { 
   "changed": true, 
   "invocation": { 
      "module_args": { 
         "conf_file": null, 
         "disable_gpg_check": false, 
         "disablerepo": null, 
         "enablerepo": null, 
         "exclude": null, 
         "install_repoquery": true, 
         "installroot": "/", 
         "list": null, 
         "name": ["demo-tomcat-1"], 
         "skip_broken": false, 
         "state": "present", 
         "update_cache": false, 
         "validate_certs": true 
      } 
   }, 
   "msg": "", 
   "rc": 0, 
   "results": [ 
      "Loaded plugins: product-id, 
      search-disabled-repos, 
      subscriptionmanager\nThis system is not registered to Red Hat Subscription Management. 
      You can use subscription-manager to register.\nResolving Dependencies\n--> 
      Running transaction check\n---> 
      Package demo-tomcat-1.noarch 0:SNAPSHOT-1 will be installed\n--> Finished Dependency 
      Resolution\n\nDependencies Resolved\n
      \n================================================================================\n 
      Package Arch Version Repository         
      Size\n==================================================================\nInstalling:\n 
      demo-tomcat-1 noarch SNAPSHOT-1 demo-repo1 7.1 M\n\nTransaction 
      Summary\n==================================================================\nInstall  1 
      Package\n\nTotal download size: 7.1 M\nInstalled size: 7.9 M\nDownloading 
         packages:\nRunning transaction 
      check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n  Installing : 
      demotomcat-1-SNAPSHOT-1.noarch 1/1 \n  Verifying  : 
      demo-tomcat-1-SNAPSHOT-1.noarch 1/1 \n\nInstalled:\n  
      demo-tomcat-1.noarch 0:SNAPSHOT-1 \n\nComplete!\n" 
   ] 
} 
 
TASK [install-tomcat : debug] **********************************************************
*************************************************************************** 
task path: /users/demo/vivek-playbook/roles/install-tomcat/tasks/main.yml:11 
Tuesday 21 November 2017  13:02:13 +0530 (0:00:06.757) 0:00:08.329 ****** 
ok: [server1] => { 
   "changed": false, 
   "msg": [ 
      "Install Tomcat artifacts task ended with message: {
         u'msg': u'', u'changed': True, u'results': 
         [u'Loaded plugins: product-id, 
         search-disabledrepos, 
         subscription-manager\\nThis system is not registered to Red Hat Subscription Management. 
         You can use subscription-manager to register.\\nResolving Dependencies\\n--> 
         Running transaction check\\n---> 
         Package demo-tomcat-1.noarch 0:SNAPSHOT-1 will be installed\\n--> 
         Finished Dependency Resolution\\n
         \\nDependencies 
         Resolved\\n\\n==================================================================\\n 
         Package Arch Version Repository         
         Size\\n======================================================================== 
         =====\\nInstalling:\\n demo-tomcat-1 noarch SNAPSHOT-1 demo-repo1 7.1 M\\n\\nTransaction 
         Summary\\n=========================================================\\nInstall  1 
         Package\\n\\nTotal download size: 7.1 M\\nInstalled size: 7.9 M\\nDownloading 
            packages:\\nRunning 
         transaction check\\nRunning transaction test\\nTransaction test succeeded\\nRunning 
            transaction\\n  
         Installing : demo-tomcat-1-SNAPSHOT-1.noarch 1/1 \\n  Verifying  : 
         demo-tomcat-1-SNAPSHOT-1.noarch
         1/1 \\n\\nInstalled:\\n  demo-tomcat-1.noarch 0:SNAPSHOT-1  \\n\\nComplete!\\n'], u'rc': 0
      }", 
      "Installed Tomcat artifacts - True" 
   ] 
} 
 
TASK [install-tomcat : Clean DEMO environment] ****************************************
************************************************************ 
task path: /users/demo/vivek-playbook/roles/install-tomcat/tasks/main.yml:19 
Tuesday 21 November 2017  13:02:13 +0530 (0:00:00.057) 0:00:08.387 ****** 
[WARNING]: when statements should not include jinja2 templating delimiters such as {{ }} or 
   {% %}. Found: {{installationOutput.changed}} 
 
Using module file /usr/lib/python2.7/sitepackages/ansible/modules/files/file.py 
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: root 
<localhost> EXEC /bin/sh -c 'echo ~ && sleep 0' 
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo 
   /root/.ansible/tmp/ansible-tmp-1511249534.13-128345805983963 `" && echo 
   ansible-tmp-1511249534.13-128345805983963="` echo 
   /root/.ansible/tmp/ansibletmp-1511249534.13-128345805983963 `" ) && sleep 0' 
<localhost> PUT /tmp/tmp0aXel7 TO 
   /root/.ansible/tmp/ansible-tmp-1511249534.13128345805983963/file.py 
<localhost> EXEC /bin/sh -c 'chmod u+x 
   /root/.ansible/tmp/ansible-tmp1511249534.13-128345805983963/ 
   /root/.ansible/tmp/ansible-tmp-1511249534.13128345805983963/file.py && sleep 0' 
<localhost> EXEC /bin/sh -c '/usr/bin/python 
   /root/.ansible/tmp/ansible-tmp1511249534.13-128345805983963/file.py; rm -rf 
   "/root/.ansible/tmp/ansible-tmp1511249534.13-128345805983963/" > /dev/null 2>&1 
   && sleep 0' 
changed: [server1] => { 
   "changed": true, 
      "diff": { 
         "after": { 
            "path": "/users/demo/DEMO", 
            "state": "absent" 
      }, 
      "before": { 
         "path": "/users/demo/DEMO", 
         "state": "directory" 
      } 
   },

   "invocation": { 
      "module_args": { 
         "attributes": null, 
         "backup": null, 
         "content": null, 
         "delimiter": null, 
         "diff_peek": null, 
         "directory_mode": null, 
         "follow": false, 
         "force": false, 
         "group": null, 
         "mode": null, 
         "original_basename": null, 
         "owner": null, 
         "path": "/users/demo/DEMO", 
         "recurse": false, 
         "regexp": null, 
         "remote_src": null, 
         "selevel": null, 
         "serole": null, 
         "setype": null, 
         "seuser": null, 
         "src": null, 
         "state": "absent", 
         "unsafe_writes": null, 
         "validate": null 
      } 
   }, 
   "path": "/users/demo/DEMO", 
   "state": "absent" 
} 
 
TASK [install-tomcat : debug] ********************************************************
************************************************************* 
task path: /users/demo/vivek-playbook/roles/install-tomcat/tasks/main.yml:29 
Tuesday 21 November 2017  13:02:14 +0530 (0:00:00.257)       0:00:08.645 ****** 
ok: [server1] => {
   "changed": false, 
   "msg": [ 
      "Clean DEMO environment task ended with message:{u'diff': {u'after': {u'path': 
         u'/users/demo/DEMO', u'state': u'absent'}, 
      u'before': {u'path': u'/users/demo/DEMO', u'state': u'directory'}}, u'state': u'absent', 
         u'changed': True, u'path': u'/users/demo/DEMO'}", 
      "check value  :True" 
   ] 
} 
 
TASK [install-tomcat : Copy Tomcat to user home] *************************************
******************************************************** 
task path: /users/demo/vivek-playbook/roles/install-tomcat/tasks/main.yml:37 
Tuesday 21 November 2017  13:02:14 +0530 (0:00:00.055)       0:00:08.701 ****** 
[WARNING]: when statements should not include jinja2 templating delimiters such as {{ }} or 
   {% %}. Found: {{installationOutput.changed}} 
 
Using module file /usr/lib/python2.7/sitepackages/ansible/modules/commands/command.py 
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: root 
<localhost> EXEC /bin/sh -c 'echo ~ && sleep 0' 
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo 
   /root/.ansible/tmp/ansible-tmp-1511249534.43-41077200718443 `" && echo 
   ansibletmp-1511249534.43-41077200718443="` echo 
   /root/.ansible/tmp/ansible-tmp1511249534.43-41077200718443 `" ) && sleep 0' 
<localhost> PUT /tmp/tmp25deWs TO 
   /root/.ansible/tmp/ansible-tmp-1511249534.4341077200718443/command.py 
<localhost> EXEC /bin/sh -c 'chmod u+x 
   /root/.ansible/tmp/ansible-tmp1511249534.43-41077200718443/ 
   /root/.ansible/tmp/ansible-tmp-1511249534.4341077200718443/command.py && sleep 0' 
<localhost> EXEC /bin/sh -c '/usr/bin/python 
   /root/.ansible/tmp/ansible-tmp1511249534.43-41077200718443/command.py; rm -rf 
   "/root/.ansible/tmp/ansibletmp-1511249534.43-41077200718443/" > /dev/null 2>&1 
   && sleep 0' 
changed: [server1] => { 
   "changed": true, 
   "cmd": [ 
      "cp", 
      "-r", 
      "/opt/ansible/tomcat/demo", 
      "/users/demo/DEMO/" 
   ],
   "delta": "0:00:00.017923", 
   "end": "2017-11-21 13:02:14.547633", 
   "invocation": { 
      "module_args": { 
         "_raw_params": "cp -r /opt/ansible/tomcat/demo /users/demo/DEMO/", 
         "_uses_shell": false, 
         "chdir": null, 
         "creates": null, 
         "executable": null, 
         "removes": null, 
         "warn": true 
      } 
   }, 
   "rc": 0, 
   "start": "2017-11-21 13:02:14.529710", 
   "stderr": "", 
   "stderr_lines": [], 
   "stdout": "", 
   "stdout_lines": [] 
} 
 
TASK [install-tomcat : debug] ********************************************************
********************************************************** 
task path: /users/demo/vivek-playbook/roles/install-tomcat/tasks/main.yml:47 
Tuesday 21 November 2017  13:02:14 +0530 (0:00:00.260)       0:00:08.961 ****** 
ok: [server1] => { 
   "changed": false, 
   "msg": "Copy Tomcat to user home task ended with message {
      'stderr_lines': [], u'changed': True, u'end': u'2017-11-21 13:02:14.547633', u'stdout': 
      u'', u'cmd': [u'cp', u'-r', u'/opt/ansible/tomcat/demo', u'/users/demo/DEMO/'], u'rc': 0, 
      u'start': u'2017-11-21 13:02:14.529710', u'stderr': u'', u'delta': u'0:00:00.017923', 
      'stdout_lines': []}" 
} 
 
TASK [start-tomcat : Start Tomcat] **************************************************
********************************************************** 
task path: /users/demo/vivek-playbook/roles/start-tomcat/tasks/main.yml:5 
Tuesday 21 November 2017  13:02:14 +0530 (0:00:00.044)       0:00:09.006 ****** 
Using module file /usr/lib/python2.7/sitepackages/ansible/modules/commands/command.py 
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: root 
<localhost> EXEC /bin/sh -c 'echo ~ && sleep 0' 
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo 
   /root/.ansible/tmp/ansible-tmp-1511249534.63-46501211251197 `" && echo 
   ansibletmp-1511249534.63-46501211251197="` echo 
   /root/.ansible/tmp/ansible-tmp1511249534.63-46501211251197 `" ) && sleep 0' 
<localhost> PUT /tmp/tmp9f06MQ TO 
   /root/.ansible/tmp/ansible-tmp-1511249534.6346501211251197/command.py 
<localhost> EXEC /bin/sh -c 'chmod u+x 
   /root/.ansible/tmp/ansible-tmp1511249534.63-46501211251197/ 
   /root/.ansible/tmp/ansible-tmp-1511249534.6346501211251197/command.py && sleep 0' 
<localhost> EXEC /bin/sh -c '/usr/bin/python 
   /root/.ansible/tmp/ansible-tmp1511249534.63-46501211251197/command.py; rm -rf 
   "/root/.ansible/tmp/ansibletmp-1511249534.63-46501211251197/" > /dev/null 2>&1 
   && sleep 0' 
changed: [server1] => { 
   "changed": true, 
   "cmd": [ "/users/demo/DEMO/bin/startup.sh" ], 
   "delta": "0:00:00.020024", 
   "end": "2017-11-21 13:02:14.741649", 
   "invocation": { 
      "module_args": { 
         "_raw_params": "/users/demo/DEMO/bin/startup.sh", 
         "_uses_shell": false, 
         "chdir": null, 
         "creates": null, 
         "executable": null, 
         "removes": null, 
         "warn": true 
      } 
   }, 
   "rc": 0, 
   "start": "2017-11-21 13:02:14.721625", 
   "stderr": "", 
   "stderr_lines": [], 
   "stdout": "Tomcat started.", 
   "stdout_lines": [ "Tomcat started." ] 
} 
 
TASK [start-tomcat : debug] *************************************************
********************************************************************** 
task path: /users/demo/vivek-playbook/roles/start-tomcat/tasks/main.yml:10 
Tuesday 21 November 2017  13:02:14 +0530 (0:00:00.150)       0:00:09.156 ****** 
ok: [server1] => { 
   "changed": false, 
   "msg": [ 
      "Start Tomcat task ended with message: {'
         stderr_lines': [], u'changed': True, u'end': u'2017-11-21 13:02:14.741649', u'stdout': 
         u'Tomcat started.', u'cmd': [u'/users/demo/DEMO/bin/startup.sh'], u'rc': 0, u'start': 
         u'2017-11-21 13:02:14.721625', u'stderr': u'', u'delta': u'0:00:00.020024', 
         'stdout_lines': [u'Tomcat started.']}", 
      "Tomcat started - True" 
   ] 
} 
META: ran handlers 
META: ran handlers 
 
PLAY RECAP ******************************************************************************* 
********************************************************* 
server1  : ok = 9    changed = 4    unreachable = 0    failed = 0 
 
Tuesday 21 November 2017  13:02:14 +0530 (0:00:00.042)       0:00:09.198 ****** 
=============================================================================== 
install-tomcat : Install Tomcat artifacts ------------------------------- 6.76s 
/users/demo/vivek-playbook/roles/install-tomcat/tasks/main.yml:5 -------------- 
Gathering Facts --------------------------------------------------------- 1.52s 
 ------------------------------------------------------------------------------ 
install-tomcat : Copy Tomcat to user home ------------------------------- 0.26s 
/users/demo/vivek-playbook/roles/install-tomcat/tasks/main.yml:37 ------------- 

install-tomcat : Clean DEMO environment --------------------------------- 0.26s 
/users/demo/vivek-playbook/roles/install-tomcat/tasks/main.yml:19 ------------- 

start-tomcat : Start Tomcat --------------------------------------------- 0.15s 
/users/demo/vivek-playbook/roles/start-tomcat/tasks/main.yml:5 ----------------

install-tomcat : debug -------------------------------------------------- 0.06s 
/users/demo/vivek-playbook/roles/install-tomcat/tasks/main.yml:11 ------------- 

install-tomcat : debug -------------------------------------------------- 0.06s 
/users/demo/vivek-playbook/roles/install-tomcat/tasks/main.yml:29 ------------- 

install-tomcat : debug -------------------------------------------------- 0.04s 
/users/demo/vivek-playbook/roles/install-tomcat/tasks/main.yml:47 ------------- 

start-tomcat : debug ---------------------------------------------------- 0.04s 
/users/demo/vivek-playbook/roles/start-tomcat/tasks/main.yml:10 --------------- 

点击以下 URL,您将被定向到如下所示的页面: http://10.76.0.134:11677/HelloWorld/HelloWorld

Hello World

已部署的 war 文件只有一个 servlet,它显示“Hello World”。由于在 ansible.cfg 文件中添加了条目,因此详细输出显示每个任务所花费的时间:

[defaults] 
callback_whitelist = profile_tasks 

Ansible - 变量

剧本中的变量与在任何编程语言中使用变量非常相似。它帮助您使用和分配变量的值,并在剧本中的任何地方使用它。可以在变量的值周围设置条件,并相应地在剧本中使用它们。

示例

- hosts : <your hosts> 
vars:
tomcat_port : 8080 

在上面的示例中,我们定义了一个名为 tomcat_port 的变量,并为该变量分配了值 8080,可以在需要时在您的剧本中使用它。

现在参考共享的示例。以下代码来自其中一个角色 (install-tomcat):

block: 
   - name: Install Tomcat artifacts 
      action: > 
      yum name = "demo-tomcat-1" state = present 
      register: Output 
          
   always: 
      - debug: 
         msg: 
            - "Install Tomcat artifacts task ended with message: {{Output}}" 
            - "Installed Tomcat artifacts - {{Output.changed}}" 

此处,输出是使用的变量。

让我们遍历上面代码中使用的所有关键字:

  • block − Ansible 语法,用于执行给定的块。

  • name − 块的相关名称 - 这用于日志记录,并有助于调试已成功执行的所有块。

  • action − action 标签旁边的代码是要执行的任务。action 也是 yaml 中使用的 Ansible 关键字。

  • register − 使用 register 关键字注册 action 的输出,Output 是保存 action 输出的变量名称。

  • always − 也是 Ansible 关键字,它表示下面的内容将始终执行。

  • msg − 显示消息。

变量用法 - {{Output}} -->

这将读取变量 Output 的值。此外,由于它在 msg 选项卡中使用,它将打印输出变量的值。

此外,您还可以使用变量的子属性。例如,检查 {{Output.changed}} 输出是否已更改,并相应地使用它。

剧本中的异常处理

Ansible 中的异常处理类似于任何编程语言中的异常处理。下面显示了剧本中异常处理的示例。

tasks: 
   - name: Name of the task to be executed 
      block: 
         - debug: msg = 'Just a debug message , relevant for logging' 
         - command: <the command to execute> 
      
      rescue: 
         - debug: msg = 'There was an exception.. ' 
         - command: <Rescue mechanism for the above exception occurred) 
      
      always: 
         - debug: msg = "this will execute in all scenarios. Always will get logged" 

以下是异常处理的语法。

  • rescuealways 是特定于异常处理的关键字。

  • Block 是编写代码的地方(在 Unix 机器上执行的任何内容)。

  • 如果 block 功能内编写的命令失败,则执行将到达 rescue 块并被执行。如果 block 功能下的命令没有错误,则不会执行 rescue。

  • Always 在所有情况下都会执行。

  • 因此,如果我们将其与 java 进行比较,则它类似于 try、catch 和 finally 块。

  • 此处,Block 类似于try 块,您可以在其中编写要执行的代码,rescue 类似于catch 块always 类似于finally

循环

以下示例演示了在 Ansible 中使用循环。

任务是从一个目录将所有 war 文件复制到 tomcat webapps 文件夹。

以下示例中使用的许多命令之前已经介绍过。在这里,我们将重点关注循环的使用。

最初在“shell”命令中,我们执行了 ls *.war。因此,它将列出目录中的所有 war 文件。

该命令的输出保存在名为 output 的变量中。

要循环,使用“with_items”语法。

with_items: "{{output.stdout_lines}}" --> output.stdout_lines 为我们提供了逐行输出,然后我们使用 Ansible 的 with_items 命令在输出上循环。

附加示例输出只是为了让大家了解如何在 with_items 命令中使用 stdout_lines。

--- 
#Tsting 
- hosts: tomcat-node 
   tasks: 
      - name: Install Apache 
      shell: "ls *.war" 
      register: output 
      args: 
         chdir: /opt/ansible/tomcat/demo/webapps 
      
      - file: 
         src: '/opt/ansible/tomcat/demo/webapps/{{ item }}' 
         dest: '/users/demo/vivek/{{ item }}' 
         state: link 
      with_items: "{{output.stdout_lines}}"
Loop

剧本整体被分解成块。要执行的最小步骤写在块中。在块中编写特定指令有助于隔离功能并在需要时使用异常处理来处理它。

变量用法、异常处理和循环中介绍了块的示例。

条件语句

条件语句用于根据条件运行特定步骤。

--- 
#Tsting 
- hosts: all 
   vars: 
      test1: "Hello Vivek" 
   tasks: 
      - name: Testing Ansible variable 
      debug: 
         msg: "Equals" 
         when: test1 == "Hello Vivek" 

在这种情况下,由于 when 条件中提到的 test1 变量相等,因此将打印 Equals。when 可与逻辑 OR 和逻辑 AND 条件一起使用,就像在所有编程语言中一样。

Conditional Output

只需将 test1 变量的值从 Hello Vivek 更改为 Hello World,然后查看输出。

Changed Conditional Output

Ansible - 高级执行

在本章中,我们将学习 Ansible 的高级执行。

如何按任务限制执行

这是一个非常重要的执行策略,其中只需要执行一次执行,而不是整个剧本。例如,假设您只想停止服务器(如果出现生产问题),然后在应用补丁后,您只想启动服务器。

这里,在原始剧本中,停止和启动是同一剧本中不同角色的一部分,但这可以使用标签来处理。我们可以为不同的角色(反过来将具有任务)提供不同的标签,因此,根据执行者提供的标签,只有指定的角色/任务才能执行。因此,对于上面提供的示例,我们可以添加如下标签:

- {role: start-tomcat, tags: ['install']}} 

以下命令有助于使用标签:

ansible-playbook -i hosts <your yaml> --tags "install" -vvv

使用上述命令,只会调用 start-tomcat 角色。提供的标签区分大小写。确保将完全匹配项传递给命令。

如何按主机限制执行

有两种方法可以在特定主机上执行特定步骤。对于特定角色,定义主机 - 指明应在哪些特定主机上运行该特定角色。

示例

- hosts: <A> 
   environment: "{{your env}}" 
   pre_tasks: 
      - debug: msg = "Started deployment. 
      Current time is {{ansible_date_time.date}} {{ansible_date_time.time}} " 
     
   roles: 
      - {role: <your role>, tags: ['<respective tag>']} 
   post_tasks: 
      - debug: msg = "Completed deployment. 
      Current time is {{ansible_date_time.date}} {{ansible_date_time.time}}" 
 
- hosts: <B> 
   pre_tasks: 
      - debug: msg = "started.... 
      Current time is {{ansible_date_time.date}} {{ansible_date_time.time}} " 
        
   roles: 
      - {role: <your role>, tags: ['<respective tag>']} 
   post_tasks: 
      - debug: msg = "Completed the task.. 
      Current time is {{ansible_date_time.date}} {{ansible_date_time.time}}" 

根据上面的示例,根据提供的主机,只会调用相应的角色。现在我的主机 A 和 B 在主机(清单文件)中定义。

替代方案

另一种解决方案可能是使用变量定义剧本的主机,然后通过--extra-vars传递特定的主机地址:

# file: user.yml  (playbook) 
--- 
- hosts: '{{ target }}' 
   user: ... 
playbook contd…. 

运行剧本

ansible-playbook user.yml --extra-vars "target = "<your host variable>"

如果未定义 {{ target }},则剧本不会执行任何操作。如果需要,也可以通过主机文件中的组传递。如果没有提供额外的变量,这不会造成损害。

针对单个主机的剧本

$ ansible-playbook user.yml --extra-vars "target = <your hosts variable>" --listhosts 

Ansible - 故障排除

调试 Ansible 剧本最常见的策略是使用以下模块:

调试和注册

这两个是 Ansible 中可用的模块。出于调试目的,我们需要明智地使用这两个模块。以下列出了示例。

使用详细模式

使用 Ansible 命令,可以提供详细级别。您可以使用详细级别一 (-v) 或二 (-vv) 运行命令。

重要提示

在本节中,我们将通过几个示例来了解一些概念。

如果您没有引用以变量开头的参数。例如,

vars: 
   age_path: {{vivek.name}}/demo/ 
   
{{vivek.name}} 

这将引发错误。

解决方案

vars: 
   age_path: "{{vivek.name}}/demo/" – marked in yellow is the fix. 
 
How to use register -> Copy this code into a yml file say test.yml and run it  
--- 
#Tsting 
- hosts: tomcat-node 
   tasks: 
 
   - shell: /usr/bin/uptime 
      register: myvar 
      - name: Just debugging usage 
         debug: var = myvar 

当我通过命令 Ansible-playbook -i hosts test.yml 运行此代码时,我得到的输出如下所示。

如果看到yaml文件,我们已经将命令的输出注册到一个变量——myvar中,并只是打印了输出。

黄色标记的文本告诉我们关于变量myvar的属性,这些属性可用于进一步的流程控制。这样我们就可以找出特定变量公开的属性。以下调试命令对此有所帮助。

$ ansible-playbook -i hosts test.yml 

PLAY [tomcat-node] ***************************************************************
**************** ****************************************************************
*************** ****************************** 
 
TASK [Gathering Facts] *****************************************************************
************** *****************************************************************
************** ************************** 
Monday 05 February 2018  17:33:14 +0530 (0:00:00.051) 0:00:00.051 ******* 
ok: [server1] 
 
TASK [command] ******************************************************************
************* ******************************************************************
************* ********************************** 
Monday 05 February 2018  17:33:16 +0530 (0:00:01.697) 0:00:01.748 ******* 
changed: [server1] 
 
TASK [Just debugging usage] ******************************************************************
************* ******************************************************************
************* ********************* 
Monday 05 February 2018  17:33:16 +0530 (0:00:00.226) 0:00:01.974 ******* 
ok: [server1] => { 
   "myvar": { 
      "changed": true, 
      "cmd": "/usr/bin/uptime", 
      "delta": "0:00:00.011306", 
      "end": "2018-02-05 17:33:16.424647", 
      "rc": 0, 
      "start": "2018-02-05 17:33:16.413341", 
      "stderr": "", 
      "stderr_lines": [], 
      "stdout": " 17:33:16 up 7 days, 35 min,  1 user,  load average: 0.18, 0.15, 0.14", 
      "stdout_lines": [ 
         " 17:33:16 up 7 days, 35 min,  1 user,  load average: 0.18, 0.15, 0.14" 
      ] 
   } 
} 
 
PLAY RECAP ****************************************************************************
**********************************************************************************
 ************************************** 
server1 : ok = 3    changed = 1    unreachable = 0    failed = 0 

常见的Playbook问题

在本节中,我们将学习一些常见的Playbook问题。这些问题包括:

  • 引用
  • 缩进

Playbook是用yaml格式编写的,以上两点是yaml/playbook中最常见的问题。

Yaml不支持基于制表符的缩进,只支持基于空格的缩进,因此需要注意这一点。

注意——编写完yaml后,打开这个网站(https://editor.swagger.io/),将你的yaml复制粘贴到左侧,以确保yaml能够正确编译。这只是一个提示。

Swagger会将错误以警告和错误的形式进行区分。

广告