我之前关于搭建家庭实验室的文章描述了许多构建个人实验室以学习新技术的选项。无论您选择哪种解决方案,随着您的服务器和应用程序的增长,如果不建立控制,维护和跟踪它们将变得越来越困难。为避免这种情况,将基础设施视为代码至关重要。
本文是关于基础设施即代码 (IaC) 的最佳实践,并包含一个示例项目,该项目自动化部署两个虚拟机 (VM),并安装 Keepalived 和 Nginx,同时实施这些实践。您可以在 GitHub 上找到该项目的所有代码。
为什么 IaC 重要?我的脚本还不够吗?
不,脚本是不够的。随着时间的推移,脚本变得难以维护和跟踪。 IaC 可以帮助您保持统一性和可扩展性,同时节省大量手动执行每项任务所浪费的时间。
手动或部分自动化管理服务器的文化的问题之一是缺乏一致性和控制,这(通常)会导致配置漂移和应用程序或服务器的未记录更改。如果必须更换服务器或虚拟机,手动安装每个软件并进行每个配置非常耗时。
使用 IaC,通常可以从集中位置配置、部署和配置数百台服务器,并且可以在版本控制系统中跟踪每个配置。 如果必须修改配置文件,则无需连接到每台服务器,可以在本地更改文件,并将代码推送到版本控制系统。扩展或更换损坏的服务器也是如此。整个基础设施都在集中管理,所有代码都保存在 Git 等版本控制存储库中,服务器所需的任何更改都仅使用此代码完成。不再有独特的独角兽! (对不起,独角兽!)
IaC 的主要优势之一是与 CI/CD 工具(如 Jenkins)集成,这使您可以更频繁地进行测试并创建部署管道,从而自动将应用程序的版本从一个环境移动到下一个环境。
那么,如何开始?
首先,清点服务器所需的每个应用程序、服务和配置;查看安装的每个软件,收集配置文件,验证其参数,并找到可以复制服务器的位置。
当您确定了所需的一切时,请记住
- 使用版本控制;一切都应该使用版本控制进行跟踪。
- 对所有内容进行编码;不应手动完成任何操作。使用代码来描述所需的状态。
- 幂等性。无论执行多少次,您编写的代码的每个结果都应始终产生相同的结果。
- 使您的代码模块化。
- 测试、测试、测试
- 再说一遍:使用版本控制。永远不要忘记这一点。
先决条件
您需要安装了 CentOS 7 的两台虚拟机。应该可以使用密钥通过 SSH 登录。
创建一个名为 **homelab** 的目录。这将是您的工作目录,本教程将其称为 **$PWD**。在此目录中创建另外两个目录:**roles** 和 **group_vars**
$ mkdir -p homelab/{roles,group_vars}
$ cd homelab
版本控制
第一个最佳实践是始终跟踪一切:自动化、配置文件、模板。像 Git 这样的版本控制系统使使用者可以轻松地进行协作,因为它提供了一个集中的存储库,可以在其中找到所有代码、配置、模板等。它还允许用户查看或还原文件的旧版本。
如果没有,请在 GitHub 或 GitLab 中创建一个帐户(或使用您选择的任何其他版本控制提供商)。
在 **$PWD** 中,初始化您的 Git 存储库
$ echo "# IaC example" >> README.md
$ git init
$ git add README.md
$ git commit -m "First commit"
$ git remote add origin <your Git URL>
$ git push -u origin master
对所有内容进行编码
IaC 的主要思想是尽可能使用代码管理所有基础设施。服务器、应用程序或配置中所需的任何更改都必须在代码中定义。配置文件可以转换为模板,以实现更大的灵活性和可重用性。特定于应用程序或服务器的设置也必须进行编码,通常在变量文件中。
创建自动化时,至关重要的是要记住幂等性:无论代码执行多少次,它都应始终具有相同的结果。相同的输入,相同的结果。例如,在编写修改文件的代码时,必须确保如果再次执行相同的代码,该文件看起来会相同。
以下步骤是自动化的,并且代码是幂等的。
模块化
在将基础设施编写为代码时,必须考虑可重用性。您编写的大多数代码都应该是可重用和可扩展的。
在编写 Ansible 角色时,最好的方法是遵循 Unix 哲学:“编写只做一件事并做好这件事的程序。” 因此,创建多个角色,每个角色用于一个软件:1)一个“基础”或“通用”角色,无论其用途如何,都可以准备每个 VM;2)一个安装和配置 Keepalived(用于高可用性)的角色;3)一个安装和配置 Nginx(Web 服务器)的角色。此方法允许将每个角色重复用于不同类型的服务器,并且将来可以节省大量编码。
创建基础角色
此角色将准备 VM 在配置后所需的所有步骤。考虑每个服务器需要的任何配置或软件;它们应该进入此模块。在此示例中,基础角色将
- 更改主机名
- 安装安全更新
- 启用 EPEL 并安装实用程序
- 自定义欢迎消息
在 **$PWD/roles** 中创建基本角色框架
$ ansible-galaxy init --offline base
该角色的主文件是 **$PWD/roles/base/tasks/main.yml**。使用以下内容对其进行修改
---
# We set the hostname to the value in the inventory
- name: Change hostname
hostname:
name: "{{ inventory_hostname }}"
- name: Update the system
yum:
name: "*"
state: latest
- name: Install basic utilities
yum:
name: ['epel-release', 'tmux', 'vim', 'wget', 'nfs-utils']
state: present
- name: Copy motd
template:
src: motd.j2
dest: /etc/motd
通过创建文件 **$PWD/roles/base/templates/motd.j2** 来创建将替换 **/etc/motd** 的模板文件
UNAUTHORIZED ACCESS TO THIS DEVICE IS PROHIBITED
You must have explicit, authorized permission to access or configure "{{ inventory_hostname }}". Unauthorized attempts and actions to access or use this system may result in civil and/or criminal penalties. All activities performed on this device are logged and monitored.
此代码中的每个任务都是幂等的。无论代码执行多少次,它都将始终产生完全相同的结果。注意 **/etc/motd** 是如何修改的;如果通过添加或附加内容(而不是使用模板)来修改文件,它将无法通过幂等性规则,因为每次执行时都会添加新行。
创建 Keepalived 角色
您可以创建一个包含 **Keepalived** 和 **Nginx** 的角色。但是,如果您需要安装 Keepalived 而没有 Web 服务器,会发生什么?代码必须重复,浪费时间、精力和简洁性。保持角色最小化和简单化是正确的方法。
自动化代码应始终处理配置文件,以便可以在版本控制系统中对其进行跟踪。但是,当设置对于每个主机可能具有不同的值时,如何处理配置文件?使用模板!模板允许您使用变量和事实,从而在统一性的基础上为您提供灵活性。
在 **$PWD/roles** 中创建 Keepalived 角色框架
$ ansible-galaxy init --offline keepalived
按如下所示修改主任务文件 **$PWD/roles/keepalived/tasks/main.yml**
---
- name: Install keepalived
yum:
name: "keepalived"
state: latest
- name: Configure keepalived with the right settings
template:
src: keepalived.j2
dest: /etc/keepalived/keepalived.conf
notify: restart keepalived
$PWD/roles/keepalived/handlers/main.yml:
---
# handlers file for keepalived
- name: restart keepalived
service:
name: keepalived
enabled: yes
state: restarted
并创建配置模板文件 **$PWD/roles/keepalived/templates/keepalived.j2**
#### File handled by Ansible.
vrrp_script chk_nginx {
script "pidof nginx" # check the nginx process
interval 2 # every 2 seconds
weight 2 # add 2 points if OK
}
vrrp_instance LAB {
interface {{ keepalived_nic }} # interface to monitor
state {{ keepalived_state }}
virtual_router_id {{ keepalived_vri }}
priority {{ keepalived_priority }}
virtual_ipaddress {
{{ keepalived_vip }}
}
track_script {
chk_nginx
}
}
Keepalived 配置文件已转换为模板。这是一个典型的 Keepalived 配置文件,但它不是硬编码值,而是参数化的。
自动化基础设施和配置文件时,至关重要的是仔细分析应用程序配置文件,注意哪些值在环境中相同,哪些设置对每个服务器都是唯一的。同样,每次处理模板时,都应产生相同的结果。创建变量,使用 Ansible 事实;这加起来就是模块化和灵活性。
创建 Nginx 角色
此简单角色将使用模板安装和配置 Nginx,遵循上述相同的原则。此角色将使用模板生成带有主机 Internet 协议 (IP) 的 **index.html**。其他事实也可以使用。
按如下所示修改主任务文件 **$PWD/roles/nginx/tasks/main.yml**
---
# tasks file for nginx
- name: Install nginx
yum:
name: 'nginx'
state: 'latest'
notify: start nginx
- name: Create web directory
file:
path: /var/www
state: directory
mode: '0755'
- name: Create index.html
template:
src: index.html.j2
dest: /var/www/index.html
- name: Configure nginx
template:
src: lb.conf.j2
dest: /etc/nginx/conf.d/lb.conf
notify: restart nginx
按如下所示修改主任务文件 **$PWD/roles/nginx/handlers/main.yml**
---
- name: start nginx
systemd:
name: 'nginx'
state: 'started'
enabled: yes
- name: restart nginx
systemd:
name: 'nginx'
state: 'restarted'
并创建以下两个配置模板文件:
$PWD/roles/nginx/templates/site.conf.j2
server {
listen {{ keepalived_vip }}:80;
root /var/www;
location / {
}
}
$PWD/roles/nginx/templates/index.html.j2:
Hello, my ip is {{ ansible_default_ipv4.address }}
整合所有内容
您已经创建了多个角色;它们已准备好使用,因此创建一个 playbook 来使用它们。
创建一个名为 **$PWD/main.yml** 的文件
---
- hosts: webservers
become: yes
roles:
- base
- nginx
- keepalived
此文件定义了哪些角色转到哪里。如果有更多角色可用,则可以将其包含在内以根据需要创建不同的组合。例如,某些服务器可能仅是 Web 服务器。这种灵活性是编写最小功能单元如此重要的主要原因之一。
先前的角色需要变量才能工作。 Ansible 非常灵活,可让您定义变量文件。此示例创建了一个名为 **all** 的文件,该文件位于 **group_vars** 中(**$PWD/group_vars/all**)。如果需要更高的灵活性,可以在名为 **host_vars** 的文件夹中为每个主机定义变量
---
keepalived_nic: eth0
keepalived_vri: 51
keepalived_vip: 192.168.2.180
使用您首选的 Keepalived 接口(通常是 **eth0**)配置 **keepalived_nic**。变量 **keepalived_vip** 应具有用作虚拟 IP 所需的 IP。
最后,定义清单(inventory)。该清单应跟踪您的整个基础设施。最好使用动态清单,直接从虚拟机监控程序收集所有信息,这样就不必手动更新。创建一个名为 inventory 的文件,其中包含一个名为 webservers 的部分,包含有关两个虚拟机的信息。
[webservers]
webserver01 ansible_user=centos ansible_host=192.168.2.101 keepalived_state=MASTER keepalived_priority=101
webserver02 ansible_user=centos ansible_host=192.168.2.102 keepalived_state=BACKUP keepalived_priority=100
变量 ansible_user 应该包含 Ansible 将用来连接到服务器的用户。变量 keepalived_state 应该指示主机将被配置为 Master 还是 Backup(如 Keepalived 模板文件中所要求的)。最后,在此设置变量 keepalived_priority,因为 master 应该具有比 backup 更高的优先级。
就这样;您已经自动化了两个虚拟机的配置,安装了 Keepalived 和 Nginx。
现在保存您的更改
$ git add .
$ git commit -m "IaC playbook"
$ git push -u origin master
并部署
$ ansible-playbook -i inventory main.yml
该项目调查了基本的 IaC 概念,但这并不是终点。 通过探索如何进行自动化服务器配置、单元测试以及与 CI/CD 工具和管道的集成来了解更多信息。 这是一个漫长的过程,但无论从技术上还是从职业发展方面来看,都是值得的。
1 条评论