Ansible剧本(playbook)是用于配置、部署和管理被控节点的一种描述文件。通过编写详细的剧本描述和执行其中的任务(tasks),可以使远程主机达到预期的状态。剧本由一个或多个"play"组成的列表构成。当需要在一台机器上进行多个操作时,使用剧本会更加方便。使用Ansible剧本可以实现自动化运维。
Tasks(任务):任务是剧本中最基本的组成部分,用于定义要在被控节点上执行的操作。每个任务通常会调用一个或多个模块来完成特定的功能。任务可以包括文件操作、软件包安装、服务管理等各种操作。即通过 task 调用 ansible 的模板将多个操作组织在一个 playbook 中运行
Variables(变量):变量用于存储和传递数据,在剧本中可以定义各种类型的变量,包括全局变量、主机变量和组变量。变量可以在剧本的不同部分进行引用和修改,使得剧本更加灵活和可配置。
Templates(模板):模板是一种用于生成配置文件或其他文本文件的机制。在剧本中可以使用Jinja2模板语言来定义模板,并通过填充变量的方式生成最终的文件。模板可以根据不同的主机或变量生成不同的配置文件。
Handlers(处理器):处理器是一种特殊的任务,它会在特定的事件触发时执行。处理器通常用于在配置文件修改后重启服务或执行其他操作。当某个任务的状态(changed)满足条件时,可以通过(notify)关键字触发执行相应的处理器。
Roles(角色):角色是一种组织和复用剧本的机制。通过定义角色,可以将相关的任务、变量和模板组织在一起,以便在多个剧本中进行复用。角色可以使剧本更加模块化和可维护,提高代码的复用性和可读性。
Ansible剧本(playbook)的原理是基于声明式编程的自动化工具。它使用YAML格式的文件来描述所需的配置和操作,然后通过Ansible引擎解析和执行这些剧本。
下面是Ansible剧本的工作原理:
解析:Ansible引擎首先会解析剧本文件,将其转换为内部数据结构。这个过程包括读取和解析YAML文件,识别剧本中的任务、变量、模板等部分。
连接:Ansible会与被控节点建立SSH连接或使用其他连接插件进行通信。这样可以确保Ansible能够远程执行命令和操作被控节点。
主机选择:根据剧本中定义的清单(Inventory),Ansible会确定要操作的目标主机或主机组。这个过程可以根据主机的IP地址、主机名、标签等进行选择。
变量解析:Ansible会解析剧本中定义的变量,并根据清单中的主机和组信息进行变量的匹配和替换。这样可以根据不同的主机或组设置不同的变量值。
任务执行:Ansible按照剧本中定义的顺序执行任务。每个任务通常会调用一个或多个模块来完成特定的操作。模块会在被控节点上执行相应的命令或操作,并返回执行结果。
状态管理:Ansible会跟踪每个任务的执行状态,包括任务是否成功、是否有变化等。这些状态信息可以用于后续的条件判断和处理。
处理器触发:当某个任务的状态满足条件时(例如任务执行成功或有变化),可以触发相应的处理器(Handlers)。处理器通常用于执行一些特定的操作,如重启服务或发送通知。
结果报告:在执行完所有任务后,Ansible会生成执行结果的报告。报告中包括每个任务的执行状态、变量的值等信息,以便用户进行查看和分析。
通过这样的工作流程,Ansible剧本可以实现自动化地配置、部署和管理被控节点,提高运维效率和一致性。同时,Ansible的模块化设计和丰富的模块库,使得剧本可以适应各种不同的场景和需求。
vim test1.yaml
---
- 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: install configuration file for httpd
copy: src=/opt/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify: "restart httpd"
- name: start httpd service
service: enabled=true name=httpd state=started
handlers:
- name: restart httpd
service: name=httpd state=restarted
##Ansible在执行完某个任务之后并不会立即去执行对应的handler,而是在当前play中所有普通任务都执行完后再去执行handler,这样的好处是可以多次触发notify,但最后只执行一次对应的handler,从而避免多次重启。
这是一个使用Ansible编写的YAML文件,用于配置和管理Web服务器。下面是对每个部分的详细解析:
---
: 这是YAML文件的分隔符,表示一个新的YAML文档开始,可省略
- name: first play
: 定义了一个名为"first play"的Play(任务集合),用于描述一组相关的任务,可省略
gather_facts: false
: 禁用了Ansible的事实(facts)收集功能,即不收集关于目标主机的信息,可省略
hosts: webservers
: 指定了这个Play要在名为"webservers"的主机组上执行,如多个主机组用冒号分隔
remote_user: root
: 指定了远程执行任务时使用的用户名,这里是"root"。
tasks:
: 定义了一个任务列表,包含了一系列要执行的任务。任务列表中的各任务按次序逐个在hosts中指定的主机上执行
- name: test connection
: 自定义任务名称,定义了一个名为"test connection"的任务,用于测试与目标主机的连接。
ping:
: 使用Ansible的ping模块,向目标主机发送一个ping请求,以测试连接。
- name: disable selinux
: 定义了一个名为"disable selinux"的任务,用于禁用SELinux。
command: '/sbin/setenforce 0'
: 使用command模块执行命令/sbin/setenforce 0
,将SELinux设置为"0"(禁用)。
ignore_errors: True
: 如执行命令的返回值不为0,就会报错,tasks停止,可以忽略执行该任务时的错误,即使命令执行失败也不会导致任务失败。
- name: disable firewalld
: 定义了一个名为"disable firewalld"的任务,用于停止firewalld服务。
service: name=firewalld state=stopped
: 使用service模块停止名为"firewalld"的服务。
- name: install httpd
: 定义了一个名为"install httpd"的任务,用于安装httpd软件包。
yum: name=httpd state=latest
: 使用yum模块安装最新版本的名为"httpd"的软件包。
- name: install configuration file for httpd
: 定义了一个名为"install configuration file for httpd"的任务,用于安装httpd的配置文件。
copy: src=/opt/httpd.conf dest=/etc/httpd/conf/httpd.conf
: 使用copy模块将源文件"/opt/httpd.conf"复制到目标位置"/etc/httpd/conf/httpd.conf"。
notify: "restart httpd"
: 当任务执行成功后,发送一个通知给名为"restart httpd"的处理程序。
- name: start httpd service
: 定义了一个名为"start httpd service"的任务,用于启动httpd服务。
service: enabled=true name=httpd state=started
: 使用service模块启用并启动名为"httpd"的服务。
handlers:
: 定义了一个处理程序列表,包含了一系列处理程序。
- name: restart httpd
: 定义了一个名为"restart httpd"的处理程序,用于重新启动httpd服务。
service: name=httpd state=restarted
: 使用service模块重新启动名为"httpd"的服务。
这个YAML文件的目标是在"webservers"主机组上执行一系列任务,包括测试连接、禁用SELinux、停止firewalld服务、安装httpd软件包、安装httpd的配置文件,并最后启动httpd服务。在任务执行成功后,会触发一个处理程序来重新启动httpd服务。
ansible-playbook test1.yaml
执行该命令时,Ansible将连接到目标主机并按照playbook中定义的顺序执行任务。
运行playbook时,可以使用ansible-playbook
命令加上相应的参数来执行。
-k
(--ask-pass
): 该参数用于交互式地输入SSH密码。当远程主机需要密码进行身份验证时,会提示你输入密码。
-K
(--ask-become-pass
): 该参数用于交互式地输入sudo密码。当需要提升权限执行任务时,会提示你输入sudo密码。
-u <username>
: 该参数用于指定执行任务时使用的用户名。可以通过-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开始运行
--syntax-check
: 使用该参数可以检查YAML文件的语法是否正确,而不执行任务。这对于在运行playbook之前验证文件的正确性非常有用。
--list-task
: 使用该参数可以列出playbook中的所有任务(tasks)。这对于查看playbook中定义的任务非常有用。
--list-hosts
: 使用该参数可以列出playbook中生效的主机。这对于查看playbook将在哪些主机上执行任务非常有用。
--start-at-task='<task_name>'
: 使用该参数可以指定从某个任务开始运行。可以通过--start-at-task
参数后跟任务名称来指定从特定任务开始执行。
通过在ansible-playbook
命令后添加这些参数,可以根据需要执行playbook,并进行各种检查和配置。
使用Ansible编写的YAML文件,用于定义和引用变量,并在任务中使用这些变量。
- name: second play
hosts: dbservers
remote_user: root
vars: #定义变量
- groupname: mysql #格式为 key: value
- username: nginx
tasks:
- name: create group
group: name={{groupname}} system=yes gid=306 #使用 {{key}} 引用变量的值
- name: create user
user: name={{username}} uid=306 group={{groupname}} #在setup模块中可以获取factsup={{groupname}}
- name: copy file变量信息
copy: content="{{ansible_default_ipv4}}" dest=/opt/vars.txt
ansible-playbook test1.yaml -e "username=nginx" #在命令行里定义变量
- name: second play
: 定义了一个名为"second play"的Play,用于描述一组相关的任务。
hosts: dbservers
: 指定了这个Play要在名为"dbservers"的主机组上执行。
remote_user: root
: 指定了远程执行任务时使用的用户名,这里是"root"。
vars:
: 定义了一个变量列表,用于存储变量的键值对。
- groupname: mysql
: 定义了一个名为"groupname"的变量,并将其值设置为"mysql"。
- username: nginx
: 定义了一个名为"username"的变量,并将其值设置为"nginx"。
tasks:
: 定义了一个任务列表,包含了一系列要执行的任务。
- name: create group
: 定义了一个名为"create group"的任务,用于创建一个组。
group: name={{groupname}} system=yes gid=306
: 使用group模块创建一个名为{{groupname}}(引用变量值)的组,设置system属性为"yes",并指定gid为306。
- name: create user
: 定义了一个名为"create user"的任务,用于创建一个用户。
user: name={{username}} uid=306 group={{groupname}}
: 使用user模块创建一个名为{{username}}(引用变量值)的用户,设置uid为306,并将其添加到{{groupname}}组中。
- name: copy file变量信息
: 定义了一个名为"copy file变量信息"的任务,用于将变量信息写入文件。
copy: content="{{ansible_default_ipv4}}" dest=/opt/vars.txt
: 使用copy模块将变量ansible_default_ipv4
的值作为文件内容,复制到目标文件"/opt/vars.txt"中。
在命令行中,可以使用-e
参数来定义变量。例如,ansible-playbook test1.yaml -e "username=nginx"
将在执行playbook时将变量"username"设置为"nginx"。
通过定义和引用变量,可以在Ansible playbook中实现更灵活和可配置的任务执行。变量可以在不同的任务中共享和重用,并且可以在命令行中动态定义,以适应不同的执行需求。
---
- hosts: dbservers
remote_user: zhangsan
become: yes #2.6版本以后的参数,之前是sudo,意思为切换用户运行
become_user: root #指定sudo用户为root
执行playbook时:ansible-playbook test1.yml -K <密码>
这是一个使用Ansible编写的YAML文件,用于在远程主机上切换用户并执行任务。
- hosts: dbservers
: 指定了这个Play要在名为"dbservers"的主机组上执行。
remote_user: zhangsan
: 指定了远程执行任务时使用的用户名,这里是"zhangsan"。
become: yes
: 这是Ansible 2.6版本以后的参数,用于指定切换用户运行任务。之前的版本使用"sudo"参数来实现相同的功能。
become_user: root
: 指定了切换用户后要使用的sudo用户为"root"。也就是说,在执行任务时,将使用"root"用户的权限来运行任务。
在执行playbook时,可以使用-K
参数来提示输入sudo密码。例如,ansible-playbook test1.yml -K
将要求你输入sudo密码以切换到指定的sudo用户(在这个例子中是"root")并执行任务。
通过指定远程主机的sudo切换用户,可以在Ansible中以不同的权限执行任务,以满足不同的需求和安全要求。
在执行playbook时,Ansible会根据条件判断来决定是否执行任务。如果条件为真,则任务将被执行;如果条件为假,则任务将被跳过。
通过使用when条件判断,可以根据不同的条件来灵活控制任务的执行,实现根据需求选择性地执行任务。
vim test2.yaml
---
- hosts: all
remote_user: root
tasks:
- name: shutdown host
command: /sbin/shutdown -r now
when: ansible_default_ipv4.address == "192.168.41.31" #when指令中的变量名不需要手动加上 {{}}
或
when: inventory_hostname == "<主机名>"
ansible-playbook test2.yaml
这是一个使用Ansible编写的YAML文件,用于根据条件判断是否执行任务。
- hosts: all
: 指定了这个Play要在所有主机上执行。
remote_user: root
: 指定了远程执行任务时使用的用户名,这里是"root"。
tasks:
: 定义了一个任务列表,包含了一系列要执行的任务。
- name: shutdown host
: 定义了一个名为"shutdown host"的任务,用于关机主机。
command: /sbin/shutdown -r now
: 使用command模块执行命令/sbin/shutdown -r now
,即立即重启主机。
when: ansible_default_ipv4.address == "192.168.41.31"
: 使用when指令来判断是否执行该任务。当ansible_default_ipv4.address
的值等于"192.168.41.31"时,任务将被执行。这里的ansible_default_ipv4.address
是一个Ansible提供的变量,表示主机的IPv4地址。
或者可以使用when: inventory_hostname == "<主机名>"
来根据主机名进行条件判断。当inventory_hostname
的值等于指定的主机名时,任务将被执行。
vim test3.yaml
---
- name: play1
hosts: dbservers
gather_facts: false
tasks:
- name: create directories
file:
path: "{{item}}"
state: directory
with_items: #等同于 loop:
- /tmp/test1
- /tmp/test2
- name: add users
user: name={{item.name}} state=present groups={{item.groups}}
with_items:
- name: test1
groups: wheel
- name: test2
groups: root
或
with_items:
- {name:'test1', groups:'wheel'}
- {name:'test2', groups:'root'}
ansible-playbook test3.yaml
这是一个使用Ansible编写的YAML文件,用于在远程主机上执行循环操作。
- name: play1
: 定义了一个名为"play1"的Play,用于描述一组相关的任务。
hosts: dbservers
: 指定了这个Play要在名为"dbservers"的主机组上执行。
gather_facts: false
: 禁用了Ansible的事实(facts)收集功能,即不收集关于目标主机的信息。
tasks:
: 定义了一个任务列表,包含了一系列要执行的任务。
- name: create directories
: 定义了一个名为"create directories"的任务,用于创建目录。
file: path: "{{item}}" state: directory
: 使用file模块创建目录,路径为{{item}}
(迭代的值),状态为"directory"。
with_items:
: 使用with_items指令来进行循环迭代。它用于迭代一个列表或字典。
- /tmp/test1 - /tmp/test2
: 定义了一个包含两个路径的列表,用于迭代创建目录。
- name: add users
: 定义了一个名为"add users"的任务,用于添加用户。
user: name={{item.name}} state=present groups={{item.groups}}
: 使用user模块添加用户,用户名为{{item.name}}
(迭代的值),状态为"present",所属组为{{item.groups}}
(迭代的值)。
with_items:
: 使用with_items指令进行循环迭代。
- name: test1 groups: wheel - name: test2 groups: root
: 定义了一个包含两个字典的列表,每个字典包含用户名和所属组的键值对,用于迭代添加用户。
或者可以使用with_items:
指令后跟包含键值对的字典列表,例如- {name:'test1', groups:'wheel'} - {name:'test2', groups:'root'}
。
在执行playbook时,Ansible会根据循环迭代的方式,依次执行任务,并使用{{item}}
来获取每次迭代的值。
通过使用循环结构,可以在Ansible中实现对列表或字典的迭代操作,从而批量执行任务或根据不同的值执行不同的操作。
Jinja是一个基于Python的模板引擎,用于生成动态内容。它提供了一种将变量和逻辑表达式嵌入到模板中的方式,以生成最终的文本输出。
在Jinja中,模板文件被编译为Template对象,然后可以通过传递变量给模板来替换模板中的标记。这些标记通常使用双花括号{{}}
表示,用于表示变量的值。Jinja还提供了条件语句、循环语句等控制结构,使得模板可以根据不同的条件生成不同的输出。
Jinja模板引擎的优势在于它的灵活性和可扩展性。它可以与各种类型的应用程序集成,并支持自定义过滤器、宏等功能,以满足不同的需求。
使用Ansible进行配置管理的示例。
.j2
为后缀的模板文件httpd.conf.j2
,并设置引用的变量。使用以下命令将/etc/httpd/conf/httpd.conf
复制到/opt/httpd.conf.j2
:cp /etc/httpd/conf/httpd.conf /opt/httpd.conf.j2
然后,使用vim编辑器打开/opt/httpd.conf.j2
文件,并修改以下行:
vim /opt/httpd.conf.j2
Listen {{http_port}} # 修改第42行
ServerName {{server_name}} # 修改第95行
DocumentRoot "{{root_dir}}" # 修改第119行
/etc/ansible/hosts
,使用主机变量定义一个变量名相同但值不同的变量。在文件中添加以下内容:vim /etc/ansible/hosts
[webservers]
192.168.41.31 http_port=192.168.41.31:80 server_name=www.test1.com:80 root_dir=/etc/httpd/htdocs
[dbservers]
192.168.41.32 http_port=192.168.41.32:80 server_name=www.test2.com:80 root_dir=/etc/httpd/htdocs
apache.yaml
,包含安装和配置Apache HTTP服务器的任务。以下是文件的内容:---
- 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
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
这个playbook会安装httpd
软件包,使用模板文件httpd.conf.j2
生成配置文件/etc/httpd/conf/httpd.conf
,然后创建目录/etc/httpd/htdocs
,最后启动httpd
服务。如果配置文件发生变化,会触发重启httpd
服务。
使用以下命令运行playbook:
ansible-playbook apache.yaml
?
tags
模块允许为任务定义标签,在执行playbook时可以使用--tags
选项只运行指定标签的任务。在这个示例中,有两个playbook文件:webhosts.yaml
和dbhosts.yaml
。
webhosts.yaml
文件内容如下:
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
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
运行webhosts.yaml
playbook,并只运行带有only
标签的任务:
ansible-playbook webhosts.yaml --tags="only"
运行dbhosts.yaml
playbook,并只运行带有only
标签的任务:
ansible-playbook dbhosts.yaml --tags="only"
这些playbook会在被管理的主机上复制/etc/hosts
文件到/opt/hosts
,并在/opt
目录下创建一个名为testhost
的文件。