ようへいの日々精進XP

よかろうもん

ゴールデンウィークは終わったけど Packer で SSM Parameter Store に AMI ID を登録するプラグインを作った

tl;dr

皆さん, パカパカパッカーしてますか.

先日に引き続き, Packer で作った EC2 AMI ID を SSM Parameter Store に登録する Post Processor プラグインを作ったので自慢させて下さい.

packer-post-processor-aws-parameter-store

リポジトリ

github.com

Packer テンプレート

パカパカ Packer のテンプレートは以下のような感じになります.

{
  "variables": {
... 略 ...
  },
  "builders": [
... 略 ...
  ],
  "provisioners": [
... 略 ...
   ],
  "post-processors": [
    [
      {
        "type": "aws-parameter-store",
        "parameters": [
          {
            "name": "/my/ami/ami1"
          },
          {
            "name": "/my/ami/ami2",
            "ami_data_type": true
          },
          {
            "name": "/my/ami/ami3",
            "secure_string": true
          }
        ]
      }
    ]
  ]
}

name はパラメータ名を指定します. name のみを指定した場合には, String タイプで登録されます. ami_data_typetrue で指定した場合には, aws:ec2:image データタイプで登録されます. aws:ec2:image データタイプの有用性については, 以下の記事で紹介されていますのでご一読下さい.

dev.classmethod.jp

また, secure_stringtrue に指定することで, SecureString タイプで登録が可能となります.

以下は実行例です.

$ packer build sample.json
amazon-ebs: output will be in this color.

==> amazon-ebs: Prevalidating any provided VPC information
==> amazon-ebs: Prevalidating AMI Name: packer-sample-1588773879
... 略 ...
==> amazon-ebs: Connected to SSH!
==> amazon-ebs: Running local shell script: /var/folders/w_/w3rfn_250g7803h_hkk90jfw0000gn/T/packer-shell172250629
    amazon-ebs: shell-local
==> amazon-ebs: Provisioning with shell script: /var/folders/w_/w3rfn_250g7803h_hkk90jfw0000gn/T/packer-shell497132425
    amazon-ebs: shell
==> amazon-ebs: Stopping the source instance...
    amazon-ebs: Stopping instance
... 略 ...
==> amazon-ebs: Running post-processor: aws-parameter-store
==> amazon-ebs (aws-parameter-store): Register the AMI ID to Parameter Store.(Parameter Name: /my/ami/ami1, AMI ID: ami-xxxxxxxxxxxxxxxxxxx)
==> amazon-ebs (aws-parameter-store): Register the AMI ID to Parameter Store.(Parameter Name: /my/ami/ami2, AMI ID: ami-xxxxxxxxxxxxxxxxxxx)
==> amazon-ebs (aws-parameter-store): Register the AMI ID to Parameter Store.(Parameter Name: /my/ami/ami3, AMI ID: ami-xxxxxxxxxxxxxxxxxxx)

パラメータストアを確認すると, 以下のように登録されていることが確認出来ました.

$ pstore -prefix=/my/ami
+--------------+-----------------------+--------------+---------------+---------+---------------------+
|     NAME     |         VALUE         |     TYPE     |   DATATYPE    | VERSION |  LASTMODIFIEDDATE   |
+--------------+-----------------------+--------------+---------------+---------+---------------------+
| /my/ami/ami1 | ami-xxxxxxxxxxxxxxxxx | String       | text          |       1 | 2020-05-09 12:48:43 |
| /my/ami/ami2 | ami-xxxxxxxxxxxxxxxxx | String       | aws:ec2:image |       1 | 2020-05-09 12:48:44 |
| /my/ami/ami3 | ******************    | SecureString | text          |       1 | 2020-05-09 12:48:44 |
+--------------+-----------------------+--------------+---------------+---------+---------------------+

以上

個人的な HashiCorp 祭りでした.

おまけ

Parameter Store をコマンドラインで操作する pstore というツール作っていますが, ちょっと修正したので v0.0.2 をリリースしました.

github.com

Packer の EC2 Launch Template AMI ID を更新するプラグインを更新した

tl;dr

先日, Packer の Post Processor プラグインとして, EC2 Launch Template の AMI ID を更新するプラグインを作ってみました.

inokara.hateblo.jp

github.com

個人的に複数の Launch Template の AMI ID 一緒に更新したいなーと思っていたので, サポートしてみました.

修正内容

github.com

使い方

インストール手順は, 上記のブログまたはリポジトリの README をご一読下さい.

以下のように Packer テンプレートを書きます.

{
  "variables": {
... 略 ...
  },
  "builders": [
... 略 ...
  ],
  "provisioners": [
... 略 ...
   ],
  "post-processors": [
    [
      {
        "type": "aws-update-launchtemplate-version",
        "templates": [
          {
            "id": "lt-xxxxxxxxxxxxxxxxx1",
            "source_version": "latest",
            "version_description": "foo"
          },
          {
            "id": "lt-xxxxxxxxxxxxxxxxx2",
            "source_version": "latest",
            "version_description": "bar"
          }
        ]
      }
    ]
  ]
}

後は, 従来どおりに packer build xxxx.json を実行すると, 以下のように出力されます.

... 略 ...
==> amazon-ebs: Running post-processor: aws-update-launchtemplate-version
==> amazon-ebs (aws-update-launchtemplate-version): Creating New Launch Template Version (Template ID: lt-xxxxxxxxxxxxxxxxx1 Source Version: 10, AMI ID: ami-xxxxxxxxxxxxxxxxxx)
==> amazon-ebs (aws-update-launchtemplate-version): Creating New Launch Template Version (Template ID: lt-xxxxxxxxxxxxxxxxx2 Source Version: 1, AMI ID: ami-xxxxxxxxxxxxxxxxxx)
... 略 ...

作成された AMI を 2 つの Launch Template の AMI ID として登録することが出来ました.

以上

メモでした.

2020 年 05 月 08 日 (🈲)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

  • 引き続き, 完全休養
  • 引き続き, 安静にしておく
  • 夕方, 奥さんと山王公園を散歩

ギョーム

  • 早朝メンテナンス
  • ウィークリーレポート
  • その他諸々

夕飯

  • 二日目が更に美味しい肉じゃがと煮大根, おいしゅうございました
  • ついでにじゃがバターも食べてじゃがいも三昧な夕飯だった

2020 年 05 月 07 日 (木)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

  • 引き続き, 完全休養
  • 引き続き, 安静にしておく

通院

  • 一ヶ月ぶりの通院
  • 圧迫骨折していたところは固まってきて快方に向かっているとのことで安心した
  • しかし, まだ走るのは止めとけとのことで, ここはグッと堪える必要がありそう
  • アクトネルは週一に変更, 多分, 明日の朝に飲む予定

ギョーム

  • GW 期間中のインフラ状況の確認
  • 各種後片付け
  • 仕組みづくりの為, Bash スクリプトを書いたり
  • 自作のちょっとしたアプリケーションの改修だったり

夕飯

  • 無水鍋で作る肉じゃが, 茅の舎の出汁で炊いた大根, それぞれがとても美味しかった
  • 約一ヶ月ぶりに 350ml の缶ビール (第三類だけど) を飲んだ, 久しぶりなので酔いの周りが強かった

ステイホームなゴールデンウィークなので Packer で EC2 Launch Template の AMI ID を更新するプラグインを作ってみたでごわす

tl;dr

皆さん, 引き続き, ステイホームしてますか, そして, パカパカパッカーしてますか.

Packer で AMI 作って, EC2 Launch Template に登録している AMI を更新するという流れをシームレスにやりたいなーと思って, 見よう見真似で Packer の Post Processor プラグインを作ってみましたのでメモでごわす.

packer-post-processor-aws-update-launchtemplate-version

リポジトリ

github.com

プラグイン名が長くてすいません.

packer-[プラグインタイプ]-[名前]

というのが命名ルールのようなので, 目的をはっきりさせようとしてこのような長ったらしい名前になってしまいました.

Packer テンプレート

パカパカ Packer のテンプレートは以下のような感じになります.

{
  "variables": {
    "aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}",
    "aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}",
    "ssh_keypair_name": "{{env `KEYPAIR_NAME`}}",
    "ssh_private_key_file": "{{env `PRIVATE_KEY_PATH`}}",
    "ami_name": "packer-sample-{{timestamp}}"
  },
  "builders": [
    {
      "type": "amazon-ebs",
... snip ....
    }
  ],
  "provisioners": [
    {
      "type": "shell",
      "inline": [
        "echo 'shell'"
      ]
    }
  ],
  "post-processors": [
    [
      {
        "type": "aws-update-launchtemplate-version",
        "template_id": "lt-xxxxxxxxxxxxxxxxxxxxx",
        "source_template_version": "latest"
      }
    ]
  ]
}

EC2 Launch Template の更新とは, 新しいバージョンを作成することになりますが, このプラグインはテンプレートを 1 から作るのではなく, 既存のテンプレートをコピーして新規作成することを想定しています.

コピー元のテンプレートは最新 (latest), デフォルト (default), 任意のバージョン (バージョン番号) の何れかを指定することになります. 上記の例だと, 最新のテンプレートをコピーして, AMI ID だけを差し替えることになります.

以下は実行例です.

$ packer build sample.json
amazon-ebs: output will be in this color.

==> amazon-ebs: Prevalidating any provided VPC information
==> amazon-ebs: Prevalidating AMI Name: packer-sample-1588773879
... 略 ...
==> amazon-ebs: Connected to SSH!
==> amazon-ebs: Running local shell script: /var/folders/w_/w3rfn_250g7803h_hkk90jfw0000gn/T/packer-shell172250629
    amazon-ebs: shell-local
==> amazon-ebs: Provisioning with shell script: /var/folders/w_/w3rfn_250g7803h_hkk90jfw0000gn/T/packer-shell497132425
    amazon-ebs: shell
==> amazon-ebs: Stopping the source instance...
    amazon-ebs: Stopping instance
... 略 ...
==> amazon-ebs: Running post-processor: aws-update-launchtemplate-version
==> amazon-ebs (aws-update-launchtemplate-version): Creating New Launch Template Version (Template ID: lt-xxxxxxxxxxxxxx Source Version: 1, AMI ID: ami-xxxxxxxxxxxxxxxxxxx)

参考

以下のドキュメントや Github リポジトリを参考にしました.

github.com

github.com

github.com

www.packer.io

qiita.com

以上

参考にさせて頂いたリポジトリのコードを読みながら, 見よう見真似が甚だしいプラグインになりましたが, 先人の方のコードを読むのは大変参考になりました. Go もなかなか初心者を脱することが出来ませんが, 少しだけやれる幅が広がった気がした黄金週間な最終日でごわした.

2020 年 05 月 06 日 (水)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

  • 引き続き, 完全休養
  • 引き続き, 安静にしておく
  • 今日も山王公園を奥さんと散歩

ギョーム

ギョームじゃないけど, 以前から作りたかった Packer の Post Processor プラグインを作った.

github.com

名前は長いけど, EC2 の Launch Template に設定されている AMI を更新する Post Processor プラグインです.

夕飯

  • 奥さんが作った味噌を付けて焼いたサワラが美味しゅうございました

2020 年 05 月 05 日 (🔥)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

  • 引き続き, 完全休養
  • 引き続き, 安静にしておく
  • 山王公園を奥さんと散歩

ギョーム

  • 昨日作った Vagrant Plugin があんまり意味のないものだったので, 改めてブログを書いた

inokara.hateblo.jp

とは言え, mitamae 向けのプラグインも作ってみた.

github.com

Vagrant で抽象化出来るという意味では作る意味はあったのかなって自分を慰めている.

夕飯

  • 手羽元の赤ワイン煮込みが美味しかったし, カボチャのサラダもカボチャの味をしっかりと味わえて良かった

vagrant で同じタイプの Provisioner を複数利用する方法 〜 ちゃんとドキュメントを読みましょう案件 〜

tl;dr

昨日, 以下のようなブロクを認めました. また, vagrant から goss というコマンドラインツールを実行出来るプラグインを作ってみました.

inokara.hateblo.jp

github.com

このプラグインを作ったのは, shell provisioner から実行していた goss を個別に実行したかったからということが理由の一つでした.

  config.vm.provision :shell, inline: <<~BASH
    sudo yum install -y wget httpd && \
     goss --gossfile spec/goss.yaml --vars node.yml validate --format documentation 
  BASH

これを,

  config.vm.provision :shell, inline: <<~BASH
    sudo yum install -y wget httpd && \
  BASH

  config.vm.provision :goss do |goss|
    goss.root_path = '/vagrant'
    goss.spec_file = '/spec/goss.yaml'
    goss.vars_file = '/node.yml'
    goss.goss_path = '/bin/goss'
  end

このように書けば, 以下のように実行出来ることを期待していました.

$ vagrant provision --provision-with=shell # こっちで wget と Apache のインストール
$ vagrant provision --provision-with=goss # こっちで goss の実行

実際に, 上記のように期待する動作を得ることが出来ましたが... なんかモヤモヤした気持ちが残っていました.

モヤモヤ

vagrant のようなプロダクトが

同じ provisioner タイプを複数実行出来ないはずがない.

という気持ちで眠れずに改めてドキュメントを読んでみました.

Basic Usage

ドキュメントの Basic Usage に明記されていました.

www.vagrantup.com

以下, provisioner の基本形です.

Vagrant.configure("2") do |config|
  config.vm.provision "bootstrap", type: "shell", run: "never" do |s|
    s.inline = "echo hello"
  end
end

config.vm.provision のオプションとして, name, type, そして, before, after が指定可能です. 上記のサンプルコードだと, 以下のような値が設定されていることになります.

  • name = bootstrap
  • type = shell

The --provision-with flag can be used if you only want to run a specific provisioner if you have multiple provisioners specified. For example, if you have a shell and Puppet provisioner and only want to run the shell one, you can do vagrant provision --provision-with shell. The arguments to --provision-with can be the provisioner type (such as "shell") or the provisioner name (such as "bootstrap" from above).

上記はドキュメントの一部を抜粋したものですが, --provision-with パラメータの値として指定するのは, name の値を指定する旨, 記載されています. ちなみに, --provision-with パラメータには name 及び type を指定することが可能なようです.

$ vagrant provision --help
Usage: vagrant provision [vm-name] [--provision-with x,y,z]
        --provision-with x,y,z       Enable only certain provisioners, by type or by name.
    -h, --help                       Print this help

やっぱり...

プラグイン作るまでもなかったようです... ということで, 以下のような Vagrantfile を書いて試してみました.

Vagrant.configure('2') do |config|
  config.vm.box = 'centos/7'

  config.vm.provider "virtualbox" do |vb|
     vb.memory = '512'
  end  

  config.vm.provision 'mitamae', type: 'shell' do |s|
    s.inline = <<~BASH
      echo 'Run mitamae!!!'
    BASH
  end

  config.vm.provision 'goss', type: 'shell' do |s|
    s.inline = <<~BASH
      echo 'Run goss!!!'
    BASH
  end
end

以下のように, --provision-withmitamaegoss を切り替えて実行可能なことが確認出来ました.

f:id:inokara:20200505102603g:plain

ということで

ドキュメントはちゃんと読もう案件でした. 昨日作ったプラグインプラグインで細々と育てていこうと思います.

おつかれ, 昨日の自分.

2020 年 05 月 04 日 (🌙)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

  • 引き続き, 完全休養
  • 引き続き, 安静にしておく
  • 山王公園を散歩

ギョーム

inokara.hateblo.jp

夕飯

  • ジャコと新キャベツのペペロンチーノを作った
  • 帆立のバター焼きも作ったけど, サクッと作った割には美味しゅうございました

ステイホームなゴールデンウィークなので Vagrant で goss を実行出来るプラグインを作ってみた

tl;dr

皆さん, ステイホームしてますか.

ちょっと前に久しぶりに EC2 のカスタム AMI を作成するにあたって, Vagrant + vagrant-ec2 + mitamae + goss という組み合わせで実装したりテストをしていました. mitamae でレシピを流して, goss でテストをするという流れです.

github.com

github.com

mitamae も goss も VagrantShell Provisioner で以下のように実行することが出来るのですが, 以下のように goss だけ走らせたい時に面倒だなあという思いがあり Vagrant Plugin 実装の勉強も兼ねて Provisioner プラグインを作ってみました.

$ vagrant provision --provision-with=goss

vagrant-plugin-goss

リポジトリ

github.com

Vagrantfile

goss は Golang で書かれている為, ワンバイナリ化されています. これをダウンロードする為に wget コマンドは必須です.

Vagrant.configure('2') do |config|
  config.vm.box = 'centos/7'

  config.vm.provider "virtualbox" do |vb|
     vb.memory = '512'
  end  

  config.vm.synced_folder '.', '/vagrant',
    disabled: false,
    type: 'rsync',
    rsync__exclude: [
      '.envrc',
      '.ruby-version',
      '.env',
      './tmp/',
      './bk/'
    ]
  config.vm.provision :shell, inline: <<~BASH
    sudo yum install -y wget httpd
  BASH

  config.vm.provision :goss do |goss|
    goss.root_path = '/vagrant'
    # root_path からの絶対パスで指定する #{root_path}/foo/bar であれば, /foo/bar と指定
    goss.spec_file = '/spec/goss.yaml'
    # root_path からの絶対パスで指定する #{root_path}/baz であれば, /baz と指定
    # goss.vars_file = '/vars.yaml'
    # root_path からの絶対パスで指定する #{root_path}/foo/bar であれば, /foo/bar と指定
    goss.goss_path = '/goss'
    # goss の output format を指定する, デフォルトは documentation, junit, json, nagios, rspecish, tap, silent
    # goss.output_format = 'junit'
  end
end

後は, 任意のディレクトリに goss が利用する YAML ファイル (--gossfile オプションで指定するファイル) を用意します.

$ mkdir spec
$ cat << EOF > ./spec/goss.yaml
package:
  httpd:
    installed: true
  wget:
    installed: true
EOF

後は, vagrant up からの vagrant provisionvagrant rsync からの vagrant provision 等, 素敵な vagrant 生活をお送り下さい.

f:id:inokara:20200504164943g:plain

vagrant-plugin-goss 前夜

ちなみに, vagrant-plugin-goss を作る前は, 以下のように Shell Provisioner を書いておりました.

  config.vm.provision :shell, inline: <<~BASH
    cd /vagrant && \
    ./bin/depend.sh && \
    ./bin/mitamae local bootstrap.rb --node-yaml=node.yml #{args}
    ./bin/goss --gossfile spec/goss.yaml --vars node.yml validate --format documentation 
  BASH

この状態で mitamae だけ, goss だけ実行したい場合, いちいち該当行以外をコメントアウトしていました.

Vagrant Plugin の実装について

以下は

このプラグインを作っていく上で学んだことなどを書きます. あくまでも自分の主観で書いているので, 用語の使い方等に誤りがあるかもしれませんがご容赦下さい.

参考

以下のドキュメントや Github リポジトリを参考にしました.

github.com

github.com

www.vagrantup.com

www.vagrantup.com

www.vagrantup.com

plugin.rb が起点になる

以下は lib/vagrant-goss/plugin.rb の抜粋です.

module VagrantPlugins
  module Goss
    class Plugin < Vagrant.plugin('2')
      name 'goss'
      description <<-DESC
      This plugin executes a goss suite against a running Vagrant instance.
      DESC

      config(:goss, :provisioner) do
        require_relative 'config'
        Config
      end

      provisioner(:goss) do
        require_relative 'provisioner'
        Provisioner
      end
    end
  end
end

プラグインにとって, ここが起点になり, 今回は Provisioner プラグインとなるので, configprovisioner のブロックを定義します. 個々のブロックで require_relative の引数に指定している configprovisioner をコツコツと書いていくことになります.

ちなみに configprovisioner 以外にも command 等も用意されています. commandについては,vagrant xxxx` と実行する際に実行されるコマンド等を定義出来るのかなーと予想しています.

config.rb

以下は lib/vagrant-goss/config.rb の抜粋です.

module VagrantPlugins
  module Goss
    class Config < Vagrant.plugin('2', :config)
      attr_accessor :output_format
      attr_accessor :spec_file
... 略 ...
      def initialize
        super
        @output_format = UNSET_VALUE
        @spec_file = UNSET_VALUE
... 略 ...
      def finalize!
        @output_format = 'documentation' if @output_format == UNSET_VALUE
        @spec_file = 'goss.yaml' if @spec_file == UNSET_VALUE
 ... 略 ...

attr_accessor しているのは, Vagrantfile で以下のように (goss.root_path とか) 書くためですよね. (多分

  config.vm.provision :goss do |goss|
    goss.root_path = '/vagrant'
    # root_path からの絶対パスで指定する #{root_path}/foo/bar であれば, /foo/bar と指定
    goss.spec_file = '/spec/goss.yaml'
... 略 ...

provisioner.rb

以下は lib/vagrant-goss/provisioner.rb の抜粋です.

... 略 ...
module VagrantPlugins
  module Goss
    class Provisioner < Vagrant.plugin('2', :provisioner)
... 略 ...
      def provision
        vars_option = "--vars #{@vars_file} " unless @vars_file.nil?
        run = "#{@goss_path} --gossfile #{@spec_file} " +
              "#{vars_option} " +
              "validate " +
              "--format #{@output_format} --color" 
        run_command(run) if download_goss(@goss_path)
      end 

goss 実行時の出力を Vagrant 標準の出力 (以下のように, 標準出力の場合には緑で表示されたり, default: が行頭につくようにする) にする為に試行錯誤しました.

f:id:inokara:20200504163530p:plain

結局, Vagrant Shell Provisioner のソースコードを参考 (そのまま利用) させて頂きました. 以下の部分です.

      # refer to: https://github.com/hashicorp/vagrant/blob/master/plugins/provisioners/shell/provisioner.rb#L67-L81
      def handle_comm(type, data)
        if [:stderr, :stdout].include?(type)
          # Output the data with the proper color based on the stream.
          color = type == :stdout ? :green : :red

          # Clear out the newline since we add one
          data = data.chomp
          return if data.empty?

          options = {}
          options[:color] = color if !config.keep_color

          machine.ui.detail(data.chomp, options)
        end
      end

ドキュメントにも書かれていました.

Most plugins are likely going to want to do some sort of input/output. Plugins should never use Ruby's built-in puts or gets style methods. Instead, all input/output should go through some sort of Vagrant UI object. The Vagrant UI object properly handles cases where there is no TTY, output pipes are closed, there is no input pipe, etc.

  • puts 等の Ruby 標準の入出力メソッドは使ってはいけない
  • 代わりに Vagrant が提供している UI オブジェクトを利用する必要がある
  • UI オブジェクトは ui プロパティを介して, すべての Vagrant::Environment で使用することが出来る

以上

ステイホームで素敵なインフラストラクチャアズコードな生活をお送り下さい.