MongoDBのDockerコンテナを使って開発を行う際に本番環境での使用も考えて、アプリケーションやターミナルから接続する時に認証するように設定しました。
コンテナを起動してからコマンドでの設定やShell Scriptを自作してやるのはスマートでないと思い色々調べていると、公式のイメージが初期データを挿入できるように作られていました。その方法と裏で何をしているのかを調べたので備忘録として書いておきます。
環境
-
Docker Desktop for Mac ver 2.0.0.3
- Docker Engine ver 18.09.2
- MongoDB Docker Image tag 4.1-bionic
認証用ユーザーの作成方法
ユーザーを作成するJavaScript
const user = {
user: 'staff',
pwd: 'staff_password',
roles: [{
role: 'readWrite',
db: 'test'
}]
};
db.createUser(user);
このスクリプトによって、ユーザー名staff
、パスワードstaff_password
、test
DBのreadWrite
権限が付与されたユーザーが作成されます。ちなみにロールは複数付与することができます。
MongoDBに接続にはmongo test -u staff -p staff_password
コマンドを実行します。
認証の有効化
MongoDBは
MongoDB does not enable access control by default. You can enable authorization using the --auth or the security.authorization setting.
と書かれている通り、デフォルトでは認証・認可は有効化されていません。認証用のユーザーを作ったところで認証・認可を有効にしないと意味がありません。
有効にする方法は、引用文に書かれているように--auth
コマンドオプションを使用するか、コンフィグのsecurity.authorization
をenabled
にする2通りあります。
Dockerfile
認証用ユーザーを起動時に作成するためには、createUser.jsを/docker-entrypoint-initdb.d
下に配置する必要があります。
そして、認証・認可を有効化したDockerfileは以下のようになります。
FROM mongo:4.1-bionic
COPY createUser.js /docker-entrypoint-initdb.d/
EXPOSE 27017
CMD ["mongod", "--auth"]
docker-entrypoint.shのカラクリ
MongoDBのDockerイメージではコンテナ起動時にdocker-entrypoint.shが実行されて初期データが挿入されます。そのShell Scriptが何をやっているのかを説明していこうと思います。
rootユーザーの生成
環境変数にMONGO_INITDB_ROOT_USERNAME
とMONGO_INITDB_ROOT_PASSWORD
が設定されているとrootユーザーが作成されます。このrootユーザーはroleがrootとなっており、全てのリソースにアクセスできるようになっています。なので、rootユーザーが必要ない状況であれば作成しない方がいいです。
以下がrootユーザーを生成している該当箇所です。
mongo=( mongo --host 127.0.0.1 --port 27017 --quiet )
if [ "$MONGO_INITDB_ROOT_USERNAME" ] && [ "$MONGO_INITDB_ROOT_PASSWORD" ]; then
rootAuthDatabase='admin'
"${mongo[@]}" "$rootAuthDatabase" <<-EOJS
db.createUser({
user: $(_js_escape "$MONGO_INITDB_ROOT_USERNAME"),
pwd: $(_js_escape "$MONGO_INITDB_ROOT_PASSWORD"),
roles: [ { role: 'root', db: $(_js_escape "$rootAuthDatabase") } ]
})
EOJS
fi
変数 | 値 | 説明 |
---|---|---|
$mongo | mongo --host 127.0.0.1 --port 27017 --quiet | localhostの27017でリッスンしているMongoDBに接続するためのコマンド |
$rootAuthDatabase | admin | adminというデータベース |
スクリプトでは、adminデータベースにユーザー名がMONGO_INITDB_ROOT_USERNAME
、パスワードがMONGO_INITDB_ROOT_PASSWORD
、ロールがroot
であるユーザーを作成しています。
初期データの挿入
初期データを挿入するためには、それ用のShell ScriptかJavaScriptを書く必要があります。この2つ以外のスクリプトであると無視されます。
挿入用スクリプトが/docker-entrypoint-initdb.d
に配置されていれば、スクリプトが実行されます。もちろん他のディレクトリに配置したら実行されません。←当たり前ですねw
前置きはこの辺にしてdocker-entrypoint.shの中身を見ていきましょう。
注) 行番号は説明のため1から連番にしてありますが、本物のソースコードの行番号と違います。
1 export MONGO_INITDB_DATABASE="${MONGO_INITDB_DATABASE:-test}"
2
3 for f in /docker-entrypoint-initdb.d/*; do
4 case "$f" in
5 *.sh) echo "$0: running $f"; . "$f" ;;
6 *.js) echo "$0: running $f"; "${mongo[@]}" "$MONGO_INITDB_DATABASE" "$f"; echo ;;
8 *) echo "$0: ignoring $f" ;;
9 esac
10 echo
11 done
1行目
操作対象となるDBを環境変数MONGO_INITDB_DATABASE
に格納してエクスポートしています。デフォルトではtest
というDBが対象となっています。
3行目
/docker-entrypoint-initdb.d
下にある全てのスクリプトを実行できるようにfor文で回しています。なので、実行内容ごとにスクリプトを分けて複数のスクリプトを/docker-entrypoint-initdb.d
に配置することも可能です。1つのスクリプトにごちゃごちゃいろんなことを書かずに済みますね。
5行目
Shell Scriptを実行しています。.
はスクリプトを読み込んで実行するという意味です。source
コマンドと同様の役割を果たします。
6行目
JavaScriptを実行します。mongoコマンドには
You can specify a .js file to the mongo shell, and mongo will execute the JavaScript directly.
とあるようにJavaScriptを直接実行できる機能があります。わざわざnode
コマンドとかで実行している訳ではありません。
${mongo[@]}
はrootユーザーの作成のところでも出てきましたが、mongo --host 127.0.0.1 --port 27017 --quiet
を指しています。
最後に
これで、初期データを挿入する方法とそのからくりがわかったと思います。
開発の場面では接続用のユーザーを作成したり、テストデータを挿入する時などに役に立つと思います。初期データを挿入できるのはMongoDBだけでなく、MySQLやPostgreSQLなどでも可能です。
便利な機能を使って環境構築は楽に素早く行って、メインの開発に注力していきましょう!
それでは