最近はAWSのAMIやECSでコンテナたてる時に使うDocker ImageをPackerで作成している @hatappiです
Packerを使うとAMIにしてもDocker Imageにしても自分の好きなプロビジョニングを使用することが出来るので好きです
今回は例えば元となるdocker imageにはrbenv/rbenvがインストールされており
.bashrcなり/etc/profile.d/rbenv.shなりに下記のようにPATHが定義されているものがあるとします
export RBENV_ROOT=/usr/local/rbenv
export PATH="${RBENV_ROOT}/bin:${PATH}"
eval "$(rbenv init -)"
このImageをPackerで使ってbundle installしたイメージを作るとする
bundle.manifest.json
{
"builders":[{
"type": "docker",
"image": "hatappi/rbenv-app",
}],
"provisioners": [
{
"type": "shell",
"inline": [
"bundle install --gemfile=/app/Gemfile"
]
}
],
"post-processors": [
[
{
"type": "docker-import",
"repository": "hatappi/hoge",
"tag": "latest"
}
]
]
}
これを単純に実行してしまうと bundle: command not found というエラーで起きてしまう
これは単にパスが通ってないだけなので下記のようにsourceでPATHが定義されたものを読みこんであげれば解決する
"provisioners": [
{
"type": "shell",
"inline": [
"source /etc/profile.d/rbenv.sh",
"bundle install --gemfile=/app/Gemfile"
]
}
],
ここからが本題でこれの別解としてPackerのオプションを利用していく
まず
{
"type": "shell",
"inline": [
"bundle install --gemfile=/app/Gemfile"
]
}
を行うとPackerではどうなるかというとまずコンテナ上に/tmp/script_6464.shのような一時ファイルを作成します
中身としては
#!/bin/sh -e bundle install --gemfile=/app/Gemfile
となっておりこれをPacker側で下記のようにdocker execを使って実行している
docker exec -i aaaaa /bin/sh -c (chmod +x /tmp/script_6464.sh; PACKER_BUILDER_TYPE='docker' PACKER_BUILD_NAME='docker' /tmp/script_6464.sh):
ここまでくるとなんとなく見えてくる
一時ファイルとして作成されたシェルファイルの1行目のshebangを変更してあげれば良い
type: “shell”のドキュメントを見るとinline_shebangというそれらしいオプションがある!!
これを使って
{
"type": "shell",
"inline": [
"bundle install --gemfile=/app/Gemfile"
],
"inline_shebang": "/bin/sh -le"
}
こんな感じで書いてあげる
-lを追加することでログインしたときのようにbashで実行することが出来るのでPATHなども読み込まれた状態で実行することが出来る
どちらを使っても実現は出来たがPackerの挙動が知れたので良かったとします
投稿日:May 18th 2017