一、学习资源
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