介绍
由于现代应用程序环境的一次性性质,服务器自动化现在在系统管理中发挥着重要作用。 配置管理工具,例如Ansible,通常用于通过为新服务器建立标准程序来简化服务器设置自动化的过程,同时减少与手动设置相关的人为错误。
Ansible 提供了一个简单的架构,不需要在节点上安装特殊软件。 它还提供了一组强大的功能和内置模块,有助于编写自动化脚本。
本指南解释了如何使用 Ansible 自动执行我们的 Ubuntu 20.04 服务器初始服务器设置指南 中包含的步骤。
先决条件
为了执行本指南中的剧本提供的自动设置,您需要:
- 一个 Ansible 控制节点:安装了 Ansible 并配置为使用 SSH 密钥连接到 Ansible 主机的 Ubuntu 20.04 机器。 确保控制节点具有具有 sudo 权限的普通用户并启用了防火墙,如我们的 初始服务器设置 指南中所述。 要设置 Ansible,请按照我们关于 如何在 Ubuntu 20.04 上安装和配置 Ansible 的指南进行操作。
- 一个全新安装 Ubuntu 20.04 的远程服务器:此服务器不需要事先设置,但您必须从上述 Ansible 控制节点通过 SSH 访问此服务器。 该服务器将成为 Ansible 主机远程服务器,目标是由 Ansible 控制节点自动配置。
这个剧本有什么作用?
这个 Ansible 剧本提供了一种替代方法,可以在每次启动时手动执行 Ubuntu 20.04 初始服务器设置指南 和 在 Ubuntu 20.04 上设置 SSH 密钥的指南服务器。 设置您的剧本一次,然后将其用于每个服务器。
运行此 playbook 将在您的 Ansible 主机上执行以下操作:
- 安装
aptitude
,这是 Ansible 首选的apt
包管理器的替代方案。 - 创建一个新的 sudo 用户并设置无密码
sudo
。 - 复制本地 SSH 公钥并将其包含在远程主机上新管理用户的
authorized_keys
文件中。 - 为 root 用户禁用基于密码的身份验证。
- 安装系统包。
- 将 UFW 防火墙配置为仅允许 SSH 连接并拒绝任何其他请求。
一旦 playbook 完成运行,您将拥有一个新用户,您可以使用该用户登录到服务器。
首先,在 Ansible 控制节点服务器上登录启用 sudo
的用户。
第 1 步 — 准备 Ansible 控制节点
在您的 Ansible 控制节点服务器上,将您的 Ansible 主机远程服务器的 IP 添加到您的 Ansible 清单文件中。 使用您喜欢的文本编辑器:
sudo nano /etc/ansible/hosts
这将打开您的 Ansible 库存文件。 将您的 Ansible 主机远程服务器的 IP 添加到 [servers]
块:
/etc/ansible/主机
[servers] server1 ansible_host=your_remote_server_ip . . .
现在您将测试并验证此 Ansible 控制节点和您的 Ansible 主机远程服务器之间的 SSH 连接:
ssh root@your_remote_server_ip
接受身份验证请求,并在出现提示时输入您的密码。 验证 SSH 连接后,点击 CTRL+D
关闭连接并返回控制节点。
第 2 步——准备你的剧本
playbook.yml
文件是定义所有 任务 的地方。 任务是您可以使用 Ansible playbook 自动执行的最小操作单元。 但首先,使用您喜欢的文本编辑器创建您的剧本文件:
nano playbook.yml
这将打开一个空的 YAML 文件。 在开始向您的剧本添加任务之前,请先添加以下内容:
剧本.yml
--- - hosts: all become: true vars: created_username: sammy
随意用您选择的用户名替换用户名。
几乎你遇到的每一本剧本都会以类似的声明开头。 hosts
声明 Ansible 控制节点将使用此 playbook 定位哪些服务器。 become
说明是否所有命令都将使用升级的 root 权限完成。
vars
允许您将数据存储在变量中。 如果您决定将来更改此用户名,您只需编辑文件中的这一行。
注意:如果要查看最终完成状态的playbook文件,跳转到步骤8。 YAML 文件的缩进结构可能很特殊,因此您可能需要在添加所有任务后仔细检查您的剧本。
第 3 步 — 将 Aptitude 安装任务添加到您的 Playbook
默认情况下,Ansible 在 playbook 中按照从上到下的顺序同步执行任务。 这意味着任务顺序很重要,您可以放心地假设一个任务将在下一个任务开始之前完成执行。
此剧本中的所有任务都可以独立存在,并可在您的其他剧本中重复使用。
添加安装 aptitude
的第一个任务,这是一个与 Linux 包管理器交互的工具:
剧本.yml
tasks: - name: Install aptitude apt: name: aptitude state: latest update_cache: true
在这里,您使用 apt
Ansible 内置的 模块 来指导 Ansible 安装 aptitude
。 Ansible 中的模块是执行操作的快捷方式,否则您必须将其作为原始 bash 命令运行。 如果 aptitude
不可用,Ansible 安全地回退到 apt
来安装包。 因此,虽然这一步在技术上是可选的,但 Ansible 历来首选 aptitude
。
第 4 步 — 将 Sudo 用户设置任务添加到您的 Playbook
避免大量使用 root 用户是一种很好的做法。 您可以通过添加以下内容自动创建被授予 sudo
权限的用户:
剧本.yml
- name: Setup passwordless sudo lineinfile: path: /etc/sudoers state: present regexp: '^%sudo' line: '%sudo ALL=(ALL) NOPASSWD: ALL' validate: '/usr/sbin/visudo -cf %s' - name: Create a new regular user with sudo privileges user: name: "{{ created_username }}" state: present groups: sudo append: true create_home: true
您正在使用 lineinfile
Ansible 模块来定位和替换文件中的特定行。 在这种情况下,您使用正则表达式来定位 sudoers
文件中的特定行,然后对其进行修改以允许无密码使用 sudo
。 您还可以使用 visudo
来验证您的更改,以防止出现任何问题。
为了利用这一点,您将使用 user
模块添加一个新用户。 Ansible 将确保创建此用户(如果尚不存在),该用户属于 sudo
组,而不是从其他组中删除,并创建主目录。
注意: 确保在大括号周围包含表示变量的引号。 省略这些引号是一个非常常见的 Ansible 语法错误。
第 5 步 — 将 SSH 密钥设置和禁用 Root 密码任务添加到您的 Playbook
Ansible 在您使用 SSH 密钥的假设下运行。 强烈建议使用 SSH 密钥与禁用 root 密码身份验证配对,这通常是很好的做法。 要自动执行此操作,请添加:
剧本.yml
- name: Set authorized key for remote user ansible.posix.authorized_key: user: "{{ created_username }}" state: present key: "{{ lookup('file', lookup('env','HOME') + '/.ssh/id_rsa.pub') }}" - name: Disable password authentication for root lineinfile: path: /etc/ssh/sshd_config state: present regexp: '^#?PermitRootLogin' line: 'PermitRootLogin prohibit-password'
如果您提供用户名和密钥的位置,则可以使用 authorized_key
模块。 在这里,通往您的密钥的路径是使用 Ansible 的 lookup
函数构建的。
lineinfile
模块用于搜索和替换 sshd_config
中的一行,以禁用 root 的密码验证,限制对其权限的访问以提高安全性。
第 6 步 — 将包安装任务添加到您的 Playbook
Ansible 可以确保某些软件包始终安装在您的服务器上。 无需在每个单独的包上调用 apt install
或将其分解为多个任务,您可以列出所有所需的包:
剧本.yml
- name: Update apt and install required system packages apt: pkg: - curl - vim - git - ufw state: latest update_cache: true
您可以根据自己的喜好添加或删除软件包。 这将确保所有软件包不仅存在,而且在最新版本上,并且在调用 apt
更新后完成。
第 7 步 — 将防火墙设置任务添加到您的 Playbook
防火墙对于任何面向 Internet 的服务器都是必不可少的。 您可以让 Ansible 通过添加以下内容来确保正确配置了 UFW(简单防火墙):
剧本.yml
- name: UFW - Allow SSH connections community.general.ufw: rule: allow name: OpenSSH - name: UFW - Enable and deny by default community.general.ufw: state: enabled default: deny
ufw
模块首先确保允许通过 SSH 访问。 然后,此模块启用您的防火墙,同时默认拒绝所有其他流量到您的服务器。
第 8 步 — 回顾你的完整剧本
您的剧本应大致如下所示,根据您的自定义设置略有不同:
剧本.yml
--- - hosts: all become: true vars: created_username: sammy tasks: - name: Install aptitude apt: name: aptitude state: latest update_cache: true - name: Setup passwordless sudo lineinfile: path: /etc/sudoers state: present regexp: '^%sudo' line: '%sudo ALL=(ALL) NOPASSWD: ALL' validate: '/usr/sbin/visudo -cf %s' - name: Create a new regular user with sudo privileges user: name: "{{ created_username }}" state: present groups: sudo append: true create_home: true - name: Set authorized key for remote user ansible.posix.authorized_key: user: "{{ created_username }}" state: present key: "{{ lookup('file', lookup('env','HOME') + '/.ssh/id_rsa.pub') }}" - name: Disable password authentication for root lineinfile: path: /etc/ssh/sshd_config state: present regexp: '^#?PermitRootLogin' line: 'PermitRootLogin prohibit-password' - name: Update apt and install required system packages apt: pkg: - curl - vim - git - ufw state: latest update_cache: true - name: UFW - Allow SSH connections community.general.ufw: rule: allow name: OpenSSH - name: UFW - Enable and deny by default community.general.ufw: state: enabled default: deny
注意: 这是一个温柔的提醒,要注意你的缩进。 如果您遇到错误,这很可能是罪魁祸首。 YAML 建议使用 2 个空格作为缩进,如本示例中所做的那样。
一旦你对你的剧本感到满意,你可以退出你的文本编辑器并保存。
第 9 步——第一次运行你的剧本
您现在已准备好在一台或多台服务器上运行此 playbook。 大多数剧本默认配置为在您库存中的每台服务器上执行,但这次您将指定您的服务器。
要仅在 server1
上执行 playbook,连接为 root
,可以使用以下命令:
ansible-playbook playbook.yml -l server1 -u root -k
-l
标志指定您的服务器,-u
标志指定在远程服务器上登录的用户。 由于您尚未设置远程服务器,因此 root 是您唯一的选择。 -k
标志在您第一次运行 playbook 时非常重要,因为它允许您输入 SSH 密码。
你会得到类似这样的输出:
Output . . . TASK [UFW - Allow SSH connections] *************************************************************************************************************************************************************************************************************************** changed: [server1] TASK [UFW - Enable and deny by default] ********************************************************************************************************************************************************************************************************************** changed: [server1] PLAY RECAP *************************************************************************************************************************************************************************************************************************************************** server1 : ok=9 changed=8 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
这表明您的服务器设置已完成! 您的输出不必完全相同,但零故障很重要。
现在您已经完成了 playbook 的第一次设置,所有后续的 ansible 调用都可以使用用户 sammy
完成,而无需 -k
标志:
ansible-playbook playbook.yml -l server1 -u sammy
您还可以使用以下方式登录服务器:
ssh sammy@your_remote_server_ip
请记住将 sammy 替换为 created_username
变量定义的用户,并将 server_host_or_IP 替换为您的服务器的主机名或 IP 地址。
登录服务器后,您可以检查 UFW 防火墙的活动规则以确认其配置正确:
sudo ufw status
你应该得到类似这样的输出:
OutputStatus: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6)
这意味着 UFW 防火墙已成功启用。 由于这是 playbook 中的最后一个任务,因此它确认 playbook 已在此服务器上完全执行。
结论
自动化初始服务器设置可以节省您的时间,同时还可以确保您的服务器遵循可以根据您的需要进行改进和定制的标准配置。 由于现代应用程序的分布式特性以及不同暂存环境之间需要更高的一致性,这样的自动化成为必要。
在本指南中,您演示了如何使用 Ansible 自动执行应在新服务器上执行的初始任务,例如创建具有 sudo
访问权限的非 root 用户,启用 UFW 和禁用基于远程密码的 root 登录。
有关如何运行 Ansible playbook 的更多信息,请查看我们的 Ansible 备忘单指南 。
如果您想在本手册中包含新任务以进一步自定义初始服务器设置,请参阅我们的 Ansible 入门指南 配置管理 101:编写 Ansible 手册。 您还可以查看我们关于 如何使用 Ansible 角色来抽象您的基础架构环境 的指南。