一、学习资源
https://www.jianshu.com/p/575ced3a08fa
http://www.ansible.com.cn/index.html
http://docs.ansible.com/
二、ansible命令的相关用法
指定test组使用shell模块执行uname -m命令
ansible -i /etc/ansible/hosts test -m shell -a 'uname -m'
本地执行date命令,默认模块command
ansible 127.0.0.1 -a 'date'
指定所有主机执行date
ansible all -a 'date'
指定所有主机执行date,并输入密码
ansible -i /etc/ansible/hosts -a 'date' -k
查看所有的模块
ansible-doc -a
查看copy模块的用法
ansible-doc -s copy
ansible-doc -s docker
查看docker的模块
ansible-doc -l |grep docker
查看命令运行的详细信息,有助于排错
ansible -i /etc/ansible/hosts test -m shell -a 'uname -m' -vvv
使用命令行的方式放到后台运行
放到后台去运行,然后查询ID,查看有没有跑完
[root@master ~]# ansible all -m ping -B 3600 -P 0
192.168.222.147 | SUCCESS => {
"ansible_job_id": "678581125189.1288",
"changed": true,
"finished": 0,
"results_file": "/root/.ansible_async/678581125189.1288",
"started": 1
}
192.168.222.146 | SUCCESS => {
"ansible_job_id": "36685447786.3154",
"changed": true,
"finished": 0,
"results_file": "/root/.ansible_async/36685447786.3154",
"started": 1
}
[root@master ~]# ansible all -m async_status -a 'jid=678581125189.1288'
192.168.222.147 | SUCCESS => {
"ansible_job_id": "678581125189.1288",
"changed": false,
"finished": 1,
"ping": "pong"
}
192.168.222.146 | FAILED! => {
"ansible_job_id": "678581125189.1288",
"changed": false,
"finished": 1,
"msg": "could not find job",
"started": 1
}
三、playbook
3.1)
如果你不需要获取被控机器的 fact 数据的话,你可以关闭获取 fact 数据功能。关闭之后,可以加快 ansible-playbook 的执行效率,尤其是你管理很大量的机器时,这非常明显。关闭获取 facts 很简单,只需要在 playbook 文件中加上“gather_facts: no”。
---
- 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
3.2)几种变量的使用方式
1、在hosts里面自定义变量
在hosts里面的主机组里面,添加key
[test]
192.168.222.146
192.168.222.147
[test:vars]
key=nima
用debug输出
---
- hosts: all
gather_facts: no
tasks:
- name: display var
debug: msg="{{key}}"
2、在playbook中定义变量,这个高于上面的优先级
---
- hosts: all
gather_facts: no
vars:
key: heihei
tasks:
- name: display var
debug: msg="{{key}}"
---
- hosts: all
gather_facts: no
vars:
key: heihei
ji: hermes
tasks:
- name: display var
debug: msg="{{key}}---{{ji}}"
3、通过文件定义变量var.yml
[root@master playbook]# cat var.yml
---
key3: weiwei
[root@master playbook]# cat var.yml
---
key3: weiwei
[root@master playbook]# cat test.yml
---
- hosts: all
gather_facts: no
vars_files:
- /etc/ansible/playbook/var.yml
tasks:
- name: display var
debug: msg="{{key3}}"
4、从命令行引入变量,内部需要先定义变量,这个优先级最高
ansible-playbook test.yml -e "key3=ni"
5、任务中传递的变量
[root@master playbook]# cat test.yml
---
- hosts: all
gather_facts: no
tasks:
- name: register var
shell: hostname
register: info //将处理的字典返回给info
- name: display var
debug: msg="{{info}}" //因为是Python写的,所以可以根据键获得值debug: msg="{{info.stdout}}"
3.3)playbook几种循环方式
6、循环列表
---
- hosts: all
gather_facts: no
tasks:
- name: debug loops
debug: msg="{{item}}"
with_items:
- one
- two
- three
- four
例如
---
- hosts: all
gather_facts: no
tasks:
- name: install
yum: name="{{item}}" state=present
with_items:
- nginx
- mysql
- php
- zabbix
7、循环字典
---
- hosts: all
tasks:
- name: dict
debug: msg="name--->{{item.key}}value--->{{item.value}}"
with_items:
- {key: "one",value: "va1"}
- {key: "two",value: "va2"}
8、嵌套循环
[root@master playbook]# cat qiantao.yml
---
- hosts: all
tasks:
- name: debug loops
debug: msg="name--->{{item[0]}} value--->{{item[1]}}"
with_nested:
- ['a','b']
- ['c','d','e']
9、散列循环,对于自定义的变量循环
---
- hosts: all
gather_facts: no
vars:
user:
shan:
name: shan
shell: bash
heihei:
name: heihei
shell: jjj
tasks:
- name: loop
debug: msg="{{item.key}}"
with_dict: "{{user}}"
10、文件循环
---
- 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/*
11、达到某条件终止循环
- shell: /usr/bin/foo
register: result
until: result.stdout.find("all systems go") != -1
retries: 5
delay: 10
[root@master playbook]# cat heihei.yml
---
- hosts: all
gather_facts: no
tasks:
- name: os
shell: /bin/uname -m
register: result
until: result.stdout == "i686"
retries: 3
delay: 5
3.4)条件判断when,when result|skipped这种方式是jinjia2的方式,result是执行命令的返回字典,当skipped为true的时候,当前task执行。
12、条件判断 when
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
---
- hosts: all
tasks:
- name: redhat install nginx
yum: name=nginx.i686 state=present
when: ansible_os_family == "RedHat"
- name: restart nginx
shell: /etc/init.d/nginx reload
when: ansible_os_family == "RedHat"
3.5)jinjia2过滤器
---
- hosts: all
gather_facts: no
vars:
list: [1,2,3,4]
one: "1"
str: "string"
ansible: "hermes"
tasks:
- name: print str
debug: msg="{{str}}"
- name: run commands
shell: df -h
register: info
- name: pprint info
debug: msg="{{info.stdout|pprint}}"
- name: info
debug: msg="{{info}}"
- name: debug conditionals filter
debug: msg="the run commands status is changed"
when: info|changed
- name: debug int caplitailize filter
debug: msg="the int value is===>{{one|int}} the lower value is===>{{str|capitalize}}"
- name: debug default filter
debug: msg="the variable value is===>{{ansible|default('ansible is not define')}}"
- name: debug list max and min filter
debug: msg="the list max value is==={{list|max}} and list min value is===>{{list|min}}"
- name: debug random filter
debug: msg="the list random value is {{list|random}} {{1000|random(1,10)}}"
- name: debug join
debug: msg="the top filter value is {{list|join("+")}}"
- name: debug replace
debug: msg="the replace value is {{str|replace("t","T")}}"
- name: debug regex_replace
debug: msg="the regex_replace value is {{str|regex_replace('.*tr(.*)$','weiwei')}}"
3.6)jinjia2语法逻辑控制,,需要使用template模块。
[root@master playbook]# cat f2.j2
{% set list=['one','two','three'] %}
{% for i in list %}
{{i}}
{% endfor%}
{% set list1=['one','two','three'] %}
{% for i in list1 %}
{% if i == 'one' %}
===>{{i}}
{% elif loop.index ==2 %}
===>{{i}}
{% else %}
===>{{i}}
{% endif %}
{% endfor %}
{% set dict={'key':'value'}%}
{% for key,value in dict.iteritems()%}
{{key}}===>{{value}}
{% endfor %}
{% set dict1={'key1':{'key2':'vlan'}}%}
{{dict1['key1']['key2']}}
[root@master playbook]# cat jinjia2.yml
---
- hosts: all
gather_facts: no
tasks:
- name: template
template: src=/etc/ansible/playbook/f2.j2 dest=/tmp/f2
四、Playbook的标准目录结构,标准很重要。
production # inventory file for production servers 关于生产环境服务器的清单文件
stage # inventory file for stage environment 关于 stage 环境的清单文件
group_vars/
group1 # here we assign variables to particular groups 这里我们给特定的组赋值
group2 # ""
host_vars/
hostname1 # if systems need specific variables, put them here 如果系统需要特定的变量,把它们放置在这里.
hostname2 # ""
library/ # if any custom modules, put them here (optional) 如果有自定义的模块,放在这里(可选)
filter_plugins/ # if any custom filter plugins, put them here (optional) 如果有自定义的过滤插件,放在这里(可选)
site.yml # master playbook 主 playbook
webservers.yml # playbook for webserver tier Web 服务器的 playbook
dbservers.yml # playbook for dbserver tier 数据库服务器的 playbook
roles/
common/ # this hierarchy represents a "role" 这里的结构代表了一个 "role"
tasks/ #
main.yml # <-- tasks file can include smaller files if warranted
handlers/ #
main.yml # <-- handlers file
templates/ # <-- files for use with the template resource
ntp.conf.j2 # <------- templates end in .j2
files/ #
bar.txt # <-- files for use with the copy resource
foo.sh # <-- script files for use with the script resource
vars/ #
main.yml # <-- variables associated with this role
defaults/ #
main.yml # <-- default lower priority variables for this role
meta/ #
main.yml # <-- role dependencies
webtier/ # same kind of structure as "common" was above, done for the webtier role
monitoring/ # ""
fooapp/ # ""
五、接着是一个haproxy+lnmp的案例Playbook,通过角色来配置,内容很糙,学习阶段使用挺好。
5.1)目录结构
[root@master ansible]# tree .
.
├── all
├── ansible.cfg
├── group_vars
│ ├── haproxy
│ ├── mysql
│ └── nginx
├── hosts
├── roles
│ ├── base
│ │ ├── files
│ │ │ └── CentOS-Base.repo
│ │ └── tasks
│ │ └── main.yml
│ ├── haproxy
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── templates
│ │ └── haproxy.cfg.j2
│ ├── mysql
│ │ └── tasks
│ │ └── main.yml
│ └── nginx
│ ├── tasks
│ │ └── main.yml
│ └── templates
│ └── index.htm.j2
└── site.yml
5.2)主机配置
[nginx]
192.168.222.147
[haproxy]
192.168.222.146
5.3)所有的变量配置跟入口文件site.yml在同一个层级
[root@master ansible]# for i in `ls group_vars`;do echo $i;cat group_vars/$i;done
haproxy
---
mode: http
balance: roundrobin
mysql
---
user: ansible
password: ansible
database: ansible
nginx
---
nginx: nginx-1.12.2.tar.gz
php: php-7.1.12.tar.gz
5.4)入口文件site.yml
[root@master ansible]# cat site.yml
---
- name: replace yum
hosts: all
roles:
- base
- name: install nginx
hosts: nginx
roles:
- nginx
- name: install mysql
hosts: nginx
roles:
- mysql
- name: install haproxy
hosts: haproxy
roles:
- haproxy
5.5)base角色,用来同步被控制机的yum源于控制机一致。
[root@master base]# tree .
.
├── files
│ └── CentOS-Base.repo
└── tasks
└── main.yml
[root@master tasks]# cat main.yml
---
- copy: src=CentOS-Base.repo dest=/etc/yum.repos.d/CentOS-Base.repo
5.6)nginx角色
[root@master nginx]# tree .
.
├── tasks
│ └── main.yml
└── templates
└── index.htm.j2
[root@master tasks]# cat main.yml
---
- yum: name=libtool-libs state=present
- shell: mkdir -p /usr/local/services
- shell: mkdir /data/soft -p
- copy: src=/data/{{nginx}}.rpm dest=/data/soft/{{nginx}}.rpm
- copy: src=/data/{{php}}.rpm dest=/data/soft/{{php}}.rpm
- shell: rpm -qa|grep {{nginx}} || rpm -ivh /data/soft/{{nginx}}
- shell: rpm -qa|grep {{php}} || rpm -ivh /data/soft/{{php}}
- shell: chdir=/usr/local/servers/ test -d nginx
- shell: chdir=/usr/local/servers/ test -d php
- shell: netstat -tnlp|grep nginx || /sbin/service nginx start
- template: src=index.htm.j2 dest=/data/htdocs/www/index.htm
[root@master templates]# cat index.htm.j2
{{ ansible_default_ipv4.address}}
5.7)mysql角色
[root@master tasks]# cat main.yml
---
- name: install mysql-server
yum: name={{item}} state=installed
with_items:
- mysql-server
- mysql-python
- name: start msyql
service: name=mysqld state=started enabled=yes
- name: create database
mysql_db: name={{database}} state=present
- name: create user
mysql_user: name={{user}} password={{password}} priv={{database}}.*:ALL host='%' state=present
5.8)haproxy角色
[root@master haproxy]# tree .
.
├── tasks
│ └── main.yml
└── templates
└── haproxy.cfg.j2
[root@master tasks]# cat main.yml
---
- name: install haproxy
yum: name={{item}} state=present
with_items:
- haproxy
- name: copyhaproxy.conf
template: src=haproxy.cfg.j2 dest=/etc/haproxy/haproxy.cfg owner=root group=root mode=644
- name: start haproxy
service: name=haproxy state=started enabled=yes
[root@master templates]# cat haproxy.cfg.j2
global
log 127.0.0.1 local0 info
log 127.0.0.1 local1 warning
maxconn 4096
chroot /usr/local/haproxy #改变当前的工作目录
pidfile /usr/local/haproxy/conf/haproxy.pid
user root
group root
daemon
stats socket /var/run/haproxy.sock mode 600 level admin
stats timeout 2m
defaults
log global
mode {{mode}}
option http-keep-alive
option httplog
option dontlognull
retries 3
maxconn 2000
timeout connect 5000ms #??server???5s
timeout client 50000ms #???????50s
timeout server 50000ms #server?????50s
frontend ansible
bind {{ansible_default_ipv4.address}}:80
mode {{mode}}
#option httplog
log global
default_backend nginx
backend nginx
option forwardfor header X-REAL-IP
option httpchk HEAD / HTTP/1.0
balance {{balance}}
#server web-node1 192.168.222.147:8080 check source 192.168.222.140:1025-65000 inter 2000 rise 30 fall 15
{% for host in groups['nginx'] %} #循环的NGINX组
server {{hostvars[host].get('ansible_hostname')}} {{hostvars[host].get('inventory_hostname')}}:80 check inter 3000 rise 3 fall 2
{% endfor %}
六、ansible优化执行速度,标准化,可以参考如下链接,我写的也很糙,时间不多。
https://blog.csdn.net/felix_yujing/article/details/76796522
1、开启ssh长连接
在openssh5.6以后的版本就可以支持multiplexing,,,不用管被管理端,只要改管理端
[root@master ansible]# ssh -v
vim ansible.cfg
ssh_args = -C -o ControlMaster=auto -o ControlPersist=5d
2、开启pipelining
将操作变成命令给远端去执行,而不是变成文件到远端去执行。,,但是这个需要在被管理端进行一些配置修改
# Enabling pipelining reduces the number of SSH operations required to
# execute a module on the remote server. This can result in a significant
# performance improvement when enabled, however when using "sudo:" you must
# first disable 'requiretty' in /etc/sudoers
#
# By default, this option is disabled to preserve compatibility with
# sudoers configurations that have requiretty (the default on many distros).
#
#pipelining = False
pipelining = True
3、开启accelerate模式,依赖ansible中的长连接,开启这个需要在管理端和被管理端安装python-keyczar
[accelerate]
accelerate_port = 5099
accelerate_timeout = 30
accelerate_connect_timeout = 5.0
4、设置facts缓存
gathering = smart
fact_caching_timeout = 86400
fact_caching_connection = /dev/shm/ansible_fact_cache
ansible还支持把数据放到redis里面,读取速度更快
gathering = smart
fact_caching_timeout = 86400
fact_caching = reids