一、playbook的组成
1.Tsaks任务 :每一个tasks就是一个模块
2.variabes变量: 存储和传递数据,自定义变量,也可以全局变量,也可以是脚本外传参
3.Tenplates模块 :用于生成配置文件和多任务的编排
4.handlers处理器:用于满足某些条件时触发的操作,一般用于重启等操作
5.roles角色:把每个任务做为一个角色,组织和封装剧本的过程,可以把任务、变量、模板、处理器组合成一个可用的单元。
二、yaml语法
1.在目标主机安装httpd,并且修改其访问页面
2. 安装nginx目标主机
3.定义变量
只在create user开始运行
切换用户:decome先用普通用户执行,但是需要切换到其它用户,列如切换到管理员
4.with_item:每一个值遍历一遍
with_list:整个表做为一个整体进行输出
with_together:一 一配对,少的用null替代
with_nested:组合型遍历
file:创建目录的两种方式
二、 tags模块:可以给任务定义标签,可以根据标签来运行
标签的类型:
always:设定了标签名为always,除非指定跳过这个标签,否则该任务将始终会运行,即使指定了标签还会运行
never:始终不运行的任务,指定标签名的时候never可以运行
debug:用于调试
setup:收集主机的信息
标签名也可以自定义:tags
指定标签运行
跳过always标签运行
运行指定的几个标签用逗号隔开
自定义标签:
templates模板:对应用的配置文件进行初始化,templates模块,Jinja组件,把编译过的模板文件传送给目标文件
定义变量
默认工作目录
在主机定义 远程主机的变量值
roles模块:ansible为了层次化,结构化的组织palynook,使用roles角色通过层次化自动装载变量、任务和处理等等。也就是roles把变量、任务和模块的文件单独放置在各个不同的文件中,通过roles一键编排
就是把原来写在一个yaml的配置分开到不同目录,不同目录保存到一个名字的yaml里面,执行时调用不同目录的同一个yaml文件,这个文件名字只能叫main.yaml
Ansible 的脚本 --- playbook 剧本
playbooks 本身由以下各部分组成 Tasks(任务): 包含要在目标主机上执行的操作,使用模块定义这些操作。 每个任务都是一个模块调用,可以是系统命令、包管理器操作、文件操作等。
Variables(变量): 用于存储和传递数据。在 Playbooks 中,您可以定义变量, 这些变量可以是全局的、主机特定的或任务特定的。
Templates(模板): 用于生成配置文件等。模板是包含占位符的文件, 这些占位符在执行时由 Ansible 替换为实际的变量值。
Handlers(处理器): 用于在任务中某些条件满足时触发的操作。 通常用于在任务中发生 "changed" 状态时执行重启服务等操作。
Roles(角色): 是一种组织和封装 Playbooks 的方式。 Roles 允许将相关的任务、变量、模板和处理器组织成一个可重用的单元,使 Playbooks 更清晰和模块化。
//示例: vim test1.yaml --- #yaml文件以---开头,以表明这是一个yaml文件,可省略
-
name: first play #定义一个play的名称,可省略 gather_facts: false #设置不进行facts信息收集,这可以加快执行速度,可省略 hosts: webservers #指定要执行任务的被管理主机组,如多个主机组用冒号分隔 remote_user: root #指定被管理主机上执行任务的用户 tasks: #定义任务列表,任务列表中的各任务按次序逐个在hosts中指定的主机上执行
-
name: test connection #自定义任务名称 ping: #使用 module: [options] 格式来定义一个任务
-
name: disable selinux command: '/sbin/setenforce 0' #command模块和shell模块无需使用key=value格式 ignore_errors: True #如执行命令的返回值不为0,就会报错,tasks停止,可使用ignore_errors忽略失败的任务
-
name: disable firewalld service: name=firewalld state=stopped #使用 module: options 格式来定义任务,option使用key=value格式
-
name: install httpd yum: name=httpd state=latest
-
name: install configuration file for httpd copy: src=/opt/httpd.conf dest=/etc/httpd/conf/httpd.conf #这里需要一个事先准备好的/opt/httpd.conf文件 notify: "restart httpd" #如以上操作后为changed的状态时,会通过notify指定的名称触发对应名称的handlers操作
-
name: start httpd service service: enabled=true name=httpd state=started handlers: #handlers中定义的就是任务,此处handlers中的任务使用的是service模块
-
name: restart httpd #notify和handlers中任务的名称必须一致 service: name=httpd state=restarted ##Ansible在执行完某个任务之后并不会立即去执行对应的handler,而是在当前play中所有普通任务都执行完后再去执行handler, 这样的好处是可以多次触发notify,但最后只执行一次对应的handler,从而避免多次重启。
-
-
name: first play gather_facts: false hosts: webservers remote_user: root tasks:
-
name: test connection ping:
-
name: disable selinux command: '/sbin/setenforce 0' ignore_errors: True
-
name: disable firewalld service: name=firewalld state=stopped
-
name: install httpd yum: name=httpd state=latest
-
name: start httpd service service: enabled=true name=httpd state=started
-
name: editon index.html shell: echo "this is httpd" > /var/www/html/index.html notify: restart httpd handlers:
-
name: restart httpd service: name=httpd state=restarted
-
//运行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开始运行
//定义、引用变量
-
name: second play hosts: dbservers remote_user: root vars: groupname: mysql username: nginx tasks:
-
name: create group group: name: "{{ groupname }}" system: yes gid: 306
-
name: create user user: name: "{{ username }}" uid: 306 group: "{{ groupname }}" shell: /sbin/nologin
-
name: copy file copy: content: "{{ hostvarsinventory_hostname['address'] }}" dest: /opt/vars.txt
-
hostvars: 这是一个包含所有主机变量的字典。
inventory_hostname: 这是当前主机的名字。
'ansible_default_ipv4': 这是一个嵌套的索引, 用于获取当前主机的 ansible_default_ipv4 字典中的 address 键的值,即 IPv4 地址。
表示获取当前主机的 IPv4 地址。复制到/opt/vars.txt
ansible-playbook test2.yml -u root -e 'username=nginx groupname=mysql' -k #在命令行里定义变量,类型shell的位置变量传参
//指定远程主机sudo切换用户
-
hosts: dbservers remote_user: zhangsan become: yes #2.6版本以后的参数,之前是sudo,意思为切换用户运行 become_user: root #指定sudo用户为root
执行playbook时:ansible-playbook test2.yml -e 'username=nginx groupname=mysql' -K 需要在配置文件中:/etc/ansible/hosts 192.168.233.30 ansible_user=root ansible_password=123
//when条件判断 在Ansible中,提供的唯一一个通用的条件判断是when指令,当when指令的值为true时, 则该任务执行,否则不执行该任务。
//when一个比较常见的应用场景是实现跳过某个主机不执行任务或者只有满足条件的主机执行任务 vim test3.yaml
-
name: this is when test playbook hosts: all remote_user: root tasks:
-
name: test when debug: msg='判断位置' #满足条件的测试输出 when: ansible_default_ipv4.address == "192.168.233.20" when: ansible_default_ipv4.address != "192.168.233.20" #取反
-
-
hosts: all remote_user: root tasks:
-
name: shutdown host command: /sbin/shutdown -r now when: ansible_default_ipv4.address == "192.168.233.20" #when指令中的变量名不需要手动加上 {{}} 或 when: inventory_hostname == "<主机名>"
-
ansible-playbook test3.yaml
//迭代 Ansible提供了很多种循环结构,一般都命名为with_items,作用等同于 loop 循环。
with_item 单循环输出
-
name: item test hosts: dbservers remote_user: root gather_facts: no tasks:
-
debug: msg: "{{item}}" with_items: [a, b, c, d]
-
-
name: item test hosts: dbservers remote_user: root gather_facts: no tasks:
-
debug: msg: "{{item}}" with_items:
-
[a, b, c, d]
-
[1, 2, 3, 4] #with_item会把所有列表当成一个整体,实际上就是输出一个列表中的所有数据。
-
with_list:每组列表一起循环的输出
-
name: item test hosts: dbservers remote_user: root gather_facts: no tasks:
-
debug: msg: "{{item}}" with_list:
-
[a, b, c, d]
-
[1 ,2, 3, 4]
-
-
with_together 同一列表位置数据组合输出的循环
-
name: item test hosts: dbservers remote_user: root gather_facts: no tasks:
-
debug: msg: "{{item}}" with_together:
-
[a, b, c, d]
-
[1 ,2, 3, 4]
-
-
-
name: item test hosts: dbservers remote_user: root gather_facts: no tasks:
-
debug: msg: "{{item}}" with_together:
-
[a, b, c, d]
-
[1 ,2, 3, 4]
-
[A, B, C]
-
-
with_nested 列表数据循环匹配的循环(根据列表个数定义有多少层的循环)
-
name: item test hosts: dbservers remote_user: root gather_facts: no tasks:
-
debug: msg: "{{item}}" with_nested:
-
[a, b, c, d]
-
[1 ,2, 3, 4]
-
-
#实操:
vim test3.yaml
-
name: play1 hosts: dbservers gather_facts: false tasks:
-
name: create file file: path: "{{item}}" state: touch with_items: [ /opt/a, /opt/b, /opt/c, /opt/d ]
-
-
name: play2 hosts: dbservers gather_facts: false vars: test:
-
/opt/test1
-
/opt/test2
-
/opt/test3
-
/opt/test4 tasks:
-
name: create directories file: path: "{{item}}" state: directory with_items: "{{test}}"
-
-
name: play3 hosts: dbservers gather_facts: false tasks:
-
name: add users user: name={{item.name}} state=present groups={{item.groups}} with_items:
-
name: test1 groups: dn
-
name: test2 groups: root 或
-
-
-
name: play3 hosts: 192.168.233.20 gather_facts: false tasks:
-
name: create groups group: name: "{{ item }}" state: present with_items:
-
'dn1'
-
'dn2'
-
-
name: create users user: name: "{{ item.name }}" state: present groups: "{{ item.groups }}" with_items:
-
{name: 'test1', groups: 'dn1'}
-
{name: 'test2', groups: 'dn2'}
-
-
ansible-playbook test3.yaml
//Templates 模块 Jinja是基于Python的模板引擎。Template类是Jinja的一个重要组件,可以看作是一个编译过的模板文件, 用来产生目标文本,传递Python的变量给模板去替换模板中的标记。
1.先准备一个以 .j2 为后缀的 template 模板文件,设置引用的变量 cp /etc/httpd/conf/httpd.conf /opt/httpd.conf.j2
vim /opt/httpd.conf.j2 Listen {{http_port}} #42行,修改 ServerName {{server_name}} #95行,修改 DocumentRoot "{{root_dir}}" #119行,修改
2.修改主机清单文件,使用主机变量定义一个变量名相同,而值不同的变量 vim /etc/ansible/hosts [webservers] 192.168.233.20 http_port=192.168.233.20:80 server_name=www.accp.com:80 root_dir=/etc/httpd/htdocs
[dbservers] 192.168.233.30 http_port=192.168.233.30:80 server_name=www.benet.com:80 root_dir=/etc/httpd/htdocs
3.编写 playbook
vim apache.yaml
-
hosts: all remote_user: root vars:
-
package: httpd
-
service: httpd tasks:
-
name: install httpd package yum: name={{package}} state=latest
-
name: install configure file template: src=/opt/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf #使用template模板 notify:
-
restart httpd
-
-
name: create root dir file: path=/etc/httpd/htdocs state=directory
-
name: start httpd server service: name={{service}} enabled=true state=started handlers:
-
name: restart httpd service: name={{service}} state=restarted
-
ansible-playbook apache.yaml
//tags 模块 可以在一个playbook中为某个或某些任务定义“标签”, 在执行此playbook时通过ansible-playbook命令使用--tags选项能实现仅运行指定的tasks。
playbook还提供了一个特殊的tags为always。 作用就是当使用always作为tags的task时,无论执行哪一个tags时,定义有always的tags都会执行。
在Ansible中,标记(Tags)是用于标记任务的标识符, 可以用来选择性地运行或忽略特定标记的任务。在执行Ansible Playbook时, 你可以使用--tags和--skip-tags选项来指定要运行或跳过的标记。以下是一些常见的标记, 你也可以自定义标记以满足特定需求:
always: 始终运行的任务,即使没有使用--tags选项。
never: 从不运行的任务,即使使用了--tags选项。
debug: 用于调试目的的任务。
setup: 收集主机的事实(facts)信息的任务。
pre_tasks: 在主任务之前运行的任务。
post_tasks: 在主任务之后运行的任务。
也可以自定义标签。
-
hosts: all tasks:
-
name: This task has the tag 'debug' debug: msg: "Debug message" tags:
-
debug
-
-
name: This task has the tag 'setup' setup: tags:
-
setup
-
-
name: This task always runs debug: msg: "Always run" tags:
-
always
-
-
name: This task never runs debug: msg: "Never run" tags:
-
never
-
-
vim webhosts.yaml
-
hosts: webservers remote_user: root tasks:
-
name: Copy hosts file copy: src=/etc/hosts dest=/opt/hosts tags:
-
only #可自定义
-
-
name: touch file file: path=/opt/testhost state=touch tags:
-
always #表示始终要运行的代码
-
ansible-playbook webhosts.yaml --tags="only"
ansible-playbook tags.yaml --skip-tags='setup' #跳过这个标签
[root@test1 opt]# ansible-playbook tags.yaml --tags='always','setup' #指定运行多个标签
vim dbhosts.yaml
-
hosts: dbservers remote_user: root tasks:
-
name: Copy hosts file copy: src=/etc/hosts dest=/opt/hosts tags:
-
only
-
-
name: touch file file: path=/opt/testhost state=touch
-
ansible-playbook dbhosts.yaml --tags="only" //分别去两台被管理主机上去查看文件创建情况
//Roles 模块 Ansible为了层次化、结构化地组织Playbook,使用了角色(roles), roles可以根据层次型结构自动装载变量文件、task以及handlers等。
简单来讲,roles就是通过分别将变量、文件、任务、模块及处理器放置于单独的目录中, 并可以便捷地include它们。
roles一般用于基于主机构建服务的场景中,但也可以用于构建守护进程等场景中。
//roles 的目录结构: cd /etc/ansible/ tree roles/ roles/ ├── web/ #相当于 playbook 中的 每一个 play 主题 │ ├── files/ │ ├── templates/ │ ├── tasks/ │ ├── handlers/ │ ├── vars/ │ ├── defaults/ │ └── meta/ └── db/ ├── files/ ├── templates/ ├── tasks/ ├── handlers/ ├── vars/ ├── defaults/ └── meta/
web/: 这是一个角色的名称,可能是用于配置和管理 Web 服务器的角色。在这个目录下,有以下子目录和文件:
files/: 用于存放要在目标主机上复制的文件。 这些文件可以通过 Ansible 的 copy 模块或者 template 模块进行复制。
templates/: 用于存放 Jinja2 模板文件,这些模板文件可以通过 Ansible 的 template 模块渲染, 并将结果复制到目标主机上。
tasks/: 包含要执行的任务的主要文件,通常是 main.yml。这些任务文件中定义了角色的主要功能。
handlers/: 包含要在角色中使用的处理器的主要文件,通常也是 main.yml。 处理器是在特定条件下触发的操作,通常是在任务执行完成后。
vars/: 包含角色特定的变量。这些变量可以在角色的任务和处理器中使用。
defaults/: 包含默认变量值。这些变量在没有在 inventory 文件或者 Playbook 中定义的情况下使用。
meta/: 包含元信息,通常用于描述依赖关系和其他元数据。
roles/ ├── my_role/ # 角色名称,根据实际情况取名 │ ├── files/ # 存放由 copy 模块或 script 模块调用的文件 │ ├── templates/ # 存放 Jinja2 模板文件 │ ├── tasks/ # 包含任务的目录 │ │ └── main.yml # 角色的主要任务定义 │ ├── 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: webservers remote_user: root roles:
-
httpd
-
-
hosts: dbservers remote_user: root roles:
-
mysql
-
(7)运行 ansible-playbook cd /etc/ansible ansible-playbook site.yml
示例: mkdir /etc/ansible/roles/httpd/{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} -p
touch /etc/ansible/roles/httpd/{defaults,vars,tasks,meta,handlers}/main.yml touch /etc/ansible/roles/mysql/{defaults,vars,tasks,meta,handlers}/main.yml touch /etc/ansible/roles/php/{defaults,vars,tasks,meta,handlers}/main.yml
------编写httpd模块------ 写一个简单的tasks/main.yml vim /etc/ansible/roles/httpd/tasks/main.yml
-
name: install apache yum: name={{pkg}} state=latest
-
name: start apache service: enabled=true name={{svc}} state=started
//定义变量:可以定义在全局变量中,也可以定义在roles角色变量中,一般定义在角色变量中 vim /etc/ansible/roles/httpd/vars/main.yml pkg: httpd svc: httpd
-------编写mysql模块------- vim /etc/ansible/roles/mysql/tasks/main.yml
-
name: install mysql yum: name={{pkg}} state=latest
-
name: start mysql service: enabled=true name={{svc}} state=started
vim /etc/ansible/roles/mysql/vars/main.yml pkg:
-
mariadb
-
mariadb-server svc: mariadb
-------编写php模块----- vim /etc/ansible/roles/php/tasks/main.yml
-
name: install php yum: name={{pkg}} state=latest
-
name: start php-fpm service: enabled=true name={{svc}} state=started
vim /etc/ansible/roles/php/vars/main.yml pkg:
-
php
-
php-fpm svc: php-fpm
-----编写roles示例-----
vim /etc/ansible/site.yml
-
hosts: webservers remote_user: root roles:
-
httpd
-
mysql
-
php
-
cd /etc/ansible ansible-playbook site.yml