10个Ansible ad-hoc命令实例
在本节中,我将使用默认的列表文件,即"/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"用户执行的,因此现在我们可以跨不同的临时命令使用此语法,并以不同的用户身份执行任务。