Skip to main content

快速开始

本节带你快速入门使用 Ansible,包括 Ansible 配置、Invenytory 与 Ad-Hoc 的使用方法。

环境初始化

环境准备

在开始前,我们需要准备实验所用到的主机。

这里为您准备了 Vagrant 环境,可以一键启动如下环境

新建目录中创建如下 config.yamlVagrantfile 文件,然后在此目录中执行 vagrant up 即可启动练习环境。关于 Vagrant 更多使用方法详见:Vagrant

启动后使用 vagrant ssh <host_name> 登录到对环境的各个节点进行初步检查:

输入 hostname && hostname -d && hostname -f 分别检查主机名、主机域和FQDN。

输入 cat /etc/hosts 检查 Hosts 配置是否正确。

Vagrant 环境配置文件:

config.yaml
servers:
- name: control
network:
- 192.168.56.100:private_network:add_hosts
port_forward:
- 8685:22:ssh
provision_shell_inline:
- "sudo timedatectl set-timezone Asia/Shanghai"
- "sudo sed -e 's|^mirrorlist=|#mirrorlist=|g' \
-e 's|^#baseurl=http://mirror.centos.org/centos|baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos|g' \
-i.bak \
/etc/yum.repos.d/CentOS-*.repo && sudo sed -i 's/nameserver .*/nameserver 8.8.8.8/' /etc/resolv.conf && sudo yum install epel-release -y && sudo yum install ansible -y"
- name: node1
network:
- 192.168.56.10:private_network:add_hosts
port_forward:
- 8686:22:ssh
provision_shell_inline:
- "sudo timedatectl set-timezone Asia/Shanghai"
- name: node2
network:
- 192.168.56.20:private_network:add_hosts
port_forward:
- 8687:22:ssh
provision_shell_inline:
- "sudo timedatectl set-timezone Asia/Shanghai"
- name: node3
network:
- 192.168.56.30:private_network:add_hosts
port_forward:
- 8688:22:ssh
provision_shell_inline:
- "sudo timedatectl set-timezone Asia/Shanghai"
default_config:
default_region: lab.local
default_cpu: 1
default_mem: 1024
default_network_mode: private_network
default_os: centos/7:2004.01
boot_timeout: 300
default_gui: false
# 设置启动顺序
boot_order: ["disk", "dvd", "none"]
# 挂载目录选项
default_synced_folder:
create: true
owner: vagrant
group: vagrant
mount_options: ["dmode=755", "fmode=644"]
type: virtualbox # virtualbox、NFS 或 rsync
# 自定义密钥
ssh_pub_keys:
local_key:
- "#{Dir.home}/.ssh/id_rsa.pub"
HostnameOSIPDescribe
controlcentos/7:1809.01192.168.56.100ansible 已经安装在此节点
node1centos/7:1809.01192.168.56.10
node2centos/7:1809.01192.168.56.20
node3centos/7:1809.01192.168.56.30

我们的 ansible 配置创建在 control 节点上 /home/vagrant/ansible 目录下。

设置免密登录

Ansible 通过 SSH 协议连接远程主机进行操作,为了安全考虑建议通过密钥免密连接而不是密码,如果使用密码 Ansible 则会使用 sshpass 来实现自动登录,这被认为是不安全的。

sshpass 安全问题和建议
warning

sshpass 存在以下安全问题:

  • 密码以明文形式传递,在查看 sshpass 进程时,可能会获取到密码。这是因为在某些系统中,命令行参数会被保存在进程的环境变量中,因此密码可能会被保存在 sshpass 进程的环境变量中。
  • 当手动运行 sshpass 时密码存储在命令行历史记录中,可能会被其他用户(如管理员)查看。

如果非要使用密码建议:

  • 不要直接将密码明文写在 inventory 中,请将密码作为外置变量引入并使用 vault 来加密。
  • 在手动运行 sshpass 命令时,使用 -e 选项来禁用密码在环境变量中的传递。
  • 限制 sshpass 进程的访问权限,避免不必要的特权用户访问进程,从而减少密码泄露的风险。
SSH 安全配置选项
info

大量的远程主机都使用同一个密码提供 ssh 远程登录是很不安全的,一般都建议所有主机都只开启私钥登录,禁用密码登录。相关配置在主机的 /etc/ssh/sshd_config 中。

在 control 节点上创建密钥对并分发给其他 node 节点。

# 创建密钥对
ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa -q
# 查看公钥
cat ~/.ssh/id_rsa.pub
# 分发公钥
sshpass -p <your_passwd> ssh-copy-id -i ~/.ssh/id_rsa.pub <user@IP>

若 SSH 禁止了密码登录,需要登录 node 节点上手动导入 control 节点的公钥。

# 手动在需要免密的节点上做以下配置
mkdir -p -m 700 ~/.ssh
echo "<control_public_key>" >> ~/.ssh/authorized_keys
chmod 600 .ssh/authorized_keys
使用脚本验证免密

使用前请确保已扫描并添加主机指纹。

#!/bin/bash
user=vagrant
StrictHostKeyChecking=yes

# 自动从 hosts 中设置 hosts 变量
# hosts=($(awk '$0 !~ /^#/ {for(i=1;i<=NF;i++) if ($i !~ /localhost/) print $i}' /etc/hosts))
# echo ${hosts[@]}
hosts=(
control
node1
node2
node3
control.lab.local
node1.lab.local
node2.lab.local
node3.lab.local
192.168.56.100
192.168.56.10
192.168.56.20
192.168.56.30
)

printf "%-70s %-15s %-50s\n" "Node" "Status" "Describe"

for host in "${hosts[@]}"; do
describe=$(ssh -o BatchMode=yes -o StrictHostKeyChecking=${StrictHostKeyChecking} ${user}@${host} "echo Logged in to $host without password" 2>&1)
if [ $? -eq 0 ]; then
printf "%-70s \033[32m%-15s\033[0m %-50s\n" "$host" "yes" "$describe"
else
printf "%-70s \033[31m%-15s\033[0m %-50s\n" "$host" "no" "$describe"
fi
done

若失败则可能是你没有添加主机指纹,请看下一节 '批量扫描主机指纹'

或者修改脚本使 StrictHostKeyChecking=no ,此时 SSH 首次连接会跳过检查主机密钥的指纹,客户端不会询问你是否信任该服务器的密钥,而是自动接受该密钥并将其保存在 ~/.ssh/known_hosts。

批量扫描主机指纹

第一次连接到一个 SSH 服务器时,会提醒我们检查主机密钥的指纹。 SSH 客户端会将服务器的公钥存储在本地计算机上,并生成一个指纹,以便在将来的连接中验证服务器的身份。如果指纹与之前存储的不匹配,则可能是中间人攻击,应该中止连接。

Ansible 默认情况下也会使用这个指纹对主机进行验证,因此我们希望能够快速地扫描出所有主机的指纹,下面提供了两种方法:

登录 Ansible 所在节点 control 运行如下命令:

echo "
control
node1
node2
node3
192.168.56.100
192.168.56.10
192.168.56.20
192.168.56.30
" > hosts-keyscan
ssh-keyscan -H -f hosts-keyscan >> ~/.ssh/known_hosts
# 添加 -H 参数,只保存主机 IP/域名的 hash 值,更安全
warning

不建议修改 ansible.cfg 使 host_key_checking = False 永久跳过检查主机指纹,这可能会受到中间人攻击。

设置 sudo 权限

Vagrant 在创建虚拟机时,会在 /etc/sudoers.d 目录下创建一个名为 vagrant 的文件,该文件包含以下内容:

sudo cat /etc/sudoers.d/vagrant
%vagrant ALL=(ALL) NOPASSWD: ALL

上述配置使 vagrant 组的用户使用 sudo 无需密码。

Ansible 配置文件

配置文件生效优先级:

  1. $ANSIBLE_CONFIG 变量
  2. 当前目录下 ansible.cfg
  3. 用户家目录下 ansible.cfg
  4. /etc/ansible/ansible.cfg (默认)

通过 ansible --version 可以看到配置文件目录等信息

可以通过 ansible-config init --disabled -t all >ansible.cfg 创建初始配置,其包含了详细的参数说明。通过 cat /etc/ansible/ansible.cfg|grep -Ev ";|#|^$" 查看默认配置。

登录 control 节点,创建工作目录 mkdir ~/ansible && cd ~/ansible ,然后创建如下配置

/home/vagrant/ansible/ansible.cfg
[defaults]
inventory = ./inventory
remote_port = 22
; host_key_checking = False
remote_user = vagrant
log_path = ./ansible.log
private_key_file = /home/vagrant/.ssh/id_rsa

[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False

inventory 主机清单

使用 inventory 主机清单以对主机进行分类,对不同类别的主机配置不同的参数,例如 ssh 登录用户名,密码信息和变量等。

/home/vagrant/ansible/inventory
# 给服务器分组,组名只能用 [a-z A-Z 0-9 _]
[ansible_control]
control
192.168.56.100:22
[node]
node1.lab.local ansible_port=22 ansible_ssh_private_key_file=/home/vagrant/.ssh/id_rsa
; node1.lab.local ansible_ssh_port='22' ansible_ssh_user='root' ansible_ssh_pass='passwd'
192.168.56.[2:3]0

# node 组的公用参数
[node:vars]
myvar='hello world'
ansible_ssh_user='vagrant'
; ansible_ssh_pass='vagrant'
; ansible_ssh_port='22'
; ## 如果登陆后需要切换用户则需要以下配置
; # 切换用户
; ansible_become=true
; # 使用su切换
; ansible_become_method=su
; # 切换到root
; ansible_become_user=root
; # root密码
; ansible_become_pass=pass

# 子组分类变量:children
[labmachine:children]
ansible_control
node

# 给服务器指定别名
[alias]
ansible ansible_host=control.lab.local ansible_become=yes ansible_become_pass=vagrant
inventory ini 和 yaml 格式转换

inventory 主机清单支持 ini 和 yaml 格式。

可以使用以下命令将上述 inventory 从 ini 格式转换到 yaml 格式:

ansible-inventory --list -i inventory --yaml > inventory.yaml

输出 inventory.yaml 内容如下

inventory.yaml
all:
children:
alias:
hosts:
ansible:
ansible_host: control.lab.local
labmachine:
children:
ansible_control:
hosts:
192.168.56.100:
ansible_port: 22
control: {}
node:
hosts:
192.168.56.20:
ansible_ssh_user: vagrant
myvar: hello world
192.168.56.30:
ansible_ssh_user: vagrant
myvar: hello world
node1.lab.local:
ansible_port: 22
ansible_ssh_private_key_file: /home/vagrant/.ssh/id_rsa
ansible_ssh_user: vagrant
myvar: hello world
ungrouped: {}

写完 inventory 主机清单后,输入下面命令,应成功输出节点信息。

ansible all --list-hosts
# 和下面等价
# ansible -i inventory all --list-hosts
# ansible -i inventory.yaml all --list-hosts

# 使用 ping 模块检查网络是否互通
ansible all -i inventory -m ping

到此已成功安装和配置 ansible ,下面介绍如何使用 Ad-hoc 模式执行临时命令。

命令模式

Ansible 中有两种模式:

  • Ad-hoc 模式,用于执行一段 “临时命令”
  • Playbook 模式,用于执行声明性配置的一组任务。

Ad-hoc 模式

Ansible 基本命令选项

Ansible 提供了海量模块,可以通过 ansible-doc -l 查看可用模块,使用 ansible-doc <mode_name> 查看模块具体用法。

ansible <host-pattern> [options]
--version #显示ansible版本信息
-i #指定主机清单文件路径,默认是在/etc/ansible/hosts
-m #指定模块名称,默认使用command模块
-a #指定模块参数
-e #指定变量
-f #指定并发数,默认5
-C #模拟测试,不会真正执行
-D #显示这些文件的差异。常与-C一起使用
--syntax #语法检查
--list-hosts #列出主机清单
-k #提示输入ssh密码,而不是用ssh的密钥认证
-T #执行命令的超时时间
  • ansible <pattern> -m <module_name> -a "<module options>"
    • 例如 ansible webservers -m service -a "name=httpd state=restarted"
  • 默认模块是 "command"
    • 如下面两条命令使用的模块都是 command。
    ansible all -i inventory -m command -a "ls -al"
    # command 为缺省模块可以省略不写。
    ansible all -i inventory -a "ls -al"

Playbook 模式

请阅读后续 Playbook 章节