使用Ansible ad-hoc命令示例

时间:2020-02-23 14:37:38  来源:igfitidea点击:

概述

  • Ansible中的ad hoc命令用于根据需要执行临时或者仅一次所需的任务或者操作。

  • 换句话说,这些是用户希望即时执行但又不想保存以备后用的任务。

  • Ansible模块可以使用ansible命令来调用

  • 使用ansible-doc -l获取模块列表,并使用ansible-doc <modulename>获取有关模块选项的信息

  • 使用-m指定要使用的模块

  • 命令模块是默认模块,不必指定

在本节中,我将使用默认列表文件,即/etc/ansible/hosts,其中添加了受管节点的主机名。由于我们使用的是默认列表文件,因此我不会在临时命令中指定列表文件的位置。当我们到达Ansible Inventory一章时,我们可以了解有关库存的更多信息,在该章中,我们将了解静态和动态库存文件。

语法:

ansible [-i INVENTORY] [server] [-m MODULE] {-a MODULE_OPTIONS}

临时命令示例示例

让我们在两个托管主机上使用ansible执行一些临时命令。在此示例中,我们将收集托管主机的正常运行时间

[ansible@controller ~]$ansible all -m shell -a uptime
server1 | CHANGED | rc=0 >>
 15:36:00 up 53 min,  4 users,  load average: 0.00, 0.00, 0.00
server2 | CHANGED | rc=0 >>
 15:36:00 up 53 min,  3 users,  load average: 0.00, 0.00, 0.00

我们将看到Ansible忠实地依次登录到每台计算机并运行uptime命令,返回当前的正常运行时间输出:

同样,我们可以执行任何其他命令

[ansible@controller ~]$ansible all -m shell -a "free -m"
server2 | CHANGED | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:            815         176         248          12         391         497
Swap:             0           0           0
server1 | CHANGED | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:            815         181         243          12         391         492
Swap:             0           0           0

Ansible如何与模块一起使用

  • 在上一节中,我们执行了某些临时命令,但是"后端会发生什么?"?

  • Ansible从列表文件中获取主机列表。由于我们未提供任何列表文件,因此ansible将从默认位置(即/etc/ansible/hosts)收集主机列表。

  • 然后,使用SSH将" ansible"并行连接到各个托管主机

  • 接下来,我们将使用命令传递的模块将被推送到远程节点。如果-m没有提供模块名称,则默认情况下将命令视为该模块。

  • 这个各自的"模块"用于在托管主机上执行任务

  • 执行完这些模块后,将从托管主机中删除这些模块。

让我们验证一下:

从托管主机中删除任何~/.ansible目录(每次ansible在托管主机上执行任务时都会创建此目录)。我将验证server2上的行为

[ansible@server-2 ~]$rm -rf ~/.ansible

" ansible"用户的主目录的现有内容:

[ansible@server-2 ~]$ls -al
total 44
drwx------   3 ansible ansible  4096 Sep 19 16:41 .
drwxr-xr-x. 12 root    root    20480 Apr  3 23:00 ..
-rw-------   1 ansible ansible    37 Sep 19 16:18 .bash_history
-rw-r--r--   1 ansible ansible    18 Jan 11  2019 .bash_logout
-rw-r--r--   1 ansible ansible   141 Jan 11  2019 .bash_profile
-rw-r--r--   1 ansible ansible   312 Jan 11  2019 .bashrc
drwx------   2 ansible ansible  4096 Jan 29  2017 .ssh

现在,我们将从控制器执行一个临时命令到此server2

[ansible@controller ~]$ansible server2 -m shell -a "free -m"
server2 | CHANGED | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:            815         176         248          12         391         497
Swap:             0           0           0

执行完后,我们可以验证在server2上是否已创建~/.ansible目录。

[ansible@server-2 ~]$tree ~/.ansible/
/home/ansible/.ansible/
└── tmp
1 directory, 0 files

但是此目录中没有"文件"。那是因为将shell模块复制到server2上,执行任务,然后ansible删除了该模块。

要将模块保留在托管主机上,可以通过设置ANSIBLE_KEEP_REMOTE_FILES = 1为相应的命令启用此配置。在此示例中,我们重新运行相同的命令:

[ansible@controller ~]$ANSIBLE_KEEP_REMOTE_FILES=1 ansible server2 -m shell -a "free -m"
server2 | CHANGED | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:            815         176         248          12         391         497
Swap:             0           0           0

现在,让我们验证服务器上的.ansible目录。

[ansible@server-2 ~]$tree ~/.ansible/
/home/ansible/.ansible/
└── tmp
    └── ansible-tmp-1600514171.7996144-28879-119129181135603
        └── AnsiballZ_command.py
2 directories, 1 file

这次模块被保留并且未被删除。因此,现在我们应该熟悉如何使用模块在托管主机上执行任务。

控制并行执行的主机数(分叉)

  • 我们已经在"可配置"部分中介绍了这一部分,但让我们通过一些示例进行讨论。

  • ansible.cfg中,我们有一个选项来定义使用forks对客户端主机执行的并行任务的数量。

  • " forks"的默认值为5,但是我们可以根据可用的系统资源和网络带宽来增加它。

  • 出于演示目的,我们可以在5台服务器上执行默认派生值即5的命令,并且我们将观察到ansible同时执行并打印所有5个主机的执行输出

  • 我们可以在ansible.cfg中减少/增加该值,或者使用-f <val>`,因此ansible将执行远程任务。

  • 就我而言,因为我只有两个托管主机,所以我正在用-f 1执行ansible。

[ansible@controller ~]$ansible all -m shell -a "free -m" -f 1
server1 | CHANGED | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:            815         181         242          12         391         492
Swap:             0           0           0
server2 | CHANGED | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:            815         176         248          12         391         497
Swap:             0           0           0

首先在server1上执行,然后在server2上执行(显然我无法通过代码段向我们展示)。

将文件从Ansible Engine传输到受管节点

在本部分中,我们将使用带有ansible ad-hoc命令的复制模块将文件从Ansible引擎复制到受管节点。

将文件从ansible引擎传输到受管节点的语法是:

ansible [-i INVENTORY] [server] -m copy -a "src=/source/file/path dest=/dest/path"

我将为演示创建一个空文件:

[ansible@controller ~]$touch /tmp/ctrl_file

接下来,我们将使用复制模块将此文件传输到server2

[ansible@controller ~]$ansible server2 -m copy -a "src=/tmp/ctrl_file dest=/home/ansible/"

验证server2上的文件

[ansible@server-2 ~]$ls -l
total 0
-rw-rw-r-- 1 ansible ansible 0 Sep 19 19:10 ctrl_file

在这个例子中,我们将"添加一些文本"到我们刚刚应付到" server2"的文件中。要添加一些数据,我们使用content = <TEXT>的复制模块。其中将" TEXT"替换为我们要与dest =一起添加的数据

[ansible@controller ~]$ansible server2 -m copy -a "content='Hello, My name is hynman' dest=~/ctrl_file"

验证服务器上的内容

[ansible@server-2 ~]$cat ctrl_file
Hello, My name is hynman

使用复制模块获取所有支持的选项的列表

将文件从受管节点下载到控制器节点

在前面的部分中,我们将文件从Ansible引擎传输到了受管节点,现在在本部分中,我们将执行相反的操作。因此,我们将文件从受管节点下载到ansible引擎节点。

我们将在这里使用fetch模块来代替复制,下面是syntax

ansible [-i INVENTORY] [server] -m fetch -a "src=/source/file/path dest=/dest/path"

我将在server2上创建一个虚拟文件。

[ansible@server-2 ~]$touch /tmp/demo.txt

现在,我们将在Ansible用户的主目录下的Ansible引擎上获取此文件

[ansible@controller ~]$ansible server2 -m fetch -a "src=/tmp/demo.txt dest=~/"

该命令的输出

如果我们观察到此命令的输出

"changed": true
"dest": "/home/ansible/server2/tmp/demo.txt",

现在,获取的过程与复制模块几乎没有什么不同。如果我们检查ansible用户的主文件夹,现在我们将找到一个新目录" server2"

[ansible@controller ~]$ls -al
total 64
drwx------   5 ansible ansible  4096 Sep 20 10:26 .
drwxr-xr-x. 15 root    root    20480 Aug 30 15:40 ..
drwx------   4 ansible ansible  4096 Sep 19 16:10 .ansible
-rw-------   1 ansible ansible   145 Sep 19 13:30 .bash_history
-rw-r--r--   1 ansible ansible    18 Jan 11  2019 .bash_logout
-rw-r--r--   1 ansible ansible   141 Jan 11  2019 .bash_profile
-rw-r--r--   1 ansible ansible   312 Jan 11  2019 .bashrc
drwxrwxr-x   3 ansible ansible  4096 Sep 20 10:26 server2
drwx------   2 ansible ansible  4096 Sep 19 14:58 .ssh
-rw-------   1 ansible ansible 10318 Sep 20 10:25 .viminfo

该目录是通过访存操作创建的。我们可以检查此目录的目录结构:

[ansible@controller ~]$tree server2/
server2/
└── tmp
    └── demo.txt
1 directory, 1 file

因此,"提取"模块已将文件复制到" server2"目录下同一路径" tmp/demo.txt"中。现在,我确定大多数用户只需要一个文件时,就不希望下载整个目录结构。

为了克服这个问题,我们将使用flat = yes,它将仅获取文件而不是所有目录结构。

让我们通过添加flat = yes来尝试相同的命令

[ansible@controller ~]$ansible server2 -m fetch -a "src=/tmp/demo.txt dest=~/flat=yes"

该命令的输出

验证文件是否已下载

[ansible@controller ~]$ls -l demo.txt
-rw-rw-r-- 1 ansible ansible 0 Sep 20 10:36 demo.txt

在远程服务器(受管节点)上本地复制文件

在本节中,我将共享临时命令以在受管节点上创建文件或者目录,即源和目标都来自同一受管节点。这可以在执行任何配置更改之前备份任何配置文件。我们将使用相同的复制模块及其语法,此外,我们需要remote_src = true才能在受管节点上本地工作。

在此示例中,我将在server1上执行操作,将~/demo.txt复制到同一服务器上的/tmp/demo-2.txt。

[ansible@controller ~]$ansible server1 -m copy -a "src=~/demo.txt dest=/tmp/demo-2.txt remote_src=yes"
server1 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": true,
    "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "dest": "/tmp/demo-2.txt",
    "gid": 1000,
    "group": "ansible",
    "md5sum": "d41d8cd98f00b204e9800998ecf8427e",
    "mode": "0664",
    "owner": "ansible",
    "size": 0,
    "src": "/home/ansible/demo.txt",
    "state": "file",
    "uid": 1000
}

因此该命令似乎成功,我们可以在server1上验证文件

[ansible@controller ~]$ssh server1 "ls -l /tmp/demo-2.txt"
-rw-rw-r-- 1 ansible ansible 0 Sep 27 10:09 /tmp/demo-2.txt

创建或者删除文件和目录

在本节中,我将共享临时命令以在受管节点上创建文件或者目录,即源和目标都来自同一受管节点。这可以在执行任何配置更改之前备份任何配置文件。我们将使用相同的复制模块及其语法,此外,我们需要remote_src = true

在受管节点上创建文件

我们将使用以下syntax来创建一个新文件:

ansible [-i INVENTORY] [server] -m file -a "path=</path/to/file.txt state=touch>"

现在,我们将使用此语法在ansible引擎上在server2上创建一个新文件/tmp/demo_1.txt

[ansible@controller ~]$ansible server2 -m file -a "path=/tmp/demo_1.txt state=touch"

我的controller节点的输出:

该命令已成功执行。我们可以看到一些已应用于新文件的默认值,例如gidgroupmodeowner等。我们还可以灵活地为新文件定义mode。我们创建的。

使用自定义参数创建文件

在这个例子中,我还为这个新文件定义了一个模式值,即755:

[ansible@controller ~]$ansible server2 -m file -a "path=/tmp/demo_2.txt state=touch mode=755"

我的controller节点的输出:

现在,文件以模式" 0755"创建。

从受管节点中删除文件

要删除文件,我们将使用缺少模块并带有以下syntax

ansible [-i INVENTORY] [server] -m file -a "path=</path/to/file.txt state=absent>"

因此,我们将使用absent而不是touch,并且将删除提供的path =文件。让我们使用以下语法删除我们之前创建的文件之一:

[ansible@controller ~]$ansible server2 -m file -a "path=/tmp/demo_2.txt state=absent"

我的控制器节点的输出:

在受管节点上创建目录

我们也可以使用文件模块来创建一个新目录,但语法略有不同,如下所示:

ansible [-i INVENTORY] [server] -m file -a "path=</path/to/dir state=directory>"

其中我们使用" state = directory"代替" touch"来在受管节点上创建目录。让我们在示例中使用它:

[ansible@controller ~]$ansible server2 -m file -a "path=/tmp/dir_1.txt state=directory"

我的controller节点的输出:

因此,该目录是在server2上创建的

[ansible@server-2 ~]$ls -l /tmp/dir_1.txt/
total 0

默认情况下,将考虑来自server2的umask值来创建目录,但是再次创建目录时,我们可以像先前对文件所做的那样修改modes和permission。

删除目录

我们将再次使用absent作为文件模块的状态,通过以下syntax删除目录:

ansible [-i INVENTORY] [server] -m file -a "path=</path/to/dir state=absent>"

让我们使用以下语法删除上面示例中刚刚创建的dir_1

[ansible@controller ~]$ansible server2 -m file -a "path=/tmp/dir_1.txt state=absent"

我的controller节点的输出:

现在,验证目录是否已从" server2"中删除

[ansible@server-2 ~]$ls -l /tmp/dir_1.txt/
ls: cannot access '/tmp/dir_1.txt/': No such file or directory

以root权限执行命令

到目前为止,在所有示例中,我们都是以ansible用户身份执行的。但是,如果我们尝试执行需要root级特权的命令,该怎么办?让我们尝试使用fdisk -l命令检查可用的分区和存储设备,该命令只能以root用户身份执行:

[ansible@controller ~]$ansible server2 -m command -a "fdisk -l"
server2 | CHANGED | rc=0 >>
fdisk: cannot open /dev/xvda: Permission denied

我们遇到了"权限被拒绝"错误,因为fdisk -l命令只能以root用户身份执行。在这种情况下,我们必须使用-b或者--become来以sudo特权执行命令。如果我们还记得在ansible配置阶段,我们已经为ansible用户赋予了'sudo完全权限'。

让我们尝试使用--become执行相同的命令

[ansible@controller ~]$ansible server2 -m command -a "fdisk -l" --become
server2 | CHANGED | rc=0 >>
Disk /dev/xvda: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes/512 bytes
I/O size (minimum/optimal): 512 bytes/512 bytes
Disklabel type: dos
Disk identifier: 0xa323d5eb
Device     Boot Start      End  Sectors Size Id Type
/dev/xvda1       2048     4095     2048   1M 83 Linux
/dev/xvda2 *     4096 20971486 20967391  10G 83 Linux

这次命令已成功执行。如果我们已将sudo配置为提示输入密码,则该命令将再次失败,要求输入sudo密码,因为默认情况下--- become将不会提示输入任何密码。在这种情况下,我们可以使用--ask-become-pass和--become来提示输入root用户的sudo密码。

[ansible@controller ~]$ansible server2 -m command -a "fdisk -l" --become --ask-become-pass
BECOME password:
server2 | CHANGED | rc=0 >>
Disk /dev/xvda: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes/512 bytes
I/O size (minimum/optimal): 512 bytes/512 bytes
Disklabel type: dos
Disk identifier: 0xa323d5eb
Device     Boot Start      End  Sectors Size Id Type
/dev/xvda1       2048     4095     2048   1M 83 Linux
/dev/xvda2 *     4096 20971486 20967391  10G 83 Linux

在此命令中,ansible提示输入" BECOME password",如果密码正确,则该命令已执行。

我们可以使用--become与ansible ad-hoc命令一起执行任何根级任务。

使用yum模块处理软件包

由于我们使用的是RHEL/CentOS 8环境,因此我们将使用yum模块作为我使用rpm的模块,但是如果我们使用的是Ubuntu/Debian,则应使用apt作为模块。

用于在受管节点上安装软件包的"语法":

ansible [-i INVENTORY] [server] -m yum -a "name=<pkg> state=<present/latest/absent>"

让我们使用此语法在server2上安装git rpm

[ansible@controller ~]$ansible server2 -m yum -a "name=git state=latest"
server2 | FAILED! => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false,
    "msg": "This command has to be run under the root user.",
    "results": []
}

该命令失败,因为我们试图以ansible用户身份安装rpm,而只能使用root特权来执行该命令。因此,我们必须在此命令中使用--become

[ansible@controller ~]$ansible server2 -m yum -a "name=git state=latest" --become
server2 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": true,
    "msg": "",
    "rc": 0,
    "results": [
        "Installed: perl-libnet-3.11-3.el8.noarch",
        "Installed: perl-Digest-1.17-395.el8.noarch",
        "Installed: perl-Mozilla-CA-20150104-7.el8.noarch",
        "Installed: perl-Digest-MD5-2.55-396.el8.x86_64",
        "Installed: perl-Net-SSLeay-1.88-1.el8.x86_64",
        "Installed: perl-Error-1:0.17025-2.el8.noarch",
        "Installed: perl-Data-Dumper-2.167-399.el8.x86_64",
        "Installed: perl-Encode-4:2.97-3.el8.x86_64",
        "Installed: perl-Getopt-Long-1:2.50-4.el8.noarch",
        "Installed: perl-HTTP-Tiny-0.074-1.el8.noarch",
        "Installed: perl-MIME-Base64-3.15-396.el8.x86_64",
        "Installed: perl-Git-2.18.4-2.el8_2.noarch",
        "Installed: perl-TermReadKey-2.37-7.el8.x86_64",
        "Installed: perl-Pod-Escapes-1:1.07-395.el8.noarch",
        "Installed: perl-Pod-Perldoc-3.28-396.el8.noarch",
        "Installed: perl-Pod-Simple-1:3.35-395.el8.noarch",
        "Installed: perl-Pod-Usage-4:1.69-395.el8.noarch",
        "Installed: perl-Storable-1:3.11-3.el8.x86_64",
        "Installed: perl-Term-ANSIColor-4.06-396.el8.noarch",
        "Installed: perl-Term-Cap-1.17-395.el8.noarch",
        "Installed: perl-IO-Socket-IP-0.39-5.el8.noarch",
        "Installed: perl-Text-ParseWords-3.30-395.el8.noarch",
        "Installed: perl-IO-Socket-SSL-2.066-4.el8.noarch",
        "Installed: perl-podlators-4.11-1.el8.noarch",
        "Installed: perl-URI-1.73-3.el8.noarch",
        "Installed: git-2.18.4-2.el8_2.x86_64",
        "Installed: git-core-2.18.4-2.el8_2.x86_64",
        "Installed: git-core-doc-2.18.4-2.el8_2.noarch"
    ]
}

这次命令执行成功,并且git和所有其他依赖项一起安装。在server2上验证相同:

[ansible@server-2 ~]$rpm -q git
git-2.18.4-2.el8_2.x86_64

要"安装具有特定版本的软件包",可以使用" state = present",而"删除转速"则可以使用" state = absent"

以其他用户身份执行临时命令

在本节中,我们将学习如何以不同的用户身份执行Ansible ad-hoc命令。默认情况下,当我们使用ansible执行命令时,它将使用与我们调用ansible命令相同的用户名。在本例中,由于我们以" ansible"身份登录并执行了所有临时命令,因此默认情况下,ansible用户将用于SSH连接。

如果我们需要连接到受管节点并以其他用户身份执行命令,则必须将-u或者--user以及ansible命令一起使用。

我将在server3上创建一个新的用户hynman并分配一个密码:

[root@server3 ~]# useradd hynman
[root@server3 ~]# passwd hynman

现在我们还没有为用户hynman配置基于密码的登录,因此我们将使用密码以" hynman"用户身份连接到" server3"。我们将在"使用密码(而非密码)使用受管节点"一章中了解有关基于密码的登录的更多信息。

如果我们使用whoami参数执行ansible命令,则应该为我们提供在server3上执行命令的用户名。

[ansible@controller ~]$ansible server3 -m command -a "whoami" --ask-pass
SSH password:
server3 | CHANGED | rc=0 >>
ansible

因此,这里使用ansible用户执行whoami

类似地,现在我将使用--user hynman并执行相同的命令:

[ansible@controller ~]$ansible server3 -m command -a "whoami" --user hynman --ask-pass
SSH password:
server3 | CHANGED | rc=0 >>
hynman

现在我们可以看到该命令是使用hynman用户执行的。因此,现在我们可以在不同的即席命令中使用此语法,并以不同的用户身份执行任务。