概要
Packerは、EC2のAMIを決められた設定・手順でプロビジョニングして作成することができ、ベースとなるAMIの作成手順をコードに残すことができるため、AMI管理において便利なツールである。
PackerでEC2のAMIを作成するときは以下の流れで処理される。(※communicatorにsshを選択している場合)
-
packer build
コマンドでJSONで記述された設定ファイルを元にAMI作成が始まる - 与えたAWS_ACCESS_KEYを使ってAWS上に「Packer Builder」というEC2インスタンス(Builder)を作成する
- Builderが指定されたベースのAMIでEC2インスタンスを立ち上げる
- そのインスタンスに対してプロビジョニングを行う
- 完了したらそのインスタンスをAMIに保存する
- Builderインスタンスがterminateされる
4の手順では、BuilderインスタンスからベースのAMIにsshログインを行って、AMI上でシェルスクリプトやAnsibleを実行する。
特にSSHログインの対象ユーザの情報を何も指定せずビルドする場合は、AWS EC2だと一般ユーザ(Amazon Linuxであればec2-user)に対して、Packerが自動でkey-pairを発行してそのkey-pair情報を元に一般ユーザに対してsshログインを行う。
困りポイント
一般ユーザでsshログインしてプロビジョニングが行う、のところで困るケースが発生した。
provisoners
でシェルスクリプト("type": "shell"
)によるプロビジョニングを行う場合、シェルスクリプト内でsudo
を指定しておけばrootユーザでコマンドを実行してくれるので問題にはならない。
しかし、ファイルの転送("type": "file"
)の場合ではrootユーザで実行するようなオプションを指定できず、一般ユーザで処理を行うことになる。
例えば、Nginxの設定ファイル(/etc/nginx/nginx.conf
)等を扱う場合はrootユーザで実行しないと、Not Permissionでエラーになるケースが発生する。そもそもプロビジョニングはrootユーザで処理したいことが大半だと思われるので、基本的にrootユーザでログインしてプロビジョニング処理を進めたいという気持ちになる。
対応
rootユーザでsshログインしてAMIをビルドするには以下の流れで対応する。
- 適切なOSなどを選択したEC2インスタンスを用意する
- そのインスタンス上で、rootユーザの
authorized_keys
に公開鍵を登録する - そのインスタンスのAMIを保存する
- packerの設定ファイルに
builders.ssh_username
とssh_private_key_file
を記述する
簡単に言うと、1~3の手順でrootユーザにsshログインできる鍵のペアを用意し、Builderインスタンスがプロビジョニング時にsshログインするときにその鍵を使ってrootユーザにsshログインする、という算段である。
手順4
手順1~3については特別なことを行うわけではないので割愛し、手順4がミソなので具体的に説明する。
-
ssh_username
: Builderインスタンスからsshログインする対象のユーザ -
ssh_private_key_file
: Builderインスタンスからsshログインする際に用いる暗号鍵のパス
を設定することができる。
例えば暗号鍵private_key
と公開鍵public_key.pub
があり、1~3の手順で作成したAMIにはpublic_key.pub
を登録しておいたとした場合、
{
...
"builders": [{
...
"communicator": "ssh",
"source_ami": "<1~3の手順で作成したAMI ID>",
"ssh_username": "root",
"ssh_private_key_file": "/home/some_user/.ssh/private_key",
...
}],
...
}
とすればrootユーザでsshログインするようになる。
設定例
以上を総括して、設定例としては以下のようなものになる(あくまで一例ということで)。
{
"variables": {
"aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}",
"aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}",
"ssh_private_key_file": "{{env `SSH_PRIVATE_KEY_FILE`}}"
},
"builders": [{
"type": "amazon-ebs",
"access_key": "{{user `aws_access_key`}}",
"secret_key": "{{user `aws_secret_key`}}",
"region": "ap-northeast-1",
"source_ami": "ami-b5ff24d3",
"instance_type": "t2.micro",
"ssh_username": "root",
"ssh_private_key_file": "{{user `ssh_private_key_file`}}",
"ssh_timeout": "3m",
"ami_name": "my_ami {{timestamp}}"
}],
"provisioners": [
{
"type": "shell",
"execute_command": "chmod +x {{ .Path }}; sudo {{ .Vars }} {{ .Path }}",
"scripts": [
"scripts/app.sh"
]
},
{
"type": "file",
"source": "nginx.conf",
"destination": "/etc/nginx/nginx.conf"
}
]
}
この設定ファイル(sample.json
という名前で保存されているとする)を使い、ビルドする。
$ export SSH_PRIVATE_KEY_FILE=/user/some_user/.ssh/private_key; export AWS_...; packer build sample.json
これで/etc/nginx/nginx.conf
が設置できた。