Ansible 使用介绍

环境信息

  • Centos 7
  • ansible-core 2.16
  • Docker image python:3.12.3

安装

ansible-core 版本及 Python 版本支持对应关系

ansible-core Version Control Node Python Target Python / PowerShell
2.16 Python 3.10 - 3.12 Python 2.7
Python 3.6 - 3.12
Powershell 3 - 5.1

为了环境部署方便灵活,可以选择使用 python:3.12.3 的 Docker 镜像,以其为基础环境安装 ansible-core 2.16 或者直接使用 ansible 镜像启动。

# docker run --rm -it python:3.12.3 bash

# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

# python --version
Python 3.12.3

# pip install ansible

# pip list
Package Version
------------ -------
ansible 9.5.1
ansible-core 2.16.6
cffi 1.16.0
cryptography 42.0.7
Jinja2 3.1.4
MarkupSafe 2.1.5
packaging 24.0
pip 24.0
pycparser 2.22
PyYAML 6.0.1
resolvelib 1.0.1
setuptools 69.5.1
wheel 0.43.0

# ansible --version
ansible [core 2.16.6]
config file = None
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.12/site-packages/ansible
ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/local/bin/ansible
python version = 3.12.3 (main, May 14 2024, 07:23:41) [GCC 12.2.0] (/usr/local/bin/python)
jinja version = 3.1.4
libyaml = True

Ansible 配置说明

Ansible 主配置文件为 /etc/ansible/ansible.cfg其中的配置都可以被 ansible-playbook 或者命令行参数覆盖

ansible 默认会读取环境变量 ANSIBLE_CONFIG 指定的配置文件,当前路径下的 ansible.cfg,以及用户家目录下的 .ansible.cfg,以及 /etc/ansible/ansible.cfg 作为配置文件,已第一个找到的为准

常用配置说明

配置项 说明 示例
inventory 指定 inventory (主机列表)文件的路径,默认为 /etc/ansible/hosts
remote_user (未指定用户时)连接远程主机时使用的用户
remote_port 连接远程主机时使用的(默认)端口
host_key_checking 默认启用。检查主机密钥可以防止服务器欺骗和中间人攻击。
如果主机重新安装并且在 know_hosts 中拥有不同的密钥,ansible 会提示确认密钥。
如果要禁用此行为,可以配置为 False
ask_pass 默认为 False。当设置为 True 时,ansible 要求输入远端服务器的密码,即使配置了免密登录
log_path 日志文件,默认 /var/log/ansible.log
pattern 当没有给出 pattern 时的默认 pattern,默认值是 * 即所有主机

配置示例

/etc/ansible/ansible.cfg
[defaults]
# 设置默认的 inventory 文件路径
inventory = /etc/ansible/hosts

# 关闭主机密钥检查,方便新主机的快速添加
host_key_checking = False

# 设置默认的远程用户
remote_user = ansible

Inventory 配置说明

默认的 inventory 配置文件路径为 /etc/ansible/hosts,主要用来配置 Managed Hosts 列表 [3]

在命令行中,可以使用选项 -i <path> 指定不同的 inventory 或者可以在 ansible 配置文件 ansible.cfg 中使用指令 inventory 指定 inventory 文件位置。

命令行中可以使用 -i <path1> -i <path2> ... 指定多个 inventory

inventory 文件支持多种格式,最常见的是 INIYAML 格式。

  • Ansible 默认创建了 2 个组:
    • all : 包含所有主机
    • ungrouped : 包含所有不在其他组(all 除外)中的所有主机。

      任何一个主机都会至少在 2 个组中,要么 all 和某个组中,要么 allungrouped

  • 一个主机可以包含在多个组中
  • parent/childchild 组被包含在 parent 组中。
    • INI 配置格式中,使用 :children 后缀配置 parent
    • YAML 配置格式中,使用 children: 配置 parent
      • 任何在 child 组中的主机自动成为 parent 组中的一员
      • 一个组可以包括多个 parentchild 组,但是不能形成循环关系
      • 一个主机可以在多个组中,但是在运行时,只能有一个实例存在,Ansible 会自动将属于多个组的主机合并。
  • 主机范围匹配。如果有格式相似的主机,可以通过范围格式使用一条指令来添加多台主机。
    • INI 配置格式中,使用以下格式
      [webservers]
      www[01:50].example.com

      ## 指定步长增长
      www[01:50:2].example.com

      db-[a:f].example.com
    • YAML 配置格式中,使用以下格式
      # ...
      webservers:
      hosts:
      www[01:50].example.com:

      ## 指定步长增长
      www[01:50:2].example.com:
      db-[a:f].example.com:

      范围格式 的第一项和最后一项也包括在内。即匹配 www01www50

Inventory 多配置文件支持

在主机数量较多,或者组织结构较复杂的情况下,使用单个 Inventory 配置文件会导致主机管理较为复杂。将单个 Inventory 配置文件按照项目或者组织或其他规则进行分割会显著降低维护复杂度。

Inventory 多配置文件支持,可以使用以下方法之一

  • 按照项目或者组织或其他规则将主机分割到多个配置中,命令行中可以使用 -i <path1> -i <path2> ... 指定多个 inventory
  • 按照项目或者组织或其他规则将主机分割放置在多个文件中,并将所有文件统一放置在一个单独的目录中(如 /etc/ansible/inventory/),在命令行中使用选项 -i /etc/ansible/inventory/ 或者在 Ansible 配置文件(ansible.cfg)中使用指令 inventory 配置目录。

    注意事项: Ansible 使用字典顺序加载配置文件,如果在不同的配置文件中配置了 parent groupschild groups,那么定义 child groups 的配置要先用定义 parent groups 的文件加载,否则 Ansible 加载配置会报错: Unable to parse /path/to/source_of_parent_groups as an inventory source [4]

  • 使用 group_varshost_vars 目录分别存储组变量和主机变量 [7]

    注意事项: 组变量和主机变量必须使用 YAML 格式,合法的文件扩展名包括: .yamlyml.json 或者无文件扩展名

INI 格式的 Inventory

主机列表中的主机可以单独出现,也可以位于某个或者多个 组([] 开头的行)中

/etc/ansible/hosts
ansible-demo1.local
ansible-demo2.local

[webserver]
webserver1.local
webserver2.local

[nginxserver]
# 匹配多个主机:nginx1.local, nginx2.local, nginx3.local, nginx4.local
nginx[1:4].local variable1=value1 variable2=value2
nginx-bak.local ansible_ssh_host=10.10.0.1 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=PASSWORD
127.0.0.1 http_port=80 maxRequestPerChild=808


连接主机使用的常用配置说明 [6]

配置项 说明 示例
ansible_host 远程主机地址
ansible_port 远程主机端口
ansible_user 连接远程主机的 ssh 用户
Ansible 默认使用 control node 上执行 ansible 的用户名来连接远程主机 [9]
ansible_password 连接远程主机的 ssh 用户密码,建议使用 key 连接
ansible_ssh_private_key_file 连接远程主机的 ssh 私钥文件路径
ansible_become
ansible_sudo
ansible_su
用户权限提升
ansible_become_method 用户权限提升(escalation)的方式
ansible_become_user
ansible_sudo_user
ansible_su_user
用户权限提升(escalation)后的用户
ansible_become_password
ansible_sudo_password
ansible_su_password
sudo 密码(这种方式并不安全,强烈建议使用 --ask-sudo-pass)
ansible_become_exe
ansible_sudo_exe
ansible_su_exe
设置用户权限提升(escalation)后的可执行文件
ansible_connection 与主机的连接类型.比如:local, ssh 或者 paramiko
Ansible 1.2 以前默认使用 paramiko。1.2 以后默认使用 smart,smart 方式会根据是否支持 ControlPersist, 来判断 ssh 方式是否可行.
ansible_shell_type 目标系统的 shell 类型.默认情况下,命令的执行使用 sh 语法,可设置为 cshfish.
ansible_python_interpreter 目标主机的 python 路径
系统中有多个 Python, 或者命令路径不是 /usr/bin/python

变量

inventory 的配置中,可以添加变量,以在 playbook 中使用变量,实现对不同主机的个性化配置。变量分好几个层级:

  • 主机变量: 跟在主机后面直接设置,变量的作用域仅限于主机。由于对变量名没有限制,所以前面的那些 ansible 的配置如果打错字了也不会报错,ansible 会认为这是一个主机变量
    /etc/ansible/hosts
    127.0.0.1 http_port=80 maxRequestPerChild=808

    变量值中包含空格,需要用引号(单引号/双引号)

  • 组变量: 组变量需要新开一个 section, 配置在名为 [组名:vars]section
    /etc/ansible/hosts
    [localloops]
    127.0.0.[1:5] ansible_connection=paramiko ansible_ssh_user=root

    [localloops:vars]
    http_port=8080

    因为主机可以在多个组中定义,假如在多个组中定义的同一个主机的同名变量的值不一样,Ansible 使用以下优先级使用变量: [5]

    • host
    • child group
    • parent group
    • all group

使用主机别名

在 Inventory 中定义主机时,可以使用主机别名

jumper ansible_port=5555 ansible_host=192.0.2.50

YAML 格式的 Inventory

基本的 YAML 格式的 Inventory 文件内容如下 [3]

ungrouped:
hosts:
mail.example.com:
webservers:
hosts:
foo.example.com:
bar.example.com:
dbservers:
hosts:
one.example.com:
two.example.com:
three.example.com:
east:
hosts:
foo.example.com:
one.example.com:
two.example.com:
west:
hosts:
bar.example.com:
three.example.com:
prod:
children:
east:
test:
children:
west:

变量

主机变量定义

atlanta:
hosts:
host1:
http_port: 80
maxRequestsPerChild: 808
host2:
http_port: 303
maxRequestsPerChild: 909

组变量定义

atlanta:
hosts:
host1:
host2:
vars:
ntp_server: ntp.atlanta.example.com
proxy: proxy.atlanta.example.com

定义可以为所有主机共用的变量

假如有些变量可以被所有主机或者大部分主机所使用(继承),可以将其定义在 all 组中,all 组是 Ansible 自动创建的,用于包含所有主机,因此在这个组中定义的变量会被所有主机继承。

/etc/ansible/hosts
all:
vars:
ansible_user: admin
ansible_ssh_private_key_file: /path/to/private/key
example_variable: value

ansible_controller_host:
hosts:
docker_host:
ansible_host: 127.17.0.1

test_target1:
hosts:
ansible-target-centos79-1:
ansible_host: ansible-target-centos79-1
ansible-target-centos79-2:
ansible_host: ansible-target-centos79-2
ansible_port: 22

所有这些变量将适用于 ansible_controller_host 组和 test_target1 组中定义的所有主机,除非在特定主机或其他组中明确覆盖了这些变量。

在主机较多的场景下,需要将变量分离以方便管理维护,可以使用 group_vars 文件,在 Inventory 配置文件的同级目录下创建目录 group_vars,在其下创建文件 all.yml

/etc/ansible/group_vars/all.yml
ansible_user: admin
ansible_ssh_private_key_file: /path/to/private/key
example_variable: value

Inventory 文件如下:

/etc/ansible/hosts

ansible_controller_host:
hosts:
docker_host:
ansible_host: 127.17.0.1

test_target1:
hosts:
ansible-target-centos79-1:
ansible_host: ansible-target-centos79-1
ansible-target-centos79-2:
ansible_host: ansible-target-centos79-2
ansible_port: 22

使用主机别名

在 Inventory 中定义主机时,可以使用主机别名

# ...
hosts:
jumper:
ansible_port: 5555
ansible_host: 192.0.2.50

ansible 使用

在配置好 inventory 后,要使 ansible 可以连接到 Managed Host,需要使用密码或者 key 的方式进行认证,建议使用 Private Key 的方式进行认证。参考文档配置 ssh 公私钥免密码认证过程

配置完 hosts 之后,在命令行中可以调用一些命令来使用 ansible,如 ansible all -m ping。命令行的 ansible 工具大体格式如下:

ansible <pattern> -m <module> -a <arguments>

Patterns

pattern 是一个标识,指定出了要操作的目标主机,常用的 patterns 如下 [8]

描述 Pattern(s) Targets
所有主机 all
*
一个主机 host1
ip/域名
多个主机 host1:host2
host1,host2
192.168.1.*
192.0.*
*.example.com
*.com
建议用 ,,在主机或者组中有 : 字符时必须用 ,
如果主机名和组名冲突,则以先出现的为准。
一个组 webservers
多个组 webservers:dbservers 取两个组的 并集
如果主机名和组名冲突,则以先出现的为准。
排除组 webservers:!atlanta 所有在 webservers 组中,但是不在 atlanta 组中
组的交集 webservers:&staging any hosts in webservers that are also in staging
slice(切片操作) webservers[0] 第一个主机
webservers[-1] 最后一个主机
webservers[0:2] 第 1 个到第 3 个(包含)
webservers[1:] 第 2 个到最后一个
webservers[:3] 第一个到第 4 个
正则表达式匹配 `~(web db).*.example.com~` 开头的匹配表达式表示使用正则匹配
  • 可以混用: one*.com:dbservers
  • 如果 Inventory 中使用了别名(alias),必须使用别名来匹配。YAML 格式中明确使用了别名。

ansible 命令常用选项

选项 说明 示例
-m, --module-name 指定模块
默认为 command
ansible all -m ping
--become-user 'BECOME_USER' 作,默认为 root <br/切换到指定的用户执行操>需要配合 -b, --become 选项使用 ansible all -m command -a "ls /root/" -b --become-user root
-b, --become 提升权限到 root 权限,需要用户有 sudo 权限
--list-hosts 列出 pattern 匹配的主机列表,不执行其他任何操作 ansible --list-hosts
-C, --check Check mode,不执行任何实际操作,而是对要执行的操作进行验证
-k, --ask-pass 询问连接密码
-o, --one-line 输出到一行里面
-f ,--forks 指定并发执行的数量,默认为 5

ansible-doc 使用

ansible-doc 命令提供 Ansible 安装的模块的简要文档(帮助)信息,其帮助示例中的代码可以直接复制粘贴到 Playbook 中使用。

ansible 常用模块

command

command 是 ansible 默认的模块。command 模块不支持 shell 变量,也不支持管道/重定向 等 shell 相关的功能.如果你想使用 shell 相关的这些功能, 请使用 shell 模块. [2]

shell

shell 模块启动一个 shell 然后执行命令

$ ansible raleigh -m shell -a 'echo $TERM'

使用 Ansible ad hoc 命令行接口时(与使用 Playbooks 的情况相反),尤其要注意 shell 引号的规则。比如在上面的例子中,如果使用双引号 "echo $TERM",会求出 TERM 变量在当前系统的值,而我们实际希望的是把这个命令传递 到其它机器执行。

ping

用来测试到目标服务器的连通性

# ansible all -m ping
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
k8s-master1 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
"unreachable": true
}
[WARNING]: Platform linux on host k8s-uat-master2 is using the discovered Python interpreter at /usr/bin/python, but future installation of
another Python interpreter could change this. See https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more
information.
k8s-master2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}

setup

使用 setup 模块,ansible 可以收集各个 Managed Hosts 的 facts,其中包含了 Managed Hosts 的很多元数据。

# ansible k8s-master-nodes[0] -m setup

k8s-uat-master1 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"10.244.0.1",
"172.31.30.123",
"10.244.0.0",
"172.17.0.1"
],
"ansible_all_ipv6_addresses": [
"fe80::84d:ccff:fe5f:56c5",
"fe80::3c4a:4bff:fe20:512",
"fe80::836:c2ff:fefb:e925",
"fe80::146d:22ff:fe20:cf86"
],
...

配合 setup 模块的 filter 参数,可以从输出中过滤出各种信息

# ansible fm-k8s-uat-master-nodes[0] -m setup -a "filter=ansible_default_ipv4"
k8s-master1 | SUCCESS => {
"ansible_facts": {
"ansible_default_ipv4": {
"address": "172.31.30.123",
"alias": "eth0",
"broadcast": "172.31.31.255",
"gateway": "172.31.16.1",
"interface": "eth0",
"macaddress": "0a:36:c2:fb:e9:25",
"mtu": 9001,
"netmask": "255.255.240.0",
"network": "172.31.16.0",
"type": "ether"
},
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}

在 Playbook 中可以使用 ansible_facts 变量直接引用 facts

hostname

修改主机名,官方文档说明

- name: Set a hostname
ansible.builtin.hostname:
name: web01

- name: Set a hostname specifying strategy
ansible.builtin.hostname:
name: web01
use: systemd

lineinfile

此模块用了确定给定的 一行内容 是否在指定文件中,或者替换文件中存在的 一行 内容。仅在需要修改单行内容时使用此模块 [10]

如果需要对多行文本或者是整块文本做修改,可以参考 ansible.builtin.blockinfileansible.builtin.replaceansible.builtin.copy or ansible.builtin.template 等模块

reboot

service

ansible.builtin.service 管理远程主机上的服务状态。 [11]

  • ansible.builtin.service 模块相当于是底层服务管理工具(systemdsysvini 等)的一个代理。默认情况会使用 ansible.builtin.setup 中发现的服务管理工具来管理远程主机上的服务状态。也可以使用 use 参数手动指定。
  • ansible.builtin.service 中的参数不一定适用于所有的底层服务管理工具(systemdsysvini 等)

常用参数

参数 说明 示例
name
string / required
服务名称
enabled
boolean
服务是否要开机启动,可选值包括
- false
- true
state
string
期望的(desired)服务状态。可选值包括:
- started / stopped : 如果服务状态已满足,不执行任何操作
- restarted: 重启
- reloaded
use
string
默认情况下,系统使用 ansible_service_mgr 中的服务管理工具。如果此值为空,则使用传统的 service 模块(命令)

除了 name 为必须的参数,enabledstate 至少要有一个存在

systemd_service

ansible.builtin.systemd_service 管理 systemd 系统上的服务

ansible.builtin.systemdansible.builtin.systemd_service 相同

常用参数

参数 说明 示例
name
string / required
服务名称
enabled
boolean
服务是否要开机启动,可选值包括
- false
- true
state
string
期望的(desired)服务状态。可选值包括:
- started / stopped : 如果服务状态已满足,不执行任何操作
- restarted: 重启
- reloaded
daemon_reexec
boolean
aliases: systemctl daemon-reexec
在执行任何操作前,先执行 systemctl daemon-reexec
默认值为 false
daemon_reload
boolean
aliases: systemctl daemon-reload
执行 systemctl daemon-reload
默认值为 false

常见错误

Permission denied

在以普通用户 ssh 登陆远程主机(Managed Host)的情况下,执行某些操作可能因为普通用户权限不足导致操作失败

# ansible my-hosts -m command -a "cat /root/.ssh/authorized_keys" 
k8s-master2 | FAILED | rc=1 >>
cat: /root/.ssh/authorized_keys: Permission deniednon-zero return code

k8s-master1 | FAILED | rc=1 >>
cat: /root/.ssh/authorized_keys: Permission deniednon-zero return code

k8s-master3 | FAILED | rc=1 >>
cat: /root/.ssh/authorized_keys: Permission deniednon-zero return code

此种情况,可以使用以下方式解决。***前提是远程登陆使用的用户具有 sudo 权限***。建议使用 -b 选项。

  • 使用 sudo 命令。如果用户没有 sudo 权限,ansible 会被阻塞,后台等待用户输入 sudo 密码,直到等待超时失败。具体报错参考以下示例中的 k8s-master2 输出
    # ansible my-hosts -m command -a "sudo cat /root/.ssh/authorized_keys" 
    k8s-master1 | CHANGED | rc=0 >>
    no-port-forwarding,no-agent-forwarding,no-X11-forwarding,command="echo 'Please login as the user \"centos\" rather than the user \"root\".';echo;sleep 10" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCGKLNMv82MQJUuQ9aZPsDofBj96aQlS1kNV2doSwyLatgMNBZ6rzgQuNOJ2DH87IzD1mZ0wL7iApvk6gkxSxcz5tmbU8dfYOYJdlBlhxGk2Nkg2V3P9FPC0hBY73szEV+1DUoqwl+COAsAXO9Uiebr0faQvWOkVT7pypunnjPrBBUaaXn2IcoPIdXZfXVLjXH2JbWSHL5J+yIGHewSMzZ/Xx7u6hwxUP0QLFHrnhD0WDukoBjoUZ2sshMP+DHgoyWjCg+uVpmjJAksp80f34WfNku5Grt90kYEj+N+x2JQ1Y4aQIXASIwDshicbJIsl+RMIMmwe+TElUJ6g9aa0qCr op2-east1-1031
    k8s-master3 | CHANGED | rc=0 >>
    no-port-forwarding,no-agent-forwarding,no-X11-forwarding,command="echo 'Please login as the user \"centos\" rather than the user \"root\".';echo;sleep 10" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCGKLNMv82MQJUuQ9aZPsDofBj96aQlS1kNV2doSwyLatgMNBZ6rzgQuNOJ2DH87IzD1mZ0wL7iApvk6gkxSxcz5tmbU8dfYOYJdlBlhxGk2Nkg2V3P9FPC0hBY73szEV+1DUoqwl+COAsAXO9Uiebr0faQvWOkVT7pypunnjPrBBUaaXn2IcoPIdXZfXVLjXH2JbWSHL5J+yIGHewSMzZ/Xx7u6hwxUP0QLFHrnhD0WDukoBjoUZ2sshMP+DHgoyWjCg+uVpmjJAksp80f34WfNku5Grt90kYEj+N+x2JQ1Y4aQIXASIwDshicbJIsl+RMIMmwe+TElUJ6g9aa0qCr op2-east1-1031

    k8s-master2 | FAILED! => {
    "ansible_facts": {
    "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "module_stderr": "Shared connection to 172.31.30.115 closed.\r\n",
    "module_stdout": "[sudo] password for centos: \r\n\r\n{\"changed\": true, \"end\": \"2023-09-01 09:24:40.247480\", \"stdout\": \"\", \"cmd\": [\"sudo\", \"cat\", \"/root/.ssh/authorized_keys\"], \"failed\": true, \"delta\": \"0:05:02.696092\", \"stderr\": \"\\nWe trust you have received the usual lecture from the local System\\nAdministrator. It usually boils down to these three things:\\n\\n #1) Respect the privacy of others.\\n #2) Think before you type.\\n #3) With great power comes great responsibility.\\n\\nsudo: timed out reading password\", \"rc\": 1, \"invocation\": {\"module_args\": {\"creates\": null, \"executable\": null, \"_uses_shell\": false, \"strip_empty_ends\": true, \"_raw_params\": \"sudo cat /root/.ssh/authorized_keys\", \"removes\": null, \"argv\": null, \"warn\": true, \"chdir\": null, \"stdin_add_newline\": true, \"stdin\": null}}, \"start\": \"2023-09-01 09:19:37.551388\", \"warnings\": [\"Consider using 'become', 'become_method', and 'become_user' rather than running sudo\"], \"msg\": \"non-zero return code\"}\r\n",
    "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error",
    "rc": 1
    }
  • 使用 ansible -b 选项。如果用户没有 sudo 权限, ansible 会因为没有输入 sudo 密码而执行失败,具体报错(Missing sudo password)参考以下示例中的 k8s-master2 输出
    # ansible my-hosts -m command -a "cat /root/.ssh/authorized_keys" -b
    k8s-master2 | FAILED | rc=-1 >>
    Missing sudo password

    k8s-master1 | CHANGED | rc=0 >>
    no-port-forwarding,no-agent-forwarding,no-X11-forwarding,command="echo 'Please login as the user \"centos\" rather than the user \"root\".';echo;sleep 10" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCGKLNMv82MQJUuQ9aZPsDofBj96aQlS1kNV2doSwyLatgMNBZ6rzgQuNOJ2DH87IzD1mZ0wL7iApvk6gkxSxcz5tmbU8dfYOYJdlBlhxGk2Nkg2V3P9FPC0hBY73szEV+1DUoqwl+COAsAXO9Uiebr0faQvWOkVT7pypunnjPrBBUaaXn2IcoPIdXZfXVLjXH2JbWSHL5J+yIGHewSMzZ/Xx7u6hwxUP0QLFHrnhD0WDukoBjoUZ2sshMP+DHgoyWjCg+uVpmjJAksp80f34WfNku5Grt90kYEj+N+x2JQ1Y4aQIXASIwDshicbJIsl+RMIMmwe+TElUJ6g9aa0qCr op2-east1-1031
    [WARNING]: Platform linux on host k8s-uat-master3 is using the discovered Python interpreter at /usr/bin/python, but future installation of
    another Python interpreter could change this. See https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more
    information.
    k8s-master3 | CHANGED | rc=0 >>
    no-port-forwarding,no-agent-forwarding,no-X11-forwarding,command="echo 'Please login as the user \"centos\" rather than the user \"root\".';echo;sleep 10" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCGKLNMv82MQJUuQ9aZPsDofBj96aQlS1kNV2doSwyLatgMNBZ6rzgQuNOJ2DH87IzD1mZ0wL7iApvk6gkxSxcz5tmbU8dfYOYJdlBlhxGk2Nkg2V3P9FPC0hBY73szEV+1DUoqwl+COAsAXO9Uiebr0faQvWOkVT7pypunnjPrBBUaaXn2IcoPIdXZfXVLjXH2JbWSHL5J+yIGHewSMzZ/Xx7u6hwxUP0QLFHrnhD0WDukoBjoUZ2sshMP+DHgoyWjCg+uVpmjJAksp80f34WfNku5Grt90kYEj+N+x2JQ1Y4aQIXASIwDshicbJIsl+RMIMmwe+TElUJ6g9aa0qCr op2-east1-1031

Connection timed out

使用以下 playbook 报错:

- name: manage Nginx Status
hosts: nginx
remote_user: root

tasks:

- name: Ensure that nginx is started
ansible.builtin.service:
name: nginx
enabled: false
state: stopped

执行结果如下,报错: {"changed": false, "msg": "Unable to disable service nginx: Failed to execute operation: Connection timed out\n"}

# ansible-playbook -vv  --diff playbooks/playbook.yml

PLAYBOOK: playbook.yml **************************************************************************************************************************************
1 plays in playbooks/playbook.yml

PLAY [manage Nginx Status] **********************************************************************************************************************************

TASK [Gathering Facts] **************************************************************************************************************************************
task path: /etc/ansible/playbooks/playbook.yml:2
ok: [nginx_2]

TASK [Ensure that nginx is started] *************************************************************************************************************************
task path: /etc/ansible/playbooks/playbook.yml:8
fatal: [nginx_2]: FAILED! => {"changed": false, "msg": "Unable to disable service nginx: Failed to execute operation: Connection timed out\n"}

PLAY RECAP **************************************************************************************************************************************************
nginx_2 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0

问题原因 是此操作需要 sudo 权限来运行。参考以下内容,加入 become: true 指令即可

- name: manage Nginx Status
hosts: nginx
become: true

tasks:

- name: Ensure that nginx is started
ansible.builtin.service:
name: nginx
enabled: false
state: stopped

参考链接

ansible 官方文档
Ansible中文权威指南
Index of all Modules

脚注