LoginSignup
27
29

More than 5 years have passed since last update.

Packer で開発環境の Vagrant Box を自作して、post-processors 処理を通して S3 に保存・バージョン管理・ホスティングする

Last updated at Posted at 2015-03-16

サーバー上のシステムをチームで開発する場合、開発環境の構築をどう共有するかは課題になると思いますが、いくつかの既存のやり方には問題があります

今までの開発環境構築のやり方

README.md などに手順を書く方法

これには次の問題が発生することがあります

  • 本番環境(ex. Ubuntu)と開発環境(ex. Mac)で土台となる OS が違う
  • 手順書の更新漏れがある
  • 手順書の再現性の検証がおろそかになる
  • 手順書の更新に対して、既存の開発環境をアップデートしないメンバーが出てくる

Vagrant を使う方法

これは上記のいくつかを解消しますが、まだ問題が残ります

  • 引き続き残る問題
    • 手順書の更新に対して、既存の開発環境をアップデートしないメンバーが出てくる
  • 新たに発生した問題
    • vagrant up に時間がかかる(ex. 30 分以上とか)

vagrant up によって時間がかかる問題は、apt-getgem install に失敗してやり直したりするリスク(時にはライブラリのインストールサーバーがしばらく不通になることもあると思います)も含めて、それなりにチーム全体でみると無駄な時間を作ってしまいます

開発環境構築済みの Vagrant BoxS3 にホスティングするやり方

開発環境構築済みの Vagrant Box を作る

これによって、vagrant up に時間がかかる問題は解消します

  • ライブラリのインストールに時間がかかったり、ライブラリをホストするサーバー依存で完了しないといったことがなくなります
  • Vagrant Box のダウンロードがほとんどの時間を占めるので、ホスティング先や回線速度にもよりますが、5 ~ 10 分程度で終わるのではないでしょうか
    • ファイルサイズは、自分の感覚ではだいたい 300 MB ~ 1.2 GB 程度に収まることが多いのではと思います

Vagrant Boxmanifest.json と一緒に S3 にホスティングする

これによって、既存の開発環境をアップデートしないメンバーが出てくるという問題は解消します

Vagrant Box の生成と S3 へのアップロードを行うために、Packer を使う

packer_image.png

Packer による Vagrant Box の生成

Packer を使うと、テンプレートファイルを用意することで AMIVagrant Box をある程度透過的に、作ることができます

  • 例えば、AWSAuto Scaling 機能を使う際に、インスタンスのセットアップをすぐに行うとか外部依存しないで終わらせるために、AMI を使うことは多いと思います
    • その AMI 構築をスクリプトで管理・実施することになるので、いわゆる、Infrastructure as a Code を実現することができます

すでに AMI 構築に Packer を使っている場合には、その構築手順を流用して Vagrant Box を作ることができます。これには、次のようなメリットがあります

  • 本番環境の更新箇所と開発環境の更新箇所(= 要するにプロビジョニング)を共通化できる
  • ソースコード上の位置的にも近接しているので、本番環境の構築スクリプト更新時に、開発環境の構築スクリプトの更新漏れが発見しやすい

まだ Packer を使っていない場合でも、後述するように、テンプレートファイルによる記述と実行の簡単さやプラグインによる拡張性の高さを理由に、Packer を使う方法をおすすめします

Packer による Vagrant BoxS3 へのアップロード

Packer はサードパーティ製のプラグインを使って、機能を拡張することができます

  • packer-post-processor-vagrant-s3 もそのひとつで、Vagrant BoxS3 へのアップロードとそのバージョン管理をするための manifest ファイル の管理を自動化してくれます
  • post-processor というのは、Packer が参照するテンプレートファイル内のブロックの名前のひとつです
    • ここでは、Vagrant Box を生成したメイン処理の後に、実施されるプラグインであるという意味になります

具体例をもとに、手順をまとめる

Vagrant Box それ自体を作成する作業と、そのプロビジョニング(= 必要なライブラリをインストールするなど)をする作業の 2 つに大別されます

前提

本番環境は Ubuntu trusty の AMI で動かしているとして、それに合わせる前提で考えます

また、PackerVagrant はすでにインストール済みで操作はわかっている前提で書きます

  • これらの導入をまとめたチュートリアルはすでに多くあると思いますのでそれらを参照ください

ubuntu-trusty-server-cloudimg-amd64 の OVA を作成する

Vagrant Box(≒ VirtualBox Virtual Machines)は、ISO から作るか、OVF/OVA から作るかという 2 つの方法があります

  • Qiita などには ISO から作るチュートリアルが多くあるのですが、スクラッチから作りたいわけではないならば、OVF/OVA から作るのがおすすめです
  • 本番環境と同じような環境を作りたいだけなので、公式に提供されているものから作った方が安全だと思うためです
    • 公式ドキュメントチュートリアルサイトにも同様の趣旨の記載があります
    • また、テンプレートファイル内に読んで理解しづらい(人によるでしょうが)ISO 生成の設定を書くのは避けたいと個人的には思っています

ubuntu 上で実行するなら次の手順で作ることができます

$ BOX_URL=https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box
$ curl $BOX_URL | tar --delete Vagrantfile > ubuntu.ova

mac 上では tar のオプションが違うので愚直な次の方法で作ることができました

$ BOX_URL=https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box
$ curl $BOX_URL > ubuntu.box
$ tar xvf ubuntu.box
$ rm Vagrantfile
$ tar cvf ubuntu_trusty.ova box.ovf box-disk1.vmdk 

Packer のテンプレートファイルを作成する

これ以後、秘匿情報は *** で隠してます

それぞれのブロックの意味

  • variables では、ファイル中で変数として参照するための定義を書いてます
  • builders では、VirtualBox VM を生成するための手順を書いています
  • provisioners では、ライブラリのインストールなど、そのプロジェクト固有の設定をするための手順を書いています
  • post-processors では、生成した Vagrant BoxS3 にアップロードするための手順を書いています

アップロード先について

  • Vagrant Boxmanifest.json は S3 の ***-vagrant-box/vagrant ディレクトリに配置されます

注意する点について

  • buildersvboxmanagememory2048 にしています
    • この値はプロジェクトによって必要最低限のメモリ使用量が良く、多ければマシンが重くなり、少なければプロジェクトが動きません
    • 例えば、1024 の場合、自分のプロジェクトでは OOM Kill されました
local.json
{
  "variables": {
      "version": "0.0.2",
      "aws_access_key": "***",
      "aws_secret_key": "***"
  },  
  "builders": [
    {
      "type": "virtualbox-ovf",
      "guest_additions_path": "VBoxGuestAdditions_{{.Version}}.iso",
      "headless": "true",
      "shutdown_command": "echo 'vagrant' | sudo -S shutdown -P now",
      "source_path": "ubuntu_trusty.ova",
      "ssh_password": "vagrant",
      "ssh_username": "vagrant",
      "ssh_wait_timeout": "20m",
      "vboxmanage": [
        ["modifyvm", "{{ .Name }}", "--memory", "2048"]
      ],
      "virtualbox_version_file": ".vbox_version",
      "vm_name": "mtburn-base"
    }
  ],
  "provisioners": [
      {
          "source": "files", 
          "destination": "/tmp/files",
          "type": "file"
      },
      {
          "scripts": [
              "scripts/ubuntu-trusty/basic.sh",
              "scripts/ubuntu-trusty/packages.sh",
              "scripts/ubuntu-trusty/user.sh",
              "scripts/ubuntu-trusty/perl.sh",
              "scripts/ubuntu-trusty/td-agent.sh",
              "scripts/ubuntu-trusty/mysql-server.sh",
              "scripts/ubuntu-trusty/redis-server.sh"
          ],
          "environment_vars": "MTBURN_ROLE=local",
          "type": "shell"
      }
  ],
  "post-processors": [
    [
        {
          "type": "vagrant", 
          "output": "/tmp/ubuntu-trusty-server-cloudimg-amd64.box"
        },
        {
          "type": "vagrant-s3",
          "region": "ap-northeast-1",
          "bucket": "***-vagrant-box",
          "manifest": "vagrant/manifest.json",
          "box_name": "mtburn-ubuntu-trusty-server-cloudimg-amd64",
          "box_dir": "vagrant/boxes",
          "version": "{{ user `version` }}",
          "access_key": "{{ user `aws_access_key` }}",
          "secret_key": "{{ user `aws_secret_key` }}"
        }
    ]
  ]
}

packer build します

  • S3 のアップロードは回線状況などによって失敗する場合があります
    • そのため、足元にも生成した box を置くようにしてます
    • その場合には手動アップロードすることになりますが、手間がかかるので手順を後述します
$ packer build local.json
...
==> virtualbox-ovf: Running post-processor: vagrant
==> virtualbox-ovf (vagrant): Creating Vagrant box for 'virtualbox' provider
    virtualbox-ovf (vagrant): Copying from artifact: output-virtualbox-ovf/mtburn-base-disk1.vmdk
    virtualbox-ovf (vagrant): Copying from artifact: output-virtualbox-ovf/mtburn-base.ovf
    virtualbox-ovf (vagrant): Renaming the OVF to box.ovf...
    virtualbox-ovf (vagrant): Compressing: Vagrantfile
    virtualbox-ovf (vagrant): Compressing: box.ovf
    virtualbox-ovf (vagrant): Compressing: metadata.json
    virtualbox-ovf (vagrant): Compressing: mtburn-base-disk1.vmdk
==> virtualbox-ovf: Running post-processor: vagrant-s3
==> virtualbox-ovf (vagrant-s3): Preparing to upload box for 'virtualbox' provider to S3 bucket '***-vagrant-box'
    virtualbox-ovf (vagrant-s3): Box to upload: /tmp/ubuntu-trusty-server-cloudimg-amd64.box (1105662889 bytes)
    virtualbox-ovf (vagrant-s3): Fetching latest manifest
    virtualbox-ovf (vagrant-s3): Generating checksum
    virtualbox-ovf (vagrant-s3): Checksum is 4f44e9727719bb2b4780da33d40c27095eeffefcb4ad2ab68917bedecde87531
    virtualbox-ovf (vagrant-s3): Adding virtualbox 0.0.2 box to manifest
    virtualbox-ovf (vagrant-s3): Uploading box to S3: vagrant/boxes/0.0.2/ubuntu-trusty-server-cloudimg-amd64.box
    virtualbox-ovf (vagrant-s3): File size > 100MB. Initiating multipart upload
    virtualbox-ovf (vagrant-s3): Uploading the manifest: vagrant/manifest.json
Build 'virtualbox-ovf' finished.

上記の手順によって生成された成果物を確認する

Vagrant Boxmanifest.jsonS3 上の所定の位置にアップロードされているはずです

  • 次の manifest.json は、理解のために、すでに 0.0.1 というバージョンをアップロードしたあとに、0.0.2 という新しいバージョンをアップロードした場合のものです
    • これによって、これ以後新規に vagrant up すると、0.0.2Vagrant Box をダウンロードして構築するようになります
    • また、すでに 0.0.1 を構築済みの環境で vagrant up した場合も、vagrant box update と打てば、0.0.2Vagrant Box をダウンロードしてアップデートしてくれます
manifest.json
{
  "name": "mtburn-ubuntu-trusty-server-cloudimg-amd64",
  "versions": [
    {
      "version": "0.0.1",
      "providers": [
        {
          "name": "virtualbox",
          "url": "https://s3-ap-northeast-1.amazonaws.com/***-vagrant-box/vagrant/boxes/0.0.1/ubuntu-trusty-server-cloudimg-amd64.box",
          "checksum_type": "sha256",
          "checksum": "d4cb23e3502c4717dff626ede4838e70ec26f92a495679ab57137f96fb7caade"
        }
      ]
    },
    {
      "version": "0.0.2",
      "providers": [
        {
          "name": "virtualbox",
          "url": "https://s3-ap-northeast-1.amazonaws.com/***-vagrant-box/vagrant/boxes/0.0.2/ubuntu-trusty-server-cloudimg-amd64.box",
          "checksum_type": "sha256",
          "checksum": "4f44e9727719bb2b4780da33d40c27095eeffefcb4ad2ab68917bedecde87531"
        }
      ]
    }
  ]
}

上記の手順によって生成された成果物を利用する

Vagrantfile を用意する

local_initfile では supervisord などプロセス管理デーモンの起動など最低限の処理や、他の開発メンバーの任意に任される(= 不要なら削除・編集してもらって構わない)ような /etc/hosts の編集などを記述しています

  • Vagrantfilelocal_initfile は、プロジェクトのレポジトリに含めて管理・共有されます
Vagrantfile
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "mtburn-ubuntu-trusty-server-cloudimg-amd64"
  config.vm.box_url = "https://s3-ap-northeast-1.amazonaws.com/***-vagrant-box/vagrant/manifest.json"
  config.vm.provision "shell", path: "Packer/scripts/ubuntu-trusty/local_initfile"
  config.vm.network "private_network", ip: "172.20.20.10"
end

Vagrant Box のバージョン管理

古いバージョンを使っている場合(すでに S30.0.2 がありながら、手元はまだ 0.0.1 など)に、vagrant up すると次のような警告が出るようになります

$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Checking if box 'mtburn-ubuntu-trusty-server-cloudimg-amd64' is up to date...
==> default: A newer version of the box 'mtburn-ubuntu-trusty-server-cloudimg-amd64' is available! You currently
==> default: have version '0.0.1'. The latest is version '0.0.2'. Run
==> default: `vagrant box update` to update.
==> default: VirtualBox VM is already running.

警告にある通り、vagrant box update を実行すれば最新に更新されます

$ vagrant box update
==> default: Checking for updates to 'mtburn-ubuntu-trusty-server-cloudimg-amd64'
    default: Latest installed version: 0.0.1
    default: Version constraints: 
    default: Provider: virtualbox
==> default: Updating 'mtburn-ubuntu-trusty-server-cloudimg-amd64' with provider 'virtualbox' from version
==> default: '0.0.1' to '0.0.2'...
==> default: Loading metadata for box 'https://s3-ap-northeast-1.amazonaws.com/***-vagrant-box/vagrant/manifest.json'
==> default: Adding box 'mtburn-ubuntu-trusty-server-cloudimg-amd64' (v0.0.2) for provider: virtualbox
...

補足

Vagrant Box の手動アップロード

生成した Vagrant BoxS3 にアップロードする post-processors 処理は回線状況によっては失敗する場合があります

  • その場合、手動で ***-vagrant-packer/vagrant 以下に manifest.jsonboxes/[version]/ubuntu-trusty-server-cloudimg-amd64.box をアップロードしたい場合もあると思います

box はそのままアップロードすれば良いですが、manifest.json はすでに S3 でホスティングされている内容に append する形式で新しいバージョンの情報を付け加える作業が必要になります

  • この際の sha256checksumopenssl dgst -sha256 ubuntu-trusty-server-cloudimg-amd64.box というコマンドで算出できます

また、metadataContent-typeapplication/json になっていないといけない点に注意してください

AMI を生成するテンプレートファイルの post-processors 処理内で Vagrant Box を生成する

例えば、すでに AMI を生成するために Packer を使っている場合、そのテンプレートファイルは次のような感じかと思います

app.json
{   
    "variables": {
        "aws_access_key": "***",
        "aws_secret_key": "***"
    },
    "builders": [{
        "type": "amazon-ebs",
        "access_key": "{{user `aws_access_key`}}",
        "secret_key": "{{user `aws_secret_key`}}",
        "region": "ap-northeast-1",
        "source_ami": "ami-e74b60e6",
        "instance_type": "t2.micro",
        "ssh_username": "ubuntu",
        "ami_name": "app {{timestamp}}"
    }],
}

https://www.packer.io/intro/getting-started/vagrant.html を読むと、次のように post-processorstype: "vagrant" を指定すれば、Vagrant Box が生成されると書いてあります

app-and-local.json
{   
    "variables": {
        "aws_access_key": "***",
        "aws_secret_key": "***"
    },
    "builders": [{
        "type": "amazon-ebs",
        "access_key": "{{user `aws_access_key`}}",
        "secret_key": "{{user `aws_secret_key`}}",
        "region": "ap-northeast-1",
        "source_ami": "ami-e74b60e6",
        "instance_type": "t2.micro",
        "ssh_username": "ubuntu",
        "ami_name": "app {{timestamp}}"
    }],
    "post-processors": [{
        "type": "vagrant",
        "output": "./Packer/box/ubuntu-trusty-14.04-amd64-server-for-local.box",
        "keep_input_artifact": true
    }]
}

これをビルドしてみると、確かに box ができます

  • ただし、Vagrant Boxprovidervirtualbox ではなく aws になっています
    • そのため、.vmdk が含まれず、vagrant-aws plugin を使う前提の box が生成されるだけです
    • AMI から生成されるので当たり前の結果といえばそうです
$ packer build Packer/app-and-local.json
amazon-ebs output will be in this color.

==> amazon-ebs: Inspecting the source AMI...
==> amazon-ebs: Creating temporary keypair: packer 54cdf714-446a-eef6-6415-8f7b2913bcf5
==> amazon-ebs: Creating temporary security group for this instance...
==> amazon-ebs: Authorizing SSH access on the temporary security group...
==> amazon-ebs: Launching a source AWS instance...
    amazon-ebs: Instance ID: i-06b6ab1f
==> amazon-ebs: Waiting for instance (i-06b6ab1f) to become ready...
==> amazon-ebs: Waiting for SSH to become available...
==> amazon-ebs: Connected to SSH!
==> amazon-ebs: Stopping the source instance...
==> amazon-ebs: Waiting for the instance to stop...
==> amazon-ebs: Creating the AMI: app 1422784276
    amazon-ebs: AMI: ami-36e7ff37
==> amazon-ebs: Waiting for AMI to become ready...
==> amazon-ebs: Terminating the source AWS instance...
==> amazon-ebs: Deleting temporary security group...
==> amazon-ebs: Deleting temporary keypair...
==> amazon-ebs: Running post-processor: vagrant
==> amazon-ebs (vagrant): Creating Vagrant box for 'aws' provider
    amazon-ebs (vagrant): Compressing: Vagrantfile
    amazon-ebs (vagrant): Compressing: metadata.json
Build 'amazon-ebs' finished.

==> Builds finished. The artifacts of successful builds are:
--> amazon-ebs: AMIs were created:

ap-northeast-1: ami-36e7ff37
--> amazon-ebs: 'aws' provider box: ./Packer/box/ubuntu-trusty-14.04-amd64-server-for-local.box
$ ls -la Packer/box/
total 8
drwxr-xr-x  3 ***  staff  102  2  1 18:53 .
drwxr-xr-x  4 ***  staff  136  2  1 18:51 ..
-rw-r--r--  1 ***  staff  355  2  1 18:53 ubuntu-trusty-14.04-amd64-server-for-local.box
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
There are errors in the configuration of this machine. Please fix
the following errors and try again:

vm:
* The box 'local-mtburn-20150201' could not be found.

http://stackoverflow.com/questions/27953910/cannot-use-the-box-created-with-packer-post-processor-vagrant に同じ指摘が書いてあります

27
29
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
29