ansible基础,有这篇就够了

ansible安装

1,安装相关的扩展

yum install -y http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

2,直接yum安装

yum -y install ansible

配置清单

清单的默认路径为/etc/ansible/hosts,以下格式都是受支持的

#直接写IP地址,管理麻烦
192.168.5.117
192.168.4.120
192.168.5.91
#[xxxx]分组的意思名字可以见名知意
#将主机分组
[webserver]
192.168.5.117
192.168.4.120
#指定端口号,因为ansible是基于ssh的有时候为了安全会改掉默认的22端口,这时候我们这里需要指定端口
[dbserver]
192.168.5.117:2222
192.168.4.120:2333
#基于ip段甚至域名
[staticserver]
192.168.5.117
192.168.4.12[0:2]
db-[a-z].example.com

ansible是通过ssh实现配置管理远程主机,我们可以配置基于ansible段密钥认证的方式连和各个节点建立关系,我这里做测试就一直敲回车生成了,但是为了安全建议加密

ansible <host-pattern> [-m module_name] [-a args]
ansible +被管理的主机(ALL) +模块  +参数
    --version              显示版本
    -m module              指定模块,默认为command
    -v                     详细过程 –vv -vvv更详细
    --list-hosts           显示主机列表,可简写 --list
    -k, --ask-pass         提示输入ssh连接密码,默认Key验证
    -C, --check            检查,并不执行
    -T, --timeout=TIMEOUT  执行命令的超时时间,默认10s
    -u, --user=REMOTE_USER 执行远程执行的用户
    -b, --become           代替旧版的sudo切换
        --become-user=USERNAME 指定sudo的runas用户,默认为root
    -K, --ask-become-pass  提示输入sudo时的口令
ansible主机上生成密钥对
ssh-keygen  #生成密钥对
ssh-copy-id 192.168.5.117  #拷贝到各个节点

我这里的清单如下,后面没有特殊说明都是以本清单进行测试

[webserver]
192.168.5.117
192.168.4.120
[dbserver]
192.168.5.117
192.168.5.91

使用ping模块测试是否可以跳过密码进行连接

[root@localhost ~]# ansible -m ping webserver
192.168.5.117 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
192.168.4.120 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

ansible的主机模式
all :表示清单里所有主机

[root@localhost ~]# ansible all -m ping
192.168.5.91 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
192.168.5.117 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
192.168.4.120 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

星号 * :通配符

[root@localhost ~]# ansible *server -m ping
192.168.5.117 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
192.168.5.91 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
192.168.4.120 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
[root@localhost ~]# ansible 192.168.5.* -m ping
192.168.5.117 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
192.168.5.91 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

或关系,即webserver或者dbserver中存在的主机

[root@localhost ~]# ansible webserver:dbserver -m ping
192.168.4.120 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
192.168.5.117 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
192.168.5.91 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

逻辑与,即存在于webserver并且存在于dbserver中的主机

[root@localhost ~]# ansible "webserver:&dbserver" -m ping
192.168.5.117 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

逻辑非,即在webserver中但是不在dbserver中

[root@localhost ~]# ansible 'webserver:&dbserver' -m ping
192.168.5.117 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

甚至还支持正则表达式这里就不贴了

ansible命令执行过程

1,加载自己的配置文件默认是/etc/ansible/ansible.cfg
2,加载自己对应的模块文件
3,通过ansible将模块或命令生成对应的临时py文件,并将该文件传输到远程服务器的对应执行用户的加目录下/root/.ansible/tmp/ansible-tmp-数字/xxx.py文件
4,给文件加X权限执行
5,执行并返回结果
6,删除临时py文件,sleep 0退出
 这个过程可以使用-vvv查看详细过程

执行状态的三种颜色
绿色:执行成功没有对目标主机做改变
黄色:执行成功对目标主机做了改变
红色:执行失败

ansible常用模块

  1. command模块,用于在远程主机上执行命令,command是默认模块,注意此模块对管道,特殊符号支持没那么友好,执行带特殊符号或者管道的命令会打印出命令不执行,对于这个问题我们可以使用另一个模块就是shell模块。
    举个使用的例子如下
#查看目标主机下/data
[root@localhost ~]# ansible webserver -m command -a 'ls /data'

相关选项示例


 1. removes  文件不存在就不执行
 [root@localhost ~]# ansible webserver -a 'removes=/etc/fs cat /etc/fstab'


2. creates   文件存在将不执行,文件不存在将执行
[root@localhost ~]# ansible webserver -a 'creates=/etc/fs cat /etc/fstab'


3.chdir  先切换到对应文件夹再执行相关操作
[root@localhost ~]# ansible webserver -a 'chdir=/data ls '

  1. shell模块 此模块和command类似,但是对于带有特殊符号的命令更加友好
    下面几个例子:
    查看远程主机名
[root@localhost ~]# ansible webserver -m shell -a 'echo $HOSTNAME'
  1. script模块 用来将本机脚本在远程主机上执行
    下面一个例子:
[root@localhost data]# ansible webserver -m script -a '/data/1.sh'

  1. Copy:从主控端复制文件到远程主机
    src : 源文件 指定拷贝文件的本地路径 (如果有/ 则拷贝目录内容,比拷贝目录本身)
    dest: 指定目标路径
    mode: 设置权限
    backup: 备份源文件
    content: 代替src 指定本机文件内容,生成目标主机文件
    下面举两个关于这些参数的例子
#将本地1.sh文件发送到远程主机并更改所属组和权限并对原来主机上的1.sh进行备份
[root@localhost data]# ansible webserver -m copy -a "src=/data/1.sh dest=/data/ showner=nginx mode=600 backup=yes"
#将aaaaaa直接写入1.txt并发送到远程主机
[root@localhost data]# ansible webserver -m copy -a "content='aaaaaa' dest=/tmp/1.txt"

  1. Fetch:从远程主机提取文件至主控端,copy相反,目前不支持目录,可以先打包,再提取文件,不过打包文件有一个指定的模块是unarchive,在本地会生成每个被管理主机不同编号的目录,不会发生文件名冲突
    打包一个文件举例:
[root@localhost data]# ansible webserver -m fetch -a 'src=/var/log/cron dest=/data/'
  1. file:文件相关的模块,举几个例子如下
#创建一个f3文件,path是文件路径,他还有name,dest两个别名,效果是一样的
[root@localhost log]# ansible webserver -m file -a 'path=/data/f3 state=touch'
#删除f3文件,absent表示删除,否定的意思,后面好多模块都会用到
[root@localhost log]# ansible webserver -m file -a 'path=/data/f3 state=absent'
#创建一个目录
[root@localhost log]# ansible webserver -m file -a 'path=/data/dir1 state=directory'
#删除目录
[root@localhost log]# ansible webserver -m file -a 'path=/data/dir1 state=absent'
#创建一个软连接,src表示源文件,path表示软连接的路径,state=link是创建软连接
[root@localhost log]# ansible webserver -m file -a 'src=/data path=/tmp/data.link state=link'
#删除软连接
[root@localhost log]# ansible webserver -m file -a 'path=/tmp/data.link state=absent'
#修改文件的属性
ansible webserver -m file -a 'path=/tmp/data.link owner=nginx mode=755'
  1. Hostname:管理主机名
#修改单台主机名
ansible 192.168.5.231 -m hostname 'name=daili01'
  1. Cron:计划任务
#支持时间:minute(分钟),hour(小时),day(天),month(月),weekday(星期)
配置每周1,3,5每分钟执行广播
job是要执行的命令,注意命令里有空格要用双引号引起来,name取个名字
ansible webserver -m cron -a 'minute=* weekday=1,3,5 job="/usr/bin/wall FBI warning" name=warningcron'
#disabled=true注释掉定时任务
ansible webserver -m cron -a 'disabled=true job="/usr/bin/wall FBI warning" name=warningcron'
#disabled=fasle启用定时任务
ansible webserver -m cron -a 'disabled=false job="/usr/bin/wall FBI warning" name=warningcron'
#state=absent删除定时任务
ansible webserver -m cron -a 'job="/usr/bin/wall FBI warning" name=warningcron state=absent'
  1. Yum:管理包
#安装vsftpd,其实后面还有个state参数,这个参数默认是present,安装的意思,这里省略没写
ansible webserver -m yum -a 'name=vsftpd'
#安装多个包,用逗号隔开
ansible webserver -m yum -a 'name=vsftpd,httpd,lrzsz'
#查看安装的所有程序列表
ansible webserver -m yum -a 'list=installed'
#卸载某个软件包
ansible webserver -m yum -a 'name=vsftpd state=absent'
#卸载多个包
ansible webserver -m yum -a 'name=vsftpd,httpd,lrzsz state=absent'
#更新yum缓存
ansible webserver -m yum -a 'update_cache=yes'
  1. Service:管理服务
#启动nginx服务,并设置开机自启
ansible webserver -m service -a 'name=nginx state=started enabled=yes'
#停止nginx服务
ansible webserver -m service -a 'name=nginx state=stopped'
#重启nginx服务
ansible webserver -m service -a 'name=nginx state=restarted'
#重新加载nginx服务
ansible webserver -m service -a 'name=nginx state=reloaded'
  1. User:管理用户
#创建一个用户,
    home   指定家目录路径
    system 指定系统账号
    uid  指定uid
    group  指定主组
    groups  指定辅助组
    remove 清除账户
    shell  指定shell类型
ansible webserver -m user -a 'name=zabbix system=yes home=/data/zabbix groups=root,bin uid=80'
#删除用户,remive   是否删除用户家目录,yes表示删除家目录
ansible webserver -m user -a 'name=zabbix state=absent remove=yes'
  1. Group:管理组
#创建一个组
ansible webserver -m group -a 'name=zabbix system=yes'
#删除组
ansible webserver -m group -a 'name=zabbix system=ansent'

ansible系列命令

  1. ansible-galaxy
    连接 https://galaxy.ansible.com 下载相应的roles(角色)
#安装一个角色
ansible-galaxy install geerlingguy.nginx
#查看所有以安装的角色
ansible-galaxy list
#删除角色
ansible-galaxy remove geerlingguy.nginx
  1. ansible-playbook
    运行一个剧本
运行一个剧本(playbook)例如
ansible-playbook hell0.yaml
  1. ansible-vault
    功能:管理加密解密yml文件
ansible-vault [create|decrypt|edit|encrypt|rekey|view]
    ansible-vault encrypt hello.yml 加密
    ansible-vault decrypt hello.yml 解密
    ansible-vault view hello.yml    查看
    ansible-vault edit hello.yml    编辑加密文件
    ansible-vault rekey hello.yml   修改口令
    ansible-vault create new.yml    创建新文件

playbook

playbook是由一个或多个"play"组成的列表。但是我们一般一个yml文件里只写一个play
play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。Task实际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按事先编排的机制执行预定义的动作
Playbook采用YAML语言编写

YAML介绍

YAML是一个可读性高的用来表达资料序列的格式。
YAML参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822等。
Clark Evans在2001年在首次发表了这种语言,另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者
YAML Ain't Markup Language,即YAML不是XML。
不过,在开发的这种语言时,YAML的意思其实是:"Yet Another Markup Language"(仍是一种标记语言)
特性
    YAML的可读性好
    YAML和脚本语言的交互性好
    YAML使用实现语言的数据类型
    YAML有一个一致的信息模型
    YAML易于实现
    YAML可以基于流来处理
    YAML表达能力强,扩展性好

更多的内容及规范参见:http://www.yaml.org

YAML语法简介

> 在单一档案中,可用连续三个连字号(-)区分多个档案。另外,还有选择性的连续三个点号( ... )用来表示档案结尾
> 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
> 使用#号注释代码
> 缩进必须是统一的,不能空格和tab混用
> 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的
> YAML文件内容是区别大小写的,k/v的值均需大小写敏感
> 多个k/v可同行写也可换行写,同行使用:分隔
> v可是个字符串,也可是另一个列表[]
> 一个完整的代码块功能需最少元素需包括 name 和 task
> 一个name只能包括一个task
> YAML文件扩展名通常为yml或yaml
List:列表,其所有元素均使用“-”打头
      列表代表同一类型的元素
示例:
# A list of tasty fruits
- Apple
- Orange
- Strawberry
- Mango

Dictionary:字典,通常由多个key与value构成 键值对
示例:
---
# An employee record
name: Example Developer
job: Developer
skill: Elite

也可以将key:value放置于{}中进行表示,用,分隔多个key:value
示例:
---
# An employee record
{name: Example Developer, job: Developer, skill: Elite}
YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。
其结构(Structure)通过空格来展示,序列(Sequence)里的项用"-"来代表,Map里的键值对用":"分隔
示例
    name: John Smith
    age: 41
    gender: Male
    spouse:
      name: Jane Smith
      age: 37
      gender: Female
    children:
      - name: Jimmy Smith
        age: 17
        gender: Male
      - name: Jenny Smith
        age 13
        gender: Female

Playbook核心元素

Hosts          执行的远程主机列表(应用在哪些主机上)

Tasks          任务集
这里有两种格式:
    (1) action: module arguments
    (2) module: arguments 建议使用  模块: 参数
    注意:shell和command模块后面跟命令,而非key=value

Variables      内置变量或自定义变量在playbook中调用

Templates模板  可替换模板文件中的变量并实现一些简单逻辑的文件

Handlers和notify结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行

tags标签       指定某条任务执行,用于选择运行playbook中的部分代码。
                ansible具有幂等性,因此会自动跳过没有变化的部分,
                即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。
                此时,如果确信其没有变化,就可以通过tags跳过此些代码片断
                ansible-playbook -t tagsname useradd.yml

下面来个示例,

[root@localhost ansible]# cat touch.yaml 
---
- hosts: webserver  #指明在哪个主机组上面执行
  remote_user: root  #指定远程主机上的用户
  
  tasks:
    - name: create new file
      file: name=/data/newfile state=touch  #创建一个文件
    - name: create new user
      user: name=test system=yes shell=/sbin/nologin  #创建一个用户
    - name: install package
      yum: name=httpd  #安装httpd
    - name: copy html
      copy: src=/var/www/html/index.php dest=/var/www/html  #把本机的页面文件拷贝到远程主机
    - name: start service
      service: name=httpd state=started enabled=yes  #启动httpd服务,并设为开机自启

对于刚写好的yml文件为了检查正确性可以使用-C参数,比如

ansible-playbook -C touch.yaml  #测试,不会对远程主机做任何更改

上面是一个简单的yaml文件,我们都清楚,因为yaml是从上到下依次执行,加入上一个模块执行失败下面的就不会继续执行,为了解决这个问题我们可以用以下的方式

tasks:
  - name: run this command and ignore the result
    shell: /usr/bin/somecommand || /bin/true  
    转错为正  如果命令失败则执行 true

或者使用ignore_errors来忽略错误信息
tasks:
  - name: run this command and ignore the result
    shell: /usr/bin/somecommand
    ignore_errors: True  忽略错误

我们做一个场景,比如下面这个例子

[root@localhost ansible]# cat touch.yaml 
---
- hosts: webserver
  remote_user: root
  
  tasks:
    - name: install package
      yum: name=httpd
    - name: copy html
      copy: src=/etc/httpd/conf/httpd.conf dest=/etc/httpd/conf/  #假如远程主机的httpd服务在运行,这里我如果把源配置文件的端口修改为8080再拷贝到远程主机,那么远程主机配置文件发生改变,但是因为远程主机已经在运行了,所以并不会重新加载配置文件,也就达不到监听8080端口的目的,下面我们修改这个yml文件解决这个问题
    - name: start service
      service: name=httpd state=started

场景问题解决:

[root@localhost ansible]# cat touch.yaml 
---
- hosts: webserver
  remote_user: root
  
  tasks:
    - name: install package
      yum: name=httpd
      tags: inshttpd
    - name: copy html
      copy: src=/etc/httpd/conf/httpd.conf dest=/etc/httpd/conf/
      notify: restart service          #可以理解为上面的模块操作的远程主机发生改变后,notify才会调用handlers的触发器,如果没有发生变化就不调用触发器,注意这里和 handlers里name里的一一对应,支持多对多
    - name: start service
      service: name=httpd state=started
  handlers:                                               #可以理解为触发器,被触发后执行下面的操作
    - name: restart service
      serveice: name=httpd state=restarted

那么我们如果想单纯的执行一个模块进行测试呢,这里要用tags来给模块打标签,比如上面的tags标签,我可以用下面的命令来单独执行安装模块

ansible-playbook -t inshttpd touch.yaml

Playbook中变量的使用

变量名:仅能由字母、数字和下划线组成,且只能以字母开头
变量来源:
    1> ansible setup facts 远程主机的所有变量都可直接调用 (系统自带变量)
       setup模块可以实现系统中很多系统信息的显示
                可以返回每个主机的系统信息包括:版本、主机名、cpu、内存
       ansible all -m setup -a 'filter="ansible_nodename"'     查询主机名
       ansible all -m setup -a 'filter="ansible_memtotal_mb"'  查询主机内存大小
       ansible all -m setup -a 'filter="ansible_distribution_major_version"'  查询系统版本
       ansible all -m setup -a 'filter="ansible_processor_vcpus"' 查询主机cpu个数
    
    2> 在/etc/ansible/hosts(主机清单)中定义变量
        普通变量:主机组中主机单独定义,优先级高于公共变量(单个主机 )
        公共(组)变量:针对主机组中所有主机定义统一变量(一组主机的同一类别)
    
    3> 通过命令行指定变量,优先级最高
       ansible-playbook –e varname=value
    
    4> 在playbook中定义
       vars:
        - var1: value1
        - var2: value2
    
    5> 在独立的变量YAML文件中定义
    
    6> 在role中定义

我们分别对上面的几种方式做测试
我们用几种不通的变量书写方法来安装httpd服务


 1. 使用-e参数在执行playbook的命令行下对yml文件中的变量赋值,优先级最高
 yml文件如下:
 [root@localhost ansible]# cat app.yml 
---
- hosts: webserver
  remote_user: root
  tasks:
    - name: install package
    yum: name={{ package }}
    - name: start service
    service: name={{ package }} state=started enabled=yes
对于这种变量书写方法我们用-e参数进行复制
ansible-playbook -e package=httpd app.yml

2. 在playbook中定义,yml文件如下
[root@localhost ansible]# cat app.yml 
---
- hosts: webserver
  remote_user: root
  vars:
    - package: httpd    #定义一个变量
  tasks:
    - name: install package
    yum: name={{ package }}
    - name: start service
    service: name={{ package }} state=started enabled=yes
3. 在/etc/ansible/hosts(主机清单)中定义变量
相关清单变量如下
[webserver]
192.168.5.231 http_port=81  #对单台主机定义变量
192.168.4.120 http_port=82
[webserver:vars]  #对整个主机组共用一套变量
nodename=www
domainname=zhangshao.com
下面我们要调用我们定义的这些变量更改我们的主机名
相关yml内容如下
[root@localhost ansible]# cat hostname.yml 
---
- hosts: webserver
  remote_user: root
  tasks:
    - name: set hostname
      hostname: name={{nodename}}{{http_port}}.{{domainname}}
      执行这个yml即可更改远程主机名为www81.zhangshao.com和www82.zhangshao.com
ansible-playbook hostname.yml
4. 我们还可以把变量单独的写入到一个文件中,我们在playbook中进行调用,注意,这种方式定义的变量只能在playbook中调用,下面是一个例子
变量文件如下:
[root@localhost ansible]# cat vars.yml 
var1: httpd
var2: vsftpd
下面我们编写一个yml文件尝试调用这两个变量分别安装httpd服务和创建一个.log文件
[root@localhost ansible]# cat testvars.yml 
---
- hosts: webserver
  remote_user: root
  vars_files:    #这里调用我们定义的变量文件
    - vars.yml
  tasks:
    - name: install packsge
      yum: name={{ var1 }}
    - name: create file
      file: name=/data/{{ var2 }}.log state=touch

模板templates

文本文件,嵌套有脚本(使用模板编程语言编写) 借助模板生成真正的文件
Jinja2语言,使用字面量,有下面形式
    字符串:使用单引号或双引号
    数字:整数,浮点数
    列表:[item1, item2, ...]
    元组:(item1, item2, ...)
    字典:{key1:value1, key2:value2, ...}
    布尔型:true/false
算术运算:+, -, *, /, //, %, **
比较操作:==, !=, >, >=, <, <=
逻辑运算:and,or,not
流表达式:For,If,When

Jinja2相关

字面量
    1> 表达式最简单的形式就是字面量。字面量表示诸如字符串和数值的 Python对象。如“Hello World”
    双引号或单引号中间的一切都是字符串。
    2> 无论何时你需要在模板中使用一个字符串(比如函数调用、过滤器或只是包含或继承一个模板的参数),如4242.23
    3> 数值可以为整数和浮点数。如果有小数点,则为浮点数,否则为整数。在Python 里, 42 和 42.0 是不一样的

Jinja2:算术运算

算术运算
Jinja 允许你用计算值。这在模板中很少用到,但为了完整性允许其存在
支持下面的运算符
    +:把两个对象加到一起。
       通常对象是素质,但是如果两者是字符串或列表,你可以用这 种方式来衔接它们。
       无论如何这不是首选的连接字符串的方式!连接字符串见 ~ 运算符。 {{ 1 + 1 }} 等于 2
    -:用第一个数减去第二个数。 {{ 3 - 2 }} 等于 1
    /:对两个数做除法。返回值会是一个浮点数。 {{ 1 / 2 }} 等于 {{ 0.5 }}
    //:对两个数做除法,返回整数商。 {{ 20 // 7 }} 等于 2
    %:计算整数除法的余数。 {{ 11 % 7 }} 等于 4
    *:用右边的数乘左边的操作数。 {{ 2 * 2 }} 会返回 4 。
       也可以用于重 复一个字符串多次。{{ ‘=’ * 80 }} 会打印 80 个等号的横条
    **:取左操作数的右操作数次幂。 {{ 2**3 }} 会返回 8

Jinja2

比较操作符
== 比较两个对象是否相等
!= 比较两个对象是否不等
> 如果左边大于右边,返回 true
>= 如果左边大于等于右边,返回 true
< 如果左边小于右边,返回 true
<= 如果左边小于等于右边,返回 true

逻辑运算符
对于 if 语句,在 for 过滤或 if 表达式中,它可以用于联合多个表达式
and
    如果左操作数和右操作数同为真,返回 true
or
    如果左操作数和右操作数有一个为真,返回 true
not
    对一个表达式取反(见下)
(expr)
    表达式组

['list', 'of', 'objects']:
一对中括号括起来的东西是一个列表。列表用于存储和迭代序列化的数据。
例如 你可以容易地在 for循环中用列表和元组创建一个链接的列表
    <ul>
    {% for href, caption in [('index.html', 'Index'), ('about.html', 'About'), ('downloads.html',
'Downloads')] %}
        <li><a href="{{ href }}">{{ caption }}</a></li>
    {% endfor %}
    </ul>
    ('tuple', 'of', 'values'):

元组与列表类似,只是你不能修改元组。
如果元组中只有一个项,你需要以逗号结尾它。
元组通常用于表示两个或更多元素的项。更多细节见上面的例子
    {'dict': 'of', 'key': 'and', 'value': 'pairs'}:

Python 中的字典是一种关联键和值的结构。
键必须是唯一的,并且键必须只有一个 值。
字典在模板中很少使用,罕用于诸如 xmlattr() 过滤器之类
    true / false:
    true 永远是 true ,而 false 始终是 false

template 的使用
这里设想一个场景,比如我想拷贝一份nginx的配置文件,但是我想根据不同的服务器配置启用不同的nginx进程数,这个是copy做不到的,那么我们就可以使用template(模板)来实现,具体实现看下面的例子
我们复制一份nginx.conf文件到和yaml/yml平级的目录下(不是绝对这样,但是建议这样),且命名为 .j2 结尾,修改这个模板,调用系统自带的模块变量
在这里插入图片描述
这里为了测试只更改这个地方
下面我们来编写一个yml文件,来将nginx配置文件使用这个模板拷贝到远程主机,使nginx线程数变为cpu核心数的两倍,yml内容如下

[root@localhost ansible]# cat tempnginx.yml 
---
- hosts: webserver
  remote_user: root
  tasks:
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf   #template功能类似于copy但是不一样
      我远程主机原来核心数分别为1和2,ansible-playbook后查看内容如下
      [root@localhost ansible]# ansible webserver -m shell -a 'cat /etc/nginx/nginx.conf |grep 'worker_processes''
192.168.4.120 | CHANGED | rc=0 >>
worker_processes  4; 
192.168.5.231 | CHANGED | rc=0 >>
worker_processes  2; 

when 实现条件判断
这里我们设想一个场景,还是上面拷贝nginx配置文件到远程主机,但是我们考虑不通版本的centos配置文件可能不同,现在我想实现如果是centos6我就拷贝centos6的配置文件,centos7我就拷贝centos7的配置文件,要怎么实现呢,when可以完美解决这个问题

我们准备centos6的配置文件为nginx.conf.c6.j2,centos7的配置文件为nginx.conf.c7.j2,并且都和yml同级目录,现在我想把centos6的配置文件拷贝到centos6的主机上,centos7的配置文件拷贝到centos7的主机上,使用when,编写如下yml文件并执行,内容如下

tasks:
  - name: install conf file to centos7
    template: src=nginx.conf.c7.j2 dest=/etc/nginx/nginx.conf
    when: ansible_distribution_major_version == "7"     #ansible_distribution_major_version查看版本的变量
  - name: install conf file to centos6
    template: src=nginx.conf.c6.j2 dest=/etc/nginx/nginx.conf
    when: ansible_distribution_major_version == "6"

迭代:with_items

迭代:当有需要重复性执行的任务时,可以使用迭代机制,类似于循环
    > 对迭代项的引用,固定变量名为"item"
    > 要在task中使用with_items给定要迭代的元素列表

下面举个例子,比如我要创建三个文件,可以使用with_items来实现

[root@localhost ansible]# cat file.yml 
---
- hosts: webserver
  remote_user: root
  tasks:
    - name: create some file
      file: name=/data/{{ item }} state=touch   #item是一个系统变量会调用with_items里定义的列表
      with_items:
        - file1
        - filr2
        - file3

还可以嵌套子变量
比如我要创建三个用户,让他们分别属于三个不同的组
相关yml文件如下

[root@localhost ansible]# cat user.yml 
---
- hosts: webserver
  remote_user: root
  tasks:
    - name: create some groups
      group: name={{ item }}
      with_items:
        - g1
        - g2
        - g3
    - name: create some users
      user: name={{ item.name }} group={{ item.group }}   #item.name分别调用 with_items里定义的三个name
      with_items:
        - { name: 'user1',group: 'g1' }
        - { name: 'user2',group: 'g2' }
        - { name: 'user3',group: 'g3' }

Playbook中template for循环
比如我这里想要通过模板将如下内容copy到目标主机可以使用如下模板和yml实现

#要在远程主机上实现的效果
server{
listen 81
}
server{
listen 82
}
server{
listen 83
}
#yml文件如下
[root@localhost ansible]# cat testfor.yml 
---
- hosts: webserver
  remote_user: root
  vars:
    liebiao:
      - 81
      - 82
      - 83
  tasks:
    - name: copy conf
      template: src=testfor1.conf.j2 dest=/data/testfor1.conf

#template使用for循环内容如下
[root@localhost ansible]# cat testfor1.conf.j2 
{% for prot in liebiao %}   #固定开始格式,prot为自定义的变量,liebiao为yml中定义的列表名
server{
listen {{ prot }}
}
{% endfor %}   #必须以此格式结束

Playbook中template if嵌套

首先yml内容如下
[root@localhost ansible]# cat for1.yml 
---
- hosts: webserver
  remote_user: root
  vars:
      ports:
        - web1:
          port: 81
          rootdir: /data/web1
        - web1:
          port: 82
          name: web2.zhangshao.com
          rootdir: /data/web2
        - web1:
          port: 83
          rootdir: /data/web3
  tasks:
        - name: copy conf
          template: src=for.conf.j2 dest=/data/for.conf
#template使用if嵌套循环内容如下
[root@localhost ansible]# cat for.conf.j2 
{% for p in ports %}
server{
listen {{ p.port }}
{% if p.name is defined %}  #当p.name被定义时执行if代码块中的内容
servername {{ p.name }}
{% endif %}
documentroot {{ p.rootdir }}
}
{% endfor %}

roles

roles
    ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。
    roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。
    要使用roles只需要在playbook中使用include指令即可。
    简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,
    并可以便捷地include它们的一种机制。
    角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中

复杂场景:建议使用roles,代码复用度高
    变更指定主机或主机组
    如命名不规范维护和传承成本大
    某些功能需多个Playbook,通过includes即可实现

roles目录结构

每个角色,以特定的层级目录结构进行组织
roles目录结构:

playbook.yml  调用角色
roles/
  project/ (角色名称)
    tasks/
    files/
    vars/
    templates/
    handlers/
    default/ 不常用
    meta/    不常用

Roles各目录作用

/roles/project/ :项目名称,有以下子目录
    files/ :存放由copy或script模块等调用的文件
    templates/:template模块查找所需要模板文件的目录
    tasks/:定义task,role的基本元素,至少应该包含一个名为main.yml的文件;
            其它的文件需要在此文件中通过include进行包含
    handlers/:至少应该包含一个名为main.yml的文件;
               其它的文件需要在此文件中通过include进行包含
    vars/:定义变量,至少应该包含一个名为main.yml的文件;
           其它的文件需要在此文件中通过include进行包含
    meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,
           其它文件需在此文件中通过include进行包含
    default/:设定默认变量时使用此目录中的main.yml文件
    
roles/appname 目录结构
    tasks目录:至少应该包含一个名为main.yml的文件,其定义了此角色的任务列表;
               此文件可以使用include包含其它的位于此目录中的task文件
    files目录:存放由copy或script等模块调用的文件;
    templates目录:template模块会自动在此目录中寻找Jinja2模板文件
    handlers目录:此目录中应当包含一个main.yml文件,用于定义此角色用到的各handler;
                  在handler中使用include包含的其它的handler文件也应该位于此目录中;
    vars目录:应当包含一个main.yml文件,用于定义此角色用到的变量;
    meta目录:应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系;
              ansible1.3及其以后的版本才支持;
    default目录:为当前角色设定默认变量时使用此目录;应当包含一个main.yml文件

roles/example_role/files/             所有文件,都将可存放在这里
roles/example_role/templates/         所有模板都存放在这里
roles/example_role/tasks/main.yml:   主函数,包括在其中的所有任务将被执行
roles/example_role/handlers/main.yml:所有包括其中的 handlers 将被执行
roles/example_role/vars/main.yml:    所有包括在其中的变量将在roles中生效
roles/example_role/meta/main.yml:    roles所有依赖将被正常登入

创建role

创建role的步骤
(1) 创建以roles命名的目录
(2) 在roles目录中分别创建以各角色名称命名的目录,如webservers等
(3) 在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和vars目录;
    用不到的目录可以创建为空目录,也可以不创建
(4) 在playbook文件中,调用各角色

下面我们举个简单例子,我现在要装nginx这个服务,大致步骤可以分为:

创建nginx组
创建nginx用户
装包
复制模板配置文件
启动nginx


我们做实现就用这几个步骤来了解roles(角色)当然生产中没那这个例子用不到角色

下面我们按照上面的步骤从头开始创建一个角色

#创建nginx组
[root@localhost tasks]# cat group.yml 
- name: create group
  group: name=nginx gid=80
#创建nginx用户
[root@localhost tasks]# cat user.yml 
- name: create user
  user: name=nginx uid=80 group=nginx system=yes shell=/sbin/nologin
#装包
[root@localhost tasks]# cat yum.yml 
- name: install package
  yum: name=nginx
#创建模板
[root@localhost templates]# pwd
/ansible/roles/nginx/templates
[root@localhost templates]# cat nginx.conf.j2 
#调用模板文件
[root@localhost tasks]# cat templ.yml 
- name: copy conf
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
#调用上面我们写的yml模块
[root@localhost tasks]# cat main.yml 
- include: group.yml
- include: user.yml
- include: yum.yml
- include: templ.yml
- include: start.yml
#最后我们编写需要执行的yml文件,注意这里要和角色目录同级
[root@localhost ansible]# cat nginx_role.yml 
- hosts: webserver
  remote_user: root
  roles:
    - role: nginx  #这里是调用我们的角色
好了 这样我们的一个简单的用角色安装nginx的步骤就完成了,下面只需要用ansible-playbook执行就ok了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值