zoukankan      html  css  js  c++  java
  • Ansible 入门指南

    上篇文章Ansible 入门指南 - 安装及 Ad-Hoc 命令使用介绍的额是 Ad-Hoc 命令方式,本文将介绍 Playbook 方式。

    Playbook 译为「剧本」,觉得还挺恰当的。

    playbook 执行语法

    Playbook 译为「剧本」,觉得还挺恰当的。那么 play 那我就译为 「场景」吧。playbook 由一个或多个 ‘plays’ 组成.它的内容是一个以 ‘plays’ 为元素的列表

    playbook 基础

    可以为 playbook 中的每一个 play,个别地选择操作的目标机器是哪些,以哪个用户身份去完成要执行的步骤(called tasks)

    $ ansible-playbook  -h
    Usage: ansible-playbook [options] playbook.yml [playbook2 ...]
    
    Runs Ansible playbooks, executing the defined tasks on the targeted hosts.
    

    palybook 小栗子

    在指定的目标主机上执行定义好的 tasks

    playbook.yml 常包含下面几个关键字:

    • hosts:为主机的IP,或者主机组名,或者关键字all
    • remote_user: 以哪个用户身份执行。
    • vars: 变量
    • tasks: playbook的核心,定义顺序执行的动作 action。每个action调用一个ansbile module
    • action 语法: module: module_parameter=module_value
    • 常用的 moduleyumcopytemplate等,module在 ansible 的作用,相当于 bash 脚本中yumcopy这样的命令。
    • 每一个 task 必须有一个名称 name,这样在运行 playbook 时,从其输出的任务执行信息中可以很好的辨别出是属于哪一个 task 的
    • handers: 是 playbook 的 event ,默认不会执行,在 action 里触发才会执行。多次触发只执行一次。

    一个简单的示例:
    deploy.yml 的功能为 web 主机部署 apache, 其中包含以下部署步骤:

    • 安装apache包;
    • 拷贝配置文件httpd,并保证拷贝文件后,apache服务会被重启;
    • 拷贝默认的网页文件index.html;
    • 启动apache服务;
    ---
    - hosts: centos
      vars:
        httpd_port: 8080
        max_clients: 200
      remote_user: root
      tasks:
      - name: ensure apache is at the latest version
        yum: name=httpd state=present
    
      - name: Write the configuration file
        template: src=templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
        notify:
        - restart apache
        ignore_errors: False
    
      - name: Write the default index.html file
        template: src=templates/index.html.j2 dest=/var/www/html/index.html
        ignore_errors: False
    
      - name: ensure apache is running
        service: name=httpd state=started
    
      handlers:
        - name: restart apache
          service: name=httpd state=restarted
    

    运行ansible-playbook deploy.yml即可执行。

    tasks

    taks 参数其实是有不同写法的,当参数比较少时,可用key=value的方式

    tasks:
      - name: make sure apache is running
        service: name=httpd state=running
    

    tasks 参数比较多时,为了美观和不易出错,用 yml的字典传参比较好:

    tasks:
      - name: make sure apache is running
        service:
          name: httpd
          state: running
    

    task中每个action会调用一个module,在module中会去检查当前系统状态是否需要重新执行。

    • 如果本次执行了,那么 action 会得到返回值 changed;
    • 如果不需要执行,那么 action 得到返回值ok

    module 的执行状态的具体判断规则由各个 module 自己决定和实现的。例如,”copy” module的判断方法是比较文件的checksum,代码如下:

    ansbile-playbook 常用命令

    查看脚本影响到的 hosts

    下面这条命令,指定 inventory 文件,列出 hosts 列表,并不会去执行定义的 tasks,观察 host 是否配置正确很有用:

    ansible-playbook -i inventory/slave_init.yml execute_slave_init.yml --list-hosts
    

    查看输出的细节

    ansible-playbook playbook.yml  --verbose
    

    并行执行脚本

    ansible-playbook playbook.yml -f 10
    

    输入密码

    playbook 中使用到了 become,执行playbook时可以加上--ask-become-pass参数:

    ansible-playbook deploy.yml --ask-become-pass
    

    yml 语法简介

    • 大小写敏感
    • 使用缩进表示层级关系
    • 缩进时不允许使用Tab键,只允许使用空格。
    • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
    • # 表示注释,从这个字符一直到行尾,都会被解析器忽略
    • YAML 还有一个小的怪癖. 所有的 YAML 文件(无论和 Ansible 有没有关系)开始行都应该是 ---. 这是 YAML 格式的一部分, 表明一个文件的开始.
    • 列表中的所有成员都开始于相同的缩进级别, 并且使用一个 "- " 作为开头(一个横杠和一个空格)
    • 一个字典是由一个简单的 键: 值 的形式组成(这个冒号后面必须是一个空格)
    • Ansible 使用 “{{ var }}” 来引用变量,foo: "{{ variable }}"

    参考

    Play vs Playbook

    其实在一个Playbook文件中还可以有针对两组server进行不同的操作,例如给web安装http服务器,和给lb安装mysql放在一个文件中:

    ---
    #安装apache的play
    - hosts: web
      remote_user: root
      tasks:
      - name: ensure apache is at the latest version
        yum: pkg=httpd state=latest
    
    # 安装mysql server的play
    - hosts: lb
      remote_user: root
      tasks:
      - name: ensure mysqld is at the latest version
        yum: pkg=mariadb state=latest
    

    上面例子中针对每一组 server 的所有操作就组成一个 play,一般一个 playbook 中只包含一个 play,play 的内容称为 tasks,即任务。

    参考:

    响应事件 Hanlder

    handlers与tasks不同,tasks会默认的按定义顺序执行每一个task,handlers则不会,它需要在tasks中被调用,才有可能被执行。

    Handlers will only be fired for tasks which report a changed state.
    只有当 task 执行状态显示是 changed 时,handler 动作才会被触发

    Tasks中的任务都是有状态的,changed或者ok。 在Ansible中,只在task的执行状态为 changed 的时候,才会执行该task调用的handler。

    在所有的task列表执行之后执行,如果有多个task notify同一个handler,那么 handlers 也只执行一次。

    什么情况下使用handlers呢?

    如果你在tasks中修改了apache的配置文件。需要重起apache。此外还安装了apache的插件。那么还需要重起apache。像这样的应该场景中,重起apache就可以设计成一个handler.

    当一个文件的内容被改动时,重启两个 services:

    - name: template configuration file
      template: src=template.j2 dest=/etc/foo.conf
      notify:
         - restart memcached
         - restart apache
    
    • notify 下列出的即是 handlers.
    • Handlers 也是一些 task 的列表,通过名字(name)来引用。
    • Handlers 是由通知者进行 notify, 如果没有被 notify,handlers 不会执行。
    • 不管有多少个通知者进行了 notify,等到 play 中的所有 task 执行完成之后,handlers 也只会被执行一次.
    handlers:
        - name: restart memcached
          service:  name=memcached state=restarted
        - name: restart apache
          service: name=apache state=restarted
    

    此外,还有个注意点:

    • handlers是按照在handlers中定义个顺序执行的,而不是安装notify的顺序执行的。比如,handlers 定义的顺序是1>2>3,notify 的顺序是3>2>1,实际执行顺序:1>2>3.

    总结,Handlers 最佳的应用场景是用来重启服务,或者触发系统重启操作.除此以外很少用到。

    参考

    变量

    playbook 中常用的集中变量:

    1. 在 playbook 中,用户自定义的变量
    2. 无需用户定义,ansible 在执行 playbook 之前,去远程主机上搜集的关于远程主机的系统信息变量
    3. task 运行的结果「注册」为一个变量来使用,这个变量叫做「注册变量」
    4. 允许用户在执行的时候传入变量的值,这时候用到的是「额外变量」

    playbook 中定义的变量

    在 playbook 中,通过关键字 vars 自定义变量,用 {{}} 引用变量。

    将变量放在单独的文件中

    通过 vars_files 关键字指定了变量文件:

    ---
    - hosts: centos
      vars:
        httpd_port: 80
      vars_files:
          - ./vars_servers.yml
      remote_user: root
      tasks:
      - debug:
          msg: "http_port: {{httpd_port}}"
      - debug:
          msg: "x86 passwd: {{x86.password}}"
      - debug:
          msg: "arm passwd: {{arm.password}}"
          # 也可以用 arm['password'] 表示
    

    专门存放变量的文件:

    # vars_servers.yml
    x86:
        password: 123
    arm:
        password: 456
    

    远程节点的系统变量(facts)

    ansible 通过 module setup 收集主机的系统信息,这些收集到的系统信息叫做 facts,这些facts可以直接以变量的形式使用。

    哪些 facts 变量可以引用的?通过如下命令行调用setup module 可以查看:

    ansible all -m setup -u root
    

    可以看到它输出的变量信息有很多!

    复杂的facts变量的使用可以用如下两种形式:

    • {{ ansible_ens3["ipv4"]["address"] }}
    • {{ ansible_ens3.ipv4.address }}

    好用的一些 facts 变量

    • ansible_hostname 指定的 host 名称
    • ansible_default_ipv4.address 主机真实的 ipv4 地址,小网IP

    ansible_os_family 查看系统类型的变量

    ---
    - hosts: all
      user: root
      tasks:
      - name: echo system
        shell: echo {{ ansible_os_family }}
      - name install ntp on Debian linux
        apt: name=git state=installed
        when: ansible_os_family == "Debian"
      - name install ntp on redhat linux
        yum: name=git state=present
        when: ansible_os_family == "RedHat"
    

    关闭 facts

    在 playbook 中,如果不收集系统信息,那么上面的变量就不能再 playbook 中使用了,但是有时候关闭会加快执行的效率:

    
    - hosts: all
      gather_facts: no
    

    注册变量 register

    将某个 task 执行的结果「注册」为一个变量。后面的 action 就可以使用它

    ---
    - hosts: centos
      tasks:
          - name: ls /tmp
            shell: ls -l /tmp
            register: result
            ignore_errors: True
    
          - name: echo result when rc==5
            shell: echo "{{result}}"
            when: result.rc == 5
    
          - name: debug show stdout
            debug:
              msg: "{{result.stdout}}"
    

    「注册变量」经常和debug module一起使用,这样可以获得 action 更多的输出信息,帮助调试。

    参考

    命令行传递变量 --extra-vars

    ---
    - hosts: "{{hosts}}"
      remote_user: "{{user}}""
    
      tasks:
        - debug: msg="{{hosts}}""
    

    命令输入变量:

    ansible-playbook extra_learn.yml --extra-vars "{'hosts':'x86','user':‘’michael'}"
    # or
    ansible-playbook extra_learn.yml --extra-vars "hosts=x86 user=michael"
    

    playbook 中的逻辑控制语句

    • when:条件判断,类似编程语言中的 if
    • loop:循环,类似编程语言中的 while
    • block:将几个 task 组成一块代码,便于针对一组操作进行异常处理等

    条件语句 wehn

    例如,在某个特定版本的系统上装包,或者只在磁盘空间满了的文件系统上执行清理操作。这些操作在Playbook中用when语句实现。

    主机为Debian Linux立刻关机

    tasks:
      - name: "shutdown Debian flavored systems"
        command: /sbin/shutdown -t now
        when: ansible_os_family == "Debian"
    

    根据action的执行结果,来决定接下来执行的action。

    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
    

    远程中的系统变量facts变量作为when的条件,用“|int”还可以转换返回值的类型:

    ---
    - hosts: web
      tasks:
        - debug: msg="only on Red Hat 7, derivatives, and later"
          when: ansible_os_family == "RedHat" and ansible_lsb.major_release|int >= 6
    

    循环语句 loop

    标准循环 with_items

    为了保持简洁,重复的任务可以用以下简写的方式:

    - name: add several users
      user: name="{{ item }}" state=present groups=wheel
      with_items:
         - michael
         - qq
    

    如果你在变量文件中或者 ‘vars’ 区域定义了一组YAML列表,你也可以这样做:

    vars:
      userlist: ["micahel", "qq"]
    tasks:
      -name: add several user
       user:
         name: "{{ item }}"
         state: present
         groups: wheel
       with_items: "{{userlist}}"
    

    使用 with_items 用于迭代的条目类型不仅仅支持简单的字符串列表.如果你有一个哈希列表,那么你可以用以下方式来引用子项:

    - name: add several users
      user: name="{{ item.name }}" state=present groups="{{ item.groups }}"
      with_items:
        - { name: 'michael', groups: 'wheel' }
        - { name: 'qq', groups: 'root' }
    

    对哈希表使用循环 with_dict

    这个例子不仅演示了 with_dict 用法,还使用循环安装了 RPM 包

    ---
    - hosts: centos
      vars:
        users:
          michael:
            name: michael xiang
            phone: 123
          qq:
            name: qq huang
            phone: 456
    
        rpms:
            - httpd
            - lrzsz
            - vim
            - git
    
      tasks:
        - name: print phone records
          debug: msg="User {{item.key }} is {{ item.value.name }} {{item.value.phone}}"
          with_dict: "{{ users }}"
    
        - name: install rpms
          yum: name="{{item}}" state=installed
          with_items: "{{rpms}}"
    

    对文件列表使用循环 with_filegloab

    with_fileglob 可以以非递归的方式来模式匹配单个目录中的文件.如下面所示:

    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/*
    

    参考

    块语句

    多个action组装成块,可以根据不同条件执行一段语句 :

     tasks:
         - block:
             - yum: name={{ item }} state=installed
               with_items:
                 - httpd
                 - memcached
    
             - template: src=templates/src.j2 dest=/etc/foo.conf
    
             - service: name=bar state=started enabled=True
    
           when: ansible_distribution == 'CentOS'
           become: true
           become_user: root
    

    ansible 示例

    参考

  • 相关阅读:
    XML(学习笔记)
    css样式学习笔记
    Request(对象)
    sql一些错误修改的总结
    转载(如何学习C#)
    sql server(学习笔记2 W3Cschool)
    sql sqrver(学习笔记1 W3Cschool)
    关于 flutter开发碰到的各种问题,有的已经解决有的一直没解决或者用其他方法替代
    关于 Flutter IOS build It appears that your application still contains the default signing identifier.
    关于 flutter本地化问题 The getter 'pasteButtonLabel' was called on null
  • 原文地址:https://www.cnblogs.com/michael-xiang/p/10461518.html
Copyright © 2011-2022 走看看