当前位置: 首页 > news >正文

Ansible自动化运维工具 —— Playbook 剧本

playbooks 本身由以下各部分组成
(1)Tasks:任务,即通过 task 调用 ansible 的模板将多个操作组织在一个 playbook 中运行
(2)Variables:变量
(3)Templates:模板
(4)Handlers:处理器,当changed状态条件满足时,(notify)触发执行的操作
(5)Roles:角色

playbook 剧本 总结

vim  XXX.yaml- name:                      #指定play名称hosts:                     #指定主机组remote_user:               #执行用户 gather_facts: true|false   #是否收集远程主机facts信息vars:                      #定义变量tasks:                     #定义task任务列表- name:                 #定义task任务名称模块:                 #定义任务使用的模块和参数with_items:           #定义循环列表when:                 #定义判断条件(== != >= > <= <),true则执行任务,否则不执行任务ignore_errors: true   #忽略任务失败notify:               #定义task任务changed状态时触发的任务名tags:                 #指定标签,ansible-playbook --tags 仅执行拥有指定 tags 标签的任务(always标签总会执行)handlers:                  #定义notify触发的任务列表

task任务 模块语法格式

模块名: 参数选项1=值  参数选项2={{变量名}}  ...模块名:参数选项1: 值参数选项2: "{{变量名}}"...

with_items 和 变量 的语法格式

with_items: ["值1", "值2", "值3"]with_items:
- 值1
- 值2
- 值3

值为对象(键值对字段)时:

with_items:
- {key1: value1, key2: value2, ...}
- {key1: value3, key2: value4, ...}with_items:
- key1: value1key2: value2
- key1: value3key2: value4

template模板模块
1)先要准备一个 xxx.j2 模板文件,在文件中使用 {{变量名}} 引用主机变量 或者 vars 自定义的变量 及 facts 字段的值
2)在 playbook 中的 tasks 中定义 template 模板配置  template: src=xxx.j2  dest=xxx

roles 角色 的作用?【重中之重】

把playbook剧本里的各个play看作为角色,将各个角色的tasks任务、vars变量、templates模板、files文件等内容放置到角色的目录中统一管理,需要的时候可在playbook中直接使用roles调用,所以roles可以实现playbook代码的复用。

实验

架构

192.168.80.101 ansible

192.168.80.102 被控服务器

192.168.80.103 被控服务器

/etc/ansible/hosts配置如下

cat /etc/ansible/hosts

示例1 安装httpd服务

mkdir -p /etc/ansible/playbook/
cp /etc/httpd/conf/httpd.conf /etc/ansible/playbook/httpd.conf
#本机的httpd配置复制到ansible目录。可以自定义位置,在下面yaml更改对应位置即可。
vim /etc/ansible/playbook/test1.yaml---     #yaml文件以---开头,以表明这是一个yaml文件,可省略。#若文件中存在多个--- 则代表有多个yaml配置文件存在于同一个文件中
- name: the first play for install apache     #定义一个play的名称,可省略gather_facts: false    #设置不进行facts信息收集,这可以加快执行速度,可省略hosts: webservers    #指定要执行任务的被管理主机组,如多个主机组用冒号分隔remote_user: root    #指定被管理主机上执行任务的用户tasks:     #定义任务列表,任务列表中的各任务按次序逐个在hosts中指定的主机上执行- name: test connection    #自定义任务名称ping:     #使用 module: [options] 格式来定义一个任务- name: disable selinuxcommand: '/sbin/setenforce 0'    #command模块和shell模块无需使用key=value格式ignore_errors: True     #如执行命令的返回值不为0,就会报错,tasks停止,可使用ignore_errors忽略失败的任务。#这里需要忽略是因为如果selinux已经关闭再次关闭会返回1- name: disable selinux foreverreplace: path=/etc/selinux/config  regexp="enforcing"  replace="disabled"- name: disable firewalldservice: name=firewalld state=stopped enabled=no    #使用 module: options 格式来定义任务,option使用key=value格式
#======================================================================================================================
# 若想要挂载光盘使用本地yum源安装(需要在控制服务器存在/etc/yum.repos.d/repo.bak/local.repo配置文件)可以省略- name: mount cdrommount: src=/dev/sr0 path=/mnt fstype=iso9660 state=mounted- name: copy local yum configuration filecopy: src=/etc/yum.repos.d/repo.bak/local.repo  dest=/etc/yum.repos.d/local.repo
#======================================================================================================================- name: install httpdyum: name=httpd state=latest- name: prepare httpd configuration filecopy: src=/etc/ansible/playbook/httpd.conf dest=/etc/httpd/conf/httpd.conf #这里需要一个事先准备好的/opt/httpd.conf文件notify: "restart httpd" ##如以上操作后为changed的状态时,会通过notify指定的名称触发对应名称的handlers操作- name: start apache httpdservice: name=httpd state=started enabled=yeshandlers:     #handlers中定义由notify触发的任务- name: restart httpd    #notify和handlers中任务的名称必须一致。注意reload不能让httpd重新加载配置文件中端口等配置,只能restartservice: name=httpd state=restarted##Ansible在执行完某个任务之后并不会立即去执行对应的handler,而是在当前play中所有普通任务都执行完后再去执行handler
##这样的好处是可以多次触发notify,但最后只执行一次对应的handler,从而避免多次重启。


//运行playbook

ansible-playbook test1.yaml//补充参数:
-k(–ask-pass):用来交互输入ssh密码
-K(-ask-become-pass):用来交互输入sudo密码
-u:指定用户ansible-playbook test1.yaml --syntax-check    #检查yaml文件的语法是否正确
ansible-playbook test1.yaml --list-task       #检查tasks任务
ansible-playbook test1.yaml --list-hosts      #检查生效的主机
ansible-playbook test1.yaml --start-at-task='install httpd'     #指定从某个task开始运行

 

定义、引用变量

vim /etc/ansible/playbook/test2.yaml- name: second playhosts: dbserversremote_user: root#remote_user: zhangsan#become: yes #这三行代表 远程控制时 使用的普通用户zhangsan提升权限使用root用户#become_user: root #需要先修改sudo配置/etc/sudoers使zhangsan用户可以使用sudo提权vars:                 #定义变量- groupname: mysql   #格式为 key: value- username: nginx- filename: /opt/123.txtgather_facts: true #可以不写 默认开启tasks:- name: create groupgroup: name={{groupname}} system=yes gid=2800    #使用 {{key}} 引用变量的值 system为默认项可以省略不写不影>响- name: create useruser: name={{username}} uid={{uid}} group={{groupname}} #uid并未写在var中,由外部命令执行时传参- name: copy file#copy: content="{{ansible_default_ipv4}}" dest={{filename}}     #在setup模块中可以获取facts变量信息 这里获>取ipv4块所有信息copy: content="{{ansible_default_ipv4.address}}" dest={{filename}}     #在setup模块中可以获取facts变量信息 这里获取ipv4块中address一项信息- name: modify username and groupname of filefile: path={{filename}} owner={{username}}  group={{groupname}}
ansible-playbook test2.yaml -e "username=nginx2" -e "uid=1234"
#在命令行里定义变量 命令行内指定的参数优先级更高可以覆盖playbook var内写的变量

可看到命令行的传参username覆盖了playbook中定义的变量,并且uid也传参进去,其余参数都从playbook中已经定义的var变量中取 



指定远程主机sudo切换用户

在上面的脚本做修改

额外注意在 /etc/ansible/hosts 组变量中是否已经指定了 用户等参数!优先级:命令行传参>host组定义>playbook中定义变量

若host组中已经规定了用户,playbook中的用户设置,become提权等可能被覆盖不会生效!

---
- hosts: dbserversremote_user: zhangsan            become: yes                    #2.6版本以后的参数,之前是sudo,意思为切换用户运行become_user: root              #指定sudo用户为root

运行前需要先在被控制的远程主机上创建zhangsan用户,并修改sudo配置使zhangsan用户可以使用sudo提权,才能在playbook中使用become 使用root用户

adduser zhangsan
passwd zhangsanvim /etc/sudoerszhangsan ALL=ALL

执行playbook,原先命令上附加上 -k -K参数

ansible-playbook test2.yaml  -e "username=nginx3" -e "uid=1357" -k -K-k -K
-k(–ask-pass):用来交互输入ssh密码
-K(-ask-become-pass):用来交互输入sudo密码 都输入zhangsan密码即可
-u:指定用户

 

when条件判断

在Ansible中,提供的唯一一个通用的条件判断是when指令,当when指令的值为true时,则该任务执行,否则不执行该任务。

when一个比较常见的应用场景是实现跳过某个主机不执行任务或者只有满足条件的主机执行任务

vim /etc/ansible/playbook/test3.yaml---
- name: third playhosts: allremote_user: roottasks:- name: touch filefile: path=/opt/1.txt state=touch #创建文件#command: /sbin/shutdown/ -r now  #重启指令when: inventory_hostname == "192.168.80.102"#写法1 inventory_hostname为主机清单 /etc/ansible/hosts的主机名#when: ansible_default_ipv4.address != "192.168.80.103" #写法2 ansible_default_ipv4.address为gather_facts获取的主机信息    != 含义为除了103主机#when指令中的变量名不需要手动加上 {{}} 
ansible-playbook test3.yaml

迭代(循环) with_items

Ansible提供了很多种循环结构,一般都命名为with_items,作用等同于 loop 循环。

with_items普通取值  写法演示

vim /etc/ansible/playbook/test4.yaml#😊with_items普通取值
---
- name: fouth playhosts: dbserversremote_user: root
##############################################################################vars:myfile:- /opt/a- /opt/b- /opt/c- /opt/dtasks:- name: touch directory #✨方法1 预先编写var变量,随后赋值给with_itemswith_items: "{{myfile}}"file: path={{item}} state=directory #🧯模组 横向写法
##############################################################################- name: touch file 1    #✨方法2 直接在with_items中定义file:                               #🧯模组 纵向写法path: "{{item}}"state: touchwith_items:                                        #🔥with_items纵向写法- /root/a- /root/b- /root/c- /root/d- name: touch file 2file:                               #🧯模组 纵向写法path: "{{item}}"state: touchwith_items: [ /opt/aa, /opt/bb, /opt/cc, /opt/dd ] #🔥with_items横向写法

with_items——值为对象(键值对字段) 写法演示

vim /etc/ansible/playbook/test5.yaml#😊with_items——值为对象(键值对字段)
---
- name: fifth playhosts: dbserversremote_user: roottasks:- name: touch filewith_items: #✨with_items(键值对字段对象)横向写法- {filename: /opt/afile, username: xue, groupname: xue}- {filename: /opt/bfile, username: zhangsan, groupname: zhangsan}#当值为对象(键值对字段)引用值需要像item.filename指定对象中的某个字段file: path={{item.filename}}  owner={{item.username}} group={{item.groupname}} state=touch #模块 横向写法- name: create dirwith_items: #✨with_items(键值对字段对象)纵向写法- filename: /opt/cfileusername: xuegroupname: xue- filename: /opt/dfileusername: zhangsangroupname: zhangsanfile: #模块 纵向写法path: "{{item.filename}}"owner: "{{item.username}}"group: "{{item.groupname}}"state: directory

  


执行playbook test4

ansible-playbook test4.yaml


 执行playbook test5

由于playbook中指定了用户与组,需要在被控制的远程主机创建
adduser xue
adduser zhangsan

 查看用户 与 组 信息(playbook中指定的{filename: /opt/afile, username: xue, groupname: xue}一定要与系统中的用户—组对应关系相匹配!不然报错)

 

在ansible服务器运行
ansible-playbook test5.yaml

Templates 模块

Jinja是基于Python的模板引擎。Template类是Jinja的一个重要组件,可以看作是一个编译过的模板文件,用来产生目标文本,传递Python的变量给模板去替换模板中的标记。

1)先要准备一个 xxx.j2 模板文件,在文件中使用 {{变量名}} 引用主机变量 或者 vars 自定义的变量 及 facts 字段的值
2)在 playbook 中的 tasks 中定义 template 模板配置  template: src=xxx.j2  dest=xxx

1.先准备一个以 .j2 为后缀的 template 模板文件,设置引用的变量

cp /etc/httpd/conf/httpd.conf /etc/ansible/playbook/httpd.conf.j2
vim /etc/ansible/playbook/httpd.conf.j2Listen {{http_port}}                 #42行
ServerName {{server_name}}           #95行
DocumentRoot "{{root_dir}}"          #119行

2.修改主机清单文件,定义变量,用于传参给模版

vim /etc/ansible/hosts[webservers]
192.168.80.102 http_port=192.168.80.102:80 server_name=www.ws1.com:80 root_dir=/var/www/html/webserver1
192.168.80.103 http_port=192.168.80.103:80 server_name=www.ws2.com:80 root_dir=/var/www/html/webserver2

3.编写 playbook,在其中引用第一步定义的template模版。运行时host文件变量会传给playbook yaml配置文件再传参给模版。

根据不同host ip为不同的服务器生成指定的配置文件。

vim /etc/ansible/playbook/test6.yaml- name: sixth playhosts: webserversremote_user: rootvars:- pkgname: httpdtasks:- name: install apacheyum: name=httpd state=latest#创建webserver1 webserver2文件夹(此处直接在每个主机上都创建这两个文件夹,可以指定when不同ip做更细分优化)- name: create root dirfile: state=directory path={{item}}with_items:- /var/www/html/webserver1- /var/www/html/webserver2#根据不同ip生成不同页面- name: create index.html in www.ws1.comcopy: content="<h1>this is web1</h1>" dest=/var/www/html/webserver1/index.htmlwhen: ansible_default_ipv4.address == "192.168.80.102"- name: create index.html in www.ws2.comcopy: content="<h1>this is web2</h1>" dest=/var/www/html/webserver2/index.htmlwhen: inventory_hostname == "192.168.80.103"#引用template模板,生成配置后触发restart - name: prepare configuration filetemplate: src=/etc/ansible/playbook/httpd.conf.j2 dest=/etc/httpd/conf/httpd.confnotify: "restart apache" #本处可以为reload也可以为restart。虽然触发项最后才执行,会在start后reload。#但是实测可能是由于start需要时间,reload第一次运行会报错,第二次运行httpd完全启动后才正常。#所以直接使用restart,即使未启动restart也会直接执行start不报错。#后续补充:restart 似乎也需要执行两次,应该也与触发项或是启动时间有关- name: start apacheservice: name={{pkgname}} state=started enabled=yeshandlers:- name: reload apacheservice: name={{pkgname}} state=reloaded
ansible-playbook test6.yaml

 

tags 模块

可以在一个playbook中为某个或某些任务定义“标签”,在执行此playbook时通过ansible-playbook命令使用--tags选项能实现仅运行指定的tasks。
playbook还提供了一个特殊的tags为always。作用就是当使用always作为tags的task时,无论执行哪一个tags时,定义有always的tags都会执行。

vim /etc/ansible/playbook/test7.yaml- name: seventh playhosts: dbserversremote_user: roottasks:- name: create together-do.txtfile: path=/opt/together-do.txt state=touchtags:- xiaoming_do_it- xiaohong_do_it- name: create always-do.txtfile: path=/opt/always—do.txt state=touchtags:- always- name: create xiaohong-do.txtcopy: content="0721" dest=/opt/xiaohong—do.txttags:- xiaohong_do_it
ansible-playbook test7.yaml --tags="xiaoming_do_it"
#执行 tag:xiaoming与always

 

ansible-playbook test7.yaml --tags="xiaohong_do_it"
#执行 tag:xiaohong与always

Roles 模块

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

roles 角色 的作用?

把playbook剧本里的各个play看作为角色,将各个角色的tasks任务、vars变量、templates模板、files文件等内容放置到角色的目录中统一管理,需要的时候可在playbook中直接使用roles调用,所以roles可以实现playbook代码的复用。

roles 的目录结构

cd /etc/ansible/
tree roles/roles/
├── httpd/                 #相当于 playbook 中的 每一个 play 主题,目录名即为角色名
│   ├── files/                  #存放copy 模块或 script 模块调用的文件
│   ├── templates/              #存放template 模块调用的jinjia2 模板文件
│   ├── tasks/main.yml          #定义此角色的任务列表
│   ├── handlers/main.yml       #定义此角色通过notity触发条件时执行的任务列表
│   ├── vars/main.yml           #定义此角色用到的自定义变量
│   ├── defaults/main.yml       #定义此角色用到的设定默认变量(一般不用)
│   └── meta/main.yml           #定义此角色的元数据信息
└── mysql/├── files/├── templates/├── tasks/├── handlers/├── vars/├── defaults/└── meta/

●files
用来存放由 copy 模块或 script 模块调用的文件。

●templates
用来存放 jinjia2 模板,template 模块会自动在此目录中寻找 jinjia2 模板文件。

●tasks
此目录应当包含一个 main.yml 文件,用于定义此角色的任务列表,此文件可以使用 include 包含其它的位于此目录的 task 文件。

●handlers
此目录应当包含一个 main.yml 文件,用于定义此角色中触发条件时执行的动作。

●vars
此目录应当包含一个 main.yml 文件,用于定义此角色用到的变量。

●defaults
此目录应当包含一个 main.yml 文件,用于为当前角色设定默认变量。 这些变量具有所有可用变量中最低的优先级,并且可以很容易地被任何其他变量覆盖。所以生产中我们一般不在这里定义变量

●meta
此目录应当包含一个 main.yml 文件,用于定义此角色的元数据信息及其依赖关系。

在一个 playbook 中使用 roles的步骤

(1)创建以 roles 命名的目录

mkdir /etc/ansible/roles/ -p
#yum装完默认就有

(2)创建全局变量目录(可选)

mkdir /etc/ansible/group_vars/ -p
touch /etc/ansible/group_vars/all
#文件名自己定义,引用的时候注意

(3)在 roles 目录中分别创建以各角色名称命名的目录,如 httpd、mysql

mkdir /etc/ansible/roles/httpd
mkdir /etc/ansible/roles/mysql

(4)在每个角色命名的目录中分别创建files、handlers、tasks、templates、meta、defaults和vars目录,用不到的目录可以创建为空目录,也可以不创建

mkdir /etc/ansible/roles/httpd/{files,templates,tasks,handlers,vars,defaults,meta}
mkdir /etc/ansible/roles/mysql/{files,templates,tasks,handlers,vars,defaults,meta}

(5)在每个角色的 handlers、tasks、meta、defaults、vars 目录下创建 main.yml 文件,千万不能自定义文件名

touch /etc/ansible/roles/httpd/{defaults,vars,tasks,meta,handlers}/main.yml
touch /etc/ansible/roles/mysql/{defaults,vars,tasks,meta,handlers}/main.yml

(6)修改 site.yml 文件,针对不同主机去调用不同的角色

vim /etc/ansible/site.yml
---
- hosts: webserversremote_user: rootroles:- httpd
- hosts: dbserversremote_user: rootroles:- mysql

(7)运行 ansible-playbook

cd /etc/ansible
ansible-playbook site.yml

示例:安装分布式LNMP架构web服务器

创建工作目录
mkdir /etc/ansible/roles/nginx/{files,templates,tasks,handlers,vars,defaults,meta} -p
mkdir /etc/ansible/roles/mysql/{files,templates,tasks,handlers,vars,defaults,meta} -p
mkdir /etc/ansible/roles/php/{files,templates,tasks,handlers,vars,defaults,meta} -ptouch /etc/ansible/roles/nginx/{defaults,vars,tasks,meta,handlers}/main.yaml
touch /etc/ansible/roles/mysql/{defaults,vars,tasks,meta,handlers}/main.yaml
touch /etc/ansible/roles/php/{defaults,vars,tasks,meta,handlers}/main.yaml
编辑主机列表
vim /etc/ansible/hosts[webservers]
192.168.80.101[mysqlservers]
192.168.80.102[phpservers]
192.168.80.103
创建playbook,包含roles
vim /etc/ansible/playbook/lnmp.yaml- name: nginx playhosts: webserversremote_user: rootroles:- nginx- name: php playhosts: phpserversremote_user: rootroles:- php- name: mysql playhosts: mysqlserversremote_user: rootroles:- mysql

 

role:nginx

vars (变量)

vim /etc/ansible/roles/nginx/vars/main.yamlhttp_port: 192.168.80.101:80
http_hostname: www.xue.com
root_dir: /usr/share/nginx/html
php_remote: 192.168.80.103:9000
pkg: nginx
service: nginx

tasks (任务)

vim /etc/ansible/roles/nginx/tasks/init.yaml- name: disable firewalldservice: name=firewalld  state=stopped  enabled=no- name: disable selinuxshell: "/usr/sbin/setenforce 0"ignore_errors: true
vim /etc/ansible/roles/nginx/tasks/main.yaml- include: "init.yaml"- name: copy nginx yum repo filecopy: src=nginx.repo  dest=/etc/yum.repos.d/- name: install nginxyum: name={{pkg}}  state=latest- name: copy index.phpunarchive: src=/etc/ansible/roles/nginx/files/wordpress-4.9.4-zh_CN.tar.gz dest={{root_dir}} copy=yes- name: copy nginx template configuration filetemplate: src=default.conf.j2  dest=/etc/nginx/conf.d/default.confnotify: reload nginx- name: start nginxservice: name={{service}} state=started enabled=yes

handles (task中触发器)

vim /etc/ansible/roles/nginx/handlers/main.yaml- name: reload nginxservice: name={{service}}  state=reloaded

files (文件)

vim /etc/ansible/roles/nginx/files/nginx.reponginx.repo 用于yum下载nginx。
也可以不使用这个方法用不着准备这个文件,直接yum install epel 更新epel源[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
准备 WordPress论坛安装包 
(不一定要藏这么深的文件夹,只要脚本中对应上路径即可。为了显示file文件夹的作用,就放在这里)/etc/ansible/roles/nginx/files/wordpress-4.9.4-zh_CN.tar.gz

templates(模版 用于给nginx服务器生成配置)

vim /etc/ansible/roles/nginx/templates/default.conf.j2server {listen       {{http_port}};server_name  {{http_hostname}};#access_log  /var/log/nginx/host.access.log  main;location / {root   {{root_dir}};index  index.php index.html index.htm;}#error_page  404              /404.html;# redirect server error pages to the static page /50x.html#error_page   500 502 503 504  /50x.html;location = /50x.html {root   /usr/share/nginx/html;}# proxy the PHP scripts to Apache listening on 127.0.0.1:80##location ~ \.php$ {#    proxy_pass   http://127.0.0.1;#}# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000#location ~ \.php$ {root           {{root_dir}};fastcgi_pass   {{php_remote}};fastcgi_index  index.php;fastcgi_param  SCRIPT_FILENAME  {{root_dir}}$fastcgi_script_name;include        fastcgi_params;}# deny access to .htaccess files, if Apache's document root# concurs with nginx's one##location ~ /\.ht {#    deny  all;#}
}
role:mysql

 vars (变量)

vim /etc/ansible/roles/mysql/vars/main.yamlhttp_port: 192.168.80.101:80
http_hostname: www.xue.com
root_dir: /usr/share/nginx/html
php_remote: 192.168.80.103:9000
pkg: nginx
service: nginx

tasks (任务)

vim /etc/ansible/roles/mysql/tasks/init.yaml- name: disable firewalldservice: name=firewalld  state=stopped  enabled=no- name: disable selinuxshell: "/usr/sbin/setenforce 0"ignore_errors: true
vim /etc/ansible/roles/mysql/tasks/main.yaml- name: yum uninstall mariadb*yum: name=mariadb* state=absent- name: wget mysqlshell: wget -i -c http://repo.mysql.com/mysql57-community-release-el7-11.noarch.rpm -P /etc/yum.repos.d- name: rpm mysql57-community-releaseshell: rpm -ivh /etc/yum.repos.d/mysql57-community-release-el7-11.noarch.rpmignore_errors: True- name: turn off yum gpgcheckreplace: path=/etc/yum.repos.d/mysql-community.repo regexp='gpgcheck=1' replace='gpgcheck=0'- name: yum install mysqlyum: name=mysql-server- name: start and enable mysqlservice: enabled=true name=mysqld.service state=started- name: get passwd from logshell: grep "password" /var/log/mysqld.log | awk 'NR==1{print $NF}'register: mysql_password   #将获取的密码导入到mysql_password的变量中
- name: echo passwddebug:    msg: "{{ mysql_password }}"           #输出变量mysql_password的值
#grep "password" /var/log/mysqld.log     #在日志文件中找出root用户的初始密码
#2021-07-31T07:55:00.366359Z 1 [Note] A temporary password is generated for root@localhost: ga7%<d<0*jD&
#grep "password" /var/log/mysqld.log | awk '{print $NF}'#临时密码修改
- name: grant locationshell:  mysql --connect-expired-password -uroot -p"{{ mysql_password['stdout'] }}" -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'Admin@123';"ignore_errors: True
#授予root用户所有权限 
- name: grant optionshell: mysql --connect-expired-password -uroot -pAdmin@123 -e "grant all privileges on *.* to 'root'@'%' identified by 'Admin@123456' with grant option;"ignore_errors: True
#创建wordpress数据库
- name: create databaseshell: mysql --connect-expired-password -uroot -pAdmin@123 -e "create database wordpress;"ignore_errors: True
#赋予mywordpress用户访问wordpress的权限(本地权限与远程权限)
- name: grantshell: mysql --connect-expired-password -uroot -pAdmin@123 -e "grant all on wordpress.* to 'admin'@'%' identified by 'mywordpress@123456';"ignore_errors: True
- name: grantshell: mysql --connect-expired-password -uroot -pAdmin@123 -e "grant all on wordpress.* to 'admin'@'localhost' identified by 'mywordpress@123456';"ignore_errors: True
#刷新权限
- name: flush privilegesshell: mysql --connect-expired-password -uroot -pAdmin@123 -e 'flush privileges;'ignore_errors: True- name: yum uninstall mariadb*yum: name=mysql57-community-release-el7-11.noarch.rpm state=absent#为了防止每次yum操作都会自动更新,卸载这个软件

role:php

vars (变量)

vim /etc/ansible/roles/php/vars/main.yamltimezone: Asia/Shanghai
user_name: php
http_port: 192.168.80.103:9000
nginx_addr: 192.168.80.101
root_dir: /usr/share/nginx/html
service: php-fpm

tasks (任务)

vim /etc/ansible/roles/php/tasks/init.yaml- name: disable firewalldservice: name=firewalld  state=stopped  enabled=no- name: disable selinuxshell: "/usr/sbin/setenforce 0"ignore_errors: true
vim /etc/ansible/roles/php/tasks/main.yaml- include: "init.yaml"- name: install yum reposhell: "rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm && rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm"ignore_errors: True- name: install phpwith_items:- php72w- php72w-cli- php72w-common- php72w-devel- php72w-embedded- php72w-gd- php72w-mbstring- php72w-pdo- php72w-xml- php72w-fpm- php72w-mysqlnd- php72w-opcacheyum: name={{item}}- name: create php useruser: name={{user_name}}- name: crate web root dirfile: name={{root_dir}} state=directory- name: copy index.phpunarchive: src=/etc/ansible/roles/nginx/files/wordpress-4.9.4-zh_CN.tar.gz dest={{root_dir}} copy=yes- name: modify php configuration filereplace: path=/etc/php.ini  regexp=";date.timezone ="  replace="date.timezone = Asia/Shanghai"notify: reload php- name: modify username and groupname in www.confreplace: path=/etc/php-fpm.d/www.conf  regexp="apache"  replace="{{user_name}}"notify: reload php- name: modify listen addr in www.confreplace: path=/etc/php-fpm.d/www.conf  regexp="127.0.0.1:9000"  replace="{{http_port}}"notify: reload php- name: modify allowed client in www.confreplace: path=/etc/php-fpm.d/www.conf  regexp="127.0.0.1"  replace="{{nginx_addr}}"notify: reload php- name: start phpservice: name={{service}} state=started enabled=yes

handles (task中触发器)

vim /etc/ansible/roles/php/handlers/main.yaml- name: reload phpservice: name={{service}} state=reloaded

配置密钥对验证 免交互登录

ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsayum install -y sshpass
sshpass -p '密码' ssh-copy-id -o StrictHostKeyChecking=no root@192.168.80.102
sshpass -p '密码' ssh-copy-id -o StrictHostKeyChecking=no root@192.168.80.102
sshpass -p '密码' ssh-copy-id -o StrictHostKeyChecking=no root@192.168.80.103

执行 

ansible-playbook /etc/ansible/playbook/lnmp.yaml

 访问http://192.168.80.101/wordpress/index.php

故障处理

出现这种情况,由于是分布式部署lnmp,与单机不同,分布式部署必须在php服务器和nginx服务器上都存在相同的html目录以及其中的内容。

本次只在NGINX的html存放了WordPress论坛文件,而没有创建php服务器的文件夹,导致出错


 

相关文章:

Ansible自动化运维工具 —— Playbook 剧本

playbooks 本身由以下各部分组成 &#xff08;1&#xff09;Tasks&#xff1a;任务&#xff0c;即通过 task 调用 ansible 的模板将多个操作组织在一个 playbook 中运行 &#xff08;2&#xff09;Variables&#xff1a;变量 &#xff08;3&#xff09;Templates&#xff1a;模…...

第二章:多态

系列文章目录 文章目录 系列文章目录前言多态的概念概念 多态的定义及实现多态的构成条件虚函数虚函数的重写C11 override 和 final重载、覆盖(重写)、隐藏(重定义)的对比 抽象类概念接口继承和实现继承 多态的原理虚函数表多态的原理动态绑定与静态绑定 单继承和多继承关系的虚…...

C++面向对象设计基础

一般类、&、const、模板、友元函数、操作符重载基本用法及实现 complex.h #ifndef COMPLEX_H #define COMPLEX_H #include<ostream> using namespace std;template<typename T> class Complex{public:Complex():re(0),img(0){}// 为什么构造函数不能传引用&a…...

Linux定时运行sh脚本,如果sh文件已经在运行,则忽略本次运行

需求来源 我需要linux的crontab定期每10分钟运行lan.sh脚本。但由于lan.sh运行需要较长时间&#xff0c;有时超过10分钟。这样会导致系统多次运行lan.sh脚本&#xff0c;引发运行堆积&#xff0c;导致一些非必要的错误。 解决方法 解决方法是写一个脚本&#xff0c;如果lan.…...

SpringBoot项目中的web安全防护

最近这个月公司对项目进行了几次安全性扫描&#xff0c;然后扫描出来了一些安全漏洞&#xff0c;所以最近也一直在修复各种安全漏洞&#xff0c;还有就是最近在备考软考高级系统架构设计师&#xff0c;也刚好复习到了网络安全这一个章节&#xff0c;顺便将最近修复的安全漏洞总…...

stm32和python串口数据收发

1-1 串口发送端&#xff08;stm32&#xff09; 1字符串发送 void USART_SendData(USART_TypeDef* USARTx, uint16_t Data) {/* Check the parameters */assert_param(IS_USART_ALL_PERIPH(USARTx));assert_param(IS_USART_DATA(Data)); /* Transmit Data */USARTx->DR (D…...

无涯教程-jQuery - Dropable移动函数

Drop-able 功能可与JqueryUI中的交互一起使用。此功能可在任何DOM元素上启用可放置功能。 Drop able - 语法 $( "#droppable" ).droppable(); Drop able - 示例 以下是一个简单的示例&#xff0c;显示了drop-able的用法- <html><head><title>…...

【Python】Web学习笔记_flask(4)——钩子函数

钩子函数可以用来注册在请求处理的不同阶段执行出 Flask的请求钩子指的是在执行视图函数前后执行的一些函数&#xff0c; 之前是有4种&#xff0c;但是 before_first_request已经被删除了&#xff0c;使用时会报错 before_request&#xff1a;在每次请求前执行&#xff0c;…...

JavaScript 原型链解析,宏任务和微任务

目录 什么是原型链&#xff1f; 原型与构造函数 原型链的工作原理 实例&#xff1a;理解原型链 宏任务&#xff08;Macro Task&#xff09; 微任务&#xff08;Micro Task&#xff09; 什么是原型链&#xff1f; JavaScript 是一门基于原型的语言&#xff0c;而原型链是…...

05|Oracle学习(UNIQUE约束)

1. UNIQUE约束介绍 也叫&#xff1a;唯一键约束&#xff0c;用于限定数据表中字段值的唯一性。 1.1 UNIQUE和primary key区别&#xff1a; 主键/联合主键每张表中只有一个。UNIQUE约束可以在一张表中&#xff0c;多个字段中存在。例如&#xff1a;学生的电话、身份证号都是…...

glide加载content://com.android.contacts图片源码粗略梳理

获取链路是这样的&#xff1b; UriLoader类里定义了协议头&#xff1a; 里面有个内部类StreamFactory&#xff1a; 通过StreamLocalUriFetcher类的loadResource方法获取InputStream然后把流转换成为图片&#xff1b; 在这里作个草稿笔记给自己看...

【机器学习】Feature Engineering and Polynomial Regression

Feature Engineering and Polynomial Regression 1. 多项式特征2. 选择特征3. 缩放特征4. 复杂函数附录 首先&#xff0c;导入所需的库&#xff1a; import numpy as np import matplotlib.pyplot as plt from lab_utils_multi import zscore_normalize_features, run_gradien…...

Rust- 变量绑定

In Rust, you bind values to a variable name using the let keyword. This is often referred to as “variable binding” because it’s like binding a name to a value. Here’s a simple example: let x 5;In this example, x is bound to the value 5. By default, …...

向“数”而“深”,联想凌拓的“破局求变”底气何来?

前言&#xff1a;要赢得更多机遇&#xff0c;“破局求变”尤为重要。 【全球存储观察 &#xff5c; 热点关注】2019年2月25日&#xff0c;承袭联想集团与NetApp的“双基因”&#xff0c;联想凌拓正式成立。历经四年多的发展&#xff0c;联想凌拓已成为中国企业级数据管理领域的…...

pytorch实战-图像分类(二)(模型训练及验证)(基于迁移学习(理解+代码))

目录 1.迁移学习概念 2.数据预处理 3.训练模型&#xff08;基于迁移学习&#xff09; 3.1选择网络&#xff0c;这里用resnet 3.2如果用GPU训练&#xff0c;需要加入以下代码 3.3卷积层冻结模块 3.4加载resnet152模 3.5解释initialize_model函数 3.6迁移学习网络搭建 3.…...

b 树和 b+树的理解

项目场景&#xff1a; 图灵奖获得者&#xff08;Niklaus Wirth &#xff09;说过&#xff1a; 程序 数据结构 算法&#xff0c; 也就说我们无时无刻 都在和数据结构打交道。 只是作为 Java 开发&#xff0c;由于技术体系的成熟度较高&#xff0c;使得大部分人认为&#xff1…...

正则表达式 —— Awk

Awk awk&#xff1a;文本三剑客之一&#xff0c;是功能最强大的文本工具 awk也是按行来进行操作&#xff0c;对行操作完之后&#xff0c;可以根据指定命令来对行取列 awk的分隔符&#xff0c;默认分隔符是空格或tab键&#xff0c;多个空格会压缩成一个 awk的用法 awk的格式…...

国芯新作 | 四核Cortex-A53@1.4GHz,仅168元起?含税?哇!!!

创龙科技SOM-TLT507是一款基于全志科技T507-H处理器设计的4核ARM Cortex-A53全国产工业核心板&#xff0c;主频高达1.416GHz。核心板CPU、ROM、RAM、电源、晶振等所有元器件均采用国产工业级方案&#xff0c;国产化率100%。 核心板通过邮票孔连接方式引出MIPI CSI、HDMI OUT、…...

【MyBatis】 框架原理

目录 10.3【MyBatis】 框架原理 10.3.1 【MyBatis】 整体架构 10.3.2 【MyBatis】 运行原理 10.4 【MyBatis】 核心组件的生命周期 10.4.1 SqlSessionFactoryBuilder 10.4.2 SqlSessionFactory 10.4.3 SqlSession 10.4.4 Mapper Instances 与 Hibernate 框架相比&#…...

三、线性工作流

再生产的各个环节&#xff0c;正确使用gamma编码及gamma解码&#xff0c;使得最终得到的颜色数据与最初输入的物理数据一致。如果使用gamma空间的贴图&#xff0c;在传给着色器前需要从gamma空间转到线性空间。 如果不在线性空间下进行渲染&#xff0c;会产生的问题&#xff1a…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...