使用容器进行 Ansible 开发容器出现之前的生活引入操作框(OpsBox)

2025-06-11

使用容器进行 Ansible 开发

容器出现之前

介绍操作框(OpsBox)

目录

容器出现之前

作为一个专注于系统开发而非应用程序开发的人,我并不认为容器能融入我的日常工作流程。但我对目前的开发体验并不满意,想看看容器能否改善它。它非常笨重且缓慢。当时我有一个完整的 Vagrant 实验室,包含两台 Linux 虚拟机和一台 Windows 虚拟机。Vagrant 会启动一个 Ansible 控制服务器和两台目标机器:一台 Windows 虚拟机,另一台 Linux 虚拟机,用于运行剧本。

写完剧本后,我必须提交、推送、通过 ssh 连接到其他地方、下载,然后再次运行。如果要调试,我只能用 vi。没有 IDE 能帮我摆脱即将陷入的“空白地狱”。有时我会忘记更新其他 Ansible 环境,导致代码运行失败。这简直就是一场噩梦,让我不禁思考,我为什么要费心使用 Ansible。我想要一个更好的工作流程。不,我需要一个更好的工作流程。

《苦难》摘要

  • 重建开发环境非常繁重且缓慢。
  • 无法在实验室环境之外使用 IDE。
  • 到处闲逛
  • 不一致的 Ansible 环境
  • 我:

介绍操作框(OpsBox)

我以前用过容器,主要是为 TeamCity 和 OctopusDeploy 等应用程序构建实验环境。基本上是那些已经有稳定基础镜像的东西。我之前没考虑过用它们来替代我的开发环境。直到有一天,一位同事分享了这篇文章《Ansible、AWS CLI 和 Kubectl 在便携式 Docker OpsBox 中的应用》。这篇文章让我了解了 Operations Box 或 OpsBox 的概念。

这篇文章详细介绍了他们如何编写 Dockerfile,其中包含如何设置开发环境的说明。对他们来说,这包括 AWS CLI 工具、Ansible,以及当时 AWS 为 Kubernetes 提供的 kubectl。我想:“好吧,我现在还不需要 AWS 和 kubectl 这些东西。如果我自己写一个怎么样?” 于是我就这么做了。没过多久,我就遇到了一个问题。我把遇到的错误发到团队聊天里寻求帮助。有趣的是,一位团队成员问:“你想做什么?” 我说:“构建一个包含 Ansible 的 Docker 镜像。” 他回答说:“哦,我已经做了。” 在使用这个容器进行 Ansible 开发大约两分钟后,我开始推广它。

为什么要使用容器

我最喜欢使用容器的地方在于能够从本地机器挂载卷。这意味着我可以共享 Ansible 仓库,并直接修改 playbook,而无需反复 git commit、push、pull 代码。我可以直接在开发环境中修改并运行 playbook,然后再将它们推送到发布管道。现在,第一个合理的问题是“为什么不直接在笔记本电脑上安装 Ansible 进行本地开发呢?” 这个问题问得好,答案是我第二喜欢的地方。使用容器而不是笔记本电脑意味着我的整个团队拥有一致的开发环境,我们更有可能遇到相同的问题,而当我们遇到这些问题并解决它们时,整个团队的问题也就解决了。

我更喜欢容器的另一个原因是它将 Ansible 环境与目标环境解耦。这里所说的目标环境是指一组服务器,通常都位于 Ansible 所针对的同一个 Active Directory 域中。在系统管理中,为每个环境复制所有基础架构组件是常见的做法。容器的可移植性证明我们无需这样做。这最终减少了我们需要管理、更新和修补的内容。管理开销的降低带来了更加稳定和一致的 Ansible 环境。

我要提到的最后一个关于使用容器的惊人好处是能够在几秒钟内轻松重建你的开发环境。你是否曾经尝试过某种自动化技术,它除了在某台特定的机器上之外,在其他任何地方都能正常工作?于是,你撸起袖子,开始使用OSI模型作为故障排除指南进行调试。大约一个小时后,你意识到运行它的机器出现了一些奇怪的环境问题。这又是使用容器的另一个好处。由于容器是不可变的,如果我现在遇到奇怪的DNS问题,我只需退出容器,它会帮我删除它,然后运行一个新的容器。我现在的第一步故障排除是刷新我的开发环境,确保它尽可能干净。

福利总结

  • 为您和您的团队提供一致的开发体验
  • 将 Ansible 环境与目标环境分离。
  • 可移植性减少了管理开销
  • 不可变的管理可变的

常见问题

为什么不在本地安装 Ansible?为什么要使用容器?

  • 容器为我的整个团队提供了一致的环境。

生产环境呢?你肯定不会手动运行所有东西吧?

  • 在开发环境中测试变更后,会发送拉取请求并进行合并。此时,发布管道负责将变更引入到基础架构中。该发布管道的部署步骤使用与我们在开发环境中定义的相同的容器镜像。保持两者一致。

如何管理 Dockerfile 和容器的更改?

  • 拉取请求

本博文的其余部分将引导您了解如何针对 Azure 资源设置用于 Ansible 开发的 OpsBox。此想法可以应用于任何其他基础设施即代码 (IaaS) 工具,例如 Terraform、AWS、vmWare、PowerCLI 等等……它主要包含两个组件:工具和平台。您只需构建适合您环境需求的容器即可。

构建 Docker 容器镜像

要构建容器镜像,首先要创建一个 Dockerfile。Dockerfile 是 Docker 用于构建容器镜像各层的一组指令。我知道这对某些人来说可能比较陌生,但它实际上与引导脚本或虚拟机配置并无太大区别。

Dockerfile 首先声明要使用的基础镜像。就像从黄金镜像创建新的虚拟机一样。这是容器的基础。Ansible 可以在几个不同的 Linux 发行版上运行,但在本文中,我选择了 CentOS。第一行内容为FROM centos:centos7.4.1708。你会注意到,除了发行版名称之外,还有更多内容。其中还包含一个版本号,在 Docker 术语中称为标签。我使用标签来锁定基础容器镜像的版本。



FROM centos:centos7.4.1708


Enter fullscreen mode Exit fullscreen mode

跑步

Docker 以分层方式构建镜像。无需赘述,只需对它有一个基本的了解即可。Dockerfile 中的每个命令(例如 FROM 和 RUN)都会为容器镜像创建一个层。为了减少层数和镜像的复杂性,通常会在单个 RUN 中发出多个命令,如下所示。此时,我已经有了一个基础镜像或操作系统,现在我需要安装 Ansible 所需的一切。

  1. 安装更新
  2. 安装几个开发包 gcc、libffi-devel、python-devel、epel-release
  3. 安装 python-pip 和 python-wheel
  4. 升级 pip


RUN  yum check-update; \
   yum install -y gcc libffi-devel python-devel openssl-devel epel-release; \
   yum install -y python-pip python-wheel; \
   pip install --upgrade pip;


Enter fullscreen mode Exit fullscreen mode

因为我正在创建一个用于管理 Azure 资源的 Docker 容器,所以我还需要 ansible[azure] pip 包。如您所见,它单独占用一行。当我将 pip 添加到之前的命令中时,我收到了错误,提示 pip 无法正常工作。原因是它尚未完全安装。将其移至另一行解决了这个问题,因为 pip 在底层可用。



RUN  pip install ansible[azure];


Enter fullscreen mode Exit fullscreen mode

Dockerfile



FROM centos:centos7.4.1708

RUN  yum check-update; \
   yum install -y gcc libffi-devel python-devel openssl-devel epel-release; \
   yum install -y python-pip python-wheel; \
   pip install --upgrade pip;

RUN  pip install ansible[azure];


Enter fullscreen mode Exit fullscreen mode

构建容器镜像

构建 Docker 镜像的最后一步是运行该docker build命令。您可以将其视为编译步骤。我已经将容器编写到 Dockerfile 中,现在需要运行该文件来创建将来容器启动时使用的镜像。docker build这是用于构建镜像的命令。

-t是一个标记镜像的参数,本质上是给镜像命名。tag 参数后面的部分包含三个部分:repository/imageName/tagVersion。其中,duffney 是我的 DockerHub 仓库名称,ansibleopsbox 是镜像名称,1.0 是表示版本的标签。在每个末尾,你会看到一个 ,.它是 Dockerfile 的路径,其中包含镜像构建说明,.表示当前目录。



docker build -t duffney/ansibleopsbox:1.0 .


Enter fullscreen mode Exit fullscreen mode

将镜像推送到注册表

此时,您的本地计算机上已经有镜像,可以运行容器了。但是您的团队成员该怎么办呢?为了让其他人使用您刚刚构建的镜像,您必须将容器镜像上传到镜像仓库。镜像仓库可以是公共镜像仓库(例如 DockerHub),也可以是私有镜像仓库(例如使用 Azure Container Registry 或 Artifactory 等工具来托管存储库)。以下是如何将镜像推送到 DockerHub 的示例。我使用用户名 duffney 将镜像上传到我的 DockerHub 帐户。我已经在笔记本电脑上将 Docker Desktop 连接到 DockerHub,DockerHub 负责处理所有身份验证等工作……



docker push duffney/ansibleopsbox:1.0


Enter fullscreen mode Exit fullscreen mode

运行容器

现在是时候开始运行容器了!与容器的交互与虚拟机略有不同。您通过 Docker 命令与它们交互,而不是使用 ssh、WinRM 或 RDP。启动新容器的 Docker 命令是docker run。默认情况下,容器以分离方式运行,这意味着在后台运行。要更改该行为,您可以-it在 docker run 命令后添加参数,该参数表示容器将以交互方式运行,并且您的命令提示符将会更改。在命令的末尾,您必须指定要用于容器的映像。在此示例中为。注意到我使用了notduffney/ansibleopsbox:latest标签。如果您不想每次都更改版本,可以选择使用该标签。latest1.0

  • docker run
    • docker cmd 启动容器
  • -it
    • 切换到交互式终端模式
  • duffney/ansibleopsbox:latest
    • 用于容器的 Docker 镜像和标签


docker run -it duffney/ansibleopsbox:latest


Enter fullscreen mode Exit fullscreen mode

替代文本

退出时移除容器

直接使用 Docker run 命令是可行的,但它会给你的机器带来巨大的混乱。因为现在每次退出容器时,它都会以停止状态停留在你的系统上。你可以选择启动它并重新进入交互式终端,但既然可以直接使用新的终端,为什么还要这样做呢?为了避免混乱,请--rm在 Docker run 命令中添加参数 --rm,以便在容器退出时自动删除它。

  • --rm
    • 容器退出时自动移除


docker run -it --rm duffney/ansibleopsbox:latest


Enter fullscreen mode Exit fullscreen mode

卷 (Volume) 使容器成为如此出色的开发环境。卷允许您将本地目录挂载到容器内的目录中。挂载卷后,您可以使用您选择的 IDE 在开发计算机上本地进行更改。这些更改随后会反映在容器内!要在容器内挂载卷,请在 docker run 命令中添加另一个参数。该参数后跟-v。sourcePathsourcePath:targetPath是您要挂载到容器的开发计算机上的位置。targetPath 是您要在容器内挂载卷的位置。

  • -v "$(pwd)":/sln
    • 将当前工作目录挂载到容器内的 /sln。


docker run -it --rm -v "$(pwd)":/sln duffney/ansibleopsbox:latest


Enter fullscreen mode Exit fullscreen mode

替代文本

工作目录

挂载卷带来的一个小麻烦是,启动容器后必须切换到目标/sln目录。这个麻烦可以通过在 docker run 命令中添加另一个参数轻松解决。该参数-w指定容器启动时的工作目录。这会将交互式提示符位置更改为传递给该参数的值。

  • -w /sln
    • 指定 /sln 的工作目录


docker run -it --rm -v "$(pwd)":/sln -w /sln duffney/ansibleopsbox:latest


Enter fullscreen mode Exit fullscreen mode

环境变量

不可避免地,你需要对某些平台进行身份验证。就 Ansible 而言,你可能需要对某个基础设施平台进行身份验证。例如 Azure、AWS、vmWare 等。Ansible 在运行 playbook 时会利用特定的环境变量来连接到这些平台。使用环境变量来存储这些信息非常方便,并且可以由 Docker 填充。

Docker 提供了几种填充环境变量的方法。一种方法是在运行时使用 docker run 命令传入它​​们。我将使用 Azure 作为我的基础架构平台,为了连接到它,我必须指定四个环境变量:AZURE_SUBSCRIPTION_ID、AZURE_CLIENT_ID、AZURE_SECRET 和 AZURE_TENANT。通过使用-e选项,后接环境变量名称,然后输入该变量的值,我可以填充容器的环境变量。

  • -e "ENVIRONMENT_VARIABLE_NAME=<VALUE>"
    • 填充容器内的环境变量


docker run -it -w /sln -v "$(pwd)":/sln --rm \
-e "AZURE_SUBSCRIPTION_ID=<subscription_id>" \
-e "AZURE_CLIENT_ID=<security-principal-appid>" \
-e "AZURE_SECRET=<security-principal-password>" \
-e "AZURE_TENANT=<security-principal-tenant>" \
duffney/ansibleopsbox:latest


Enter fullscreen mode Exit fullscreen mode

使用环境变量只是从 Ansible 连接到 Azure 的几种方法之一。有关更多信息,请参阅使用 Ansible 连接到 Azure。

在容器内使用 Ansible

此时,您需要自行决定如何将 Ansible 容器集成到您的开发工作流程中。我见过的两种最常见的用法是:在独立终端中运行它,以及在 IDE 中使用集成终端(例如 VS Code)运行它。从使用容器的角度来看,这两种方法完全相同。您将在容器内部通过命令行与 Ansible 进行交互。

就我个人而言,我大部分时间都花在了 VS Code 的集成终端上。原因是,我可以利用 VS Code 提供的各种便捷工具和工具,快速编辑已挂载卷中的所有文件。不过,有时我也会在命令行启动容器来执行或调试 playbook。

常见环境

  • 独立终端
  • IDE 中的集成终端(VS Code)

独立终端

替代文本

集成终端 VS Code

替代文本

附加阅读材料和资源

快速入门:在 Azure 中的 Linux 虚拟机上安装 Ansible

编写 Dockerfile 的最佳实践

Azure 容器注册表

DockerHub 注册

我把这篇博文整理成了一本关于 Ansible 的电子书的第一章!你可以在becomeansible.com上免费获取第一章

鏂囩珷鏉ユ簮锛�https://dev.to/cloudskills/using-containers-for-ansible-development-2n9n
PREV
使用 Javascript 的随机密码生成器
NEXT
使用 WASM + Wuffs 在 Web 上快速解析 GIF 演示已完成