クラウド同上

PackerによるGCPのカスタムイメージ作成の自動化

Author
a-kitano
Lv:2 Exp:253

2019年にクラウドエースに入社

オンプレミスで稼動しているシステムをクラウドネイティブなシステムへ移行するにおいて、稼動しているシステムをそのままクラウド上で稼動させ、クラウドで提供されているマネージドサービスへ徐々に移行していくことが一般的です。
そのため、稼動しているシステムをそのままクラウド上へ移行させる必要があります。もし稼動しているシステムをAnsibleやChefなどの構成管理ツールを用い管理しているならば、VMイメージを作成するツールであるPackerを利用することで簡便に移行ができます。

本記事では、Packerを使いGCP上でカスタムイメージを作成する方法について説明します。
注意: Packerはv1.5よりHCL2形式の記述が可能になりましたが、現状、ベータ版であるためJson形式記載方法について説明します。

Packerとは

Packerは、HashiCorpが作成している、AWSやVMWareなどさまざまな仮想基盤上でVMイメージを作成するオープンソースのCLIツールです。Packerが対応している仮想基盤にGCPも含まれており、PackerによりGCEのカスタムイメージを作成できます。PackerはVMイメージの作成方法を定義したテンプレート(以降、テンプレートと略します)をもとにしてVMを作成するため、VMの作成をコード管理することができます。
また、PackerはAnsibleやChefなどさまざな構成管理ツールとの連携も可能となっており、システムの運用にもちいている構成管理ツールの資産を再利用でき、オンプレミスで稼動しているシステムのGCPへの移行を簡便におこなうことができます。

Packerの処理の流れ

ここでは、PackerがVMイメージを作成する処理の流れを説明します。
PackerがテンプレートをもとにVMイメージの作成処理を実行すると、以下の順でVMイメージを作成します。

  1. 仮想基盤上にVMインスタンスの作成
  2. VMインスタンスに定義された設定の実施
  3. VMのイメージ化
  4. VMイメージへの処理

上記の処理においてPackerは、VMへの通信にSSHまたはWinrm のプロトコルを利用します。(Winrmは、Microsoftにより実装されたSoapベースのWS-Management プロトコルです。)
以下にローカルマシン上でPackerを実行し、GCP上にカスタムイメージを作成するときの処理の概略図を記載します。

Packer process flow

Packerとテンプレート内部で定義した構成管理ツール(図では、例としてAnsibleとしています)をインストールしたホスト上で、テンプレートと構成管理の定義ファイルを作成します。そして、Packerビルドを実行すると、GCP上にCompute Engine(以降、GCEと略します)が作成され、当該GCEに対して構成管理ツールを用い設定をします。
設定が完了すると、GCEをイメージ化しカスタムイメージとして登録しGCEを削除します。

Packerの使い方

ここでは、CLIツールであるpackerの使い方について説明します。
packerコマンドには、下記サブコマンドが定義されています。

  • build : VMイメージの作成
  • inspect: テンプレートの定義表示
  • validate: テンプレート内の文法ミスの確認
  • fix: 旧packerバージョンのテンプレートから新バージョンのテンプレートへのパース
  • console: テンプレートの変数に格納される値を表示するコンソールの起動
  • version: packerのバージョン表示

サブコマンドversion以外は、テンプレートを引数に渡すことで実行されます。以下にサブコマンドのビルドを例に示します。

$packer build <テンプレートのパス>

テンプレートの内容

ここでは、テンプレートに定義する内容について説明します。テンプレートは、以下の内容で構成されています。

  • builders : VMイメージを作成する仮想基盤の設定の定義
  • provisioners: VMインスタンスへの設定内容の定義
  • post-processors: 設定終了後のVMイメージの処理の定義
  • variables: テンプレート内の変数の定義
  • description: テンプレートの実行内容の説明
  • min_packer_version: packerの実行バージョンに必要なバージョンの定義

上記のブロックを1つのjsonファイルで定義したものが、テンプレートとなります。
以下に特筆すべきbuilders,provisioners,post-processors,variablesブロックについて説明します。

buildersブロック

仮想基盤上でVMイメージを作成する際に作成されるVMインスタンスの作成方法を定義します。buildブロックは必須で定義しなければなりません。
VMイメージを作成する仮想基盤を指定する項目は、 “type”となっています。この項目に googlecomputeを指定すると、GCP上にVMイメージを作成します。
GCP上でカスタムイメージを作成する場合、以下を必ず定義する必要があります。

  • project_id: カスタムイメージを作成するプロジェクト
  • source_image/source_image_family : VMインスタンスの元となるVMイメージ
  • zone: カスタムイメージを作成するゾーン

その他にgooglecomputeを指定した際に定義できる設定値は、下記ページをご参照ください。
Google Compute Builder: https://packer.io/docs/builders/googlecompute.html

provisionersブロック

仮想基盤上でVMイメージを作成する際に、buildersブロックの定義により作成されたVMインスタンスに対して設定を実施する方法を定義します。ここには、AnsibleやChefといったサードパーティのツールが定義可能です。これらサードパーティのツールを定義した場合、Packerの実行環境にサードパーティツールのインストールが必要となります。当該ブロックは、オプションとなっています。
対応しているprovisionerは、以下のページをご参照ください。
Provisioners: https://packer.io/docs/provisioners/index.html

post-processorsブロック

buildersブロックとprovisionersブロックで定義された内容で作成されたVMイメージのアップロードや再パッケージなどの処理を定義することができます。当該ブロックは、オプションとなっています。
例えば、googlecompute-exportをpost-processorsブロックに定義すると、作成したVMイメージをtarballでアーカイブ化したファイルをGCSに保存します。
その他の対応しているpost-processorsブロックは、下記ページをご参照ください。
post-Processors: https://packer.io/docs/post-processors/index.html

variablesブロック

variablesは、他のブロックで変数のデフォルト値を定義するブロックとなっています。
packerにおける変数は、 “{{ user 変数名 }}” と定義されます。当該変数にデフォルト値を設定する場合、variablesブロックに 変数名 : 値と定義することで定義できます。

設定例

以下にbuilderブロックのimage_nameの値をimage_nameという変数で定義し、variablesブロックで当該変数にtestを代入した例を示します。

{
  "variables": {
    "image_name": "test”,
  },
  "builders":[
    {
      "type": "googlecompute",
      "project_id": "project-name",
      "source_image_family": "debian-9"",
      "ssh_username": "packer",
      "zone": "asia-northeast1-b",
      "image_name": "{{user `image_name`}}",
    }
  ]
}

また、buildサブコマンドは変数を直接入力可能となっており、 以下のように上記の値を直接指定するとデフォルト値のtestからdemoに上書かれて実行されます。

$packer build -var ‘image_name=demo’ 

PackerでGCP上にカスタムイメージを作成する方法

ここでは、ローカルマシンからPackerでGCP上の公式イメージのUbuntu 1804 LTSにNginxをインストールしたカスタムイメージtestを作成する方法を紹介します。
カスタムイメージを作成するGCPの環境は、下記のとおりとします。

  • project_id: ca-kitano-study-sandbox
  • source_image_family: ubuntu1804
  • ssh_username: packer
  • zone: asia-northeast1-b
  • image_name: test

また、nginxのインストールは、Ansibleでおこないます。
ローカルマシンの環境は下記のとおりです。

  • OS: mac 64bit
  • python バージョン 3.4以上
  • OSにインストールするアプリケーション: Packer, Ansible

ここで、Packerの実行に必要な権限と、ローカルホストにインストールするPacker,Ansibleのインストール方法を説明し、Packerを使ったカスタムイメージの作成を説明します。

権限の設定

Packerを使いカスタムイメージを作成するにあたり、以下の2つの権限が必要となります。

  • Compute Engine Instance Admin (v1)
  • サービス アカウント ユーザー

ローカルマシンへの権限の付与方法は、下記の手順で実施します。

Cloud Consoleの[IAMと管理] の[サービスアカウント]で、Compute Engine Instance Admin(v1)とサービス アカウント ユーザーの権限を付与しサービスアカウントを作成し、ローカルサービスアカウントのJsonファイルをローカルマシンに保存します。
roles

ローカルマシンの環境変数GOOGLE_APPLICATION_CREDENTIALSに先の手順で保存したサービスアカウントのJsonファイルのパスを指定します。

 $export GOOGLE_APPLICATION_CREDENTIALS=

アプリケーションのインストール方法

Packerのインストール方法

ここでは、64-bitのmac OSでPackerをインストール方法をご紹介します。
以下のPackerのダウンロードページからmac OS の64-bitをクリックしパッケージをダウンロードします。
packer download

ダウンロードするとpackerのバイナリファイルを格納したzipファイルがダウンロードされます。当該zipファイルを解凍し、packerのバイナリファイルをパスが通っている場所に移動させます。以下はファイルのzipファイルの解凍とパスの通った場所にファイルを移動する方法です。

~ $cd Downloads
~/Downloads $ ls
packer_1.5.5_darwin_amd64.zip
~/Downloads $unzip packer_1.5.5_darwin_amd64.zip
~/Downloads $ls
packer                        packer_1.5.5_darwin_amd64.zip
~/Downloads $mv packer /usr/local/bin/
~/Downloads $packer --version
1.5.5

Packerのダウンロードページ: https://packer.io/downloads.html

Ansibleのインストール方法

ここでは、pipを使ったインストール方法を説明します。
(python3.4以上では、デフォルトでpipがインストールされているため、pipのインストールは不要となります。)
Ansibleは、sshでVMに対して設定をおこないますが、pipでインストールしたAnsibleはsshをラップしたpythonライブラリであるparamikoが必要となるため合わせてインストールしてください。
インストール方法は下記コマンドとなります。

 $pip3 install ansible paramiko

テンプレートと構成管理ツールの定義ファイルの作成

ここではnginxのカスタムイメージを作成するpackerのテンプレートとAnsibleのplaybookの定義を示します。ここでは、テンプレートとplaybookの名前をそれぞれmain.jsonとansible-playbook.yamlとしてます。また、2つのファイルは同じディレクトリに格納します。

main.json

{
  "variables": {
    "project_id": "project-name",
    "image_id": "debian-9",
    "image_name": "test",
    "image_zone": "asia-northeast1-b",
    "user": "packer"
  },
  "builders":[
    {
      "type": "googlecompute",
      "project_id": "{{user `project_id`}}",
      "source_image_family": "{{user `image_id`}}",
      "ssh_username": "{{user `user`}}",
      "zone": "{{ user `image_zone` }}",
      "image_name": "{{user `image_name`}}"
    }
  ],
  "provisioners": [
    {
      "type": "ansible",
      "playbook_file": "./ansible-playbook.yaml",
      "user": "{{user `user`}}"
    }
  ]}

ansible-playbook.yaml

- hosts: all
  become: true
  tasks:
    - name: package repository update
      apt:
        update_cache: yes

    - name: install nginx
      apt:
        name:
          - nginx

Packerの実行

ここでは、上記で説明したテンプレートを実行しカスタムイメージを作成する方法を記載します。

 $packer build main.json

最後に作成したカスタムイメージからGCEを作成しnginxがインストールされていることを確認します。

$gcloud compute instances create test --zone asia-northeast1-b --image test --machine-type f1-micro

Created [https://www.googleapis.com/compute/v1/projects/ca-kitano-study-sandbox/zones/asia-northeast1-b/instances/test].
NAME  ZONE               MACHINE_TYPE  PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP    STATUS
test  asia-northeast1-b  f1-micro                   10.146.0.59  34.84.145.158  RUNNING

作成したGCEにsshし、nginxのプロセスが起動していることを確認します。

$gcloud compute ssh test
kitano@test:~$ sudo systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
   Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2020-04-08 23:40:29 UTC; 2min 26s ago
     Docs: man:nginx(8)
  Process: 665 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
  Process: 634 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
 Main PID: 668 (nginx)
    Tasks: 2 (limit: 4915)
   CGroup: /system.slice/nginx.service
           ├─668 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
           └─669 nginx: worker process

Apr 08 23:40:27 test systemd[1]: Starting A high performance web server and a reverse proxy server...
Apr 08 23:40:29 test systemd[1]: nginx.service: Failed to read PID from file /run/nginx.pid: Invalid argument
Apr 08 23:40:29 test systemd[1]: Started A high performance web server and a reverse proxy server.

また、作成されたGCEにブラウザからアクセスすると以下のようにNginxのページが表示されることが確認されます。
nginx

まとめ

Packerを使いGCP上でカスタムイメージを作成する方法を説明しました。本記事では、GCP上で公開されているUbuntuイメージよりnginxをインストールしたカスタムイメージを作成しました。同様の手順によりWindowsイメージについても同じようにカスタムイメージを作成することができます。