01. Ansible - 安装使用

发展历史

Ansible 于 2012 年 3 月 9 日发布了 0.0.1 版,其作者兼创始人是 Michael DeHaan,同时也是 Cobbler 与 Func 的作者。

Michael DeHaan 在 RedHat 任职期间,在尝试了 Puppet、Chef、Cfengine、Capistrano、Fabric、Function、Plain SSH 等各式工具后,决定自己打造一款能结合众多工具优点的自动化工具,Ansible 由此诞生。现已经被 RedHat 收购 。官网地址:

https://www.ansible.com/

原理特点

工作机制:

  1. 在执行命令时,通过其底层传输连接模块,将一个或多个文件,或定义的一个 Play 或 Command 命令传输到远程服务器 tmp 下的临时目录。
  2. 远程执行这些 PlayComand 命令,然后删除这些临时文件,同时回传整体命令执行结果。

主要特点:

  1. 基于 Python (Paramiko(ssh),PyYAML,Jinja2(模板)三个关键模块)实现,无客户端,也无需运行 Daemon 进程,部署简单,只需 SSH、Python 即可。
  2. 支持 Windows,但仅支持客户端,服务端必须是 Linux 系统。
  3. 基于 OpenSSH 通信,底层基于 SSH 协议(Windows 基于 PowerShell),支持通过系统账户密码或公私钥认证,过程简单、方便、安全。
  4. 模块化,提供了丰富的自带模块,直接调用即可完成特定任务,支持任何编程语言写自定义模块。
  5. 支持 playbook 编排任务,YAML 格式,使用简单。
  6. 幂等性,一个任务执行 1 遍和执行 n 遍效果一样,不因重复执行带来意外情况。

架构组成

主要组成:

  1. Ansible:命令工具,核心。
  2. Host Inventory:管理的主机清单,默认定义在 /etc/anaible/hosts
  3. Playbooks:任务剧本(任务集),编排定义 Ansible 任务集的配置文件,通常是 YML 文件。
  4. Modules:执行命令的功能模块,多数为内置核心模块,也可自定义。
  5. Plugins:模块功能的补充插件,不常用。
  6. API:供第三方程序调用的应用程序编程接口。

管理方式:

  1. Ansible-Hoc:单条命令,主要用于临时命令使用场景。
  2. Ansible-playbook:主要用于长期规划的场景。

服务安装

测试节点说明:

IP 解析 系统 配置 说明
192.168.2.40 server01.host.local CentOS 7.9 4C/4G 控制节点
192.168.2.201 server02.host.local CentOS 7.9 4C/4G 普通节点
192.168.2.201 server03.host.local CentOS 7.9 4C/4G 普通节点

在三台机器都加上 host 解析,便于测试:

cat >> /etc/hosts << EOF
192.168.2.40  server01.host.local
192.168.2.201 server02.host.local
192.168.2.202 server03.host.local
EOF

由于 Ansible 是基础 Python 开发,所以安装方法有几种,都是在 控制节点 执行。推荐使用 yum 安装:

# 使用 epel 源安装
yum -y install epel-release

# 安装 ansible
yum -y install ansible

# 查看安装版本
ansible --version

配置文件说明:

/etc/ansible/
├── ansible.cfg # 主配置文件
├── hosts		# 主机清单
└── roles		# 角色配置

命令工具说明:

/usr/bin/
├── ansible -> /usr/bin/ansible-2.7
├── ansible-2 -> /usr/bin/ansible-2.7
├── ansible-2.7
├── ansible-config -> ansible
├── ansible-connection
├── ansible-console -> /usr/bin/ansible-console-2.7
├── ansible-console-2 -> /usr/bin/ansible-console-2.7
├── ansible-console-2.7 -> ansible
├── ansible-doc -> /usr/bin/ansible-doc-2.7
├── ansible-doc-2 -> /usr/bin/ansible-doc-2.7
├── ansible-doc-2.7 -> ansible
├── ansible-galaxy -> /usr/bin/ansible-galaxy-2.7
├── ansible-galaxy-2 -> /usr/bin/ansible-galaxy-2.7
├── ansible-galaxy-2.7 -> ansible
├── ansible-inventory -> ansible
├── ansible-playbook -> /usr/bin/ansible-playbook-2.7
├── ansible-playbook-2 -> /usr/bin/ansible-playbook-2.7
├── ansible-playbook-2.7 -> ansible
├── ansible-pull -> /usr/bin/ansible-pull-2.7
├── ansible-pull-2 -> /usr/bin/ansible-pull-2.7
├── ansible-pull-2.7 -> ansible
├── ansible-vault -> /usr/bin/ansible-vault-2.7
├── ansible-vault-2 -> /usr/bin/ansible-vault-2.7
├── ansible-vault-2.7 -> ansible

可以发现,处理 ansible-connection,其它的都有 ansible 命令的软连接。其实都是一个命令,为了区分使用才区分的。

  • /usr/bin/ansible:主程序,用于执行临时命令。
  • /usr/bin/ansible-console:基于 Console 界面与用户交互的执行工具。
  • /usr/bin/ansible-doc:查看配置文档,模块功能查看工具。
  • /usr/bin/ansible-galaxy:下载/上传优秀代码或 Roles 模块的官网平台。
  • /usr/bin/ansible-playbook:定制自动化任务,编排剧本工具。
  • /usr/bin/ansible-pull:远程执行命令的工具。
  • /usr/bin/ansible-vault:文件加密工具。

主机清单

主机清单 inventory 主要作用在于批量定义主机列表并实现分组,默认放在 /etc/ansible/hosts 下面,也可以有多个。

它遵循 INI 文件的风格,通过 [xxx] 来定义组名,同一台主机可以属于多个组。此外,如果主机不是 22 端口,还可以定义相应的端口。

配置示例:

# 不属于任何组的主机
server01.host.local
server02.host.local
server03.host.local
192.168.2.40
192.168.2.201
192.168.2.202

# 主机分组 1
[master]
server01.host.local
192.168.2.40

# 主机分组 2
[client]
server02.host.local
server03.host.local
192.168.2.201
192.168.2.202

# 范围
[linux]
server[01:03].host.local
192.168.2.40
192.168.2.40 # 重复配置
192.168.2.[201:202]

可以通过命令查看每个组下面有哪些主机,重复的会被过滤。

# 查看指定组的主机列表
ansible --list-host linux

# 查看全部主机
ansible --list-host all

如图所示:

主配置文件

主配置文件为 /etc/ansible/ansible.cfg,一般默认即可,也可以根据实际情况修改一些常用的配置。下面是一些常用的配置说明:

[defaults]
# 主机清单配置文件
inventory      = /etc/ansible/hosts
# 库文件存放位置
#library        = /usr/share/my_modules/
# 临时文件 py 在远程主机存放位置
#remote_tmp     = ~/.ansible/tmp
# 临时文件 py 在本地主机存放位置
#local_tmp      = ~/.ansible/tmp
# 默认并发数
#forks          = 5
# 默认 sudo 切换到的用户
#sudo_user      = root
# 远程默认端口
#remote_port    = 22
# 角色配置目录
#roles_path    = /etc/ansible/roles
# 是否检查对应服务器上的 host_key,建议取消注释
host_key_checking = False
# 远程默认用户
#remote_user = root
# 日志存放目录,建议打开
log_path = /var/log/ansible.log
# 默认模块,建议修改
#module_name = command

修改配置都不需要重启这类操作,因为 ansible 没有 daemon 进程,使用时候才会去读配置文件。

ansible-doc(查看帮助文档)

ansible-doc 为帮助文档显示模块,通过它可以查看到模块的使用方法。语法模板如下:

ansible-doc [参数] [模块...]

常见的用法:

  • ansible-doc -l:列出所有支持的模块。
  • ansible-doc ping:查看指定模块的用法。
  • ansible-doc -s ping:查看指定模块的用法,精简版。

ansible(主机参数)

ansible 的主命令,基于 SSH 实现远程控制,基本语法如下:

ansible <主机参数> [其它参数] [-m 模块] [-a 参数...]

常见用法:

  • 指定主机组,查看改组的主机列表,查看所有就用 all,默认会进行去重:
# 单独的主机
ansible 192.168.2.40 --list

# 主机组
ansible linux --list

# 所有主机
ansible all --list

  • *,主机参数可以使用通配符进行匹配设置,注意通配符需要用引号括起来:
# 所有主机
ansible '*' --list

# 批量匹配主机或主机解析
ansible '192.168.2.*' --list
ansible 'server*.host.local' --list

特别说明:

建议都是用单引号,而不是双引号,因为某些特殊的情况下只有单引号才起作用。比如逻辑非的时候只能单引号。


  • :,逻辑或,取并集:
ansible 'master:client' --list

  • :&,逻辑与,取交集:
ansible 'master:&linux' --list

  • :!:逻辑非,只能单引号:
ansible ':!master' --list

# 两者取非,则从前者剔除后者的列表
ansible 'linux:!client' --list

  • 正则表达式:
ansible '~.*local$' --list
ansible '~192.168.2.(201|202)' --list

多种匹配方式是可以组合在一起用的,但是其实不建议用的太复杂。

ansible(常用参数)

常用的参数列表:

  • --version:显示版本。

  • -m:指定模块。

  • -a:模块参数。

  • -v:输出详细过程,可以更详细 -vv 和 -vvv。

  • --list:显示指定的主机列表信息。

  • -k,--ask-pass:提示输入 SSH 密码,但是只会输一次,如果多台机器不同密码则会出现问题。

  • -C,--check:只是检查,并不执行。

  • -T,--timeout:执行超时时间,默认是 10s。

  • -u,--user=xxx:远程执行用户。

  • -b,--become-user=xxx:指定 sudo 的用户。

  • -K,--ask-become-pass:提示 sudo 时候的密码。


示例用法:

  • 使用远端的 test(事先创建)用户登录,并输入 SSH 密码验证,执行 ping 模块
ansible '192.168.2.201' -u test -k -m ping

但是发现执行会报错:

192.168.2.201 | FAILED! => {
"msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add this host's fingerprint to your known_hosts file to manage this host."
}

原因在于本身第一远程 ssh 主机的时候会有一个要我们输入 yes 的提示,直接使用 ansible 的时候跳过了这个过程,导致在 known_hosts 中不存在该主机。解决这个问题的方法有两种:

  1. 手动 SSH 远程一次远端机器,以后的登录就不会有该提示。
  2. 修改 ansible 配置文件,跳过这个步骤:
# 将这个注释放开,关闭检测
host_key_checking = False

此时再测试就不需要了。


  • 远程之后 sudo 切换用户执行:
ansible '192.168.2.201' -u test -k -b -K -m ping

此时会需要输入两次 test 用户的密码,但是一般会报错:

test 不在 sudoers 文件中。

这是由于 test 想要使用 sudo 命令需要配置 visudo,将 test 用户添加进去。


通过上面的执行,可以大致捋一下 ansible 命令执行的过程:

  1. 加载主配置文件,默认 /etc/ansible/ansible.cfg。

  2. 加载对应的模块文件,如 command。

  3. 通过 ansible 将模块或命令生成对应的临时 py 文件,并将该文件传输至远程服务器的对应执行用户 $HOME/.ansible/tmp/ 下面。

  4. 给文件 +x 执行。

  5. 执行并返回结果。

  6. 删除临时 py 文件,sleep 0 退出。

主机清单(认证)

由于远程执行所有的模块在没有配置免密登录的时候都需要在命令行设置账户密码,而且有时候密码还不一样,为了解决这个问题,有两种方式:

  1. 控制节点配置所有节点的免密登录。
  2. 在主机清单中配置好相关 ssh 参数,主要的参数清单如下:
参数 说明 示例
ansible_ssh_host SSH 地址 ansible_ssh_host="192.168.2.40"
ansible_ssh_user SSH 用户 ansible_ssh_user="test"
ansible_ssh_port SSH 端口 ansible_ssh_port="22"
ansible_ssh_pass SSH 密码 ansible_ssh_pass="123"
ansible_sudo sudo 用户 ansible_sudo="root"
ansible_sudo_pass sudo 验证的密码 ansible_sudo_pass="123"
ansible_sudo_exe sudo 命令路径 ansible_sudo_exe=/usr/bin/sudo

主机清单配置示例:

# 主机分组 2
[client]
server02.host.local ansible_ssh_user="test" ansible_ssh_port="22" ansible_ssh_pass="123" ansible_sudo="root" ansible_sudo_pass="123"
server03.host.local ansible_ssh_user="test" ansible_ssh_port="22" ansible_ssh_pass="123" ansible_sudo="root" ansible_sudo_pass="123"
192.168.2.201 ansible_ssh_user="test" ansible_ssh_port="22" ansible_ssh_pass="123" ansible_sudo="root" ansible_sudo_pass="123"
192.168.2.202 ansible_ssh_user="test" ansible_ssh_port="22" ansible_ssh_pass="123" ansible_sudo="root" ansible_sudo_pass="123"

此时就可以直接执行,不需要密码(由于使用到 sudo,还是需要 -b 参数,否则会是 ssh user 直接执行,提示没权限):

ansible 'client' -b -m command -a "ls /root"

上面的配置方法有个问题,每台机器都需要去单独配置,但是他们的配置其实是一样的,对于这种情况是可以简化的:

# 主机分组 2
[client]
server02.host.local
server03.host.local
192.168.2.201
192.168.2.202

# 对应组的公共配置
[client:vars]
ansible_ssh_user="test"
ansible_ssh_port="22"
ansible_ssh_pass="123"
ansible_sudo="root"
ansible_sudo_pass="123"

如果想要配置所有的,只需要把组换成 [all:vars] 即可。


但是某个组如果单独设置相关的参数,则这些机器的配置会覆盖 all 的配置,比如:

[master]
server01.host.local
192.168.2.40

# 对应组的公共配置
[master:vars]
ansible_ssh_user="root"
ansible_ssh_port="22"
ansible_ssh_pass="123456"

# 主机分组 2
[client]
server02.host.local
server03.host.local
192.168.2.201
192.168.2.202

# 对应组的公共配置
[client:vars]
ansible_ssh_user="test"
ansible_ssh_port="22"
ansible_ssh_pass="123"
ansible_sudo="root"
ansible_sudo_pass="123"

[all:vars]
ansible_ssh_user="test"
ansible_ssh_port="22"
ansible_ssh_pass="123"
ansible_sudo="root"
ansible_sudo_pass="123"

此时执行:

ansible all -b -m command -a "ls /root"

所有的请求都是正常的,client 的用的 test 用户远程,master 用的 root 用户远程。

主机清单(嵌套)

主机组是可以进行嵌套的,这样能够更方便的对主机进行管理。

# 嵌套
[servers:children]
master
client

查看主机:

ansible "servers" --list

核心模块(Command / Shell)

Command 模块主要用于在远程主机上执行命令,是默认模块,可以忽略 -m 选项。

但是该模块不够完善,在使用变量或者某些特殊符号的时候会存在一定的问题。

ansible-doc -s command

其中包含几个主要参数:

  • chdir:切换目录
  • creates:如果文件存在,就不执行
  • removes:如果文件存在,则执行

使用示例:

# 普通的远程执行命令
ansible "192.168.2.201" -m command -a "ls /tmp"

# 用自带的参数执行某些操作
ansible "192.168.2.201" -m command -a "chdir=/tmp creates=1.txt removes=1.txt 2.txt"

Shell 模块作为 Command 模块的加强版,修复了 Command 模块存在的问题。所以建议将默认的模块改为 Shell 模块。

修改主配置文件中的 module_name = commandmodule_name = shell 并放开注释即可。

Shell 模块的参数和 Command 的几乎一模一样。使用示例:

ansible client -m shell -a 'echo $HOSTNAME'

特别注意:

-a 参数后面的命令如果有变量,并且是需要远程使用的变量,一定要单引号括起来,避免本地还没执行就解析了。

如果命令太复杂,不方便写在一行,则需要使用到 Script 模块。

核心模块(Script)

Script 模块用于在远程主机上面执行 Ansible 主机本地的脚本,它的基本参数也是和 Shell 等模块类似。

同样的,Script 的主要参数和 Shell 也类似。

本地准备个测试的脚本:demo.sh

#!/bin/sh
hostname=$(hostname)
ip=$(ip a | grep 192.168 | awk '{print $2}' | awk -F '/' '{print $1}')
echo "$ip $hosname" > /tmp/1.txt
cat /tmp/1.txt

测试远程执行该脚本:

ansible client -b -m script -a 'demo.sh'

核心模块(Copy / Fetch)

Copy 模块主要用从 Ansible 主机复制文件到其它主机,常用的参数包含以下:

  • src:源文件
  • dest:指定目标路径
  • mode:设置权限
  • backup:备份源文件
  • content:用于替换 src,以内容作为数据源

使用示例:

# 将固定内容写入远端服务器,并设置权限
ansible client -m copy -a "content='Hello World' dest=/tmp/1.txt mode=0777"

# 将本地文件发送到远端服务器并改名
ansible client -b -m copy -a "src=/tmp/demo.sh dest=/tmp/info.sh mode=0755 owner=nobody backup=yes"

如果传输的是文件到远程指定目录,那么那个目录需要事先存在,如果传输的是目录,那么远程目录不是必须存在。

backup 配置的作用在于,如果已经文件存在,并且和要传过去的内容文件不一样,则先备份(格式为名称后面加时间戳)。


Fetch 模块和 Copy 相反,主要用于从远处主机拉取文件到本机,目前只支持文件,不支持目录。

使用示例:

ansible client -m fetch -a "src=/tmp/hello/demo.sh dest=/tmp"

值得注意的是,拉回来的文件会被存在 <dest目录>/<远程地址>/<远程绝对路径> 下面。

核心模块(File)

File 模块用于配置文件的属性,包含以下主要参数:

  • path:指定需要管理的文件
  • recurse:文件夹递归,类似 Linux 下面的 -R
  • src:创建软链接或者硬链接的时候指定源目标,需要配合 state=link 或者 state=hard 使用
  • state:文件状态,支持以下值:
    • link:软链接
    • hard:硬链接
    • absent:删除
    • touch:创建文件
    • directory:创建目录

使用示例:

# 创建文件,并设置用户权限,注意需要 root 权限,需要 sudo
ansible client -b -m file -a "path=/tmp/hello.txt state=touch owner=nobody group=nobody mode=0777"

# 创建目录
ansible client -m file -a "path=/tmp/world state=directory"

# 删除文件
ansible client -b -m file -a "path=/tmp/hello.txt state=absent"

# 创建软链接
ansible client -b -m file -a "src=/tmp/info.sh dest=/tmp/abc.sh state=link"

核心模块(Unarchive / Archive)

Unarchive 模块主要用于压缩包解压缩,包含两种模式:

  1. 将主机上的压缩包传输到远程主机后解压到指定目录,设置 copy=yes。
  2. 将远程主机上的某个压缩包解压到指定目录,设置 copy=no。

包含以下主要参数:

  • copy:默认 yes,将本地压缩包传到远端解压然后解压到指定目录
  • src:源路径,可以是本地,也可以是远端
  • dest:目的路径
  • mode:解压后文件权限

使用示例:

# 将本地压缩文件传到远程并解压修改权限
ansible '192.168.2.201' -b -m unarchive -a "src=/tmp/go-web.tar.gz dest=/tmp/world copy=yes mode=0777"

# 解压远端本地的压缩文件到指定目录
ansible '192.168.2.201' -b -m unarchive -a "src=/tmp/hello.tar.gz dest=/tmp/world copy=no"

# 也可以是下载文件然后解压
ansible '192.168.2.201' -b -m unarchive -a "src=https://example.com/example.zip dest=/tmp copy=no"

而 Archive 模块和 Unarchive 相反,该模块主要用于压缩文件,常用的参数包含如下:

  • path:指定路径
  • dest:指定目标文件
  • format:指定打包文件,支持:bz2,gz,tar,xz,zip

使用示例:

# 打包目录
ansible '192.168.2.201' -b -m archive -a "path=/tmp dest=/root/tmp.zip format=zip"

核心模块(Hostname)

Hostname 模块主要用于管理主机名,常用参数只有一个 name,这是主机名。

使用示例:

# 修改主机名
ansible '192.168.2.201' -b -m hostname -a "name=node-01"

核心模块(Cron)

Cron 模块主要用于设置定时任务,常用的参数包含:

  • minute,hour,day,month,weekday:和 Linux 本身的定时任务一样,分时日月周设置

  • job:定时任务的内容

  • name:定时任务的名称

  • disabled:设置 yes 则让定时任务不起作用

  • state:可以选择 absent 和 present,默认 present

  • reboot:设置为 yes,该任务会在每次 reboot 之后执行,未来会被 special_time 参数取代

使用示例:

# 普通定时任务,注意 $ 的转义,否则会被取值
ansible '192.168.2.201' -b -m cron -a "minute=*/1 name='Echo date' job='echo \$(date) >> /tmp/date.log'"

# 注释掉定时任务
ansible '192.168.2.201' -b -m cron -a "minute=*/1 name='Echo date' job='echo \$(date) >> /tmp/date.log' disabled=yes"

# 删除定时任务
ansible '192.168.2.201' -b -m cron -a "name='Echo date' state=absent"

# 开机启动任务
ansible '192.168.2.201' -b -m cron -a "name='Reboot job' job='echo \$(date) >> /tmp/date.log' reboot=yes"

# 推荐使用新的开机执行设置
ansible '192.168.2.201' -b -m cron -a "name='Reboot job' job='echo \$(date) >> /tmp/date.log' special_time=reboot"

核心模块(User)

User 模块用于用户管理,常见的参数如下:

  • name:用户名
  • password:密码
  • home:指定家目录
  • system:设置为系统用户
  • remove:删除用户
  • group:设置用户组

使用示例:

# 创建用户指定各种信息
ansible '192.168.2.201' -b -m user -a 'name=user1 comment="test user" uid=1111 home=/tmp/user1 group=root'

# 创建系统用户
ansible '192.168.2.201' -b -m user -a 'name=user2 system=yes home=/tmp/user2'

# 删除用户,不删家目录
ansible '192.168.2.201' -b -m user -a 'name=user1 state=absent'

# 删除用户,及所有数据
ansible '192.168.2.201' -b -m user -a 'name=user2 state=absent remove=yes'

核心模块(Lineinfile / Replace)

Lineinfile 模块能够解决在 ansible 中使用 sed 命令各种特殊符号可能导致替换失败的问题,主要用于替换行,常用的参数如下:

  • path:需要修改的文件

  • regexp:正则表达式表示需要修改的行

  • line:表示要修改成的行

  • state:设置 absent 执行删除

使用示例:

# 替换行内容
ansible '192.168.2.201' -b -m lineinfile -a "path=/etc/selinux/config regexp='^SELINUX=.*' line='SELINUX=disabled'"

# 删除注释的行
ansible '192.168.2.201' -b -m lineinfile -a "path=/etc/selinux/config state=absent regexp='^#'"

Replace 模块也是类似的功能,使用示例:

# 在匹配内容前面加上 #
ansible '192.168.2.201' -b -m replace -a "path=/etc/selinux/config regexp='^(SELINUX.*)' replace='#\1'"

# 在匹配内容前面加上 #,后面加上 Hello
ansible '192.168.2.201' -b -m replace -a "path=/etc/selinux/config regexp='^(#SELINUX.*)' replace='#\1Hello'"

核心模块(Setup)

Setup 模块主要用于获取远程主机的详细配置信息。

使用示例:

ansible master -m setup

通过该方法能获取系统,软硬件等信息,可以通过自带的参数 filter 来过滤。

小结

还有一些其它的模块可以通过官方文档查看:

https://docs.ansible.com/ansible/latest/collections/ansible/index.html

其中主要 ansible.builtin 中的模块是用的最多的。同时,文档中都有关于每个模块的详细说明以及用法示例,可以根据实际需求去查看。

posted @ 2023-03-17 23:36  Dy1an  阅读(90)  评论(0编辑  收藏  举报