Ubuntu Weekly Recipe

第479回 LXDコンテナとホストの間でファイルを共有する方法

この記事を読むのに必要な時間:およそ 4 分

lxc fileコマンドを使ったファイルの受け渡し

ホストから特定のコンテナとのファイルを受け渡ししたいのであれば,lxc fileコマンドが使えます。

コンテナからファイルを取得する
$ lxc file pull コンテナ名/フルパス 保存先

コンテナにファイルを渡す
$ lxc file push ファイル コンテナ名/フルパス

気をつけなければいけないのは,コンテナ側のファイル名は「コンテナ名/フルパス」の書式であるということです。sampleコンテナの/etc/environmentならsample/etc/environmentになります。-rオプションをつけると,再帰的に受け渡しします。またcpコマンドなどと同じく送信元のファイル(=最後の引数を除いたファイル)は複数指定可能です。その場合,保存先はディレクトリになります。

lxc file pushの場合,-pオプションを付けることで保存先のパスに合わせてディレクトリを作成します。また--uid--gid--modeオプションによって保存先のファイルオーナーやモードを変更できます。

非特権コンテナであってもlxc fileコマンドを使う限り,UID等の変更は「うまく」扱ってくれます。コンテナ上のUID=1000(ホスト上のUID=166536)がオーナーのファイルをホストにpullしたら,ホスト上のUID=1000がオーナーになりますし,その逆もまた然りです。コンテナとホストの間を手動で受け渡しすれば事足りるのであれば,lxc fileだけで十分です。特に別ホストにいるコンテナ(リモートコンテナ)にも同じコマンドで送ることができるというメリットがあります。

ちなみにlxc fileにはファイルを削除するlxc file deleteやホスト上のテキストエディターでコンテナのファイルを編集できるlxc file editコマンドもあります。特に後者は,ちょっとコンテナの設定を書き換えたいときに真価を発揮します。

ホストのディレクトリーツリーをbind mountする

名前空間による制限により,コンテナからホストのルートファイルシステムを直接見ることはできません。またAppArmorにより,コンテナ内部からのブロックファイルのmountは禁止されています。もしコンテナとホストの間,もしくは同じホスト上のコンテナ間でファイルやディレクトリを共有したい場合は,コンテナの設定でbind mountする方法が便利です。

$ lxc config device add sample share disk source=/srv/shared path=/srv/shared

上記のコマンドはホストの/srv/sharedsource=オプション)を,コンテナ内部の/srv/sharedpath=オプション)としてbind mountします。つまりホストとコンテナで/srv/sharedを共有できるというわけです。

lxc configによる設定は永続的に反映されますので,コンテナの再起動を行ってもそのまま残っています。

$ lxc config show sample
(中略)
devices:
  nfsdir:
    path: /srv/shared
    source: /srv/shared
    type: disk
(後略)

この方法のメリットは,ホスト側のファイルシステムに関係なく同じ方法でコンテナと共有できることです。たとえばコンテナの内部からNFSディレクトリをmountする場合も,一度ホスト側でNFSディレクトリをmountしておけば,それをそのままコンテナにbind mountできるのです。よって同じホスト上のコンテナ間だけでなく,ネットワーク越しのコンテナ間ともファイルやディレクトリを共有できます。

ただしlxc fileと異なり,UID等のマッピングの変更は行いません。よってコンテナの一般ユーザーで作ったファイルやディレクトリのオーナーは,ホストから見るととても大きなUIDを持っていることになります。

ホストとコンテナでUID等を一致させる

bind mountによる共有ディレクトリを使う場合,ホストとコンテナで一般ユーザーのUID等を一致させたほうが便利です。つまりコンテナのUID=1000はホストでもUID=1000にします。もちろんrootを一致させるとそれはとどのつまり「ほぼ特権コンテナ」となりますので,非特権コンテナにしておく意味が薄れます。あくまで「普段使うユーザー」のみUIDを一致させるのです。理想的にはそのユーザーはsudoグループに入っていないほうがいいでしょう。

UID等のマッピングは/etc/subuid/etc/subgidファイルで管理しています。UID=1000,GID=1000のユーザーとグループはホストとコンテナで一致したい場合は次のように設定します。

$ echo "root:1000:1" | sudo tee -a /etc/subuid
$ echo "root:1000:1" | sudo tee -a /etc/subgid

このうちrootは今回設定したUID等のマッピングを許可するユーザーです。LXDの場合はrootがコンテナ起動時にマッピングを行うのでrootにしています。書式はUSER:START:COUNTです。上記設定の場合は,⁠ID=1000から1つ」になります。もちろん1100にして複数のUIDをマッピングすることも可能です。

コンテナ内部のマッピングに関する設定は,コンテナごとに行います。

$ lxc config set sample raw.idmap 'both 1000 1000'

bothはUIDとGID両方に同じ値を設定するパラメーターです。書式はboth HOST_ID CONTAINER_IDとなります。HOST_IDにはホスト上のUID/GIDを,CONTAINER_IDにはHOST_IDをコンテナの中にマップした時のIDを記述します。言い換えると「ホスト上のUID/GID 1000をコンテナ上のUID/GID 1000として扱う」ということです。

もしUID/GIDを異なる値にしたい場合はbothのかわりにuidgidを使います。

ホスト上のUID=1010をコンテナ上ではUID=1000として扱いたい場合
uid 1010 1000

ホスト上のGID=1011をコンテナ上ではGID=1000として扱いたい場合
gid 1011 1000

uidgidを同時に設定したい場合は,改行でつなぎます。しかしながらlxc configコマンドは直接改行を扱えません。そこで設定内容を標準入力から受け付けるようにして,そこにパイプで設定内容を流し込みます。

$ echo -e "uid 1010 1000\ngid 1011 1000" | lxc config set xenial raw.idmap -

ハイフンをつないで範囲を指定することも可能です。この場合,マッピング元とマッピング先の個数が同じになるようにしてください。

変更した設定を反映するには,一度そのコンテナを再起動します。冒頭と同じようにプロセスのUIDをコンテナとホストで比べたら,UID=0はマッピングされているものの,UID=1000はコンテナとホストで一致していることがわかるはずです。

これらを組み合わせれば,ホスト・コンテナ間のファイルやディレクトリのアクセス権をそれなりにコントロールできることでしょう。

著者プロフィール

柴田充也(しばたみつや)

Ubuntu Japanese Team Member株式会社 創夢所属。数年前にLaunchpad上でStellariumの翻訳をしたことがきっかけで,Ubuntuの翻訳にも関わるようになりました。

コメント

コメントの記入