ansible
查询每个模块的用法:
ansible-doc yum
列出已安装的模块文档:
ansible-doc -l
cat nodes.txt
[k8s-rancher]
192.168.219.101
[k8s-k8s1]
#192.168.219.102 ansible_ssh_pass=root ansible_become_password=ubuntu
192.168.219.102
[k8s-server-all:children]
k8s-rancher
k8s-k8s1
ansible -i nodes.txt k8s-k8s1 -a "ip a" -u ubuntu --become #使用sudo用户 免密执行
ansible -i nodes.txt k8s-k8s1 -a "ip a" -u ubuntu --become -K #使用sudo用户 手动输入密码 -K 大K sudo密码
ansible -i nodes.txt k8s-k8s1 -a "id" -u alex -k #登录普通用户alex, -k 小k 普通用户ssh密码
ansible -i nodes.txt k8s-rancher -a "id" -u ubuntu #使用普通用户ubuntu 来执行id命令
ansible -i nodes.txt k8s-k8s1 -a "/sbin/reboot" -f 10 #fork出10个进程 每次执行10台机器
----------------------------------------------------
文件传输
ansible webservers -m copy -a "src=/root/ans/book/1.yaml dest=/tmp/a.yaml"
文件改权限
ansible webservers -m file -a "dest=/srv/foo/a.txt mode=600" #把目标文件改成600
ansible webservers -m file -a "dest=/srv/foo/b.txt mode=600 owner=mdehaan group=mdehaan" #把目标文件改所有者和所有组 和 权限
创建目录 mkdir -p一样
ansible webservers -m file -a "dest=/path/to/c mode=755 owner=mdehaan group=mdehaan state=directory"
删除目录(递归删除)和删除文件
ansible webservers -m file -a "dest=/tmp/a/b state=absent"
-------------------------------------------------------
包管理:
yum示例:
确认一个软件包已经安装,但不去升级他:
ansible webservers -m yum -a "name=acme state=present"
确认一个软件包的安装版本
ansible webservers -m yum -a "name=acme-1.5 state=present"
确认一个软件包还没有安装
ansible webservers -m yum -a "name=acme state=absent"
---------------------------------
用户和用户组
使用user模块创建账户,删除账户,或者管理现有的账户:
ansible -i nodes.txt k8s-k8s1 -m user -a "name=clex password=<crypted password here>"
删除用户:
ansible -i nodes.txt k8s-k8s1 -m user -a "name=clex state=absent"
使用git来部署:
ansible -i nodes.txt k8s-k8s1 -m git -a "repo=http://git.onlyedu.com.cn/python/ils-ai.git dest=/srv/myapp version=HEAD" #未实验成功
服务管理:
确认某个服务在指定服务器上 都已经启动:
ansible -i nodes.txt k8s-k8s1 -m service -a "name=sshd state=started"
重启服务:
ansible -i nodes.txt k8s-k8s1 -m service -a "name=sshd state=restarted"
停止某个服务:
ansible -i nodes.txt k8s-k8s1 -m service -a "name=sshd state=stopped"
--------------------------------------------------
需要长时间运行的命令可以放到后台去,在命令开始运行后我们也可以检查运行的状态.如果运行命令后,不想获取返回的信息, 可执行如下命令:
ansible all -B 3600 -P 0 -a "/usr/bin/long_running_operation --do-stuff" #会返回一个job id
-B SECONDS, --background SECONDS
run asynchronously, failing after X seconds 放在后台运行,超过多久报错
-P POLL_INTERVAL, --poll POLL_INTERVAL
set the poll interval if using -B (default=15) 每多少秒拉取一下日志
如果你确定要在命令运行后检查运行的状态,可以使用 async_status 模块.前面执行后台命令后会返回一个 job id, 将这个 id 传给 async_status 模块:
$ ansible web1.example.com -m async_status -a "jid=488359678239.2844"
------------------------------------------------
Gathering Facts
在 playbooks 中有对于 Facts 做描述,它代表的是一个系统中已发现的变量.
These can be used to implement conditional execution of tasks but also just to get ad-hoc information about your system.
可通过如下方式查看所有的 facts:
$ ansible all -m setup
----------------------------------------------
playbooks
小案例:
---
- hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: pkg=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running
service: name=httpd state=started
handlers:
- name: restart apache
service: name=httpd state=restarted
remote_user是远程登录的用户。
也可以为每个task,定义自己的远程用户:
---
- hosts: webservers
remote_user: root
tasks:
- name: test connection
ping:
remote_user: yourname
也支持sudo执行命令:
---
- hosts: webservers
remote_user: yourname
sudo: yes
可以再一个task中执行sudo,而不是再整个play中使用sudo:
---
- hosts: webservers
remote_user: yourname
tasks:
- service: name=nginx state=started
sudo: yes
也可以登陆后,sudo 到不同的用户身份,而不是使用 root:
---
- hosts: webservers
remote_user: yourname
sudo: yes
sudo_user: postgres
如果你需要在使用 sudo 时指定密码,可在运行 ansible-playbook 命令时加上选项 --ask-sudo-pass (-K).
如果使用 sudo 时,playbook 疑似被挂起,可能是在 sudo prompt 处被卡住,这时可执行 Control-C 杀死卡住的任务,再重新运行一次.
下面是一种基本的 task 的定义,service moudle 使用 key=value 格式的参数,这也是大多数 module 使用的参数格式:
tasks:
- name: make sure apache is running
service: name=httpd state=running
比较特别的两个 modudle 是 command 和 shell ,它们不使用 key=value 格式的参数,而是这样:
tasks:
- name: disable selinux
command: /sbin/setenforce 0
使用 command module 和 shell module 时,我们需要关心返回码信息,如果有一条命令,它的成功执行的返回码不是0, 你或许希望这样做:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true
或者是这样:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
在 action 行中可以使用变量.假设在 ‘vars’ 那里定义了一个变量 ‘vhost’ ,可以这样使用它:
tasks:
- name: create a virtual host file for {{ vhost }}
template: src=somefile.j2 dest=/etc/httpd/conf.d/{{ vhost }}
Handlers: 在发生改变时执行的操作
这里有一个例子,当一个文件的内容被改动时,重启两个 services:
- name: template configuration file
template: src=template.j2 dest=/etc/foo.conf
notify:
- restart memcached
- restart apache
例子:
1.yaml
---
- hosts: k8s-k8s1
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: write a test file
copy: src=/root/ans/book/1.yaml dest=/tmp/a.yaml
notify:
- stop tomcat9
handlers:
- name: stop tomcat9
service: name=tomcat9 state=stopped
运行:
ansible-playbook -i ../nodes.txt 1.yaml -f 10 #选择inventory文件 并发10个
在执行一个 playbook 之前,想看看这个 playbook 的执行会影响到哪些 hosts,你可以这样做:
ansible-playbook 1.yaml --list-hosts -i ../nodes.txt
playbook: 1.yaml
play #1 (k8s-k8s1): k8s-k8s1 TAGS: []
pattern: [u'k8s-k8s1']
hosts (1):
192.168.219.102
---------------------------------------------------
Playbook 角色(Roles) 和 Include 语句
如果你运行的是 Ansible 1.4 及以后的版本,include 语法可更为精简,这种写法同样允许传递列表和字典参数:
tasks:
- { include: wordpress.yml, wp_user: timmy, ssh_keys: [ 'keys/one.txt', 'keys/two.txt' ] } #wp_user: timmy 是传参进workpress.yml
使用上述任意一种语法格式传递变量给 include files 之后,这些变量就可以在 include 包含的文件中使用了。 关于变量的详细使用方法请查看 Variables 。变量可以这样去引用:
{{ wp_user }}
从 1.0 版开始,Ansible 支持另一种传递变量到 include files 的语法,这种语法支持结构化的变量:
tasks:
- include: wordpress.yml
vars:
wp_user: timmy
some_list_variable:
- alpha
- beta
- gamma
Include 语句也可以用在 ‘handlers’ section 中,比如,你希望定义一个重启 apache 的 handler, 你只需要定义一次,然后便可在所有的 playbook 中使用这个 handler。你可以创建一个 handlers.yml 文件如下:
---
# this might be in a file like handlers/handlers.yml
- name: restart apache
service: name=apache state=restarted
然后在你的主 playbook 文件中,在一个 play 的最后使用 include 包含 handlers.yml:
handlers:
- include: handlers/handlers.yml
--------------
roles
那怎样组织 playbook 才是最好的方式呢?简单的回答就是:使用 roles ! Roles 基于一个已知的文件结构,去自动的加载某些 vars_files,tasks 以及 handlers。基于 roles 对内容进行分组,使得我们可以容易地与其他用户分享 roles 。
一键生成roles官方目录:
mkdir {nfs,rsync,web}/{vars,tasks,templates,handlers,files} -p
tree
.
├── nfs #角色名称
│ ├── files #存放静态文件
│ ├── handlers #触发任务
│ ├── tasks #具体任务
│ ├── templates #模板文件(多变的文件,如httpd.conf.j2)
│ └── vars #存放变量
roles内各目录中可用的文件
tasks目录:至少应该包含一个名为main.yaml的文件,其定义了此角色的任务列表,此文件可以使用include包含其它的位于此目录中的task文件。
files目录:存放由copy或script等模块调用的文件。
templates目录:template模块会自动在此目录中寻找jenja2模板文件。
handlers目录:此目录中应包含一个main.yaml的文件,用于定义此角色用到的各handlers。
vars目录:应当包含一个main.yaml文件,用于定义此角色用到的变量。
mate目录:应当包含一个main.yaml文件,用于定义此角色的特殊设定及其依赖关系。
摘自:https://www.jianshu.com/p/157ed21bf47d
使用roles创建Rsync服务, 目录结构如下
[root@m01 roles]# tree /etc/ansible/roles/
/etc/ansible/roles/
├── hosts
├── rsync
│ ├── files
│ │ ├── rsyncd.conf
│ │ └── rsync.passwd
│ ├── handlers
│ │ └── main.yml
│ ├── tasks
│ │ └── main.yml
│ ├── templates
│ └── vars
├── site.yml
[root@m01 roles]# cat /etc/ansible/roles/site.yml
- hosts: backup
remote_user: root
roles:
- rsync
tags: rsync
`
[root@m01 roles]# cat /etc/ansible/roles/hosts
[backup]
172.16.1.41
[root@m01 roles]# cat /etc/ansible/roles/rsync/tasks/main.yml
- name: Install Rsync Server
yum: name=rsync state=present
- name: Configure Rsync Server
copy: src={{ item.src }} dest=/etc/{{ item.dest }} mode={{ item.mode }}
with_items:
- {src: "rsyncd.conf", dest: "rsyncd.conf", mode: "0644"}
- {src: "rsync.passwd", dest: "rsync.passwd", mode: "0600"}
notify: Restart Rsync Server
- name: Start Rsync Server
service: name=rsyncd state=started enabled=yes
[root@m01 roles]# cat /etc/ansible/roles/rsync/handlers/main.yml
- name: Restart Rsync Server
service: name=rsyncd state=restarted
执行roles,使用-t指定执行测试rsync角色
[root@m01 roles]# ansible-playbook -i hosts -t rsync site.yml
----------------------------
一个项目的结构如下:
site.yml
webservers.yml
fooservers.yml
roles/
common/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
webservers/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
这个 playbook 为一个角色 ‘x’ 指定了如下的行为:
如果 roles/x/tasks/main.yml 存在, 其中列出的 tasks 将被添加到 play 中
如果 roles/x/handlers/main.yml 存在, 其中列出的 handlers 将被添加到 play 中
如果 roles/x/vars/main.yml 存在, 其中列出的 variables 将被添加到 play 中
如果 roles/x/meta/main.yml 存在, 其中列出的 “角色依赖” 将被添加到 roles 列表中 (1.3 and later)
所有 copy tasks 可以引用 roles/x/files/ 中的文件,不需要指明文件的路径。
所有 script tasks 可以引用 roles/x/files/ 中的脚本,不需要指明文件的路径。
所有 template tasks 可以引用 roles/x/templates/ 中的文件,不需要指明文件的路径。
所有 include tasks 可以引用 roles/x/tasks/ 中的文件,不需要指明文件的路径。
如果你愿意,也可以使用参数化的 roles,这种方式通过添加变量来实现,比如:
---
- hosts: webservers
roles:
- common
- { role: foo_app_instance, dir: '/opt/a', port: 5000 }
- { role: foo_app_instance, dir: '/opt/b', port: 5001 }
当一些事情不需要频繁去做时,你也可以为 roles 设置触发条件,像这样:
---
- hosts: webservers
roles:
- { role: some_role, when: "ansible_os_family == 'RedHat'" }
最后,你可能希望给 roles 分配指定的 tags。比如:
---
- hosts: webservers
roles:
- { role: foo, tags: ["bar", "baz"] }
如果 play 仍然包含有 ‘tasks’ section,这些 tasks 将在所有 roles 应用完成之后才被执行。
如果你希望定义一些 tasks,让它们在 roles 之前以及之后执行,你可以这样做:
---
- hosts: webservers
pre_tasks:
- shell: echo 'hello'
roles:
- { role: some_role }
tasks:
- shell: echo 'still busy'
post_tasks:
- shell: echo 'goodbye'
角色默认变量(Role Default Variables)
New in version 1.3.
角色默认变量允许你为 included roles 或者 dependent roles(见下) 设置默认变量。
要创建默认变量,只需在 roles 目录下添加 defaults/main.yml 文件。
这些变量在所有可用变量中拥有最低优先级,可能被其他地方定义的变量(包括 inventory 中的变量)所覆盖。
-----------------------------------------
variables 合法变量名
变量名可以为字母,数字以及下划线.变量始终应该以字母开头
Facts通过访问远程系统获取相应的信息. 一个例子就是远程主机的IP地址或者操作系统是什么. 使用以下命令可以查看哪些信息是可用的:
ansible hostname -m setup
可以在playbook中这样引用以上例子中第一个硬盘的型号:
{{ ansible_devices.sda.model }}
关闭Facts
如果你不需要使用你主机的任何fact数据,你已经知道了你系统的一切,那么你可以关闭fact数据的获取.这有利于增强Ansilbe面对大量系统的push模块,或者你在实验性平台中使用Ansible.在任何playbook中可以这样做:
- hosts: whatever
gather_facts: no
注册变量
变量的另一个主要用途是在运行命令时,把命令结果存储到一个变量中.不同模块的执行结果是不同的.
运行playbook时使用-v选项可以看到可能的结果值. 在ansible执行任务的结果值可以保存在变量中,以便稍后使用它.在 条件选择 章节有一些示例.
这里有一个语法示例,在上面文档中也有所提及:
- hosts: web_servers
tasks:
- shell: /usr/bin/foo
register: foo_result
ignore_errors: True
- shell: /usr/bin/bar
when: foo_result.rc == 5
-------------
变量文件分割(变量存在外部文件中)
把playbook置于源代码管理之下是个很好的注意,当你可能会想把playbook源码公开之余还想保持某些重要的变量私有.有时你也想把某些信息放置在不同的文件中,远离主playbook文件.
你可以使用外部的变量文件来实现:
---
- hosts: all
remote_user: root
vars:
favcolor: blue
vars_files:
- /vars/external_vars.yml
tasks:
- name: this is just a placeholder
command: /bin/echo foo
这可以保证你共享playbook源码时隔离敏感数据的风险.
每个变量文件的内容是一个简单的YAML文件,如下所示:
---
# in the above example, this would be vars/external_vars.yml
somevar: somevalue
password: magic
------------------------
命令行中传递变量
除了`vars_prompt`和`vars_files`也可以通过Ansible命令行发送变量.如果你想编写一个通用的发布playbook时则特别有用,你可以传递应用的版本以便部署:
ansible-playbook release.yml --extra-vars "version=1.23.45 other_variable=foo"
Example:
---
- hosts: '{{ hosts }}'
remote_user: '{{ user }}'
tasks:
- ...
ansible-playbook release.yml --extra-vars "hosts=vipers user=starbuck"
Ansible 1.2中你也可以给extra-vars传递JSON,比如:
--extra-vars '{"pacman":"mrs","ghosts":["inky","pinky","clyde","sue"]}'
Ansible 1.3中,实用”@”语法可以为extra-vars传递JSON文件:
--extra-vars "@some_file.json"
变量的优先级:
* extra vars (-e in the command line) always win
* then comes connection variables defined in inventory (ansible_ssh_user, etc)
* then comes "most everything else" (command line switches, vars in play, included vars, role vars, etc)
* then comes the rest of the variables defined in inventory
* then comes facts discovered about a system
* then "role defaults", which are the most "defaulty" and lose in priority to everything.
* extra vars (在命令行中使用 -e)优先级最高
* 然后是在inventory中定义的连接变量(比如ansible_ssh_user)
* 接着是大多数的其它变量(命令行转换,play中的变量,included的变量,role中的变量等)
* 然后是在inventory定义的其它变量
* 然后是由系统发现的facts
* 然后是 "role默认变量", 这个是最默认的值,很容易丧失优先权
小例子:
root@alexworkstation:~/ans/book# cat var.yaml
---
- hosts: k8s-k8s1
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: write a test file
command: touch {{ ansible_date_time.weekday }} #这个变量从facts引用
root@alexworkstation:~/ans/book# ansible-playbook var.yaml -i ../nodes.txt
------------------------------------------------------------------------
条件的选择
when语句
例子1:
tasks:
- name: "shutdown Debian flavored systems"
command: /sbin/shutdown -t now
when: ansible_os_family == "Debian"
想忽略某一错误,通过执行成功与否来做决定,我们可以像这样:
tasks:
- command: /bin/false
register: result
ignore_errors: True
- command: /bin/something
when: result|failed
- command: /bin/something_else
when: result|success
- command: /bin/still/something_else
when: result|skipped
有些时候你得到一个返回参数的值是一个字符串,并且你还想使用数学操作来比较它,那么你可以执行一下操作:
tasks:
- shell: echo "only on Red Hat 6, derivatives, and later"
when: ansible_os_family == "RedHat" and ansible_lsb.major_release|int >= 6
在playbooks 和 inventory中定义的变量都可以使用. 下面一个例子,就是基于布尔值来决定一个任务是否被执行:
vars:
epic: true
一个条件选择执行也许看起来像这样:
tasks:
- shell: echo "This certainly is epic!"
when: epic
或者像这样:
tasks:
- shell: echo "This certainly isn't epic!"
when: not epic
如果一个变量不存在,你可以使用Jinja2的`defined`命令跳过或略过.例如:
tasks:
- shell: echo "I've got '{{ foo }}' and am not afraid to use it!"
when: foo is defined
- fail: msg="Bailing out. this play requires 'bar'"
when: bar is not defined
playbook显示命令的输出:
---
- hosts: test
gather_facts: F #开启debug
vars:
war: "ps -ef | grep tomcat | grep -v grep | awk '{print $2}'"
tasks:
- name: stop tomcat
shell: nohup /bin/bash /tmp/stop_tomcat.sh&
ignore_errors: True
register: tomcat_out #定义变量存储返回的结果
- name: show 结果 #定义输出结果的task
debug: var=tomcat_out verbosity=0 #debug的模块显示输出的记过
- name: back war
shell: cp /home/admin/taobao-tomcat-production-7.0.59.3/deploy/ROOT.war /tmp/
- name: remove romate dir
file: path=/home/admin/taobao-tomcat-production-7.0.59.3/deploy/ROOT state=absent
- name: remove romate war
file: path=/home/admin/taobao-tomcat-production-7.0.59.3/deploy/ROOT.war state=absent
- name: copy war
copy: src=/home/admin/.jenkins/jobs/NET-hangfa/workspace/aecc_purchase_portal_web/xx.war dest=/home/admin/taobao-tomcat-production-7.0.59.3/deploy/ROOT.war owner=admin group=wheel mode=0644
- name: start tomcat
shell: nohup sh /home/admin/taobao-tomcat-production-7.0.59.3/bin/startup.sh &
- name: tomcatalive
shell: "{{war}}"
register: check
- name: show
debug: var=check.stdout verbosity=0 #check.stdout 显示出的信息会看的更清晰点
如果你的很多任务都共享同样的条件语句的话,可以在选择语句后面添加inlcudes语句,参见下面事例. 这个特性并不适用于playbook的inclues,只有task 的 includes适用.所有的task都会被检验, 选择会应用到所有的task上面:
- include: tasks/sometasks.yml
when: "'reticulating splines' in output"
或者应用于role:
- hosts: webservers
roles:
- { role: debian_stock_config, when: ansible_os_family == 'Debian' }
在系统中使用这个方法但是并不能匹配某些标准时,你会发现在Ansible中,有很多默认’skipped’的结果. 详情参见:doc:modules 文档中的 ‘group_by’ 模块, 你会找到更加赏心悦目的方法来解决这个问题.
例子 :可以多准备几个文件,xxx.yml 不同系统引入不同的yml
---
- hosts: all
remote_user: root
vars_files:
- "vars/common.yml"
- [ "vars/{{ ansible_os_family }}.yml", "vars/os_defaults.yml" ]
tasks:
- name: make sure apache is running
service: name={{ apache }} state=running
‘ansible_os_family’ 已经被导入到为vars_files定义的文件名列表中了.
提醒一下,很多的不同的YAML文件只是包含键和值:
---
# for vars/CentOS.yml
apache: httpd
somethingelse: 42
这个具体事怎么工作的呢? 如果操作系统是’CentOS’, Ansible导入的第一个文件将是’vars/CentOS.yml’,紧接着 是’/var/os_defaults.yml’,
如果这个文件不存在.而且在列表中没有找到,就会报错. 在Debian,最先查看的将是’vars/Debian.yml’而不是’vars/CentOS.yml’,
如果没找到,则寻找默认文件’vars/os_defaults.yml’
注册变量,绑定变量,register
这个 ‘register’ 关键词决定了把结果存储在哪个变量中.结果参数可以用在模版中,动作条目,或者 when 语句. 像这样(这是一个浅显的例子):
- name: test play
hosts: all
tasks:
- shell: cat /etc/motd
register: motd_contents
- shell: echo "motd contains the word hi"
when: motd_contents.stdout.find('hi') != -1
这个注册后的参数的内容为字符串’stdout’是可以访问.
这个注册了以后的结果,如果像上面展示的,可以转化为一个list(或者已经是一个list),就可以在任务中的”with_items”中使用.
“stdout_lines”在对象中已经可以访问了,当然如果你喜欢也可以调用 “home_dirs.stdout.split()” , 也可以用其它字段切割:
- name: registered variable usage as a with_items list
hosts: all
tasks:
- name: retrieve the list of home directories
command: ls /home
register: home_dirs
- name: add home dirs to the backup spooler
file: path=/mnt/bkspool/{{ item }} src=/home/{{ item }} state=link
with_items: home_dirs.stdout_lines
# same as with_items: home_dirs.stdout.split()
----------------------------------------------------------
循环
标准循环
- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
也可以用hash字典:
- name: add several users
user: name={{ item.name }} state=present groups={{ item.groups }}
with_items:
- { name: 'testuser1', groups: 'wheel' }
- { name: 'testuser2', groups: 'root' }
嵌套循环:
- 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' ]
嵌套循环 + 预定义变量:
- name: here, 'users' contains the above list of employees
mysql_user: name={{ item[0] }} priv={{ item[1] }}.*:ALL append_privs=yes password=foo
with_nested:
- "{{users}}"
- [ 'clientdb', 'employeedb', 'providerdb' ]
对哈希hash表使用循环:
假如你有以下变量:
---
users:
alice:
name: Alice Appleworth
telephone: 123-456-7890
bob:
name: Bob Bananarama
telephone: 987-654-3210
你想打印出每个用户的名称和电话号码.你可以使用 with_dict 来循环哈希表中的元素:
tasks:
- name: Print phone records
debug: msg="User {{ item.key }} is {{ item.value.name }} ({{ item.value.telephone }})"
with_dict: "{{users}}"
对文件列表循环:
with_fileglob 可以以非递归的方式来模式匹配单个目录中的文件.如下面所示:
---
- hosts: all
tasks:
# first ensure our target directory exists
- file: dest=/etc/fooapp state=directory
# copy each file over that matches the given pattern
- copy: src={{ item }} dest=/etc/fooapp/ owner=root mode=600
with_fileglob:
- /playbooks/files/fooapp/*
Do-Until循环
有时你想重试一个任务直到达到某个条件.比如下面这个例子:
- action: shell /usr/bin/foo
register: result
until: result.stdout.find("all systems go") != -1
retries: 5
delay: 10
上面的例子递归运行shell模块,直到模块结果中的stdout输出中包含”all systems go”字符串,或者该任务按照10秒的延迟重试超过5次.”retries”和”delay”的默认值分别是3和5.
该任务返回最后一个任务返回的结果.单次重试的结果可以使用-vv选项来查看. 被注册的变量会有一个新的属性’attempts’,值为该任务重试的次数.
----------------------------------------------------------------------
异步操作和轮询:
默认情况下playbook中的任务执行时会一直保持连接,直到该任务在每个节点都执行完毕.有时这是不必要的,比如有些操作运行时间比SSH超时时间还要长.
解决该问题最简单的方式是一起执行它们,然后轮询直到任务执行完毕.
你也可以对执行时间非常长(有可能遭遇超时)的操作使用异步模式.
为了异步启动一个任务,可以指定其最大超时时间以及轮询其状态的频率.如果你没有为 poll 指定值,那么默认的轮询频率是10秒钟:
---
- hosts: all
remote_user: root
tasks:
- name: simulate long running op (15 sec), wait for up to 45 sec, poll every 5 sec
command: /bin/sleep 15
async: 45 #最大超时时间,45秒
poll: 5 #poll,拉取值的间隔时间。如果poll值为0,那么会启用 启动并忽略。
当你想对 “启动并忽略” 做个变种,改为”启动并忽略,稍后再检查”,你可以使用以下方式执行任务:
---
# Requires ansible 1.8+
- name: 'YUM - fire and forget task'
yum: name=docker-io state=installed
async: 1000
poll: 0
register: yum_sleeper
- name: 'YUM - check on fire and forget task'
async_status: jid={{ yum_sleeper.ansible_job_id }}
register: job_result
until: job_result.finished
retries: 30
-------------------------------
check mode 检查模式 dry run
当以 --check 参数来运行 ansible-playbook 时,将不会对远程的系统作出任何更改.
相对的,任何带有检测功能的模块(这几乎包含了所有的主要核心模块,但这不要求所有的模块都需支持.)
只要支持 ‘检测模式’ 将会报告它们会做出什么改变而不是直接进行改变.其他不支持检测模式的模块将既不响应也不提出相应的报告.
检测模式只是一种模拟.如果你的playbook是以先前命令的执行结果作为条件的话,那它可能对你就没有什么大用处了.
但是对于基于一次一节点的基础配置管理的使用情形来说是很有用.
Example:
ansible-playbook foo.yml --check
-----------------
一个ubuntu1804安装docker的例子
cat installdocker.yaml --- - hosts: rancherc vars: http_port: 80 max_clients: 200 remote_user: root tasks: - name: init aliyun apt copy: src=/etc/apt/sources.list dest=/etc/apt/sources.list - name: do apt update apt: update_cache=true - name: copy zonefile shell: cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime - name: write Lang shell: echo 'LANG="en_US.UTF-8"' >> /etc/profile - name: source profile shell: . /etc/profile - name: disable dns shell: systemctl disable systemd-resolved.service - name: stop dns shell: systemctl stop systemd-resolved.service - name: add host in /etc/hosts shell: echo "{{ ansible_ens33.ipv4.address }} {{ ansible_hostname }}" >>/etc/hosts - name: delete resolv.conf file: dest=/etc/resolv.conf state=absent - name: add new resolv.conf shell: echo "nameserver 114.114.114.114\nnameserver 8.8.8.8">>/etc/resolv.conf - name: add sysctl.conf shell: echo "net.bridge.bridge-nf-call-ip6tables=1\nnet.bridge.bridge-nf-call-iptables=1\nnet.ipv4.ip_forward=1\nnet.ipv4.conf.all.forwarding=1\nnet.ipv4.neigh.default.gc_thresh1=4096\nnet.ipv4.neigh.default.gc_thresh2=6144\nnet.ipv4.neigh.default.gc_thresh3=8192\nnet.ipv4.neigh.default.gc_interval=60\nnet.ipv4.neigh.default.gc_stale_time=120" >> /etc/sysctl.conf - name: modify ulimit shell: echo "root soft nofile 65535\nroot hard nofile 65536\n* soft nofile 65535\n* hard nofile 65536" >> /etc/security/limits.conf - name: wget mod.txt get_url: url=http://www.alexman.cn/mod.txt dest=/root/ - name: modprobe mod shell: for i in `cat /root/mod.txt`;do modprobe $i;done - name: sysctl -p shell: sysctl -p - name: install docker apt: name=docker.io 运行:ansible-playbook -i ../nodes.txt installdocker.yaml