CentOS 7でPackerを使用してDigitalOceanスナップショットを作成する方法

前書き

HashicorpによるPackerは、複数のプラットフォームおよび環境用に同一のマシンイメージをすばやく作成するためのコマンドラインツールです。 Packerでは、templateと呼ばれる構成ファイルを使用して、事前構成されたオペレーティングシステムとソフトウェアを含むマシンイメージを作成します。 その後、このイメージを使用して新しいマシンを作成できます。 単一のテンプレートを使用して、実稼働環境、ステージング環境、および開発環境を同時に作成することもできます。

このチュートリアルでは、Packerを使用してCentOS 7でNginx Webサーバーを構成します。 次に、Packerを使用してこのDropletのスナップショットを作成し、DigitalOceanダッシュボードですぐに使用できるようにして、新しいDropletを作成できるようにします。

前提条件

Packerを起動して実行する前に、いくつかのものが必要です。

[[step-1 -—- downloading-and-installing-packer]] ==ステップ1—Packerのダウンロードとインストール

サーバーにログインした後、Packerバイナリパッケージをダウンロードし、現在のユーザー用にPackerをインストールし、インストールが成功したことを確認します。

システムでPackerを実行する最も簡単な方法は、Hashicorpの公式リリースwebsiteから最新のバイナリパッケージをダウンロードすることです。 執筆時点で、最新バージョンは0.12.2です。

curlユーティリティを使用して、HashicorpWebサイトからバイナリパッケージをダウンロードします。

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

ダウンロードしたら、unzipユーティリティをインストールし、それを使用してパッケージの内容を/usr/localディレクトリに解凍します。これは、すべてのユーザーがPackerを使用できるようにするための推奨される場所です。

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

CentOSにはすでにpackerというプログラムが含まれており、コマンドを実行するたびにフルパスを入力するだけで済みますが、この問題を回避するためのより効率的な方法は、packer.ioをマップするシンボリックリンクを作成することです。 /usr/local/packerに。 次のコマンドを使用して、/usr/local/binフォルダーにシンボリックリンクを作成します。

sudo ln -s /usr/local/packer /usr/local/bin/packer.io

コマンドラインでpacker.ioが使用可能であることを確認して、インストールが成功したことを確認します。

packer.io

インストールが成功すると、次の結果が出力されます。

Outputusage: packer [--version] [--help]  []

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がインストールされ、マシンで動作します。 次の手順では、プロジェクトディレクトリを設定し、テンプレートを構成して基本的なCentOSスナップショットを作成します。

[[step-2 -—- configuring-the-digitalocean-builder]] ==ステップ2— DigitalOceanBuilderの構成

PackerでDropletを作成し、ソフトウェアと構成ファイルをインストールしてから、そのDropletを新しいマシンの作成に使用できるイメージに変換します。 Packerは、templateと呼ばれる構成ファイルを使用します。このファイルには、Packerにイメージの作成方法を指示するすべての詳細が含まれています。 この構成は、構成ファイルの一般的な形式であるJSONを使用して記述します。

Packer-speakでは、builderは、Packerで作成するイメージのブループリントを含むJSONオブジェクトです。 digitaloceanビルダーを使用して、NYC1リージョンで起動される512MBのCentOS7.3ドロップレットを作成するようにPackerに指示します。

このチュートリアルで作成するテンプレートおよび構成ファイルを保持する新しいディレクトリを作成して変更します。

mkdir ~/packerProject
cd ~/packerProject

プロジェクトディレクトリができたので、テキストエディタでtemplate.jsonという新しいファイルを開きます。

vi ~/packerProject/template.json

各ビルダーは、template.jsonbuildersセクションに移動する必要があります。 ここでこのセクションを追加し、次のコードをファイルに配置してdigitaloceanビルダーを含めます。

~/packerProject/template.json

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

typeキーは、Packerがイメージの作成に使用するビルダーを定義します。 digitaloceanビルダーは、Packerがスナップショットを作成するDigitalOceanドロップレットを作成します。

Packerは、DigitalOceanのイメージを作成することを知っていますが、ビルドを完了するには、さらにいくつかのキーと値のペアが必要です。

これらのキーと値を追加して、NYC1リージョンで起動される512 MB CentOS 7ドロップレットからスナップショットを作成することにより、ドロップレットの構成を完了します。 ファイルを次のように変更します。

~/packerProject/template.json

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

Packerは、ssh_username値を使用してドロップレットに接続します。 Packerが正常に機能するには、この値を「ルート」に設定する必要があります。

template.jsonを保存し、テキストエディタを終了します。

上記のコードブロックには、DigitalOcean Dropletを作成するために必要な最小限の構成が含まれていますが、次の表に示すように、追加の構成オプションを使用できます。

Key 必須 説明

api_token

ひも

Yes

アカウントへのアクセスに使用するAPIトークン。 設定されている場合は、環境変数DIGITALOCEAN_API_TOKENを介して指定することもできます。

image

ひも

Yes

使用するベースイメージの名前(またはスラッグ)。 これは、新しいドロップレットを起動してプロビジョニングするために使用されるイメージです。 受け入れられたイメージ名/スラッグのリストを取得する方法の詳細については、https://developers.digitalocean.com/documentation/v2/#list-all-imagesを参照してください。

region

ひも

Yes

ドロップレットを起動するリージョンの名前(またはスラッグ)。 したがって、これはスナップショットが利用できる領域です。 受け入れられるリージョン名/スラッグについては、https://developers.digitalocean.com/documentation/v2/#list-all-regionsを参照してください。

size

ひも

Yes

使用するドロップレットサイズの名前(またはスラッグ)。 受け入れられるサイズ名/スラッグについては、https://developers.digitalocean.com/documentation/v2/#list-all-sizesを参照してください。

api_url

ひも

No

非標準のAPIエンドポイントのURL。 DigitalOcean API互換サービスを使用している場合は、これを設定します。

droplet_name

ひも

No

ドロップレットに割り当てられた名前。 DigitalOceanは、マシンのホスト名をこの値に設定します。

private_networking

ブール値

No

作成中のドロップレットのプライベートネットワークを有効にするには、trueに設定します。 これはデフォルトでfalseであるか、有効になっていません。

snapshot_name

ひも

No

アカウントに表示される結果のスナップショットの名前。 これは一意である必要があります。

state_timeout

ひも

No

タイムアウトする前に、ドロップレットが目的の状態(「アクティブ」など)に入るのを期間文字列として待機する時間。 デフォルトの状態タイムアウトは「6m」です。

user_data

ひも

No

ドロップレットで起動するユーザーデータ。 詳細については、An Introduction to Droplet Metadataを参照してください。

これで有効なテンプレートが作成されましたが、APIトークンはテンプレートにハードコーディングされています。 これは悪い習慣であり、潜在的なセキュリティリスクです。 次のステップでは、このトークンの変数を作成し、template.jsonから移動します。

[[step-3 -—- creating-and-storing-user-variables]] ==ステップ3—ユーザー変数の作成と保存

Packerでは、変数の値を別のファイルに作成して保存できます。 イメージを構築する準備ができたら、このファイルをコマンドライン経由でPackerに渡すことができます。

変数を別のファイルに保存することは、機密情報や環境固有のデータをテンプレートから排除するための理想的な方法です。 これは、チームメンバーと共有したり、GitHubなどの公開リポジトリに保存したりする場合に重要です。

ローカルコピーのみを保存する場合でも、テンプレートの外部に変数を保存することはPackerのベストプラクティスです。

この情報を保存するために、packerProjectディレクトリに新しいJSONファイルを作成して開きます。

vi ~/packerProject/variables.json

次に、my_token変数を追加し、その値をDigitalOceanAPIトークンに設定します。

~/packerProject/variables.json

{
  "my_token": "YOUR_DIGITALOCEAN_API_TOKEN"
}

variables.jsonを保存し、エディターを終了します。

次に、変数を使用するようにテンプレートを構成しましょう。 my_token変数またはその他の変数を使用する前に、まず、template.jsonファイルの先頭にあるvariablesセクションで変数を定義して、変数が存在することをPackerに通知する必要があります。

エディタでtemplate.jsonを開きます。

vi 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セクションを追加して、イメージを作成する前にマシンにNginxWebサーバーをインストールしてセットアップするようにPackerを構成します。

[[step-4 -—- configuring-provisioners]] ==ステップ4—プロビジョナーの構成

provisionersセクションは、Packerが実行中のDropletにソフトウェアをインストールして構成してから、それをマシンイメージに変換する場所です。 Builderと同様に、Dropletを構成するために使用できるさまざまなタイプのプロビジョニングツールがあります。

Nginxを構成するには、Packerのfileプロビジョナーを使用して構成ファイルをサーバーにアップロードしてから、shellプロビジョナーを使用してそれらのファイルを使用するインストールスクリプトを実行します。 fileプロビジョナーを使用すると、イメージに変換される前に、実行中のマシンとの間でファイルとディレクトリを移動できます。 shellプロビジョナーを使用すると、そのマシンでシェルスクリプトをリモートで実行できます。

プロビジョニングツールは、テンプレート内に表示されるのと同じ順序で実行されます。 これは、シェルスクリプトがアップロードされたファイルを必要とするため、fileプロビジョナーを最初に配置することを意味します。

template.jsonbuildersセクションの直後にprovisionersセクションを追加し、使用する2つのプロビジョナーを設定します。

~/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セクションが完成しました。 ファイルを保存してVimを終了します。

次に、Packerがイメージの作成に使用するシェルスクリプトと構成ファイルを作成します。

[[step-5 -—- adding-configuration-files-and-installation-scripts]] ==ステップ5—構成ファイルとインストールスクリプトの追加

適切な構成ファイルとデフォルトのWebページを備えた、完全に構成されたNginxインストールとともにイメージを出荷する必要があります。 このセクションでは、チュートリアルHow To Set Up Nginx Server Blocks (Virtual Hosts) on Ubuntu 16.04に基づいて事前定義された構成からこれらのファイルを作成します。これは、Nginx構成がこのチュートリアルの範囲を超えているためです。

単一のインストールスクリプトで処理される3つの個別の構成ファイルを作成してアップロードすることにより、サーバーにNginxをプロビジョニングします。

最初に、プロジェクトフォルダー内に新しいディレクトリを作成して、構成ファイルを保存します。

mkdir ~/packerProject/configs

/configsに変更して、Nginx構成ファイルを作成します。

cd ~/packerProject/configs

最初に、新しいドメインから提供するデフォルトのWebページが必要です。 ファイルindex.html.newを作成します。

vi index.html.new

この新しいファイルに、次を挿入します。

~/packerProject/configs/index.html.new

HELLO FROM YOUR TEST PAGE

次に、ドメインのリスニングポートとWebページの場所を定義するドメインのサーバーブロックを定義するNginx構成ファイルが必要です。 newDomain.confというファイルを作成します。

vi 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;
        }
}

[.note]#この例では、プレースホルダー値としてexample.comを使用しています。 イメージから新しいマシンを作成するときは、新しいマシンにログインし、このファイルを変更して、マシンを指す実際のドメインまたはIPアドレスを反映する必要があります。

最後に、Nginxがドメインの構成を新しいディレクトリ/etc/nginx/vhost.d/からロードするようにします。 これは、メインのNginx設定ファイルを編集することを意味します。

nginx.conf.newを作成します。

vi nginx.conf.new

デフォルトのNginx構成ファイルを使用しますが、特定のサイト構成が含まれるように変更します。 このファイルに次の内容を入れます。

~/packerProject/configs/nginx.conf.new

user nginx;
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
vi configureNginx.sh

次のファイルをファイルに貼り付けます。作成した構成ファイルを使用して、Nginxをインストール、構成、および起動します。

~/packerProject/scripts/configureNginx.sh

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

# Update your system:
yum update -y

# Install EPEL Repository, update EPEL, and install Nginx:
yum install -y epel-release
yum update -y
yum 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-ドロップレットの検証と構築

Packerのvalidateサブコマンドを使用してテンプレートをテストするときが来ました。 テンプレートが正常に検証されると、Dropletを構築してスナップショットを作成します。

プロジェクトのルートに変更します。

cd ~/packerProject

validateサブコマンドは、有効な構文および構成オプションについてテンプレートをチェックします。

packer.io 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.io buildを呼び出してドロップレットを作成し、スナップショットを作成します。

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

-var-fileフラグは、buildサブコマンドとvalidateサブコマンドの両方でまったく同じように動作することに注意してください。

正常なビルドの出力は次のようになります。

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-1467580504
==> 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-1487878703' (ID: 18252043) in region 'nyc1'

ビルドが成功すると、DigitalOceanスナップショットリポジトリに新しいスナップショットが見つかります。 出力でスナップショットの名前を見つけることができます。 この例では、packer-1487878703です。

ここから、DigitalOceanダッシュボードにアクセスし、Imagesを選択すると、新しいスナップショットがリストに表示されます。

Docker snapshot in DigitalOcean dashboard

これで、この新しいスナップショットを使用して新しいドロップレットを作成できます。 Moreを選択し、Create Dropletを選択します。 次に、フォームに入力して新しいマシンを作成します。

マシンがオンラインになったら、ダッシュボードからそのIPアドレスを確認し、新しいマシンにログインします。

ssh root@your_new_server_ip_address

次に、Nginxサーバーの構成ファイルを編集します。

vi /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

this tutorialsedの詳細を学ぶことができます。

トラブルシューティング

エラーメッセージで十分に説明されていない問題が発生する場合があります。 これらのシナリオでは、デバッグモードを有効にするか、Packerログを検査するか、またはその両方によって、ビルドに関する詳細を抽出できます。

デバッグモードは、リモートビルドの各ステップのビルダー固有のデバッグ情報を提供します。 DigitalOceanビルドのデバッグモードを有効にすると、プロジェクトフォルダーに一時的なプライベートキーが生成され、スナップショットに変換される前に実行中のドロップレットに接続して検査できます。

コマンドラインで-debugフラグをpacker.io buildに渡すと、デバッグモードに入ることができます。

packer.io 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 communityの誰かに連絡してみてください。

結論

Packerの基本に慣れたので、この基盤を構築することに興味があるかもしれません。

テンプレートに2番目のビルダーを追加して、DigitalOceanスナップショットと一緒にローカルテスト環境を作成してみてください。 たとえば、virtualbox-isoビルダーは、企業と愛好家の両方が使用する無料のオープンソース仮想化製品であるVirtualBoxのイメージを生成します。 VirtualBoxイメージにpost-processorを定義し、DigitalOceanスナップショットをミラーリングするVagrant環境を作成できます。 これにより、Webサイトの変更をライブドロップレットにプッシュする前にローカルでテストできます。 詳細については、Vagrant post-processor documentationを参照してください。

または、Webサーバーをデータベースに接続することもできます。 2番目のdigitaloceanビルダーを追加し、provisionersセクションでonlyキーを使用して、ビルドごとに異なるプロビジョニングを適用します。

構成管理ツールの使用に慣れている場合、Packerには、AnsiblePuppetChefなどのサポートが付属しています。 これらのプロビジョニングツールのいずれかを使用して、ユースケースに合わせてドロップレットをさらに設定してみてください。 これまで構成管理を試したことがない場合は、How To Create Ansible Playbooks to Automate System Configuration on Ubuntuを確認してください。