dockerのpermission denied対策

Google Container Engine(GKE)など、クラウドインフラ上でdockerコンテナを動作させる場合、データ確保のため外部ディスクを利用するケースが多々あります。

GKEでは、設定ファイルにpersistentDiskの設定を記述することで、dockerコンテナにpersistentDiskがmountされた状態で起動します。

この場合、外部ストレージのファイルパーミッションが問題となり、コンテナが起動できないトラブルによく遭遇します。

(AWSではためしていませんが、kubernetesではEBSも指定できるので、問題の構造は同様でしょう)

典型的な用途では、mysqlはmysqlユーザー、postgresqlはpostgresユーザーでDBディレクトリを読み書きできる必要があります。

そのため初回起動時にpersistentDiskのファイルオーナーを各ユーザーに変更しておかないとDBインスタンスが起動しません。

なお、起動時エラーはkubectl logsコマンドで取得できる場合があります。

手作業でパーミッション変更

原始的ながら比較的わかりやすい方法として、とにかくコンテナを起動して手動でchownする方法があります。

起動時の実行コマンドを差し替えてしまうことで、ひとまず起動する作業用イメージを作れます。

以下の例は、jenkinsのDockerfileの記述例ですが、FROMのイメージを書き換えることで他のイメージでも同様の手法を使えます。

(jenkinsはjenkinsユーザーで起動するため、今回の作業用にrootユーザーを指定しています)

FROM jenkins

USER root
ENTRYPOINT tail -f /dev/null

Unix UIDを適切に設定する必要があるため、FROMのイメージは最終的に利用するイメージと同じものである必要があります。

この設定でdocker buildしたイメージを用いて、persistentDiskをmountしたうえでコンテナ起動します。

コンテナが起動したら kubectl execなどdocker exec系のツールでシェルログインします。

あとは通常のLinux管理ですが、たとえばjenkinsのケースではchown -R jenkins:jenkins /var/jenkins_homeでファイルオーナーを変更できます。

一度変更したあとはこの作業用のイメージは捨てて、もともと利用する予定だったイメージを起動すれば動作するはずです。

起動時フックスクリプトにchownを書く

より定型的な動作をさせたい場合は、コンテナ起動後に実行されるスクリプトにchownを記載して実行させます。

MySQLとPostgreSQLの公式dockerイメージは、いずれもコンテナの /docker-entrypoint-initdb.d というディレクトリに置いたスクリプトを起動後に自動実行する仕様となっています。

たとえばPostgreSQLの場合、以下のようなスクリプトをCOPY chown.sh /docker-entrypoint-initdb.d/でコンテナにコピーしておくことで動作します。

#!/bin/bash

if [ ! -e /var/lib/postgresql/data/pgdata ]; then
  mkdir -p /var/lib/postgresql/data/pgdata
fi
chown -R postgres.postgres /var/lib/postgresql

なお、PostgreSQLは、データディレクトリにext4の lost+found/ など異物があるとエラーになるため、空のサブディレクトリを追加する処理を加えています。

スタートアップスクリプトにchownを書く

記載する処理内容は同じですが、MySQLやPostgreSQLのように任意のスクリプトを実行するフック機構を提供していない場合、ENTRYPOINTに指定されている起動スクリプトを書き換えてchownを追加するような準備が必要になります。

これはやや手間ですが、公式dockerイメージのDockerファイルを読んで修正するスクリプトを特定したうえで、ファイルを取得&編集してDockerfileビルドで上書きする、という流れになります。

または、コンテナを起動してからdocker inspectコマンドの出力を読んでENTRYPOINTの設定を知る方法もあります。

まとめ

データベースなど、外部ディスクにデータ保存する用途では、初回起動時にUnixファイル管理上の権限エラーに遭遇することがあります。

そのため利用開始前の準備手順として、chownなどで実行デーモンのための適切なファイルパーミッション設定が必要になります。

また、 kubernetes+dockerについてで記載したとおり、コンテナの自動リカバリ時にpersistentDiskのアンマウントが適切に動作せず、別nodeで再起動する処理が完結しないようなトラブルも起こります。

現時点では、docker関連ホスティングの外部ディスク利用には特有のトラブルが残っている状況です。

中馬崇尋
Chuma Takahiro