目的
ホストの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
の設定などを引き継ぐ、みたいな使い方もできます。ただし、コンテナにアタッチされるとホームディレクトリが丸見えなので、使用の際にはご注意を。