自动化工具--Ansible

Ansible

ansible简介

ansible是一种可以批量管理远程远程主机的的自动化运维工具

ansible配置文件:

​ /etc/ansible/ansible.cfg 主配置文件,配置ansible工作特性,也可以在项目的目录中创建此文件,当前目录下如果也有ansible.cfg,则此文件优先生效,建议每个项目目录下,创建独有的ansible.cfg文件,Ansible 的默认配置文件 /etc/ansible/ansible.cfg ,其中大部分的配置内容无需进行修改

​ /etc/ansible/hosts 主机清单

​ /etc/ansible/roles/ 存放角色的目录

ansible主机清单

​ 默认的inventory file为 /etc/ansible/hosts,inventory file可以有多个,生产建议在每个项目目录下创建项目独立的hosts文件

​ 主机清单格式:

​ inventory文件遵循INI文件风格,中括号中的字符为组名。可以将同一个主机同时归并到多个不同的组 中
​ 此外,当如若目标主机使用了非默认的SSH端口,还可以在主机名称之后使用冒号加端口号来标明
​ 如果主机名称遵循相似的命名模式,还可以使用列表的方式标识各主机

例:

ansible支持多种格式的主机清单:[server_name]为自定义内容
host

[server_name]
host
...

[server_name1]
host
...

[server_name2]
host
...

实现嵌套
[server_all:children]
server_name1
server_name2

[test]
host  ansible_connection=ssh  ansible_ssh_port=端口  ansible_ssh_user=连接用户
ansible_ssh_password=密码
...


#执行ansible命令时显示别名,如web01,支持定义变量供主机使用
[server_names]
serve1 ansible_ssh_host=host1
serve2 ansible_ssh_host=host2
[websrvs:vars]
ansible_ssh_password=password

范例:
[websrv]
10.0.0.27

[dbsrv]
10.0.0.18

ansible 相关工具大多数是通过ssh协议,实现对远程主机的配置管理、应用部署、任务执行等功能 建议:使用此工具前,先配置ansible主控端能基于密钥认证的方式联系各个被管理节点

#!/bin/bash
ips='10.0.0.27 10.0.0.18'
rpm -q sshpass >/dev/null || yum -y insatll sshpass
[ -f /root/.ssh/id_rsa ] || ssh-keygen  -f /root/.ssh/id_rsa  -P ''

export SSHPASS='123456'

for i in $ips
do
{ sshpass -e  ssh-copy-id -o StrictHostKeyChecking=no $i ;} &
done
wait

ansible查看帮助

ansible-doc [options] [module...]

​ -l, --list #列出可用模块

​ -s, --snippet #显示指定模块的playbook片段

ansible使用

Ansible Ad-Hoc 的执行方式的主要工具就是 ansible

格式:

ansible <host-pattern> [-m module_name] [-a args]
	--version #显示版本
	-m module   #指定模块,默认为command
	-v #详细过程 -vv -vvv更详细
	--list-hosts #显示主机列表,可简写 --list
	-C, --check   #检查,并不执行
	-T, --timeout=TIMEOUT #执行命令的超时时间,默认10s
	-k, --ask-pass     #提示输入ssh连接密码,默认Key验证 
	-u, --user=REMOTE_USER #执行远程执行的用户,默认root
	-b, --become    #代替旧版的sudo 切换
	--become-user=USERNAME  #指定sudo的runas用户,默认为root
	-K, --ask-become-pass  #提示输入sudo时的口令
	-f FORKS, --forks FORKS #指定并发同时执行ansible任务的主机数
ansible的Host-pattern用于匹配被控制的主机的列表
	All :表示所有Inventory中的所有主机
	同时还支持 
		'*' 通配符,匹配内容用 ""
		':'逻辑或,匹配内容用 ""
		':&'逻辑与,匹配内容用 ""
		':!'逻辑非,匹配内容用 ''
		综合逻辑,匹配内容用 ''
		正则表达式,匹配内容用 ""
ansible命令执行过程
	1. 加载自己的配置文件,默认/etc/ansible/ansible.cfg
	2. 加载自己对应的模块文件,如:command
	3. 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户
		$HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件
	4. 给文件+x执行
	5. 执行并返回结果
	6. 删除临时py文件,退出

范例:

[root@centos7 ~]# ansible all --list
  hosts (2):
    10.0.0.27
    10.0.0.18
[root@centos7 ~]# ansible webserver --list
  hosts (1):
    10.0.0.27
[root@centos7 ~]# ansible dbserver --list
  hosts (1):
    10.0.0.18

[root@centos7 ~]# ansible "db*" --list
  hosts (1):
    10.0.0.18
[root@centos7 ~]# ansible "db*:web*" --list
  hosts (2):
    10.0.0.18
    10.0.0.27

ansible-playbook

​ 此工具用于执行编写好的 playbook 任务

[root@centos7 data]# vim hello.yaml
---
- hosts: all
  remote_user: root

  tasks:
    - name: hello world
      command: wall hello world

[root@centos7 data]# ansible-playbook hello.yaml

ansible-vault

​ 此工具可以用于加密解密yml文件

ansible-vault encrypt hello.yml #加密
ansible-vault decrypt hello.yml #解密
ansible-vault view hello.yml #查看
ansible-vault edit hello.yml #编辑加密文件
ansible-vault rekey hello.yml #修改口令
ansible-vault create new.yml #创建新文件

Ansible常用模块

ping 模块

功能:测试远程主机连通性

[root@centos7 data]# ansible all -m ping
10.0.0.27 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
10.0.0.18 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    }, 
    "changed": false, 
    "ping": "pong"
}

Shell 模块

功能:和command相似,用shell执行命令,支持各种符号,比如:*,$, >

注意:此模块不具有幂等性

[root@centos7 data]# ansible all -m shell -a "hostname -I"
10.0.0.27 | CHANGED | rc=0 >>
10.0.0.27 
10.0.0.18 | CHANGED | rc=0 >>
10.0.0.18 

Script 模块

功能:在远程主机上运行ansible服务器上的脚本(无需执行权限)

注意:此模块不具有幂等性

[root@centos7 data]# ansible all -m script -a script.sh 
10.0.0.27 | CHANGED => {
    "changed": true, 
    "rc": 0, 
    "stderr": "Shared connection to 10.0.0.27 closed.\r\n", 
    "stderr_lines": [
        "Shared connection to 10.0.0.27 closed."
    ], 
    "stdout": "10.0.0.27 \r\n", 
    "stdout_lines": [
        "10.0.0.27 "
    ]
}
10.0.0.18 | CHANGED => {
    "changed": true, 
    "rc": 0, 
    "stderr": "Shared connection to 10.0.0.18 closed.\r\n", 
    "stderr_lines": [
        "Shared connection to 10.0.0.18 closed."
    ], 
    "stdout": "10.0.0.18 \r\n", 
    "stdout_lines": [
        "10.0.0.18 "
    ]
}

Copy 模块

功能:从ansible服务器主控端复制文件到远程主机

[root@centos7 data]# ansible all -m copy -a "src=/data/script.sh dest=/data/" 
10.0.0.27 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "9c73218a465637d8e69b5a313d72634cab082501", 
    "dest": "/data/script.sh", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "dd648acb20ec6b67f338f2af0a049fec", 
    "mode": "0644", 
    "owner": "root", 
    "size": 24, 
    "src": "/root/.ansible/tmp/ansible-tmp-1656574490.85-23965-23856603304984/source", 
    "state": "file", 
    "uid": 0
}
10.0.0.18 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    }, 
    "changed": true, 
    "checksum": "9c73218a465637d8e69b5a313d72634cab082501", 
    "dest": "/data/script.sh", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "dd648acb20ec6b67f338f2af0a049fec", 
    "mode": "0644", 
    "owner": "root", 
    "size": 24, 
    "src": "/root/.ansible/tmp/ansible-tmp-1656574490.8-23966-115216944889568/source", 
    "state": "file", 
    "uid": 0
}

注意:"content='内容' dest=文件"可以将内容直接写入远程主机文件中
在复制目录时,目录后又/ 复制目录,目录后没有/ 复制目录下文件
backup=yes选项在复制到远程主机时,如果目标存在则先备份

Fetch 模块

功能:从远程主机提取文件至ansible的主控端,copy相反,目前不支持目录

[root@centos7 data]# ansible all -m fetch -a "src=/etc/passwd dest=/data/"
10.0.0.27 | CHANGED => {
    "changed": true, 
    "checksum": "f46e74616780e28c950837c16571665b058c3233", 
    "dest": "/data/10.0.0.27/etc/passwd", 
    "md5sum": "388824fe0e2029fba5ef752f0e0fab2c", 
    "remote_checksum": "f46e74616780e28c950837c16571665b058c3233", 
    "remote_md5sum": null
}
10.0.0.18 | CHANGED => {
    "changed": true, 
    "checksum": "bbc6e343974d164f4f1a337def3fdeaa631d36b5", 
    "dest": "/data/10.0.0.18/etc/passwd", 
    "md5sum": "5df294b28938a994ed8c1f8cbd1f2a26", 
    "remote_checksum": "bbc6e343974d164f4f1a337def3fdeaa631d36b5", 
    "remote_md5sum": null
}

[root@centos7 data]# ls 10.0.0.*/etc/
10.0.0.18/etc/:
passwd

10.0.0.27/etc/:
passwd

File 模块

功能:设置文件属性,创建软链接等

[root@centos7 data]# ansible all -m file -a "path=/data/test.txt state=touch"
10.0.0.27 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "dest": "/data/test.txt", 
    "gid": 0, 
    "group": "root", 
    "mode": "0644", 
    "owner": "root", 
    "size": 0, 
    "state": "file", 
    "uid": 0
}
10.0.0.18 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    }, 
    "changed": true, 
    "dest": "/data/test.txt", 
    "gid": 0, 
    "group": "root", 
    "mode": "0644", 
    "owner": "root", 
    "size": 0, 
    "state": "file", 
    "uid": 0
}

[root@centos7 data]# ansible all -m file -a "path=/data/test state=directory"
10.0.0.27 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "gid": 0, 
    "group": "root", 
    "mode": "0755", 
    "owner": "root", 
    "path": "/data/test", 
    "size": 6, 
    "state": "directory", 
    "uid": 0
}
10.0.0.18 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    }, 
    "changed": true, 
    "gid": 0, 
    "group": "root", 
    "mode": "0755", 
    "owner": "root", 
    "path": "/data/test", 
    "size": 6, 
    "state": "directory", 
    "uid": 0
}
[root@centos7 data]# ansible all -m shell -a "ls /data/"
10.0.0.27 | CHANGED | rc=0 >>
script.sh
test
test.txt
10.0.0.18 | CHANGED | rc=0 >>
script.sh
test
test.txt

unarchive 模块

功能:解包解压缩

实现有两种用法:

1、将ansible主机上的压缩包传到远程主机后解压缩至特定目录,设置copy=yes,此为默认值,可省略

2、将远程主机上的某个压缩包解压缩到指定路径下,设置copy=no

常见参数:

copy:默认为yes,当copy=yes,拷贝的文件是从ansible主机复制到远程主机上,如果设置为copy=no,

会在远程主机上寻找src源文件

remote_src:和copy功能一样且互斥,yes表示在远程主机,不在ansible主机,no表示文件在ansible

主机上

src:源路径,可以是ansible主机上的路径,也可以是远程主机(被管理端或者第三方主机)上的路径,如果是远程主机上的路径,则需要设置copy=no

dest:远程主机上的目标路径

mode:设置解压缩后的文件权限

[root@centos7 data]# ansible 10.0.0.27 -m unarchive -a "src=/data/mysql-5.7.33-linux-glibc2.12-x86_64.tar.gz dest=/data/ copy=yes"
10.0.0.27 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "dest": "/data/", 
    "extract_results": {
        "cmd": [
            "/usr/bin/gtar", 
            "--extract", 
            "-C", 
            "/data/", 
            "-z", 
            "-f", 
            "/root/.ansible/tmp/ansible-tmp-1656576444.73-24464-156337659830963/source"
        ], 
        "err": "", 
        "out": "", 
        "rc": 0
    }, 
    "gid": 0, 
    "group": "root", 
    "handler": "TgzArchive", 
    "mode": "0755", 
    "owner": "root", 
    "size": 94, 
    "src": "/root/.ansible/tmp/ansible-tmp-1656576444.73-24464-156337659830963/source", 
    "state": "directory", 
    "uid": 0
}

[root@centos7 data]# ls
mysql-5.7.33-linux-glibc2.12-x86_64  script.sh  test  test.txt

Service 模块

功能:管理服务

[root@centos7 data]# ansible all -m service  -a 'name=httpd state=started'

[root@centos7 data]# systemctl status httpd
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
   Active: active (running) since Thu 2022-06-30 16:21:11 CST; 2min 22s ago
   
state=started/restarted/stoped/reloaded 服务状态
enabled=yes 开机自启

Setup 模块

功能: setup 模块来收集主机的系统信息,这些 facts 信息可以直接以变量的形式使用,但是如果主机较多,会影响执行速度

[root@centos7 data]# ansible all -m setup -a "filter=ansible_all_ipv4_addresses"
10.0.0.18 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "10.0.0.18"
        ], 
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    }, 
    "changed": false
}
10.0.0.27 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "10.0.0.27"
        ], 
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false

Cron 模块

功能:计划任务

支持时间:minute,hour,day,month,weekday

[root@centos7 data]# ansible all -m cron -a "hour=*/10 job='/bin/bash /data/script' name=scritp disabled=no"
10.0.0.27 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "envs": [], 
    "jobs": [
        "scritp"
    ]
}
10.0.0.18 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    }, 
    "changed": true, 
    "envs": [], 
    "jobs": [
        "scritp"
    ]
}


[root@centos7 data]# crontab -l
#Ansible: scritp
* */10 * * * /bin/bash /data/script

Yum 和 Apt 模块

功能:

yum 管理软件包,只支持RHEL,CentOS,fedora,不支持Ubuntu其它版本

apt 模块管理 Debian 相关版本的软件包

[root@centos7 data]# ansible 10.0.0.27 -m yum -a 'name=httpd state=present'
10.0.0.27 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "changes": {
        "installed": [
            "httpd"
        ]


[root@centos7 data]# ansible 10.0.0.27 -m shell -a "rpm -q httpd" 
[WARNING]: Consider using the yum, dnf or zypper module rather than running 'rpm'.  If you need to use command because yum,
dnf or zypper is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg
to get rid of this message.
10.0.0.27 | CHANGED | rc=0 >>
httpd-2.4.6-95.el7.centos.x86_64

User 模块

功能:管理用户

[root@centos7 data]# ansible 10.0.0.27 -m user -a "name=test uid=1024"
10.0.0.27 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "comment": "", 
    "create_home": true, 
    "group": 1024, 
    "home": "/home/test", 
    "name": "test", 
    "shell": "/bin/bash", 
    "state": "present", 
    "system": false, 
    "uid": 1024
}

[root@centos7 data]# id test
uid=1024(test) gid=1024(test) groups=1024(test)

Group 模块

功能:管理组

[root@centos7 data]# ansible 10.0.0.27 -m group -a "name=test_group gid=2048"
10.0.0.27 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "gid": 2048, 
    "name": "test_group", 
    "state": "present", 
    "system": false
}

Lineinfile 模块

ansible在使用sed进行替换时,经常会遇到需要转义的问题,而且ansible在遇到特殊符号进行替换时,存在问题,无法正常进行替换 。其实在ansible自身提供了两个模块:lineinfile模块和replace模块,可以方便的进行替换

一般在ansible当中去修改某个文件的单行进行替换的时候需要使用lineinfile模块

regexp参数 :使用正则表达式匹配对应的行,当替换文本时,如果有多行文本都能被匹配,则只有最后面被匹配到的那行文本才会被替换,当删除文本时,如果有多行文本都能被匹配,这么这些行都会被删除。

如果想进行多行匹配进行替换需要使用replace模块

Replace 模块

该模块有点类似于sed命令,主要也是基于正则进行匹配和替换,建议使用

[root@centos7 data]# ansible 10.0.0.27 -m replace -a "path=/data/fstab regexp='^(UUID=*)' replace='#\1'"
10.0.0.27 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "msg": "4 replacements made"
}

[root@centos7 data]# cat fstab 

#
# /etc/fstab
# Created by anaconda on Wed Jan 19 12:08:41 2022
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
#UUID=3f6b6d7e-825b-4983-b1c0-822c4a2539f4 /                       xfs     defaults        0 0
#UUID=1c37b4ff-d945-40e7-8bbb-471211a10827 /boot                   xfs     defaults        0 0
#UUID=fbacfb2e-6736-4881-80b0-0e0176f1011c /data                   xfs     defaults        0 0
#UUID=b376739b-b8f5-41e5-8c0c-2c1a0ec12e15 swap                    swap    defaults        0 0

SELinux 模块

该模块管理 SELInux 策略

[root@centos7 data]# ansible 10.0.0.18 -m selinux -a "state=disabled"

mount 挂载和卸载

功能: 挂载和卸载文件系统

#永久挂载
ansible all -m mount -a 'src= path= opts="_netdev" state=mounted'
#永久卸载
ansible websrvs -m mount -a 'src= path= state=absent'

stat判断文件状态

[root@centos7 data]# ansible all -m stat -a 'path=/data/fstab'
10.0.0.27 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "stat": {
        "atime": 1656578257.6191027, 
        "attr_flags": "", 
        "attributes": [], 
        "block_size": 4096, 
        "blocks": 8, 
        "charset": "us-ascii", 
        "checksum": "01eb0765bafd693168139653c45270c5a7448c2d", 
        "ctime": 1656578253.3401027, 
        "dev": 2051, 
        "device_type": 0, 
        "executable": false, 
        "exists": true, 
        "gid": 0, 
        "gr_name": "root", 
        "inode": 84461, 
        "isblk": false, 
        "ischr": false, 
        "isdir": false, 
        "isfifo": false, 
        "isgid": false, 
        "islnk": false, 
        "isreg": true, 
        "issock": false, 
        "isuid": false, 
        "mimetype": "text/plain", 
        "mode": "0644", 
        "mtime": 1656578253.340102, 
        "nlink": 1, 
        "path": "/data/fstab", 
        "pw_name": "root", 
        "readable": true, 
        "rgrp": true, 
        "roth": true, 
        "rusr": true, 
        "size": 599, 
        "uid": 0, 
        "version": "1413777910", 
        "wgrp": false, 
        "woth": false, 
        "writeable": true, 
        "wusr": true, 
        "xgrp": false, 
        "xoth": false, 
        "xusr": false
    }
}
10.0.0.18 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    }, 
    "changed": false, 
    "stat": {
        "exists": false
    }
}

playbook

playbook 剧本是由一个或多个"play"组成的列表
play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。Task实际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按事先编排的机制执行预定义的动作
Playbook 文件是采用YAML语言编写的

Playbook 核心组件

1 hosts 组件

​ Hosts:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清单中

2 remote_user 组件

​ remote_user: 可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户

3 task列表和action组件

​ play的主体部分是task list,task list中有一个或多个task,各个task 按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个task后,再开始第二个task

​ task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致

​ 每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。

​ 如果未提供name,则action的结果将用于输出

task两种格式:

​ action: module arguments #示例: action: shell wall hello

​ module: arguments #建议使用 #示例: shell: wall hello

4 其它组件说明

某任务的状态在运行后为changed时,可通过"notify"通知给相应的handlers任务

还可以通过"tags"给task 打标签,可在ansible-playbook命令上使用-t指定进行调用

playbook 命令

	ansible-playbook <filename.yml> ... [options]
	--syntax-check   #语法检查,可缩写成--syntax, 相当于bash -n 
	-C --check #模拟执行,只检测可能会发生的改变,但不真正执行操作,dry run 
	--list-hosts  #列出运行任务的主机
	--list-tags #列出tag
	--list-tasks #列出task
	--limit 主机列表 #只针对主机列表中的特定主机执行
	-i INVENTORY    #指定主机清单文件,通常一个项对应一个主机清单文件
	--start-at-task START_AT_TASK #从指定task开始执行,而非从头开始,START_AT_TASK为任务的name
	-v -vv -vvv #显示过程

忽略错误 ignore_errors

如果一个task出错,默认将不会继续执行后续的其它task,利用 ignore_errors: yes 可以忽略此task的错误,继续向下执行playbook其它task

---
- hosts: all

  tasks:
   - name: error
     command: /bin/false
     ignore_errors: yes
   - name: ipaddress
     shell: hostname -I

[root@centos7 data]# ansible-playbook ignore.yaml 

PLAY [all] ******************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************
ok: [10.0.0.18]
ok: [10.0.0.27]

TASK [error] ****************************************************************************************************************
fatal: [10.0.0.27]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.001753", "end": "2022-06-30 17:05:05.410635", "msg": "non-zero return code", "rc": 1, "start": "2022-06-30 17:05:05.408882", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring
fatal: [10.0.0.18]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.001144", "end": "2022-07-01 01:05:03.116615", "msg": "non-zero return code", "rc": 1, "start": "2022-07-01 01:05:03.115471", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring

TASK [ipaddress] ************************************************************************************************************
changed: [10.0.0.27]
changed: [10.0.0.18]

PLAY RECAP ******************************************************************************************************************
10.0.0.18                  : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1   
10.0.0.27                  : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1   

handlers和notify

---
- hosts: all
  remote_user: root
  gather_facts: no

  tasks:
    - name: ip a
      shell: ip a
      notify:
        - message

  handlers:
     - name: message
       debug:
         msg: this is handlers
         
[root@centos7 data]# ansible-playbook  notify.yaml 

PLAY [all] ******************************************************************************************************************

TASK [ip a] *****************************************************************************************************************
changed: [10.0.0.27]
changed: [10.0.0.18]

RUNNING HANDLER [message] ***************************************************************************************************
ok: [10.0.0.27] => {
    "msg": "this is handlers"
}
ok: [10.0.0.18] => {
    "msg": "this is handlers"
}

PLAY RECAP ******************************************************************************************************************
10.0.0.18                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
10.0.0.27                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

tags组件

在playbook文件中,可以利用tags组件,为特定 task 指定标签,当在执行playbook时,可以只执行特 定tags的task,而非整个playbook文件

可以一个task对应多个tag,也可以多个task对应一个tag

还有另外3个特殊关键字用于标签, tagged, untagged 和 all,它们分别是仅运行已标记,只有未标记和所 有任务。

---
- hosts: 10.0.0.27
  remote_user: root
  gather_facts: no
  tasks:
   - name: tags1
     debug:
       msg: this is tags1
     tags:
       - tags1

   - name: tags2
     debug:
       msg: this is tags2
     tags:
       - tags2
   - name: tags3
     debug:
       msg: this is tags3
     tags:
       - tags3
[root@centos7 data]# ansible-playbook --list-tags tags.yaml 

playbook: tags.yaml

  play #1 (10.0.0.27): 10.0.0.27	TAGS: []
      TASK TAGS: [tags1, tags2, tags3]

[root@centos7 data]# ansible-playbook -t tags2 tags.yaml 

PLAY [10.0.0.27] ************************************************************************************************************

TASK [tags2] ****************************************************************************************************************
ok: [10.0.0.27] => {
    "msg": "this is tags2"
}

PLAY RECAP ******************************************************************************************************************
10.0.0.27                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0


[root@centos7 data]# ansible-playbook --skip-tags tags2 tags.yaml 

PLAY [10.0.0.27] ************************************************************************************************************

TASK [tags1] ****************************************************************************************************************
ok: [10.0.0.27] => {
    "msg": "this is tags1"
}

TASK [tags3] ****************************************************************************************************************
ok: [10.0.0.27] => {
    "msg": "this is tags3"
}

PLAY RECAP ******************************************************************************************************************
10.0.0.27                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

playbook使用变量

​ 变量名:仅能由字母、数字和下划线组成,且只能以字母开头

​ 变量调用方式: 通过 {{ variable_name }} 调用变量,且变量名前后建议加空格,有时用"{{ variable_name }}"才生效

变量来源:
1. ansible 的 setup facts 远程主机的所有变量都可直接调用
2. 通过命令行指定变量,优先级最高
	ansible-playbook -e varname=value test.yml
3. 在playbook文件中定义
	vars:
	 var1: value1
	 var2: value2
4. 在独立的变量YAML文件中定义
	- hosts: all
	 vars_files:
	   - vars.yml
5. 在主机清单文件中定义
	主机(普通)变量:主机组中主机单独定义,优先级高于公共变量
	组(公共)变量:针对主机组中所有主机定义统一变量
6. 在项目中针对主机和主机组定义
	在项目目录中创建 host_vars和group_vars目录
7. 在role中定义

变量的优先级从高到低如下
-e 选项定义变量 -->playbook中vars_files --> playbook中vars变量定义 -->host_vars/主机名文件 -->主机清单中主机变量--> group_vars/主机组名文件-->group_vars/all文件--> 主机清单组变量

使用 setup 模块中变量
本模块自动在playbook调用,不要用ansible命令调用,生成的系统状态信息, 并存放在facts变量中
facts 包括的信息很多,如: 主机名,IP,CPU,内存,网卡等

register注册变量

---
- hosts: 10.0.0.27
  remote_user: root
  gather_facts: no

  tasks:
   - name: register
     shell: hostname
     register: var
   - name: print var
     debug:
        msg: "{{ var }}"

template

template功能:可以根据和参考模块文件,动态生成相类似的配置文件
template文件必须存放于templates目录下,且命名为 .j2 结尾
yaml/yml 文件需和templates目录平级,目录结构如下示例:
./
├── temnginx.yml
└── templates
└── nginx.conf.j2

在.j2文件中可使用变量实现根据主机配置动态调整

例如:使用 ansible_processor_vcpus变量调整nginx配置

​ worker_processes {{ ansible_processor_vcpus }};

使用:

- name: template config
     template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf 

template中也可以使用流程控制 for 循环和 if 条件判断,实现动态生成文件功能

{% for i in EXPR %}
 ...
{% endfor %}
示例:
{% for i in range(1,10) %}
 server_name web{{i}};
{% endfor %}

定义一个列表变量,遍历列表,根据列表元素动态生成.j2文件

使用 if条件判断,决定是否生成相关的配置信息

{% for vhost in nginx_vhosts %}
server {
   listen {{ vhost.listen }}
   {% if vhost.server_name is defined %}
server_name {{ vhost.server_name }}   #注意缩进
   {% endif %}
root  {{ vhost.root }}                #注意缩进
}
{% endfor %}
范例: 生成keepalived配置文件
vrrp_instrance VI_1 {
{% if ansible_fqdn == "ka1" %}
 state MASTER
 priority 100
{% elif ansible_fqdn == "ka2" %}
 state SLAVE
 priority 80
{% endif% }
......
}

使用循环迭代

​ 迭代:当有需要重复性执行的任务时,可以使用迭代机制

​ 迭代 with_items(loop) 对迭代项的引用,固定内置变量名为"item" 要在task中使用with_items给定要迭代的元素列表 注意: ansible2.5版本后,可以用loop代替with_items

---
- hosts: 10.0.0.27
  remote_user: root
  gather_facts: no

  tasks:
   - name: register
     debug:
        msg: "{{ item }}"
     with_items:
       - item1
       - item2
       - item3

[root@centos7 data]# ansible-playbook  var.yaml

PLAY [10.0.0.27] ************************************************************************************************************

TASK [register] *************************************************************************************************************
ok: [10.0.0.27] => (item=item1) => {
    "msg": "item1"
}
ok: [10.0.0.27] => (item=item2) => {
    "msg": "item2"
}
ok: [10.0.0.27] => (item=item3) => {
    "msg": "item3"
}

PLAY RECAP ******************************************************************************************************************
10.0.0.27                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

在迭代中,还可以嵌套子变量,关联多个变量在一起使用

---
- hosts: 10.0.0.27
  remote_user: root
  gather_facts: no

  tasks:
   - name: register
     user: name={{ item.name }} uid={{ item.uid }} system={{ item.system }}
     with_items:
       - {name: 'chen',uid: '1000',system: 'yes'}

when

​ when语句可以实现条件测试。如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否 的前提时要用到条件测试,通过在task后添加when子句即可使用条件测试,jinja2的语法格式

---
- hosts: 10.0.0.27
  remote_user: root

  tasks:
   - name: os
     debug: msg="centos7"
     when: ansible_distribution_major_version == "7"
   - name: os
     debug: msg="centos8"
     when: ansible_distribution_major_version == "8"

block:当满足条件时执行block分组的task

---
- hosts: 10.0.0.27
  remote_user: root

  tasks:
   - block:
      - debug: msg="centos7"
      - debug: msg="centos7"
     when:
        ansible_facts['distribution_major_version'] == "7"

changed_when 检查task返回结果,决定是否继续向下执行

- name: check config
     shell: /usr/sbin/nginx -t
     register: check_nginx_config 
     changed_when:
       - (check_nginx_config.stdout.find('successful')) #如果执行结果中有successful字符串,则继续执行,如果没有则停止向下执行
       - false  #nginx -t 每次成功执行是changed状态,关闭此changed状态

滚动执行

管理节点过多导致的超时问题解决方法

默认情况下,Ansible将尝试并行管理playbook中所有的机器。对于滚动更新用例,可以使用serial关键 字定义Ansible一次应管理多少主机,还可以将serial关键字指定为百分比,表示每次并行执行的主机数 占总数的比例

- hosts: all
  serial: 2  #每次只同时处理2个主机,将所有task执行完成后,再选下2个主机再执行所有task,直至所有主机
  
- name: test serail
  hosts: all
  serial: "20%"   #每次只同时处理20%的主机

yaml文件的相互调用

​ 利用include 或 include_tasks 可以在某个task中调用其它的只有task内容的yaml文件

​ 也可以将多个包含完整内容的yml文件由一个yml统一调用

   - name: excute b.yml
     include: b.yml    #调用另一个yaml文件
      #include_tasks: b.yml #另一种写法
[root@ansible ansible]#cat total_tasks.yml 
- import_playbook: tasks1.yml
- import_playbook: tasks2.yml

roles

用于层次性、结构化地组织playbook。roles能够根据层次型结 构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。 简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地 include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中

roles:多个角色的集合目录, 可以将多个的role,分别放至roles目录下的独立子目录中

roles目录结构:

playbook1.yml
playbook2.yml
roles/
 project1/
   tasks/
   files/
   vars/       
   templates/
   handlers/
   default/    
   meta/       
 project2/
   tasks/
   files/
   vars/       
   templates/
   handlers/
   default/    
   meta/ 

Roles各目录作用
	roles/project/ :项目名称,有以下子目录
	files/ :存放由copy或script模块等调用的文件
	templates/:template模块查找所需要模板文件的目录
	tasks/:定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
	handlers/:至少应该包含一个名为main.yml的文件;此目录下的其它的文件需要在此文件中通过
	include进行包含
	vars/:定义变量,至少应该包含一个名为main.yml的文件;此目录下的其它的变量文件需要在此文件中通过include进行包含
	meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,其它文件需在此文件中通过include进行包含
	default/:设定默认变量时使用此目录中的main.yml文件,比vars的优先级低

创建role的步骤

1 创建role的目录结构.在以roles命名的目录下分别创建以各角色名称命名的目录,如mysql等,在每个角色命名的目录中分别创建相关的目录和文件,比如tasks、files、handlers、templates和vars等目录;用不到的目录可以创建为空目录,也可以不创建
2 编写和准备role的功能文件
3 编写playbook文件调用需要的角色应用于指定的主机

利用 ansible-galaxy 创建角色目录的结构
 ansible-galaxy init test_role

playbook 调用角色

---
- hosts: websrvs
 remote_user: root
 roles:
 - mysql
 - memcached
 - nginx 
 
 
---
- hosts: all
 remote_user: root
 roles:
   - role: mysql
     username: mysql
   - { role: nginx, username: nginx }


---
- hosts: all
 remote_user: root
 roles:
   - { role: nginx, username: nginx, when: ansible_distribution_major_version == '7' }

playbook安装二进制mysql

---
- hosts: 10.0.0.27
  remote_user: root
  gather_facts: no

  tasks:
   - name: intsall package
     yum: name=libaio,numactl-libs
   - name: add group
     group: name=mysql
   - name: add user
     user: name=mysql group=mysql system=yes shell=/sbin/nologin
   - name: unarchive mysql
     unarchive: src=/data/mysql-5.7.33-linux-glibc2.12-x86_64.tar.gz dest=/usr/local/ copy=yes owner=root group=root
   - name: create link
     file: src=/usr/local/mysql-5.7.33-linux-glibc2.12-x86_64 dest=/usr/local/mysql state=link
   - name: change PATH
     shell: echo "PATH=/usr/local/mysql/bin:$PATH" >/etc/profile.d/mysql.sh
   - name: mysql script
     shell: source /etc/profile.d/mysql.sh
   - name: create config
     copy: content="[mysqld]\nserver-id=1\nlog-bin\ndatadir=/data/mysql\nsocket=/data/mysql/mysql.sock\nlog-error=/data/mysql/mysql.log\npid-file=/data/mysql/mysql.pid\n[client]\nsocket=/data/mysql/mysql.sock\n" dest=/etc/my.cnf
   - name: initialize
     shell: mysqld --initialize-insecure --user=mysql --datadir=/data/mysql
   - name: create start script
     shell: cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
   - name: add mysqld
     shell: chkconfig --add mysqld
   - name: start mysql
     service: name=mysqld state=started

测试

[root@centos7 data]# ansible-playbook  install_mysql.yaml 

PLAY [10.0.0.27] **************************************************************************************************************************************************************************

TASK [intsall package] ********************************************************************************************************************************************************************
ok: [10.0.0.27]

TASK [add group] **************************************************************************************************************************************************************************
ok: [10.0.0.27]

TASK [add user] ***************************************************************************************************************************************************************************
ok: [10.0.0.27]

TASK [create link] ************************************************************************************************************************************************************************
ok: [10.0.0.27]

TASK [change PATH] ************************************************************************************************************************************************************************
changed: [10.0.0.27]

TASK [mysql script] ***********************************************************************************************************************************************************************
changed: [10.0.0.27]

TASK [create config] **********************************************************************************************************************************************************************
ok: [10.0.0.27]

TASK [initialize] *************************************************************************************************************************************************************************
changed: [10.0.0.27]

TASK [create start script] ****************************************************************************************************************************************************************
changed: [10.0.0.27]

TASK [add mysqld] *************************************************************************************************************************************************************************
changed: [10.0.0.27]

TASK [start mysql] ************************************************************************************************************************************************************************
changed: [10.0.0.27]

PLAY RECAP ********************************************************************************************************************************************************************************
10.0.0.27                  : ok=11   changed=6    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


[root@centos7 data]# ss -ant
State       Recv-Q Send-Q                                                Local Address:Port                                                               Peer Address:Port              
LISTEN      0      128                                                               *:22                                                                            *:*                  
LISTEN      0      100                                                       127.0.0.1:25                                                                            *:*                  
ESTAB       0      0                                                         10.0.0.27:22                                                                    10.0.0.17:53972              
ESTAB       0      52                                                        10.0.0.27:22                                                                     10.0.0.1:59397              
LISTEN      0      80                                                             [::]:3306                                                                       [::]:*                  
LISTEN      0      128                                                            [::]:80                                                                         [::]:*                  
LISTEN      0      128                                                            [::]:22                                                                         [::]:*                  
LISTEN      0      100                                                           [::1]:25                                                                         [::]:* 

批量部署apache

---
- hosts: all
  remote_user: root

  tasks:
   - name: install package
     yum: name=gcc,make,pcre-devel,openssl-devel,expat-devel,bzip2 state=installed 
   - name: unarchive apr
     unarchive: src=/data/apr-1.7.0.tar.bz2 dest=/data/ copy=yes
   - name: unarchive apr-util
     unarchive: src=/data/apr-util-1.6.1.tar.bz2 dest=/data/ copy=yes
   - name: unarchive httpd2.4
     unarchive: src=/data/httpd-2.4.46.tar.bz2 dest=/data/ copy=yes
   - name: configuer apr
     shell: chdir=/data/apr-1.7.0  ./configure --prefix=/app/apr && make && make install
   - name: configuer apr-util
     shell: chdir=/data/apr-util-1.6.1  ./configure --prefix=/app/apr-util --with-apr=/app/apr  && make && make install
   - name: configuer httpd
     shell: chdir=/data/httpd-2.4.46  ./configure --prefix=/app/http2.4 --enable-so --enable-ssl --enable-cgi --enable-rewrite --with-zlib --with-pcre --with-apr=/app/apr --with-apr-util=/app/apr-util  --enable-modules=most --enable-mpms-shared=all --with-mpm=prefork && make && make install
   - name: create group
     group: name=apache system=yes
   - name: create user
     user: name=apache group=apache system=yes shell=/sbin/nologin create_home=no
   - name: change user
     shell: grep -E "^User apache" /app/http2.4/conf/httpd.conf || sed -r -e "s/^User.*/User apache/" -e "s/^Group.*/Group apache/" /app/http2.4/conf/httpd.conf
   - name: source PATH
     shell: echo "PATH=/app/http2.4/bin:$PATH" > /etc/profile.d/httpd.sh && source /etc/profile.d/httpd.sh
   - name: man
     shell: echo "MANDATORY_MANPATH           /app/http2.4/man " >> /etc/man_db.conf
   - name: unit file
     template: src=httpd.service.j2 dest=/usr/lib/systemd/system/httpd.service
   - name: system-daemon
     shell: systemctl daemon-reload
   - name: start httpd
     service: name=httpd state=started
   - name: create index.html
     template: src=index.html dest=/var/www/html/index.html
   - name: start httpd
     service: name=httpd state=started


[root@centos7 data]# cat templates/index.html 
{{ ansible_default_ipv4.address }}
posted @   ——浮生——  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示