これはなんですか
- PackerでCompute Engineのマシンイメージを作ってみたので、作業記録を残します。
- Docker/Kubernetes の時代になって、初めてイメージを焼きました。
つくりたいもの
- Embulkが動作するGCE VM Machine Image
- Embulk用にユーザーを作成する
- とりあえずsudoerが
sudo su - embulk
でユーザーを切り替えられる様な状態にする- 発展形として、外部ユーザーが
embulk
コマンドの実行やプラグインのインストールをできるようにしたい。
- 発展形として、外部ユーザーが
作業記録
作業環境
- MacBook Pro
-
brew install packer
でPackerをインストールする
-
- Cloud Shell
-
gcloud project config set [YOUR PROJECT NAME]
でプロジェクトを指定しておく。
-
サービスアカウント作成
Packer の Google Compute Builder ページ
https://www.packer.io/docs/builders/googlecompute.html
Cloud IAM 役割について
https://cloud.google.com/iam/docs/understanding-roles
雑に↓を振ってみる
- roles/compute.networkUser
- roles/compute.instanceAdmin.v1
- roles/iam.serviceAccountUser
Cloud Shell上でサービスアカウント packer
を作成する。
https://cloud.google.com/iam/docs/creating-managing-service-accounts?hl=ja#iam-service-accounts-create-gcloud
$ gcloud beta iam service-accounts create packer --description "Allow to build Compute Engine images (for Packer)"
作成したサービスアカウントに役割を付与する。
https://cloud.google.com/iam/docs/granting-roles-to-service-accounts?hl=ja#granting_access_to_a_service_account_for_a_resource
$ gcloud projects add-iam-policy-binding [YOUR_PROJECT_ID] --member serviceAccount:packer@[YOUR_PROJECT_ID].iam.gserviceaccount.com --role roles/compute.networkUser
$ gcloud projects add-iam-policy-binding [YOUR_PROJECT_ID] --member serviceAccount:packer@[YOUR_PROJECT_ID].iam.gserviceaccount.com --role roles/compute.instanceAdmin.v1
$ gcloud projects add-iam-policy-binding [YOUR_PROJECT_ID] --member serviceAccount:packer@[YOUR_PROJECT_ID].iam.gserviceaccount.com --role roles/iam.serviceAccountUse
キーの発行
サービスアカウントはできたので、キーを発行する。Cloud Shell 上でキーを発行してローカルに落とす。
https://cloud.google.com/iam/docs/creating-managing-service-account-keys?hl=ja#creating_service_account_keys
$ gcloud iam service-accounts keys create ~/key.json \
--iam-account packer@[YOUR_PROJECT_ID].iam.gserviceaccount.com
created key [0fa7b041fb670319ec3400f0432e7f0e13af4425] of type [json] as [/home/username/key.json] for [packer@[YOUR_PROJECT_ID].iam.gserviceaccount.com]
Packer ファイル作成
まとめた。
https://github.com/Hikosaburou/packer_gce_embulk
{
"project_id": "[YOUR_PROJECT_ID]",
"image_family": "debian-9",
"account_file_path": "{{ env `GOOGLE_APPLICATION_CREDENTIALS` }}"
}
{
"builders": [
{
"type": "googlecompute",
"account_file": "{{user `account_file_path`}}",
"project_id": "{{user `project_id`}}",
"source_image_family": "{{user `image_family`}}",
"ssh_username": "packer",
"zone": "asia-northeast1-a",
"image_family": "{{user `image_family`}}",
"image_name": "embulk-{{user `image_family`}}-{{timestamp}}"
}
],
"provisioners": [
{
"type": "shell",
"script": "install_embulk.sh"
}
]
}
#!/bin/bash -ex
sleep 5
sudo sed -e 's/APT::Periodic::Update-Package-Lists "1";/APT::Periodic::Update-Package-Lists "0";/' \
-e 's/APT::Periodic::Unattended-Upgrade "1";/APT::Periodic::Unattended-Upgrade "0";/' \
/etc/apt/apt.conf.d/20auto-upgrades -i
sudo apt-get update -y
sudo apt-get install default-jdk -y
sudo adduser --disabled-password --gecos '' embulk
sudo curl --create-dirs -o /home/embulk/.embulk/bin/embulk --silent -L "https://dl.embulk.org/embulk-latest.jar"
sudo chmod +x /home/embulk/.embulk/bin/embulk
echo 'export PATH="$HOME/.embulk/bin:$PATH"' >> ~/tmp_bashrc
sudo sh -c "cat ${HOME}/tmp_bashrc >> /home/embulk/.bashrc"
sudo chown -R embulk:embulk /home/embulk/
rm ~/tmp_bashrc
sudo su - embulk <<EOF
/home/embulk/.embulk/bin/embulk gem install embulk-input-sqlserver
/home/embulk/.embulk/bin/embulk gem install embulk-output-bigquery
EOF
install_embulk.sh内の sudo apt-get update -y
はなんとも微妙。。。でも進める。
Packer コマンドでローカルからビルドする:
$ packer build --var-file=variables.json embulk.json
googlecompute output will be in this color.
==> googlecompute: Checking image does not exist...
==> googlecompute: Creating temporary SSH key for instance...
==> googlecompute: Using image: debian-10-buster-v20191121
==> googlecompute: Creating instance...
googlecompute: Loading zone: asia-northeast1-a
googlecompute: Loading machine type: n1-standard-1
googlecompute: Requesting instance creation...
googlecompute: Waiting for creation operation to complete...
googlecompute: Instance has been created!
==> googlecompute: Waiting for the instance to become running...
googlecompute: IP: 34.84.207.9
==> googlecompute: Using ssh communicator to connect: 34.84.207.9
==> googlecompute: Waiting for SSH to become available...
==> googlecompute: Connected to SSH!
==> googlecompute: Provisioning with shell script: install_embulk.sh
==> googlecompute: + sleep 5
==> googlecompute: + sudo sed -e 's/APT::Periodic::Update-Package-Lists "1";/APT::Periodic::Update-Package-Lists "0";/' -e 's/APT::Periodic::Unattended-Upgrade "1";/APT::Periodic::Unattended-Upgrade "0";/' /etc/apt/apt.conf.d/20auto-upgrades -i
...
==> googlecompute: Deleting instance...
googlecompute: Instance has been deleted!
==> googlecompute: Creating image...
==> googlecompute: Deleting disk...
googlecompute: Disk has been deleted!
Build 'googlecompute' finished.
==> Builds finished. The artifacts of successful builds are:
--> googlecompute: A disk image was created: embulk-debian-9-1575458143
通った。
失敗の記録
主にシェルスクリプト力の欠如による失敗の記録。
実行するコマンドも出力したい
Shell Provisionerのドキュメントに書いてあった。
https://www.packer.io/docs/provisioners/shell.html
スクリプトのシェバン(shebang)に -x
をつけよ、とのこと。
#!/bin/bash -ex
inline
パラメータでコマンドを渡している場合は inline_shebang
で渡してあげれば良いらしい。
curl の出力を省略したい
--silent
オプションをつければ、↓みたいなのが出なくなる.
==> googlecompute: % Total % Received % Xferd Average Speed Time Time Time Current
==> googlecompute: Dload Upload Total Spent Left Speed
==> googlecompute: 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
==> googlecompute: 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
==> googlecompute: 100 607 0 607 0 0 1498 0 --:--:-- --:--:-- --:--:-- 5232
==> googlecompute: 100 43.2M 100 43.2M 0 0 10.3M 0 0:00:04 0:00:04 --:--:-- 15.4M
この辺でエラーが出ていたせいで惑わされた。
adduser
の対話式インターフェースをスキップしたい
当初はこうやっていた。
yes '' | sudo adduser --disabled-password embulk
けど、もっとちゃんとしたオプションをask ubuntuに教えてもらったので、それに切り替えた。
https://askubuntu.com/questions/94060/run-adduser-non-interactively
sudo adduser --disabled-password --gecos '' embulk
sudo su - embulk
でユーザーが切り替えられない
Packerはpacker
ユーザーとしてシェルスクリプトを実行する。途中 embulk
ユーザーに切り替えてプラグインをインストールするところでこけた
sudo su - embulk
/home/embulk/.embulk/bin/embulk gem install embulk-input-sqlserver
/home/embulk/.embulk/bin/embulk gem install embulk-output-bigquery
==> googlecompute: + sudo su - embulk
googlecompute: -rwxr-xr-x 1 embulk embulk 45378569 Dec 4 11:03 embulk
==> googlecompute: + id
googlecompute: uid=1000(packer) gid=1001(packer) groups=1001(packer),4(adm),30(dip),44(video),46(plugdev),1000(google-sudoers)
上記はスクリプトに id
をかませている。
無知な自分は、これの回避方法をテラテイル様に教えていただいた。
https://teratail.com/questions/138081
sudo su - username
にリダイレクトをかけるか、sh -u username -c "..."
で引数としてスクリプトを渡せば良いらしい。
sudo su - embulk <<EOF
/home/embulk/.embulk/bin/embulk gem install embulk-input-sqlserver
/home/embulk/.embulk/bin/embulk gem install embulk-output-bigquery
EOF
/home/embulk/.bashrc
に PATH
の更新をかけてたから embulk
コマンドで通せるかと一瞬思ったけど、当然ダメだった。ので、フルパスを渡している。
[ERROR] Embulk does not support Java 11 yet.
というエラー
新しい Debian イメージ debian-10
を設定して実行したら、↑のエラーが出た。sudo apt-get install default-jdk -y
で入るJavaのバージョンが新しすぎたためにエラーとなっていた。(.shの中で java -version
実行して確認した。。。 )
apt-get
でバージョン指定するのが良い。けど、とりあえず debian-9
を指定してお茶を濁した。ただ、sudo apt-get update -y
が入ってる時点で結末は見えている。。。
感想
- Packer 自体はシンプルで簡単だったが、シェルスクリプト力が足りず苦しんだ。
- GCEは爆速でインスタンスが立ち上がるのでAMI焼きよりは楽だったと思う。