以下配置都是以下表环境为例

角色

主机名

IP地址

组名

CPU

控制主节点

ansiblecontrol

192.168.242.10

---

2C

被管理节点

web1

192.168.242.11

webservers

2C

被管理节点

web2

192.168.242.12

webservers

2C

Ansible安装

安装前提


对管理主机要求


目前,只要机器上安装了 Python 2.6 (windows 系统不可以做控制主机 ) ,都可以运行 Ansible.



主机的系统可以是 Red Hat, Debian, CentOS, OS X, BSD 的各种版本等等。




对托管主机要求



托管节点上需要安装 Python 2.4 及以上的版本。但如果版本低于 Python 2.5 ,则需要额外安装



一个模块 : python-simplejson




管理主机:



1 、管理你的被管理节点



        定义资产管理清单-- 在资产清单内定义的就是被管理节点



2 、定义任务



        通过ad-hoc 、 playbook 、 role 的方式定义任务



3 、下发任务



        在Ansible 管理节点上定义的任务,下发到被管理节点上!



        管理节点,是要和被管理节点建立通信




被管理节点:



        1、执行 Ansible Controller 下发的任务



        2、提供应用访问




安装Ansible

Ansible环境准备

角色名

IP

master.zjm.com

192.168.242.10

node1.zjm.com

192.168.242.11

node2.zjm.com

192.168.242.12

源码安装:源码安装需要python2.6以上版本,其依赖模块paramiko、PyYAML、Jinja2、httplib2、 simplejson、pycrypto模块,以上模块可以通过pip或easy_install 进行安装

pip安装:pip是专门用来管理Python模块的工具,Ansible会将每次正式发布都更新到pip仓库中。所以通过pip 安装或更新Ansible,会比较稳妥的拿到最新稳定版。

yum安装

安装 CentOS 7 的 EPEL repository

[root@master ~]# yum install -y epel-release

使用 yum 来安装 ansible

[root@master ~]#  yum install -y ansible

查看ansible的版本

[root@master ~]# ansible --version
ansible 2.9.23
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /bin/ansible
  python version = 2.7.5 (default, Aug  7 2019, 00:51:29) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]

ad-hoc的方式确定下ansible能否正常工作

[root@master ~]# ansible localhost -m ping
localhost | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

配置运行环境

配置Ansible环境

Ansible配置文件是以ini格式存储配置数据的,在 Ansible 中,几乎所有的配置项都可以通过



Ansible 的 playbook 或环境变量来重新赋值。 在运行 Ansible 命令时,命令将会按照预先设定的顺序查找配置文件, 如下所示



1 ) ANSIBLE_CONFIG:首 先, Ansible 命令会检查环境变量,及这个环境变量将指向的配置文件。



2 ) ./ansible.cfg: 其次, 将会检查当前目录下的 ansible.cfg 配置文件。



3 )~/.ansible.cfg :再次, 将会检查当前用户 home 目录下的 . ansible.cfg 配置文件。



4 ) /etc/ansible/ansible.cfg: 最后,将会检查在用软件包管理工具安装 Ansible 时自动产生的配置文件。




1. 使用环境变量方式来配置



大多数的 Ansible 参数可以通过设置带有 ANSIBLE, 开头的环境变量进行配置,参数名称必须都是大写 字母, 如下配置项: export ANSIBLE_SUDO_USER=root



设置了环境变量之后, ANSIBLE_SUDO_USER 就可以在 playbook 中直接引用。




2. 设置 ansible.cfg 配置参数



        • inventory :这个参数表示资源清单 inventory 文件的位置



        • library :这个 library 参数就是指向存放 Ansible 模块的目录



        • forks :设置默认情况下 Ansible 最多能有多少个进程同时工作, 默认设置最多 5 个进程并行处理。



        • sudo_user :设置默认执行命令的用户



        • remote_port :指定连接被管节点的管理端口, 默认是 22



        • host_key_checking :这是设置是否检查 SSH 主机的密钥。



        • timeout :这是设置 SSH 连接的超时间隔, 单位是秒



        • log_path :Ansible 系统默认是不记录日志的, 如果想把 Ansible 系统的输出记录到日志文件中,需要设置 _ 来指定一个存储 日志的文。




使用公钥认证



如果有台被管节点重新安装系统并在 known hosts 中有了与之前不同的密钥信息,就会提示一个密钥不匹配的错误信息, 直到被纠正为止。 在使用 Ansible 时, 如果有台被管节点没有在 known_hosts 中被初始化,将会在使用 Ansible 或定时执行 Ansible 时提示对 key 信息的确认。



如果你不想出现这种情况, 并且你明白禁用此项行为的含义, 只要修改 home 目录下

~/.ansible.cfg 或 /etc/ansible/ansible.cfg 的配置项:

[defaults]
host_key_checking = False


 或者直接在控制主机的操作系统中设置环境变量如下:

$export ANSIBLE_HOST_KEY_CHECKING=False

配置 Linux 主机 SSH 无密码访问


为了避免 Ansible 下发指令时输入目标主机密码, 通过证书签名达到 SSH 无密码是一个好的方案。推荐使用 ssh-keygen 与 ssh-copy-id 来实现快速证书的生成及公钥下发,其中 ssh-keygen 生产一对密钥,使用ssh-copy-id 来下发生成的公钥。



或者直接在控制主机的操作系统中设置环境变量, 如下所示 :



$export ANSIBLE_HOST_KEY_CHECKING=False




[root@master ~]# vi /etc/hosts
[root@master ~]# tail -3  /etc/hosts
192.168.242.10 master
192.168.242.11 node1
192.168.242.12 node2

1、在控制主机上创建密钥

[root@master ~]# ssh-keygen -f ~/.ssh/id_rsa -P '' -q
[root@master ~]# ls -l ~/.ssh
total 8
-rw-------. 1 root root 1679 Aug 11 23:02 id_rsa
-rw-r--r--. 1 root root  393 Aug 11 23:02 id_rsa.pub

2、下发密钥到被管理节点

[root@master ~]# ssh-copy-id node1
[root@master ~]# ssh-copy-id node2

3、验证SSH无密钥配置是否成功

[root@master ~]# for name in node{1,2}; do ssh $name hostname; done
node1
node2

Ansible Inventory

在大规模的配置管理工作中,我们需要管理不同业务的不同机器,这些机器的信息都存放在Ansible的Inventory组件里面,在我们工作中配置部署针对的主机必须先存放在Inventory里面,这样才能使用Ansible对它进行操作,默认Ansible的Inventory是一个静态的INI格式的文件/etc/ansible/hosts,当然,还可以通过ANSIBLE_HOSTS环境变量指定或者运行ansible和ansible-playbook的时候用-i参数临时设置

定义主机和主机组

具体的定义实例

[root@master ~]# vi /etc/ansible/hosts
[root@master ~]# tail -11 /etc/ansible/hosts
192.168.242.11 ansible_ssh_pass='123'
192.168.242.12 ansible_ssh_pass='123'

[docker]
192.168.242.1[1:2]

[docker:vars]
ansible_ssh_pass='123'

[ansible:children]
docker

第一二行:定义了一个主机是192.168.242.11/12,使用Inventory内置变量定义了SSH登录密码

第三行:定义了一个docker的组,第四行:定义了docker组下有两台主机192.168.242.11/192.168.242.12,用':'可以表示连续的多个,例如1:5,则为从一到五

第五六行:针对docker组使用了Inventory内置变量定义了SSH登陆密码

第七八行:定义了一个ansible的组,在这个组下包含了docker组



下面是分别针对不同的主机和主机组进行 Ansible 的 ping 模块检测

[root@master ~]# ansible 192.168.242.11:192.168.242.12 -m ping -o
192.168.242.12 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
192.168.242.11 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
[root@master ~]# ansible docker -m ping -o
192.168.242.12 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
192.168.242.11 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
[root@master ~]# ansible ansible -m ping -o
192.168.242.12 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
192.168.242.11 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}

动态Inventory

在实际应用部署中会有大量的主机列表,如果手动维护这些列表将是一个非常繁琐的事情,其实Ansible还支持动态的Inventory,动态Inventory就是Ansible所有的Inventory文件里面的主机列表和变量信息都支持从外部拉取



关于引用动态 Inventory 的功能配置只需要把 ansible.cfg 文件中 inventory 的定义值改成一个执行脚本即可。这个脚本的内容不受任何编程语言限制,但是这个脚本使用参数时有一定的规范并且对脚本 执行的结果也有要求。这个脚本需要支持两个参数




--list 或者 -l: 这个参数运行后会显示所有的主机以及主机组的信息( JSON 格式)。



--host 或者 -H: 这个参数后面需要指定一个 host ,运行结果会返回这台主机的所有信息( 包括认证信息、主机变量等 ) ,也是 jSON 格式。




这个脚本定义了两个函数, lists 在指定 --list 时执行, hosts 在指定 --host 时执行




[root@master ~]# vi hosts.py
[root@master ~]# cat hosts.py
#!/usr/bin/env python3
import argparse
import sys
import json
def lists():
  r = {}
  h = [ '192.168.242.1' + str(i) for i in range(0,2) ]
  hosts = {'host': h}
  r['docker'] = hosts
  return json.dumps(r,indent=3)

def hosts(name):
  r = {'ansible_ssh_pass': '123'}
  cpis=dict(r.items())
  return json.dumps(cpis)

if __name__ == '__main__':
  parser = argparse.ArgumentParser()
  parser.add_argument('-l', '--list' , help='hosts list' , action='store_true')
  parser.add_argument('-H', '--host', help='hosts vars')
  args = vars(parser.parse_args())
  if args['list']:
    print(lists())
  elif args['host']:
    print(hosts(args['host']))
  else:
    parser.print_help()

 测试脚本

[root@master ~]# chmod +x hosts.py
[root@master ~]# ./hosts.py -l
{
   "docker": {
      "host": [
         "192.168.242.10",
         "192.168.242.11",
         "192.168.242.12"
      ]
   }
}

[root@master ~]# ./hosts.py -H 192.168.242.12
{"ansible_ssh_pass": "123"}



Ansible组成介绍



[root@master ~]# tree /etc/ansible/
/etc/ansible/
├── ansible.cfg    #ansible的配置文件
├── hosts          #资源清单文件
└── roles

1 directory, 2 files

主机联通性测试

#修改主机与组的配置
[root@master ~]# cat >> /etc/ansible/hosts << EOF
> [webservers]
> node[1:2]
> EOF

#测试一台主机
[root@master ~]# ansible node1 -m ping
node1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}

#测试一组主机
[root@master ~]# ansible webservers -m ping
node1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
node2 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}

批量执行命令

#使用ansible在远程机器输出“hello ansible!"

#使用shell模块
[root@master ~]# ansible webservers -m shell -a '/bin/echo hello ansible!' -o
node2 | CHANGED | rc=0 | (stdout) hello ansible!
node1 | CHANGED | rc=0 | (stdout) hello ansible!


#使用command模块
[root@master ~]# ansible webservers -a '/bin/echo hello ansible!' -o
node1 | CHANGED | rc=0 | (stdout) hello ansible!
node2 | CHANGED | rc=0 | (stdout) hello ansible!

#使用raw模块
[root@master ~]# ansible webservers -m raw -a '/bin/echo hello ansible!'
node1 | CHANGED | rc=0 >>
hello ansible!
Shared connection to node1 closed.

node2 | CHANGED | rc=0 >>
hello ansible!
Shared connection to node2 closed.

获取帮助信息



在 Ansible 中有 8 个主要的 Ansible 管理工具,每个管理工具都是一系列的模块、参数支持。随时可获取的帮助信息对了解掌握 Ansible 系统非常重要。 对于 Ansible 每个工具,都可以简单地在命令后面加上 -h 或 -help 直接获取帮助。




ansible-doc:用于查看模块信息

//参数-1 列出可使用的模块

[root@master ~]# ansible-doc -l
fortios_router_community_list                                 Configure community lists in Fortinet's FortiOS and FortiGate
azure_rm_devtestlab_info                                      Get Azure DevTest Lab facts
ecs_taskdefinition                                            register a task definition in ecs
avi_alertscriptconfig                                         Module for setup of AlertScriptConfig Avi RESTful Object
tower_receive                                                 Receive assets from Ansible Tower
netapp_e_iscsi_target                                         NetApp E-Series manage iSCSI target configuration
azure_rm_acs                                                  Manage an Azure Container Service(ACS) instance
fortios_log_syslogd2_filter                                   Filters for remote system server in Fortinet's FortiOS and FortiGate

//-s 列岀某个模块支持的动作

[root@master ~]# ansible-doc -s shell
- name: Execute shell commands on targets
  shell:
      chdir:                 # Change into this directory before running the command.
      cmd:                   # The command to run followed by optional arguments.
      creates:               # A filename, when it already exists, this step will *not*
                               be run.
      executable:            # Change the shell used to execute the command. This
                               expects an absolute path
                               to the executable.
      free_form:             # The shell module takes a free form command to run, as a
                               string. There is no actual
                               parameter named 'free
                               form'. See the examples on
                               how to use this module.
      removes:               # A filename, when it does not exist, this step will *not*
                               be run.
      stdin:                 # Set the stdin of the command directly to the specified
                               value.
      stdin_add_newline:     # Whether to append a newline to stdin data.
      warn:                  # Whether to enable task warnings.



//-v 查看详细示例



[root@master ~]# ansible-doc -v shell
Using /etc/ansible/ansible.cfg as config file
> SHELL    (/usr/lib/python2.7/site-packages/ansible/modules/commands/shell.py)

        The `shell' module takes the command name followed by a list
        of space-delimited arguments. Either a free form command or
        `cmd' parameter is required, see the examples. It is almost
        exactly like the [command] module but runs the command through
        a shell (`/bin/sh') on the remote node. For Windows targets,
        use the [win_shell] module instead.

  * This module is maintained by The Ansible Core Team
  * note: This module has a corresponding action plugin.

ansible:用于执行ad-hoc命令



ansible 是指令核心部分,其主要用于执行 ad-hoc 命令,即单条命令。默认后面需要跟主机和选项部分,默认不指定模块时,使用的是command 模块。



[root@master ~]# ansible localhost -a date
localhost | CHANGED | rc=0 >>
Thu Aug 12 00:22:39 CST 2021



另外, 在 Ansible 调试自动化脚本时候经常需要获取执行过程的详细信息, 可以在命令后面添加 -v 或 -vvv 得到详细的输出结果。



[root@master ~]# ansible node1 -m ping -vv
ansible 2.9.23
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Nov 16 2020, 22:23:17) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
Using /etc/ansible/ansible.cfg as config file
Skipping callback 'actionable', as we already have a stdout callback.
Skipping callback 'counter_enabled', as we already have a stdout callback.
Skipping callback 'debug', as we already have a stdout callback.
Skipping callback 'dense', as we already have a stdout callback.
Skipping callback 'dense', as we already have a stdout callback.
Skipping callback 'full_skip', as we already have a stdout callback.
Skipping callback 'json', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'null', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.
Skipping callback 'selective', as we already have a stdout callback.
Skipping callback 'skippy', as we already have a stdout callback.
Skipping callback 'stderr', as we already have a stdout callback.
Skipping callback 'unixy', as we already have a stdout callback.
Skipping callback 'yaml', as we already have a stdout callback.
META: ran handlers
node1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
META: ran handlers
META: ran handlers