11
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ローカル環境でAmazon Linuxをテストする

Last updated at Posted at 2017-01-13

はじめに

可搬性(ポータビリティ)に立ちふさがる密林、Amazon Linux。担当プロジェクトでもご多分に漏れず、Amazon LinuxをOSとしたシステムを組んでいます。
chefを用いて構成管理(商用環境は、OpsWorks)、Test Kitchen + ServerspecでインフラテストしているがOSはCentOS6.7(packerで生成したVagrant box)...OSが違うのに、何が構成管理か、何が可搬性か。
AWS公式のDockerイメージもリリースされたことですし、Dockerを武器にローコストで可搬性を手に入れることが出来ると思い立ったが吉日。
1営業日くらいで可搬性のあるインフラテスト環境を手に入れることが出来ました :dragon_face:

変更のサマリ

- OpsWorks用cookbook ローカル環境用cookbook Test KitchenでプロビジョニングするホストのOS Test Kitchenのドライバ 初回のテスト完了までの所要時間
ビフォー example example_local CentOS6.7 Vagrant 20分程度
アフター example - Amazon Linux Docker 5分程度

主たる変更は、kitchen-dockerを導入し、Test KitchenのドライバとしてDockerを採用したことです。
変更により、以下のメリットを享受出来るようになりました。

  • cookbookの統一
  • プロビジョニング対象ホストのOSをOpsWorksと合わせることが出来る
  • 初回テスト時の所要時間の短縮

以下で、詳細を記載していきます。

ビフォー

before.png

  1. exampleアプリケーションを稼働させるためのcookbook(example)を開発する
    • OpsWorksを利用しているので、リポジトリ直下にcookbookを配置する必要がある
  2. example cookbookをTest Kitchenで稼働させるために、example_localを開発する
    • example::defaultをincludeし、attributeを上書きするcookbook
  3. Serverspecでテストコードを開発する
    • Test Kitchenにも対応するので、example_localに配置
  4. Test Kitchenでexample cookbookの動作確認とテストを実施
    • プロビジョニング:bundle exec kitchen converge default-example
    • テスト:bundle exec kitchen verify default-example
  5. テストが通ったら、packerに対応させる
    • packer/example.jsonを開発し、cookbookと一緒にAtlasにアップロード
    • AtlasのpackerでVagrant boxを生成する(リモートビルド)
  6. 開発担当者がAtlasからVagrant boxをダウンロードし、exampleアプリケーションを開発

...だるい

設計し、実装を終えた当初は、堅牢で素晴らしいワークフローだと思ったものです。
このケースの課題は

  • cookbook開発のオーバーヘッドが無視できない
    • cookbookの見通しが悪い。_localって何??
    • Atlasは、日本の日勤帯の時間は、ネットワーク帯域を絞っているのでboxのダウンロードが激重
  • attributeでパッケージ名を上書きしている
    • OSが異なることが諸悪の根源
  • 学習コストが結構かかる
    • chefとServerspecは必要経費だとしても、Test Kitchen、Vagrant、Packer、Atlas....

ゴールデンイメージなVagrant boxを中心に添えたワークフローは、堅牢ですがミドルウェアのアップデートのスピードには着いていくことが難しいというのが個人的な印象です。

アフター

after.png

  1. exampleアプリケーションを稼働させるためのcookbook(example)を開発する
    • OpsWorksを利用しているので、リポジトリ直下にcookbookを配置する必要がある
  2. Serverspecでテストコードを開発する
    • Test Kitchenにも対応するので、テストコードはexample cookbookに配置
  3. Test Kitchenでexample cookbookの動作確認とテストを実施
    • Test Kitchenのドライバとして、Dockerを指定
    • kitchen-dockerでAmazon LinuxのイメージをPULLし、example cookbookをプロビジョニング
    • プロビジョニング:bundle exec kitchen converge default-example
    • テスト:bundle exec kitchen verify default-example
  4. テストが通ったら、リモートリポジトリにPUSH
  5. OpsWorksのスタックをsetupし、AWS上のインフラをプロビジョニング

cookbook開発だけでなく、アプリケーションのローカル開発環境の見直しも併せて行った(Dockerの導入)ので、かなりシンプルはワークフローとなりました。
メリットをまとめると

  • 同一のOSに対してプロビジョニングし、テスト出来る
    • AWS公式Dockerイメージに対してプロビジョニングした結果をテスト出来る
  • コードベースがシンプルになる
    • example_local cookbookを破棄することが出来る
  • cookbook開発に注力出来る
    • 以前に比べて、学習費用対効果が良い
    • 必要経費(chef、Serverspec)のみで開発出来る

Tips

導入に際してのポイントをコードを交えて説明してみます。

kitchen-dockerの導入

gemのインストール

kitchen-dockerというgemが必要になりますので、Gemfileに追記しましょう。
Kitchen-vagrantは不要となりますので、削除しました。

source "https://rubygems.org"

gem "chef"
gem "berkshelf"
gem "test-kitchen"
gem "kitchen-docker"

Gemfileの編集が終わったらbundlerでインストールします。

bundle install --path ./vendor/bundle

.kitchen.ymlの編集

kitchen-dockerのREADMEを参考に、Test Kitchenの設定ファイルを編集していきます。

provisioner:
  name: chef_solo
  environments_path: ../environments
  solo_rb:
    environment: local

Test KitchenのドライバとしてDockerを指定します。sudoするとdockerコマンドへのパスが見つからない場合が多いかと思うので、use_sudo: falseと指定しておきます。
OpsWorks環境とは異なるattributeがあれば、environmentsとしてJSON形式のファイルにまとめておくことをおすすめします。

platforms:
  - name: amazonlinux-201609
    driver_config:
      platform: rhel
      image: amazonlinux:2016.09

name要素でプロビジョニング対象のホストの名前を指定します。
Amazon Linuxは、Test Kitchenの分類ではRHEL系のディストリビューションとなるので、platform: rhelと指定します。
image要素で、Dockerレジストリから取得したいイメージを指定します。OpsWorks環境のOSバージョンと合わせるため、image: amazonlinux:2016.09と指定します。

suites:
  - name: default
    run_list:
      - recipe[example::amazonlinux-local]
      - recipe[example::default]
    attributes:

テストしたいrecipeをリストします。
amazonlinux-localというレシピについては、後述します。

上記をまとめると、以下の様な.Kitchen.ymlとなります。

---
driver:
  name: docker
  use_sudo: false

provisioner:
  name: chef_solo
  environments_path: ../environments
  solo_rb:
    environment: local

platforms:
  - name: amazonlinux-201609
    driver_config:
      platform: rhel
      image: amazonlinux:2016.09

suites:
  - name: default
    run_list:
      - recipe[example::amazonlinux-local]
      - recipe[example::default]
    attributes:

amazonlinuxの導入

amazonlinuxは、AWS公式のDockerイメージですが、AWS環境と全く同一のものではありません。あくまでも、可搬性の観点で現状取りうる手段の中で最もAWS環境で稼働するAmazon Linuxに近い仮想環境です。
そのため、AWS環境との差異(OSの初期設定含む)については、自分たちで対応する必要があります。
私達のチームでは、差異を埋めるrecipeを開発して対応しました。

# sysconfigファイル
default[:sysconfigs] = ['i18n', 'network']

システム設定ファイル(/etc/sysconfig)の差異をattributeにまとめ、templateとして配置しておきます。

$ tree /path/to/example/example/templates/default/
/path/to/example/example/templates/default/
├── i18n.erb
├── config.erb
└── network.erb
# ローカル開発環境(Amazon LinuxのDockerイメージ)でのレシピ開発のための各種ファイルの配置
node[:sysconfigs].each do |sysconfig|
  template "/etc/sysconfig/#{sysconfig}" do
    owner "root"
    group "root"
    mode 0644
    not_if { File.exist?("/etc/sysconfig/#{sysconfig}") }
  end
end

配置したtemplateを上記の様なrecipeでプロビジョニングしていきます。

# SELinuxは明示的にDisable
include_recipe 'selinux'
template "/etc/selinux/config" do
  owner "root"
  group "root"
  mode 0644
  not_if { File.exist?("/etc/selinux/config") }
end

これは、テストのためのプロビジョニングです。
ServerspecでSELinuxの設定をテストしているのですが、/etc/selinux/configファイルが必須の内容となっておりましたので、ローカル環境でのrecipe開発のためだけにプロビジョニングしています。

# peclを利用するのでコンパイラをインストール
package "gcc"

gccがインストールされておりませんので、テスト対象のrecipeをプロビジョニングする前にインストールしておきます。

上記をまとめると、以下の様なrecipe(amazonlinux-local.rb)となります。
このrecipeをテスト対象のrecipe(example::default)の前にプロビジョニングします(前述の.kitchen.yml参照)。

# Cookbook Name:: example
# Recipe:: amazonlinux-local

# ローカル開発環境(Amazon LinuxのDockerイメージ)でのレシピ開発のための各種ファイルの配置
node[:sysconfigs].each do |sysconfig|
  template "/etc/sysconfig/#{sysconfig}" do
    owner "root"
    group "root"
    mode 0644
    not_if { File.exist?("/etc/sysconfig/#{sysconfig}") }
  end
end

# SELinuxは明示的にDisable
include_recipe 'selinux'
template "/etc/selinux/config" do
  owner "root"
  group "root"
  mode 0644
  not_if { File.exist?("/etc/selinux/config") }
end

# peclを利用するのでコンパイラをインストール
package "gcc"

Test Kitchen

kitchen-dockerの導入を紹介してきましたが、Test Kitchenのコマンド集をまとめておきます。

# cookbookのディレクトリに移動
$ cd /path/to/example/example

# インスタンスの確認
$ bundle exec kitchen list
Instance                    Driver  Provisioner  Verifier  Transport  Last Action  Last Error
default-amazonlinux-201609  Docker  ChefSolo     Busser    Ssh        Verified     <None>

# インスタンスを作成
$ bundle exec kitchen create default-amazonlinux-201609

# インスタンスのセットアップ
$ bundle exec kitchen converge default-amazonlinux-201609

# インスタンスへログイン(tty)
$ bundle exec kitchen login default-amazonlinux-201609
Last login: Thu Jan  5 20:23:42 2017 from 172.17.0.1
[kitchen@685fdd7c1349 ~]$
[kitchen@685fdd7c1349 ~]$ pwd
/home/kitchen

# テスト(serverspec)の実行
$ bundle exec kitchen verify default-amazonlinux-201609

# インスタンスの破棄
% bundle exec kitchen destroy default-amazonlinux-201609

おわりに

OpsWorksを導入して以来、Amazon Linuxをどうテストするかという課題を抱えていましたが、AWS公式のDockerイメージが提供されたことにより、ローコストで可搬性のあるテストを実施出来るようになりました。
今後の課題は、プロビジョニングをCIすることを目標に必要なライブラリの導入や開発、変更を加えて行きたいと思います。
増え続けるcookbookや優秀なchefの育成に困っている開発チームの課題解決の一助となれば幸いです。

参考

11
14
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
11
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?