part11.all

一、ansible 常用指令总结,并附有相关示例

1、Ansible相关工具

  • /usr/bin/ansible 主程序,临时命令执行工具
  • /usr/bin/ansible-doc 查看配置文档,模块功能查看工具,相当于man
  • /usr/bin/ansible-playbook 定制自动化任务,编排剧本工具,相当于脚本
  • /usr/bin/ansible-pull 远程执行命令的工具
  • /usr/bin/ansible-vault 文件加密工具
  • /usr/bin/ansible-console 基于Console界面与用户交互的执行工具
  • /usr/bin/ansible-galaxy 下载/上传优秀代码或Roles模块的官网平台

利用ansible实现管理的主要方式:

  • Ansible Ad-Hoc 即利用ansible命令,主要用于临时命令使用场景
  • Ansible playbook 主要用于长期规划好的,大型项目的场景,需要有前期的规划过程

ansible 使用前准备
rocky下载ansible:

[root@ansible ~]#yum -y remove glibc-gconv-extra-2.28-189.1.el8.x86_64
[root@ansible ~]#yum -y install python39 rust
[root@ansible ~]#pip3 install --upgrade pip -i https://pypi.douban.com/simple
[root@ansible ~]#pip3 install ansible -i https://pypi.douban.com/simple/

#通过环境变量ANSIBLE_CONFIG指定ansible配置文件路径
[root@ansible ~]#cd /data/ansible/
[root@ansible ansible]#cat ansible.cfg 
[defaults]
inventory      = ./hosts
[root@ansible ansible]#cat hosts 
[web]
192.168.217.134
192.168.217.133
[app]
192.168.217.132
192.168.217.131
[root@ansible ansible]#export ANSIBLE_CONFIG=./ansbile.cfg 
[root@ansible ansible]#ansible --version
  config file = /data/ansible/ansible.cfg
#在此目录下才可通过运行hosts文件的主机

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

#下载sshpass
[root@ansible ~]#wget http://sourceforge.net/projects/sshpass/files/latest/download -O sshpass.tar.gz
[root@ansible ~]#tar xvf sshpass.tar.gz 
[root@ansible ~]#cd sshpass-1.08/
[root@ansible sshpass-1.08]# ./configure && make && sudo make install



[root@ansible ~]#vim ssh_key.sh
#!/bin/bash
IPLIST="
192.168.217.134
192.168.217.133
192.168.217.132
192.168.217.131"

[ -f /root/.ssh/id_rsa ] || ssh-keygen -f /root/.ssh/id_rsa  -P ''
export SSHPASS='zxk19981125'
for IP in $IPLIST;do
   { sshpass -e ssh-copy-id -o StrictHostKeyChecking=no $IP; } &
done
wait

1.1、ansible-doc

此工具用来显示模块帮助,相当于man

格式:
ansible-doc [options] [module…]
-l, --list #列出可用模块
-s, --snippet #显示指定模块的playbook片段

范例:

#列出所有模块
ansible-doc -l  
#查看指定模块帮助用法
ansible-doc ping  
#查看指定模块帮助用法
ansible-doc -s  ping

范例: 查看指定的插件

[root@ansible ~]#ansible-doc -t connection -l
[root@ansible ~]#ansible-doc -t lookup -l

1.2、ansible 命令用法

格式:
ansible [-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实现通过sudo机制实现提升权限
--become-user=USERNAME  #指定sudo的runas用户,默认为root
-K, --ask-become-pass  #提示输入sudo时的口令
-f FORKS, --forks FORKS #指定并发同时执行ansible任务的主机数
-i INVENTORY, --inventory INVENTORY  #指定主机清单文件

范例:

#以wang用户执行ping存活检测
ansible all -m ping -u wang  -k
#以wang sudo至root执行ping存活检测
ansible all -m ping -u wang -k -b
#以wang sudo至mage用户执行ping存活检测
ansible all -m ping -u wang -k -b --become-user=mage
#以wang sudo至root用户执行ls 
ansible all -m command  -u wang -a 'ls /root' -b --become-user=root -k -K

范例: 并发执行控制

#分别执行下面两条命令观察结果
#每过5s运行完一台
[root@ansible ~]#ansible all -a 'sleep 5' -f1
#过5s后10台同时运行完
[root@ansible ~]#ansible all -a 'sleep 5' -f10

范例: 使用普能用户进行远程管理

#在所有控制端和被控制端创建用户和密码
[root@rocky8 ~]#useradd wang
[root@rocky8 ~]#echo wang:123456 | chpasswd
#在所有被控制端对用户sudo授权
[root@rocky8 ~]#visudo 
wang    ALL=(ALL)   NOPASSWD: ALL
[root@rocky8 ~]#visudo -c
/etc/sudoers: parsed OK
#实现从控制端到被控制端的基于key验证
[root@ansible ~]#su - wang
wang@ansible:~$ssh-keygen -f ~/.ssh/id_rsa  -P ''
wang@ansible:~$$ssh-copy-id wang@'10.0.0.8'
#使用普通用户测试连接,默认连接权限不足失败
wang@ansible:~$ ansible 10.0.0.8 -m shell -a 'ls /root'
10.0.0.8 | FAILED | rc=2 >>
ls: cannot open directory '/root': Permission deniednon-zero return code
#使用普通用户通过-b选项连接实现sudo提权后连接成功
wang@ansible:~$ ansible 10.0.0.8 -m shell -a 'ls /root' -b --become-user root
10.0.0.8 | CHANGED | rc=0 >>
anaconda-ks.cfg
#修改配置文件指定sudo机制
[root@ansible ~]#vim /etc/ansible/ansible.cfg
#取消下面行前面的注释
[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False
#再次测试
[root@ansible ~]#su - wang
wang@ansible:~$ ansible 10.0.0.8 -m shell -a 'ls /root'
10.0.0.8 | CHANGED | rc=0 >>
anaconda-ks.cfg

范例: 使用普通用户连接远程主机执行代替另一个用户身份执行操作

[root@centos8 ~]#useradd wang
[root@centos8 ~]#echo wang:123456 | chpasswd
#先在被控制端能过sudo对普通用户授权
[root@centos8 ~]#grep wang /etc/sudoers
wang    ALL=(ALL) NOPASSWD: ALL
#以wang的用户连接用户,并利用sudo代表mage执行whoami命令
[root@ansible ~]#ansible 10.0.0.8 -m shell -a 'whoami' -u wang -k -b --becomeuser=mage
SSH password: #输入远程主机wang用户ssh连接密码
10.0.0.8 | CHANGED | rc=0 >>
mage

ansible的Host-pattern
用于匹配被控制的主机的列表
All :表示所有Inventory中的所有主机

范例:

  • *:通配符
ansible "*" -m ping 
ansible 192.168.1.* -m ping
ansible "srvs" -m ping
ansible "10.0.0.6 10.0.0.7" -m ping
  • 或关系
ansible "websrvs:appsrvs" -m ping 
ansible "192.168.1.10:192.168.1.20" -m ping
  • 逻辑与
#在websrvs组并且在dbsrvs组中的主机
ansible "websrvs:&dbsrvs" -m ping
  • 逻辑非
#在所有主机,但不在websrvs组和dbsrvs组中的主机
#注意:此处为单引号
ansible 'all:!dbsrvs:!websrvs' -m ping
  • 综合逻辑
ansible 'websrvs:dbsrvs:&appsrvs:!ftpsrvs' -m ping
  • 正则表达式
ansible "~(web|db).*\.magedu\.com" -m ping

ansible 命令的执行过程

  1. 加载自己的配置文件,默认/etc/ansible/ansible.cfg
  2. 查找主机清单中对应的主机或主机组
  3. 加载自己对应的模块文件,如:command
  4. 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户
    $HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件
  5. 给文件+x执行
  6. 执行并返回结果
  7. 删除临时py文件,退出

ansible 命令的执行状态

[root@centos8 ~]#grep -A 14 '\[colors\]' /etc/ansible/ansible.cfg 
[colors]
#highlight = white
#verbose = blue
#warn = bright purple
#error = red
#debug = dark gray
#deprecate = purple
#skip = cyan
#unreachable = red
#ok = green
#changed = yellow
#diff_add = green
#diff_remove = red
#diff_lines = cyan
  • 绿色:执行成功并且对目标主机不需要做改变的操作
  • 黄色:执行成功并且对目标主机做变更
  • 红色:执行失败

1.3、ansible-console

此工具可交互执行命令,支持tab,ansible 2.0+新增

提示符格式:
执行用户@当前操作的主机组 (当前组的主机数量)[f:并发数]$

常用子命令:

  • 设置并发数: forks n 例如: forks 10
  • 切换组: cd 主机组 例如: cd web
  • 列出当前组主机列表: list
  • 列出所有的内置命令: ?或help

范例:

[root@ansible ~]#ansible-console
Welcome to the ansible console.
Type help or ? to list commands.
root@all (3)[f:5]$ ping
10.0.0.7 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
   },
       "changed": false,
    "ping": "pong"
}
10.0.0.6 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
   },
    "changed": false,
    "ping": "pong"
}
10.0.0.8 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
   },
    "changed": false,
    "ping": "pong"
}
root@all (3)[f:5]$ list
10.0.0.8
10.0.0.7
10.0.0.6
root@all (3)[f:5]$ cd websrvs
root@websrvs (2)[f:5]$ list
10.0.0.7
10.0.0.8
root@websrvs (2)[f:5]$ forks 10
root@websrvs (2)[f:10]$ cd appsrvs
root@appsrvs (2)[f:5]$ yum name=httpd state=present
root@appsrvs (2)[f:5]$ service name=httpd state=started

1.4、ansible-playbook

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

格式:
ansible-vault [create|decrypt|edit|encrypt|rekey|view]

范例:

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 #创建新文件
#执行加密的playbook,交互式输入密码
chmod 600 hello.yml
ansible-playbook  --ask-vault-pass hello.yml
#从pass.txt文件中读取密码
ansible-playbook --vault-password-file pass.txt hello.yml
#从配置文件中取得密码
#vi /etc/ansible/ansible.cfg
[defaults]
ault-password-file=pass.txt
#可以直接执行加密文件
ansible-playbook   hello.yml

1.5、ansible-galaxy

Galaxy 是一个免费网站, 类似于github网站, 网站上发布了很多的共享的roles角色。
Ansible 提供了ansible-galaxy命令行工具连接 https://galaxy.ansible.com 网站下载相应的roles, 进行
init(初始化、search( 查拘、install(安装、 remove(移除)等操作。

范例:

#搜索项目
[root@ansible ~]#ansible-galaxy search lamp
#列出所有已安装的galaxy
ansible-galaxy list
#安装galaxy,默认下载到~/.ansible/roles下
ansible-galaxy install geerlingguy.mysql
ansible-galaxy install geerlingguy.redis
#删除galaxy
ansible-galaxy remove geerlingguy.redis

二、总结ansible playbook目录结构及文件用途

image.png
  • 一个 playbook(剧本)文件是一个YAML语言编写的文本文件
  • 通常一个playbook只包括一个play
  • 一个 play的主要包括两部分: 主机和tasks. 即实现在指定一组主机上执行一个tasks定义好的任务列表。
  • 一个tasks中可以有一个或多个task任务
  • 每一个Task本质上就是调用ansible的一个module
  • 在复杂场景中,一个playbook中也可以包括多个play,实现对多组不同的主机执行不同的任务

1、Playbook 核心组件

官方文档
https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html#playbook-keywords

一个playbook 中由多个组件组成,其中所用到的常见组件类型如下:

  • Hosts 执行的远程主机列表
  • Tasks 任务集,由多个task的元素组成的列表实现,每个task是一个字典,一个完整的代码块功能需最
    少元素需包括 name 和 task,一个name只能包括一个task
  • Variables 内置变量或自定义变量在playbook中调用
  • Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
  • Handlers 和 notify 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
  • tags 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此
    会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地
    长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断

1.1、hosts 组件

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

案例:

- hosts: websrvs:appsrvs

1.2、remote_user 组件

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

- hosts: websrvs
 remote_user: root
  
 tasks:
   - name: test connection
     ping:
     remote_user: magedu
     sudo: yes #默认sudo为root
     sudo_user:wang    #sudo为wang

1.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

注意:shell和command模块后面跟命令,而非key=value

范例:

[root@ansible ansible]#cat hello.yml 
- hosts: web
  remote_user: root
  gather_facts: no
  tasks:
    - name: task1
      debug: msg="task1 running"
    - name: task2
      debug: msg="task2 running"
- hosts: app
  remote_user: root
  gather_facts: no
  tasks:
    - name: task3
      debug: msg="task3 running"
    - name: task4
      debug: msg="task4 running"

范例:

[root@ansible ansible]#cat hello.yaml
---
# first yaml file 
- hosts: web
 remote_user: root
 gather_facts: no   #不收集系统信息,提高执行效率
 tasks:
    - name: test network connection
      ping:
    - name: excute command
     command: wall "hello world!"

1.4、其它组件说明

某任务的状态在运行后为changed时,可通过"notify"通知给相应的handlers任务
还可以通过"tags"给task 打标签,可在ansible-playbook命令上使用-t指定进行调用

1.5、ShellScripts VS Playbook 案例

#SHELL脚本实现
#!/bin/bash
# 安装Apache
yum install --quiet -y httpd 
# 复制配置文件
cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf
cp/tmp/vhosts.conf /etc/httpd/conf.d/
# 启动Apache,并设置开机启动
systemctl enable --now httpd 
#Playbook实现
---
- hosts: web
 remote_user: root
 gather_facts: no
  
 tasks:
   - name: "安装Apache"
     yum: name=httpd
   - name: "复制配置文件"
     copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/
   - name: "复制配置文件"
     copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/
   - name: "启动Apache,并设置开机启动"
     service: name=httpd state=started enabled=yes

三、使用ansible playbook实现一个mysql角色

1、创建目录

[root@ansible mysql]#pwd
/data/ansible/roles/mysql

[root@ansible mysql]#mkdir -pv {files,tasks,vars}

[root@ansible mysql]#tree /data/ansible/roles/mysql/
/data/ansible/roles/mysql/
├── files
├── tasks
└── vars

2、准备mysql安装包和主配置文件

[root@ansible files]#cat /data/ansible/roles/mysql/files/my.cnf 
[mysqld]
server-id=1
log-bin
datadir=/data/mysql
socket=/data/mysql/mysql.sock

log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid

[client]
socket=/data/mysql/mysql.sock

[root@ansible files]#ls
my.cnf  mysql-8.0.23-linux-glibc2.12-x86_64.tar.xz

3、准备mysql全局参数

[root@ansible vars]#cat /data/ansible/roles/mysql/vars/main.yml 
mysql_version: 8.0.23
mysql_file: mysql-{{mysql_version}}-linux-glibc2.12-x86_64.tar.xz
mysql_root_password: 123456

4、编写tasks

#下载相关依赖包
[root@ansible tasks]#cat install.yml 
- name: install packages
  yum:
     name:
          - libaio
          - numactl-libs

#创建用户和用户组
[root@ansible tasks]#cat user.yml 
- name: create mysql user
  user: name=mysql uid=306 group=mysql shell=/sbin/nologin system=yes create_home=no home=/data/mysql
[root@ansible tasks]#cat group.yml 
- name: create mysql group
  group: name=mysql gid=306

#解压
[root@ansible tasks]#cat unarchive.yml 
- name: copy tar to remote host and file mode 
  unarchive: src={{mysql_file}} dest=/usr/local/ owner=root group=root 

#软连接,重新命名目录
[root@ansible tasks]#cat linkfile.yml 
- name: create linkfile /usr/local/mysql 
  file: src=/usr/local/mysql-{{ mysql_version }}-linux-glibc2.12-x86_64 dest=/usr/local/mysql state=link

#初始化mysql
[root@ansible tasks]#cat data.yml 
- name: data dir
  shell: /usr/local/mysql/bin/mysqld --initialize-insecure --user=mysql --datadir=/data/mysql
  tags: data

#设定mysql配置文件
[root@ansible tasks]#cat config.yml 
- name: config my.cnf
  copy: src=/data/ansible/roles/mysql/files/my.cnf  dest=/etc/my.cnf
[root@ansible tasks]#cat script.yml 
- name: service script
  shell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld

#设置全局变量
[root@ansible tasks]#cat path.yml 
- name: PATH variable
  copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh

#设置启动服务
[root@ansible tasks]#cat service.yml 
- name: enable service
  shell: chkconfig --add mysqld;/etc/init.d/mysqld start
  tags: service

#修改root登录密码
[root@ansible tasks]#cat secure.yml 
- name: change password
  shell: /usr/local/mysql/bin/mysqladmin  -uroot password {{mysql_root_password}}

5、汇总tasks

[root@ansible tasks]#cat main.yml 
- include: install.yml
- include: group.yml
- include: user.yml
- include: dir.yml
- include: unarchive.yml
- include: linkfile.yml
- include: data.yml
- include: config.yml
- include: script.yml
- include: path.yml
- include: service.yml
- include: secure.yml

6、查看文件

#准备好所有文件,如下所示
[root@ansible mysql]#tree /data/ansible/roles/mysql/
.
├── files
│   ├── my.cnf
│   └── mysql-8.0.23-linux-glibc2.12-x86_64.tar.xz
├── tasks
│   ├── config.yml
│   ├── data.yml
│   ├── group.yml
│   ├── install.yml
│   ├── linkfile.yml
│   ├── main.yml
│   ├── path.yml
│   ├── script.yml
│   ├── secure.yml
│   ├── service.yml
│   ├── unarchive.yml
│   └── user.yml
└── vars
   └── main.yml

7、准备ansible角色yml并验证

[root@ansible ansible]#cat role_mysql.yml 
---
- hosts: dbsrvs
  remote_user: root
  gather_facts: no
  roles: 
        - mysql

[root@ansible ansible]#ansible-playbook role_mysql.yml 

#验证dbsrvs
[root@Rocky8 ~]#mysql -uroot -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 8.0.23 MySQL Community Server - GPL

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> exit

可能会有安装问题:
linux安装MySQL报 error while loading shared libraries: libtinfo.so.5

MySQL 我采用的是 Linux- Generic 包安装,其中详细略过不表。一顿操作之后,终于到将 mysql 服务启动。但是到了连接服务的时候却报错了。
mysql: error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No such file or directory

解决办法:
sudo ln -s /usr/lib64/libtinfo.so.6.1 /usr/lib64/libtinfo.so.5

四、基于角色完成部署LNMP架构,并支持一键发布,回滚应用。同时基于zabbix角色批量部署zabbix。

基于角色完成部署LNMP架构,并支持一键发布,回滚应用。同时基于zabbix角色批量部署zabbix。

1、部署LNMP架构

ansible-lnmp.png

1.1、准备文件目录和全局参数

[root@ansible roles]#mkdir -pv ./{nginx,redis,php-fpm,wordpress}/{handlers,tasks,templates}

[root@ansible ansible]#cat hosts 
[dbservers]
192.168.217.131


[webservers]
192.168.217.131 

[webservers:vars]
uid=88
user=www
gid=88
group=www
version="1.20.2"
url="http://nginx.org/download/nginx-{{ version }}.tar.gz"
install_dir="/apps/nginx"
root_path=/data/wordpress
fqdn=www.zxk.org
app=wordpress-6.0-zh_CN

1.2、准备mysql角色

需要利用ansible-playbook的模块mysql_db和mysql_user,前提是部署机器安装好python3-PyMySQL包

官方文档:Database modules — Ansible Documentation

#由于之前已经部署过mysql,第二次只需建立所需wordpress的数据库,修改一下main.yml即可

#(1)创建wordpress用户和数据库,并赋予wordpress权限
[root@ansible ansible]#cat roles/mysql/tasks/createdb.yml 
- name: Create a new database with name 'wordpress'
  mysql_db:
     login_user: root
     login_password: '123456'
     name: wordpress
     state: present

[root@ansible ansible]#cat roles/mysql/tasks/db_user.yml 
- name: Create database user with password and 'wordpress' database privileges and 'WITH GRANT OPTION'
  mysql_user:
    login_user: root
    login_password: '123456'
    name: wordpress
    password: '123456'
    host: '192.168.217.%'
    priv: 'wordpress.*:ALL,GRANT'
    state: present

#(2)修改main.yml
[root@ansible ansible]#cat roles/mysql/tasks/main.yml 
- include: install.yml
- include: group.yml
- include: user.yml
- include: dir.yml
- include: unarchive.yml
- include: linkfile.yml
- include: config.yml
- include: script.yml
- include: path.yml
- include: service.yml
- include: createdb.yml
- include: db_user.yml

1.3、准备nginx角色

#(1)准备tasks的main.yml
[root@ansible ansible]#cat roles/nginx/tasks/main.yml
- name: install packages
  yum:
    name: "{{ item }}"
  loop:
    - gcc  
    - make 
    - pcre-devel 
    - openssl-devel 
    - zlib-devel 
    - perl-ExtUtils-Embed
    - python3-PyMySQL

- name: get nginx source
  unarchive:
    src: "{{ url }}"
    dest: "/usr/local/src"
    remote_src: yes

- name: compile and install 
  shell:
    cmd: "./configure --prefix={{ install_dir }} --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module &&  make && make install"
    chdir: "/usr/local/src/nginx-{{ version }}"
    creates: "{{install_dir}}/sbin/nginx"

- name: create  {{ group }}
  group: 
    name: "{{ group }}"
    gid: "{{ gid}}"

- name: create {{ user }}
  user: 
    name: "{{ user }}"
    uid: "{{ uid }}"
    group: "{{ group }}"
    system: yes

- name: copy config 
  template:  
    src: nginx.conf.j2
    dest: "{{install_dir}}/conf/nginx.conf"
  notify: 
    - restart nginx 

- name: config dir
  file:
    path: "{{install_dir}}/conf.d"
    state: directory

- name: config file mode
  file:
    path: "{{install_dir}}"
    owner: "{{ user }}"
    group: "{{ group }}"
    recurse: yes

- name: check nginx config
  shell:
    cmd: "{{install_dir}}/sbin/nginx -t"
  register: check_nginx_config 
  changed_when:
    - check_nginx_config.stdout.find('successful') 
    - false 

- name: service file
  template:
    src: nginx.service.j2
    dest: /lib/systemd/system/nginx.service

#出现问题后加的
- name: reload service
  shell:
    cmd: "systemctl daemon-reload"

- name: start nginx
  service:
    name: nginx
    state: started
    enabled: yes

#(2)准备handlers的main.yml,Handlers只会在每一个play的末尾运行一次;可被tasks中的任务调用,但不一定会执行,如果tasks中的任务没有做出实际的操作,即使被调用了也不会执行
[root@ansible ansible]#cat roles/nginx/handlers/main.yml 
- name: restart nginx
  service:
    name: nginx
    state: restarted

#(3)准备所需conf和service模板
[root@ansible ansible]#tree roles/nginx/templates/
roles/nginx/templates/
├── nginx.conf.j2
└── nginx.service.j2
[root@ansible ansible]#cat roles/nginx/templates/nginx.conf.j2 

user {{ user }}; 
worker_processes  auto;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;
    keepalive_timeout  65;
    include {{install_dir}}/conf.d/*.conf;
}

[root@ansible ansible]#cat roles/nginx/templates/nginx.service.j2 
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile={{ install_dir }}/logs/nginx.pid
ExecStartPre=/usr/bin/rm -f {{ install_dir }}/logs/nginx.pid
ExecStartPre={{ install_dir }}/sbin/nginx -t
ExecStartPost=/bin/sleep 0.1 #因为nginx启动需要时间,而systemd在nginx完成启动前就去读取pid file造成读取pid失败
ExecStart={{ install_dir }}/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
KillSignal=SIGQUIT      
TimeoutStopSec=5
KillMode=mixed
PrivateTmp=true

[Install]
WantedBy=multi-user.target

#nginx角色文件目录
[root@ansible ansible]#tree roles/nginx/
roles/nginx/
├── files
├── handlers
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
│   ├── nginx.conf.j2
│   └── nginx.service.j2
└── var

此时nginx的配置文件没有监听任何端口

部署好nginx可能出会出现一个问题
nginx.service: Failed to parse PID from file /apps/nginx/logs/nginx.pid: Invalid argument
出现的原因:因为nginx启动需要时间,而systemd在nginx完成启动前就去读取pid file造成读取pid失败
解决方法:在yml文件中执行systemctl daemon-reload

1.4、准备php-fpm角色

#(1)准备tasks的main.yml
[root@ansible ansible]#cat roles/php-fpm/tasks/main.yml 
- name: install packages
  yum:
    name: "{{ item }}"
  loop:
    - php-fpm
    - php-mysqlnd
    - php-json
    - php-xml
    - php-gd 
    - php-pecl-zip

- name: php path 
  file: 
    path: /var/lib/php/
    owner: "{{ user }}"
    group: "{{ group }}"
    recurse: yes

- name: config php.ini
  template:
    src: php.ini.j2
    dest: /etc/php.ini  
  notify: restart php-fpm

- name: config www.conf
  template: 
    src: w.conf.j2
    dest: /etc/php-fpm.d/www.conf
  notify: restart php-fpm

- name: config nginx 
  template:
    src: php-fpm.conf.j2
    dest: "{{ install_dir }}/conf.d/php-fpm.conf"
  notify: restart nginx

#为了测试php是否运行正常,wordpress部署不需要这一步
#- name: test index.php
#    template:
#    src: index.php.j2
#    dest: "{{ root_path }}/index.php"
#  notify: restart nginx

- name: modify file permission
  shell:
    cmd: "chown -R www.www {{ root_path }}"

- name: start php-fpm 
  service: 
    name: php-fpm
    state: started
    enabled: yes

#(2)准备handlers的main.yml
[root@ansible ansible]#cat roles/php-fpm/handlers/main.yml 
- name: restart php-fpm
  service:
    name: php-fpm
    state: restarted

- name: restart nginx
  service:
    name: nginx
    state: restarted

#(3)准备所需conf和service模板
[root@ansible ansible]#cat roles/php-fpm/templates/index.php.j2 
<?php
phpinfo();
?>
[root@ansible ansible]#cat roles/php-fpm/templates/php-fpm.conf.j2 
##
server {
    listen 80;
    server_name {{ fqdn }};
    root {{ root_path }};
    index index.php;
    location ~ \.php$ {
        root  {{ root_path }}  ;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;

    }
}
[root@ansible ansible]#cat roles/php-fpm/templates/php.ini.j2 
#内容太多,从其他下好了php-fpm的主机copy一份就行
[root@ansible ansible]#cat roles/php-fpm/templates/w.conf.j2 
[www]
user = {{ user }}
group = {{ group }}
listen = 127.0.0.1:9000
listen.acl_users = apache,nginx
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path]    = /var/lib/php/session
php_value[soap.wsdl_cache_dir]  = /var/lib/php/wsdlcache

#php-fpm角色文件目录
[root@ansible ansible]#tree roles/php-fpm/
roles/php-fpm/
├── files
│   └── www.conf
├── handlers
│   └── main.yml
├── tasks
│   └── main.yml
└── templates
    ├── index.php.j2
    ├── php-fpm.conf.j2
    ├── php.ini.j2
    ├── w.conf.j2
    └── www.conf.j2

1.5、准备wordpress角色

#(1)准备tasks的main.yml
[root@ansible ansible]#cat roles/wordpress/tasks/main.yml 
- name: down wordpress
  unarchive:
    src: "{{app}}.tar.gz"
    dest: /data/
    owner: "{{ user }}"
    group: "{{ group }}"

#(2)准备meta的main.yml,在文件中可以设置该role和其它role之前的关联关系
[root@ansible ansible]#cat roles/wordpress/meta/main.yml 
dependencies:
  - role: nginx
  - role: php-fpm
  - role: mysql

#(3)准备wordpress的安装包
[root@ansible ansible]#tree roles/wordpress/
roles/wordpress/
├── files
│   └── wordpress-6.0-zh_CN.tar.gz
├── handlers
├── meta
│   └── main.yml
├── tasks
│   └── main.yml
└── templates

1.5、部署wordpress并测试

#仅测试并展示部署结果,不在主机上实施
[root@ansible ansible]#ansible-playbook -C  wordpress_role.yml 
PLAY RECAP *******************************************************************************************************************
192.168.217.131            : ok=17   changed=3    unreachable=0    failed=0    skipped=5    rescued=0    ignored=0   
[root@ansible ansible]#ansible-playbook  wordpress_role.yml

做好dns解析和安装步骤,即可使用wordpress

image.png

2、基于zabbix角色批量部署zabbix

zabbix-ansible.png

2.1、部署zabbix-server

2.1.1、准备文件目录和全局参数

[root@ansible ansible]#mkdir -p roles/{server,agent2,proxy}/{files,handlers,meta,tasks,templates,vars}
[root@ansible ansible]#cat hosts 
[zbxserver]
192.168.217.133

[zbxserver:vars]
zabbixdb_password="123456"
fqdn="www.zabbixzxk.com"

[zbxagent2]
192.168.217.132

[zbxagent2:vars]
zabbix_server_ip=192.168.217.133

说明:

files:存放需要同步到异地服务器的源码文件及配置文件; 
handlers:当资源发生变化时需要进行的操作,若没有此目录可以不建或为空; 
meta:存放说明信息、说明角色依赖等信息,可留空; 
tasks:zabbix安装过程中需要进行执行的任务; 
templates:用于执行zabbix安装的模板文件,一般为脚本; 
vars:本次安装定义的变量

2.1.1、准备tasks的main.yml

#tags的作用:如果在某次运行中,我们多次运行同一个playbook,第一次运行时我们期望所有的tasks都运行,第二次运行时我们期望只运行某一个task,也可跳过某个tasks(--skip-tags=*,*,*)
[root@ansible ansible]#cat roles/server/tasks/main.yml
- name: install zabbix.repo
  shell: rpm -Uvh https://repo.zabbix.com/zabbix/5.0/rhel/8/x86_64/zabbix-release-5.0-1.el8.noarch.rpm  
  tags: repo

- name: zabbix.repo update
  shell: "sed -i 's#http://repo.zabbix.com#https://mirrors.tuna.tsinghua.edu.cn/zabbix#' /etc/yum.repos.d/zabbix.repo"

- name: clear YUM
  shell: dnf clean all

- name: install packages
  yum:
    name: "{{ item }}" 
  loop:
    - zabbix-server-mysql  
    - zabbix-web-mysql 
    - zabbix-nginx-conf 
    - zabbix-agent2 
    - python3-PyMySQL
    - mysql-server
    - zabbix-get
  tags: install

- name: restart mysql
  shell: systemctl enable --now mysqld

- name: create zabbix-server database
  mysql_db:
    login_host: "localhost"
    login_user: "root"
    name: "zabbix"
    encoding: "utf8_bin"
    state: "present"
  tags: test_pymysql 

- name: create zabbix-server user
  mysql_user:
    login_host: "localhost"
    login_user: "root"
    name: zabbix             ##用户名
    host: "%"
    password: "{{ zabbixdb_password }}" #用户密码,这里设立变量不给明文更安全
    priv: 'zabbix.*:ALL'  #将zabbix数据库的权限给出
    state: present

- name: init zabbix-server db
  mysql_db:
    login_host: "localhost"
    login_user: "root"
    name: zabbix
    state: import
    target: /usr/share/doc/zabbix-server-mysql/create.sql.gz
  ignore_errors: yes
  tags: import_db

- name: copy zabbix_server.conf template
  template:
    src: /data/ansible/roles/server/templates/zabbix_server.conf.j2
    dest: "/etc/zabbix/zabbix_server.conf"
  notify:
    - restart zabbix-server

- name: copy zabbix-ngx.conf template
  template:
    src: /data/ansible/roles/server/templates/zabbix_ngx.conf.j2
    dest: "/etc/nginx/conf.d/zabbix.conf"
  notify:
    - restart nginx

- name: copy zabbix.conf template substitute yum install
  template:
    src: /data/ansible/roles/server/templates/zabbix_php.conf.j2
    dest: "/etc/php-fpm.d/zabbix.conf"
  notify:
    - restart php-fpm

- name: start nginx server service
  service:
    name: nginx
    state: restarted
    enabled: yes

- name: start zabbix server service
  service:
    name: zabbix-server
    state: restarted
    enabled: yes

2.1.2、准备handlers的main.yml

[root@ansible ansible]#cat roles/server/handlers/main.yml
- name: restart zabbix-server
  service:
    name: zabbix-server
    state: restarted

- name: restart nginx
  service:
    name: nginx
    state: restarted

- name: restart php-fpm
  service:
    name: php-fpm
    state: restarted

2.1.2、准备zabbix-server所需conf模板

[root@ansible ansible]#cat roles/server/templates/zabbix_server.conf.j2 
LogFile=/var/log/zabbix/zabbix_server.log
LogFileSize=0
PidFile=/var/run/zabbix/zabbix_server.pid
SocketDir=/var/run/zabbix
DBName=zabbix
DBUser=zabbix
DBPassword={{ zabbixdb_password }}
#DBSocket={{ datadir }}/mysql.sock
SNMPTrapperFile=/var/log/snmptrap/snmptrap.log
Timeout=4
AlertScriptsPath=/usr/lib/zabbix/alertscripts
ExternalScripts=/usr/lib/zabbix/externalscripts
LogSlowQueries=3000
StatsAllowedIP=127.0.0.1

[root@ansible ansible]#cat roles/server/templates/zabbix_ngx.conf.j2 
server {
         listen          80;
         server_name     {{ fqdn }} ;
 
         root    /usr/share/zabbix;
  
         index   index.php;
  
         location = /favicon.ico {
                 log_not_found   off;
         }
 
         location / {
                 try_files       $uri $uri/ =404;
         }
 
         location /assets {
                 access_log      off;
                 expires         10d;
         }
 
         location ~ /\.ht {
                deny            all;
         }
 
         location ~ /(api\/|conf[^\.]|include|locale) {
                deny            all;
                return          404;
        }

         location /vendor {
                 deny            all;
                 return          404;
        }

         location ~ [^/]\.php(/|$) {
                 fastcgi_pass    unix:/run/php-fpm/zabbix.sock;
                 fastcgi_split_path_info ^(.+\.php)(/.+)$;
                 fastcgi_index   index.php;
 
                 fastcgi_param   DOCUMENT_ROOT   /usr/share/zabbix;
                 fastcgi_param   SCRIPT_FILENAME /usr/share/zabbix$fastcgi_script_name;
                 fastcgi_param   PATH_TRANSLATED /usr/share/zabbix$fastcgi_script_name;
 
                 include fastcgi_params;
                 fastcgi_param   QUERY_STRING    $query_string;
                 fastcgi_param   REQUEST_METHOD  $request_method;
                 fastcgi_param   CONTENT_TYPE    $content_type;
                 fastcgi_param   CONTENT_LENGTH  $content_length;

                 fastcgi_intercept_errors        on;
                 fastcgi_ignore_client_abort     off;
                 fastcgi_connect_timeout         60;
                 fastcgi_send_timeout            180;
                 fastcgi_read_timeout            180;
                 fastcgi_buffer_size             128k;
                 fastcgi_buffers                 4 256k;
                 fastcgi_busy_buffers_size       256k;
                 fastcgi_temp_file_write_size    256k;
        }
 }

[root@ansible ansible]#cat roles/server/templates/zabbix_php.conf.j2 
[zabbix]
user = apache
group = apache
listen = /run/php-fpm/zabbix.sock
listen.acl_users = apache,nginx
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
php_value[session.save_handler] = files
php_value[session.save_path]    = /var/lib/php/session
php_value[max_execution_time] = 300
php_value[memory_limit] = 128M
php_value[post_max_size] = 16M
php_value[upload_max_filesize] = 2M
php_value[max_input_time] = 300
php_value[max_input_vars] = 10000
php_value[date.timezone] = Asia/Shanghai

2.1.3、确定文件

[root@ansible ansible]#cat zabbix_server_role.yml 
---
- hosts: zbxserver
  remote_user: root
  gather_facts: no
  roles: 
        - server

[root@ansible ansible]#tree roles/server/
roles/server/
├── files
├── handlers
│   └── main.yml
├── meta
├── tasks
│   └── main.yml
├── templates
│   ├── zabbix_ngx.conf.j2
│   ├── zabbix_php.conf.j2
│   └── zabbix_server.conf.j2
└── vars

2.1.4、利用ansible-playbook部署zabbix-server

[root@ansible ansible]#ansible-playbook zabbix_server_role.yml

做好dns解析,可以登录zabbix web

image.png

2.2、部署zabbix-agent2

2.2.1、准备tasks的main.yml

[root@ansible ansible]#cat roles/agent2/tasks/main.yml 
- name: install zabbix.repo
  shell: rpm -Uvh https://repo.zabbix.com/zabbix/5.0/rhel/8/x86_64/zabbix-release-5.0-1.el8.noarch.rpm  
  tags: repo

- name: zabbix.repo update
  shell: "sed -i 's#http://repo.zabbix.com#https://mirrors.tuna.tsinghua.edu.cn/zabbix#' /etc/yum.repos.d/zabbix.repo"

- name: clear YUM
  shell: dnf clean all
 
- name: install the zabbix-agent2
  dnf:
    name: zabbix-agent2
    state: present
  tags: dnf

- name: copy the zabbix_agent2.conf
  template:
    src: /data/ansible/roles/agent2/templates/zabbix_agent2.conf.j2
    dest: /etc/zabbix/zabbix_agent2.conf
  tags: copy

- name: start zabbix-agent2
  service:
    name: zabbix-agent2
    state: started
    enabled: true
  tags: service

2.2.2、准备zabbix-agent2所需conf模板

[root@ansible ansible]#cat roles/agent2/templates/zabbix_agent2.conf.j2 
PidFile=/var/run/zabbix/zabbix_agent2.pid
LogFile=/var/log/zabbix/zabbix_agent2.log
LogFileSize=0
Server={{ zabbix_server_ip }}
ServerActive={{ zabbix_server_ip }}
Hostname=192.168.217.132
Include=/etc/zabbix/zabbix_agent2.d/*.conf
ControlSocket=/tmp/agent.sock

2.2.3、确定文件

[root@ansible ansible]#cat zabbix_agent2_role.yml 
---
- hosts: zbxagent2
  remote_user: root
  gather_facts: no
  roles: 
        - agent2

[root@ansible ansible]#tree roles/agent2/
roles/agent2/
├── files
├── handlers
├── meta
├── tasks
│   └── main.yml
├── templates
│   └── zabbix_agent2.conf.j2
└── vars

2.2.4、利用ansible-playbook部署zabbix-agent2

[root@ansible ansible]#ansible-playbook  zabbix_agent2_role.yml

目标主机测试

#10050端口打开即agent2运行正常
[root@Rocky8 ~]#ss -ntl
State          Recv-Q         Send-Q                 Local Address:Port                   Peer Address:Port         Process                                                    
LISTEN         0              128                                *:10050                             *:*                            
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容