10个Ansible ad-hoc命令实例

时间:2020-01-09 10:34:02  来源:igfitidea点击:

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

语法:

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

ad-hoc命令示例

让我们在两个托管主机上使用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"命令,返回当前的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从"inventory"文件获取主机列表。由于我们没有提供任何列表文件,ansible将从默认位置(即"/etc/ansible/hosts")收集主机列表`

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

  • 下一步,我们通过命令传递的模块将被推送到远程节点。如果模块名未与"-m"一起提供,则默认情况下,"command"被视为模块。

  • 此相应的"module"用于在托管主机上执行任务

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

让我们验证一下:

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

[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

现在让我们验证server2上的.ansible目录

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

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

控制并行执行的主机数(forks)

  • 我们已经在"ansible配置"一节中介绍了这一部分,但是让我们用一些例子来讨论这个问题。

  • ansible.cfg文件我们可以选择使用"forks"定义对客户端主机执行的并行任务数。

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

  • 出于演示目的,我们可以在5台服务器上使用默认forks值(即5)执行命令,我们将看到ansible同时执行并打印来自所有5台主机的执行输出

  • 你可以减少/增加这个值ansible.cfg文件或者使用"-f<val>"并相应地执行远程任务。

  • 在我的例子中,因为我只有两个托管主机,所以我用"-f1"执行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引擎传输到托管节点

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

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

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

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

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

接下来,我们将使用copy模块将此文件传输到"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"的文件中。为了添加一些数据,我们使用"copy"模块和"content=<TEXT>"。此处将"TEXT"替换为要随"dest"一起添加的数据

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

验证服务器上的内容

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

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

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

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

我们将其中使用"fetch"模块而不是"copy",下面是"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

此目录是使用fetch操作创建的。我们可以检查此目录的目录结构:

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

因此,"fetch"模块已将文件复制到同一路径"tmp"中/演示.txt在"server2"目录下。现在我确信大多数用户不会希望下载整个目录结构,而我们只需要一个文件。

为了克服这个问题,我们将使用"flat=yes",它只"fetch"文件,而不是所有的director结构。

让我们通过添加"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上执行操作,并其中复制~/演示.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

创建或者删除文件和目录

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

在托管节点上创建文件

我们将使用以下"语法"创建新文件:

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

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

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

我的"控制器"节点的输出:

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

使用自定义参数创建文件

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

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

现在该文件是以"0755"模式创建的。

从托管节点中删除文件

要删除文件,我们将使用带有以下"语法"的"absent"模块:

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

因此,我们将不使用"touch",而是使用"absent",并且将删除提供的带有"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>"

这里不使用"touch",而是使用"state=directory"在托管节点上创建目录。我们举个例子:

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

所以目录是在server2上创建的`

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

默认情况下,"server2"中的"umask"值被视为创建目录,但是我们可以在创建目录时修改"modes"和"permission",就像我们之前对文件所做的那样。

删除目录

我们将再次使用'abside'作为状态with file模块删除目录,语法如下:`

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"

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

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

以root权限执行命令

到目前为止,我们学习的所有示例都是作为ansible用户执行的。但是,如果我们尝试执行一个需要根级别权限的命令呢。让我们尝试使用"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"用户执行,因此出现"permission denied"错误。在这种情况下,我们必须使用"-b"或者"-become"以sudo权限执行命令。如果我们还记得在ansible配置阶段,我们将"full sudo privilege"授予了"ansible"用户。

让我们尝试用"-been"执行相同的命令`

[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配置为提示输入密码,那么命令将再次失败,因为默认情况下"-been"不会提示输入任何密码。在这种情况下,可以使用"-ask been pass"和"-been"来提示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即席命令的根级任务。

使用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": []
}

命令失败,因为我们正在尝试将rpm安装为ansible用户,而这只能使用root权限执行。所以我们必须在这个命令中使用"-been":

[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",而要删除rpm,可以使用"state=absent"

以不同的用户身份执行特殊命令

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

如果我们需要连接到托管节点并以不同的用户身份执行命令,那么我们必须使用"-u"或者"-user"以及"ansible"命令。

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

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

现在我们还没有为用户"deepak"配置基于密码短语的登录,所以我们将使用密码作为"deepak"用户连接到"server3"。我们将在"使用密码(而不是密码短语)"一章中了解更多关于基于密码的登录的信息

如果我们用'whoami'参数执行ansible命令,这应该给我们在'server3'上执行命令所使用的用户的用户名

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

所以这里的"ansible"用户被用来执行"whoami"。

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

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

现在我们可以看到该命令是使用"deepak"用户执行的,因此现在我们可以跨不同的临时命令使用此语法,并以不同的用户身份执行任务。