1 Ansible常用模块

常用模块帮助文档参考: https://docs.ansible.com/ansible/latest/modules/modules_by_category.html

1.1 Command 模块

功能:在远程主机执行命令,此为默认模块,可忽略-m选项 注意:此命令不支持 $VARNAME < > | ; & 等,可以用shell模块实现 范例:

[root@c8-ansible ~]# ansible-doc -s command
- name: Execute commands on targets
  command:
    chdir:                 # Change into this directory before running the command.
      							切换到文件夹再执行命令
      cmd:                   # The command to run.
      creates:               # A filename or (since 2.0) glob pattern. If it already exists, this step *won't* be run.	文件存在就不执行
      free_form:             # The command module takes a free form command to run. There is no actual parameter named 'free form'.
      removes:               # A filename or (since 2.0) glob pattern. If it already exists, this step *will* be run.	文件存在执行
      stdin:                 # Set the stdin of the command directly to the specified value.
      stdin_add_newline:     # If set to `yes', append a newline to stdin data.
      strip_empty_ends:      # Strip empty lines from the end of stdout/stderr in result.
      warn:                  # Enable or disable task warnings.

ansible 主机名 -m command -a "cmd"	#-m command 默认可以不加;-a 参数;cmd是执行的命令
ansible 主机名 -a "chdir=/dir"

#cmd模块
[root@c8-ansible ~]# ansible all -a 'hostname'
192.168.209.27 | CHANGED | rc=0 >>
c7-slave02
192.168.209.17 | CHANGED | rc=0 >>
c7-slave01
192.168.209.37 | CHANGED | rc=0 >>
c7-slave03
192.168.209.18 | CHANGED | rc=0 >>
c8-slave01
192.168.209.38 | CHANGED | rc=0 >>
c8-slave03
192.168.209.28 | CHANGED | rc=0 >>
c8-slave02

[root@c8-ansible ~]# ansible websrvs -a 'touch a.txt'	#ansible使用file模块来代替touch命令
[WARNING]: Consider using the file module with state=touch rather than running 'touch'.  If you need to use command because file 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.
192.168.209.37 | CHANGED | rc=0 >>
192.168.209.38 | CHANGED | rc=0 >>
[root@c8-ansible ~]# ansible websrvs -a 'ls /root/a.txt' #没有指定目录,则是创建到了root家目录下
192.168.209.37 | CHANGED | rc=0 >>
/root/a.txt
192.168.209.38 | CHANGED | rc=0 >>
/root/a.txt

#chdir模块
[root@c8-ansible ~]# ansible websrvs -a 'chdir=/opt touch b.txt'  #先切换目录,再创建文件
192.168.209.37 | CHANGED | rc=0 >>
192.168.209.38 | CHANGED | rc=0 >>
[root@c8-ansible ~]# ansible websrvs -a 'ls /opt/b.txt'
192.168.209.37 | CHANGED | rc=0 >>
/opt/b.txt
192.168.209.38 | CHANGED | rc=0 >>
/opt/b.txt

#creates和removes模块
#creates=/etc/fstab,这个文件存在,所以不执行后面的rm操作
[root@c8-ansible ~]# ansible websrvs -a 'creates=/etc/fstab rm -f /opt/b.txt'
192.168.209.37 | SUCCESS | rc=0 >>
skipped, since /etc/fstab exists
192.168.209.38 | SUCCESS | rc=0 >>
skipped, since /etc/fstab exists
#而removes相反,/etc/fstab文件存在,所以执行后面的rm操作
[root@c8-ansible ~]# ansible websrvs -a 'removes=/etc/fstab rm -f /opt/b.txt'
192.168.209.37 | CHANGED | rc=0 >>
192.168.209.38 | CHANGED | rc=0 >>

[root@c8-ansible ~]# ansible websrvs -a 'ls /opt/b.txt'
192.168.209.37 | FAILED | rc=2 >>
ls: cannot access /opt/b.txt: No such file or directorynon-zero return code
192.168.209.38 | FAILED | rc=2 >>
ls: cannot access '/opt/b.txt': No such file or directorynon-zero return code

#此命令不支持 $VARNAME < > | ; & 等,要用shell模块实现
[root@c8-ansible ~]# ansible websrvs -a 'echo $HOSTNAME'
192.168.209.37 | CHANGED | rc=0 >>
$HOSTNAME
192.168.209.38 | CHANGED | rc=0 >>
$HOSTNAME
[root@c8-ansible ~]# ansible websrvs -a "echo $HOSTNAME"  #显示的是当前ansible服务器的主机名,而不是客户端的主机名
192.168.209.37 | CHANGED | rc=0 >>
c8-ansible
192.168.209.38 | CHANGED | rc=0 >>
c8-ansible
[root@c8-ansible ~]# ansible websrvs -m shell -a 'echo $HOSTNAME'
192.168.209.37 | CHANGED | rc=0 >>
c7-slave03
192.168.209.38 | CHANGED | rc=0 >>
c8-slave03

[root@c8-ansible ~]# ansible websrvs -a "echo hello >/opt/hello.txt"  #客户端未创建hello.txt文件
192.168.209.37 | CHANGED | rc=0 >>
hello >/opt/hello.txt
192.168.209.38 | CHANGED | rc=0 >>
hello >/opt/hello.txt
[root@c8-ansible ~]# ansible websrvs -a 'ls /opt'
192.168.209.37 | CHANGED | rc=0 >>
192.168.209.38 | CHANGED | rc=0 >>

[root@c8-ansible ~]# ansible websrvs -a 'echo centos |passwd --stdin root'	#未修改
192.168.209.37 | CHANGED | rc=0 >>
centos |passwd --stdin root
192.168.209.38 | CHANGED | rc=0 >>
centos |passwd --stdin root

1.2 Shell 模块

功能:和command相似,用shell执行命令

范例:

[root@c8-ansible ~]# ansible websrvs -m shell -a "echo $HOSTNAME"
192.168.209.37 | CHANGED | rc=0 >>
c8-ansible
192.168.209.38 | CHANGED | rc=0 >>
c8-ansible
[root@c8-ansible ~]# ansible websrvs -m shell -a 'echo $HOSTNAME'
192.168.209.37 | CHANGED | rc=0 >>
c7-slave03
192.168.209.38 | CHANGED | rc=0 >>
c8-slave03

[root@c8-ansible ~]# ansible websrvs -m shell -a 'ls -l /etc/shadow'
192.168.209.37 | CHANGED | rc=0 >>
---------- 1 root root 584 Jul  6 11:02 /etc/shadow
192.168.209.38 | CHANGED | rc=0 >>
----------. 1 root root 760 Jul  7 18:34 /etc/shadow

[root@c8-ansible ~]# ansible websrvs -m shell -a 'cat /etc/redhat*'
192.168.209.37 | CHANGED | rc=0 >>
CentOS Linux release 7.9.2009 (Core)
192.168.209.38 | CHANGED | rc=0 >>
CentOS Linux release 8.1.1911 (Core)

[root@c8-ansible ~]# ansible websrvs -m shell -a 'echo centos |passwd --stdin root'
192.168.209.37 | CHANGED | rc=0 >>
Changing password for user root.
passwd: all authentication tokens updated successfully.
192.168.209.38 | CHANGED | rc=0 >>
Changing password for user root.
passwd: all authentication tokens updated successfully.


[root@c8-ansible ~]# ansible websrvs -m shell -a "echo hello >/opt/hello.txt"
192.168.209.37 | CHANGED | rc=0 >>
192.168.209.38 | CHANGED | rc=0 >>
[root@c8-ansible ~]# ansible websrvs -m shell -a 'ls -l /opt/*'
192.168.209.37 | CHANGED | rc=0 >>
-rw-r--r-- 1 root root 6 Jul 15 13:22 /opt/hello.txt
192.168.209.38 | CHANGED | rc=0 >>
-rw-r--r-- 1 root root 6 Jul 15 21:22 /opt/hello.txt
[root@c8-ansible ~]# ansible websrvs -m shell -a 'cat /opt/hello.txt'
192.168.209.37 | CHANGED | rc=0 >>
hello
192.168.209.38 | CHANGED | rc=0 >>
hello

#
[root@c8-ansible ~]# ansible websrvs -m shell -a 'sleep 10'
192.168.209.37 | CHANGED | rc=0 >>

#ansible执行的时候,会在客户端生成临时的python程序,执行完毕后,自动删除
[root@c7-slave02 ~]# tree .ansible/tmp
.ansible/tmp
└── ansible-tmp-1626326986.2722778-14827-22658287469129
    └── AnsiballZ_command.py
1 directory, 1 file

[root@c7-slave03 ~]# ll .ansible/tmp	#执行完成后清除
total 0

范例:将shell模块代替command,设为模块

[root@c8-ansible ~]# vim /etc/ansible/ansible.cfg
#修改下面一行
module_name = shell

1.3 Script 模块

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

范例:

[root@c8-ansible ~]# ansible-doc -s script
- name: Runs a local script on a remote node after transferring it
  script:
      chdir:                 # Change into this directory on the remote node before running the script.
      cmd:                   # Path to the local script to run followed by optional arguments.
      creates:               # A filename on the remote node, when it already exists,this step will *not* be run.
      decrypt:               # This option controls the autodecryption of source files using vault.
      executable:            # Name or path of a executable to invoke the script with.   
      free_form:             # Path to the local script file followed by optional arguments.
      removes:               # A filename on the remote node, when it does not exist, this step will *not* be run.


范例:

#websrvs组的主机中/opt目录下都有hello.txt文件
[root@c8-ansible ~]# ansible websrvs -m shell -a 'ls /opt/'
192.168.209.37 | CHANGED | rc=0 >>
hello.txt
192.168.209.38 | CHANGED | rc=0 >>
hello.txt

#shell脚本,查看主机名并删除文件
[root@c8-ansible ~]# cat /data/test.sh
hostname
rm -f /opt/*
[root@c8-ansible ~]# ll /data/test.sh	
-rw-r--r-- 1 root root 22 Jul 15 14:17 /data/test.sh	#无需设置执行权限
[root@c8-ansible ~]# ansible websrvs -m script -a '/data/test.sh'
192.168.209.37 | CHANGED => {
    "changed": true,
    "rc": 0,
    "stderr": "Shared connection to 192.168.209.37 closed.\r\n",
    "stderr_lines": [
        "Shared connection to 192.168.209.37 closed."
    ],
    "stdout": "c7-slave03\r\n",
    "stdout_lines": [	
        "c7-slave03"		#显示的主机名
    ]
}
......

[root@c8-ansible ~]# ansible websrvs -m shell -a 'ls /opt/'		#文件已被删除
192.168.209.37 | CHANGED | rc=0 >>

192.168.209.38 | CHANGED | rc=0 >>


1.4 Copy 模块

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

范例:

#如目标存在,默认覆盖,此处指定先备份
ansible websrvs -m copy -a "src=/root/test1.sh dest=/tmp/test2.sh owner=wang mode=600 backup=yes"	#先备份,再覆盖,客户端要有owner用户,否则报错
[root@c8-ansible ~]# ansible websrvs -m shell -a "useradd haha"
192.168.209.37 | CHANGED | rc=0 >>

192.168.209.38 | CHANGED | rc=0 >>

[root@c8-ansible ~]# ansible websrvs -m copy -a "src=/data/test.sh dest=/opt/test1.sh owner=haha mode=600 backup=yes"
192.168.209.37 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "checksum": "7fb1bfed15f95114e46fdc7b72ced39744a690d4",
    "dest": "/opt/test1.sh",
    "gid": 0,
    "group": "root",
    "mode": "0600",
    "owner": "haha",
    "path": "/opt/test1.sh",
    "size": 22,
    "state": "file",
    "uid": 1000
}
192.168.209.38 | CHANGED => {
...同上...
[root@c8-ansible ~]# ansible websrvs -m shell -a "ls -l  /opt/*"
192.168.209.37 | CHANGED | rc=0 >>
-rw------- 1 haha root 22 Jul 15 14:47 /opt/test1.sh
192.168.209.38 | CHANGED | rc=0 >>
-rw------- 1 haha root 22 Jul 15 22:48 /opt/test1.sh
#再次复制,由于test.sh内容不变,所以根据ansible的幂等性,不会生成备份文件,显示是success而非changed
[root@c8-ansible ~]# ansible websrvs -m copy -a "src=/data/test.sh dest=/opt/test1.sh owner=haha mode=600 backup=yes"
192.168.209.37 | SUCCESS => {
192.168.209.38 | SUCCESS => {
[root@c8-ansible ~]# echo hello >/data/test.sh		#修改test.sh文件后,再次复制,会生成test1.sh的备份文件
[root@c8-ansible ~]# ansible websrvs -m copy -a "src=/data/test.sh dest=/opt/test1.sh owner=haha mode=600 backup=yes"
192.168.209.37 | CHANGED => {
192.168.209.38 | CHANGED => {
[root@c8-ansible ~]# ansible websrvs -m shell -a "ls -l  /opt/*"
192.168.209.37 | CHANGED | rc=0 >>
-rw------- 1 haha root  6 Jul 15 14:55 /opt/test1.sh
-rw------- 1 haha root 22 Jul 15 14:47 /opt/test1.sh.123180.2021-07-15@14:55:42~
192.168.209.38 | CHANGED | rc=0 >>
-rw------- 1 haha root  6 Jul 15 22:55 /opt/test1.sh
-rw------- 1 haha root 22 Jul 15 22:48 /opt/test1.sh.17171.2021-07-15@22:55:46~


#指定内容,直接生成目标文件;如果目标文件存在,会覆盖其内容
[root@c8-ansible ~]# ansible websrvs -m copy -a "content='test line1\ntest line2' dest=/opt/test1.sh"
[root@c8-ansible ~]# ansible websrvs -m copy -a "content='test line1\ntest line2' dest=/opt/test2.txt"
[root@c8-ansible ~]# ansible websrvs -a "cat /opt/test1.sh"   #test1.sh文件的内容由hello变更如下               
192.168.209.37 | CHANGED | rc=0 >>
test line1
test line2
192.168.209.38 | CHANGED | rc=0 >>
test line1
test line2
[root@c8-ansible ~]# ansible websrvs -a "cat /opt/test2.txt"	#同上


#复制/etc/sysconfig目录自身,注意/etc/sysconfig后面没有/
[root@c8-ansible ~]# ansible websrvs -m copy -a "src=/etc/sysconfig dest=/opt/"
192.168.209.37 | CHANGED => {
    "changed": true,
    "dest": "/opt/",
    "src": "/etc/sysconfig"
}
192.168.209.38 | CHANGED => {
    "changed": true,
    "dest": "/opt/",
    "src": "/etc/sysconfig"
}
[root@c7-slave02 ~]# ll /opt
total 20
drwxr-xr-x 6 root root 4096 Jul 15 03:44 sysconfig	#复制的整个目录


#复制/etc/sysconfig下的文件,不包括/etc/sysconfig目录自身,注意/etc/后面有/
[root@c8-ansible ~]# ansible websrvs -m copy -a "src=/etc/sysconfig/ dest=/opt"
[root@c7-slave02 ~]# ls /opt
anaconda          irqbalance       rsyslog    console        kdump         run-parts
cpupower          kernel           selinux    crond          man-db        sshd
ebtables-config   modules          sysconfig  firewalld      network       grub           network-scripts   ip6tables-config  nftables.conf    iptables-config   rhn 

[root@c8-ansible ~]# ansible websrvs  -a "cat /etc/os-release"
192.168.209.37 | CHANGED | rc=0 >>
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"

192.168.209.38 | CHANGED | rc=0 >>
NAME="CentOS Linux"
VERSION="8 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="8"
PLATFORM_ID="platform:el8"
PRETTY_NAME="CentOS Linux 8 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:8"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-8"
CENTOS_MANTISBT_PROJECT_VERSION="8"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="8"

1.5 Fetch 模块

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

范例:

#提取远程主机的test.sh文件到/data/scripts目录下
ansible websrvs -m fetch -a 'src=/root/test.sh dest=/data/scripts'

范例:

#提取所有远程主机的文件到当前主控端的/data/os目录下,并按远程主机的ip地址创建各自的目录存放
[root@c8-ansible ~]# ansible websrvs -m fetch -a 'src=/etc/redhat-release dest=/data/os'
192.168.209.37 | CHANGED => {
    "changed": true,
    "checksum": "0d3186157c40752f89db0e618a5866935b523e7b",
    "dest": "/data/os/192.168.209.37/etc/redhat-release",
    "md5sum": "902962816d0ec4fbb532949f70a41ae7",
    "remote_checksum": "0d3186157c40752f89db0e618a5866935b523e7b",
    "remote_md5sum": null
}
192.168.209.38 | CHANGED => {
    "changed": true,
    "checksum": "808b06c0b0ba3ea8da9cf504c2e8efae9564323c",
    "dest": "/data/os/192.168.209.38/etc/redhat-release",
    "md5sum": "af7668530a179ab22b8e08a29eefda8d",
    "remote_checksum": "808b06c0b0ba3ea8da9cf504c2e8efae9564323c",
    "remote_md5sum": null
}

#会创建/data/os目录,并在其目录下创建主机ip命名的目录存放文件
[root@c8-ansible ~]# tree /data/os
/data/os
├── 192.168.209.37
│   └── etc
│       └── redhat-release
└── 192.168.209.38
    └── etc
        └── redhat-release

4 directories, 2 files


1.6 File 模块

功能:设置文件属性

范例:

#创建空文件,修改权限,前提是用户已存在,不存在该用户会报错
[root@c8-ansible ~]# ansible websrvs -a "getent passwd wang"
192.168.209.37 | FAILED | rc=2 >>
non-zero return code
192.168.209.38 | CHANGED | rc=0 >>
wang:x:1000:1000:wang:/home/wang:/bin/bash		#只有38主机有wang用户
[root@c8-ansible ~]# ansible websrvs -m file -a "path=/opt/test.sh state=touch"	#创建空白文件
192.168.209.37 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "dest": "/opt/test.sh",
    "gid": 0,
    "group": "root",
    "mode": "0644",
    "owner": "root",
    "size": 0,
    "state": "file",
    "uid": 0
}
192.168.209.38 | CHANGED =>	#都同上
#修改文件权限,没有wang用户,失败
[root@c8-ansible ~]# ansible websrvs -m file -a "path=/opt/test.sh owner=wang mode=755"
192.168.209.37 | FAILED! => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "gid": 0,
    "group": "root",
    "mode": "0644",
    "msg": "chown failed: failed to look up user wang",		#没有找到wang用户
    "owner": "root",
    "path": "/opt/test.sh",
    "size": 0,
    "state": "file",
    "uid": 0
}
192.168.209.38 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": true,		#成功
    "gid": 0,
    "group": "root",
    "mode": "0755",
    "owner": "wang",
    "path": "/opt/test.sh",
    "size": 0,
    "state": "file",
    "uid": 1000
}
[root@c8-ansible ~]# ansible websrvs -a "ls -l /opt"
192.168.209.37 | CHANGED | rc=0 >>
-rw-r--r-- 1 root root 0 Jul 16 11:14 test.sh		#未修改
192.168.209.38 | CHANGED | rc=0 >>
-rwxr-xr-x 1 wang root 0 Jul 16 19:14 test.sh		#权限和用户已修改

#创建目录
ansible all -m file -a "path=/data/mysql state=directory owner=mysql group=mysql"
[root@c8-ansible ~]# ansible websrvs -m file -a "path=/data/dir state=directory"
192.168.209.37 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "gid": 0,
    "group": "root",
    "mode": "0755",
    "owner": "root",
    "path": "/data/dir",
    "size": 6,
    "state": "directory",
    "uid": 0
}
192.168.209.38 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": true,
    "gid": 0,
    "group": "root",
    "mode": "0755",
    "owner": "root",
    "path": "/data/dir",
    "size": 6,
    "state": "directory",
    "uid": 0
}

创建目录或文件,使用file模块,具有幂等性。如果使用mkdir等Linux命令,重复创建会报错
[root@c8-ansible ~]# ansible websrvs -a "mkdir /data/dir2" 
192.168.209.37 | CHANGED | rc=0 >>
192.168.209.38 | CHANGED | rc=0 >>
[root@c8-ansible ~]# ansible websrvs -a "mkdir /data/dir2"
192.168.209.37 | FAILED | rc=1 >>
mkdir: cannot create directory ‘/data/dir2’: File existsnon-zero return code
192.168.209.38 | FAILED | rc=1 >>
mkdir: cannot create directory ‘/data/dir2’: File existsnon-zero return code

#删除使用state=absent
[root@c8-ansible ~]# ansible websrvs -m file -a "path=/data/dir2 state=absent"  
192.168.209.37 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "path": "/data/dir2",
    "state": "absent"
}
192.168.209.38 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": true,
    "path": "/data/dir2",
    "state": "absent"
}


#创建软链接,原文件是在目标主机指定的目录中,否则失败
ansible all -m file -a 'src=/data/testfile dest=/data/testfile-link state=link'
[root@c8-ansible ~]# ansible websrvs -a "ls -l /opt/test1.sh"	#37中没有test1.sh
192.168.209.37 | CHANGED | rc=0 >>
ls: cannot access /opt/test1.sh: No such file or directorynon-zero return code
192.168.209.38 | CHANGED | rc=0 >>
-rw------- 1 haha root 21 Jul 15 23:46 /opt/test1.sh
[root@c8-ansible ~]# ansible websrvs -m file -a "src=/opt/test1.sh state=link dest=/opt/test1.sh.link"			#创建软链接时,37主机失败
192.168.209.37 | FAILED! => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "msg": "src file does not exist, use \"force=yes\" if you really want to create the link: /opt/test1.sh",
    "path": "/opt/test1.sh.link",
    "src": "/opt/test1.sh"
}
192.168.209.38 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": true,
    "dest": "/opt/test1.sh.link",
    "gid": 0,
    "group": "root",
    "mode": "0777",
    "owner": "root",
    "size": 13,
    "src": "/opt/test1.sh",
    "state": "link",
    "uid": 0
}

[root@c8-ansible ~]# ansible websrvs -a "ls -l /opt/test*.sh.link"
192.168.209.37 | CHANGED | rc=0 >>
ls: cannot access /opt/test*.sh.link: No such file or directorynon-zero return code
192.168.209.38 | CHANGED | rc=0 >>
lrwxrwxrwx 1 root root 13 Jul 16 19:01 /opt/test1.sh.link -> /opt/test1.sh


1.7 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@c8-ansible ~]# tar zcvf sys.tar.gz /etc/sysconfig
[root@c8-ansible ~]# ll sys.tar.gz
-rw-r--r-- 1 root root 5125 Jul 16 13:59 sys.tar.gz
[root@c8-ansible ~]# ansible websrvs -m unarchive -a 'src=sys.tar.gz dest=/opt owner=haha group=bin'
[root@c8-ansible ~]# ansible websrvs -a 'ls -l /opt/etc'
192.168.209.37 | CHANGED | rc=0 >>
total 4
drwxr-xr-x 6 haha bin 4096 Jul  16 14:06 sysconfig
192.168.209.38 同上

[root@c8-ansible ~]# ansible dbsrvs -m copy -a 'src=sys.tar.gz dest=/opt'
[root@c8-ansible ~]# ansible websrvs -m unarchive -a 'src=/opt/sys.tar.gz dest=/tmp copy=no mode=0777'
[root@c8-ansible ~]# ansible websrvs -a 'ls /tmp/etc -l'
192.168.209.37 | CHANGED | rc=0 >>
total 4
drwxrwxrwx 6 root root 4096 Jul 16 14:14 sysconfig
192.168.209.38 | CHANGED | rc=0 >>
total 4
drwxrwxrwx 6 root root 4096 Jul 16 14:14 sysconfig

ansible all -m unarchive -a 'src=https://example.com/example.zip dest=/data copy=no'

1.8 Archive 模块

功能:打包压缩保存在被管理节点

范例:

[root@c8-ansible ~]# ansible websrvs -m archive -a 'path=/etc/sysconfig dest=/opt/sys.tar.bz2 format=bz2 owner=haha mode=0600'
[root@c8-ansible ~]# ansible websrvs -a 'ls /opt/*.bz2 -l'
192.168.209.37 | CHANGED | rc=0 >>
-rw------- 1 haha root 37253 Jul 16 14:35 /opt/sys.tar.bz2
192.168.209.38 | CHANGED | rc=0 >>
-rw------- 1 haha root 4902 Jul 16 14:35 /opt/sys.tar.bz2

1.9 Hostname 模块

功能:管理主机名,不能按照需要修改为不同的主机名,以后可以使用循环判断来修改主机名

范例:

#如果目标主机的/etc/hosts中有对应的域名,则替换hostname和nodename,如果没有,全部替换
[root@c7-slave01 ~]# cat /etc/hosts
192.168.209.17 www.17.com
[root@c8-ansible ~]# ansible dbsrvs -m hostname -a "name=websrvs"
192.168.209.17 | CHANGED => {
    "ansible_facts": {
        "ansible_domain": "17.com",		#自带域名,不修改
        "ansible_fqdn": "www.17.com",		
        "ansible_hostname": "websrvs",		#替换为websrvs
        "ansible_nodename": "websrvs",
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "name": "websrvs"
}
192.168.209.18 | CHANGED => {
    "ansible_facts": {
        "ansible_domain": "",
        "ansible_fqdn": "websrvs",		#全部替换为websrvs
        "ansible_hostname": "websrvs",
        "ansible_nodename": "websrvs",
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": true,
    "name": "websrvs"
}


#查看原hostname
[root@c8-ansible ~]# ansible websrvs -a 'hostname'
192.168.209.37 | CHANGED | rc=0 >>
c7-slave03
192.168.209.38 | CHANGED | rc=0 >>
c8-slave03
[root@c8-ansible ~]#  ansible 192.168.209.38 -m hostname -a 'name=c8.magedu.com'
192.168.209.38 | CHANGED => {
    "ansible_facts": {
        "ansible_domain": "magedu.com",
        "ansible_fqdn": "c8.magedu.com",
        "ansible_hostname": "c8",
        "ansible_nodename": "c8.magedu.com",
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "name": "c8.magedu.com"
}
[root@c8-ansible ~]# ansible websrvs -a 'hostname'	#38主机的hostname被修改了
192.168.209.37 | CHANGED | rc=0 >>
c7-slave03
192.168.209.38 | CHANGED | rc=0 >>
c8.magedu.com
[root@c8-ansible ~]# ansible websrvs -a 'cat /etc/hostname'	#而且文件内容也被修改了
192.168.209.37 | CHANGED | rc=0 >>
c7-slave03
192.168.209.38 | CHANGED | rc=0 >>
c8.magedu.com


1.10 Cron 模块

功能:计划任务

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

范例:

#备份数据库脚本
[root@c8-ansible data]# cat mysql_backup.sh
mysqldump -A -F --single-transaction --master-data=2 -q -uroot |gzip > /opt/mysql_`date +%F`.sql.gz
[root@c8-ansible data]# ansible dbsrvs -m copy -a 'src=/data/mysql_backup.sh dest=/opt'
[root@c8-ansible data]# ansible dbsrvs  -a 'ls -l /opt/*.sh'	#不用加执行权限
192.168.209.17 | CHANGED | rc=0 >>
-rw-r--r-- 1 root root 100 Jul 16 15:11 /opt/mysql_backup.sh
192.168.209.18 | CHANGED | rc=0 >>
-rw-r--r-- 1 root root 100 Jul 16 23:11 /opt/mysql_backup.sh

#创建任务
[root@c8-ansible data]# ansible dbsrvs -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/opt/mysql_backup.sh'
192.168.209.17 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "envs": [],
    "jobs": [
        "backup mysql"
    ]
}
192.168.209.18 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": true,
    "envs": [],
    "jobs": [
        "backup mysql"
    ]
}

[root@c8-ansible data]# ansible dbsrvs  -a 'crontab -l'
192.168.209.17 | CHANGED | rc=0 >>
#Ansible: backup mysql
30 2 * * 1-5 /opt/mysql_backup.sh
192.168.209.18 | CHANGED | rc=0 >>
#Ansible: backup mysql
30 2 * * 1-5 /opt/mysql_backup.sh


#再创建一个时间同步的计划任务
[root@c8-ansible data]# ansible dbsrvs -m cron -a 'minute=*/5 job="/usr/sbin/ntpdate ntp.aliyun.com &>/dev/null" name=Synctime'
[root@c8-ansible data]# ansible dbsrvs  -a 'crontab -l'
192.168.209.17 | CHANGED | rc=0 >>
#Ansible: backup mysql
30 2 * * 1-5 /opt/mysql_backup.sh
#Ansible: Synctime
*/5 * * * * /usr/sbin/ntpdate ntp.aliyun.com &>/dev/null
192.168.209.18 | CHANGED | rc=0 >>		#同上

#删除任务
[root@c8-ansible data]# ansible dbsrvs -m cron -a 'name="backup mysql" state=absent'
[root@c8-ansible data]# ansible dbsrvs  -a 'crontab -l'
192.168.209.17 | CHANGED | rc=0 >>
#Ansible: Synctime
*/5 * * * * /usr/sbin/ntpdate ntp.aliyun.com &>/dev/null
192.168.209.18 | CHANGED | rc=0 >>


#禁用计划任务
[root@c8-ansible data]# ansible dbsrvs -m cron -a 'minute=*/5 job="/usr/sbin/ntpdate ntp.aliyun.com &>/dev/null" name=Synctime disabled=yes'

[root@c8-ansible data]# ansible dbsrvs  -a 'crontab -l'
192.168.209.17 | CHANGED | rc=0 >>
#Ansible: Synctime
#*/5 * * * * /usr/sbin/ntpdate ntp.aliyun.com &>/dev/null	#就是注释掉该计划任务
192.168.209.18 | CHANGED | rc=0 >>		#同上

#启用计划任务
[root@c8-ansible data]# ansible dbsrvs -m cron -a 'minute=*/5 job="/usr/sbin/ntpdate ntp.aliyun.com &>/dev/null" name=Synctime disabled=no'

1.11 Yum 模块

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

范例:

ansible websrvs -m yum -a 'name=iotop,cowsay state=present' 	#安装,present可以省略
ansible websrvs -m yum -a 'name=iotop,cowsay state=absent' 	#删除
[root@c8-ansible ~]# ansible websrvs -m yum -a 'name=iotop,cowsay'

1.12 Service 模块

功能:管理服务

范例:

ansible all -m service -a 'name=httpd state=started enabled=yes'
ansible all -m service -a 'name=httpd state=stopped'
ansible all -m service -a 'name=httpd state=reloaded'
ansible all -m shell -a "sed -i 's/^Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf"
ansible all -m service -a 'name=httpd state=restarted'

范例:

[root@c8-ansible data]# ansible websrvs -m yum -a "name=vsftpd"
[root@c8-ansible data]# ansible websrvs -m service -a "name=vsftpd state=started"
[root@c8-ansible data]# ansible websrvs -a "systemctl status vsftpd"
192.168.100.37 | CHANGED | rc=0 >>
● vsftpd.service - Vsftpd ftp daemon
   Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; disabled; vendor preset: disabled)
   Active: active (running) since Sun 2021-07-25 16:20:08 CST; 24s ago
  Process: 4340 ExecStart=/usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf (code=exited, status=0/SUCCESS)
 Main PID: 4341 (vsftpd)
   CGroup: /system.slice/vsftpd.service
           └─4341 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf

Jul 25 16:20:08 c7-pxc2 systemd[1]: Starting Vsftpd ftp daemon...
Jul 25 16:20:08 c7-pxc2 systemd[1]: Started Vsftpd ftp daemon.
192.168.100.38 | CHANGED | rc=0 >>

#增加开机启动enabled
[root@c8-ansible data]# ansible websrvs -m service -a "name=vsftpd state=started enabled=yes"
[root@c8-ansible data]# ansible websrvs -a "systemctl status vsftpd"
192.168.100.37 | CHANGED | rc=0 >>
● vsftpd.service - Vsftpd ftp daemon
   Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; enabled; vendor preset: disabled)
   Active: active (running) since Sun 2021-07-25 16:20:08 CST; 5min ago
192.168.100.38 | CHANGED | rc=0 >>
[root@c8-ansible data]# ansible websrvs -a "systemctl is-enabled vsftpd"
192.168.100.37 | CHANGED | rc=0 >>
enabled
192.168.100.38 | CHANGED | rc=0 >>
enabled

#停止服务
[root@c8-ansible data]# ansible websrvs -m service -a "name=vsftpd state=stopped"
[root@c8-ansible data]# ansible websrvs -a "systemctl status vsftpd"
192.168.100.37 | FAILED | rc=3 >>
● vsftpd.service - Vsftpd ftp daemon
   Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; enabled; vendor preset: disabled)
   Active: inactive (dead) since Sun 2021-07-25 16:32:41 CST; 21s ago
 Main PID: 4341 (code=killed, signal=TERM)

Jul 25 16:20:08 c7-pxc2 systemd[1]: Starting Vsftpd ftp daemon...
Jul 25 16:20:08 c7-pxc2 systemd[1]: Started Vsftpd ftp daemon.
Jul 25 16:32:41 c7-pxc2 systemd[1]: Stopping Vsftpd ftp daemon...
Jul 25 16:32:41 c7-pxc2 systemd[1]: Stopped Vsftpd ftp daemon.non-zero return code
192.168.100.38 | FAILED | rc=3 >>

1.13 User 模块

功能:管理用户

范例:

#创建用户
#用户名 描述 uid 家目录 所属组
ansible all -m user -a 'name=user1 comment="test user" uid=2048 home=/app/user1 group=root'
#用户名 描述 uid 所属组 从属组 shell类型 是否系统账户 是否创建家目录 家目录路径 uid是否唯一
ansible all -m user -a 'name=nginx comment=nginx uid=88 group=nginx groups="root,daemon" shell=/sbin/nologin system=yes create_home=no home=/data/nginx non_unique=yes'

#remove=yes表示删除用户及家目录等数据,默认remove=no
ansible all -m user -a 'name=nginx state=absent remove=yes'

1.14 Group 模块

功能:管理组

范例:

#创建组
ansible websrvs -m group -a 'name=nginx gid=88 system=yes'
#删除组
ansible websrvs -m group -a 'name=nginx state=absent'

1.15 Lineinfile 模块

功能:相当于sed,可以修改文件内容

范例:

#lineinfile是整行替换
ansible all -m lineinfile -a "path=/etc/selinux/config regexp='^SELINUX=' line='SELINUX=disabled'"

ansible websrvs -m lineinfile -a "path=/etc/httpd/conf/httpd.conf regexp='^Listen' line='Listen 80'"

#删除#开头的行
ansible all -m lineinfile -a 'dest=/etc/fstab state=absent regexp="^#"'

1.16 Replace 模块

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

范例:

#添加#
ansible all -m replace -a "path=/etc/fstab regexp='^(UUID.*)' replace='#\1'"

[root@c8-ansible ~]# ansible websrvs -m replace -a "path=/opt/fstab.bak regexp='^(UUID.*)' replace='#\1'"
192.168.209.37 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "msg": "4 replacements made"
}
192.168.209.38 | CHANGED => {
[root@c8-ansible ~]# ansible websrvs -a "cat /opt/fstab.bak"
192.168.209.37 | CHANGED | rc=0 >>
#UUID=969c27c4-5d7c-4ccb-8a3c-65fa9cbd0df6 /              xfs     defaults        0 0
#UUID=44fe34d5-daf7-4066-ac9d-def0a554f1e1 /boot          ext4    defaults        1 2
#UUID=06ac3eeb-6c1a-468f-a386-ab869b1ba7ec /data          xfs     defaults        0 0
#UUID=49f06d17-be23-479a-8de9-4f86694a156e swap           swap    defaults        0 0

#去掉#
ansible all -m replace -a "path=/etc/fstab regexp='^#(.*)' replace='\1'"

1.17 Setup 模块

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

范例:

ansible all -m setup		#收集服务器详细信息
ansible all -m setup -a "filter=ansible_nodename"		#主机全名
ansible all -m setup -a "filter=ansible_hostname"		#主机名(部分名称)
ansible all -m setup -a "filter=ansible_os_family"		#操作系统家族
ansible all -m setup -a "filter=ansible_domain"			#域名
ansible all -m setup -a "filter=ansible_memtotal_mb"		#内存总大小
ansible all -m setup -a "filter=ansible_memory_mb"		#内存,包含交换分区等
ansible all -m setup -a "filter=ansible_memfree_mb"		#剩余内存

ansible all -m setup -a "filter=ansible_distribution_major_version"	#操作系统版本号
ansible all -m setup -a "filter=ansible_distribution_version"		#小版本号
ansible websrvs -m setup -a "filter=ansible_distribution"		#操作系统版本
#返回"ansible_distribution": "CentOS"

ansible all -m setup -a "filter=ansible_processor_vcpus"		#cpu个数
ansible all -m setup -a "filter=ansible_all_ipv4_addresses"		#多块网卡的所有ip地址
ansible all -m setup -a "filter=ansible_default_ipv4"			#默认ip地址		

范例:

[root@c8-ansible ~]# ansible appsrvs -m setup -a "filter=ansible_python_version"
192.168.209.47 | SUCCESS => {
    "ansible_facts": {
        "ansible_python_version": "2.7.5",
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false
}
192.168.209.46 | SUCCESS => {
    "ansible_facts": {
        "ansible_python_version": "2.6.6",
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false
}
192.168.209.48 | SUCCESS => {
    "ansible_facts": {
        "ansible_python_version": "3.6.8",
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false
}

范例:取IP地址

#取所有IP
[]# ip a a 192.168.209.88/24 dev 
[root@c8-ansible ~]# ansible 192.168.209.38  -m setup -a "filter=ansible_all_ipv4_addresses"
192.168.209.38 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.209.38",
            "192.168.209.88"
        ],
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false
}

#取默认IP
[root@c8-ansible ~]# ansible 192.168.209.38  -m setup -a "filter=ansible_default_ipv4"
192.168.209.38 | SUCCESS => {
    "ansible_facts": {
        "ansible_default_ipv4": {
            "address": "192.168.209.38",
            "alias": "ens33",
            "broadcast": "192.168.209.255",
            "gateway": "192.168.209.2",
            "interface": "ens33",
            "macaddress": "00:0c:29:c9:d6:1b",
            "mtu": 1500,
            "netmask": "255.255.255.0",
            "network": "192.168.209.0",
            "type": "ether"
        },
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false
}

2 roles角色

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

运维复杂的场景:建议使用roles,代码复用度高

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

roles/
  mysql/
  nginx/
  tomcat/
  redis/

20a12.jpg

2.1 Ansible Roles目录编排

2.1.1 roles目录结构

playbook.yml		#调用profect中的文件
roles/
  project/
    tasks/
    files/
    vars/
    templates/
    handlers/
    default/
    meta/

2.1.2 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的优先级低

#扩展的时候,只需要修改特定目录下的指定文件即可,其他文件不受影响

2.2 创建 role

2.2.1 创建role的步骤

  1. 创建以roles命名的目录
  2. 在roles目录中分别创建以各角色名称命名的目录,如webservers、nginx、mysql等
  3. 在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和vars目录;用不到的目录可以创建为空目录,也可以不创建
  4. 在playbook文件中,调用各角色

2.2.2 针对大型项目使用Roles进行编排

范例:roles的目录结构

nginx-role.yml
roles/
└── nginx
     ├── files
     │    └── main.yml
     ├── tasks
     │    ├── groupadd.yml
     │    ├── install.yml
     │    ├── main.yml
     │    ├── restart.yml
     │    └── useradd.yml
     └── vars
     └── main.yml

2.3 playbook调用角色

调用角色方法1:

---
- hosts: websrvs
  remote_user: root
  roles:
    - mysql
    - memcached
    - nginx
#在websrvs组的主机中安装mysql、memcached、nginx角色

调用角色方法2:

键role用于指定角色名称,后续的k/v用于传递变量给角色

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

调用角色方法3:

还可基于条件测试实现角色调用

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

2.4 roles 中 tags 使用

#nginx-role.yml

---
- hosts: websrvs
  remote_user: root
  roles:
    - { role: nginx, tags: [ 'nginx', 'web' ], when: ansible_distribution_major_version == "6" }
    #标签tags是httpd或web
    - { role: httpd, tags: [ 'httpd', 'web' ] }
    - { role: mysql, tags: [ 'mysql', 'db' ] }
    - { role: mariadb, tags: [ 'mariadb', 'db' ] }
ansible-playbook --tags="nginx,httpd,mysql" nginx-role.yml  #执行的时候选择标签执行


2.5 实战案例

2.5.1 案例1:实现 httpd 角色

#创建角色相关的目录,生产中有个默认的roles目录,在/etc/ansible下
[root@c8-ansible ~]# mkdir -p /data/ansible/roles/httpd/{tasks,handlers,files}

#创建角色相关的文件
[root@c8-ansible ~]# cd /data/ansible/roles/httpd/
[root@c8-ansible httpd]# tree
.
├── files
├── handlers
└── tasks

#main.yml 是task的入口文件,必须使用main.yml名字
[root@c8-ansible httpd]# cat tasks/main.yml
- include: group.yml
- include: user.yml
- include: install.yml
- include: config.yml
- include: index.yml
- include: service.yml

[root@c8-ansible httpd]# cat tasks/group.yml
- name: create apache group
  group: name=apache system=yes gid=80
[root@c8-ansible httpd]# cat tasks/user.yml
- name: create apache user
  user: name=apache uid=80 group=apache system=yes shell=/sbin/nologin home=/data/
[root@c8-ansible httpd]# cat tasks/install.yml
- name: install httpd package
  yum: name=httpd
[root@c8-ansible httpd]# cat tasks/config.yml
- name: configure file
  copy: src=httpd.conf dest=/etc/httpd/conf/ backup=yes
  notify: restart
[root@c8-ansible httpd]# cat tasks/index.yml
- name: index.htmldata
  copy: src=index.html dest=/data/html/
[root@c8-ansible httpd]# cat tasks/service.yml
- name: start service
  service: name=httpd state=started enabled=yes
[root@c8-ansible httpd]# cat handlers/main.yml
- name: restart
  service: name=httpd state=restarted

#在files目录下准备两个文件httpd.conf和index.html,修改如下位置
[root@c8-ansible httpd]# vim files/httpd.conf
Listen 808
DocumentRoot "/data/html"
<Directory "/data/html">

[root@c8-ansible httpd]# cat files/index.html
welcome to magedu by ansible playbook apache

[root@c8-ansible httpd]# tree
.
├── files
│   ├── httpd.conf
│   └── index.html
├── handlers
│   └── main.yml
└── tasks
    ├── config.yml
    ├── group.yml
    ├── index.yml
    ├── install.yml
    ├── main.yml
    ├── service.yml
    └── user.yml
3 directories, 10 files


#在playbook中调用角色,和roles目录平级
[root@c8-ansible ansible]# cat /data/ansible/role_httpd.yml
#httpd role
---
- hosts: websrvs
  remote_user: root
  roles:
    - httpd

#运行playbook
[root@c8-ansible ansible]# ansible-playbook /data/ansible/role_httpd.yml

#测试
[root@c8-ansible ansible]# curl 192.168.209.37:808
welcome to magedu by ansible playbook apache
[root@c8-ansible ansible]# curl 192.168.209.38:808
welcome to magedu by ansible playbook apache


#修改httpd.conf文件的端口号为909,再次测试
[root@c8-ansible ansible]# grep '^Listen' roles/httpd/files/httpd.conf
Listen 909
[root@c8-ansible ansible]# ansible-playbook /data/ansible/role_httpd.yml
RUNNING HANDLER [httpd : restart] ***********************************************************************************************************************
changed: [192.168.209.37]
changed: [192.168.209.38]

[root@c8-ansible ansible]# ansible websrvs -a 'ss -nlt'
192.168.209.37 | CHANGED | rc=0 >>
State      Recv-Q Send-Q Local Address:Port               Peer Address:Port
LISTEN     0      128       [::]:909                   [::]:*
192.168.209.38 | CHANGED | rc=0 >>		#同上

[root@c8-ansible ansible]# curl 192.168.209.38:808
curl: (7) Failed to connect to 192.168.209.38 port 808: Connection refused
[root@c8-ansible ansible]# curl 192.168.209.38:909
welcome to magedu by ansible playbook apache

2.5.2 案例2:实现 nginx 角色,默认路径

1、创建相应目录
[root@c8-ansible ~]# mkdir -p /data/ansible/roles/nginx/{tasks,handlers,templates,vars}
2、创建task文件
[root@c8-ansible nginx]# cd /data/ansible/roles/nginx/
[root@c8-ansible nginx]# cat tasks/main.yml
- include: install.yml
- include: config.yml
- include: index.yml
- include: service.yml
[root@c8-ansible nginx]# cat tasks/config.yml
- name: configure file for centos7
  template: src=nginx7.conf.j2 dest=/etc/nginx/nginx.conf
  when: ansible_distribution_major_version=="7"
  notify: restart
- name: configure file for centos8
  template: src=nginx8.conf.j2 dest=/etc/nginx/nginx.conf
  when: ansible_distribution_major_version=="8"
  notify: restart
[root@c8-ansible nginx]# cat tasks/index.yml
- name: copy centos7.html
  template: src=centos7.html dest=/usr/share/nginx/html/index.html
  when: ansible_distribution_major_version=="7"
- name: copy centos8.html
  template: src=centos8.html dest=/usr/share/nginx/html/index.html
  when: ansible_distribution_major_version=="8"
[root@c8-ansible nginx]# cat tasks/install.yml
- name: install nginx
  yum: name=nginx
[root@c8-ansible nginx]# cat tasks/service.yml
- name: start service
  service: name=nginx state=started enabled=yes


3、创建handler文件
[root@c8-ansible nginx]# cat handlers/main.yml
- name: restart
  service: name=nginx state=restarted

4、创建template文件
[root@c8-ansible nginx]# cat templates/centos7.html
centos7
[root@c8-ansible nginx]# cat templates/centos8.html
centos8
[root@c8-ansible nginx]# cat templates/nginx7.conf.j2
user {{user}};
worker_processes {{ansible_processor_vcpus+3}};
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
...省略...

[root@c8-ansible nginx]# cat templates/nginx8.conf.j2
user {{user}};
worker_processes {{ansible_processor_vcpus**3}};
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
...省略...

5、创建变量文件
[root@c8-ansible nginx]# cat vars/main.yml
user: daemon

6、目录结构如下
[root@c8-ansible nginx]# tree
.
├── handlers
│   └── main.yml
├── tasks
│   ├── config.yml
│   ├── index.yml
│   ├── install.yml
│   ├── main.yml
│   ├── service.yml
├── templates
│   ├── centos7.html
│   ├── centos8.html
│   ├── nginx7.conf.j2
│   └── nginx8.conf.j2
└── vars
    └── main.yml

4 directories, 11 files

7、在playbook中调用nginx角色,和roles目录平级
[root@c8-ansible memcache]# cat /data/ansible/role_nginx.yml
#nginx role
---
- hosts: websrvs
  remote_user: root
  roles:
    - nginx

8、运行
[root@c8-ansible nginx]# ansible-playbook /data/ansible/role_nginx.yml

9、测试
[root@c8-ansible nginx]# curl 192.168.209.38
centos8
[root@c8-ansible nginx]# curl 192.168.209.37
centos7

2.5.3 案例3:centos7和8系统下实现 mysql 5.6 的角色

1、创建目录
[root@c8-ansible ~]# mkdir -p /data/ansible/roles/mysql56/{files,tasks}
[root@c8-ansible ~]# cd /data/ansible/roles/mysql56

2、导入文件
#my.cnf配置文件
[root@c8-ansible mysql56]# cat files/my.cnf
[mysqld]
socket=/tmp/mysql.sock
user=mysql
symbolic-links=0
datadir=/data/mysql
innodb_file_per_table=1
log-bin
pid-file=/data/mysql/mysqld.pid
[client]
port=3306
socket=/tmp/mysql.sock
[mysqld_safe]
log-error=/var/log/mysqld.log
[root@c8-ansible mysql56]# cat files/secure_mysql.sh
#!/bin/bash
/usr/local/mysql/bin/mysql_secure_installation <<EOF

y
magedu
magedu
y
y
y
y
EOF

[root@c8-ansible mysql56]# cat files/path_mysql.sh		#创建软链接到PATH路径下
ln -s /usr/local/mysql/bin/mysql /usr/local/sbin
[root@c8-ansible mysql56]# chmod +x files/secure_mysql.sh files/path_mysql.sh
[root@c8-ansible mysql56]# ls files/
my.cnf   mysql-5.6.51-linux-glibc2.12-x86_64.tar.gz   path_mysql.sh   secure_mysql.sh

[root@c8-ansible mysql56]# tree
.
├── files
│   ├── my.cnf
│   ├── mysql-5.6.51-linux-glibc2.12-x86_64.tar.gz
│   ├── path_mysql.sh
│   └── secure_mysql.sh
└── tasks
    ├── config.yml
    ├── data.yml
    ├── group.yml
    ├── install.yml
    ├── link.yml
    ├── main.yml
    ├── path.yml
    ├── secure.yml
    ├── service.yml
    ├── unarchive.yml
    └── user.yml
2 directories, 15 files

3、tasks目录下的yml文件
[root@c8-ansible mysql56]# cat tasks/main.yml
- include: install.yml
- include: group.yml
- include: user.yml
- include: unarchive.yml
- include: link.yml
- include: path.yml
- include: config.yml
- include: data.yml
- include: service.yml
- include: secure.yml
[root@c8-ansible mysql56]# cat tasks/install.yml
- name: 安装依赖的包文件
  yum: name=libaio,perl-Data-Dumper,perl-Getopt-Long,numactl-libs,libncurses*
[root@c8-ansible mysql56]# cat tasks/group.yml
- name: 创建mysql组
  group: name=mysql gid=306
[root@c8-ansible mysql56]# cat tasks/user.yml
- name: 创建mysql用户
  user: name=mysql uid=306 group=mysql shell=/sbin/nologin system=yes create_home=no home=/data/mysql
[root@c8-ansible mysql56]# cat tasks/unarchive.yml
- name: 复制mysql压缩文件到远程主机
  unarchive: src=mysql-5.6.51-linux-glibc2.12-x86_64.tar.gz dest=/usr/local owner=root group=root
[root@c8-ansible mysql56]# cat tasks/link.yml
- name: 创建软链接
  file: src=/usr/local/mysql-5.6.51-linux-glibc2.12-x86_64 dest=/usr/local/mysql state=link
[root@c8-ansible mysql56]# cat tasks/path.yml
- name: 创建软链接到PATH路径
  script: path_mysql.sh
[root@c8-ansible mysql56]# cat tasks/config.yml
- name: config my.cnf
  copy: src=my.cnf dest=/etc/my.cnf
[root@c8-ansible mysql56]# cat tasks/data.yml
- name: data dir
  shell: chdir=/usr/local/mysql/ ./scripts/mysql_install_db --datadir=/data/mysql --user=mysql
[root@c8-ansible mysql56]# cat tasks/service.yml
- name: service script
  shell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld;/etc/init.d/mysqld start
[root@c8-ansible mysql56]# cat tasks/secure.yml
- name: secure script安全加固
  script: secure_mysql.sh

4、在playbook中调用mysql56角色
[root@c8-ansible mysql56]# cat /data/ansible/role_mysql56.yml
#mysql56 role
---
- hosts: dbsrvs
  remote_user: root
  roles:
    - mysql56

5、运行    
[root@c8-ansible mysql56]# ansible-playbook /data/ansible/role_mysql56.yml

6、测试
[root@c8-slave02 ~]# mysql
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
[root@c8-slave02 ~]# mysql -uroot -pmagedu
Server version: 5.6.51-log MySQL Community Server (GPL)
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)
mysql> exit
Bye
[root@c8-slave02 ~]# ll /usr/local/sbin/
total 0
lrwxrwxrwx 1 root root 26 Aug 20 17:41 mysql -> /usr/local/mysql/bin/mysql


卸载mysql5.6
[root@c8-ansible mysql56]# cat remove_mysql56.yml
---
#remove mysql56
- hosts: dbsrvs
  remote_user: root
  tasks:
    - name: stop service
      shell: /etc/init.d/mysqld stop
    - name: remove mysql
      yum: name=mysql state=absent
    - name: delete files and dir
      file: path={{item}} state=absent
      with_items:
        - /data/mysql
        - /etc/init.d/mysqld
        - /tmp/mysql.sock
        - /var/log/mysqld.log
        - /usr/local/mysql
        - /usr/local/mysql-5.6.51-linux-glibc2.12-x86_64
        - /etc/my.cnf
        - /usr/local/sbin/mysql
    - name: delete mysql user
      user: name=mysql state=absent


2.5.4 案例4:Ansible playbook实现zabbix-agent批量部署(主机名不同)

1、主机分配
192.168.209.252  c8-ansible
192.168.209.18	 centos8-client1
192.168.209.17   centos7-client2

2、安装ansible
[root@c8-ansible ~]# yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm -y
[root@c8-ansible ~]# yum install -y ansible

3、配置hosts
[root@c8-ansible ~]# vim /etc/ansible/hosts
......
[zabbix_agent]
192.168.209.18
192.168.209.17

3、ssh认证
[root@c8-ansible ~]# ssh-keygen
[root@c8-ansible ~]# ssh-copy-id 127.0.0.1
[root@c8-ansible ~]# rsync -av .ssh 192.168.209.18:/root/
[root@c8-ansible ~]# rsync -av .ssh 192.168.209.17:/root/

4、创建ansible/roles目录
[root@c8-ansible ~]# mkdir -p /data/ansible/roles/zabbix_agent/{tasks,handlers,templates}

5、主要配置文件
[root@c8-ansible ~]# cd /data/ansible/roles/zabbix_agent
[root@c8-ansible zabbix_agent]# cat tasks/main.yml
- include: install.yml
- include: config.yml
- include: service.yml

[root@c8-ansible zabbix_agent]# cat tasks/install.yml
- name: install zabbix40-agent
  yum: name=zabbix40-agent
[root@c8-ansible zabbix_agent]# cat tasks/config.yml
- name: zabbix-agent config
  template: src=zabbix.conf.j2 dest=/etc/zabbix/zabbix_agentd.conf
  notify: restart

[root@c8-ansible zabbix_agent]# cat tasks/service.yml
- name: start zabbix-agent
  service: name=zabbix-agent state=started enabled=yes

[root@c8-ansible zabbix_agent]# cat templates/zabbix.conf.j2
PidFile=/run/zabbix/zabbix_agentd.pid
LogFile=/var/log/zabbix/zabbix_agentd.log
LogFileSize=0
Server=192.168.209.252				#zabbix服务器ip地址
ServerActive=192.168.209.252
Hostname={{ansible_hostname}}		#各客户端的主机名

[root@c8-ansible zabbix_agent]# cat handlers/main.yml
- name: restart
  service: name=zabbix-agent state=restarted

6、配置roles/zabbix_agent角色并调用测试
[root@c8-ansible zabbix_agent]# cat ../../role_zabbixagent.yml
---
- hosts: dbsrvs
  remote_user: root
  roles:
    - zabbix_agent
7、运行
[root@c8-ansible zabbix_agent]# ansible-playbook ../../role_zabbixagent.yml
8、测试
[root@c8-ansible zabbix_agent]# ansible dbsrvs -a 'ss -nlt'		#客户端的端口号已开启
192.168.209.18 | CHANGED | rc=0 >>
State     Recv-Q    Send-Q       Local Address:Port        Peer Address:Port
LISTEN    0         128                0.0.0.0:10050            0.0.0.0:*
LISTEN    0         128                0.0.0.0:22               0.0.0.0:*
LISTEN    0         128                   [::]:10050               [::]:*
LISTEN    0         128                      *:80                     *:*
LISTEN    0         128                   [::]:22                  [::]:*
192.168.209.17 | CHANGED | rc=0 >>
State      Recv-Q Send-Q Local Address:Port               Peer Address:Port
LISTEN     0      128          *:22                       *:*
LISTEN     0      128          *:10050                    *:*
LISTEN     0      128       [::]:22                    [::]:*
LISTEN     0      128       [::]:10050                 [::]:*

[root@centos7-client2 ~]# cat /etc/zabbix/zabbix_agentd.conf
PidFile=/run/zabbix/zabbix_agentd.pid
LogFile=/var/log/zabbix/zabbix_agentd.log
LogFileSize=0
Server=192.168.209.252
ServerActive=192.168.209.252
Hostname=centos7-client2

[root@centos8-client1 ~]# systemctl status zabbix-agent
● zabbix-agent.service - Zabbix Monitor Agent
   Loaded: loaded (/usr/lib/systemd/system/zabbix-agent.service; enabled; vendor preset: disabled)
   Active: active (running) since Sat 2021-08-21 10:52:48 CST; 2min 8s ago