Ansible详解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ansible详解相关的知识,希望对你有一定的参考价值。
一、template模板
二、playbook中的条件判断
三、PlayBook中的循环
四、角色(roles)
一、template模板
template使用了Jinjia2格式作为文件模版,进行文档内变量的替换的模块。它的每次使用都会被ansible标记为”changed”状态。基于模板方式生成一个文件复制到远程主机
常用参数:
参数名 是否必须 默认值 选项 说明 backup no no yes/no 建立个包括timestamp在内的文件备份,以备不时之需. dest yes 远程节点上的绝对路径,用于放置template文件。//必须是绝对路径 group no 设置远程节点上的的template文件的所属用户组 mode no 设置远程节点上的template文件权限。类似Linux中chmod的用法 //group,owner owner no 设置远程节点上的template文件所属用户 src yes 本地Jinjia2模版的template文件位置。 //绝对或者相对路径
一般编程语言都有把自己嵌入到文本的模板语言
php:直接嵌入
python:Jinja2 //ansible就是python写的
Jinja2 中常用的编程元素
字面量:字符串,单引号或者双引号引用即可
数字:整数和浮点数
列表:[item1,item2,...]
元祖:(item1,itme2,...) //不可变
字典:{key1:value1,key2:value2,...}
布尔型:true/false
算数运算:
+,-,*,/,%, //,** //:表示只要熵
比较运算:
==,!=,>=,<=,<,
逻辑运算符:
and,or,not
ansible-doc -s template
利用模板:实现对不同主机的nginx配置成不同的启动processor
vim nginx.conf.j2
worker_processes {{ ansible_processor_vcpus }}; //使用模板变量
listen {{ http_port }}; //自定义变量
注:这个参数是在setup模板中
worker_processes {{ ansible_processor_vcpus-1 }}; //可以直接增加或减去
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf mode=0644
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=bin group=wheel mode="u=rw,g=r,o=r"
vim ansible/hosts
[websrvs]
192.168.4.100 http_port=888
192.168.4.116 http_port=808 //使用主机变量
[[email protected] ~]# cat nginx.yaml
- hosts: websrvs remote_user: root tasks: - name: install nginx yum: name=nginx state=present - name: install conf template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf mode=0644 notify: restart nginx tags: instconf - name: start nginx service service: name=nginx state=started handlers: - name: restart nginx service: name=nginx state=restarted
ansible-playbook --check nginx.yaml
ansible-playbook nginx.yaml
注意:6和7的配置nginx配置文件不一样
执行结果
RUNNING HANDLER [restart nginx]
************************************************
changed: [192.168.4.110] //发生改变的话,就会执行 restart nginx
changed: [192.168.4.106]
handlers:用于当关注的资源发生变化时触发一定的操作。
“notify”这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作
取而代之,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作。
二、playbook中的条件判断
多个条件:and/when/or
1.条件测试:tasks上使用when语句,在tasks上使用,Jinja2的语法格式。根据不同的OS分配不同的机制
字符串要加引号{单双都可},数值一定不加引号
ansible all -m setup | grep "ansible_distribution" //版本信息
"ansible_distribution": "CentOS",
"ansible_distribution_major_version": "6",
"ansible_distribution_release": "Final",
"ansible_distribution_version": "6.6",
tasks:
- name: install conf file
template: src=nginx.conf.7
when: ansible_distribution_major_version == '7' 4tasks:
- name: install conf file
template: src=nginx.conf.6
when: ansible_distribution_major_version == '6'
条件测试1: when
- hosts: websrvs remote_user: root tasks: - name: copy file 6 template: src=/tmp/6.txt dest=/tmp when: ansible_distribution_major_version == '6' notify: restart nginx - name: copy file 7 template: src=/tmp/7.txt dest=/tmp when: ansible_distribution_major_version == '7' notify: restart nginx handlers: - name: restart nginx service: name=nginx state=restarted
2.register
示例,判断sda6是否存在。存在就执行一些相应的脚本,则可以为该判断注册一个register变量,并用它来判断是否存在,存在返回 succeeded, 失败就是 failed.
- name: Create a register to represent the status if the /dev/sda6 exsited shell: df -h | grep sda6 register: dev_sda6_result ignore_errors: True tags: docker - name: Copy docker-thinpool.sh to all hosts copy: src=docker-thinpool.sh dest=/usr/bin/docker-thinpool mode=0755 when: dev_sda6_result | succeeded tags: docker
假如我们想忽略某一错误,通过执行成功与否来做决定,我们可以像这样:
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
三、PlayBook中的循环
循环:迭代,需要重复执行的任务;
例如需要同时安装,nginx,httpd,php-fpm,php-mysql,mariabd等
对迭代项的引用,固定变量名为"item"
而后,要在task中使用with_items给定要迭代的元素列表
列表方法:
字符串:
字典:
1.标准循环:
- name: install some packages yum: name={{ item }} state=present with_items: - nginx - memcached - php-fpm //将可以安装多个软件同时安装 循环测试脚本:item [[email protected] ~]# cat e.yaml - hosts: websrvs remote_user: root tasks: - name: install pkgs yum: name={{ item }} state=present with_items: - telnet - vim - tree
循环测试脚本3.
创建三个用户分别属于不同组
[[email protected] ~]# cat f.yaml
- hosts: websrvs remote_user: root tasks: - name: group add group: name={{ item }} state=present //注意:引用的时候使用的是{{ }}没有s,列举参数的时候使用的是复数,items with_items: - group11 - group12 - group13 - name: add users user: name={{ item.name }} group={{ item.group }} state=present with_items: - { name: 'user11', group: 'group11' } - { name: 'user12', group: 'group12' } - { name: 'user13', group: 'group13' }
==============================
[[email protected] ~]# cat c.yaml
- hosts: testweb remote_user: root tasks: - name: install user user: name={{ item.name }} state=present groups={{ item.groups }} with_items: - { name: 'testuser1', groups: 'wheel' } - { name: 'testuser2', groups: 'root' }
//创建testuser1{wheel},testuser2{root}
注意:
1.hosts 不是host
2.严格对齐,列表和内容分开
3.name: 'user11' //中间必须有空格,字符必须用引号,
4.目标主机存在user11或其中一个用户的话,也会返回错误
5.whih_itmes后的内容为下一个key-value (先加空格)
2.嵌套循环:
-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'] //表示item[0],nested:嵌套 -['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' ]
[[email protected] ~]# cat c.yaml
- hosts: testweb remote_user: root tasks: - name: install user 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 command: "echo name={{ item[0] }} priv={{ item[1] }} test={{ item[2] }}" with_nested: - [ 'alice', 'bob' ] - [ 'clientdb', 'employeedb', 'providerdb' ] - [ '1', '2', ] tags: netsted
输出:
skipping: [192.168.2.122] => (item=[u'alice', u'clientdb', u'1']) skipping: [192.168.2.122] => (item=[u'alice', u'clientdb', u'2']) skipping: [192.168.2.122] => (item=[u'alice', u'employeedb', u'1']) skipping: [192.168.2.122] => (item=[u'alice', u'employeedb', u'2']) skipping: [192.168.2.122] => (item=[u'alice', u'providerdb', u'1']) skipping: [192.168.2.122] => (item=[u'alice', u'providerdb', u'2']) skipping: [192.168.2.122] => (item=[u'bob', u'clientdb', u'1']) skipping: [192.168.2.122] => (item=[u'bob', u'clientdb', u'2']) skipping: [192.168.2.122] => (item=[u'bob', u'employeedb', u'1']) skipping: [192.168.2.122] => (item=[u'bob', u'employeedb', u'2']) skipping: [192.168.2.122] => (item=[u'bob', u'providerdb', u'1']) skipping: [192.168.2.122] => (item=[u'bob', u'providerdb', u'2'])
3.字典循环
假如你有以下变量:
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}}"
4.遍历文件whith_file,whith_fileglob
with_file 是将每个文件的文件内容作为item的值
- 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必须要用 “-” - copy: src={{ item }} dest=/etc/fooapp/ owner=root mode=600 with_fileglob: - /playbooks/files/fooapp/*
with_fileglob 是将每个文件的全路径作为item的值, 在文件目录下是非递归的, 如果是在role里面应用改循环, 默认路径是roles/role_name/files_directory
5.并行数据循环
已知变量:
alpha: [ 'a', 'b', 'c', 'd' ]
numbers: [ 1, 2, 3, 4 ]
如果你想得到’(a, 1)’和’(b, 2)’之类的集合.可以使用’with_together’:
tasks:
- debug: msg="{{ item.0 }} and {{ item.1 }}"
with_together:
- "{{alpha}}"
- "{{numbers}}"
还有更多的循环介绍方法请参考本文尾部链接地址...
四、角色:(roles)
一个主机可以担任多种角色:
定义为多个身份,用的时候直接调用该身份即可
角色名就是目录名,任何角色都不能引用自己所属目录之外的其他目录文件
roles/
mysql/
httpd/
nginx/
memcached/
每个角色,以特定的层级目录结构进行组织: 注意:大多数都是复数"s",除了meta
mysql/
files/ 存放由copy或script模块等调用的文件
templates/ template模块查找所需要的模板文件目录;
handlers/ 至少应该包含一个名为main.yml文件
vars/ 至少一个main.yml
tasks/ 基本元素:至少一个名为main.yml的文件,其他的文件需要在此文件中通过include进行包含
meta/ main.yml,定义当前角色的特殊设定,及其依赖关系
default/ 设定默认变量时使用此目录中的main.yml文件
调用角色:
- hosts: websrvs
remote_user: root
roles:
- mysql //会自动到mysql目录中跑一遍
- memcached
- nginx
mkdir /etc/ansible/roles/nginx/{files,tasks,templates,handlers,vars,default,meta} -pv
cd /etc/ansible/roles/nginx/
1.tasks
[[email protected] nginx]# cat tasks/main.yml
- name: install nginx pkg yum: name=nginx state=present - name: install conf file template: src=nginx.conf dest=/etc/nginx/nginx.conf.test ///nginx.conf不在同级目录,但是role可以直接识别为template中的文件 - name: start nginx service: name=nginx state=started enabled=true
templates 目录中有存放的nginx.conf
2.在其他地方创建nginx.yaml //这个可以放在其他地方
- hosts: websrvs remote_user: root roles: - nginx
执行:
ansible-playbook --check nginx.yaml
/etc/ansible/roles/nginx/ ├── default ├── files ├── handlers ├── meta ├── tasks │ └── main.yml ├── templates │ └── nginx.conf └── vars
3.添加handler
修改handlers/main.yml
- name: restart nginx //注意,前面的 - 不可少,代表是handler的一个清单
service: name=nginx state=restarted
创建tasks/main.yml
- name: install nginx pkg yum: name=nginx state=present - name: install conf file template: src=nginx.conf dest=/etc/nginx/nginx.conf.test notify: restart nginx tags: instconf - name: start nginx service: name=nginx state=started enabled=true
修改一下nginx.conf //否则不会触发handler
ansible-playbook -t instconf --check g.yaml
4.变量
[[email protected] yaml]# cat h.yaml
- hosts: websrvs remote_user: root vars: - username: testuser1 - groupname: testgroup1 tasks: - name: create group group: name={{ groupname }} state=present - name: create user user: name={{ username }} group={{ groupname }} state=present
在playbook中定义变量的方法
vars:
- var1: value1
- var2: value2
ansible-playbook -e "groupname=mygrp1" -e "username=myuser" --check h.yaml
//可以覆盖变量,在命令行中定义的变量,会覆盖
5.变量使用,roles中
vim nginx/vars/main.yml
username: nginx
vim templates/nginx.conf
user {{ username }} //让nginx以该用户的身份运行
其他不修改
ansible
问题:
[[email protected] yaml]# ansible-playbook --check g.yaml
ERROR! The vars/main.yml file for role 'nginx' must contain a dictio
nary of variables
原因:vars/main.yml 前面不需要 - ,和其他的main.yml不一样
ansible-playbook -e "username=adm" --check nginx.yml //假如想改变运行nginx的用户,直接修改即可
6.在playbook中调用角色方法2
vim nginx.yaml
- hosts: websrvs
remote_user: root
roles:
- {role: nginx, username: nginx} //向该角色传递变量
键role用于指定角色名称,后续的k/v用于传递变量给角色
还可以基于条件测试,实现角色调用;
例如:
roles:
- {role: nginx,when: "ansible_distribution_major_version == '7' }
//条件满足时,应用该角色
[[email protected] yaml]# cat i.yaml
- hosts: websrvs
remote_user: root
roles:
- { role: nginx, username: nginx, when: "ansible_distribution_major_version == '7'" }
//只有在OS为7才会执行
7.安装memcached,占用内从空间为当前可用空间的1/3
mkdir -pv memcached/{tasks,vars,templates,hanlers}
vim tasks/main.yml - name: install pack yum: name=memcached state=present - name: install conf template: src=memcached.j2 dest=/etc/sysconfig/memcached notify: restart memcached tags: memconf - name: start memcached service: name=memcached state=started enabled=true vim templates/memcached PORT="11211" USER="memcached" MAXCONN="1024" CACHESIZE="{{ ansible_memtotal_mb//4 }}" //除以4,可能是小数,因此// 取出整数 OPTIONS="" vim handlers/main.yml - name: restart memcached service: name=memcached state=restarted vim lnm.yaml //同时调用两个role - hosts: websrvs remote_user: root - roles: - { role: nginx, when: ansible_distribution_version == '7' } - { role: memcached, when: ansible_hostname == 'memcached' }
ansible-playbook -t memconf lnm.yaml
出错原因:
1.main.yml中,template是没有s的,但是目录名是有s的
2.notify不是nofify
=======================================================
yaml和yml格式的区别:
1.yml不需要hosts,remote_user //这些在yaml中定义
- name: install pkgs
yum: name=memcached state=present
2.yaml一定要-hosts,-remote_user
- hosts: all
remote_user: root
roles:
- { role: nginx,when:ansible_distribution_version == '7' }
ansible all -m setup //查看所有内置变量
www.ansible.com.cn //站点,
推荐:参考ansible官方role的写法,自行创建role进行练习
http://blog.csdn.net/kellyseeme/article/details/50619562
http://www.ansible.com.cn/docs/playbooks_loops.html
https://www.cnblogs.com/v394435982/p/5593274.html
以上是关于Ansible详解的主要内容,如果未能解决你的问题,请参考以下文章