ansible

ansible

ansible简介

Ansible是一种开源的自动化工具,可以简化应用程序部署、配置管理和任务执行。它使用简单易懂的语法和模块化的架构,可在多个目标系统上自动化执行任务,包括配置管理、应用程序部署、编排等。

以下是一些关于Ansible的重要特点和功能:

  1. 简单易用: Ansible使用基于YAML的Playbook语法,使得编写和理解任务配置变得容易。无需编写复杂的代码,即可执行自动化任务。
  2. 无需客户端代理: Ansible通过SSH协议与目标主机进行通信,不需要在目标主机上安装客户端或代理程序。这简化了配置和管理的过程,并降低了部署的复杂性。
  3. 剧本和角色: Ansible使用Playbook来组织和执行任务。Playbook是一个包含多个任务的声明性配置文件,可以定义主机、变量、任务和角色等。角色是可复用的任务集合,可在多个Playbook中共享和引用。
  4. 模块化架构: Ansible的功能通过模块实现,模块是用于执行特定任务的代码块。Ansible提供了丰富的内置模块,涵盖了系统操作、配置管理、云服务、网络设备等各个领域。
  5. 多平台支持: Ansible能够管理和自动化多种操作系统和云平台,包括Linux、Windows、网络设备和云服务提供商如AWS、Azure、GCP等。
  6. 可扩展性: Ansible具有良好的扩展性,可以通过插件机制添加自定义模块、回调和插件,以满足特定的需求。
  7. 可靠性和可重复性: 使用Ansible进行自动化操作,可以确保一致性和可重复性。通过编写Playbook,可以定义所需的状态和配置,并确保在不同环境中的一致执行。

ansible安装和配置

安装
# 环境:centos7
yum -y install epel-release
yum -y install ansible
目录结构
tree /etc/ansible
|-- ansible.cfg
|-- hosts
`-- roles
配置ansible.cfg
# 默认不使用初始目录,一般会新建一个目录
cp -r /etc/ansible /root/ansible
# 配置ansible.cfg文件
cat >/root/ansible/ansible.cfg<< EOF
[defaults]
# some basic default values...
inventory      = /root/ansible/hosts
remoute_user   = root
host_key_checking = False
EOF
配置hosts
# hosts文件用来按组的方式编写主机列表
cat >/root/ansible/hosts<<EOF
[ansible]
192.168.12.12 host_name=ansible

[server1]
192.168.12.13 host_name=server1

[server2]
192.168.12.14 host_name=server2

#[all:vars]
#ansible_user=root
#ansible_ssh_pass=13579@st
EOF
内置变量
  1. ansible_host:主机的连接地址(IP地址或主机名)。
  2. ansible_port:SSH连接的端口号。
  3. ansible_user:SSH连接的用户名。
  4. ansible_ssh_pass:SSH连接的密码(不推荐使用,建议使用SSH密钥认证)。
  5. ansible_ssh_private_key_file:SSH连接的私钥文件路径。
  6. ansible_connection:主机连接方式,如sshlocal等。
  7. ansible_python_interpreter:远程主机上使用的Python解释器路径。
  8. ansible_distribution:远程主机的发行版名称。
  9. ansible_distribution_release:远程主机的发行版版本。
  10. ansible_architecture:远程主机的体系结构。
  11. ansible_facts:包含有关主机的事实(如CPU信息、内存、磁盘等)的字典。

除了上述变量,Ansible还提供了其他用于访问主机清单、任务和Playbook的信息的变量,如:

  • inventory_hostname:当前主机的名称(根据主机清单中的定义)。
  • inventory_hostname_short:当前主机的短名称(移除域名部分)。
  • groups:所有主机组的字典(组名作为键,包含组成员的列表作为值)。
  • hostvars:所有主机的字典(主机名作为键,包含主机变量的字典作为值)。
  • vars:Playbook中的全局变量。

ansible模块(应用)

command模块

​ 说明: 特殊符号,自定义变量不能使用)

  • args:要在目标主机上执行的命令。可以是单个命令字符串,也可以是包含多个命令的列表。

    - name: playbook名称
      hosts: all
      gather_facts: false  # 跳过检测,提升执行速度
      become: <boolean>    # 是否切换到特权用户执行任务
      become_user: <user>  # 切换到特权用户的用户名
      tasks:
      - name: Run command with args
        command:
          args: echo "Hello, World!"
    

    在上述示例中,args 参数指定要执行的命令,即输出 “Hello, World!”。

    ansible all -m command -a 'echo "Hello, World!"'
    
  • chdir:指定要执行命令时的工作目录。可以是绝对路径或相对路径。

      - name: Run command in specific directory
        command:
          cmd: pwd
          chdir: /path/to/directory
    

    在上述示例中,chdir 参数指定在 /path/to/directory 目录中执行 pwd 命令

    ansible all -m command -a 'chdir=/path/to/directory pwd'
    
  • creates:指定一个文件路径,如果该文件已经存在,则命令将被跳过。适用于避免重复执行相同的命令。

      - name: Run command if file does not exist
        command:
          args: echo "File does not exist"
          creates: /path/to/file.txt
    

    在上述示例中,creates 参数指定只有当 /path/to/file.txt 文件不存在时才执行命令.

    ansible all -m command -a 'creates=/path/to/file.txt echo "File does not exist"'
    
  • removes:指定一个文件路径,如果该文件不存在,则命令将被跳过。适用于确保文件存在时才执行的命令。

      - name: Run command if file exists
        command:
          args: echo "File exists"
          removes: /path/to/file.txt
    

    在上述示例中,removes 参数指定只有当 /path/to/file.txt 文件存在时才执行命令。

    ansible all -m command -a 'removes=/path/to/file.txt echo "File  exists"'
    
  • executable:指定要在目标主机上使用的可执行程序的路径。通常用于指定非默认的Shell。

      - name: Run command with custom shell
        command:
          args: ls -l
          executable: /bin/sh
    

    在上述示例中,executable 参数指定在目标主机上使用 /bin/sh 作为执行命令的 shell。

    ansible all -m command -a 'executable=/bin/sh ls -l'
    
shell模块

说明: 支持管道符等特殊符号,比command用途广泛

- name: Run shell command
  shell:
    cmd: "your_command_here"
    warn: true  # 可选参数,生成警告而不是失败
    executable: /bin/sh  # 可选参数,指定要使用的可执行程序
    creates: /path/to/file  # 可选参数,仅当文件不存在时运行命令
    removes: /path/to/file  # 可选参数,仅当文件存在时运行命令
    chdir: /path/to/directory  # 可选参数,指定命令运行的工作目录
  register: result_variable  # 可选参数,将命令输出保存到变量中

eg1: 列出目录下文件

  - name: ls dir
    shell:
      cmd: ls /data
      warn: true
    register: result
    tags: shell_ls
  - debug:
      var: result.stdout_lines
    tags: shell_ls

eg2: 执行多条命令

  # 忽略错误
  - name: Exec shell and ignore errors
    shell: echo "ignore_errors" && exit 1
    ignore_errors: true
  - name: Exec shell and ignore errors with /bin/true
    shell: echo "ignore_errors with /bin/true" && wrong_command || /bin/true
  - name: Exec shell and ignore errors with cat
    shell: echo "ignore_errors with cat" && wrong_command ||   
  # 执行多条命令
  - name: Exec multi line command with |
    shell: |
      echo "multi line command with |"
      echo "2"
      echo "3"
  - name: Exec multi line command with ;
    shell:
      echo "Exec multi line command with ;";
      echo "2";
      echo "3"
  # 执行多条命令
  - name: Exec multi shell command with &&
    shell: echo "Exec multi line command with &&" && echo "2"
  
  # 检查 test.log 是否存在,不存在则创建
  - name: Exec and check
    shell: ls|grep test.log
    register: test_log
    ignore_errors: true
  - name: Check test_log
    shell: touch test.log
    when: test_log.stdout == ""
script模块

模块允许在受控节点上执行本地脚本。使用script模块,您可以在远程主机上运行本地脚本,而无需将脚本复制到远程主机。

以下是script模块的详细说明:

参数

  • script:(必需) 本地主机上要运行的脚本的路径。
  • chdir:(可选) 要切换到的远程主机上的工作目录。
  • creates:(可选) 一个文件或目录的路径,如果此文件或目录已经存在,则不运行脚本。
  • 在远程主机上执行脚本

    - name: example scrpit module
      gather_facts: false
      hosts:
        - server1
      tasks:
        - name: exec script
          script: script-1.sh
          register: result
    
        - debug:
            var: result.stdout_lines
    
  • 在远程主机上的指定目录执行脚本

    - name: example scrpit module
      gather_facts: false
      hosts:
        - server1
      tasks:
        - name: exec script
          script: script-1.sh
          args:
            chdir: /tmp
          register: result
    
        - debug:
            var: result.stdout_lines
    
  • 在远程主机上指定目录,并判断某个文件如果存在,则不执行脚本

    - name: example scrpit module
      gather_facts: false
      hosts:
        - server1
      tasks:
        - name: exec script
          script: script-1.sh
          args:
            chdir: /tmp
            creates: /tmp/file  # 如果tmp目录下存在file文件则跳过执行script-1.sh
          register: result
    
        - debug:
            var: result.stdout_lines
    
file模块

file是 Ansible 的一个核心模块,它用于管理文件,软链接和目录。有了 file 模块,你可以设置文件的属性(例如权限、归属、创建硬链接和符号链接等),也可以创建、删除单个文件或目录。

参数:

  • path(必须):需要管理的文件/链接/目录的路径。
  • state:目标的状态。可以是 absent(不存在),directory(将目标设置为目录),file(设置为文件),touch(功能和 Unix的 ‘touch’ 类似),link(创建符号链接,或用 hard 创建硬链接),hard
  • mode:设置文件或目录的权限,可以使用数字 (比如 644) 或符号 (a=r,u+rw)。
  • owner:文件的拥有者。需要提供用户名,UID,或者 '.',If the user does not exist on the target platform, the numerical ID will be set. 要求Ansible用户具有权限更改该文件的所有者。
  • group:文件的所属组。需要提供组名,GID,或者 '.'。如果组在目标平台上不存在,则将设置数值ID。要求Ansible用户具有权限更改该文件的组。
  • 创建目录:

    - name: Create directory
      file:
        path: /path/to/directory
        state: directory
    
  • 创建文件

    - name: Create file
      file:
        path: /path/to/file
        state: touch
    
  • 更改文件权限和所有权:

    - name: Change file ownership, group and permissions
      file:
        path: /path/to/myfile
        owner: foo
        group: foo
        mode: '0644'
    
  • 删除文件:

    - name: Remove file
      file:
        path: /path/to/myfile
        state: absent
    
  • 创建软链接:

    - name: Create symlink
      file:
        src: /path/to/source
        dest: /path/to/dest
        state: link
    
  • 删除软链接

    - name: Remove file
      file:
        path: /path/to/dest
        state: absent
    
copy模块

copy 模块是 Ansible 的核心模块之一,用于将本地文件复制到托管的远程节点上。以下是关于该模块的详细解释:

  • 基本参数

  • src: 本地机器上的文件路径,这是你要复制到远程机器上的文件。

  • dest: 在远程机器上的目标路径。

  • content: 用于直接设置文件内容而不是从另一个文件复制的内容。当使用此参数时,不需要 src 参数。

  • force: 默认为 yes,如果设置为 no,则只在目标文件不存在时才会复制。

  • backup: 默认为 no。如果设置为 yes,在修改文件(例如更改权限或内容)之前,将对其进行备份。

  • remote_src: 默认为 no。如果设置为 yes,将使用远程机器上的文件作为源文件,而不是使用控制机上的文件。

  • 权限和所有权

  • owner: 文件的目标所有者。

  • group: 文件的目标组。

  • mode: 用于设置文件的权限。可以是数字(例如 0755)或符号表示法(例如 u=rw,g=r,o=r)。

  • 校验和验证

  • checksum: 用于验证文件的SHA-1校验和。通常,Ansible会自动计算这个值。

  • validate: 用于在将文件复制到其最终位置之前运行验证命令。这对于某些类型的文件(如配置文件)非常有用。

  • 案例

  • 简单复制

    - name: Copy file to remote machine
      copy:
        src: /local/path/file.txt
        dest: /remote/path/file.txt
    
  • 强制复制

    - name: Copy file to remote machine
      copy:
        src: /local/path/file.txt
        dest: /remote/path/file.txt
        force: yes
    
  • 设置权限和所有权

    - name: Copy with permissions and ownership
      copy:
        src: /local/path/file.txt
        dest: /remote/path/file.txt
        owner: user1
        group: group1
        mode: '0755'
    
  • 直接设置文件内容(覆盖的形式)

    - name: Set file content directly
      copy:
        content: "This is the file content."
        dest: /remote/path/file.txt
    
  • 复制远程机器上的文件

    - name: Copy file to remote machine
      copy:
        src: /remote/path/file.txt
        dest: /remote/path/file1.txt
        remote_rc: yes
    
  • 修改文件之前备份

    备份生效源文件必须存在

    - name: backup before change file
      copy:
        content: "shahhs"
        dest: /tmp/file04.txt
        owner: dockerroot
        mode: '0644'
        backup: yes
    
user模块
  • 创建单个用户并加sudo

    - name: create user single
      user:
        name: ansrole
        shell: /bin/bash
        password: "{{ '13579@st' | password_hash('sha512') }}"
      tags: single
    
    - name: sudo privilege single
      copy:
        content: "%ansrole ALL=(ALL) NOPASSWD: ALL"
        dest: /etc/sudoers.d/ansrole
      tags: single
    
  • 创建多个用户

    - name: create user multi
      user:
        name: "{{ item.name }}"
        shell: /bin/bash
        password: "{{ item.passwd | password_hash('sha512') }}"
      with_items:
        - {name: 'user01', passwd: '123456qq'}
        - {name: 'user02', passwd: '123456qw'}
        - {name: 'user03', passwd: '123456qe'}
      tags: multi
    
    - name: sudo privilege multi
      copy:
        content: "%{{ item }} ALL=(ALL) NOPASSWD: ALL"
        dest: "/etc/sudoers.d/{{ item }}"
      with_items:
        - 'user01'
        - 'user02'
        - 'user03'
      tags: multi
    
    
  • 删除多个用户

    - name: remove user multi
      user:
        name: "{{ item }}"
        state: absent
        remove: yes
      with_items:
        - 'user01'
        - 'user02'
        - 'user03'
      tags: remove
    
    - name: remove privilege file
      file:
        path: "/etc/sudoers.d/{{ item }}"
        state: absent
      with_items:
        - 'user01'
        - 'user02'
        - 'user03'
      tags: remove
    
cron模块

参数解析

  • name:cron任务的名称,需要在系统中唯一。

  • minute, hour, day, month, weekday:用于指定cron任务的执行时间。具体的时间值可以是数字(0-59)或特殊字符。

  • 特殊字符包括:

  • *:所有值。

  • */n:每隔n个时间单位执行。

  • n:具体的时间值。

  • job:指定cron任务要执行的命令或脚本的路径。

  • user:指定要运行cron任务的用户。默认为当前用户。

  • state:指定cron任务的状态。可以是present(任务存在)或absent(任务不存在)。

  • reboot:布尔值,设置为yes表示cron任务在系统重启后运行。

  • special_time:布尔值,设置为yes表示可以在minutehour参数中使用特殊时间字符串。

    创建一个任务

    - name: Create a cron job
      cron:
        name: "My cron job"
        minute: "*/5"
        job: "/path/to/my/script.sh"
        state: present
    
  • 修改现有的cron任务:

    - name: Modify a cron job
      cron:
        name: "My cron job"
        minute: "0"
        hour: "1"
        job: "/path/to/my/updated_script.sh"
        state: present
    
  • 删除cron任务:

    - name: Remove a cron job
      cron:
        name: "My cron job"
        state: absent
    
lineinfile模块
  • lineinfile模块的一些常用参数:

  • path: 指定要操作的目标文件的路径。

  • regexp: 用于匹配待操作的行的正则表达式。

  • line: 指定要添加或修改的行内容。

  • state: 指定行的状态。可以是present(存在,执行添加/修改行的操作)或absent(不存在,执行删除行的操作)。

  • backrefs: 是否使用后向引用,可以在替换时引用正则表达式的捕获组。

  • insertafter, insertbefore,,在某行之前/之后插入行,但是只在首次插入行时生效。

  • 在文件中添加一行(如果不存在该行)

    - name: Add a line to a file
      lineinfile:
        path: /path/to/file
        line: "This is the line to add"
        state: present
    
  • 修改文件中匹配某个正则表达式的行:

    - name: Modify a line in a file
      lineinfile:
        path: /path/to/file
        regexp: "^Some pattern.*"
        line: "New line content"
    
  • 删除文件中匹配某个正则表达式的行

    - name: Remove matching lines from a file
      lineinfile:
        path: /path/to/file
        regexp: "^Some pattern.*"
        state: absent
    
  • 在某行之前插入一行

    - name: Ensure we have our own comment added to /etc/services
      lineinfile:
        path: /etc/services
        insertbefore: '^www.*80/tcp'
        line: '# port for http by default'
    
  • 在某行之后插入一行

    - name: Ensure the default Apache port is 8080
      lineinfile:
        path: /etc/httpd/conf/httpd.conf
        insertafter: '^#Listen '
        line: Listen 8080
    
template模块

template模块是Ansible中用于生成配置文件的强大工具。它允许你使用模板文件和变量来动态生成目标主机上的配置文件。

参数解析

  • src:指定模板文件的路径。模板文件可以是本地文件或从Ansible控制节点的文件系统中的相对路径。
  • dest:指定生成的配置文件的路径和文件名。
  • owner, group, mode:可选参数,用于设置生成的配置文件的属主、属组和权限。
  • backup:是否创建配置文件的备份。可以使用yesno设置。
  • validate:验证生成的配置文件的语法是否正确的命令或脚本。
  • vars:一个字典类型参数,用于传递变量给模板文件。
  • 添加ip域名对应关系

    在ansible hosts文件中添加如下

    [tem]
    ip1 host_name=name1
    ip2 host_name=name2
    ip3 host_name=name3
    

    创建hosts.j2文件

    
    {% for host in groups['tem'] %}
    {{ hostvars[host].inventory_hostname }} {{ hostvars[host].host_name }}
    {% endfor %}
    

    创建template.yml

    - name: TEMPLATE EXAMPLE
      hosts: tem
      gather_facts: false
      tasks:
      - name: config hosts file
        template:
          src: ./hosts.j2
          dest: /etc/hosts
        tags: config
    
  • jinja2

变量描述
loop.index当前循环迭代的次数(从 1 开始)
loop.index0当前循环迭代的次数(从 0 开始)
loop.revindex到循环结束需要迭代的次数(从 1 开始)
loop.revindex0到循环结束需要迭代的次数(从 0 开始)
loop.first如果是第一次迭代,为 True 。
loop.last如果是最后一次迭代,为 True 。
loop.length序列中的项目数。
loop.cycle在一串序列间期取值的辅助函数。
  • for语法案例

    {% for host in groups['zookeeper'] %}
    sever.{{ loop.index }}={{ hostvars[host].inventory_hostname }}:2888:3888
    {% endfor %}
    
    {% for host in groups['etcd'] %}
    {% if not loop.last %}sever.{{ loop.index }}=http://{{ hostvars[host].inventory_hostname }}:2379,{% else %}{{%- endif %}
    {% endfor %}
    
  • if语法案例

    {% set var=2 %}
    {% if var %}
    var is: {{ var }}
    {% else %}
    var is not found
    {% endfi %}
    
  • 循环控制

  • 这个循环每两项跳过一次

    {% for user in users %}
        {%- if loop.index is even %}{% continue %}{% endif %}
        ...
    {% endfor %}
    
  • 这个循环 10 次迭代之后会终止处理

    {% for user in users %}
        {%- if loop.index >= 10 %}{% break %}{% endif %}
    {%- endfor %}
    
  • jinja2内置模板函数

  • range语法格式

    range([start, ]stop[, step])
    
  • range生成1~10内的奇数

    # 输出是一个列表
      - name: output range
        debug:
          msg: '{{ range(1,10,2)|list }}'
    
  • range结合count

    {% for item in users %}
    {{ item }}
    {% endfor %}
    
    {% for n in range(10 -users|count) %}
    {{ n }}
    {% endfor %}
    
    - hosts: localhost
      gather_facts: false
      tasks:
      - name: output range
        debug:
          msg: '{{ range(1,10,2)|list }}'
          # 将列表的内容以","拼接
          #msg: '{{ range(1,10,2)|list|join(',') }}'
    
      - name: range and count
        vars:
          users:
            - user1
            - user2
            - user3
        template:
          src: range.j2
          dest: /tmp/file1
        tags: rac
    
  • split

    split(“.”)将字符串以"."为分割线转化为列表

    {{ "192.168.4.1".split(".") }}
    
      - name: debug split
        debug:
          msg: '{{ "192.168.4.1".split(".") }}''
    

    split切片后重新转为字符

      # 将"192.168.4.1"拼接为"192.168.4.254"
      - name: debug split
        debug:
          msg: '{{ "192.168.4.1".split(".")[:3].join('.').254 }}''
          
    
    
  • trim

    移除字符串两边的空格

      - name: debug trim
        debug:
          msg: '{{ "  hello world  "|trim}'
    
循环(loop|with_*)
  • 标准循环

      - name: debug standard criculation
        debug:
          msg: '{{ item }}'
        with_items:
          - user1
          - user2
          - user3
          - user4
        tags: stand
    
      - name: debug stand criculation
        debug:
          msg: '{{ item.name,item.groups}}'
        with_items:
          - {name: 'user01', groups: 'wheel'}
          - {name: 'user02', groups: 'nginx'}
          - {name: 'user03', groups: 'root'}
        tags: stand
    
  • 嵌套循环

      - name: debug nest criculation
        debug:
          msg: '{{ item.name,item.groups}}'
        with_nested:
          - ['Alice','Joker']
          - ['clientdb', 'employeedb', 'providerdb']
        tags: nest
    
  • 对哈希表循环

      - name: debug hash criculation
        vars:
          users:
            Alice:
              name: Alice Mreia
              phone: 125-223-397
            Bob:
              name: Bob Wer
              phone: 526-129-287
        debug:
          msg: 'User: {{ item.key }} is {{ item.value.name }} ({{ item.value.phone }})'
        with_dict:
          - '{{ users }}'
        tags: hash
    
  • 对文件列表使用循环

      - name: debug file list criculation
        debug:
          msg: '{{ item }}'
        with_fileglob:
          - /etc/*
        tags: file 
    
  • 对并行数据集循环

      - name: debug parallel data criculation
        debug:
          msg: '({{ item.0 }},{{ item.1 }})'
        with_together:
          - ['a','b','c']
          - [1,2,4]
        tags: paral
    
  • Do-until循环

    重试一个任务直到达到某个条件

      - name: 
        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次.”retries”和”delay”的默认值分别是3和5.

  • 循环中使用注册器

    - name: Loop with registered variable example
      hosts: localhost
      gather_facts: false
      vars:
        fruits:
          - apple
          - banana
          - orange
      tasks:
        - name: Print fruits
          debug:
            msg: "Fruit: {{ item }}"
          loop: "{{ fruits }}"
          register: loop_result
    
        - name: Print registered variable
          debug:
            msg: "Registered: {{ loop_result.results | map(attribute='item') | list }}"
    

    描述: 使用注册变量loop_result.results并通过mapattribute过滤器提取item属性,最后转换为一个列表,以输出注册变量中的值。

条件选择(when)
  • 当ansible_os_family为ReadHat时执行shell

      tasks:
      - name: 
        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:
      - name:
        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
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值