目的
ホストのUID/GIDで作業可能なsudo付きDockerコンテナをDockerfileを作成せず、かつ出来るだけ制約の少ない方法で立ち上げる。
背景
Dockerコンテナを開発環境として使っていると、デフォルトがrootユーザなせいで、ファイルのownerの問題にぶち当たる。
よくあるパターンが、ディレクトリをマウントして作成したファイルのownerがrootになってて、がホスト側から編集出来ない、とかいうケース。
Dockerコンテナを開発環境に使ってると、よくこのパターンにハマり、ownerを変更するためだけにコンテナを起動したりすることも...。
回避方法として-u $(id -u):$(id -g)のオプションを付ける方法あるが、これだけではホスト側のユーザIDと一致しなかったり、sudoが使えなかったりと困ることも多い。
じゃあ、sudoインストールしたりuseraddしたりするDockerfileを作るというのもあるが、いちいちpullしてきたイメージに対してそれをやるのも面倒。
というわけで、できるだけ簡単にホストユーザのsudo付きDockerコンテナを立ち上げるコマンドの紹介。
方法
UbuntuとCentOSで若干違うので分けて記載。
Ubuntu
コンテナ名は適当にtest-user-with-sudoとでもしときます。
CNAME=test-user-with-sudo
まずは、コンテナ起動。
docker run -it --name ${CNAME} \
-u $(id -u):$(id -g) \
-v /etc/group:/etc/group:ro -v /etc/passwd:/etc/passwd:ro \
-v ${HOME}/src:${HOME}/src -w ${HOME} \
ubuntu:20.04 bash
-
-u $(id -u):$(id -g): ユーザ:グループを指定 -
-v /etc/group:/etc/group:ro -v /etc/passwd:/etc/passwd:ro:ホスト側との整合性(リードオンリー) -
-v ${HOME}/src:${HOME}/src:お好み。私の場合はソースコードとか大抵ホームディレクトリに置いてるので。 -
-w ${HOME}:お好み。コンテナ入る度にホームディレクトリに移動するのが面倒なので。
このままだと、
$ sudo apt update
bash: sudo: command not found
のようにsudoが使えないため、使えるようにする。
コンテナ起動後、一旦C-p C-qで抜ける。
docker exec -it -u root ${CNAME} \
bash -c "apt update && apt install sudo -y \
&& ( echo $(id -nu):$(id -nu) | /usr/sbin/chpasswd ) \
&& ( echo \"$(id -nu) ALL=(ALL:ALL) NOPASSWD: ALL\" | tee /etc/sudoers.d/$(id -nu) )"
-
apt install sudo -y:sudoをインストール -
echo $(id -nu):$(id -nu) | /usr/sbin/chpasswd:パスワードを設定(パスワードにユーザ名を使用している)。- 一見すると
/etc/passwdがroなので実行できなそうに見えるが、実際パスワードは/etc/shadowに保存されており、こちらはマウントしていないため問題なく実行できる。
- 一見すると
-
echo \"$(id -nu) ALL=(ALL:ALL) NOPASSWD: ALL\" | tee /etc/sudoers.d/$(id -nu) ):sudoをパスワード無しで実行できるようにする。- パスワード無しはセキュリティ的に...と感じるかもしれないが、上記のコマンドから分かるように、そもそも横から簡単に
rootで実行できちゃうため、ここでは気にしない。 - 今回はあくまで開発環境など性善説的な場面を想定しており、セキュリティ面を気にする場合はrootlessモードを使うのが良さそう。
- パスワード無しはセキュリティ的に...と感じるかもしれないが、上記のコマンドから分かるように、そもそも横から簡単に
パスワード無しsudoなので「パスワードの設定」は不要そうだが、パスワード設定をしておかないとsudoコマンドが使えなかったため設定。
動作確認。
# ホスト
$ docker attach ${CNAME}
-----
# コンテナ内
$ sudo apt update
CentOS
パスワードの設定方法が若干違うが、基本的に同じ。
CNAME=test-suer-with-sudo
docker run -it --name ${CNAME} \
-u $(id -u):$(id -g) \
-v /etc/group:/etc/group:ro -v /etc/passwd:/etc/passwd:ro \
-v ${HOME}/src:${HOME}/src -w ${HOME} \
centos:8 bash
# C-p C-q で抜ける
docker exec -it -u root ${CNAME} \
bash -c "yum install sudo passwd -y \
&& ( echo $(id -nu) | passwd --stdin $(id -nu) ) \
&& ( echo \"$(id -nu) ALL=(ALL:ALL) NOPASSWD: ALL\" | tee /etc/sudoers.d/$(id -nu) )"
最後に
Dockerコンテナを開発環境として使うと、ツールのインストールやビルド済みのイメージが使えたりしていろいろ便利です。
マシンが自分しかログインしない場合には、${HOME}を丸ごとマウントしてsshの設定などを引き継ぐ、みたいな使い方もできます。ただし、コンテナにアタッチされるとホームディレクトリが丸見えなので、使用の際にはご注意を。