自动化批量管理-Ansible
:::tip{title=“普及时刻”}
Ansible介绍
Ansible是一个同时管理多个远程主机的软件(任何可以通过SSH协议登录的机器),因此Ansible可以管理远程虚拟机、物理机,也可以是本地主机。
Ansible通过SSH协议实现管理节点、远程节点的通信。只要是能够SSH登录的主机完成的操作,都可以通Ansible自动化操作,比如批量复制、批量删除、批量修改、批量查看、批量安装、重启、更新等。
Ansible特点
Ansible的编排引擎可以出色的完成配置管理、流程控制、资源部署等多方面的操作。和其他IT自动化产品比较,Ansible无须安装客户端软件,管理简便,功能强大,便于维护。
Ansible基于Python开发,由主要的Paramiko和PyYAML两个关键模块构建。
- 安装部署简单,学习曲线平坦
- 管理主机便捷,支持多台主机并行管理
- 无须单独在被管理主机上安装客户端软件(no agents),无须占用其他端口,仅利用SSH服务工作。
- 远程执行安全,轻松对执行的内容进行审计、评估、重写
- 能够立即管理远程主机,无须事先安装任何客户端。
- 不仅支持python、还可以使用其他语言开发模块。
- 非root账户可用
- 不需要安装服务端(no servers),不需要守护进程服务
- 有活跃的官方社区
- 在云计算时代,基础架构必须满足按需自动伸缩、按使用量计费的基本特性,因此自动化运维软件是必备的工具之一。
Ansible工作原理
大致工作原理就是ansible程序调用读取/etc/ansible/ansible.cfg配置文件获取主机列表清单/etc/ansible/hosts文件,获取所要处理的主机列表,然后查看剧本任务,在根据剧本中一系列任务生成一个临时的脚本文件,然后将该脚本文件发送给所管理的主机,脚本文件在远程主机上执行完成后返回结果,然后删除本地临时文件
ansible工作模式
ansible分为两种工作模式:
一是adhoc(点对点模式):此模式相当于对管理主机执行单个的shell命令
二是playbook(剧本模式):该模式应用较多,该模式是指将一系列任务整合形成一个剧本,以此来达成某种功能(譬如部署某个服务,数据库备份等)的目的。
上述两种模式可类比于一个是执行单个shell命令,一个是shell脚本
:::
:::info{title=“小结”}
批量管理多台机器,实现自动化运维,搭配ssh免密使用
:::
命令参数介绍
:::tip{title=“参数”}
ansible的七个命令
安装完ansible后,发现ansible一共为我们提供了七个指令:ansible、ansible-doc、ansible-galaxy、ansible-lint、ansible-playbook、ansible-pull、ansible-vault 。这里我们只查看usage部分,详细部分可以通过 “指令 -h” 的方式获取。
1、ansible
ansible是指令核心部分,其主要用于执行ad-hoc命令,即单条命令。默认后面需要跟主机和选项部分,默认不指定模块时,使用的是command模块。如:ansible 192.168.0.102 -a 'date',不过默认使用的模块是可以在ansible.cfg 中进行修改的。
2、ansible-doc
该指令用于查看模块信息,常用参数有两个-l 和 -s
列出所有已安装的模块
ansible-doc -l
查看具体某模块的用法,这里如查看command模块
ansible-doc -s command
3、ansible-galaxy
ansible-galaxy 指令用于方便的从https://galaxy.ansible.com/ 站点下载第三方扩展模块,我们可以形象的理解其类似于centos下的yum、python下的pip或easy_install 。如下示例:ansible-galaxy install aeriscloud.docker
这个安装了一个aeriscloud.docker组件,前面aeriscloud是galaxy上创建该模块的用户名,后面对应的是其模块。在实际应用中也可以指定txt或yml 文件进行多个组件的下载安装。这部分可以参看官方文档(opens new window)
4、ansible-lint
ansible-lint是对playbook的语法进行检查的一个工具。用法是ansible-lint playbook.yml 。
5、ansible-playbook
该指令是使用最多的指令,其通过读取playbook 文件后,执行相应的动作,这个后面会做为一个重点来讲。
6、ansible-pull
该指令使用需要谈到ansible的另一种模式---pull 模式,这和我们平常经常用的push模式刚好相反,其适用于以下场景:你有数量巨大的机器需要配置,即使使用非常高的线程还是要花费很多时间;你要在一个没有网络连接的机器上运行Anisble,比如在启动之后安装。这部分也会单独做一节来讲。
7、ansible-vault
ansible-vault主要应用于配置文件中含有敏感信息,又不希望他能被人看到,vault可以帮你加密/解密这个配置文件,属高级用法。主要对于playbooks里比如涉及到配置密码或其他变量时,可以通过该指令加密,这样我们通过cat看到的会是一个密码串类的文件,编辑的时候需要输入事先设定的密码才能打开。这种playbook文件在执行时,需要加上 –ask-vault-pass参数,同样需要输入密码后才能正常执行。具体该部分可以参查官方博客 (opens new window)。
:::
环境准备
| ansible环境 | 主机名和ip |
| — | — |
| ansible管理端 | m01 10.0.0.61 |
| 被管理机器 | web01 10.0.0.7 |
ansible部署
主m01上安装
yum install -y ansible
安装完之后把你要管理的机器ip一行一行放这里面
这个oldboy是一个组,相当于你直接调用组里面的机器ip就可以,是不是很方便
[root@m01 ~]$ cat /etc/ansible/hosts
[oldboy]
172.16.1.7
172.16.1.31
172.16.1.41
172.16.1.51
弄好就测试一下吧
#对oldboy组执行 ping命令
[root@m01 ~]$ ansible oldboy -m ping
稍微解释下吧
olbdoy是我们上面设置的cat /etc/ansible/hosts名单里面的组,意思就是我用ansible控制这个组里的机器,同时去执行ping命令
-m 命令:这是指定模块
常用命令
ansible db -m command -a 'hostname' # 查看db组
ansible all -m command -a 'hostname' # 查看全部
ansible 172.16.1.7 -m command -a 'hostname' # 查看单机
:::tip{title=“看不懂命令就去研究下”}
通过命令: ansible-doc -s command
官网地址
https://docs.ansible.com/ansible/latest/collections/ansible/builtin/index.html#plugins-in-ansible-builtin
:::
好了上面讲完下面就要深入讲下了,觉得够用的可以走了
模块
1. Ans-命令与脚本类模
块
1.1 command模块
:::tip{title=““}
仅支持简单命令,不支持特殊符号,管道….
⚠ 这个模块是默认模块,ansible不加上模块,默认就使用这个模块.
:::
ansible all -m command -a '命令'
ansible all -a 'hostname' #相当于省略 -m command
ansible all就是,我不指定组了,我清单里面的机器都去执行我的操作
1.2 shell模块
与command模块类似,shell模块支持特殊符号,执行脚本….
ansible all -m command -a 'ip a s eth0 |sed -n 3p'
ansible all -m shell -a 'ip a s eth0 |sed -n 3p'
ansible中的颜色代表什么
:::warning{title=“ansible中的颜色代表什么”}
绿色 表示正常 \
黄色 表示执行正常,状态变化\
红色 表示错误,输出错误信息\
紫色 表示警告,建议
:::
1.3 script模块-传输脚本到被管理端并执行脚本
:::info{title=“作用”}
传输脚本\
执行脚本\
卡住需要清理下 : 被管理机器的yum缓存.
:::
安装ipvsadm
[root@m01 ~]$ cat /server/scripts/yum.sh
[root@m01 ~]$ yum install -y ipvsadm
使用script 模块执行脚本.
[root@m01 ~]$ ansible db -m script -a '/server/scripts/yum.sh'
1.4 小结
:::tip{title=“小结”}
command模块 \
作用 执行命令\
应用
简单命令,不含特殊符号. 默认的模块
ansible all -a 'hostname'
shell模块 \
作用 执行命令或脚本\
应用
执行含有特殊符号: 管道,反引号,{}的命令,运行脚本. (脚本在被管理端)
script模块 \
作用
先传输脚本,然后运行脚本\
应用
一般用于执行脚本
:::
Ans-文件与目录管理模块
:::tip{title=“提示”}
file 创建文件,目录\
copy 远程传输文件,目录.类似于scp
:::
file模块
管理文件或目录,软连接
| file模块中的选项 | |
| — | — |
| path | 路径(目录,文件) 必须要写 |
| src (source源) | 源文件一般用于link(创建软连接模式) 用于指定源文件 |
| state | 状态(模式) state=directory 创建目 state=file (默认) 更新文件,如果文件不存在也不创建. state=link 创建软连接 state=touch 创建文件 state=absent 删除 |
小测试
案例01-创建目录/oldboy/目录 ⭐⭐⭐⭐⭐
ansible all -m file -a 'path=/oldboy state=directory'
ansible all -a 'ls -ld /oldboy/'
我们应该怎么去理解这个?
file模块,就是和文件操作相关的,我们之前学习的时候,关于文件的无非是、复制、粘贴、移动、删除、创建、授权;其实ansile这个模块就是专门帮我们处理文件相关的。 你要考虑的是,我使用这个模块,移动的话,应该怎么弄?
--- state :动作,我们是要对文件做什么操作?
--- src : 源,就是你的目标,你当前执行操作这台电脑里面的内容。
--- path : 你要把你的目标文件放到哪里
案例02-创建文件/oldboy/oldboy.txt文件⭐⭐⭐⭐⭐
ansible all -m file -a 'path=/oldboy/oldboy.txt state=touch'
#给ansible清单里面的所有机器,touch----》创建。 文件创建的路径path=/oldboy/oldboy.txt
#我们创建完成之后,要去检查,找几个主机看看,是不是有这个文件
ansible all -a 'ls -l /oldboy/'
案例03-创建软连接 /oldboy/oldboy.txt到/tmp/oldboy.txt.soft ⭐
ansible all -m file -a 'src=/oldboy/oldboy.txt path=/tmp/oldboy.txt.soft state=link'
ansible all -a 'ls -l /tmp/oldboy.txt.soft'
案例04-删除文件/目录/软连接⭐⭐⭐⭐⭐
ansible all -m file -a 'path=/oldboy/oldboy.txt state=absent ' #删除文件
ansible all -m file -a 'path=/oldboy state=absent ' #删除目录
ansible all -m file -a 'path=/tmp/oldboy.txt.soft state=absent ' #删除软连
案例05-创建文件/tmp/oldboy.txt,所有者root,用户组root,权限755
ansible all -m file -a 'path=/tmp/oldboy.txt owner=root group=root mode=755 state=touch'
ansible all -a 'ls -l /tmp/oldboy.txt'
copy 远程传输模块
| copy模块 | |
| — | — |
| src | source 源文件 |
| dest | destination 目标 |
| backup | backup=yes 则会在覆盖前进行备份 |
| mode | 修改权限 |
| owner | 修改为指定所有者 |
| group | 修改为指定用户组 |
案例01-传输/etc/hosts文件到/etc/hosts ⭐⭐⭐⭐⭐
ansible all -m copy -a 'src=/etc/hosts dest=/etc/hosts'
#复制模块,和我们file模块差不多
---src :你复制的源目标,就是你要复制的文件
---dest: 你要复制到目标机器哪个位置
案例02-传输/etc/hosts文件到/etc/hosts-先备份然后修改⭐⭐⭐⭐
ansible all -m copy -a 'src=/etc/hosts dest=/etc/hosts backup=yes'
ansible all -m shell -a 'ls -l /etc/hosts*'
文件管理与传输模块小结
| 文件管理与传输模块 | 含义 |
| — | — |
| file | 创建/删除 文件/目录,软连接 |
| copy | 远程分发文件/目录,软件包,压缩包 |
Ans-服务管理模块
:::tip{title=“systemctl 命令”}
启动/关闭/重启服务 开机自启动/开机不自启动
:::
systemd⭐⭐⭐⭐⭐
| systemd模块 | |
| — | — |
| name | 用于指定服务名称 |
| enabled | 控制服务的开机自启动 enabled=yes /enabled=no |
| state | 表示服务开,关,重启… state=started 开启 state=stopped 关闭 state=reloaded 重读配置文件(服务支持) sshd,nfs state=restarted 重启(关闭再开启) |
| daemon-reload | yes是否重新加载对应的服务的管理配置文件(讲解了systemctl配置文件.) |
案例01-关闭firewalld
:::tip{title=“实现功能”}
正在运行
关闭开机自启动.
:::
我们linux关闭防火墙的命令:systemctl stop firewalld
ansible all -m systemd -a 'name=firewalld enabled=no state=stopped'
#这个systemd模块就是针对使用systemctl命令开启、关闭、重启等操作的
name:就是你服务的名称,你可以先找打这个服务的名称
enable:设置是否开机自启
state:设置服务的开、关重启
ansible all -a 'systemctl status firewalld'
#我们也可以不用那么麻烦,直接使用command模块,执行整个命令
案例02-开启sshd服务
ansible all -m systemd -a 'name=sshd enabled=yes state=started'
ansible all -a 'systemctl status sshd'
案例03-重启backup这台机器上面的rsync服务
ansible backup -m systemd -a 'name=rsyncd state=restarted'
service 了解
Ans-软件包管理模块
:::tip{title=“提示”}
yum_repository (管理yum源)\
yum (yum命令)\
get_url(wget命令)
:::
yum源配置管理模块
[root@m01 ~]$ cat /etc/yum.repos.d/epel.repo
[epel]
name=Extra Packages for Enterprise Linux 7 -$basearch
baseurl=http://mirrors.aliyun.com/epel/7/$basearch
failovermethod=priority
enabled=1
gpgcheck=0
gpgkey=file://etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
案例01-批量添加nginx-yum源
[root@m01 ~]$ cat /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
ansible web -m yum_repository -a 'name=nginx description="nginx stable repo" baseurl="http://nginx.org/packages/centos/$releasever/$basearch/" gpgcheck=no enabled=yes'
#注意未来也可以通过,copy模块实现.
yum模块 ⭐⭐⭐⭐⭐
案例01-安装lrzsz
ansible all -a 'rpm -e lrzsz '
ansible all -m yum -a 'name=lrzsz state=installed '
案例02-安装sl,cowsay,aalib
ansible web -m yum -a 'name=sl,cowsay,aalib state=installed'
get_url模块(wget) ⭐⭐⭐⭐⭐
| get_url下载功能 | |
| — | — |
| url | 指定要下载的地址 |
| dest | 下载到哪个目录 |
案例01-下载tengine源码包到/server/tools/(不存在)目录下
下载地址: https://tengine.taobao.org/download/tengine-2.3.3.tar.gz
ansible web -m file -a 'path=/server/tools/ state=directory'
ansible web -m get_url -a'url=https://tengine.taobao.org/download/tengine-2.3.3.tar.gz dest=/server/tools/'
ansible web -a 'tree /server/'
软件包管理模块小结
| 模块名字 | |
| — | — |
| yum_repository | yum源配置文件 |
| yum | 通过yum命令安装软件 |
| get_url | wget命令下载软件包/源码,下载文件 |
系统管理模块
mount模块 ⭐⭐⭐⭐⭐
案例01-挂载案例
web01把 nfs共享的目录/data目录挂载到 web01的/upload_video
步骤01_web01上面创建挂载点/upload_video
ansible web -m file -a 'path=/upload_video state=directory'
步骤02_挂载nfs
ansible web -m mount -a 'fstype=nfs src="172.16.1.31:/data" path=/upload_videostate=mounted '
ansible web -a 'df -h'
ansible web -a 'tail -2 /etc/fstab'
cron定时任务模块
案例01-添加自动同步时间的定时任务
#1. sync time lidao996
*/2 * * * * /sbin/ntpdate ntp1.aliyun.com &>/dev/null
步骤01_备份数据
ansible all -a 'cp /var/spool/cron/root /tmp/'
ansible all -a 'ls -l /tmp/root'
ansible all -a 'crontab -r'
步骤02_书写定时任务
ansible all -m cron -a 'name="sync time by lidao996 20221111" minute="*/2" job="/sbin/ntpdate ntp1.aliyun.com &>/dev/null" state=present'
用户管理模块
:::tip{title=“提示”}
group创建组模块\
user创建用户模块⭐ ⭐ ⭐ ⭐ ⭐
:::
user⭐⭐⭐⭐
案例01-创建用户lidao996
[root@m01 ~]# ansible web -m user -a 'name=lidao996'
案例02-创建虚拟用户tengine,指定uid为10086
- 命令解释器: /sbin/nologin
- 不创建家目录
useradd -u 10086 -s /sbin/nologin -M tengine
[root@m01 ~]# ansible web -m user -a 'name=tengine uid=10086 shell=/sbin/nologin create_home=no state=present'
172.16.1.7 | CHANGED ==> {
"ansible_facts": {
"discovered_interpreter_python":
"/usr/bin/python"
},
"changed": true,
"comment": "",
"create_home": false,
"group": 10086,
"home": "/home/tengine",
"name": "tengine",
"shell": "/sbin/nologin",
"state": "present",
"system": false,
"uid": 10086
}
[root@m01 ~]# ansible web -a 'id tengine'
172.16.1.7 | CHANGED | rc=0 >>
uid=10086(tengine) gid=10086(tengine)
groups=10086(tengine)
[root@m01 ]# ansible web -a 'grep tengine /etc/passwd'
172.16.1.7 | CHANGED | rc=0 >>
tengine:x:10086:10086::/home/tengine:/sbin/nologin
group模块
Ans模块实战-部署rsync服务端
:::tip{title=” 列出流程”}
部署rsync服务端需要什么模块与流程
1️⃣ yum 安装或更新
2️⃣ 配置文件 3️⃣ 虚拟用户 rsync 4️⃣ 密码文件和权限 5️⃣ 模块对应目录,改所有者 6️⃣ 重启服务
:::
根据流程找出命令(ans-模块)
切记是管理机器上操作的
| 部署rsync服务端 | 命令 |
| — | — |
| 服务部署:yum 安装或更新 | yum install -y rsync |
| 配置文件 | 先准备好配置文件,scp 传输到rsync服务器上面. |
| 虚拟用户 rsync | useradd -s /sbin/nologin -M rsync |
| 密码文件和权限 | echo 'rsync_backup:1' >/etc/rsync.password 然后 修改权限chmod 600 /etc/rsync.password |
| 模块对应目录,改所有者 | mkdir -p /data && chown rsync.rsync /data |
| 重启服务 | systemctl start rsyncd && systemctl enable rsyncd
|
根据选择的模块实现对应的功能
服务部署 yum 安装或更新
ansible backup -m yum -a 'name=rsync state=lastest'
配置文件分发
mkdir -p /server/ans/pro-rsync
准备配置文件存放在 上面目录中 rsyncd.conf
ansible backup -m copy -a 'src=/server/ans/pro-rsync/rsyncd.conf dest=/etc/rsyncd.conf backup=yes'
虚拟用户 rsync
ansible backup -m user -a 'name=rsync shell=/sbin/nologin create_home=no state=present'
密码文件和权限
创建文件
ansible backup -m file -a 'path=/etc/rsync.password mode=600 state=touch'
增加
ansible backup -m lineinfile -a 'path=/etc/rsync.password line="rsync_backup:1"'
模块对应目录,改所有者
ansible backup -m file -a 'path=/data owner=rsync group=rsync state=directory'
重启服务
ansible backup -m systemd -a 'name=rsyncd enabled=yes state=started'
命令行测试
[root@m01 /server/ans/pro-rsync]# rsync -av /etc/hostname rsync_backup@172.16.1.31:/data
Password:
sending incremental file list
hostname
sent 101 bytes received 43 bytes 57.60 bytes/sec
total size is 4 speedup is 0.03
[root@m01 /server/ans/pro-rsync]#
指定hosts文件的位置
tree /server/ans/pro-rsync/ /server/ans/pro-rsync/
├── hosts
└── rsyncd.conf
0 directories, 2 files
ansible -i hosts all -m ping
总结
:::tip{title=“提示”}
仅用于展示,未来批量管理rsyn服务或其他服务,要使用ansible playbook 剧本
这个只是用来掌握部署某个服务的流程
:::
Ansible-playbook(剧本)
:::info{title=“相关信息”}
我们作为导演,编排一出戏. 通过你设置步骤,让演员做对应动作操作. 剧本核心:指定主机,执行什么任务(模块),什么操作(选项)
:::
ansible ad-hoc vs playbook区别
playbook vs shell脚本
| 剧本与脚本 | 应用场景 |
| — | — |
| playbook剧本 | 批量管理,批量部署,批量分发… |
| shell脚本 | 某一台,服务脚本,系统巡检,定时备份… |
Playbook剧本极速使用指南
- 剧本格式叫yaml格式yml.
- 缩进,不要用tab键,空格.
:::tip{title=“提示”}
核心格式剧本中所有的内容要对齐 对齐的时候不能使用tab键. 只能使用空格,2个空格. hosts用于指定在哪些主机执行指令 tasks: 用于对于这些主机,运行什么模块及选项
:::
案例01:在所有机器的/tmp下面创建lidao.txt
--------- 执行剧本-------------
cat 01.touch.yml
- hosts: all
vars:
filename: lidao.txt
tasks:
- name: touch file
shell: touch /tmp/{{ filename }}
cp /etc/ansible/hosts .
ansible-playbook -i hosts 01.touch.yml
--------- 检查剧本-------------
tree /server/ans/playbook/
/server/ans/playbook/
├── 01.touch.yml
└── hosts
0 directories, 2 files
- hosts: all
tasks:
- name: touch file
shell: touch /tmp/lida.txt
案例02:添加定时同步时间的定时任务
原始命令行ansible命令
ansible all -m cron -a 'name="sync time by lidao996 20221111" minute="*/2" job="/sbin/ntpdate ntp1.aliyun.com &>/dev/null" state=present'
ansible -i hosts all -a 'crontab -l'
修改为剧本之后
#简单粗暴版本
---
- hosts: all
tasks:
- name: add cron sync time
cron:
name="sync time by lidao996 20221111"
minute="*/2"
job="/sbin/ntpdate ntp1.aliyun.com &>/dev/null"
state=present
#格式优化后
---
- hosts: all
tasks:
- name: add cron sync time
cron:
name: "sync time by lidao996 20221111"
minute: "*/2"
job: "/sbin/ntpdate ntp1.aliyun.com &>/dev/null"
state: present
- ==在剧本中使用模块和选项==
- ==选项最好是一行一个选项,选项后面的跟着冒号==
- ==选项要对齐与缩进==
检查
ansible -i hosts all -a 'crontab -l'
案例03-企业案例-批量下载安装zabbix-agent2-6.0客户端并启动
zabbix-agent2客户端
- 1️⃣ 下载rpm包
- 2️⃣ 安装rpm包
- 3️⃣ 启动服务zabbix-agent2
| zabbix-agent2客户端 | 命令和模块 |
| — | — |
| 下载rpm包 | wget get_url |
| 安装rpm包 | rpm/yum yum |
| 启动服务zabbix-agent2 | systemctl systemd |
模块对应命令
---
- hosts: all
tasks:
- name: 1. download zabbix agent2 rpm
get_url:
ur: https://mirrors.tuna.tsinghua.edu.cn/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent2-6.0.0-1.el7.x86_64.rpm
dest: /tmp/
validate_certs: no
- name: 2. install zabbix agent2 rpm
yum:
name: /tmp/zabbix-agent2-6.0.0-1.el7.x86_64.rpm
state: installed
- name: 3. start zabbix agent2 service
systemd:
name: zabbix-agent2
enabled: yes
state: started
案例04-部署rsync服务端(剧本)
准备:当前目录中包含,rsyncd.conf配置文件
### 1) 服务部署:yum 安装或更新
ansible backup -m yum -a 'name=rsync state=lastest'
### 2) 配置文件分发
mkdir -p /server/ans/pro-rsync
准备配置文件存放在 上面目录中 rsyncd.conf
ansible backup -m copy -a 'src=/server/ans/pro-rsync/rsyncd.conf dest=/etc/rsyncd.conf backup=yes'
### 3) 虚拟用户 rsync
ansible backup -m user -a 'name=rsync
shell=/sbin/nologin create_home=no state=present'
### 4)密码文件和权限
创建文件
ansible backup -m file -a 'path=/etc/rsync.password mode=600 state=touch'
增加
ansible backup -m lineinfile -a'path=/etc/rsync.password line="rsync_backup:1"'
### 5)模块对应目录,改所有者
ansible backup -m file -a 'path=/data owner=rsync group=rsync state=directory'
### 6) 重启服务
ansible backup -m systemd -a 'name=rsyncd enabled=yes state=started'
[root@m01 /server/ans/playbook]# ansible -i hosts backup -m ping
172.16.1.41 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
[root@m01 /server/ans/playbook]# cat 05-backup-resyncd.yml
---
- hosts: backup
tasks:
- name: 1) 服务部署:yum 安装或更新
yum:---
- hosts: backup
tasks:
- name: 1) 服务部署:yum 安装或更新
yum:
# name: rsync
# state: latest
- name: 2) 配置文件分发
copy:
src: /server/ans/playbook/rsyncd.conf
dest: /etc/rsyncd.conf
backup: yes
- name: 3) 虚拟用户 rsync
user:
name: rsync
shell: /sbin/nologin
create_home: no
state: present
- name: 4) 密码文件和权限
lineinfile:
path: /etc/rsync.password
mode: 0600
line: "rsync_backup:1"
create: yes
- name: 5) 模块对应目录,改所有者
file:
path: /data/
owner: rsync
group: rsync
state: directory
- name: 6) 重启服务
systemd:
name: rsyncd
enabled: yes
state: started
Ansible命令总结与记录
ansible-playbook命令格式
:::warning{title=“注意”}
格式:ansible-playbook -i 指定主机清单文件 [选项] yml文件
选项:\
-i :指定主机清单文件\
-C : 模拟运行剧本,看看是否有问题\
–syntax-check :仅仅检查剧本格式是否有误
:::
更深入的东西,看不懂就不用看了
案例06-部署nfs服务端全流程
Ansible-变量系列
变量
- 命令行 : 临时使用,较少用.
- 变量文件vars_files : 某一个主机使用,较少用.
- 主机组共用的变量文件 group_vars : 应用范围广泛.
- ansible内置变量(facts变量) : 收集主机的基本信息,ip地址,主机名,系统及版本….
- register变量 : 实现命令行 $() 或 `` 功能
变量详解
vars,vars_files , group_vars
剧本中定义变量 ⭐ ⭐ ⭐ ⭐ ⭐
cat 07.vars_dir.yml
---
- hosts: all
vars:
dir_name: /oldboy_lidao
file_name: lidao996.icu
tasks:
- name: 01. mkdir
file:
path: "{{ dir_name }}"
state: directory
- name: 02. touch
file:
path: "{{ dir_name }}/{{ file_name }}"
state: touch
把变量存放到一个文件中. 剧本比较大的时候
cat vars.yml
dir_name: /xiaoliu
file_name: xiaoliu.我爱你
cat 08.vars_files_dir.yml
---
- hosts: all
vars_files: ./vars.yml
tasks:
- name: 01. mkdir
file:
path: "{{ dir_name }}"
state: directory
- name: 02. touch
file:
path: "{{ dir_name }}/{{ file_name }}"
state: touch
创建一个变量文件,给某个组共用⭐ ⭐ ⭐ ⭐ ⭐
用法:需要创建一个group_vars目录
目录下面创建以主机组命名的目录
存放变量文件vars.yml
group_vars/ 目录
lb/vars.yml #存放lb组的变量
web/vars.yml #存放web组的变量
data/vars.yml #存放xxx组的变量
all/vars.yml #所有主机共用的变量
案例01-根据不同的主机组创建对应的目录.
group_vars/ 目录
web/vars.yml #存放web组的变量
data/vars.yml #存放xxx组的变量
all/vars.yml #所有主机共用的变量
web服务器创建 /app/code/目录
dir_name: /app/code/
data服务端创建 /data/目录
dir_name: /data/
#参考:
##变量文件内容
[root@m01 /server/ans/playbook]$ cat group_vars/data/vars.yml
dir_name: /datav2/
[root@m01 /server/ans/playbook]$ cat group_vars/web/vars.yml
dir_name: /app/code/ #冒号:后面一定要加空格
[root@m01 /server/ans/playbook]# tree group_vars/
group_vars/
├── data
│ └── vars.yml
└── web
└── vars.yml
3 directories, 3 files
#剧本内容
[root@m01 /server/ans/playbook]$ cat 09.vars_group_vars_dir.yml
- hosts: all
tasks:
- name: 根据主机创建不同的目录
file:
path: "{{ dir_name }}"
state: directory
group_vars未来应用场景:使用all统一存放变量
案例02-使用group_vars的all组定义变量.⭐⭐⭐⭐⭐
[root@m01 /server/ans/playbook]$ tree group_vars/
group_vars/
├── all
│ └── vars.yml
├── data
│ └── vars.yml
└── web
└── vars.yml
3 directories, 3 files
[root@m01 /server/ans/playbook]$ cat group_vars/all/vars.yml
dir_name_code: /app/code/
dir_name_data: /data/
[root@m01 /server/ans/playbook]$ cat > 09.vars_group_vars_dir.yml <<'EOF'
- hosts: all
tasks:
- name: 01 {{ dir_name_code }}
file:
path: "{{ dir_name_code }}"
state: directory
- name: 02 {{ dir_name_data }}
file:
path: "{{ dir_name_data }}"
state: directory
EOF
剧本目录,目录结构
[root@m01 /server/ans/playbook]$ tree
.
├── 01.touch.yml
├── 02.add-cron.yml
├── 03.add-cron-you.yml
├── 04.install-zabbix-agent2.yml
├── 05-backup-resyncd.yml
├── 06-nfs-server.yml
├── 07.vars_dir.yml
├── 08.vars_files_dir.yml
├── 09.vars_group_vars_dir.yml
├── group_vars
│ ├── all
│ │ └── vars.yml
│ ├── data
│ │ └── vars.yml
│ └── web
│ └── vars.yml
├── hosts
├── rsyncd.conf
└── vars.yml
4 directories, 15 files
变量基础定义小结
| 使用方法 | 含义和应用场景 |
| — | — |
| 变量写在剧本开头 | vars: 简单的较少的一种 |
| 变量写在独立文件中: | vars_files: 指定变量文件位置 了解为主 |
| 变量写在独立文件中,按照组进行分类: | group_vars/目录 all/vars.yml 掌握在all中创建所有主机/分组用的变量即可|
ansible-facts变量
facts变量说明 : ansible内置变量,执行剧本,有个默认的任务(task),收集每个主机的基本信息.
:::tip{title=“提示”}
ansible_facts是一个特殊的变量,它包含了关于目标主机的系统信息和其他有用的信息。这些信息由Ansible在执行任务时自动收集并存储在ansible_facts变量中,你可以在后续的任务中使用这些信息
:::
#查看 ansible facts变量内容
ansible -i hosts web -m setup
常用fact变量
ansible_hostname #主机名
ansible_memtotal_mb #内存大小(总计) 单位mb
ansible_processor_vcpus #cpu数量
ansible_default_ipv4.address #默认的网卡ip eth0
ansible_distribution #系统发行版本名字
CentOS Ubuntu Debian ...
ansible_processor_cores #核心总数
ansible_date_time.date #当前时间 年-月-日
案例01-系统巡检-获取所有机器的基础信息保存到/tmp/主机名命名文件中.
步骤:
01.创建文件
02.写入内容
[root@m01 /server/ans/playbook]$ cat 10.vars_sys_info.yml
---
- hosts: all
tasks:
- name: 创建文件并写入系统基本信息
lineinfile:
path: /tmp/{{ ansible_hostname }}
create: yes
line: "主机名: {{ ansible_hostname }}\n ip地址: {{ ansible_default_ipv4.address }}\n内存总计: {{ ansible_memtotal_mb }}"
:::danger{title=“facts小结”}
如果ans中使用到了一些系统的基础信息. eg: ip地址,主机名,时间.
如果没有这种需求或通过别的方式实现这个需求,可以关闭facts功能,让剧本执行加速. 使用gather_facts: no
:::
---
- hosts: all
gather_facts: no
vars:
dir_name: /oldboy_lidao
file_name: lidao996.icu
tasks:
- name: 01. mkdir
file:
path: "{{ dir_name }}"
state: directory
- name: 02. touch
file:
path: "{{ dir_name }}/{{ file_name }}"
state: touch
ansible-register变量
:::tip{title=“提示”}
register变量用于存储任务执行的结果。通过将register关键字与一个变量名结合使用,可以将任务的输出保存到该变量中,以便后续的任务可以使用
:::
创建压缩包压缩包名字包含时间. tar打包压缩,date获取时间.
tar zcf /tmp/etc-`date +%F`.tar.gz /etc/
案例01-创建以主机名命名文件/opt/主机名
步骤:
01.获取主机名:hostname
02.创建文件,使用上一步的结果
register: 变量名字 #这个变量的内容,叫json格式.
register: hostname #json格式,只想要输出标准输出 stdout
standard output 标准输出.
hostname.stdout #取出命令的结果 `hostname`
[root@m01 /server/ans/playbook]# cat 12.vars_register.yml
---
- hosts:
tasks:
- name: 01.获取主机名
shell: hostname
register: hostname
- name: 输出变量内容
debug:
msg: "{{ hostname }}"
[root@m01 /server/ans/playbook]# cat 12.vars_register.yml
---
- hosts: all
tasks:
- name: 01.获取主机名
shell: hostname
register: hostname
- name: 输出变量内容
debug:
msg: "{{ hostname.stdout }}"
- name: 02. 创建文件
file:
path: /opt/{{ hostname.stdout }}
state: touch
register变量输出结果
{
"msg": {
"changed": true,
"cmd": "hostname",
"delta": "0:00:00.008150",
"end": "2022-04-14 12:32:14.587547",
"failed": false,
"rc": 0, #命令的返回值,0表示正确,非0错误.
"start": "2022-04-14 12:32:14.579397",
"stderr": "", #错误信息
"stderr_lines": [],
"stdout": "backup02", #这个最常用. 命令的结果,输出
"stdout_lines": [
"backup02"
]
}
}
register: hostname
hostname.stdout #正常输出信息
hostname.rc #取出返回值.
hostname.stderr #取出错误信息.
变量小结
为何使用变量:
剧本,脚本使用的变量放在一个文件中,剧本开头的.
一般存放: 用户名,用户组,目录,端口……
Ansible-进阶-剧本调试方法
:::info{title=“概述”}
debug模块
tags 标签
忽略错误
:::
Debug模块
- msg : 相当于是echo 命令,配合着register一起用
案例01-调试-nfs服务端部署剧本
[root@m01 /server/ans/playbook]$ cat 13-debug-nfs-server.yml
---
- hosts: db
tasks:
- name: 01. 部署nfs服务端软件
yum:
name: nfs-utils
state: installed
- name: 02. 修改配置文件
lineinfile:
path: /etc/exports
line: "/data 172.16.1.0/24(rw)"
state: present
backup: yes
- name: 03. 创建对应的目录,权限
file:
path: /data/
owner: nfsnobody
group: nfsnobody
state: directory
register: file_jieguo
- name: 输出,显示这个过程
debug:
msg: "{{ file_jieguo }}"
- name: 04. 启动服务-rpc服务
systemd:
name: rpcbind
enabled: yes
state: started
- name: 05. 启动服务-nfs服务
systemd:
name: nfs
enabled: yes
state: started
tags标签
- 一般用于调试剧本,给剧本的每个task可以设置个标签. 运行剧本的时候可以运行指定标签. 运行剧本的时候排除某些标签.
[root@m01 /server/ans/playbook]$ cat 14-tags-nfs-server.yml
---
- hosts: db
tasks:
- name: 01. 部署nfs服务端软件
yum:
name: nfs-utils
state: installed
tags:
- install
- name: 02. 修改配置文件
lineinfile:
path: /etc/exports
line: "/data 172.16.1.0/24(rw)"
state: present
backup: yes
tags:
- conf
- conf_file
- name: 03. 创建对应的目录,权限
file:
path: /data/
owner: nfsnobody
group: nfsnobody
state: directory
tags:
- conf
- conf_dir
- name: 04. 启动服务-rpc服务
systemd:
name: rpcbind
enabled: yes
state: started
tags:
- start_srv
- name: 05. 启动服务-nfs服务
systemd:
name: nfs
enabled: yes
state: started
tags:
- start_srv
运行指定的标签
ansible-playbook -i hosts --tags conf 14-tags-nfs-server.yml
ansible-playbook -i hosts --tags conf_file,conf_dir 14-tags-nfs-server.yml
运行剧本的时候排除指定的标签
ansible-playbook -i hosts - ---skip-tags install,conf_file 14-tags-nfs-server.yml
忽略错误
:::info{title=“ignore_errors: yes”}
用于运行剧本的时候,强制让某个任务(模块)运行即使出错了,也不要中断我们的剧本
:::
[root@m01 /server/ans/playbook]$ cat 15-ignore-nfs-server.yml
---
- hosts: db
tasks:
- name: 01. 部署nfs服务端软件
yum:
name: nfs-util
state: installed
ignore_errors: yes
tags:
- install
- name: 02. 修改配置文件
lineinfile:
path: /etc/exports
line: "/data 172.16.1.0/24(rw)"
state: present
backup: yes
tags:
- conf
- conf_file
- name: 03. 创建对应的目录,权限
file:
path: /data/
owner: nfsnobody
group: nfsnobody
state: directory
tags:
- conf
- conf_dir
- name: 04. 启动服务-rpc服务
systemd:
name: rpcbind
enabled: yes
state: started
tags:
- start_srv
- name: 05. 启动服务-nfs服务
systemd:
name: nfs
enabled: yes
state: started
tags:
- start_srv
调试方法小结
| 具体方法 | 应用场景 |
| — | — |
| debug模块 | 执行剧本的时候输出剧本的执行流程,一般配合register一起使用. 输出facts变量.自定义变 |
| tags 标签 | 给一些模块加上标签,运行剧本的时候可以运行指定标签的内容,排除指定标签 |
| 忽略错误 | 运行剧本的时候忽略一些模块的错误,让剧本继续运行 |
Ansible-进阶-进阶应用
- include
- handler
- when判断
- 循环
include功能-熟悉
:::tip{title=“提示”}
include文件包含.把一个任务分成多个剧本来实现,书写个总剧本文件,通过include_tasks: 引用子剧本文件
:::
handlers ⭐⭐⭐⭐⭐
==handler 触发器(条件),满足条件后再做什么事情==
应用场景:想表示:配置文件变化,再重启服务
配置handlers之前,每次运行剧本都会重启nfs,无论配置文件是否变化
[root@m01 /server/ans/playbook]$ cat 17-handler-nfs-server.yml
---
- hosts: db
tasks:
- name: 01. 分发配置文件
copy:
src: ./exports
dest: /etc/exports
backup: yes
- name: 02. 启动服务-nfs服务
systemd:
name: nfs
enabled: yes
state: restarted
==配置了handerles,只有服务配置文件变化了再重启服务==。
---
- hosts: db
tasks:
- name: 01. 分发配置文件
copy:
src: ./exports
dest: /etc/exports
backup: yes
notify: #通知,当这个copy模块执行完,就通知指定的模块名称,这里是02. 重启 nfs
- 02. 重启 nfs
handlers:
- name: 02. 重启 nfs
systemd:
name: nfs
enabled: yes
state: restarted
when(判断)
:::tip{title=“提示”}
when是ansible中的判断语句(条件语句). 实现对于某个模块在满足或不满足xxxxx条件下再执行.
给web服务器或lb服务器,配置nginx yum源
:::
when: ( ansible_distribution "Ubuntu" ) #如果系统的发行版本是Ubuntu则 运行模块 ansible_distribution ansible facts变量
when: ( ansible_hostname is match("web|lb")) #主机名包含web或lb 配置nginx源.
when: ( ansible_hostname is not match("web|lb") )
cat nginx.repo
[nginx]
baseurl = http://nginx.org/packages/centos/$releasever/$basearch/
enabled = 1
gpgcheck = 0
name = nginx stable repo
[root@m01 /server/ans/playbook]$ cat 18-when-fenfa-nginx-yum.yml
---
- hosts: all
tasks:
- name: 配置lb或web的nginx yum源
copy:
src: ./nginx.repo
dest: /etc/yum.repos.d/nginx.repo
backup: yes
when: ( ansible_hostname is match("web|lb") )
:::tip{title=“when小结:“}
when一般与ansible facts变量一起使用,判断主机/判断系统类型
when也可以与register变量 一起搭配
:::
循环⭐⭐⭐⭐⭐
批量启动,重启服务
案例01-批量重启服务:crond,nfs,rpcbind ⭐⭐⭐⭐⭐
没学循环之前,重复写多个重启服务
- name: 04. 启动服务-rpc服务
systemd:
name: crond
enabled: yes
state: started
- name: 04. 启动服务-rpc服务
systemd:
name: rpcbind
enabled: yes
state: started
- name: 05. 启动服务-nfs服务
systemd:
name: nfs
enabled: yes
state: started
使用循环后,就不用重复写多个了
[root@m01 /server/ans/playbook]# cat 19-item-restart-service.yml
---
- hosts: nfs
gather_facts: no
tasks:
- name: restart 多个服务
systemd:
name: "{{ item }}"
state: restarted
with_items:
- crond
- rpcbind
- nfs
案例02-循环添加用户并指定uid ⭐
ansible中2个或多个变量的循环语句格式.
| 用户名 | uid |
| — | — |
| lidao | 12307 |
| oldboy996 | 12580 |
- hosts: all
gather_facts: no
tasks:
- name: 批量添加用户
user:
name: "{{ item.name }}"
uid: "{{ item.uid }}"
state: present
with_items:
- { name: "lidao", uid: "12307" }
- { name: "oldboy996", uid: "12580" }
:::tip{title=“Ans循环小结:“}
with_items: 实现循环,变量名字item 多个变量循环了解即可.
注:这里的with_items可以替换成loop.
:::
Jinja2模板
:::info{title=“相关信息”}
经常使用在配置文件中,==让配置文件中包含变量==
copy模块就没有解析变量
template模块 传输的时候解析配置文件中变量(ansible),配置文件格式改为 exports.j2
:::
root@m01 /server/ans/playbook]$ cat 21-jinja-fenfa-conf.yml
---
- hosts: nfs
tasks:
- name: 分发nfs配置文件,加主机名
template:
src: ./exports.j2
dest: /etc/exports
[root@m01 /server/ans/playbook]$ cat > exports.j2 <<'EOF'
# {{ ansible_hostname }} nfs配置文件...
/data 172.16.1.0/24(rw,all_squash)
EOF
使用jinja2模板要求: ⭐ ⭐ ⭐ ⭐ ⭐ 🅰 配置文件要以.j2结尾(ansible) 🅱 分发文件的时候,使用template模块,template用法与copy一致.
jinja2循环(了解)
批量共享目录/data /backup /nfsdata
[root@m01 /server/ans/playbook]$ cat > 21-jinja-fenfa-conf.yml <<'EOF'
---
- hosts: nfs
tasks:
- name: 分发nfs配置文件,加主机名
template:
src: ./exports.j2
dest: /etc/exports
EOF
[root@m01 /server/ans/playbook]$ cat exports.j2
# {{ ansible_hostname }} nfs配置文件...
{% for name in [ "/data","/backup","/nfsdata" ] %}
{{ name }} 172.16.1.0/24(rw,all_squash)
{% endfor %}
:::tip{title=“jinja2小结”}
核心掌握:
配置文件xxxx.j2 + template模块
jinja2配置文件支持ans变量.
:::
Roles
:::info{title=“相关信息”}
roles: 规范剧本相关的目录.本质规定的几个专用的目录
:::
剧本nfs服务端
---
- hosts: nfs
tasks:
- name: 01. 部署nfs服务端软件
yum:
name: nfs-utils
state: installed
- name: 02. 修改配置文件
template:
src: ./exports.j2
dest: /etc/exports
backup: yes
notify:
- 04.启动服务-rpcbind-nfs服务
- name: 03. 创建对应的目录,权限
file:
path: /data/
owner: nfsnobody
group: nfsnobody
state: directory
handlers:
- name: 04.启动服务-rpcbind-nfs服务
systemd:
name: "{{ item }}"
enabled: yes
state: restarted
with_items:
- rpcbind
- nfs
剧本转换为roles格式
roles结构
环境准备及部署流程
- 先书写或拆分剧本中tasks的内容.
- 根据剧本,分类存放配置文件,模板文件(j2)
- 根据剧本,配置handlers的main.yml文件
- 书写入口剧本. 与nfs-server目录同级
mkdir roles
cd roles/
mkdir -p nfs-server/{files,templates,tasks,handlers}
1.先书写或拆分剧本中tasks的内容.
1. 先书写或拆分剧本中tasks的内容.
[root@m01 /server/ans/playbook/roles]$ tree -F
.
└── nfs-server/
├── files/
├── handlers/
├── tasks/
└── templates/
5 directories, 0 files
[root@m01 /server/ans/playbook/roles]$ vim nfs-server/tasks/main.yml
[root@m01 /server/ans/playbook/roles]$ tree -F
.
└── nfs-server/
├── files/
├── handlers/
├── tasks/
│ └── main.yml
└── templates/
5 directories, 1 file
[root@m01 /server/ans/playbook/roles]# cat > nfs-server/tasks/main.yml <<'EOF'
- name: 01. 部署nfs服务端软件
yum:
name: nfs-utils
state: installed
- name: 02. 修改配置文件
template:
src: ./exports.j2
dest: /etc/exports
backup: yes
notify:
- 04.启动服务-rpcbind-nfs服务
- name: 03. 创建对应的目录,权限
file:
path: /data/
owner: nfsnobody
group: nfsnobody
state: directory
EOF
2.根据剧本,分类存放配置文件,模板文件(j2)
2. 根据剧本,分类存放配置文件,模板文件(j2)
[root@m01 /server/ans/playbook/roles]# cp ../exports.j2 nfs-server/templates/
[root@m01 /server/ans/playbook/roles]# tree -F
.
└── nfs-server/
├── files/
├── handlers/
├── tasks/
│ └── main.yml
└── templates/
└── exports.j2
5 directories, 2 files
[root@m01 /server/ans/playbook/roles]# cat > nfs-server/templates/exports.j2 <<'EOF'
# {{ ansible_hostname }} nfs配置文件
/data/ 172.16.1.0/24(rw,all_squash)
EOF
3.根据剧本,配置handlers的main.yml文件
3. 根据剧本,配置handlers的main.yml文件
[root@m01 /server/ans/playbook/roles]# tree -F
.
└── nfs-server/
├── files/
├── handlers/
│ └── main.yml
├── tasks/
│ └── main.yml
└── templates/
└── exports.j2
5 directories, 3 files
[root@m01 /server/ans/playbook/roles]# cat > nfs-server/handlers/main.yml <<'EOF'
- name: 04.启动服务-rpcbind-nfs服务
systemd:
name: '{{ item }}'
enabled: yes
state: restarted
with_items:
- rpcbind
- nfs
EOF
4.书写入口剧本. 与nfs-server目录同级
4. 书写入口剧本. 与nfs-server目录同级.
top.yml
[root@m01 /server/ans/playbook/roles]$ cat > top.yml <<'EOF'
---
- hosts: nfs
roles:
- role: nfs-server
EOF
[root@m01 /server/ans/playbook/roles]$ tree -F
.
├── nfs-server/
│ ├── files/
│ ├── handlers/
│ │ └── main.yml
│ ├── tasks/
│ │ └── main.yml
│ └── templates/
│ └── exports.j2
└── top.yml #注意top.yml与nfs-server在同一层目录。
5 directories, 4 files
[root@m01 /server/ans/playbook]$ ansible-playbook -i hosts top.yml
roles执行流程
- ansible-playbook -i hosts top.yml
- 读取top.yml内容 获取 roles 信息
- 根据顺序先执行第1个role—->nfs-server
- 执行nfs-server,找nfs-server对应的目录
- 执行里面的tasks下面的main.yml
- 执行main.yml的时候,遇到copy/template模块则找对应的目录copy(files),template(templates),找对应的文件。
- 执行main.yml的时候,遇到notify,则会找handlers下面的main.yml的内容,进行匹配与执行
Galaxy - 了解
官方roles集合.
ansible-galaxy install geerlingguy.nginx /root/.ansible/roles/
Ansible-vault 了解
加密文件
ansible-vault encrypt hosts #加密这个文件,设置密码
ansible --ask-vault-pass -i hosts all -m ping #使用ansible命令或ansible-playbook命令需要加上--ask-vault-pass
Ansible-进阶-优化
/etc/ansible/ansible.cfg
inventory = /etc/ansible/hosts #指定的默认的主机清单. 未来可以修改为 ./hosts 就可以不用加上-i
forks = 50 #并发数量. 可以增加这个数量获取更快批量管理效率.
sudo_user = root #配置下被管理端具有sudo权限的用户,并且修改/etc/sudoers 注释掉requiretty
host_key_checking = False #默认是True 连接新的主机要进行验证. 建议关闭,加速.
log_path = /var/log/ansible.log #默认没有开启.
ssh_args = -C -o ControlMaster=auto -o ControlPersist=6d #连接的保持时间. 6d 10d
pipelining = True #加速,加速连接合并不必要的连接. 要求:不能使用sudo,如果使用则不能开启.
评论区