💡

dockerでmariadbサーバーをdocker-entrypoint.shでパスワード初期化するときに詰まった話

に公開

(タイトル読みづら!!)

はじめに

詰まったので記録。雑記録なので読みづらい。

前提の知識や環境や対象

  • docker使えること。
  • mariadb-serverがインストールされているコンテナが起動できること。
  • 起動時にdocker-entrypoint.shが設定されていること。
  • secretsやconfigs、ボリュームマウントやmariadbdの設定方法がわかること。
  • SQL文かシェルスクリプトか、コンテナ内かホスト内か判断がつくこと。

やりたいこと

mariadbサーバーのユーザーのパスワードをdockerの起動するたびに新しく設定したい。

条件

ただし以下の条件で。

  • 認証プラグインはed25519 を使用する
  • 既存のmariadbイメージは使わない。
  • パスワードファイルをsecretsで指定して、docker-entrypoint.shでそのファイルを使ってパスワードを初期化する。
  • rootのパスワードを設定する。

条件を設定した理由

  • mysql_native_password は、←の赤文字で書いてあるとおり、危険であるようなので、ed25519 を使いたかった。
  • 勉強のため。(取り回しを自由にするため。)
  • 設定に関する情報はイメージの外から設定できる方が都合が良い。と思った。
  • たぶん、よりセキュア。

ハマったポイント

以下の内容でつまりました。

  • サーバーが立ち上がっていない
  • rootでログインできない
  • パスワードが変更できない
  • シンタックスエラー

docker-entrypoint.shについて

ENTRYPIONTをdocker-entrypoint.shとして、イメージを立ち上げる。
PID1で立ち上げるためだとか、サーバーが落ちたときにコンテナも落とすだとか、各種設定を初期化するとかの目的で使用しています。
詳しいことはきっと誰かが書いている。(公式でのベストプラクティスとか、公式イメージとかで色々想像をふくらませる)

サーバーが立ち上がっていない -> 一時サーバーを立てる

mariadbの公式イメージのdocker-entrypoint.shを参考にしました。
公式では、mariadbサーバーを一時的に立ち上げてその中で処理をしているようでした。
具体的にはこんなイメージ

# 一時的なサーバーを立ち上げる
mariadbd &
local mariadbdpid="$!"

# 一時的なサーバーが立ち上がるまで待つ。
while ! mariadb -e "SELECT 1;"; do
    sleep 1;
done

# 一時的なサーバーを落とす
kill "$mariadbd"
wait "$mariadbd"

# コンテナのメインサーバーを立ち上げる。PID1で立ち上げるためにexec使用。
exec "mariadbd"

rootでログインできない -> --skip-grant-tablesをつけて起動する

サーバーを立ち上げるときに、--skip-grant-tablesオプションをつけてサーバーを起動することでパスワードなしでログインできるようになる。

パスワードが変更できない -> FLUSH PRIVILEGES;を実行する

rootでログインできたものの、ALTER USERだとかSET PASSWORDがうまく行かなかった。
エラーにもあるが、--skip-grant-tablesを実行すると、権限周りの変更ができなくなる・・・?
skip-grant-tablesオプションにある通り、有効にする。
今回は、SET PASSWORDALTER USERを使いたいので、FLUSH PRIVILEGES;を接続した状態で実行。
これで、管理者としてログインしたままデータベースを使えるようになった。

シンタックスエラー -> plugin_load_add = auth_ed25519

ALTER USER 'root'@'localhost' IDENTIFIED VIA ed25519 USING PASSWORD('$(cat_password $ROOT_PASS_FILE)');がシンタックスエラーを出していた。(cat_passwordは改行文字を削除している。tr -d '\n'
ed25519を使うために、INSTALL SONAME 'auth_ed25519';を実行する必要があるが、次回以降の起動時は、外部プラグインなので、ロードした上で起動する必要がある。これが原因だった。
自分が見つけた方法は、サーバーの起動オプションで渡す方法と設定ファイルで変更する方法の2つである。
起動オプションは(設定ファイルでも同様に指定可能だが)--plugin-load-add--plugin-loadの2つがあったが違いがよくわからなかった。
他にも方法はありそうだが、公式サイトのed25519で例として明示されていたので設定ファイルで変更する方法を使用した。
設定例 (/etc/mysqld/mariadb.conf.d/50-server.cnf)

[mariadb]
plugin_load_add = auth_ed25519

流れ

  1. 事前に、設定ファイルにplugin_load_addを追加する。
  2. FLUSH PRIVILEGES;をテキストとしてSQL変数に追加。
  3. ALTER USER 'root'@'localhost' IDENTIFIED VIA ed25519 USING PASSWORD('$(cat_password $ROOT_PASS_FILE)');をSQL変数として追加。

ROOT_PASS_FILEは、パスワードが記録されているファイル。secretsを使ってマウントされているパス。

  1. docker-entrypoint.sh内で
    一時的なサーバーを立ち上げる。その際に--skip-grant-tablesを設定。

  2. mariadb -u root -h localhost -e "$SQL"などでSQL文を実行する。
    一時的なサーバーを落とす。

  3. 起動する。

docker-entrypoint.sh の最終イメージ

SQL="FLUSH PRIVILEGES;"
SQL=$SQL"ALTER USER 'root'@'localhost' IDENTIFIED VIA ed25519 USING PASSWORD('$(cat_password $ROOT_PASS_FILE)');"

# 一時的なサーバーを立ち上げる

# SQLを実行する
mariadb -u root -h localhost -e "$SQL"

# 一時的なサーバーを落とす

# 本当のサーバーを立ち上げる
exec "mariadb"

補足

一時的なサーバーを立ち上げるときは様々な追加のオプションが推奨されるようだ。
少なくとも、--skip-networkingは追加で指定しておくと良さそう。

Discussion