一、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 命令的执行过程
- 加载自己的配置文件,默认/etc/ansible/ansible.cfg
- 查找主机清单中对应的主机或主机组
- 加载自己对应的模块文件,如:command
- 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户
$HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件 - 给文件+x执行
- 执行并返回结果
- 删除临时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目录结构及文件用途
- 一个 playbook(剧本)文件是一个YAML语言编写的文本文件
- 通常一个playbook只包括一个play
- 一个 play的主要包括两部分: 主机和tasks. 即实现在指定一组主机上执行一个tasks定义好的任务列表。
- 一个tasks中可以有一个或多个task任务
- 每一个Task本质上就是调用ansible的一个module
- 在复杂场景中,一个playbook中也可以包括多个play,实现对多组不同的主机执行不同的任务
1、Playbook 核心组件
一个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架构
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
2、基于zabbix角色批量部署zabbix
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
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 *:*