Dockerコンテナを起動する際に、環境変数で渡したパラメーターを使って設定ファイルを作りたいことがある。 例えばsambaにアクセスするとき、ユーザー名が foo なら許可、それ以外は不許可としたければ設定ファイルは以下のようにする。
[global] log file = /var/log/samba/%m [share] path = /mount guest ok = no valid users = foo # ユーザー foo ならアクセスを許可する
このユーザー名を可変にしたいとしよう。Docker で docker run -e USER=foo -e PASSWORD=pass ...
のようにしたいなら、以下のようになる。
Dockerfile
FROM ubuntu:latest RUN apt update \ && apt install -y \ samba COPY samba.sh /root/ EXPOSE 139 445 CMD ["/root/samba.sh"]
samba.sh
#!/bin/sh # /etc/samba/smb.conf を生成する cat <<SMBCONF >> /etc/samba/smb.conf [global] log file = /var/log/samba/%m [share] path = /mount guest ok = no valid users = $USER SMBCONF # システムに foo ユーザーを追加し、foo ユーザーとしてアクセスできるようにする useradd $USER cat <<PASSWORD | passwd $USER $PASSWORD $PASSWORD PASSWORD cat <<PASSWORD | smbpasswd -a -s $USER $PASSWORD $PASSWORD PASSWORD # samba サーバーを起動する /usr/sbin/smbd -F -S --no-process-group
しかしこのファイル生成方法は、smb.conf
のテンプレートがスクリプト中にあって気持ちが悪い。
こんなとき Ruby なら ERB が使えるのだが、インストールすると依存する複数のパッケージも入ってしまうし、テンプレートを使いたいだけなのにちょっと大げさだ。
# Ubuntu 19.10 の場合 $ root@f86b2af49215:/# apt install ruby Reading package lists... Done Building dependency tree Reading state information... Done The following additional packages will be installed: ca-certificates fonts-lato javascript-common libgdbm-compat4 libgdbm6 libjs-jquery libruby2.5 libyaml-0-2 openssl rake ruby-did-you-mean ruby-minitest ruby-net-telnet ruby-power-assert ruby-test-unit ruby-xmlrpc ruby2.5 rubygems-integration unzip zip Suggested packages: apache2 | lighttpd | httpd gdbm-l10n ri ruby-dev bundler The following NEW packages will be installed: ca-certificates fonts-lato javascript-common libgdbm-compat4 libgdbm6 libjs-jquery libruby2.5 libyaml-0-2 openssl rake ruby ruby-did-you-mean ruby-minitest ruby-net-telnet ruby-power-assert ruby-test-unit ruby-xmlrpc ruby2.5 rubygems-integration unzip zip 0 upgraded, 21 newly installed, 0 to remove and 23 not upgraded. Need to get 7568 kB of archives. After this operation, 31.9 MB of additional disk space will be used. Do you want to continue? [Y/n]
Ruby には軽量版の mruby がある。
素の mruby のバイナリは Ubuntu 19.10 なら apt install mruby
でインストールできるが、これには ERB がバンドルされておらず利用できないので、代わりに mitamae を使うことにする。
プロビジョニングツールであり ERB を使ってテンプレートから設定ファイルを生成し配置する機能をもともと備えているし、シングルバイナリで 2.28MB (v1.10.5の場合)とコンパクトなので、インストールも手間がかからない。
Dockerfile
FROM ubuntu:latest RUN apt update \ && apt install -y \ samba # mitamae の latest の URL を指定する。 # 最新版のバイナリへのリダイレクトを伴うためか、変更がなくとも docker build の度に毎回ダウンロードが走るので、気になる場合は指定バージョンの URL を使う。 ADD https://github.com/itamae-kitchen/mitamae/releases/latest/download/mitamae-x86_64-linux /root/mitamae RUN chmod +x /root/mitamae COPY samba.sh mitamae /root/ EXPOSE 139 445 CMD ["/root/samba.sh"]
samba.sh
#!/bin/sh (cd /root && mitamae local setup.rb) # mitamae にはユーザー追加機能も任意のコマンド実行機能もあるので、`passwd` `smbpasswd` も `setup.rb` に切り出してしまう。 # samba サーバーを起動する /usr/sbin/smbd -F -S --no-process-group
setup.rb
# /etc/samba/smb.conf 生成 template "/etc/samba/smb.conf" do variables(user: ENV["USER"]) end # ユーザー追加 user ENV["USER"] do password ENV["password"] end execute "Add a samba user" do command <<-COMMAND.gsub(/^ */, "") cat <<PASSWORD | smbpasswd -a -s #{ENV["USER"]} #{ENV["PASSWORD"]} #{ENV["PASSWORD"]} PASSWORD COMMAND end
mitamae/templates/etc/samba/smb.conf.erb
[global] log file = /var/log/samba/%m [share] path = /mount guest ok = no valid users = <%= @user %>
テンプレート部を別ファイルに切り出せた。
また mitamae 化の他の利点として、実行時にシステムへの変更がわかりやすく差分表示されることを記しておきたい。
パラメーターを JSON にしてみる
mitamae は JSON をパースできる。パラメーターを JSON で渡すことを考えてみる。
param = JSON.parse(ENV["SMB_PARAM"]) user = param["user"] template "/etc/samba/smb.conf" do variables(user: user["name"]) end user user["name"] do password user["password"] end execute "Add a samba user" do command <<-COMMAND.gsub(/^ */, "") cat <<PASSWORD | smbpasswd -a -s #{user["name"]} #{user["password"]} #{user["password"]} PASSWORD COMMAND end
$ smb_param=$(cat <<PARAM { "user": { "name": "foo", "password": "pass" } } PARAM $ sudo docker run --rm -p 139:139 -p 445:445 -e SMB_PARAM="$smb_param"
コード量をそれほど変えることなく JSON に対応することができた。 これにより
- パラメーターを階層化でき、追加や削除、環境変数の名前空間管理が楽 (プレフィックス付きの長い環境変数名にしなくていい)
- 配列が扱える (上記の例だとユーザーを複数にするとき
USER1
,USER2
, ... などとせず"user": [...]
とできる) - 環境ごとにパラメーターをまとめて管理できる (それぞれの JSON ファイルを作ればいい)
などの利便性を得られる。
なお実装は nowlinuxing/docker-samba においてあるので、気になる方は参照されたし。