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    

 

posted @ 2020-06-08 11:01  alexhe  阅读(246)  评论(0编辑  收藏  举报