使用 Puppet 管理 Docker 实例

在之前的文章《使用 Puppet 配置 Docker》(发表于 2016 年 12 月刊)中,我介绍了使用 Puppet 在新系统上安装 Docker 服务的方法之一。相比之下,本文重点介绍如何使用 Puppet 管理 Docker 镜像和容器。

将 Docker 与 Puppet 集成的原因

将 Docker 与 Puppet 或其他配置管理工具(如 Chef 或 Ansible)集成有三个核心用例

  1. 使用配置管理在主机上配置 Docker 服务,以便它可以管理 Docker 实例。

  2. 在托管主机上添加或删除特定的 Docker 实例,例如容器化的 Web 服务器。

  3. 使用配置管理工具(例如,Puppet agent)构建到 Docker 镜像中,从而管理 Docker 容器内部复杂或动态的配置。

《使用 Puppet 配置 Docker》(发表于 LJ 2016 年 12 月刊)涵盖了第一个用例。本文主要关注第二个用例。

使用 Puppet 进行容器管理,您可以完成许多事情,这些事情随着组织扩展其系统规模而变得越来越重要,包括以下内容

  1. 利用组织现有的配置管理框架,而不是使用完全独立的流程来管理 Docker 容器。

  2. 将 Docker 容器视为“只是另一种资源”,以便在配置管理包/文件/服务生命周期中进行整合。

  3. 根据主机名、节点分类或节点特定的事实自动安装 Docker 容器。

  4. 编排多个主机上 Docker 容器内部的命令。

虽然当然还有其他方法可以实现这些目标(请参阅“选择工具链”侧边栏),但扩展您现有的 Puppet 基础设施以处理容器作为节点角色或配置文件的一部分,只需很少的工作。这就是本文的重点。

选择工具链

为什么要关注使用 Puppet 进行容器管理?当然还有其他方法可以管理 Docker 实例、容器和集群,包括 Docker 本身的一些原生方法。与任何其他 IT 工作一样,您选择的工具链既提供了功能,也限制了您的能力。对于家庭系统,您对工具链的选择在很大程度上是个人品味的问题,但在数据中心,尽可能利用现有工具和内部专业知识通常更好。

之所以选择 Puppet 用于本系列文章,是因为它是一个强大的企业级解决方案,已经广泛部署了十多年。但是,如果您选择,也可以使用 Chef 或 Ansible 做同样的事情。

选择 Puppet 而不是其他容器编排工具的另一个原因是,许多大型组织已经在使用至少一种配置管理工具。在许多情况下,将容器管理包含在现有工具链中,而不是攀登更专业的工具(如 Kubernetes)的学习曲线,更有优势。

如果您已经在数据中心使用 Puppet、Chef 或 Ansible,那么通过扩展您当前的工具集开始进行容器管理可能是明智之举。但是,如果您发现自己遇到了配置管理工具的限制,您可能需要评估其他企业级解决方案,例如 Apache Mesos、Kubernetes 或 DC/OS。

创建测试环境

为了配合本文其余部分的代碼清单和示例,请确保已安装 Vagrant 和 VirtualBox。接下来,您将准备一组配置脚本,以在 Ubuntu 虚拟机上配置测试环境。

准备您的配置脚本

创建一个工作目录,例如 ~/Documents/puppet-docker。将 Vagrantfile 和 docker.pp 清单放在此目录中(请参阅清单 1 和 2)。

Vagrantfile 是一个基于 Ruby 的配置文件,Vagrant 使用它来驱动一个或多个“提供程序”。Vagrant 默认支持 VirtualBox、Hyper-V 和 Docker,但它也支持许多其他提供程序,例如 VMware Fusion、DigitalOcean、Amazon AWS 等。因为目标是模拟在成熟的操作系统上管理 Docker 守护程序、镜像和容器,所以让我们关注跨平台的 VirtualBox 提供程序。

清单 1. Vagrantfile


Vagrant.configure(2) do |config|
  # Install the official Ubuntu 16.04 Vagrant guest.
  config.vm.box = 'ubuntu/xenial64'

  # Forward port 8080 on the Ubuntu guest to port
  # 8080 on the VirtualBox host. Set the host value
  # to another unused port if 8080 is already in
  # use.
  config.vm.network 'forwarded_port',
                    guest: 8080,
                    host:  8080

  # Install the puppet agent whenever Vagrant
  # provisions the guest. Note that subsequent
  # releases have renamed the agent package from
  # "puppet" to "puppet-agent".
  config.vm.provision 'shell', inline: <<-SHELL
    export DEBIAN_FRONTEND=noninteractive
    apt-get -y install puppet
  SHELL
end

请注意,此特定的 Vagrantfile(清单 1)安装了 Puppet 3.8.5,这是 Ubuntu 16.04.1 LTS 当前支持的版本。不同的版本可以作为 Puppet Enterprise 包或 Ruby gems 提供,但本文重点介绍 Ubuntu 为其当前长期支持版本提供的版本。

Docker.pp 是一个 Puppet 清单,它使用声明性语法将节点带入定义的状态。docker.pp 清单(清单 2)使用了官方支持的 Puppet Forge 模块,该模块为您处理了大量底层工作,使 Docker 守护程序、镜像和容器的安装和管理比自己滚动更容易。

在某些系统上,Puppet 清单只需一个简单的 include 'docker' 语句即可启用基本的 Docker 设置。但是,对于本文,您将覆盖特定的设置,例如您在访客操作系统上的用户名,以便将正确的用户添加到可以与 Docker 守护程序通信的组。您还将覆盖要安装的 Docker 包的名称,因为您希望使用 Ubuntu 特定的“docker.io”包,而不是 Puppet 模块默认使用的上游“docker-engine”包。

清单 2. docker.pp


# Most Vagrant boxes use 'vagrant' rather than
# 'ubuntu' as the default username, but the Xenial
# Xerus image uses the latter.
class { 'docker':
  package_name => 'docker.io',
  docker_users => ['ubuntu'],
}

# Install an Apache2 image based on Alpine Linux.
# Use port forwarding to map port 8080 on the
# Docker host to port 80 inside the container.
docker::run { 'apache2':
  image   => 'httpd:alpine',
  ports   => ['8080:80'],
  require => Class['docker'],
}

当将 docker.pp 放入与 Vagrantfile 相同的目录时,Vagrant 将使用其同步文件夹功能自动使 Puppet 清单在虚拟机内部可用。正如您很快将看到的,当配置访客操作系统时,这个看似微小的步骤可以带来自动化友好的回报。

使用 Puppet Apply 进行配置

将 Vagrantfile 和 docker.pp 存储在您的工作目录中后,您就可以启动和配置测试环境了。由于本文完全是关于自动化的,所以让我们继续编写脚本来完成这些活动。

在与 Vagrantfile 相同的目录中创建清单 3 中显示的 shell 脚本。您可以将其命名为您喜欢的任何名称,但一个明智的名称,例如 vagrant_provisioning.sh,可以清楚地表明脚本的作用。

清单 3. vagrant_provisioning.sh


#!/usr/bin/env bash

# Provision an Ubuntu guest using VirtualBox.
vagrant up --provider virtualbox

# Install the officially-supported Docker module
# from the Puppet Forge as a non-root user.
vagrant ssh -c \
    'puppet module install \
     puppetlabs-docker_platform --version 2.1.0'

# Apply our local Docker manifest using the Puppet
# agent. No Puppet Master required!
#
# Note that the modulepath puppet installs to can
# vary on different Ubuntu releases, but this one is
# valid for the image defined in our Vagrantfile.
vagrant ssh -c \
    'sudo puppet apply \
     --modulepath ~/.puppet/modules \
     /vagrant/docker.pp'

# After adding the "ubuntu" user as a member of the
# "docker" group to enable non-root communications
# with the Docker daemon, we deliberately close the
# SSH control connection to avoid unhelpful Docker
# errors such as "Cannot connect to the Docker
# daemon. Is the docker daemon running on this
# host?" on subsequent connection attempts.
vagrant ssh -- -O exit

使用 chmod 755 vagrant_provisioning.sh 使脚本可执行,然后使用 ./vagrant_provisioning.sh 运行它。这将启动和配置虚拟机,但这可能需要几分钟(以及大量的屏幕输出),然后您才能返回到命令提示符。根据您计算机的性能和互联网连接速度,您可能想在这时去给自己泡一杯咖啡。

当您带着咖啡回来时,您可能会看到 Puppet Forge 模块导致的一些弃用警告,但为了您的目的,可以安全地忽略这些警告。只要 docker.pp 清单在应用时出现警告而不是错误,您就可以验证访客操作系统和您刚刚配置的 Docker 容器的配置。

信不信由你,通过 Puppet agent 应用的 docker.pp Puppet 清单,您已经完成了!您现在有一个运行 Apache 的 Docker 容器,并提供默认的“It works!”文档。您可以使用 curl localhost:8080 在顶级主机上轻松测试它,或者在桌面浏览器中使用 https://127.0.0.1:8080/ 测试它。

使用 Puppet Agent 应用本地清单

通过使用此处显示的 puppet apply,您可以执行与在更传统的客户端/服务器 Puppet 配置中使用的相同过程,而无需执行以下操作

  1. 首先配置 Puppet Master。

  2. 管理 SSL 客户端证书。

  3. 将服务器端模块安装到正确的 Puppet 环境中。

  4. 为您要管理的节点指定 Puppet 环境。

  5. 定义将使用清单的角色、配置文件或节点。

这实际上是 Puppet 测试的关键技术之一,也是运行无主 Puppet 基础设施的基本技能。虽然对无主 Puppet 的优缺点的讨论超出了本文的范围,但重要的是要知道 Puppet 实际上并不需要 Puppet Master 才能运行。

不要被愚弄了。虽然您实际上还没有做任何用几行命令提示符无法完成的事情,但您已经以一致且可重复的方式自动化了它。一致性和可重复性是自动化的基石,一旦您使用角色和配置文件扩展该过程,就真的可以创造奇迹。

使用 Puppet 角色和配置文件控制 Docker

自动化单台机器的配置似乎需要做很多工作。但是,即使只处理一台机器,托管配置的一致性和可重复性也是一个很大的优势。此外,这项工作为自动化无限数量的机器奠定了基础,这对于将配置管理扩展到数百或数千台服务器至关重要。Puppet 通过“角色和配置文件”工作流程使这成为可能。

在 Puppet 世界中,角色和配置文件只是 Puppet 清单的特殊情况。这是一种通过组合来表达所需配置的方式,其中配置文件由组件模块组成,然后一个或多个配置文件构成一个角色。然后,角色被动态或静态地分配给节点,通常通过 site.pp 文件或外部节点分类器 (ENC)。

让我们逐步了解角色和配置文件工作流程的简化示例。首先,您将在与 Vagrantfile 相同的目录中创建一个名为 roles_and_profiles.pp 的新清单。清单 4 显示了一个有用的示例。

清单 4. roles_and_profiles.pp


####################################################
# Profiles
####################################################
# The "dockerd" profile uses a forge module to
# install and manage the Docker daemon. The only
# difference between this and the "docker" class
# from the earlier docker.pp example is that we're
# wrapping it inside a profile.
class profile::dockerd {
    class { 'docker':
      package_name => 'docker.io',
      docker_users => ['ubuntu'],
    }
}

# The "alpine33" profile manages the presence or
# absence of the Alpine 3.3 Docker image using a
# parameterized class. By default, it will remove
# the image.
class profile::alpine33 ($status = 'absent') {
    docker::image { 'alpine_33':
        image     => 'alpine',
        image_tag => '3.3',
        ensure    => $status,
    }
}


# The "alpine34" profile manages the presence or
# absence of the Alpine 3.4 Docker image. By
# default, it will remove the image.
class profile::alpine34 ($status = 'absent') {
    docker::image { 'alpine_34':
        image     => 'alpine',
        image_tag => '3.4',
        ensure    => $status,
    }
}

####################################################
# Roles
####################################################
# This role combines two profiles, passing
# parameters to add or remove the specified images.
# This particular profile ensures the Alpine 3.3
# image is installed, and removes Alpine 3.4 if
# present.
class role::alpine33 {
    class { 'profile::alpine33':
        status => 'present',
    }

    class { 'profile::alpine34':
        status => 'absent',
    }
}

# This role is the inverse of role::alpine33. It
# calls the same parameterized profiles, but
# installs Alpine 3.4 and removes Alpine 3.3.
class role::alpine34 {
    class { 'profile::alpine33':
        status => 'absent',
    }

    class { 'profile::alpine34':
        status => 'present',
    }
}

####################################################
# Nodes
####################################################
# Apply role::alpine33 to any host with "alpine33"
# in its hostname.
node /alpine33/ {
    include ::role::alpine33
}

# Apply role::alpine34 to any host with "alpine34"
# in its hostname.
node /alpine34/ {
    include ::role::alpine34
}

请注意,所有配置文件、角色和节点都放在一个 Puppet 清单中。在生产系统上,这些都应该是单独的清单,位于 Puppet Master 上的适当位置。虽然此示例具有说明性,并且对于使用无主 Puppet 非常有用,但请注意,为了方便起见,这里违反了一些规则。

让我简要讨论清单的每个部分。配置文件是组织良好的 Puppet 环境的可重用构建块。每个配置文件应该只有一个职责,尽管您可以允许配置文件接受可选参数,使其更灵活。在本例中,Alpine 配置文件允许您根据您作为参数传入的 $status 变量的值来添加或删除给定的 Docker 镜像。

角色是您分配给节点的“存在理由”。一个节点可以同时拥有多个角色,但每个角色都应该描述一个单一的目的,无论实现该目的需要多少个组件部分。在实际应用中,分配给节点的一些常见角色可能包括

  • role::ruby_on_rails

  • role::jenkins_ci

  • role::monitored_host

  • role::bastion_host

每个角色都由一个或多个配置文件组成,这些配置文件共同描述了节点的整体目的或功能。对于此示例,您将 alpine34 角色定义为存在带有 Alpine 3.4 的 Docker 守护程序不存在 Alpine 3.3 镜像,但您也可以轻松地描述由 NTP、SSH、Ruby on Rails、Java 和 Splunk forwarder 的配置文件组成的更复杂的角色。

这种关注点分离是从面向对象编程中借用来的,您尝试通过组合来定义节点,以便将实现细节与用户可见的行为隔离。一种不太程序化的思考方式是,配置文件通常描述节点的特性,例如其包、文件或服务,而角色描述节点在数据中心内的功能

节点通常在 Puppet Master 的 site.pp 文件或外部节点分类器中定义,角色在其中静态或动态地分配给每个节点。这就是 Puppet 真正扩展能力变得显而易见的地方。在本例中,您定义了两种不同类型的节点。每个节点定义都使用一个字符串或正则表达式,该字符串或正则表达式与主机名(或客户端/服务器配置中的 certname)匹配,以确定应将哪些角色应用于该节点。

在示例清单的节点部分中,您告诉 Puppet 将 role::alpine33 分配给任何主机名中包含“alpine33”的节点。同样,主机名中包含“alpine34”的任何节点都会获得 role::alpine34。以这种方式使用模式匹配意味着您的数据中心中可以有任意数量的主机,并且每个主机都将根据已分配的主机名选择正确的配置。例如,假设您有五个主机,名称如下

  1. foo-alpine33

  2. bar-alpine33

  3. baz-alpine33

  4. abc-alpine34

  5. xyz-alpine34

然后,前三个将在它们联系 Puppet Master 时选择 Alpine 3.3 角色,而后两个将选择 Alpine 3.4 角色。这几乎神奇般的简单。让我们看看这种类型的动态角色分配在实践中是如何工作的。

动态角色分配

假设您已将 roles_and_profiles.pp 放入包含 Vagrantfile 的目录中,您就可以访问 Ubuntu 虚拟机中的清单。让我们登录到虚拟机并进行测试(清单 5)。

清单 5. 登录到 Ubuntu 虚拟机


# Ensure we're in the right directory on our Vagrant
# host.
cd ~/Documents/puppet-docker

# Ensure that the virtual machine is active. There's
# no harm in running this command multiple times,
# even if the machine is already up.
vagrant up

# Login to the Ubuntu guest.
vagrant ssh

接下来,运行 roles_and_profiles.pp Puppet 清单,看看会发生什么。提示:它将失败,然后您将探索为什么这是一件好事。这是发生的事情


ubuntu@ubuntu-xenial:~$ sudo puppet apply --modulepath
 ↪~/.puppet/modules /vagrant/roles_and_profiles.pp
Error: Could not find default node or by name with
 ↪'ubuntu-xenial.localdomain, ubuntu-xenial' on node
 ↪ubuntu-xenial.localdomain
Error: Could not find default node or by name with
↪'ubuntu-xenial.localdomain, ubuntu-xenial' on node
 ↪ubuntu-xenial.localdomain

为什么清单未能应用?实际上有几个原因。第一个原因是您没有定义任何与当前主机名“ubuntu-xenial”匹配的节点。第二个原因是您没有定义在找不到其他匹配项时要应用的默认值。Puppet 允许您定义默认值,但在许多情况下,引发错误比获得您不期望的配置更好。

在此测试环境中,您希望展示 Puppet 能够根据运行 Puppet agent 的节点的主机名动态分配角色。考虑到这一点,让我们修改 Ubuntu 访客的主机名,以了解如何使用站点清单仅根据每台机器的主机名来配置大型机器集群。

更改 Linux 主机名

在 Linux 系统上更改主机名时,重要的是要了解如果许多信息来源在当前主机名上意见不一致,sudo 实用程序会大声且频繁地抱怨。特别是,在 Ubuntu 系统上,以下内容应全部一致

  1. 存储在 /etc/hostname 中的主机名。

  2. 为 /etc/hosts 中的 127.0.1.1 定义的主机名。

  3. /bin/hostname 报告的主机名。

如果它们不完全匹配,您可能会看到如下错误


> sudo: unable to resolve host quux

在极端情况下,您甚至可能会失去运行 sudo 命令的能力。最好通过确保在更改主机名时将所有三个数据源更新为相同的值来避免这种情况。

为了避免 sudo 命令出现错误,您实际上需要在多个位置更改虚拟机的主机名。此外,PS1 提示符报告的主机名在您启动新 shell 之前不会更新。在 Ubuntu 访客内部运行时,以下命令将进行必要的更改


# Must be exported to use in sudo's environment.
export new_hostname="foo-alpine33"

# Preserve the environment or sudo will lose the
# exported variable. Also, we must explicitly
# execute on localhost rather than relying on
# whatever sudo thinks the current hostname is to
# avoid "sudo: unable to resolve host" errors.
sudo \
    --preserve-env \
    --host=localhost \
    -- \
    sed --in-place \
        "s/${HOSTNAME}/${new_hostname}/g" \
        /etc/hostname /etc/hosts
sudo \
    --preserve-env \
    --host=localhost \
    -- \
    hostname "$new_hostname"

# Replace the current shell in order to pick up the
# new hostname in the PS1 prompt.
exec "$SHELL"

您的提示符现在应显示主机名已更改。当您重新运行 Puppet 清单时,它将与节点列表匹配,因为您已为主机名中包含“alpine33”的主机定义了规则。Puppet 然后将为您应用 role::alpine33,仅仅因为主机名与节点定义匹配!例如


# Apply the manifest from inside the Ubuntu guest.
sudo puppet apply \
    --modulepath ~/.puppet/modules \
    /vagrant/roles_and_profiles.pp

# Verify that the role has been correctly applied.
docker images alpine

REPOSITORY   TAG       IMAGE ID        CREATED         SIZE
alpine       3.3       6c2aa2137d97    7 weeks ago     4.805MB

忽略“update_docker_image.sh”错误

在示例中运行 Puppet 清单时,您可能会看到几个包含以下子字符串的错误


> update_docker_image.sh alpine:3.4 returned 3 instead of one of [0,1]

这些错误目前是由示例中使用的 Puppet Docker 模块中的上游错误引起的。错误已向上游提交,但为了本文的直接目的,可以安全地忽略这些错误。尽管报告了错误,但 Docker 镜像实际上仍在正确安装,您可以使用 docker images alpine 在虚拟机内部自行验证。

如果您想跟踪这些错误的进度,请参阅

要将此角色应用于整个机器集群,您只需确保它们的主机名与您定义的条件匹配即可。例如,假设您有五个主机,名称如下

  1. foo-alpine33

  2. bar-alpine33

  3. baz-alpine33

  4. abc-alpine33

  5. xyz-alpine33

然后,/alpine33/ 的单个节点定义将应用于所有这些主机,因为正则表达式与它们每个主机名都匹配。通过将角色分配给主机名的模式,您只需设置正确的主机名即可配置数据中心的大部分!还有什么比这更容易的呢?

在运行时重新分配角色

好吧,现在您有一种一次为数千个盒子分配角色的方法。这本身就很令人印象深刻,但魔法并没有就此止步。如果您需要将系统重新分配给不同的角色怎么办?

假设您有一个安装了 Alpine 3.3 镜像的盒子,并且您想升级该盒子,使其托管 Alpine 3.4 镜像。实际上,托管多个镜像不是问题,并且这些镜像不是互斥的。但是,它可以说明如何使用 Puppet 添加、删除、更新和替换镜像和容器。

鉴于现有的节点定义,您只需更新主机名以包含“alpine34”,并让 Puppet 选择新角色


# Define a new hostname that includes "alpine34"
# instead of "alpine33".
export new_hostname="foo-alpine34"

sudo \
    --preserve-env \
    --host=localhost \
    -- \
    sed --in-place \
        "s/${HOSTNAME}/${new_hostname}/g" \
        /etc/hostname /etc/hosts
sudo \
    --preserve-env \
    --host=localhost \
    -- \
    hostname "$new_hostname"
exec "$SHELL"

# Rerun the manifest using the new node name.
sudo puppet apply \
    --modulepath ~/.puppet/modules \
    /vagrant/roles_and_profiles.pp

# Show the Alpine images installed.
docker images alpine

REPOSITORY   TAG       IMAGE ID        CREATED         SIZE
alpine       3.4       baa5d63471ea    7 weeks ago     4.803MB

从输出中可以看出,Puppet 已经删除了 Alpine 3.3 镜像,并安装了 Alpine 3.4 镜像!这是怎么发生的?让我们将其分解为步骤

  1. 您重命名了主机,使其主机名中包含子字符串“alpine34”。

  2. Puppet 在其节点定义列表中使用正则表达式匹配了子字符串。

  3. Puppet 应用了分配给与“alpine34”子字符串匹配的节点的 Alpine 3.4 角色 (role::alpine34)。

  4. Alpine 3.4 角色使用“present”和“absent”参数调用其组件配置文件(实际上是参数化类),以声明每个镜像的预期状态。

  5. Puppet 应用了 Alpine 3.3 和 Alpine 3.4 配置文件(分别为 profile::alpine33profile::alpine34)内部的镜像管理声明,以安装或删除每个镜像。

虽然基于主机名的角色分配只是管理多个系统配置的众多方法之一,但它是一种非常强大的方法,并且肯定是演示起来最简单的方法之一。Puppet 支持大量方法来指定应将哪些配置应用于给定的主机。基于可发现的标准动态配置系统的能力使 Puppet 成为 Docker 版本化镜像和容器化的绝佳补充。

用于节点分配的其他 Puppet 选项

Puppet 可以通过多种方式将角色、配置文件和类分配给节点,包括以下方式

  • 使用 Puppet Enterprise 控制台对节点进行分类。

  • 在主站点清单(例如 site.pp)中定义节点。

  • 实施外部节点分类器 (ENC),它是一个外部工具,用于替换或补充主站点清单。

  • 将分层数据存储在 Hiera YAML 配置文件中。

  • 使用 Puppet Lookup,它将 Hiera 信息与环境和模块数据合并。

  • 根据服务器或客户端在运行时已知的事实制作条件配置。

每个选项都代表了表达能力、分层继承和可维护性方面的一系列权衡。对这些权衡进行全面讨论超出了本文的范围。尽管如此,重要的是要理解 Puppet 在您如何大规模分类和管理节点方面为您提供了极大的灵活性。本文重点介绍基于名称的分类的常见用例,但当然还有其他有效的方法。

结论

在本文中,我仔细研究了如何使用 docker::imagedocker::run 管理 Docker 镜像和容器,但 Puppet Docker 模块支持更多功能,我这次没有空间介绍。其中一些附加功能包括

  • 使用 docker::image 类从 Dockerfile 构建镜像。

  • 使用 docker::networks 类管理 Docker 网络。

  • 使用 docker::compose 类使用 Docker Compose。

  • 使用 docker::registry 类实施私有镜像注册表。

  • 使用 docker::exec 类在容器内部运行任意命令。

总而言之,这一强大的功能集合使您可以组合极其强大的角色和配置文件,以管理几乎任何规模的基础设施中的 Docker 实例。此外,通过利用 Puppet 的声明性语法及其自动化角色分配的能力,可以在多个主机上添加、删除和修改 Docker 实例,而无需直接管理每个实例,这通常是企业自动化方面的巨大胜利。最后,与手动调整、手工制作的节点(随着时间的推移可能会“偏离”理想状态)相比,Puppet 驱动的容器管理的标准化和可重复性使系统更加可靠。

简而言之,Docker 提供了一个强大的工具来创建轻量级的黄金镜像和容器化服务,而 Puppet 提供了在云或数据中心编排这些镜像和容器的手段。就像草莓和巧克力一样,两者都不比另一个“更好”;但将它们结合起来,您会得到比其各部分总和更大的东西。

资源

本文中的关键文件,可在 GitHub 上获取: https://github.com/CodeGnome/MDIWP-Examples

Docker: https://www.docker.co

Puppet 主页(文档和商业版本): https://puppet.com

Puppet Ruby Gem(开源版本): https://rubygems.org.cn/gems/puppet

Puppet Labs docker_platform 模块: https://forge.puppet.com/puppetlabs/docker_platform

docker_platform 封装的 garethr-docker 模块: https://github.com/garethr/garethr-docker

官方 Apache HTTP Server Docker 镜像: https://hub.docker.com/_/http

Oracle VirtualBox: https://www.virtualbox.org

HashiCorp 的 Vagrant: https://www.vagrantup.com

HashiCorp Atlas 上的 Ubuntu 镜像: https://atlas.hashicorp.com/ubuntu

关于“角色和配置文件”模式的 Puppet 文档: https://docs.puppet.com/pe/2016.4/r_n_p_intro.html

Todd A. Jacobs 是 Flow Capital Group 的首席执行官,该公司收购和管理专门从事 IT 自动化、DevOps 和敏捷转型、安全与合规性、Fractional CIO/CTO 服务以及网络风险和其他热门技术问题的董事会咨询服务的公司。Todd 一生都在等待 Matt Smith 在《神秘博士》中扮演的角色再次让领结变得酷炫。他和他的妻子和儿子住在马里兰州巴尔的摩附近,他希望将自己对 Linux 和技术的热爱传递给他们——但也许不会传递他的时尚感。

加载 Disqus 评论