Ansible对远程服务器的操作实际是通过模块完成的。
Ansible中的模块是幂等的。也就是说,多次执行相同的操作,只有第一次会起作用。这也是在编写自定义Ansible模块时需要注意的地方。
Ansible的模块非常多,如果以模块的功能进行分类,可以分为:
模块参考文档
#获取模块帮助信息
ansible-doc -l
#获取指定模块帮助信息
ansible-doc [modules]
command,raw,script和shell模块都可以实现在远程服务器上执行Linux命令。
command模块包含的其他重要选项:
chdir: 在执行指令之前,先切换到该指定的目录,类似与Linux下的cd
executable: 切换shell来执行命令。
raw模块相当于管道
shell模块
script模块
file模块主要用于对远程服务器上的文件(包括链接和目录)进行操作,包括修改文件的权限,修改文件所有者,创建文件,删除文件等。
#创建一个目录
ansible test -m file -a "path=/tmp/dd state=directory mode=0755"
#修改文件的权限
ansible test -m file -a "path=/tmp/dd sate=touch mode="u=rw, g=r, o=r""
#创建一个软链接
ansible test -m file -a "src=/tmp/dd dest=/tmp/ddl owner=lmxgroup=lmx state=link"
#修改一个文件所有者
ansible test -m file -a "path=/tmp/dd owner=root group=root mode=0644" -become
copy模块用来将主控节点的文件或目录拷贝到远程服务器上,类似于Linux下的scp命令。但是,copy模块比scp命令更强大,在拷贝文件到远程服务器的同时,也可以设置文件在远程服务器的权限和所有者。
user模块请求的是useradd, userdel, usermod 三个指令,goup模块请求的是groupadd,groupdel,groupmod三个指令。
apt模块用来Debian/Ubuntu系统中安装软件,删除软件。
7.get_url
从互联网下载数据到本地,作用类似于Linux下的curl命令。get_url模块比curl命令更加灵活,可以控制下载以后的数据所有者,权限以及检查数据的checksum等。
unarchive模块用于解压文件,其作用类似于Linux下的tar命令。默认情况下,unarchive的作用是将控制节点的压缩包拷贝到远程服务器,然后解压。
git模块非常好理解,就是在远程服务器执行git相关的操作。该模块一般应用于需要源码安装软件时,从github源码托管下载到本地。
stat模块用于获取远程服务器上的文件信息,其作用类似于Linux下的stat命令。stat模块可以获取atime,ctime,mtime,checksum,size,uid,gid等信息。
cron是管理Linux下计划任务的模块
service模块的作用类似于Linux下的service命令,用来启动,停止,重启服务。
该模块的作用与Linux下的sysctl命令相似,用于控制Linux的内核参数。
在远程服务器上挂在磁盘,当进行挂盘操作时,如果挂载点指定的路径不存在,将创建该路径。
synchronizze模块是对rsync命令的封装,以便对常见的rsync任务进行处理既然synchronize模块是对rsync命令的封装,那么,我们也可以使用command模块调用rsync命令执行相应的操作。rsync是一个比较复杂的命令,相对来说,使用synchrronize简单一些。
Ansible为了提高部署的效率,默认使用了并发的方式对远程服务器进行更新。我们可以使用–forks参数控制并发的进程数,默认并发进程数为5.
- name: test play
hosts: webservers
#一次只更新一台
serial: 1
#一次更新30%
serial: "30%"
#先更新1台然后更新5台,在更新10台,直至webservers组中所有服务器都更新完毕
serial:
- 1
- 5
- 10
playbook中的每个play都指明了要对那些服务器执行那些操作。典型的用法是, Ansible在定义好的一组服务器上执行相同的操作。大部分情况下,这也是我们想要的功能。但是,在某些特殊情况下,对服务器进行批量操作的过程中需要对其中一台服务器进行特殊处理。此时,需要使用ANsible的任务委派功能。
例如: 在部署之前将一台服务器从负载均衡集群中删除;或在对一台服务器做改变前去掉相应dns记录。
-name take out of load balancer pool
command: /usr/bin/take_out_of_pool {{ inventory_hostname }}
delegate_to: 127.0.1
Ansible默认只对远程服务器执行操作,如果要在Ansible的控制服务器(Ansible进程所在服务器)上执行操作,可以使用delegate_to功能将任务委派到本地执行。除此之外,Ansible还提供了local_action选项明确指定在控制服务器执行操作。
tasks:
- name: take out of load balancer pool
local_action: command /usr/bin/take_out_of_pool {{ inventory_hostname }}
考虑这样一个需求:有多台应用服务器运行在负载均衡后面,现在需要进行数据库迁移,应该如何实现,这个任务特殊之处在于,只需要在一台应用服务器上执行这个迁移操作,在任何一台应用服务器上执行迁移都可以这个时候,我们可以使用索引1和切片的方式访问组中的服务器,因此,可以像下面这样指定该组中的第一台服务器执行数据库迁移操作:
- command: /opt/application/migrate_db.py
when: inventory_hostname = webservers[0]
通过索引的方式指定服务器,虽然能够满足这里的需求。但是,没有明确说明任务仅执行一次这个重点,其他人看到这段代码时,看到的是该组下的第一台服务器中执行迁移操作,,而不是任意一台服务器上执行一次数据迁移操作。为了让代码更加清晰明了,Ansible提供了run_once选项。
- command: /opt/application/migrate_db.py
run_once: true
默认情况下,Ansible会选择在组中第一台服务器中执行run_once操作。因此,上面两种方式的实际效果是一样的,他们都会选择该组中的第一台服务器执行数据库迁移操作。如果要指定某一台服务器执行数据库迁移操作,可以结合delegate_to选项1实现
- command: /opt/application/migrate_db.py
run_once: true
deletegate_to: web01.example.org
---
users:
alice:
name: Alice Appleworth
telephone: 123-456-7890
bob:
name: Bob Bananarama
telephone: 987-654-3210
tasks:
- name: Print phone records
debug:
msg: "User {{ item.key }} is {{ item.value.name }} {{{ item.value.telephone }}}"
with_dict: "{{ user }}"
...
- name: give users access to multiple databases
mysql_user:
name: "{{ item[0] }}"
priv: "{{ item[1] }}.*:ALL"
append_privs: yes
password: "foo"
with_nested:
- ['alice', 'bob']
- ['clientdb', 'employeedb', ''providerdb]
随机选择某一项
- debug:
msg: "{{ item }}"
with_random_choice:
- "go through the door"
- "drink from the goblet"
- "press the red button"
- "do nothing"
# create some test users
- user:
name: "{{ item }}"
state: present
groups: "evens"
with_sequence: start=0 end=32 format=testuser%02x
使用Ansible部署服务器时,如果部署的任务比较复杂,那么,不可避免地导致任务列表变长。任务列表变长以后,错误处理就会比较麻烦。这时因为Ansible中的task是按顺序依次执行的。当我们重新指定修改过后的Playbook,Ansible会重新执行前面已经执行过task。如果中间某些步骤比较耗时(如下载一个很大的安装包),那么会显著增加复杂Playbook的调试时间。这个时候,我们希望跳过某些task仅执行Playbook中的部分task,或者明确指定运行Playbook中的部分task。在Ansible中,可以通过tags选项实现这个功能。
- name: install package
yum: name={{ item }} state=installed
with_items:
- httpd
- memcached
tags:
- packages
- name: uploading config file
template: src=templates/src.j2 dest=/etc/foo.conf
tags:
- configuration
- name: be sure ntpd is running and enabled
service: name=ntpd state=started enabled=yes
tags: ntp
在这个例子中,我们使用tags为每个任务打上了一个标签。有了标签以后,可以使用ansible-playbook的–skip-tags选项与–tags选项指定需要执行1的task或者需要跳过的task。
#仅执行这个Playbook中前两个task
ansible-playbook example.yaml --tags "configuration,packages"
#忽略后一个task的功能
ansible-playbook example.yaml --skip-tags "ntp"
当shell命令或模块运行时,它们往往会根据自己的判断报告是否对远程服务器进行了修改,然后通过返回值中的"changed"字段返回给我们。如果changed字段返回有误,则可以根据具体的场景修正changed字段的返回值。
tasks:
- shell: /usr/bin/billybass --mode="take me to the river"
register: bass_result
changed_when: "bass_result.rc != 2"
与changed字段类似,我们也可以通过自定义的方式判断命令是否执行成功。如果使用Ansible执行shell命令,默认情况下通过命令的返回码是否为0判断命令是否执行成功(这也是Linux命令的标准)。对于一些特殊的命令,无法通过返回码知道命令是否执行成功,那么,我们可以使用failed_when选项自定义命令执行失败的标准。
- name: this command prints FAILED when it fails
command: /usr/bin/example-command -x -y -z
register: command_result
failed_when: "FAILED' in command_result.stderr"