• 自动化运维工具之Ansible


    ansible简介

    Ansible的创始人是Michael DeHaan(同时也是Cobbler和Func的作者),2012年3月发布第一版,在2015年10月被Red Hat公司收购。

    功能:自动化批量部署、配置并启动应用服务;同类的自动化工具还有Saltstack、Puppet、Chef和Fabric等

    特性:

    1. 高度模块化,支持自定义模块,可以使用任何编程语言编写模块
    2. 基于Python语言实现
    3. 部署简单,无需agent,基于ssh管理
    4. 支持Playbook编排任务
    5. 幂等性,一个任务执行1遍和执行n遍效果一样,不因重复执行带来意外情况
    6. 使用YAML语言编写Playbook,支持丰富的数据结构
    7. 较强大的多层解决方案roles

    Ansible的执行过程和执行状态:

    执行过程:

    1. 加载自己的配置文件 默认/etc/ansible/ansible.cfg
    2. 加载自己对应的模块文件,如command
    3. 通过ansible将模块或命令生成对应的临时py文件,并将该 文件传输至远程服务器的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件
    4. 给文件+x执行
    5. 执行并返回结果
    6. 删除临时py文件,sleep 0退出

    执行状态返回:

    • 绿色:执行成功,并且没有对主机做更改
    • 黄色:执行成功,对主机做过更改
    • 红色:执行失败

    一、安装Ansible

    1、yum安装,基于EPEL源

    [root@centos7 ~]# yum install ansible

    2、源码安装Ansible

      1)准备Python环境

    # yum groupinstall "Development Tools"
    # yum install zlib-devel openssl-devel libffi-devel # wget https://www.python.org/ftp/python/2.7.8/Python-2.7.8.tgz # tar xf Python-2.7.8.tgz # cd Python-2.7.8/ # ./configure --prefix=/usr/local # make && make install # cp -av /usr/local/include/python2.7/* /usr/local/include/ # cd /usr/bin/ # ln -sf /usr/local/bin/python . # 编辑/usr/bin/yum 修改为 #!/usr/bin/python2 避免yum不可用

      2)获取源码

    # wget https://pypi.python.org/packages/source/s/setuptools/setuptools-19.6.2.tar.gz
    # wget https://pypi.python.org/packages/source/p/pycrypto/pycrypto-2.6.1.tar.gz
    # wget http://pyyaml.org/download/libyaml/yaml-0.1.6.tar.gz
    # wget https://pypi.python.org/packages/source/P/PyYAML/PyYAML-3.11.tar.gz
    # wget https://pypi.python.org/packages/source/M/MarkupSafe/MarkupSafe-0.9.3.tar.gz
    # wget https://pypi.python.org/packages/source/J/Jinja2/Jinja2-2.8.tar.gz
    # wget https://pypi.python.org/packages/source/s/simplejson/simplejson-3.8.1.tar.gz
    # wget https://files.pythonhosted.org/packages/20/c1/2a1a6104f7660b5d6b9876ea351f24212c19ce17c03771baf94f1c81d13b/ansible-2.5.3.tar.gz

      3)PyYAML模块安装

    # tar xf yaml-0.1.6.tar.gz 
    # cd yaml-0.1.6/
    # ./configure --prefix=/usr/local
    # make && make install
    # cd ..
    # tar xf PyYAML-3.11.tar.gz 
    # cd PyYAML-3.11/
    # python setup.py install

      4)setuptools模块安装,依赖zlib-devel包

    # tar xf setuptools-19.6.2.tar.gz 
    # cd setuptools-19.6.2/
    # python setup.py install

      5)pycrypto模块安装

    # tar xf pycrypto-2.6.1.tar.gz 
    # cd pycrypto-2.6.1/
    # python setup.py install

      6)Jinja2模块安装,依赖setuptools模块

    # tar xf MarkupSafe-0.9.3.tar.gz 
    # cd MarkupSafe-0.9.3/
    # python setup.py install
    # cd ..
    # tar xf Jinja2-2.8.tar.gz 
    # cd Jinja2-2.8/
    # python setup.py install

      7)simplejson模块安装

    # tar xf simplejson-3.8.1.tar.gz 
    # cd simplejson-3.8.1/
    # python setup.py install

      8)安装Ansible

    # tar xf ansible-2.5.3.tar.gz
    # cd ansible-2.5.3
    # python setup.py install

      9)测试

    # ansible --version
    ansible 2.5.3
      config file = None
      configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
      ansible python module location = /usr/local/lib/python2.7/site-packages/ansible-2.5.3-py2.7.egg/ansible
      executable location = /usr/local/bin/ansible
      python version = 2.7.8 (default, May 29 2018, 14:06:44) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]
    # mkdir .ssh
    # ssh-keygen -t rsa -f .ssh/id_rsa -P ''
    # ssh-copy-id -i .ssh/id_rsa.pub 192.168.0.11
    # cp -a examples/* /etc/ansible/
    # vim /etc/ansible/hosts
    	[web_servers]
    	192.168.0.11
    # ansible web_servers -m ping
    	192.168.0.11 | SUCCESS => {
    		"changed": false, 
    		"ping": "pong"
    	}

    3、Git安装Ansible

    4、Pip安装Ansible

    # yum -y install zlib-devel openssl openssl-devel libffi libffi-devel gcc gcc-c++ python-devel python-simplejson python-setuptools
    # pip install paramiko PyYAML Jinja2 httplib2 six
    # pip install ansible
    # ansible --version
    	ansible 2.5.3
    	  config file = None
    	  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
    	  ansible python module location = /usr/lib/python2.7/site-packages/ansible
    	  executable location = /usr/bin/ansible
    	  python version = 2.7.5 (default, Apr 11 2018, 07:36:10) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]

    二、主机清单和配置文件

    主机清单 Inventory

    /etc/ansible/hosts 默认主机清单文件,inventory file可以有多个,且也可以通过Dynamic Inventory来动态生成

    Inventory文件遵循INI文件风格,中括号中的字符为组名。可以将同一个主机同时归并到多个不同的组中;此外,当如若目标主机使用了非默认的SSH端口,还可以在主机名称之后使用冒号加端口号来标明。

    格式1:

      host:[port]

    格式2:

      [groupname]

      host1

      host2

      host3

    格式3:

      [groupname]

      host[1:3]

    配置文件

    配置文件/etc/ansible/ansible.cfg (一般保持默认) 

    inventory      = /etc/ansible/hosts		#主机清单文件
    library        = /usr/share/my_modules/		#库文件存放目录
    remote_tmp     = ~/.ansible/tmp			#临时py命令文件存放在远程主机目录 
    local_tmp      = ~/.ansible/tmp			#本机的临时命令执行目录 
    forks          = 5  				#默认并发数
    sudo_user      = root				#默认sudo用户
    ask_sudo_pass = True				#每次执行ansible命令是否询问ssh密码 
    remote_port    = 22 				#远程主机端口号
    host_key_checking = False 			#禁用第一次连接的key检查
    log_path = /var/log/ansible.log 		#默认ansible不记录日志,启用此项开启日志记录 

    三、Ansible系列命令集

    ansible

    用法:ansible <host-pattern> [-m module_name] [-a args]

    选项:

    • --version:查看版本相关信息
    • -m module:指定模块,默认为command
    • -v|–vv|-vvv:详细过程
    • —list|--list-hosts:显示主机列表
    • -k|--ask-pass:提示连接密码,默认Key验证
    • -K|--ask-become-pass:提示输入sudo
    • -C|--check:检查执行,并不是真正执行
    • -T|--timeout=TIMEOUT:执行命令的超时时间,默认10s
    • -u|--user=REMOTE_USER:执行远程执行的用户
    • -b|--become:代替旧版的sudo切换

    host-pattern:

    • all:表示主机清单中所有的主机
    • groupname:表示组中的所有主机
    • host:指定某台主机,但是此主机必须在主机清单中
    • 支持通配符(*)、逻辑与(:&)或(:)非(:!)和正则表达式(~)

    ansible-doc

    用法:ansible-doc [options] [module...]

    选项:

    • -a 显示所有模块的文档
    • -l, --list 列出可用模块
    • -s, --snippet 显示指定模块的playbook片段

    ansible-galaxy

    从网站上下载对应的roles(https://galaxy.ansible.com)

    • install 安装roles 
    • list 列出所有roles 
    • remove 删除roles 

    ansible-playbook

    执行.yml剧本文件

    • -C | --check 检查执行,不真正执行
    • -t tags 执行指定的标签
    • --list-tags 列出剧本中的所有的标签
    • --list-tasks 列出剧本中所有的任务
    • --list-hosts 列出剧本中所有的主机
    • --limit host_group_name 只针对主机列表中的主机执行
    • -v | -vv | -vvv 显示详细信息
    • -e 'var=value' 自定义变量赋值

    ansible-vault

    管理加密解密yml文件

    • encrypt 加密
    • decrypt 解密
    • view 查看
    • edit 编辑加密文件
    • rekey 修改口令
    • create 创建新文件

    ansible-console

    ansible的交互式终端,root@all (3)[f:5]$:执行用户@当前操作的主机组 (当前组的主机数量)[f:并发数]$ 

    • forks #:设置并发数
    • cd:切换主机组或主机
    • list:列出当前主机列表
    • help:获取帮助

    ansible-pull

    推送命令至远程,支持直接从git下载playbook执行,需要遵循其规定的目录格式,用处不是特别大

    四、常用模块

    1)command 不支持管道、变量和管道,只支持简单功能,需要使用shell模块

    removes=/path/file 如果文件不存在则不执行

    creates=/path/file 如果文件存在则不执行

    chdir=/path/file 进入指定文件夹

    ~]# ansible all -a 'df -h'
    ~]# ansible all -m command -a 'chdir=/data ls' 

    2)shell 和command模块用法相同,但是支持管道、变量和管道等复杂命令

    ~]# ansible all -m shell -a 'echo $HOSTNAME'

    3)script 在远程主机上执行本地脚本

    --some-arguments 1234 指定参数

    ~]# ansible all -m script -a '/root/ansible/host.sh'

    4)copy 将本地文件复制至远程主机

    backup 复制覆盖时先备份

    content 指定一些内容当文件复制

    dest 目标路径

    mode 权限

    owner 所有者

    src 源路径

    ~]# ansible all -m copy -a 'src=/root/ansible/selinux dest=/etc/selinux/config backup=yes'
    ~]# ansible all -m copy -a 'content="hello world" dest=/data/f1'

    5)fetch 从远程主机文件复制到本地,必须是一个文件,在本地目录下会生成主机名对应的文件夹,文件存放于文件夹中按远程主机上的目录结构

    dest 本地的一个目录

    src 远程主机系统上的一个文件(必须)

    ~]# ansible all -m fetch -a 'src=/var/log/messages dest=/data'

    6)archive 打包文件

    7)unarchive 解包文件

    8)file 创建,删除,设置文件属性

    state= directory | touch | link | hard | absent 目录,空文件,软链接,硬链接,递归删除

    dest | name | path= 路径

    src= 创建软链接时的原文件

    mode= 权限

    owner= 所属者

    ~]# ansible all -m file -a 'name=/data/testfile.ans state=touch'
    ~]# ansible all -m file -a 'name=/data/dir1 state=directory'
    ~]# ansible all -m file -a 'src=/etc/fstab dest=/data/f2 state=link'

    9)hostname 设置主机名,立即生效并且同步至配置文件

    name= 主机名

    ~]# ansible 192.168.0.11 -m hostname -a 'name=node1'

    10)cron 任务计划

    name 名称

    job 作业

    disabled=true | false 禁用|启用

    state=absent 删除

    day 天

    hour 小时

    minute 分钟

    month 月

    weekday 星期

    ~]# ansible all -m cron -a 'minute=* weekday=1,3,5 job="/usr/bin/wall FBI warning" name=warningcron'
    ~]# ansible all -m cron -a 'disabled=true job="/usr/bin/wall FBI warning" name=warningcron'

    11)yum 管理软件包模块

    list=installed 列出已安装的软件包

    name= 包名称

    state= present | absent latest 安装 | 卸载 | 安装最新版

    disable_gpg_check=yes 临时禁用gpg检查

    update_cache=yes 更新yum缓存

    ~]# ansible all -m yum -a 'name=vsftpd state=latest'

    12)service 管理服务模块

    name 服务名

    enabled=yes 开机启动

    state=started | stopped | restarted | reloaded 启动 | 停止 | 重启 | 重读配置文件

    ~]# ansible all -m service -a 'name=vsftpd state=started enabled=yes'

    13)user 用户管理模块

    name= 用户名

    password= 密码

    remove= 删除用户及家目录

    system=yes 创建系统用户

    shell= 设置默认shell

    ~]# ansible all -m user -a 'name=nginx shell=/sbin/nologin system=yes home=/var/nginx groups=root,bin uid=80 comment="nginx service"' 
    ~]# ansible all -m user -a 'name=nginx state=absent remove=yes'

    14)group 组管理模块

    15)setup 获取远程主机的系统信息

    filter=var 过滤查看变量参数

    五、剧本(Playbook)

    playbook是由一个或多个“play”组成的列表,play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲,所谓task无非是调用ansible的一个module。将多个play组织在一个playbook中,即可以让它们联同起来按事先编排的机制同唱一台大戏。

    YAML简介

    Playbook采用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"(仍是一种标记语言) http://www.yaml.org

    基本格式:

    1. --- :表示一个档案
    2. ... :表示档案结尾
    3. # :注释
    4. : :分割k/v(键/值)
    5. 缩进必须是统一的,不能空格和tab混用,一般习惯建议2个空格缩进
    6. 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的
    7. k/v(键/值)的值均需大小写敏感
    8. v(值)可以是字符串,也可以是嵌套另一个列表
    9. 文件的后缀通常为yml或yaml
    10. - :列表
    11. Dictionary:字典由多个key与value构成 

    组成playbook的核心元素

    1、主机列表:Hosts

    playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清单中。

    remote_user: 可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户

    ---
    - hosts: all
      remote_user: root
    
      tasks:
        - name: see hostname
          command: hostname
    ...

    2、任务集:Tasks和action

    play的主体部分是task list。task list中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后再开始第二个。在运行自下而下某playbook时,如果中途发生错误,所有已执行任务都将回滚,因此,在更正playbook后重新执行一次即可

    task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致

    每个task都应该有其name,用于playbook的执行结果输出,建议其内容尽可能清晰地描述任务执行步骤。如果未提供name,则action的结果将用于输出

    格式:module: arguments ,但是command模块和shell模块后直接写命令

    ---
    - hosts: websrvs
    remote_user: root
    tasks:                   #任务 - name: install httpd package    #action yum: name=httpd           #调用yum模块,并向yum模块传递name=httpd的参数 - name: copy configuration file for httpd copy: src=files/httpd.conf dest=/etc/httpd/conf/httpd.conf - name: start httpd service service: name=httpd state=started ...

    如果命令或脚本的退出码不为零,使用 ignore_errors:True 来忽略错误信息

    3、变量:Variables

    变量名:仅能由字母、数字和下划线组成,且只能以字母开头

    内建变量:facts,setup模块到主机上收集的所有信息保存为变量,可以直接引用,列如 ansible_fqdn 变量用来保存主机名

    # ansible all -m setup |grep ansible_fqdn         
            "ansible_fqdn": "node1", 
            "ansible_fqdn": "node2", 
            "ansible_fqdn": "node3", 

    自定义变量赋值:

    3.1.命令行直接赋值

    ansible-playbook -e 'var=value'

    3.2.在playbook中定义变量

    vars:

      - varname: value

    3.3.在主机清单中定义变量

    主机变量,直接在主机后定义,只对定义主机有效,优先级高于公共变量

    host var=value

    公共变量,对主机组内所有主机有效

    [groupname:vars] 为指定主机组自定义变量,vars为关键字

    varname=value

    3.4.roles中变量在 ansible/roles/object/vars/main.yml 文件中直接定义

    var:value
    var2:value2

    3.5.在.yml文件中直接定义,使用vars_files 关键字引用,例如:

    # vim vars.yml
    var1: httpd
    var2: vstfpd
    
    # vim testvar.yml
    ---
    - hosts: all
      remote_user: root
      vars_files:
        - vars.yml
      tasks:
        - name: install package
          yum: name={{ var1 }} state=present
        - name: create file
          file: name=/data/{{ var2 }}.log state=touch
    ...

    变量引用:命令行中定义的变量优先级最高

    {{ varname }}

    ---
    - hosts: websrvs
      remote_user: root
      vars:
        - package_name: httpd
    
      tasks:
        - name: install httpd package
          yum: name={{ package_name }}
        - name: copy configuration file for httpd
          copy: src=files/httpd.conf dest=/etc/httpd/conf/httpd.conf
        - name: start httpd service
          service: name={{ package_name }} state=started
    ...

    4、模板:Templates

    我们为了对不同配置的主机配置不同的配置,我们不可能每次都要修改配置文件,所有就出现了模板技术,这样我们只要定义好一份模板,以后推送配置文件时会自动将配置文件模板中的变量替换为目标主机的参数

    templates功能:根据模块文件动态生成对应的配置文件,ansible中模板使用jinja2语言编写,第七节有关于jinja2的介绍

    要求:

    1. templates文件必须存放于templates目录下且命名为 .j2 结尾
    2. yaml/yml 文件需和templates目录平级
    3. 在playbook中使用template关键字调用模板
    [root@centos7 ansible]# vim templates/httpd.conf.j2
    ServerRoot "/etc/httpd"
    Listen 80
    Include conf.modules.d/*.conf
    User apache
    Group apache
    ServerAdmin root@localhost
    ServerName {{ ansible_fqdn }}:80
    [root@centos7 ansible]# vim temp_httpd.yml 
    ---
    - hosts: all
      remote_user: root
      vars:
      - package_name: httpd
      - service_name: httpd
    
      tasks:
        - name: install package
          yum: name={{ package_name }}
        - name: copy config file
          template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
          notify: restart service
        - name: start service
          service: name={{ service_name }} state=started
    
      handlers:
        - name: restart service
          service: name={{ service_name }} state=started
    ...
    [root@centos7 ansible]# tree 
    .
    ├── temp_httpd.yml
    └── templates
        └── httpd.conf.j2

      ansible_fqdn 变量代表主机名,是setup模块返回的变量,可以直接使用

    5、触发器:Handlers和notify

    Handlers是task列表,这些task与前述的task并没有本质上的不同,用于当关注的资源发生变化时,才会采取一定的操作;

    notify这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作。

    ---
    - hosts: websrvs
    remote_user: root tasks: - name: install httpd package yum: name=httpd - name: copy configuration file for httpd copy: src=files/httpd.conf dest=/etc/httpd/conf/httpd.conf notify: restart service - name: start httpd service service: name=httpd state=started handlers: - name: restart service service: name=httpd state=restarted ...

    当copy的配置文件发生改变时则执行重启服务的功能,这是必须的

    6、标签:Tags

    为action打上一个标签,可以使用ansible-playbook -t 来指定标签名,用来只执行单个action

    ---
    - hosts: websrvs
    remote_user: root tasks: - name: install httpd package yum: name=httpd - name: copy configuration file for httpd copy: src=files/httpd.conf dest=/etc/httpd/conf/httpd.conf tags: put_config_file - name: start httpd service service: name=httpd state=started tags: start_service ...

    使用 ansible-playbook --list-tags httpd.yml 命令查看playbook中的标签

    六、角色(Roles)

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

    创建role的步骤:

    1) 创建以roles命名的目录;

    2) 在roles目录中分别创建以各角色名称命名的目录,如webservers等;

    3) 在每个角色命名的目录中分别创建files、handlers、tasks、templates和vars目录;用不到的目录可以创建为空目录,也可以不创建;

    4) 在playbook文件中,通过Includes调用各角色。

    [root@centos7 ansible3]# mkdir -p roles/project/{tasks,files,vars,templates,handlers,default,meta}
    [root@centos7 ansible3]# tree
    .
    └── roles
        └── project
            ├── default
            ├── files
            ├── handlers
            ├── meta
            ├── tasks
            ├── templates
            └── vars
    
    9 directories, 0 files

      各目录作用介绍:

    • 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文件

    示例:接下来我们就简单的构建一个role

      1)创建目录框架

    [root@centos7 ansible4]# mkdir -p roles/httpd/{tasks,templates,files,handlers}
    [root@centos7 ansible4]# tree
    .
    └── roles
        └── httpd
            ├── files
            ├── handlers
            ├── tasks
            └── templates

      2)编写任务

    [root@centos7 ansible4]# vim roles/httpd/tasks/yum.yml
    - name: install httpd
      yum: name=httpd state=present
    
    [root@centos7 ansible4]# vim roles/httpd/tasks/copy.yml
    - name: copy config file
      template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
      notify: restart service
    - name: copy index.html
      copy: src=index.html dest=/var/www/html/ owner=apache
    
    [root@centos7 ansible4]# vim roles/httpd/tasks/start.yml
    - name: start httpd
      service: name=httpd state=started
    
    [root@centos7 ansible4]# vim roles/httpd/tasks/main.yml
    - include: yum.yml
    - include: copy.yml
    - include: start.yml

      3)配置模板和主页测试文件

    [root@centos7 ansible4]# cp /etc/httpd/conf/httpd.conf roles/httpd/templates/httpd.conf.j2
    [root@centos7 ansible4]# vim roles/httpd/templates/httpd.conf.j2
    ServerName www.{{ ansible_fqdn }}.com:80
    [root@centos7 ansible4]# vim roles/httpd/files/index.html
    <h1>The is a test website.</h1>

      4)定义handlers,使得配置文件模板改变后可以重启服务

    [root@centos7 ansible4]# vim roles/httpd/handlers/main.yml              
    - name: restart service
      service: name=httpd state=restarted
    [root@centos7 ansible4]# tree
    .
    └── roles
        └── httpd
            ├── files
            │   └── index.html
            ├── handlers
            │   └── main.yml
            ├── tasks
            │   ├── copy.yml
            │   ├── main.yml
            │   ├── start.yml
            │   └── yum.yml
            └── templates
                └── httpd.conf.j2

      5)角色已经编写完成,我们只需要在roles目录的同级目录下编写playbook,在playbook中直接使用角色所定义的任务

    [root@centos7 ansible4]# vim httpd.yml
    ---
    - hosts: websvrs
      remote_user: root
      
      roles:
        - httpd
    ...

      6)大功告成,一个简单的角色就定义完成了,接下来我们去测试,go

    [root@centos7 ansible4]# ansible-playbook -C httpd.yml #先空跑一下,没有问题再实际执行
    [root@centos7 ansible4]# ansible-playbook httpd.yml
    [root@centos7 ansible4]# curl 192.168.0.11
    <h1>The is a test website.</h1>
    [root@centos7 ansible4]# curl 192.168.0.12
    <h1>The is a test website.</h1>

       # 和我们所预期的操作一样,那么以后可以向这个角色中添加更为丰富的功能

    七、jinja2语法

    字符串:使用单引号或双引号

    列表:[ item1, item2, ... ]

    元组:( item1, item2, ... )

    字典:{ key1:value1, key2:value2, ... }

    算术运算

    +	把两个对象加到一起。通常对象是素质,但是如果两者是字符串或列表,你可以用这 种方式来衔接它们。无论如何这不是首选的连接字符串的方式!连接字符串见 ~ 运算符。 {{ 1 + 1 }} 等于 2 
    -	用第一个数减去第二个数。 {{ 3 - 2 }} 等于 1 
    /	对两个数做除法。返回值会是一个浮点数。 {{ 1 / 2 }} 等于 {{ 0.5 }} 
    //	对两个数做除法,返回整数商。 {{ 20 // 7 }} 等于 2 
    %	计算整数除法的余数。 {{ 11 % 7 }} 等于 4 
    *	用右边的数乘左边的操作数。 {{ 2 * 2 }} 会返回 4 。也可以用于重 复一个字符串多次。 {{ ‘=’ * 80 }} 会打印 80 个等号的横条
     worker_processes {{ ansible_processor_vcpus*2 }};    #被控端的cpu核心数*2

    比较操作符

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

    逻辑运算符

    and	如果左操作数和右操作数同为真,返回 true 
    or	如果左操作数和右操作数有一个为真,返回 true 
    not	对一个表达式取反(见下)
    (expr)	表达式组

    条件测试:when

      条件测试:如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过when语句实现,在task中使用

    ---
    - hosts: all
      remote_user: root
      vars:
      - package_name: httpd
      - service_name: httpd
    
      tasks:
        - name: install package
          yum: name={{ package_name }}
        - name: copy config file
          template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
          notify: restart service
        - name: start service
          service: name={{ service_name }} state=started
          when: ansible_fqdn == "node2"  #只有主机名是 node2 的节点启动web服务
    
      handlers:
        - name: restart service
          service: name={{ service_name }} state=started

    迭代:with_items

      当有需要重复性执行的任务时,可以使用迭代机制,要在task中使用with_items给定要迭代的元素列表。使用item变量引用列表中的变量

    ---
    - hosts: all
      remote_user: root
    
      tasks:
        - name: create some files
          file: name=/data/{{ item }} state=touch
          with_items:
            - file1
            - file2
            - file3
        - name: install some package
          yum: name={{ item }}
          with_items:
            - httpd
            - vsftpd
            - htop
            - dstat
            - iftop
            - sl
            - iotop
            - hping3
    ...   

      迭代中嵌套子变量

    ---
    - hosts: all
      remote_user: root
    
      tasks:
        - name: create some groups
          group: name={{item}}
          with_items:
            - g1
            - g2
            - g3
        - name: ceate some users
          user: name={{item.name}} group={{item.group}}
          with_items:
            - { name: 'user1', group: 'g1' }
            - { name: 'user2', group: 'g2' }
            - { name: 'user3', group: 'g3' }
    ...

    for循环

      for语句在templates文件中使用

    [root@centos7 ansible]# vim testfor.yml 
    ---
    - hosts: all
      remote_user: root
      vars:
        ports:
          - 81
          - 82
          - 83
    
      tasks:
        - name: copy config file
          template: src=for1.conf.j2 dest=/data/for1.conf
    ...
    
    [root@centos7 ansible]# vim templates/for.conf.j2 
    {% for p in ports %}
    server{
        listen {{ p }}
    }
    {% endfor %}

      也可以使用for来遍历列表

    [root@centos7 ansible]# vim testfor2.yml 
    ---
    - hosts: all
      remote_user: root
      vars:
        ports:
          - http_port: 81
          - http_port: 82
          - http_port: 83
    
      tasks:
        - name: copy config file
          template: src=for2.conf.j2 dest=/data/for2.conf
    ...
    
    [root@centos7 ansible]# vim templates/for2.conf.j2 
    {% for p in ports %}
    server{
        listen {{ p.http_port }}
    }
    {% endfor %}

      以上的模板生成的结果:

    server{
            listen 81
    }
    server{
            listen 82
    }
    server{
            listen 83
    }

    if判断

      if语句在templates文件中使用

    [root@centos7 ansible]# cat testif.yml 
    ---
    - hosts: all
      remote_user: root
      vars:
        ports:
          - web1:
            port: 81
            name: web1.test.com
            rootdir: /data/website1
          - web1:
            port: 82
            name: web2.test.com
            rootdir: /data/website2
          - web1:
            #port: 83
            name: web3.test.com
            rootdir: /data/website3
    
      tasks:
        - name: copy config file
          template: src=if.conf.j2 dest=/data/if.conf
    ...
    
    [root@centos7 ansible]# cat templates/if.conf.j2 
    {% for i in ports %}
    server{
    {% if i.port is defined %}  #这个判断的意思是如果变量i.port,也就是ports中的port变量,没有配置,则这个语句块则不生效
            Listen {{ i.port }}
    {% endif %}
            ServerName {{ i.name }}
            Documentroot {{ i.rootdir }}
    }
    {% endfor %}

    学习^_^    +++博文完成于2018-05-31 09:57:41

  • 相关阅读:
    《你必须知道的495个C语言问题》读书笔记之第15-20章:浮点数、风格、杂项
    《你必须知道的495个C语言问题》读书笔记之第8-10章:字符串、布尔类型和预处理器
    《你必须知道的495个C语言问题》读书笔记之第4-7章:指针
    《你必须知道的495个C语言问题》读书笔记之第3章:表达式
    《你必须知道的495个C语言问题》读书笔记之第1-2章:声明和初始化
    bzoj4361 isn(树状数组优化dp+容斥)
    bzoj4665 小w的喜糖(dp+容斥)
    P4859 已经没有什么好害怕的了(dp+二项式反演)
    bzoj4710 [Jsoi2011]分特产(容斥)
    bzoj2839 集合计数(容斥)
  • 原文地址:https://www.cnblogs.com/L-dongf/p/9101934.html
Copyright © 2020-2023  润新知