戦後レジュームから復活したアラサー土方がはじめてCentOS7でDockerを利用しようとして、ファイル回りで少し嵌ったのでメモしておきます。
2018.10.08追記: --privilegedオプションなしで実行する方法を追記しました。
まずは普通にインストール
yumから。
$sudo yum -y update
$sudo yum -y install docker-io
インストール出来たらdockerのserviceを起動します。
$sudo systemctl start docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
Active: active (running) since 日 2018-10-07 14:05:46 JST; 13s ago
Docs: http://docs.docker.com
Main PID: 24300 (dockerd-current)
Tasks: 22
CGroup: /system.slice/docker.service
├─24300 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docke...
└─24307 /usr/bin/docker-containerd-current -l unix:///var/run/docker/libconta...
$sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
中に誰もいませんね。適当なDockerイメージを作って動かしてみます。
buildは時間が掛かるので作業しているフリしてサボりましょう。
$mkdir ~/my-docker
$cd my-docker
$vi Dockerfile # イメージを作成する
$sudo docker build -t mydocker . # -t <タグ名>
FROM ubuntu
RUN \
apt-get update -y \
apt-get install -y vim-common \
apt-get clean
作成したイメージを実行してみませう。
$sudo docker run -it mydocker /bin/bash # -i インタラクティブモード
root@a7317ef36825:/#
コンテナ内のターミナルに入れました。Dockerでは何も指定しないと、コンテナ内でrootユーザになります。また、コンテナ内で"exit"と打つと実行を終了します。
このままではコンテナ内で作成したファイルは終了時に消滅してしまいます。
さらに、ホストOS上に存在するファイルを参照することも出来ません。
ではどうするかというと、-v|--volume
オプションによりホストOSのディレクトリをコンテナのディスクイメージにマウントします。
$mkdir data
$echo "[$HOSTNAME]" `date` >> data/A # コンテナ内で利用したいファイル
$sudo docker run --privileged=true -v $PWD/data:/tmp/data -it mydocker /bin/bash
volumeオプションの書式は-v <ホスト側のパス>:<マウント先>
です。ホスト側のパスはフルパスで記載してください。そうしないと変な処(1)に作成されます。また、./
などの相対パスはエラーになります。
--privileged=true
はデバイスにアクセスする権限などをコンテナに与えます。通常、CentOS7ではこれを指定しないとコンテナ側からマウント先にアクセスできません。(2)
ボリューム・ラベルを適切に設定することでも解決できます。(後述)
#cat /tmp/data/A
[hostos] 2018年 10月 7日 日曜日 15:20:05 JST
#echo "[$HOSTNAME]" `date` >> /tmp/data/logfile
$cat data/A
[hostos] 2018年 10月 7日 日曜日 15:20:05 JST
[ef3844bdb907] Sun Oct 7 06:20:40 UTC 2018
はい。双方向にファイルのやり取りができますね。
実行ユーザと所有権
上述の通り、Dockerでは何も指定しないと、コンテナ内でrootユーザとなります。
つまり、コンテナ内で作成したファイルも所有者はrootになっているということです。
$touch /tmp/data/B
$ls -l data/B
-rw-r--r--. 1 root root 0 10月 7 13:40 B
-u|-user
オプションでコンテナ内で実行するユーザID:グループIDを指定出来ます。
下のようなコマンドをシェル化しておくと良いでしょう。
export $runuser=`id | sed -E 's/uid=([0-9]+).+gid=([0-9]+).+/\1:\2/'`
$sudo docker run --privileged=true -u $runuser -v $PWD/data:/tmp/data -it mydocker /bin/bash
上記のように実行するとコンテナ内のユーザが指定したuid,gidになります。
$touch /tmp/data/C
$ls -l data/C
-rw-r--r--. 1 user group 0 10月 7 13:40 C
docker-composeを利用する場合
docker run
に指定していたオプションをymlで指定します。
こちらはホスト側のパスとして相対パスが使えます。
hoge:
...
user: "${runuser}"
volumes:
- ./data:/tmp/data
privileged: true
...
なお、上の例で環境変数を使っていますが、予めexportしておくのを忘れないように。
おまけ:sudoが邪魔
dockerrootというgroupがいるので、自ユーザを追加してやればdocker run
などのコマンドをスーパーユーザにならなくても実行出来ます。
$sudo gpasswd -A hogeuser dockerroot # 再ログイン or reboot
(2018.10.08追記) ボリューム・ラベルの設定
--privileged=true
を指定しないでコンテナからボリュームに書き込もうとした場合、"Permission Denied"のエラーと共に、/var/log/messagesにSELinuxによるアクセス拒否のエラーが出ていました。
$docker run -v $PWD/data:/tmp/data -it mydocker /bin/bash
# コンテナ内でread, write
$ls -l /tmp/data
$echo aaaa > /tmp/share/aaaa
# => Permission Denied
Oct 8 08:24:05 slv-1 journal: I have no name!@b78ac2791ae0:/$ #015#033[KI have no name!@b78ac2791ae0:/$ ls -l /#010 #010/tmp/share/#015
Oct 8 08:24:05 slv-1 journal: ls: cannot open directory '/tmp/share/': Permission denied#015
Oct 8 08:24:20 slv-1 journal: I have no name!@b78ac2791ae0:/$ echo aaaa > /tmp/share/aaaa#015
Oct 8 08:24:20 slv-1 journal: bash: /tmp/share/aaaa: Permission denied#015
Oct 8 08:24:20 slv-1 chronyd[689]: Selected source 210.173.160.87
Oct 8 08:24:23 slv-1 dbus[625]: [system] Activating service name='org.fedoraproject.Setroubleshootd' (using servicehelper)
Oct 8 08:24:23 slv-1 dbus[625]: [system] Successfully activated service 'org.fedoraproject.Setroubleshootd'
Oct 8 08:24:24 slv-1 setroubleshoot: SELinux is preventing bash from write access on the directory share. For complete SELinux messages run: sealert -l 71a31f44-e0b3-47e2-83fc-280190bc430a
Oct 8 08:24:24 slv-1 python: SELinux is preventing bash from write access on the directory share.#012#012***** Plugin catchall (100. confidence) suggests **************************#012#012If you believe that bash should be allowed write access on the share directory by default.#012Then you should report this as a bug.#012You can generate a local policy module to allow this access.#012Do#012allow this access for now by executing:#012# ausearch -c 'bash' --raw | audit2allow -M my-bash#012# semodule -i my-bash.pp#012
Oct 8 08:24:24 slv-1 journal: Allocating size to ShellEmbeddedWindow 0x12f0940 without calling gtk_widget_get_preferred_width/height(). How does the code know the size to allocate?
以下の記事に詳しく書かれてあるように、原因はディレクトリにSELinuxのラベルが適切に付与されていなかったためのようです。
dockerで共有ディレクトリを利用したが、「Permission denied」が出てアクセスできない。
$ls -lZ data
drwxrwxr-x. hoge hage unconfined_u:object_r:user_home_t:s0 data
$ls -Z /tmp/data
drwxrwxr-x. 2 1000 1000 unconfined_u:object_r:user_home_t:s0 6 Oct 7 15:15 /tmp/data
-v
の後ろに:z
,:Z
を付与することで正しくラベルが付与されます。
$docker run -u 1000:1000 -v $PWD/share:/tmp/share:z -v $PWD/share2:/tmp/share2:Z -it mydocker /bin/bash
$ls -Z
drwxrwxr-x. hoge hoge system_u:object_r:container_file_t:s0 share
drwxrwxr-x. hoge hoge system_u:object_r:container_file_t:s0:c462,c792 share2
$ls -Z /tmp
system_u:object_r:container_file_t:s0 share
system_u:object_r:container_file_t:s0:c462,c792 share2
これでアクセスできます。ただし、:z
,:Z
は元のラベルを上書きするので本番環境での運用には注意が必要です。
参考
[Docker ドキュメント日本語化プロジェクト]
http://docs.docker.jp/index.html
[dockerで共有ディレクトリを利用したが、「Permission denied」が出てアクセスできない。]
https://qiita.com/shuichiro/items/adaaeccebdc55089f1b8
[SELinux と Docker と OpenShift v3]
https://qiita.com/nak3/items/361b62595601828bd354