Ansible 自动化运维入门基础

Ansible基础

简介

  • Ansible是一个开源的IT自动化运维工具,能够批量配置系统,部署软件,编排其他更复杂的IT任务如零停机时间滚动更新。Ansible本身没有自动化能力。真正具有批量部署自动化的是Ansible运行的模块,最大的特点就是基于ssh远程通信不需要在远程的主机上安装client/agents。Ansible目前已经已经被红帽官方收购,是自动化运维工具中大家认可度最高的,并且上手容易,学习简单。是每位运维工程师必须掌握的技能之一。

特点

  • 简单:Ansible使用yaml语言,具有人工可读的特点,无需特殊编码技能,playbook中是按照模块顺序执行。
  • 强大:Ansible支持通过PowerShell管理Windows(只能被控),具有幂等性,在Ansible中如果执行报错可以多次重复执行对结果影响是一致的。
  • 无代理:无需在被管客户端安装客户端,Windows中通过winrm原生支持的远程管理方式;Linux中通过ssh;网络设备通过snmp简单网络管理协议;公有云/私有云通过云平台的API接口管理。

架构及组件

  • 架构
    Ansible架构.png
  • 组件
    • 核心:Ansible本体
    • 核心模块:(Core Modules)自带的模块
    • 扩展模块:(Costome Modules)核心模块不足以完成的任务可以添加扩展模块
    • 插件:(Plugins)补充完成模块的功能
    • 剧本:(Playbook)定义需要完成的多个任务
    • 连接插件:(Connection Plugins)用来连接主机和Ansible,虽然Ansible基于ssh但是也可以用其他连接方法所以需要连接插件
    • 主机清单:(Host Inventory)记录由Ansible管理的主机信息,ansible在管理多台主机时,可以选择只对其中的一部分执行某些操作
      ansible 只能管理清单中的主机,如果被管理的主机不在清单中,ansible不执行任务

工作机制

Ansible工作机制.png

  1. 解析Inventory主机清单,在执行任务之前Ansible都会解析主机清单确定需要被管理节点
  2. SSH连接到被管理节点,Ansible会验证SSH密钥并启动一个临时的SSH连接进程
  3. 执行任务,建立连接之后Ansible通过模块执行对应的操作,模块是Ansible执行每个任务的工具,如文件操作、软件包安装、服务启动等。Ansible会将任务分发给所有被管理节点,并在这些节点上执行相应的操作。当任务执行完成后,Ansible会收集任务执行结果并返回给控制节点。
  4. 关闭连接,任务完成之后会关闭与被控的联系,停止与被控SSH连接

Ansible安装

# 至少需要两台主机,以servera和serverb演示
# 以使用CentOS7.6系统及华为开源镜像站源作为演示
0.前置操作
配置好固定IP
添加hosts域名解析
vim /etc/hosts# 将两台主机IP和主机名添加

1.配置yum源
wget -O /etc/yum.repos.d/CentOS-Base.repo https://repo.huaweicloud.com/repository/conf/CentOS-7-reg.repo

yum clean all

yum makecache

2.配置epel源
sed -i "s/#baseurl/baseurl/g" /etc/yum.repos.d/epel.repo

sed -i "s/metalink/#metalink/g" /etc/yum.repos.d/epel.repo

sed -i "s@https\?://download.fedoraproject.org/pub@https://repo.huaweicloud.com@g" /etc/yum.repos.d/epel.repo

yum update

3.安装ansible
yum install ansible

4.确认安装
ansible -v

5.Ansible与其他不同,获取的配置文件会从多个地方查找作为学习测试使用可以将其复制之后修改(之后执行需到复制的目录下)
mkdir /example

cp -r /etc/ansible /example

6.免密
ssh-keygen -t rsa# 全部回车

cd /root/.ssh

ssh-copy-id -i ~/.ssh/id_rsa.pub root@serverb

sshroot@serverb

ssh-keygen -t rsa# 全部回车

cd /root/.ssh

ssh-copy-id -i ~/.ssh/id_rsa.pub root@servera

exit

cd /example

ls /example
ansible.cfg  hosts  roles

ansible.cfg#Ansible配置文件
hosts    #主机清单(可以自己修改,需要在配置文件中配置为对应地址即可)
roles#存放角色的文件夹

Ansible用法

主机清单

主机清单中写的内容为主机名或者是IP地址,主机名的话需要配置/etc/hosts 能够被解析到。默认的主机清单为/etc/ansible/hosts,也可以通过修改配置文件来更改其他位置具体我们在下面配置文件中会写到。

主机清单的格式:

  1. 主机名或IP
    servera
    serverb
    192.168.100.100
    192.168.100.200
  2. 主机组
    [组名]
    成员主机
    成员主机
    [dev]
    192.168.100.200
    servera
  3. 主机和主机组(同时出现则需要把主机放在主机组前以免ansible将单个主机识别为主机组内)
    servera
    [dev]
    serverb
    serverc
  4. 主机组嵌套(有web和database两个组,组内分别包含了几台主机。dev组内包含web和database两个组所有的主机即为嵌套)
    [web]
    web1
    web2
    [database]
    db1
    db2
    [dev:children] # 嵌套格式 [组名:children] 下边跟上要添加的组
    web
    database

Ansible主机清单支持定义范围

** **举例:如果有web01web50,50台主机加入webservers组。database组中有从serveraserverd5台主机

** **[webservers]

** **web[01:50]

** **[database]

** **server[a:z]

配置文件

Ansible的配置文件名为ansible.cfg,一般存在四个地方

  1. ANSIBLE_CONFIG:环境变量
  2. ./ansible.cfg:当前工作目录,当前执行ansible命令的目录(ansible对执行命令的工作的目录比较敏感)
  3. ~/.ansible.cfg:当前用户家目录下隐藏文件
  4. /etc/ansible/ansible.cfg:默认的配置文件
    优先级为:首先检查环境变量,优先使用工作目录下的配置文件,然后为当前用户家目录下的隐藏文件,最后如果都没有则使用默认的/etc/ansible/ansible.cfg

配置文件分为十段

[defaults]   # 通用配置

[inventory]   # 主机清单相关

[privilege_escalation]    # 提权相关

[paramiko_connection]    # 早期连接方式(RHEL6)

[ssh_connection]    # ssh链接配置

[persistent_connection]# 持久链接配置

[accelerate]   # 加速链接配置

[selinux]   # selinux配置项

[colors]   # 定义执行后输出结果的颜色

[diff]   # 差异比较

配置案例

[defaults] 

inventory   = ./hosts  # 主机清单的位置(基于当前目录)

ask_pass    = false   # false表示秘钥验证 true 密码验证

remote_user =  root  # 表示使用root来ssh管理被控也可以自行创建其他远程用户

log_path    = /var/log/ansible.log   # 指定ansible的日志文件位置

host_key_checking = False # 如果是第一次ssh链接被控,自动信任主机公钥

[privilege_escalation]

become=True  # 开启提权

become_method=sudo # 提权的方式sudo

become_user=root   # 提权到root

become_ask_pass=False  # 提权不需要密码

[ssh_connection]

ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no   # ssh的加速链接项

如果设置其他远程用户需要注意被控端需要创建用户设置密码,做好免密提权

配置完成之后使用ping模块测试连通性(工作目录执行)

ansible all -m ping # 使用ping 模块测试

image-20230724161248281.png

执行任务

Ad-hoc

Ad-hoc:ansible临时命令,常用来执行单个模块的命令

格式一般为

ansible 执行的被控主机 -m 使用的模块 -a '模块的参数' ansible参数

ansible   servera    -m    user   -a    ‘name=devops’    -u   root     -k

在servera这台主机上使用user模块创建一个名字叫devops的用户,指定以root用户ssh链接并提示输入ssh密码

ansible官方提供了大量模块,可以通过一下命令查询

ansible-doc-l# 查看所有模块

ansible-doc-smodule     # 查看某个模块参数

ansible-docmodule# 模块详细用法

例子:为所有主机配置yum源(RHEL8)

ansibleall-myum_repository-a"name=BASEOS description='BaseOS' file=rhel_dvd baseurl=file:///media/cdrom/BaseOS gpgcheck=yes gpgkey=file:///media/cdrom/RPM-GPG-KEY-redhatrelease enable=yes"
ansibleall-myum_repository-a"name=APPSTREAM description='AppStream' file=rhel_dvd baseurl=file:///media/cdrom/AppStream gpgcheck=yes gpgkey=file:///media/cdrom/RPM-GPG-KEY-redhatrelease enable=yes"

playbook

Playbook:ansible剧本,由一个或多个play组成,play主要作用就是对规定的主机使用定义好的task。而一个task就是对ansible一个module(模块)的调用,将多个play按照一定顺序编写进一个playbook称之为编排。

一般playbook为 .yml 格式,在 Ansible Playbook 中,缩进是非常重要的,因为它用于表示层级关系和嵌套结构。正确的缩进可以确保 Playbook 的语法正确,并且逻辑清晰可读。缩进时不允许使用Tab键只能使用空格,空格数目不重要左侧对齐即可。

执行playbook:

ansible-playbookxxx.yml

playbook是依次执行,从上至下如果任务在某一个任务执行报错,则不会再继续执行。如果有任务在所有主机上都执行失败了则剧本会退出。

playbook错误处理,如果存在报错退出,可以根据提示信息修改,修改完成之后再次执行不用担心任务会重复执行产生问题(幂等性)会从错误的地方继续执行之前已经执行成功的会跳过。

Handler(处理程序)

handler用来处理ansible中任务状态,当一个或几个任务结果发生变化时通过notify监听任务触发handler,本质上handler也是一个task,只是默认不执行,只有被触发时才会执行,会在所有play都执行完之后才会执行避免重复执行。

语法校验

ansible-playbook	--syntax-check	xxx.yml

测试运行playbook(测试playbook执行情况,不会实际生效)

ansible-playbook	-C	xxx.yml
- name: Example Playbook		# playbook的名称,一般描述剧本内容
  hosts: servera				# 指定执行的主机或者主机组
  remote_user: root				# 连接的用户

  tasks:						# 执行的任务
    - name: Create user				# 此任务模块的描述信息
      user:						# 使用了user这个模块
        name: zhangsan				# 模块内参数:创建名字叫张三的用户
        state: present				# 模块内参数:动作为创建用户
        shell: /bin/bash			# 模块内参数:指定shell为bash shell

    - name: Install package			# 此任务模块描述信息
      yum:							# 使用yum这个模块
        name: httpd					# 模块内参数:对httpd进行操作
        state: present				# 模块内参数:动作为安装
# 通用的标准格式模板
- name: Playbook name   # Playbook描述信息
  hosts: target_hosts   # 指定目标主机或主机组
  become: yes           # 是否切换到特权(sudo)模式
  remote_user: username # 指定远程连接的用户名

  vars:                 # 变量定义
    var_name: var_value
    another_var: another_value

  tasks:                # 任务列表
    - name: Task name
      module_name:
        module_parameter: value
      register: variable_name

    - name: Another task
      module_name:
        module_parameter: value
      when: condition

  handlers:             # 处理程序
    - name: Handler name
      notify:
        - Task name

  roles:                # 引用角色
    - role1
    - role2

playbook常用模块

shell和script

Ansible 提供了 shell 模块和 script 模块,用于在远程主机上执行 Shell 命令或脚本。

  1. shell 模块: shell 模块用于在远程主机上执行 Shell 命令。它适用于简单的命令行操作,例如执行一条命令并获取其输出。
  2. script 模块: script 模块用于在远程主机上执行本地的脚本文件。它将本地脚本文件上传到远程主机,并在远程主机上执行该脚本。
    • shell 模块适用于简单的命令行操作,而 script 模块适用于执行复杂的脚本文件。
    • shell 模块不需要提前准备脚本文件,它直接在远程主机上执行一次性的命令。而 script 模块需要在控制节点上准备好要执行的脚本文件,并将其上传到远程主机。
    • shell 模块实时输出命令的执行结果,而 script 模块将整个脚本文件上传到远程主机后才返回结果。

示例

  1. 用shell执行命令
    - name: 执行 Shell 命令
      shell: ls -l /path/to/directory
    
  2. 用script执行脚本(脚本需提前上传至被控端)
    - name: 执行脚本
      script: /path/to/script.sh
    

file

Ansible 的 file 模块用于管理文件和目录。它提供了一系列的操作,可以链接、创建、修改、删除文件或目录,并设置相应的权限和所有权。

主要选项:

  • path :指定文件或者目录的路径(必选)
  • owner:指定文件或者目录的拥有人
  • group:指定文件或者目录的拥有组
  • mode:设置文件或者目录的权限(ACL)
  • state:操作(创建,修改,删除)

示例:

创建目录:

- name: 创建目录
  file:
    path: /path/to/directory
    state: directory
    mode: '0755'

创建文件:

- name: 创建文件
  file:
    path: /path/to/file.txt
    state: touch
    mode: '0644'

修改文件权限:

- name: 修改文件权限
  file:
    path: /path/to/file.txt
    mode: '0755'

修改文件所有权:

- name: 修改文件所有权
  file:
    path: /path/to/file.txt
    owner: new_owner
    group: new_group

复制文件:

- name: 复制文件
  file:
    src: /path/to/source/file.txt				# 源端 
    dest: /path/to/destination/file.txt			 # 目的端
    remote_src: yes							    # 删除源端

删除文件或目录:

- name: 删除文件或目录
  file:
    path: /path/to/file_or_directory
    state: absent

copy

Ansible中copy模块主要用于将文件或者目录从控制端复制到被控端

需要注意的是,Ansible会将源文件或目录复制到指定目标位置,如果位置不存在则自动创建。如果已经存在会直接放入;如果存在同一文件则会覆盖。复制多个文件可以使用循环或者include_tasks。

主要选项:

  • src: 指定要复制的源文件或源目录的路径。可以是控制节点上的绝对路径或相对路径。
  • dest: 指定目标文件或目录在远程主机上的路径。可以是远程主机上的绝对路径或相对路径。

示例:

- name: 复制文件到远程主机
  copy:
    src: /path/to/local/file
    dest: /path/to/remote/file

- name: 复制目录到远程主机
  copy:
    src: /path/to/local/directory/
    dest: /path/to/remote/directory/

yum_repository

Ansible中yum_repository模块主要用于管理 yum 软件源配置文件。

主要选项:

  • name: 指定软件源的名称。
  • description: 指定软件源的描述信息。
  • baseurl: 指定软件源的基础 URL,即软件包所在的位置。
  • gpgcheck: 指定是否要进行 GPG 校验,可选值为 "yes"(进行 GPG 校验)和 "no"(不进行 GPG 校验)。
  • gpgkey: 指定 GPG 密钥文件的路径。
  • state: 指定要执行的操作,可选值为 "present"(创建或更新软件源配置)和 "absent"(删除软件源配置)。

示例:

- name: 添加 EPEL 软件源
  yum_repository:
    name: epel
    description: Extra Packages for Enterprise Linux 7 - $basearch
    baseurl: http://download.fedoraproject.org/pub/epel/7/$basearch
    gpgcheck: yes
    gpgkey: /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
    state: present

- name: 删除 EPEL 软件源
  yum_repository:
    name: epel
    state: absent

yum

Ansible中yum模块主要用于在远程主机上执行 yum 包管理器相关的操作,例如安装、升级、删除软件包等。

主要选项:

  • name: 指定要进行操作的软件包名称。可以是单个软件包名称,也可以是多个软件包名称列表。
    • 列表可以使用loop循环
    • 包组使用格式:“@XXX”
  • state: 指定要执行的操作,可选 "present"(安装软件包)和 "absent"(删除软件包)。

示例:

- name: yum example
  hosts: all
  tasks:
     - name: 安装 mariadb php
       yum:
           name: "{{ item }}"
           state: present
       loop:
         - php
         - mariadb
     - name: 安装 Development Tools
       yum:
           name: "@Development Tools"
           state: present
     - name: 升级所有包
       yum:
           name: '*'
           state: latest

service

Ansible中service模块主要用于管理系统服务。它可以启动、停止、重启或重新加载服务,并检查服务的状态。

主要选项

  • name :指定要进行操作的软件包名称。
  • state:指定要执行的操作,可选 "started"(启动服务); "stoped"(停止服务);“restarted”(重启服务)。

示例

启动服务

- name: 启动服务
  service:
    name: apache2
    state: started

停止服务

- name: 停止服务
  service:
    name: apache2
    state: stopped

重启服务

- name: 重启服务
  service:
    name: apache2
    state: restarted

重新加载服务配置

- name: 重新加载服务配置
  service:
    name: apache2
    state: reloaded

systemd

**Ansible 中的 **service 模块和 systemd 模块都用于管理和操作系统服务,但它们在实现和使用上有一些不同之处。

相同之处:

  1. 目标:两个模块的目标都是管理服务,包括启动、停止、重启等操作。
  2. 跨平台支持:service 模块和 systemd 模块都可以在不同的操作系统上使用,例如 Linux、Unix 和一些 Windows 版本(具体取决于操作系统的服务管理机制)。

不同之处:

  1. 实现机制:service 模块是基于 SysVinit 或 Upstart 等传统的初始化系统,而 systemd 模块则使用 Systemd 系统守护进程。这意味着根据目标主机的不同,您可能需要选择适合的模块来管理服务。
  2. 选项和参数:由于底层实现的不同,service 模块和 systemd 模块具有不同的选项和参数。例如,service 模块通常使用 name 参数指定服务的名称,而 systemd 模块则使用 name 参数指定服务的名称,并使用 state 参数指定操作(如启动、停止、重启等)。
  3. 功能支持:由于 Systemd 的高级功能,systemd 模块通常提供更丰富的功能支持。例如,您可以使用 systemd 模块设置服务的启动顺序、依赖关系、定时任务等。而 service 模块通常只提供基本的服务管理功能。
  4. **平台限制:由于 **service 模块是基于传统的初始化系统,因此它在一些新的 Linux 发行版中可能不被完全支持,而 systemd 模块则可以更好地适应当前流行的 Systemd 初始化系统。

cron

在 Ansible 中,可以使用 cron 模块来管理和配置 cron 作业。cron模块可以创建、更新和删除 cron 作业,并指定作业的执行时间表、要运行的命令等。

主要选项

  • name(必需):指定 cron 作业的名称。
  • minute:指定 cron 作业执行的分钟数。可以是一个具体的数值(0-59)、逗号分隔的多个数值、区间(例如:1-30),或者使用星号(*)表示任意。
  • hour:指定 cron 作业执行的小时数。格式与 minute 相同。
  • day:指定 cron 作业执行的日期。可以是一个具体的数值(1-31)、逗号分隔的多个数值、区间,或者使用星号表示任意。
  • month:指定 cron 作业执行的月份。可以是一个具体的数值(1-12)、逗号分隔的多个数值、区间,或者使用星号表示任意。
  • weekday:指定 cron 作业执行的星期几。可以是一个具体的数值(0-7,其中 0 和 7 都代表星期日)、逗号分隔的多个数值、区间,或者使用星号表示任意。
  • job(必需):指定 cron 作业要运行的命令或脚本。
  • state:指定 cron 作业的状态。可选值为 present(默认,表示作业存在且符合定义)和 absent(表示作业将被删除)。
  • user:指定运行 cron 作业的用户。如果未指定,默认为当前用户。
  • environment:设置 cron 作业的环境变量。可以是一个字典,其中键值对表示要设置的环境变量。

示例

创建一个定时任务

- name: Create a cron job
  cron:
    name: "My Cron Job"
    minute: "30"
    hour: "2"
    job: "/path/to/my_command"

更新定时任务

- name: Update a cron job
  cron:
    name: "My Cron Job"
    minute: "0"
    hour: "8"
    job: "/path/to/updated_command"

删除定时任务

- name: Remove a cron job
  cron:
    name: "My Cron Job"
    state: absent

user和group

在Ansible中,有两个模块可以用于管理系统中的用户和用户组:user 模块和 group 模块。

主要选项

**对于 **user 模块:

  • name(必需):指定用户的名称。
  • comment:为用户添加注释。
  • password:设置用户的密码。
  • shell:指定用户的默认 Shell。
  • home:指定用户的家目录路径。
  • uid:为用户指定一个特定的 UID。
  • state:指定用户的状态。可选值为 present(默认,表示用户存在且符合定义)、absent(表示用户将被删除)或 locked(锁定用户)等。

**对于 **group 模块:

  • name(必需):指定用户组的名称。
  • gid:为用户组指定一个特定的 GID。
  • state:指定用户组的状态。可选值为 present(默认,表示用户组存在且符合定义)或 absent(表示用户组将被删除)等。

示例

创建用户

- name: Create a user
  user:
    name: myuser
    password: mypassword
    state: present

创建组

- name: Create a group
  group:
    name: mygroup
    state: present

变量

Ansible支持使用变量,用于会重复使用到的值,以便简化项目降低出错。

变量要求

  1. 变量名只能有字母、数字或者下划线来组成
  2. 且变量名必须以字母开头
  3. ansible的内置关键字不能作为变量(定义时尽量不要以ansible开头)

Inventory主机清单变量

内置的环境变量,可以直接调用的。

  • 连接变量
    • ansible_host # 被控端主机IP
    • ansible_port # 主机端口
    • ansible_user # 连接使用的用户
  • 提权变量
    • ansible_become # 允许使用提权相当于ansible_sudo
    • ansible_become_user # 提权之后的权限相当于root用户
    • ansible_become_pass # 密码
    • ansible_sudo_exec # 路径
  • 连接变量
    • ansible_connection # 连接类型默认ssh
    • ansible_ssh_pass # 连接ssh密码
    • ansible_ssh_private_key # 密钥文件
    • ansible_ssh_exec # ssh不在默认路径则通过此改变路径

自定义变量

在playbook中可以通过vars来自定义使用变量,vars在tasks之上

定义示例

- name: vars example
  hosts: all
  vars:
    port: 80
    host_name: servera
    file: /etc/passwd

引用变量

- name: vars example
  hosts: all
  vars:
    port: 80
    host_name: servera
    file: /etc/passwd
  tasks:
    - name: print vars
      shell: echo "{{ port }} {{ host_name }} {{ file }}" > /test.txt

fact变量

ansible中存在一个setup模块可以用来获取远程主机的信息并且可以在playbook中直接调用。setup模块获取这些信息就是依赖fact,返回数据为json格式。

查看所有fact信息

ansible	all	-m	setup

查看内存信息

ansible	all	-m	setup	-a	'filter=ansible_*_mb'

查看网卡信息

ansible	all	-m	setup	-a	'filter=ansible_ens160'

常用关键字

ansible_distribution		# 显示系统发行版本
ansible_distribution_version	# 显示系统具体发行版本号
ansible_hostname			# 主机名
ansible_interfaces           # 网络接口列表
ansible_kernel				# 内核版本
ansible_devices				# 显示磁盘设备信息

魔法变量

在Ansible中,魔法变量(Magic Variables)是指一些特殊的预定义变量,它们提供了有关任务、主机和执行环境的额外信息。这些变量可用于在剧本中执行条件检查、动态配置和操作控制等。

hostvars

**用来获取某台指定的主机相关的变量,使用前提是需要确保已经收集到这些变量。您可以在使用 **gather_facts 关键字将远程主机的信息收集到 Facts 变量后,才能使用 hostvars 访问它们。

示例:

# 需要注意['servera']中servera只能是主机名不能用IP地址
# 调用主机IP
{{ hostvars['servera'].ansible_eth0.ipv4.address }}

# 显示其他主机的变量值
{{ hostvars['servera'].some_variable }}

inventory_hostname

**Ansible 中的一个特殊变量,它包含当前主机在清单文件中定义的名称。也就是说,它表示当前正在执行任务的主机的名称。使用 **inventory_hostname 变量可以方便地在剧本中引用当前主机的名称,无需显式指定主机名。

示例

# 识别当前正在运行的task的主机的主机名
{{ hostvars[inventory_hostname].ansible_eth0.ipv4.address }}

条件循环

条件

  • 在实际生产过程中,有时候play的结果依赖变量或迁移任务的结果,这个时候就可以采用条件判断是否执行操作。而这个条件判断的关键字就是wher
  • 示例
    # 这是一个判断系统为Redhat或Debian或者都不是的情况下安装对应的版本vim,或者报出is not supported
    - name: when example
      hosts: all
      tasks:
        - name: install vim
          yum:
            name: vim-enhanced
            state: installed
          when: ansible_os_family == "Redhat"
            - name: Install VIM apt
              apt:
                name: vim 
                state: installed
              when: ansible_os_family == "Debian"
            - name: Unexpected OS family
              debug: msg="OS Family {{ ansible_os_family }} is not supported"
              when: not ansible_os_family == "RedHat" or ansible_os_family == "Debian"
    

运算比较符

==:是否相等,相等则为真
!=:是否不等,不等则为真
>:是否左边大于右边,则为真
<:是否左边小于右边,则为真
>=:是否左边大于等于右边,则为真
<=:是否右边大于等于左边,则为真

逻辑运算符

and:逻辑与,左右同时为真,则为真
or:逻辑或,左右任意一个为真,则为真
not:逻辑否,对表达式取反
():组合表达式,组合内都是逻辑与关系

block

block 多个任务进行判断

** 多个任务使用同一个条件来进行判断,可以使用block 区块方式来进行,block可以将多个任务放到一个区域中,使用同一个条件来进行判断**

- name: block
  hosts: all
  tasks:
    - block:
      - yum:
        name: httpd
        state: present
      - yum:
        name: mariadb
        state: present
      - yum:
        name: php
        state: present
  when: ansible_os_family == "Redhat"

rescue

rescue对block中错误的任务进行处理

** rescue专门用来处理block中出错的任务,只有block出错才会触发rescue执行其中的任务**

tasks:
        - block:
                - shell: ls /opt/demoa
          rescue:
                - file:
                        path: /opt/demo
                        state: directory
                - debug:
                        msg: "hello ansible"

always

always 无论如何都要执行

** rescue必须依赖于block中的任务出错才会执行;但是always无论block中的任务是否报错,其都会执行**

tasks:
        - block:
                - shell: ls /opt/demoa
          rescue:
                - file:
                        path: /opt/demo
                        state: directory
                - debug:
                        msg: "hello ansible"
          always:
                  - debug:
                          msg: "hello always"

fail

fail 模块 专门用来结束剧本运行(和when连用时,当任务达到指定条件则结束运行);选项 msg 打印结束信息(出错信息)

tasks:
          - debug:
                  msg: "msg1"
          - debug:
                  msg: "msg2"
          - fail:
				  msg: “exit playbook”
            when: ansible_os_family == "RedHat"

failed_when: 对任务进行判断,条件成立时直接结束运行

tasks:
          - debug:
                  msg: "msg1"
          - debug:
                  msg: "msg2"
            failed_when: ansible_os_family == "RedHat"
          - debug:
                  msg: "msg3"

循环

在ansible中可以用两种方式来实现循环,在ansible2.5之前使用的是with_的方式,虽然这种方式还可以继续使用但不免未来的版本会删除废弃掉。在ansible2.5之后采用loop进行循环,所有在此便不在举例with_的方式。

遍历列表

- name: Loop over a list
  debug:
    msg: "Item: {{ item }}"
  loop:
    - item1
    - item2
    - item3

遍历字典

- name: Loop over a dictionary
  debug:
    msg: "Key: {{ item.key }}, Value: {{ item.value }}"
  loop: "{{ my_dict | dict2items }}"

jinja2模板

Jinja2 是 Python 中广泛使用的模板引擎,它也是 Ansible 中默认的模板引擎。Jinja2 提供了一种在模板中嵌入表达式的方式,这些表达式可以通过变量、过滤器、控制结构等进行扩展。使用 Jinja2,可以在 Ansible Playbook 的模板文件中动态生成配置文件、命令等内容,以适应不同的环境和条件。

作用

  • 变量替换:使用 Jinja2 表达式可以将变量的值动态插入到模板文件中,实现配置的个性化定制。
  • 条件和循环:使用 Jinja2 的控制结构(如 if 语句和 for 循环)可以根据条件执行不同的操作或迭代处理数据。
  • 过滤器:Jinja2 提供了一系列内置的过滤器,用于对变量进行处理和转换,例如格式化日期、字符串处理等。
  • 模板继承和包含:可以使用 Jinja2 的继承和包含特性来复用和组织模板代码,提高模板的可维护性和复用性。

常见选项

  • {% control_structure %}:通过控制结构(如 if/else、for 循环)来实现条件判断或循环操作。
  • {{ variable_name | filter_name }}:使用过滤器对变量进行转换和处理。
  • {% extends 'base_template' %}:继承其他模板,可以将公共部分放在基础模板中,然后在子模板中进行扩展。
  • {% include 'partial_template' %}:包含其他模板,可以将模板的一部分作为独立模块引入到当前模板中。
  • {{ variable_name }}:通过双大括号可以在模板中引用变量。

示例

  • 动态生成Nginx配置文件

playbook内容:

- name: 生成 Nginx 配置文件
  hosts: web_servers
  vars:
    nginx_listen_port: 80
    upstream_servers:
      - 192.168.1.10
      - 192.168.1.11
      - 192.168.1.12
  tasks:
    - name: 生成 Nginx 配置文件
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf

Nginx模板文件(nginx_config.j2):

http {
    upstream backend {
        {% for server in upstream_servers %}
        server {{ server }};
        {% endfor %}
    }

    server {
        listen {{ nginx_listen_port }};
        location / {
            proxy_pass http://backend;
        }
    }
}
  • 根据主机列表生成SSH配置文件

playbook文件内容

- name: 生成 SSH 配置文件
  hosts: bastion_host
  vars:
    ssh_hosts:
      - host1.example.com
      - host2.example.com
      - host3.example.com
  tasks:
    - name: 生成 SSH 配置文件
      template:
        src: ssh_config.j2
        dest: /etc/ssh/ssh_config

SSH配置模板文件ssh_config.j2

{% for host in ssh_hosts %}
Host {{ host }}
    Port 22
    User your_username
    IdentityFile ~/.ssh/id_rsa
{% endfor %}

角色

什么是角色

roles的出现是为了简化playbook的编写,我们将一个playbook拆分成多个文件目录;将其称为roles(角色)

创建角色

# 创建一个名为apache的角色,角色名就是目录名,使用init会帮助我们在当前目录下创建一个角色目录结构
ansible-galaxy init  apache

role目录构成

role_name/
├── tasks/
│   └── main.yml
├── handlers/
│   └── main.yml
├── files/
│   └── <additional files>
├── templates/
│   └── <template files>
├── vars/
│   └── main.yml
├── defaults/
│   └── main.yml
├── meta/
│   └── main.yml
└── README.md
  1. tasks/:该目录包含角色的任务文件。通常,main.yml 文件位于此目录中,定义了要在目标主机上执行的操作流程。
  2. handlers/:这个目录包含角色的处理器文件。处理器定义了在配置更改时触发的操作,例如重启服务或重新加载配置。通常,main.yml 文件位于此目录中,定义了处理器任务。
  3. files/:您可以将需要复制到目标主机的静态文件放在这个目录中,例如脚本、配置文件等。
  4. templates/:在这个目录中,您可以放置使用模板语法定义的模板文件。这些模板文件将根据变量的值动态生成内容,例如配置文件。
  5. vars/:在这个目录中,您可以定义角色的变量。这些变量可以在角色的任务和模板中使用,以根据需要定制行为。通常,main.yml 文件位于此目录中,定义了角色的变量。
  6. defaults/:如果用户未覆盖角色的变量,将使用该目录中的默认变量值。通常,main.yml 文件位于此目录中,定义了角色的默认变量。
  7. meta/:这个目录包含与角色相关的元数据。通常,main.yml 文件位于此目录中,可以指定角色的依赖关系、作者信息、最低 Ansible 版本要求等。
  8. README.md:该文件是角色的说明文档,可以提供有关角色用途、配置示例和注意事项的信息。

角色使用

通过将相关任务、变量和文件组织到一个目录中,可以轻松地重复使用角色,并将其在不同的 Playbook 中调用。

例如,在 Playbook 中使用角色的示例:

- name: Example playbook
  hosts: myhosts
  roles:
    - apache

角色命令

ansible-galaxy  search  		# 搜索角色
ansible-galaxy  install  		# 角色名 –p  roles/  安装路径,将角色安装到当前目录下的roles目录中
ansible-galaxy  list  			# 查看已经安装的roles
ansible-galaxy info myrole  	 # 查看已经安装的roles的详情
ansible-galaxy remove  rolesname # 卸载一个角色(也可以直接删除roles目录中对应的角色目录)

实用案例

  • 自动化安装Docker和Kubernetes
- name: Install Docker, Kubernetes
  hosts: all
  become: true

  tasks:
    # Install required packages
    - name: Install packages
      yum:
        name: "{{ item }}"
        state: present
      loop:
        - yum-utils
        - device-mapper-persistent-data
        - lvm2

    # Add Docker repository
    - name: Add Docker repository
      yum_repository:
        name: docker-ce
        description: Docker CE Stable
        baseurl: https://download.docker.com/linux/centos/7/x86_64/stable
        enabled: true
        gpgcheck: true
        gpgkey: https://download.docker.com/linux/centos/gpg
      tags: docker

    # Install Docker
    - name: Install Docker
      yum:
        name: "docker-ce-{{ item }}"
        state: present
      loop:
        - cli
        - containerd.io
      tags: docker

    # Start and enable Docker service
    - name: Start Docker service
      systemd:
        name: docker
        state: started
        enabled: true
      tags: docker

    # Add Kubernetes repository
    - name: Add Kubernetes repository
      yum_repository:
        name: kubernetes
        description: Kubernetes
        baseurl: https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
        enabled: true
        gpgcheck: true
        gpgkey: https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg

    # Install Kubernetes packages
    - name: Install Kubernetes packages
      yum:
        name: "{{ item }}"
        state: present
      loop:
        - kubelet
        - kubeadm
        - kubectl

    # Start and enable Kubernetes services
    - name: Start Kubernetes services
      systemd:
        name: "{{ item }}"
        state: started
        enabled: true
      loop:
        - kubelet

    # Disable SELinux
    - name: Disable SELinux
      selinux:
        state: disabled

    # Set vm.swappiness to 0
    - name: Set vm.swappiness to 0
      sysctl:
        name: vm.swappiness
        value: 0
        state: present
        sysctl_file: /etc/sysctl.d/99-kubernetes.conf
        reload: yes

    # Set net.bridge.bridge-nf-call-iptables to 1
    - name: Set net.bridge.bridge-nf-call-iptables to 1
      sysctl:
        name: net.bridge.bridge-nf-call-iptables
        value: 1
        state: present
        sysctl_file: /etc/sysctl.d/99-kubernetes-iptables.conf
        reload: yes
  • 配置华为开源镜像站epel源
- name: epel
  hosts: all
  tasks:
    - name: install epel-release
      yum:
        name: epel-release
        state: present
    - name: Configure the EPEL source of Huawei open source mirror
      yum_repository:
        name: epel
        description: EPEL - Extra Packages for Linux
        baseurl: https://mirrors.huaweicloud.com/epel/$releasever/$basearch/
        gpgcheck: no
        state: present
    - name: makecache
      yum:
        name: '*'
        state: latest
  • 生成主机硬件报告
- name: Gather hardware inventory
  hosts: all
  gather_facts: yes

  tasks:
    - name: Get host information
      debug:
        msg: "Hostname: {{ ansible_hostname }}"

    - name: Get memory information
      command: free -m
      register: memory_output

    - name: Parse memory information
      set_fact:
        total_memory: "{{ memory_output.stdout_lines[1] | regex_replace('\\s+', ' ') | split(' ')[1] }}"
        used_memory: "{{ memory_output.stdout_lines[1] | regex_replace('\\s+', ' ') | split(' ')[2] }}"

    - name: Get BIOS version
      command: dmidecode -s bios-version
      register: bios_output

    - name: Get disk device information
      command: lsblk --output NAME,FSTYPE,SIZE,MOUNTPOINT
      register: disk_output

    - name: Parse disk device information
      set_fact:
        disks: "{{ disk_output.stdout_lines[1:] | map('regex_replace', '\\s+', ' ') | map('split', ' ') | list }}"

    - name: Display hardware inventory
      debug:
        msg: |
          Hostname: {{ ansible_hostname }}
          Total memory: {{ total_memory }}MB
          Used memory: {{ used_memory }}MB
          BIOS version: {{ bios_output.stdout }}
          Disk devices:
          {% for disk in disks %}
          - Name: {{ disk[0] }}
            Filesystem: {{ disk[1] }}
            Size: {{ disk[2] }}
            Mountpoint: {{ disk[3] }}
          {% endfor %}

创建web内容

- hosts: all
  tasks:
    - name: install httpd
      yum:
        name: httpd
        state: present
    - name: enable httpd
      systemd:
        name: httpd
        enabled: yes
        state: started
    - name: enable 80/tcp
      firewalld:
        service: http
        immediate: yes
        permanent: yes
        state: enabled
    - name: Create webdev directory
      file:
        path: /webdev
        state: directory
        owner: root
        group: devops
        mode: '2775'
        setype: httpd_sys_content_t
    - name: Creat file
      copy:
        content: "Devlopment\n"
        dest: /webdev/index.html
        setype: httpd_sys_content_t
    - name: create soft link
      file:
        src: /webdev
        dest: /var/www/html/webdev
        state: link

文档查询

# ansible官网
https://www.ansible.com/
# ansible官方产品文档
https://docs.ansible.com
# 角色使用文档
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html
# 华为云开源镜像站
https://mirrors.huaweicloud.com/home
# ansible模块
https://docs.ansible.com/ansible/latest/collections/index_module.html