• ansible笔记(二)


    我是先在本地用Markdown记的笔记,然后直接粘贴到博客园,可能格式上会有些问题,还请谅解。

    一、playbook和yaml语法

    1.1 YAML语法

    基本语法规则:

    1. 大小写敏感
    2. 使用缩进表示层级关系
    3. 缩进不允许使用Tab,只允许使用空格
    4. 缩进的空格数目不重要,相同层级的元素左侧对齐即可
    5. 使用#注释

    支持三种数据结构

    1. 对象:键值对的集合
    2. 数组:一组按次序排列的值,以-开头
    3. 纯量:单个的,不可再分的值

    1.2 playbook

    ansible的配置、部署、编排语言。使用yaml语言编写。

    1.2.1 示例:

    - hosts: webservers	# 主机或组
      vars:	# 变量
        http_port: 80
        max_clients: 200
      remote_user: root	# 远程用户
      # sudo: yes	支持sudo执行命令
      tasks:
      - name: ensure apache is at the latest version	# 任务名(必须有)
        remote_user: yourname	# tasks下也可以定义远程用户
        sudo: yes	# 支持sudo执行命令
        sudo_user: postgres	# 登录到postfres用户
        yum: pkg=httpd state=latest	# 使用yum模块安装apache
        tags: t1	# 打标签
      - name: write the apache config file
      	# template模块
        template: src=/src/httpd.j2 dest=/etc/httpd.conf
        # 当/src/httpd.j2文件被改动时,重启apache
        notify:		# notify会在playbook的每一个task结束时被触发
        - restart apache
        tags: t2
      - name: ensure apache is running
        service: name=httpd
        tags: 
          - t3
          - tag3	# 添加多个标签
    

    使用sudo时指定密码,在运行ansible-playbook命令时加上选项--ask-sudo-pass(-K)

    每一个play包括一个task列表,前一个task执行完成才会执行下一个task

    1.2.2 执行一个playbook

    # 查看所有选项
    ansible-playbook --help
    
    # 检查playbook的语法是否正确
    ansible-playbook --syntax-check playbook.yml
    
    # 列出运行任务的主机
    ansible-playbook --list-hosts playbook.yml
    
    # 模拟执行playbook
    ansible-playbook --check playbook.yml
    
    # 普通的运行playbook
    ansible-playbook playbook.yml
    
    # 开启十个并发的进程执行playbook
    ansible-playbook playbook.yml -f 10
    
    # 根据tags指定执行哪一个任务,指定多个标签用逗号隔开
    ansible-playbook --tags=xxx playbook.yml
    
    # 根据tags指定不执行哪一个任务
    ansible-playbook --skip-tags=xxx playbook.yml
    

    1.2.3 notify和Handlers

    一个notify示例:当/src/htpd.j2文件被改动时,重启apache,即使有多个task通知改动的发生,notify也只会触发一次。

    - restart apache即是一个handlers,handlers其实是一种特殊的tasks。

    - hosts: webservers
      ...
      tasks:
      ...
      - name: write the apache config file
        template: src=/src/httpd.j2 dest=/etc/httpd.conf
        notify:
        - restart apache
    

    handlers示例

    handlers:
        - name: restart apache
          service: name=apache state=restarted
    

    完整实例:

    - hosts: webservers
      remote_user: root
      tasks:
        - name: write the apache config file
          template: src=/src/httpd.j2 dest=/etc/httpd.conf
          notify:
          - restart apache
      handlers:
        - name: restart apache
          service: name=apache state=restarted
    

    1.2.4 Roles和Include语句

    引入Roles和 Include的目的是为了提高playbook的重用性。

    5.2.4.1 include

    在多个playbook中重用同一个task列表

    一个task include file由一个普通的task列表所组成

    # 文件名:tasks/foo.yml
    
    - name: placeholder foo
      command: /bin/foo
    - name: placeholder bar
      command: /bin/bar
    

    在playbook中使用include语句导入

    tasks:
      - include: tasks/foo.yml
    

    给include传递变量

    tasks:
      - include: wordpress.yml wp_user=timmy
      - include: wordpress.yml wp_user=alice
      - include: wordpress.yml wp_user=bob
      
    tasks:
      - include: wordpress.yml
        vars:
    	wp_user: timmy
    	some_list_variable:
    	  - alpha
    	  - beta
    	  - gamma
    

    include也可用在handlers语句中

    # handlers/handlers.yml
    - name: restart apache
      service: name=apache stae=restarted
    

    然后在主playbook中使用include导入

    handlers:
      - include: handlers/handlers.yml
    

    将一个playbook导入另一个playbook

    - name: this is a play at the top level of a file
      hosts: all
      remote_user: root
    
      tasks:
    
      - name: say hi
        tags: foo
        shell: echo "hi..."
    
    - include: load_balancers.yml
    - include: webservers.yml
    - include: dbservers.yml
    

    1.2.4.2 Roles

    Roles基于一个已知的文件结构、自动的加载某些vars_files,tasks以及handlers

    一个项目结构如下所示:

    site.yml
    webservers.yml
    fooservers.yml
    roles/
    	|_ common/
    	|		|_ files/
    	|		|_ templates/
    	|		|_ tasks/
    	|		|_ handlers/
    	|		|_ vars/
    	|		|_ defaults/
    	|		|_ meta/
    	|_ webservers/
    			|_ files/
    			|_ templates/
    			|_ tasks/
    			|_ handlers/
    			|_ vars/
    			|_ defaults/
    			|_ meta/
    

    一个playbook如下:

    - hosts: webservers
      roles:
        - common
        - webservers
    

    以common为例,以上这段playbook的含义如下

    • 如果roles/common/tasks/main.yml存在,其中的tasks将添加到play中

    • 如果roles/common/handlers/main.yml存在,其中列出的handlers将被添加到play中

    • 如果roles/common/vars/main.yml存在,其中列出的variables将被添加到play中

    • 如果roles/common/meta/main.yml存在,其中列出的角色依赖将会添加到roles中

      这个角色依赖没看懂是干啥用的

    • 所有copy tasks都可以引用roles/common/file中的文件,不需要指明文件的路径

    • 所有script tasks可以引用roles/common/file中的脚本,不需要知名文件的路径

    • 所有template tasks可以引用roles/common/templates/中的文件,不需要指明文件的路径

    • 所有include tasks可以引用roles/common/tasks/中的文件,不需要指明文件的路径

    Roles是playbook编排的一种方式,可以在使用Roles的同时在playbook中松散地列出 tasks,vars_files 以及 handlers,这种方式仍然可用

    如果roles目录下有文件不存在也没有关系,这些文件将被忽略

    参数化的roles

    - hosts: webservers
      roles:
        - common
        - { role: foo_app_instance, dir: '/opt/a',  port: 5000 }
        - { role: foo_app_instance, dir: '/opt/b',  port: 5001 }
    

    为roles设置触发条件

    - hosts: webservers
      roles:
        - { role: some_role, when: "ansible_os_family ='RedHat'" }
    

    给roles分配指定的tags

    - hosts: webservers
      roles:
        - { role: foo, tags: ["bar", "baz"]}
    

    定义一些 tasks,让它们在 roles 之前以及之后执行

    - hosts: webservers
    
      pre_tasks:
        - shell: echo 'hello'
    
      roles:
        - { role: some_role }
    
      tasks:
        - shell: echo 'still busy'
    
      post_tasks:
        - shell: echo 'goodbye'
    

    1.2.5 Variables 变量

    1.2.5.1 合法的变量名

    • 变量名可以为字母,数字以及下划线.
    • 变量始终应该以字母开头.

    1.2.5.2 在playbook中定义变量

    直接定义变量

    - hosts: webservers
      vars:
        http_port: 80
    

    在文件和role中定义变量

    roles/item/vars/

    1.2.5.3 使用变量

    ansible使用Jinja2模板系统引用变量

    template: src=foo.cfg.j2 dest={{ remote_install_path }}/foo.cfg
    

    {{ remote_install_path }}部分就是变量引用部分

    使用外部变量

    - hosts: all
      remote_user: root
      vars:
        favcolor: blue
      vars_files:
        - /vars/external_vars.yml
      tasks:
      - name: this is just a placeholder
        command: /bin/echo foo
    

    vars/external_vars.yml文件内容如下:

    somevar: somevalue
    password: magic
    

    命令行中传递变量

    ansible-playbook release.yml --extra-vars "version=1.23.45 other_variable=foo"
    

    1.2.6 条件选择语句 when

    when的值是一个条件表达式,如果条件处理,tasks才执行。

    示例:

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

    下面这段没看懂是啥意思

    tasks:
      - command: /bin/false
        register: result
        ignore_errors: True
        # 当result等于failed时,执行
      - command: /bin/something
        when: result|failed
      - command: /bin/something_else
        when: result|success
      - command: /bin/still/something_else
        when: result|skipped
    

    有些时候得到一个返回参数的值是一个字符串,并且你还想使用数学操作来比较它,那么可以执行以下操作:

    tasks:
      - shell: echo "only on Red Hat 6, derivatives, and later"
        when: ansible_os_family == "RedHat" and ansible_lsb.major_release|int >= 6
    

    如果一个变量不存在,使用Jinja2的defined命令跳过或略过

    tasks:
      - shell: echo "I've got '{{ foo }}' and am not afraid to use it!"
        when: foo is defined
    
      - fail: msg="Bailing out. this play requires 'bar'"
        when: bar is not defined
    

    在roles和includes上应用when语句

    - include: tasks/sometasks.yml
      when: "'reticulationg splines' in output"
    
    - hosts: webservers
      roles:
        - { role: debain_stock_config, when: ansible_os_family == 'Debian' }
    

    1.2.7 循环

    1.2.7.1 标准循环 with_item模块

    使用with_items循环模块创建两个用户testuser1和testuser2

    - name: add serveral users
      user: name={{ item }} stat=present groups=wheel
      with_items:
        - testuser1
        - testuser2
    
    - name: add several users
      user: name={{ item.name }} state=present groups={{ item.groups }}
      with_items:
        - { name: 'testuser1', groups: 'wheel' }
        - { name: 'testuser2', groups: 'root' }
    

    1.2.7.2 嵌套循环 with_nested模块

    - 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' ]
        - [ 'clientdb', 'employeedb', 'providerdb' ]
    

    1.2.7.3 对哈希表使用循环 with_dict

    有如下哈希表

    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}}"
    

    debug: msg="User alice is Alice Appleworth (123-456-7890)"

    debug: msg="User Bob is Bob Bananarama (987-654-3210)"

    1.2.7.4 对文件列表使用循环 with_fileglob

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

    1.2.7.5 对并行数据集使用循环 with_together

    alpha: [  'a', 'b', 'c', 'd' ]
    numbers: [ 1, 2, 3, 4 ]
    
    tasks:
        - debug: msg="{{ item.0 }} and {{ item.1 }}"
          with_together:
            - "{{alpha}}"
            - "{{numbers}}"
    

    1.2.7.6 对子元素使用循环 with_subelements

    如下定义了一个复合结构的字典变量users,在with_subelements循环中,指定了users变量和users变量的子元素hobby

    ---
    - hosts: testB
      remote_user: root
      gather_facts: no
      vars:
        users:
        - name: bob
          gender: male
          hobby:
            - Skateboard
            - VideoGame
        - name: alice
          gender: female
          hobby:
            - Music
      tasks:
      - debug:
          msg: "{{ item.0.name }}'hobby is {{item.1}}'"
        with_subelements:
        - "{{users}}"
        - hobby
    

    执行效果为

    bob's hobby is Skateboard
    bob's hobby is VideoGame
    alice's hobby is Music
    

    item.0获取到users变量的name、gender部分,item.1获取到hobby部分

    1.2.7.7 对整数序列使用循环 with_sequence

    ---
    - hosts: all
    
      tasks:
        - group: name=evens state=present
        - group: name=odds state=present
        # 创建四个用户,用户名为testuser00到testuser32
        - user: name={{ item }} state=present groups=evens
          with_sequence: start=0 end=32 format=testuser%02x
        - file: dest=/var/stuff/{{ item }} state=directory
        # stride 跨度
          with_sequence: start=4 end=16 stride=2
        - group: name=group{{ item }} state=present
          with_sequence: count=4
    

    1.2.7.8 随机选择 with_random_choice

    - debug: msg={{ item }}
      with_random_choice:
         - "go through the door"
         - "drink from the goblet"
         - "press the red button"
         - "do nothing"
    

    1.2.7.9 Do-Until循环

    重复一个任务直到某个条件满足

    - action: shell /usr/bin/foo
      register: result
      until: result.stdout.find("all systems go") != -1
      retries: 5
      delay: 10
    

    递归运行shell模块,直到模块结果中的stdout输出中包含all systems go字符串,或者该任务按照10秒的延迟重试超过5次

    1.2.7.10 循环中使用注册器

    使用register来注册变量,结果包含一个results属性

    示例:

    - shell: echo "{{ item }}"
      with_items:
        - one
        - two
      register: echo
    

    返回如下数据结构

    {
        "changed": true,
        "msg": "All items completed",
        "results": [
            {
                "changed": true,
                "cmd": "echo "one" ",
                "delta": "0:00:00.003110",
                "end": "2013-12-19 12:00:05.187153",
                "invocation": {
                    "module_args": "echo "one"",
                    "module_name": "shell"
                },
                "item": "one",
                "rc": 0,
                "start": "2013-12-19 12:00:05.184043",
                "stderr": "",
                "stdout": "one"
            },
            {
                "changed": true,
                "cmd": "echo "two" ",
                "delta": "0:00:00.002920",
                "end": "2013-12-19 12:00:05.245502",
                "invocation": {
                    "module_args": "echo "two"",
                    "module_name": "shell"
                },
                "item": "two",
                "rc": 0,
                "start": "2013-12-19 12:00:05.242582",
                "stderr": "",
                "stdout": "two"
            }
        ]
    }
    

    在tasks中循环注册变量,用来检测结果值

    - name: Fail if return code is not 0
      fail:
        msg: "The command ({{{ item.cmd }}}) did not have a 0 return code"
      when: item.rc != 0
      with_items: "{{ echo.results }}"
    
  • 相关阅读:
    Spring aop 记录操作日志 Aspect 自定义注解
    winSCP连接FTP没有上传的权限
    Ubantu下安装FTP服务器
    设置ubantu的软件源地址
    Ubantu中安装sublime
    Ubantu 新建用户后没有生成对应文件夹
    Spring aop 记录操作日志 Aspect
    Java中如何获取spring中配置文件.properties中属性值
    java中获取ServletContext常见方法
    解决:“java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut myMethod”问题!
  • 原文地址:https://www.cnblogs.com/CharrammaBlog/p/14767840.html
Copyright © 2020-2023  润新知