软件设置、选项和配置有许多不同的形式。一类是使用精心设计、直观明了、响应迅速、同时效验无效配置的 GUI。另一类是利用文本文件。虽然文本文件因其清晰简洁、自动化潜力和最低使用要求(您可能有几个打开的终端窗口,对吧?)而备受工程师和 DevOps 团队的推崇,但使用文本文件配置软件显然也有弊端。举例来说,试问哪位 Linux 用户不曾因文本文件配置错误而导致软件包崩溃过。
作为唯一一款将软件代理、负载均衡器、Web 服务器和 API 网关集于一身的多合一产品,NGINX 是现代互联网基础设施的关键组成部分。在大多数情况下,这些基础设施都采用基于 Linux 内核的操作系统。为了更好地满足这一生态系统及其专业支持人员的使用需求,NGINX 高度依赖基于文本的配置。
F5 NGINX Instance Manager 模块一直是 NGINX 相关配置编排的首选,提供了各种高级功能,可通过其直观的用户界面和 API 支持远程批量配置管理,并配有丰富的支持文档和使用模板。虽然单个 NGINX 配置文件酷似代码,但也无妨,因为软件团队已经拥有了强大的代码管理工具:Git。Git 为开发人员和运维团队提供了一系列用于管理文本文件工作流的功能。
Instance Manager 的新功能提供与 Git 及其他外部系统的集成,支持版本控制、分散贡献、审批工作流及团队协调等特性。GitHub 和 GitLab 等平台通过基于 Web 的用户界面将此特性集扩展到持续集成/持续部署(CI/CD)、协作、问题跟踪及其他重要功能。
本文将介绍如何使用 GitHub 来管理 NGINX 配置,并在发生变更时自动将这些配置推送到实例。
Instance Manager API
Instance Manager 提供了丰富的 REST API 集,与其 Web 用户界面相辅相成。API 的一大优势是能够更新所管理的数据平面实例的配置文件。最近,我们扩展了这一功能,支持将配置更新与文件的特定版本关联。在 Git 代码库中管理配置时,可使用 Git 提交哈希标记配置。此外,我们还在 Instance Manager 中为外部托管配置实施了一种新状态,以提醒潜在文件编辑器配置受外部管理。
GitHub Actions
GitHub 允许开发人员使用一项名为 Actions 的功能在其代码库中创建自定义部署流水线。用户可以选择定义自己的操作,或者通过 YAML 定义调用现有脚本。这些流水线可通过多种方式触发,例如当使用提交或拉取请求合并更新代码库时。
在本文的示例中,我们使用现成的 GitHub Actions 和 Linux 命令,介绍了如何通过 Instance Manager API 在 NGINX 实例上更新 GitHub 管理的 NGINX 配置文件。首先,按照 GitHub 文档中所述的以下步骤新建一个 YAML,用于在代码库中运行 Actions。
设置 Actions 密钥
Instance Manager 支持多种形式的身份验证。在示例中,我们使用了 Basic 身份验证方法,不过我们建议在生产环境中配置 OIDC 身份验证。
GitHub 允许您将密钥定义为代码库变量,而非将 Instance Manager 凭证存储至代码库。这些变量可供 Actions 环境访问,但在日志中不可见。按照以下步骤将 Instance Manager 用户名和密码存储为密钥,以便用其对 API 调用进行身份验证。
此处,我们将这些变量设置为 NMS_USERNAME
和 NMS_PASSWORD
。
设置 Actions 变量
同样,与其在 YAML 中定义常量变量,不如将其提取出来在 GitHub 用户界面中进行管理。在 Variables(变量)页面,您可以了解如何定义涵盖所有代码库 Actions 的变量。在示例中,我们借此机会定义 Instance Manager FQDN 或 IP (NMS_HOSTNAME
)、NGINX 运行系统的标识符(SYSTEM_ID
)以及要更新的特定 NGINX 实例的标识符(INSTANCE_ID
)。
注:我们设置这些变量是为了简化示例,但您可以选择以其他方式管理 Instance Manager、系统和 NGINX 标识信息。例如,您可选择在代码库中创建多个目录以存储不同实例的特定配置,并使用系统或实例 ID 命名这些目录。然后,您可以修改 YAML 或 Action 脚本,以读取目录名称并更新相应实例的配置文件。
用于更新 NGINX 配置的 Instance Manager REST API 调用简析
Instance Manager 配置更新 REST API 调用需要多个关键组件。您的 YAML 将需要定义这些参数,并以正确的格式将其打包到 API 调用中。
在示例中,我们使用 API 调用更新单个实例。不过,您也可以在 Instance Manager 中配置实例组。这样一来,每当从 GitHub 推送新配置时,您都能够更新组中的所有实例。更多信息,请参阅我们的《发布配置操作指南》。
以下是 Instance Manager 的配置更新 REST API 调用的详解:
https://{INSTANCE MANAGER HOSTNAME}/api/platform/v1/systems/{SYSTEM ID}/instances/{INSTANCE ID}/config'
--header "accept: application/json"
--header "Authorization: Basic {LOGIN CREDENTIALS}"
--header 'Content-Type: application/json'
--data '{
"configFiles": '{
"rootDir": "/etc/nginx",
"files": [{
"contents": "{NGINX CONFIGURATION FILE}",
"name": "{PATH TO CONFIGURATION FILE ON SYSTEM}"
}]
},
"externalIdType": "{SOURCE OF CONFIGS}",
"externalId": "{COMMIT HASH}",
"updateTime": "{TIMESTAMP}"
}'}'
URI 参数
- 系统标识符 – 用于标识 NGINX 运行系统的唯一值。在我们的示例中,该数据在 GitHub Actions 变量界面中进行定义。
- NGINX 实例标识符 – 用于标识系统上特定 NGINX 实例的唯一值。在我们的示例中,该数据在 GitHub Actions 变量界面中进行定义。
请求头参数
- Authorization – Instance Manager 用于对 API 调用进行身份验证的授权方法和 Base64 编码凭证。在示例中,您将使用基本授权和来自代码库中密钥集的凭证数据。
JSON 数据参数
- configFiles – 正在更新的配置文件的 Base64 编码内容及其在 NGINX 运行系统上的位置。您还需要提供 NGINX 配置文件根目录的路径,通常配置为:
/etc/nginx
。 - externalIdType – 用于向 Instance Manager 标识配置文件源的标签。可能的值为
git
或other
。在我们的示例中,我们将该参数硬编码为git
。 - externalId – Git 提交安全哈希算法(SHA),用于标识配置文件变更。
- updateTime – 包含当前日期和时间的字符串,格式为
%Y-%m-%dT%H:%M:%SZ
。
Base64 编码
为了满足 Instance Manager 的 API 规范要求,您必须通过将某些数据编码为 Base64 格式来转换这些数据。虽然现有 GitHub Actions 并没有实现这一功能的原生方法,但我们可以依靠 Linux 工具(可从 YAML 访问)。
Instance Manager 凭证
首先引用之前定义为密钥的 Instance Manager 登录凭证,并将它们连接为字符串。然后,将字符串转换为 Base64,将其输出(echo)为 Linux 变量(NMS_LOGIN
),并将结果附加到预定义的环境变量(GITHUB_ENV
),以供 Actions 运行程序访问。
run: echo "NMS_LOGIN=`echo -n "${{ secrets.NMS_USERNAME }}:${{ secrets.NMS_PASSWORD }}" | base64`" >> $GITHUB_ENV
时间戳
Instance Manager API 要求特定格式的时间戳与特定 API 有效载荷一起发送。您可以使用 Linux date
命令以这种格式构建时间戳。与前面的例子类似,将构建的字符串作为变量添加到 Linux 环境。
run: echo "NMS_TIMESTAMP=`date -u +"%Y-%m-%dT%H:%M:%SZ"`" >> $GITHUB_ENV
NGINX 配置
接下来,将您计划管理的 NGINX 配置添加到代码库中。您可通过多种方法将文件添加到 GitHub 代码库。更多信息,请参阅 GitHub 文档中的指南。如果要使用我们的示例,您可以在 GitHub 代码库中创建一个与实例相同的目录结构。
下面的 YAML 条目从代码库中读取配置文件,将其内容编码为 Base64,并同样将结果添加到环境变量中。
run: echo "NGINX_CONF_CONFIG_FILE=`cat nginx-server/etc/nginx/nginx.conf | base64 -w 0`" >> $GITHUB_ENV
在我们的示例中,我们对 GitHub 代码库中的每个配置文件都重复执行此操作。
总结
最后,您可以使用 GitHub 的示例参考实现,在 YAML 文件中试验以上内容。如文件中所定义,每当用户通过提交或拉取请求更新该代码库时,所有相关的 GitHub Actions 脚本都会运行。YAML 中的最后一个条目将运行 curl
命令,该命令将调用相应的 API,其中包括 Instance Manager 更新所有相关配置文件所需的数据。
注:在 YAML 中需要使用多行运行条目(run: |
)来运行 curl
命令,因为这会指示 YAML 解释器将条目参数部分的冒号“:”视为文本。
name: Managing NGINX configs with GitHub and GitHub Actions
# 控制工作流的运行时间
on:
# 触发推送或拉取请求事件的工作流,但仅限于“主”分支
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
# 允许您从 Actions 选项卡手动运行此工作流
workflow_dispatch:
# 一个工作流运行由一个或多个作业组成,这些作业既可按顺序运行,也可并行运行
jobs:
# 此工作流包含一个名为“build”的作业
build:
# 作业运行的运行程序类型
runs-on: ubuntu-latest
# steps 表示将作为作业的一部分执行的一系列任务
steps:
# 在 $GITHUB_WORKSPACE 下签出您的代码库,以便您的作业能够对其进行访问
- uses: actions/checkout@v4
- name: Set environment variable for NMS API login credentials
run: echo "NMS_LOGIN=`echo -n "${{ secrets.NMS_USERNAME }}:${{ secrets.NMS_PASSWORD }}" | base64`" >> $GITHUB_ENV
- name: Set environment variable for NMS API timestamp
run: echo "NMS_TIMESTAMP=`date -u +"%Y-%m-%dT%H:%M:%SZ"`" >> $GITHUB_ENV
- name: Set environment variable for base64 encoded config file
run: echo "NGINX_CONF_CONFIG_FILE=`cat app-sfo-01/etc/nginx/nginx.conf | base64 -w 0`" >> $GITHUB_ENV
- name: Set environment variable for base64 encoded config file
run: echo "MIME_TYPES_CONFIG_FILE=`cat app-sfo-01/etc/nginx/mime.types | base64 -w 0`" >> $GITHUB_ENV
- name: Set environment variable for base64 encoded config file
run: echo "DEFAULT_CONF_CONFIG_FILE=`cat app-sfo-01/etc/nginx/conf.d/default.conf | base64 -w 0`" >> $GITHUB_ENV
- name: Set environment variable for base64 encoded config file
run: echo "SSL_CONF_CONFIG_FILE=`cat app-sfo-01/etc/nginx/conf.d/ssl.conf | base64 -w 0`" >> $GITHUB_ENV
- name: API call to Instance Manager
run: |
curl --location 'https://${{ vars.NMS_HOSTNAME }}/api/platform/v1/systems/${{ vars.SYSTEM_ID }}/instances/${{ vars.INSTANCE_ID }}/config' --header "accept: application/json" --header "Authorization: Basic ${{ env.NMS_LOGIN }}" --header 'Content-Type: application/json' --data '{"configFiles": {"rootDir": "/etc/nginx","files": [{"contents": "${{ env.NGINX_CONF_CONFIG_FILE }}","name": "/etc/nginx/nginx.conf"},{"contents": "${{ env.MIME_TYPES_CONFIG_FILE }}","name": "/etc/nginx/mime.types"},{"contents": "${{ env.DEFAULT_CONF_CONFIG_FILE }}","name": "/etc/nginx/conf.d/default.conf"},{"contents": "${{ env.SSL_CONF_CONFIG_FILE }}","name": "/etc/nginx/conf.d/ssl.conf"}]},"externalIdType": "git","externalId": "${{ github.sha }}","updateTime": "${{ env.NMS_TIMESTAMP }}"}'
NGINX 参考实现
在文件变更后,可通过不同的方式执行配置更新 API 调用。对于使用 GitHub 的用户而言,GitHub Actions 是最便捷的方法,但却不适用于 GitLab 或独立 Git 实现。针对这些用例,我们开发了一个配套 shell 脚本参考实现,支持从命令行进行触发或从自定义脚本调用。
总而言之,我们对 Instance Manager API 的新扩展提供了一套功能强大的工具,能够以一种现代的分散化方式管理配置更新、回滚及版本历史记录。该扩展与 GitHub 等第三方文本文件和代码管理平台结合使用,可通过直观的 Web 用户界面实现更多工作流、CI/CD、协作及问题跟踪功能。
我们希望倾听您的想法!现在就试试吧,并微信添加“小N助手(微信号:nginxoss)”加入 NGINX 官方微信群告诉我们您的想法。