この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
TerraformのChef Provisionerの機能を使うと、Terraformで構築したサーバーに対してChefでプロビジョニングを実行することができます。(AWS環境であれば「EC2の起動 → EC2にChef Clientをインストール → レシピの実行」までを自動化することができます)
今回は AWS OpsWorks for Chef Automateを使ってこのChef Provisionersを実行する方法をご紹介します。
AWS OpsWorks for Chef Automateのセットアップ
セットアップ手順は以下のブログエントリを参照ください。
[速報]AWS OpsWorks For Chef Automateが発表されました #reinvent | Developers.IO
CredentialsとStarter Kitのダウンロード
セットアップウィザードの最後の画面で以下の2つをダウンロードします。 - Credentials - Starter Kit
CredentialsにはChef Automate DashboardへログインするためのログインIDとパスワード情報が含まれています。これは後から再ダウンロードできませんので、このタイミングで必ずダウンロードしておきましょう。
Starter KitはChef Automate server用にカスタマイズされたknife.rb(knifeコマンドのconfigファイル)や、Chef Automate serverにアクセスするためのプライベートキー(private.pem)などが含まれたchef-repo(chefのレポジトリ)です。このStarter Kitを使うことで、Chef Automate serverを利用するための事前準備の手間を大幅に省くことができます。
Starter Kitも再ダウンロードはできませんが、再作成することは可能です。ただし再作成するとプライベートキーも新しいものに置き換わってしまうのでご注意ください。
セキュリティグループ
セットアップウィザードで作成されるセキュリティグループではHTTP(80)とSSH(22)が全ての接続元に対して許可されています。実運用時は接続元のIPアドレスで制限をかけた方がよいでしょう。
Starter Kitの中身
Starter Kitについてもう少し詳しくみていきます。ダウンロードしたstarter_kit.zipを解凍すると、「my-chef-server-ak8xxxxxxxxxxxxx」といった名称のフォルダが展開されます。ディレクトリ構成は以下のようになっています。
.
├── .chef
│ ├── ca_certs
│ │ └── opsworks-cm-ca-2016-root.pem
│ ├── knife.rb
│ └── private.pem
├── Berksfile
├── README.md
├── chefignore
├── cookbooks
│ └── README.md
├── environments
│ └── README.md
├── roles
│ └── README.md
└── userdata.sh
Berksfile、cookbooks、environments、rolesなど、chefで利用するファイルやディレクトリが一式含まれています。
.chef/knife.rb
の中身は以下のようになっています。
base_dir = File.join(File.dirname(File.expand_path(__FILE__)), '..')
log_level :info
log_location STDOUT
node_name 'pivotal'
client_key File.join(base_dir, '.chef', 'private.pem')
syntax_check_cache_path File.join(base_dir, '.chef', 'syntax_check_cache')
cookbook_path [File.join(base_dir, 'cookbooks')]
chef_server_url 'https://my-chef-server-ak8xxxxxxxxxxxxx.us-west-2.opsworks-cm.io/organizations/default'
ssl_ca_file File.join(base_dir, '.chef', 'ca_certs', 'opsworks-cm-ca-2016-root.pem')
trusted_certs_dir File.join(base_dir, '.chef', 'ca_certs')
chef_server_url
には構築したChef Automate serverのエンドポイントがセットされていますので、このStarter Kitディレクト内でknifeコマンドを実行すれば先ほど構築したChef Automate serverに対して操作が行われる、というわけです。
ただしTerraformはこのknife.rbの設定を参照してくれませんので、後述の通りTerraformのテンプレートファイルでChef Automate serverのエンドポイント、Chef Automate serverに接続するためのユーザー名、プライベートキーを指定する必要があります。
Workstationの準備
手元の端末にChef Development Kitをインストールします。各OS毎にパッケージが用意されていますので簡単にインストールすることができます。
macOSの場合はHomebrew Caskでインストールすることも可能です。
$ brew cask install chefdk
Cookbookのアップロード
TerraformからChef Provisionerを実行する準備として、あらかじめChef Automate serverにcookbookをアップロードしておきます。今回はnginxをインストールするだけのcookbookを用意して、それをアップロードします。
cookbookの作成
Starter Kitディレクト内でknife cookbook create
コマンドを実行しcookbookの雛形を作成します。
$ knife cookbook create nginx -o cookbooks
cookbook/nginx/recipes/default.rb
に以下のようなnginxインストール用のレシピを記述します。
package "nginx" do
action :install
end
service "nginx" do
action [:enable, :start]
end
Chef Automate serverへのcookbookのアップロード
Starter Kitディレクト内でknife cookbook upload
コマンドでChef Automate serverへ作成したcookbookをアップロードします。
$ knife cookbook upload nginx
knife cookbook list
コマンドでcookbookがアップロードされたことを確認します。
$ knife cookbook list
TerraformでEC2の起動&Chef Provisionerを実行
今回は以下のようにStarter Kitディレクトリと同じ階層にTerraformのテンプレートファイルを準備しました。
├── main.tf
├── my-chef-server-ak8xxxxxxxxxxxxx
└── variables.tf
テンプレートファイルの全体はこちらを参照ください。
以下はaws_instance
リソース部分の抜粋です。
resource "aws_instance" "web_server" {
count = 1
ami = "${data.aws_ami.amazon_linux.id}"
instance_type = "t2.nano"
key_name = "${var.ssh_key_name}"
vpc_security_group_ids = [
"${aws_security_group.external_ssh.id}",
"${aws_security_group.web_server.id}",
]
subnet_id = "${element(aws_subnet.external.*.id, count.index)}"
associate_public_ip_address = true
root_block_device = {
volume_type = "gp2"
volume_size = "20"
}
iam_instance_profile = "${aws_iam_instance_profile.web_server.name}"
monitoring = false
disable_api_termination = false
tags {
Name = "${var.name}-${format("web_server-%02d", count.index+1)}"
Environment = "${var.environment}"
}
provisioner "chef" {
connection {
host = "${self.public_ip}"
type = "ssh"
user = "ec2-user"
private_key = "${file(var.ssh_key_file)}"
}
environment = "_default"
run_list = ["nginx::default"]
node_name = "${var.name}-${format("web_server-%02d", count.index+1)}"
server_url = "https://my-chef-server-ak8xxxxxxxxxxxxx.us-west-2.opsworks-cm.io/organizations/default"
recreate_client = true
user_name = "pivotal"
user_key = "./my-chef-server-ak8xxxxxxxxxxxxx/.chef/private.pem"
fetch_chef_certificates = true
}
}
provisioner
にchefを指定します。その他指定が必要な項目は以下の通りです。
設定項目 | 説明 | 備考 |
---|---|---|
node_name | Chef Automate serverに登録するノード名 | 任意の名前を指定 |
run_list | 実行するレシピ | |
server_url | Chef Automate serverのURL | |
user_name | Chef Automate serverのユーザー名 | Chef Automate serverにノードを登録するために必要 |
user_key | Chef Automate serverの認証用のプライベートキー |
今回user_name
にはChef Automate serverのスーパーユーザーであるpivotal
を指定しました。
Chef Automate serverのSSL証明書は自己署名証明書のため、fetch_chef_certificates = true
を指定してChef Automate serverの証明書をクライアントの/etc/chef/trusted_certs
にダウンロードするようにします(これを指定しないと証明書のバリデーションに失敗します)。
実行結果
Chef AutomateのDashboardにアクセスすると、nodeが追加されていることが確認できます。
なお、terraform destroy
でEC2を削除してもChef server側のノード情報は削除されないのでご注意ください。
まとめ
AWS OpsWorks for Chef Automateを使えばChef Serverを簡単に使い始めることができます。Terraform + Chef、ぜひお試しください。
ちなみにTerraformではリモートサーバー上で任意のコマンドを実行できるremote-execというprovisionerも利用できます。興味ある方は以下のブログエントリを参照ください。