如何在Ubuntu16.04上使用Packer创建DigitalOcean快照

来自菜鸟教程
跳转至:导航、​搜索

介绍

Hashicorp 的 Packer 是一个命令行工具,用于为多个平台和环境快速创建相同的机器映像。 使用 Packer,您可以使用称为 模板 的配置文件来创建包含预配置操作系统和软件的机器映像。 然后,您可以使用此映像来创建新机器。 您甚至可以使用单个模板来协调同时创建生产、登台和开发环境。

在本教程中,您将使用 Packer 在 Ubuntu 16.04 上配置 Nginx Web 服务器。 然后,您将使用 Packer 创建此 Droplet 的快照,并使其立即在您的 DigitalOcean 仪表板中可用,以便您可以使用它来创建新的 Droplet。

先决条件

在启动并运行 Packer 之前,您需要做一些事情。

第 1 步 — 下载并安装 Packer

登录到您的服务器后,您将下载 Packer 二进制包,为当前用户安装 Packer,并检查您的安装是否成功。

让 Packer 在您的系统上运行的最简单方法是从 Hashicorp 官方版本 网站 下载最新的二进制包。 在撰写本文时,最新版本是 0.12.2。

使用 curl 实用程序从 Hashicorp 网站下载二进制包。

curl -O https://releases.hashicorp.com/packer/0.12.2/packer_0.12.2_linux_amd64.zip

下载后,安装 unzip 实用程序并使用它将包内容解压缩到 /usr/local/bin 目录以使 Packer 可供所有用户使用:

sudo apt install -y unzip
sudo unzip -d /usr/local/bin packer_0.12.2_linux_amd64.zip

通过检查 packer 在命令行上是否可用来验证安装是否成功:

packer

安装成功会输出以下信息:

Outputusage: packer [--version] [--help] <command> [<args>]

Available commands are:
    build       build image(s) from template
    fix         fixes templates from old versions of packer
    inspect     see components of a template
    push        push a template and supporting files to a Packer build service
    validate    check that a template is valid
    version     Prints the Packer version

Packer 现在已安装并在您的机器上运行。 在下一步中,您将设置项目目录并配置模板以生成基本的 Ubuntu 快照。

第 2 步 — 配置 DigitalOcean Builder

我们希望 Packer 创建一个 Droplet,安装一些软件和配置文件,然后将该 Droplet 转换为我们可以用来创建新机器的映像。 Packer 使用一个名为 template 的配置文件,其中包含告诉 Packer 如何构建映像的所有详细信息。 我们使用 JSON 编写此配置,这是配置文件的常用格式。

在 Packer 中,builder 是一个 JSON 对象,其中包含您希望 Packer 创建的图像的蓝图。 使用 digitalocean 构建器,您将指示 Packer 创建一个 512 MB 的 Ubuntu 16.04 Droplet,它将在 NYC1 区域启动。

创建并更改到一个新目录,该目录将保存我们将在本教程中创建的模板和配置文件:

mkdir ~/packerProject
cd ~/packerProject

现在您有了一个项目目录,在您的文本编辑器中打开一个名为 template.json 的新文件:

nano ~/packerProject/template.json

每个构建器都需要进入 template.jsonbuilders 部分。 现在添加此部分并通过将此代码放入文件中来包含 digitalocean 构建器:

~/packerProject/template.json

{
  "builders": [
    {
      "type": "digitalocean"
    }]
}

type 键定义了 Packer 使用哪个构建器来创建您的图像。 digitalocean 构建器创建 DigitalOcean Droplets,Packer 从中创建快照。

Packer 现在知道您要为 DigitalOcean 创建一个映像,但它仍然需要更多的键值对才能完成构建。

通过添加这些键和值以从在 NYC1 区域中启动的 512 MB Ubuntu 16.04 Droplet 生成快照,完成对 Droplet 的配置。 修改您的文件,使其看起来像这样:

~/packerProject/template.json

{
  "builders": [
    {
      "type": "digitalocean",
      "ssh_username": "root",
      "api_token": "YOUR_DIGITALOCEAN_API_TOKEN",
      "image": "ubuntu-16-04-x64",
      "region": "nyc1",
      "size": "512mb"
    }]
}

Packer 使用 ssh_username 值连接到 Droplets。 需要将此值设置为“root”,以便 Packer 正常工作。

保存 template.json 并退出文本编辑器。

前面的代码块包含创建 DigitalOcean Droplet 所需的最少配置量,但还有其他可用的配置选项,如下表所示:

钥匙 价值 必需的 描述
api_token 细绳 是的 用于访问您的帐户的 API 令牌。 它也可以通过环境变量 DIGITALOCEAN_API_TOKEN 来指定,如果设置的话。
image 细绳 是的 要使用的基本映像的名称(或 slug)。 这是将用于启动新 Droplet 并对其进行配置的图像。 请参阅 https://developers.digitalocean.com/documentation/v2/#list-all-images 以获取有关如何获取已接受图像名称/slug 列表的详细信息。
region 细绳 是的 要在其中启动 Droplet 的区域的名称(或 slug)。 因此,这是快照可用的区域。 请参阅 https://developers.digitalocean.com/documentation/v2/#list-all-regions 了解接受的区域名称/slugs。
size 细绳 是的 要使用的 Droplet 大小的名称(或 slug)。 请参阅 https://developers.digitalocean.com/documentation/v2/#list-all-sizes 以了解接受的尺寸名称/slugs。
api_url 细绳 非标准 API 端点的 URL。 如果您使用的是与 DigitalOcean API 兼容的服务,请设置此项。
droplet_name 细绳 分配给 Droplet 的名称。 DigitalOcean 将机器的主机名设置为此值。
private_networking 布尔值 设置为 true 为正在创建的 Droplet 启用专用网络。 这默认为 false,或未启用。
snapshot_name 细绳 将出现在您的帐户中的生成快照的名称。 这必须是唯一的。
state_timeout 细绳 在超时之前等待的时间,作为持续时间字符串,Droplet 进入所需状态(例如“活动”)。 默认状态超时为“6m”。
user_data 细绳 使用 Droplet 启动的用户数据。 有关详细信息,请参阅 Droplet 元数据简介

您现在有一个有效的模板,但您的 API 令牌在您的模板中是硬编码的。 这是一种不好的做法,并且存在潜在的安全风险。 在下一步中,您将为该令牌创建一个变量并将其移出 template.json

第三步——创建和存储用户变量

Packer 允许您在单独的文件中创建和存储变量的值。 然后,当您准备好构建映像时,可以通过命令行将该文件传递给 Packer。

将变量存储在单独的文件中是将敏感信息或环境特定数据保留在模板之外的理想方式。 如果您打算与团队成员共享它或将其存储在面向公众的存储库(如 GitHub)中,这一点至关重要。

即使您只保存本地副本,在模板之外存储变量也是 Packer 的最佳做法。

packerProject 目录中创建并打开一个新的 JSON 文件来存储此信息:

nano ~/packerProject/variables.json

现在,添加一个 my_token 变量并将其值设置为您的 DigitalOcean API 令牌:

~/packerProject/variables.json

{
  "my_token": "YOUR_DIGITALOCEAN_API_TOKEN"
}

保存 variables.json 并退出编辑器。

现在让我们配置我们的模板以使用变量。 在使用 my_token 变量或任何其他变量之前,首先需要通过在 template.json 文件开头的 variables 部分中定义变量来告诉 Packer 该变量存在.

在编辑器中打开 template.json

nano template.json

在您之前定义的 builders 部分上方添加一个新的 variables 部分。 在这个新部分中,声明 my_token 变量并将其默认值设置为空字符串:

~/packerProject/template.json

{
  "variables": {
    "my_token":""
  },
  "builders": [
  ...

}

variables 部分中定义的变量全局可用。

接下来,将 builders 部分中的 API 令牌替换为对 my_token 的调用:

~/packerProject/template.json

{
  ...
  "builders": [
    {
      "type": "digitalocean",
      "api_token": "{{ user `my_token` }}",
      ...
    }]
}

如您所见,对用户变量的调用必须使用特定格式:"模板:User `variable name`。 引号和反引号是必需的,双花括号也是如此。

保存文件并退出编辑器。

您现在有了一个工作模板,该模板生成一个基本快照和一个单独的变量文件来存储您的 API 密钥。 在验证和构建映像之前,让我们在模板中添加一个 provisioners 部分,它将配置 Packer 在创建映像之前在机器上安装和设置 Nginx Web 服务器。

第 4 步 — 配置供应商

provisioners 部分是 Packer 在将其转换为机器映像之前在运行的 Droplet 上安装和配置软件的地方。 与构建器一样,您可以使用不同类型的配置器来配置 Droplet。

为了配置 Nginx,您将使用 Packer 的 file 配置器将配置文件上传到服务器,然后使用 shell 配置器执行使用这些文件的安装脚本。 file 配置器允许您在将文件和目录转换为映像之前将文件和目录移入和移出正在运行的机器。 使用 shell 配置器,您可以在该机器上远程执行 shell 脚本。

Provisioner 的执行顺序与它们在模板中出现的顺序相同。 这意味着将 file 配置器放在首位,因为您的 shell 脚本需要上传的文件。

template.json 中的 builders 部分之后立即添加一个 provisioners 部分,并设置您将使用的两个配置器:

~/packerProject/template.json

{
  ...
  "builders": [
    {
      ...
  }],
  "provisioners": [
    {
      "type": "file"
    },
    {
      "type": "shell"
    }]
}

file 配置器需要一个 source,它指向本地文件路径,以及一个 destination,它指向正在运行的机器上的现有文件路径。 Packer 只能将文件移动到已经存在的目的地。 为此,我们一般将文件上传到/tmp目录。

通过将突出显示的行添加到 template.json 来配置 file 供应商:

~/packerProject/template.json

{
  ...
  "provisioners": [
    {
      "type": "file",
      "source": "configs/",
      "destination": "/tmp"
    },
    ...
}

下一步,我们将在本地计算机上创建 configs 文件夹。 在我们开始之前,让我们通过设置 shell 配置器来完成对配置文件的编辑。

shell 配置器采用 scripts 键,其中包含应传递给运行机器的脚本数组。 每个脚本都按照模板中指定的顺序上传和执行。

现在,通过提供脚本的完整路径来配置 shell 配置器:

~/packerProject/template.json

{
  ...
  "provisioners": [
    {
      "type": "file",
      "source": "configs/",
      "destination": "/tmp"
    },
    {
      "type": "shell",
      "scripts": [
        "scripts/configureNginx.sh"
      ]
    }]
}

脚本必须单独列出,这样您就可以控制脚本的执行顺序。

模板的 provisioners 部分已完成。 如果您使用的是 nano,请按住 ctrl 键并按 x 退出文件,并在提示保存更改时按 y

现在让我们创建 Packer 将用来创建映像的 shell 脚本和配置文件。

第 5 步 — 添加配置文件和安装脚本

我们希望我们的镜像附带一个完全配置的 Nginx 安装、正确的配置文件和一个默认网页。 在本节中,您将根据教程 How To Set Up Nginx Server Blocks (Virtual Hosts) on Ubuntu 16.04 从一些预定义的配置创建这些文件,因为 Nginx 配置超出了本教程的范围。

我们将通过创建和上传由单个安装脚本处理的三个单独的配置文件来为服务器提供 Nginx。

首先,在项目文件夹中创建一个新目录来存储配置文件。

mkdir ~/packerProject/configs

更改为 /configs 以创建您的 Nginx 配置文件:

cd ~/packerProject/configs

首先,您需要一个默认网页来从您的新域提供服务。 创建文件 index.html.new

nano index.html.new

在这个新文件中,插入以下内容:

~/packerProject/configs/index.html.new

HELLO FROM YOUR TEST PAGE

接下来,您需要一个 Nginx 配置文件,该文件为您的域定义服务器块,进而定义该域的侦听端口和网页的位置。 创建一个名为 newDomain.conf 的文件:

nano newDomain.conf

在此文件中放置以下配置:

~/packerProject/configs/newDomain.conf

server {
        listen 80;
        listen [::]:80;

        server_name example.com;

        location / {
                root /var/www/html/newDomain;
                index index.html index.htm;
        }
}

在此示例中,我们使用 example.com 作为占位符值。 当您从映像创建新机器时,您必须登录到新机器并更改此文件以反映指向该机器的实际域或 IP 地址。


最后,您希望 Nginx 从新目录 /etc/nginx/vhost.d/ 加载您的域的配置。 这意味着编辑主要的 Nginx 配置文件。

创建 nginx.conf.new

nano nginx.conf.new

我们将使用默认的 Nginx 配置文件,但我们将对其进行修改以包含我们的特定站点配置并确保 Nginx 以 www-data 用户身份运行。 将以下内容放入该文件中:

~/packerProject/configs/nginx.conf.new

user www-data;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/vhost.d/*.conf;

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

        include /etc/nginx/default.d/*.conf;

        location / {
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }

}

保存并退出文件。

配置文件到位后,让我们定义 Packer 将用来安装我们需要的软件的脚本。 创建一个新文件夹来存储您的脚本:

mkdir ~/packerProject/scripts

现在切换到这个新目录并创建安装脚本 configureNginx.sh,它会安装、配置、启用和启动 Nginx Web 服务器:

cd ~/packerProject/scripts
nano configureNginx.sh

将以下内容粘贴到文件中,该文件使用您刚刚创建的配置文件安装、配置和启动 Nginx:

~/packerProject/scripts/configureNginx.sh

#!/bin/bash
# Script to install Nginx and enable on boot.

# Update your system:
apt-get update -y
apt-get upgrade -y

# Install Nginx:
apt-get install -y nginx

#Start Nginx service and enable to start on boot:
systemctl enable nginx
systemctl start nginx

# Create new 'vhost' directory for domain configuration:
mkdir /etc/nginx/vhost.d

# Create a new directory to serve new content.
mkdir -p /var/www/html/newDomain

# Create a copy of original configuration files and import configuration:
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.original
cp /tmp/nginx.conf.new /etc/nginx/nginx.conf

# Copy over the server block configuration:
cp /tmp/newDomain.conf /etc/nginx/vhost.d/newDomain.conf

# Copy over the html test page:
cp /tmp/index.html.new /var/www/html/newDomain/index.html

# Restart Nginx:
systemctl restart nginx

您的模板已完成,您现在可以验证和构建您的快照。

第 6 步 - 验证和构建 Droplet

是时候使用 Packer 的 validate 子命令测试您的模板了。 一旦您的模板成功验证,您将构建您的 Droplet 并创建快照。

更改到项目的根目录:

cd ~/packerProject

validate 子命令将检查您的模板是否有有效的语法和配置选项:

packer validate -var-file=variables.json template.json

-var-file 标志读取 variables.json 并在 template.json 内设置 my_token 的值。

您将看到以下输出:

OutputTemplate validated successfully.

如果 template.json 有问题,您将收到一条错误消息。 此消息将根据错误而有所不同,但大多数可以通过仔细检查语法和更正任何拼写错误来修复。

build 子命令运行您在模板的 builders 部分中定义的构建。 换句话说,它告诉 Packer 构建您的 Droplet,然后在您的 DigitalOcean 仪表板中创建该 Droplet 的快照。

调用 packer build 构建 Droplet 并创建快照:

packer build -var-file=variables.json template.json

请注意,-var-file 标志对 buildvalidate 子命令的操作方式完全相同。

成功构建的输出将类似于以下内容:

Outputdigitalocean output will be in this color.

==> digitalocean: Creating temporary ssh key for Droplet...
==> digitalocean: Creating Droplet...
==> digitalocean: Waiting for Droplet to become active...
==> digitalocean: Waiting for SSH to become available...
==> digitalocean: Connected to SSH!
==> digitalocean: Gracefully shutting down Droplet...
==> digitalocean: Creating snapshot: packer-1488487459
==> digitalocean: Waiting for snapshot to complete...
==> digitalocean: Destroying Droplet...
==> digitalocean: Deleting temporary ssh key...
Build 'digitalocean' finished.

==> Builds finished. The artifacts of successful builds are:
--> digitalocean: A snapshot was created: 'packer-1488487459' (ID: 18252043) in region 'nyc1'

成功构建后,您将在 DigitalOcean 快照存储库中找到一个新快照。 您可以在输出中找到快照的名称。 在此示例中,它是 packer-1488487459

从这里访问您的 DigitalOcean 仪表板,选择 Images,新的快照将出现在您的列表中:

您现在可以使用这个新快照来创建新的 Droplet。 选择More,然后选择创建Droplet。 然后填写表格以创建您的新机器。

机器在线后,从仪表板确定其 IP 地址并登录到新机器:

ssh root@your_new_server_ip_address

然后编辑 Nginx 服务器配置文件:

nano /etc/nginx/vhost.d/newDomain.conf

并将 example.com 替换为机器的 IP 地址或您将使用的域名:

~/packerProject/configs/newDomain.conf

server {
        listen 80;
        listen [::]:80;

        server_name your_new_server_ip_address;

        location / {
                root /var/www/html/newDomain;
                index index.html index.htm;
        }
}

或者,您可以使用 sed 命令替换文件中的值,如下所示:

sudo sed -i 's/^.*server_name example.com/server_name your_new_server_ip_address/' /etc/nginx/vhost.d/newDomain.conf

您可以在本教程中了解有关sed的更多信息。

然后重新启动 Nginx 服务器以应用更改:

sudo systemctl restart nginx

故障排除

有时,您可能会遇到错误消息未充分解释的问题。 在这些情况下,您可以通过启用调试模式、检查 Packer 日志或两者兼而有之来提取有关构建的更多详细信息。

调试模式为远程构建中的每个步骤提供特定于构建器的调试信息。 为 DigitalOcean 构建启用调试模式还将在您的项目文件夹中生成一个临时私钥,您可以使用它来连接和检查正在运行的 Droplet,然后再将其转换为快照。

您可以通过在命令行上将 -debug 标志传递给 packer build 来进入调试模式:

packer build -debug --var-file=variables.json template.json

如果您无法在调试模式下诊断问题,您可以尝试启用 Packer 日志。 这些日志主要用于调试本地构建器,但它们也可能提供有关远程构建的有用信息。

要启用 Packer 日志,请将 PACKER_LOG 环境变量设置为除“0”或空字符串之外的任何值:

PACKER_LOG=1 packer build --var-file=variables.json template.json

除非您还设置了 PACKER_LOG_PATH 环境变量,否则日志将打印到控制台。

如果您仍然遇到问题,您可能想尝试与 Packer 社区 中的某个人联系。

结论

现在您已经熟悉了 Packer 的基础知识,您可能有兴趣在此基础上进行构建。

尝试将第二个构建器添加到您的模板中,以在您的 DigitalOcean 快照旁边创建一个本地测试环境。 例如,virtualbox-iso 构建器为 VirtualBox 生成图像,这是一种免费的开源虚拟化产品,可供企业和爱好者使用。 您可以为 VirtualBox 映像定义 post-processor 并创建镜像您的 DigitalOcean 快照的 Vagrant 环境。 这将允许您在将网站更改推送到实时 Droplet 之前在本地测试网站更改。 您可以在 Vagrant 后处理器文档 中了解更多信息。

或者您可能希望将您的 Web 服务器连接到数据库。 添加第二个 digitalocean 构建器并使用 provisioners 部分中的 only 键为每个构建应用不同的配置。

如果您更习惯使用配置管理工具,Packer 提供对 AnsiblePuppetChef 等的开箱即用支持。 尝试使用这些配置器之一来进一步配置您的 Droplet 以匹配您的用例。 如果您以前从未尝试过配置管理,请查看 如何创建 Ansible Playbooks 以在 Ubuntu 上自动化系统配置。