それなりに適当にやってます

なんとなくそれっぽいメモとか備忘録とか適当に。 2018年5月にブログ移転しました。 古い記事は未整理です。

Packer + Ansible で GCP のイメージを作成してみた

概要

名称 役割
Packer AMIなどイメージを作成するためのツール
Ansible OS・ミドルウェアの導入・設定を行うための構成管理ツール
Terraform インフラの構成・設定をコード化するためのツール
  • Packer + Ansible = インスタンス〜ミドルウェアまでを設定
  • Terraform = インフラとしての構成(ネットワーク、ロードバランサ、インスタンスなど)全体を設定

イメージとしては Packer + Ansible でインスタンス・テンプレートを作成し、Terraform でVPC全体像をデプロイする形になる。

Packer

インストール

公式のダウンロードページからバイナリをダンロードして ${HOME}/bin 配下に展開する。

$ mkdir ~/bin ; cd $_
$ curl -O https://releases.hashicorp.com/packer/1.2.4/packer_1.2.4_linux_amd64.zip
$ unzip packer_1.2.4_linux_amd64.zip
$ rm packer_1.2.4_linux_amd64.zip
$ echo PATH=${HOME}/bin:${PATH} >> ~/.bashrc
$ source ~/.bashrc
$ packer version
Packer v1.2.4
  • ドキュメントの指定するまま AWS で AMI の作成を行っても良いんだけど、個人的にはGCPのほうが好きなのでGCPで試してみる。
  • GCPのインスタンスイメージを1から作る方法もあるが、公式のドキュメントにあった Builder のドキュメント の通り、GCP上にすでに用意されているイメージを利用する。
  • GCP上でサービスアカウントを作成・認証ファイル(JSON)の取得し、CloudSDK (gcloudコマンド) を利用できる状態にしとく。

最初のデプロイ

Packer の基本的な設定を作成してデプロイしてみる。 下記JSONで指定する source_imageGCPのコンソール > Compute Engine > イメージ または gcloud compute images list で確認できる。

$ mkdir ~/packer-example ; cd $_
$ vi base.json
{
  "builders": [
    {
      "type": "googlecompute",
      "account_file": "account.json",
      "project_id": "my project",
      "source_image": "centos-7-v20180523",
      "ssh_username": "packer",
      "zone": "asia-northeast1-a"
    }
  ]
}

作成したJSONで色々試してみる。

$ packer inspect base.json      #<-作成したJSONで何が実施されるのか内容を表示
$ packer validate base.json     #<-バリデーションチェック
$ packer build base.json
...
googlecompute output will be in this color.

==> googlecompute: Checking image does not exist...
==> googlecompute: Creating temporary SSH key for instance...
==> googlecompute: Using image: centos-7-v20180523
==> googlecompute: Creating instance...
    googlecompute: Loading zone: asia-northeast1-a
    googlecompute: Loading machine type: n1-standard-1
    googlecompute: Requesting instance creation...
    googlecompute: Waiting for creation operation to complete...
    googlecompute: Instance has been created!
==> googlecompute: Waiting for the instance to become running...
    googlecompute: IP: xxx.xxx.xxx.xxx
==> googlecompute: Waiting for SSH to become available...
==> googlecompute: Connected to SSH!
==> googlecompute: Deleting instance...
    googlecompute: Instance has been deleted!
==> googlecompute: Creating image...
==> googlecompute: Deleting disk...
    googlecompute: Disk has been deleted!
Build 'googlecompute' finished.

==> Builds finished. The artifacts of successful builds are:
--> googlecompute: A disk image was created: packer-1527668955      #<-packer-1527668955 というイメージが作成された

実際に GCPコンソール > ComputeEngine > イメージ を確認すると packer-1527668955 というイメージが作成されていた。 JSONの細かいオプションは 公式のドキュメント を見るとわかる。 例えば source_image_family を指定することで常に centos-7 の最新版を利用したり、image_name で生成されるイメージの名前を指定することができる。

Packer と Ansible の連携

Packer に読み込ませる JSON は下記のように4つの項目で設定する。 variableprovisioners を利用することで Ansible などと連携したイメージの作成が行える。

{
    "variables": [
      {
        // 変数
      }
    ],
    "builders": [
      {
        // AWS, GCP などデプロイ先の設定
      }
    ],
    "provisioners": [
      {
        // Ansible, ShellScript ほか
      }
    ],
    "post-processors": [
      {
        // 後処理
      }
    ]
}

作成例

公式ドキュメントのProvisionerの項目を見れば大体わかるけど、Ansible についてはインスタンスのローカル・リモートからの両方に対応してみるみたい。
作成例は下記の通り。 sshd の sftp-server にオプションを追加しているのは、公式のドキュメントに注意書きがあったため

{
  "builders": [
    {
      "type": "googlecompute",
      "account_file": "account.json",
      "project_id": "my project",
      "source_image_family": "centos-7",
      "ssh_username": "packer",
      "zone": "asia-northeast1-a"
    }
  ],
  "provisioners": [
    {
      "type": "shell",
      "inline": [
        "sudo yum -y update",
        "sudo yum -y --enablerepo=epel install ansible",
        "sudo sed -i '/sftp-server$/s/$/ -e/' /etc/ssh/sshd_config",
        "sudo systemctl restart sshd"
      ]
    },
    {
      "type": "ansible",
      "playbook_file": "apache.yml"
    }
  ]
}

同じディレクトリに Ansbile の Playbook を置く。 become: true で root で実行されるようにする。

---
- hosts: all
  become: true
  tasks:
    - name: install apache
      yum: name=httpd
    - name: create index.html
      shell: echo "Hello World!" > /var/www/html/index.html
    - name: apache restart
      service: name=httpd state=restarted enabled=yes

この状態で packer validate を実行すると ansible-playbook が見つからないと怒られるので、別途Ansibleを入れてから行う (自分は pyenv で入れた)

$ pyenv virtualenv 3.6.5 ansible
$ pyenv local ansible
$ pip install ansible
$ packer validate base.json
Template validated successfully.

そして packer inspect で反映される内容を確認してからデプロイしてみる。

$ packer inspect base.json
$ packer build base.json
...
#-> yum 〜 ansible の実行までの出力がわかる

んで、インスタンスを作成する際にカスタムイメージを選択してインスタンスを作成・起動し、Apache が起動していることを確認するとこまでできた。
あとは Packer のTemplates とかドキュメント見たり、やりたいことを整理して Ansible で頑張る感じかな。

参考URL

その他

作成したイメージを利用して、インスタンス・テンプレートを作成して〜とかは Terraform で行うので、次は Terraform を頑張る。

以上