これは、名前付きボリューム(つまり、「データボリュームコンテナー」、「volumes-from」はありません)とdocker-compose.ymlに関するものです。
ここでの目標は、docker-composeを使用して2つのサービス「appserver」と「server-postgresql」を2つの別々のコンテナーで管理し、「volumes:」docker-compose.yml機能を使用してサービス「server-postgresql」からのデータを永続化することです。 。
'server-postgresql'のDockerfileは次のようになります。
FROM ubuntu:14.04
MAINTAINER xxx
RUN apt-get update && apt-get install -y [pgsql-needed things here]
USER postgres
RUN /etc/init.d/postgresql start && \
psql --command "CREATE USER myUser PASSWORD 'myPassword';" && \
createdb -O diya diya
RUN echo "host all all 0.0.0.0/0 md5" >> /etc/postgresql/9.3/main/pg_hba.conf
RUN echo "listen_addresses='*'" >> /etc/postgresql/9.3/main/postgresql.conf
CMD ["/usr/lib/postgresql/9.3/bin/postgres", "-D", "/var/lib/postgresql/9.3/main", "-c", "config_file=/etc/postgresql/9.3/main/postgresql.conf"]
Docker-compose.ymlは次のようになります。
version: '2'
services:
appserver:
build: appserver
depends_on:
- server-postgresql
links:
- "server-postgresql:serverPostgreSQL"
ports:
- "1234"
- "1235"
restart: on-failure:10
server-postgresql:
build: serverPostgreSQL
ports:
- "5432"
volumes:
- db-data:/volume_data
restart: on-failure:10
volumes:
db-data:
driver: local
次に、すべてをdocker-compose up -d
で開始し、サーバーのpostgresqlコンテナーにdocker-compose exec server-postgresql bash
を入力します。簡単なls
/volume_data
、次にcd
して、 touch testFile
を試してみると、「許可が拒否されました。簡単なls -l
は、 volume_data
がroot:root
によって所有されていることを示しているため、これは正常です。
今起こっていると思うのは、DockerfileにUSER postgres
があるので、 docker-compose exec
を実行すると、ユーザー 'postgres'としてログインします(そしてpostgresqlデーモンはユーザー 'postgres'として実行されます同様に、 /volume_data
に書き込むことはできません)。
代わりにこれを実行すると、 docker-compose exec --user root server-postgresql bash
とcd /volume_data
とtouch testFile
を再試行すると、機能するため、これは確認されています(ホストとコンテナー間のアクセス許可エラーではありません。コンテナがホストフォルダをマウントする場合があります。これは、ユーザー「postgres」が書き込もうとしているときに/volume_data
が「root:root」としてマウントされるため、一般的なUNIXパーミッションエラーです。
したがって、docker-compose.ymlには、namedvolumesを特定のユーザーとしてマウントする方法が必要です。
version: '2'
services:
appserver:
[...]
server-postgresql:
[...]
volumes:
- db-data:/volume_data:myUser:myGroup
[...]
volumes:
db-data:
driver: local
私が考えることができる唯一の_dirty_回避策は、DockerfileからUSER posgres
ディレクティブを削除し、カスタム「init_script.sh」を指すようにENTRYPOINTを変更することです(私はUSER postgres
削除しました)、このスクリプトは/volume_data
権限を変更して、 'postgres'が書き込み、次にsu postgres
を実行し、postgresqlデーモンを(フォアグラウンドで)実行できるようにします。 しかし、これはDockerfileとdocker-compose.ymlを非標準的な方法でリンクするため、実際には非常に汚いです(ランタイムENTRYPOINTは、マウントされたボリュームがdocker-compose.ymlによって利用可能になるという事実に依存します)。
これはDockerエンジンでサポートされているとは思わないため、APIに追加されるまで、Composeでサポートする方法はありません。 ただし、この機能を追加する必要はないと思います。 ファイルはいつでも正しいユーザーにchownできます。
version: '2'
services:
web:
image: alpine:3.3
volumes: ['random:/path']
volumes:
random:
$ docker-compose run web sh
/ # touch /path/foo
/ # ls -l /path
total 0
-rw-r--r-- 1 root root 0 Apr 5 16:11 foo
/ # chown postgres:postgres /path/foo
/ # ls -l /path
total 0
-rw-r--r-- 1 postgres postgres 0 Apr 5 16:11 foo
/ #
$ docker-compose run web sh
/ # ls -l /path
total 0
-rw-r--r-- 1 postgres postgres 0 Apr 5 16:11 foo
あなたが直面している問題は、名前付きボリュームの初期化に関するものです。 これは確かにComposeによって処理されるものではありませんが(スコープ外であるため)、 docker-compose up
実行する前に、dockercliを使用して名前付きボリュームを簡単に初期化できます。
これがDockerの問題なのか、作成の問題なのかは確かにわかりませんでした。ファイルを間違えた場合は申し訳ありません。
これはDockerAPIの計画ですか、そこで問題を報告する必要がありますか?
コンテナに手動でログインし、ボリュームを「postgres」ユーザーにchown
する可能性があることを理解しています。 しかし、私の場合、Composeを使用しているので、新しいクライアント( docker-compose -p client_name up
)の新しいコンテナーをすぐにインスタンス化でき、Composeはカスタムネットワークclient_name_default
を作成し、コンテナーを作成します。 client_name _appserver_1
とclient_name _server-postgresql_1
、そして_もっと重要なこと__という名前で、ボリュームclient_name_db-data
を作成します。 これらはすべて手動で行う必要がないため、クライアント登録を処理するスクリプトで実行できます。
あなたが説明した解決策(ボリュームラベルにsh
とchown
してコンテナに_手動で_ "ロギング"する)では、新しいクライアントを追加する簡単な手順がありません。これは必須です。手で世話をします。
これが、この機能を実装する必要があると思う理由です。 Docker APIでは、ボリュームをマウントするときにro
またはrw
(読み取り専用または読み取り/書き込み用)のアクセス許可を指定できます。 user:group
を指定できるはずです。
あなたはどう思いますか、私の要求は理にかなっていますか?
実はここにニュースを持って来て、達成しようとしていることは実行可能のようですが、これが機能なのかバグなのかわかりません。 これが私が変更した理由です:
私のDockerfileで、_ユーザー 'postgres'に変更する
# ...
RUN mkdir /volume_data
RUN chown postgres:postgres /volume_data
USER postgres
# ...
これは、ディレクトリ/ volume_dataを作成し、その権限を変更して、ユーザー 'postgres'が書き込みできるようにします。
これはDockerfileの部分です。
今、私はdocker-compose.ymlで何も変更していません:したがって、docker-composeはまだ名前付きボリュームdirectory_name_db-data
を作成し、それを/volume_data
マウントし、権限は保持されています! 。
つまり、名前付きボリュームが_pre-existing_ディレクトリ/volume_data
マウントされ、アクセス許可が保持されているため、「postgres」で書き込むことができます。
それで、これが意図された動作またはセキュリティの違反である場合はどうなりますか? (ただし、この場合は役に立ちます!)
これはDocker1.10.xで追加されたため、名前付きボリュームは、それらを使用した最初のコンテナーから初期化されると思います。 期待される動作だと思います。
また、Dockerfileで所有権が設定されている名前付きボリュームを実行しており、composeではuser: postgres
追加して、PID1でさえroot以外のユーザーが所有するようにしています。
Docker-compose
についてvolumes
持っているdriver_opts
オプションを提供します。
ドライバーlocal
場合でも、 chmod
、 chown
ようなオプションがあるのは非常に良いことです。
特に、起動時に存在しない場合は、ローカルで作成されたホストディレクトリにも適用されるようにしたいと思います。
誰かがMobyプロジェクトですでに問題を開いていましたか?
@dnephinからの回答はchown
またはchmod
コマンドが失敗し、ボリュームがrootによって所有されているため、標準ユーザーはアクセス許可を変更できません。
@jcberthon推奨される方法は、rootを開始ユーザーとしてコンテナーを実行し、chown / chmodの後にUSER
コマンドを使用して、基本的に「特権の削除」を行うことです。
Dockerイメージを制御している場合は問題ありませんが、既存のイメージを使用している場合は、実際にはオプションではありません。
@ dragon788と@micheljung 、問題を解決しました。
実際の本当の問題は、Dockerfileで、 VOLUME
を宣言してVOLUME
宣言をDockerfileの最後に移動する(またはオプションの場合は削除する)だけで、私の問題は解決します。 権限は正しいです。
したがって、間違いは次のとおりです。
FROM blabla
RUN do stuff
VOLUME /vol
RUN useradd foo && chown -R foo /vol
USER foo
CMD ["blabla.sh"]
上記のDockerfileの例のchown
は、ビルド中にVOLUME
を宣言しているため、ビルド中に失われます。 コンテナーを実行すると、dockerdは、指定されたボリューム内で、 VOLUME
宣言の前に/vol
のコンテンツをコピーします(したがって、root権限を使用します)。 したがって、実行中のプロセスはアクセス許可を変更または変更できないため、blabla.shスクリプトで強制的にchownを実行しても機能しません。
ファイルを次のように変更する。
FROM blabla
RUN do stuff
RUN useradd foo && chown -R foo /vol
USER foo
VOLUME /vol
CMD ["blabla.sh"]
問題は解決しました。
@jcberthon docker -compose.ymlでボリューム/ volをホストシステムにバインドする方法を教えてください。
私はFedoraでDockerを使用しています(つまり、SELinuxが有効になっています)が、上記の方法はどれも機能しませんでした。 理想的には、ユーザー(rootなし)のコンテキストでコンテナー内のアプリケーションを実行したいのですが、このボリュームの問題はそれを妨げるものです。
私にとって有効な唯一の回避策は、アプリケーションユーザーを排除し、すべてをrootユーザーとして実行/所有することです。
こんにちは@renanwilliamと@ egee-irl
私はいくつかのOSを含むいくつかのOSで上記のソリューションを使用しています。 Fedora26とCentOS7は両方ともSELinuxが適用され、Ubuntu 16.04、17.10とRaspbian 9はすべてAppArmorがアクティブ化されています(amd64プラットフォームとarmhfプラットフォームが混在しています)。
先ほど言ったように、Dockerfileの最後にVOLUME ...
宣言を移動しましたが、すべて削除できます。必須ではありません。 また、私が通常行うことは、Dockerfileでユーザーを作成するときにユーザーIDを修正することです(例: useradd -u 8002 -o foo
)。 次に、ホストでそのUIDを再利用して、フォルダーに適切なアクセス許可を与えることができます。
したがって、次のステップは、ホスト上に/vol
ディレクトリの「ペンダント」を作成することです。たとえば、 /opt/mycontainer1/vol
であるとすると、次のようになります。
$ sudo mkdir -p /opt/mycontainer1/vol
$ sudo chown -R 8002 /opt/mycontainer1/vol
$ sudo chmod 0750 /opt/mycontainer1/vol
次に、コンテナをユーザーfooとして実行すると、 /opt/mycontainer1/vol
ディレクトリに書き込むことができます。 何かのようなもの:
$ sudo -u docker-adm docker run --name mycontainer1 -v /opt/mycontainer1/vol:/vol mycontainer1-img
SELinuxベースのホストでは、Dockerがフォルダーに適切にタグを付けるように、ボリュームに:z
:Z
オプションを追加することをお勧めします。 z
とZ
の違いは、小文字のz
がボリュームにタグを付けるため、このホストのすべてのコンテナーがSELinuxによってそのディレクトリへのアクセスを許可される可能性があることです(ただし、明らかに別のコンテナにバインドマウントする場合のみ)、大文字のZ
はタグを付けて、その特定のコンテナのみがディレクトリにアクセスできるようにします。 したがって、SELinuxを使用するFedoraでは、次のことを試してみてください。
$ sudo -u docker-adm docker run --name mycontainer1 -v /opt/mycontainer1/vol:/vol:Z mycontainer1-img
更新:ここで私のリポジトリを確認できますhttps://github.com/jcberthon/unifi-dockerこの方法を使用して、ホストを構成してコンテナーを実行する方法を説明しています。 これがあなたの問題をさらに解決するのに役立つことを願っています。
ところで、 @ renanwilliamへの返信が大幅に遅れたことをお詫び申し上げます。 今年の終わりには余暇があまりありません...
だから、せっかちな人の短い長い話:
RUN mkdir /volume_data
RUN chown postgres:postgres /volume_data
ボリュームは既存のディレクトリの権限を保持するため、事前にボリュームディレクトリを作成し、 chown
解決します。
これは自明ではないため、回避策としては不十分です(Dockerfileでchownを実行し、マウント中にその所有権を継承します)。 docker-composeおよびdockerCLIで所有者とグループの制御を公開することは、UNIXスタイルのコマンドにとって最も驚きのないパスです。
@villasv
小さなヒント:2つのRUN ...
を1つにマージします。これにより、余分なレイヤーが作成されるのを防ぎ、ベストプラクティスになります。 だからあなたの2行は
RUN mkdir /volume_data && chown postgres:postgres /volume_data
ただし、(上記のコメントで述べたように) VOLUME ...
を使用してボリュームを宣言する(または実際にはボリュームを宣言しない)前に、上記のRUN ...
コマンドを実行する必要があることに注意してください。 ボリュームを宣言した後に所有権の変更を行った場合(私が行ったように)、それらの変更は記録されず、失われます。
@colbygkそれは確かに便利ですが、それはLinuxがどのように機能するかではありません。 DockerはLinuxマウント名前空間を使用して、さまざまな単一ディレクトリ階層( /
およびサブフォルダー)を作成しますが、現在Linuxマウント名前空間でオーバーライドされているユーザー/グループマッピングまたはアクセス許可はありません。 コンテナー内の(およびバインドマウントボリュームを含む)これらの「マウント」は、ホスト上のファイルシステム上にあり(もちろん他のDockerボリュームプラグインを使用しない限り)、このファイルシステムはすべてを実行するLinuxVFSレイヤーを尊重していますファイルのアクセス許可を確認します。 ホスト上に、コンテナーがコンテナー内のファイルにアクセスするのを妨げる可能性のあるMAC(SELinux、AppArmorなど)が存在する可能性もあります。 実際、 chroot
を実行すると、chroot内のマウントフォルダーをバインドできるのと同様の問題が発生する可能性があります。また、chroot環境内で実行されているプロセスの有効なUID / GIDが間違ってファイルにアクセスする可能性があるという問題もあります。バインドマウント。
単純なLinux(そして実際にはUnixも)ルールがコンテナーに適用されます。 秘訣は、今日のLinux名前空間の可能性と限界を見て理解することです。そうすれば、この問題などの問題を解決する方法が明らかになりつつあります。 私は古典的なUnixコマンドを使用してそれを完全に解決しました。
@jcberthonあなたの思慮深い応答をありがとう:
これはあなたが提案するようにプラグインレイヤーにプッシュされる問題であり、したがってDockerに付属する汎用ボリュームハンドラープラグインの一部になる可能性があると私は主張します。 コンテナの派生元のイメージで定義されている本質的に静的な関係に外部リソース(特定のコンテナの外部)を強制的に適用することは、私のように非常にアンクラウド/コンテナのようです。
「unix」の他の同様の領域で発生する、この正確な種類のuid / gidマッピングの他の例があります。
私が間違っている場合は訂正してください。 https://github.com/zfsonlinux/zfs/issues/4177は、Linux上のZFSがUID / GID情報を正しく提供していないため、「LXC / LXDのリーダー」が原因であるようです。ここで説明しているほぼ_正確な_方法でコンテナを作成します。 https://github.com/zfsonlinux/zfs/issues/4177をよく見ると、zfsボリュームタイプは実際には名前空間間のこのuid / gidマッピングをすでにサポートしているようですが、そうするためのコントロールは公開されていません。
Dockerを使用するほとんどの人は開発/ CI用であり、php / nginx(ランナー)やgradle / python(ビルダー)などの「一般的な」イメージを使用するため、適切なソリューションは次のようになります。
ボリュームの書き込み権限(X:X:OPTION_READ_WRITE)は簡単に決定できるので、同じ方法で所有者を追加するのはどうでしょうか。
SOURCE:TARGET:RW:OWNER
私は同じ問題を抱えています。 おそらくベストプラクティスがあり、私の方法はそれではありません。
version: '3.5'
services:
something:
image: someimage
user: '1000'
expose:
- 8080
volumes:
- dev:/app
volumes:
dev:
これにより、 EACCES: permission denied, access '/app'
ます。
これをどのように行う必要がありますか? つまり、新しいボリュームを定義し、root以外のユーザーでそれにアクセスできるようにしますか?
こんにちは@Redsandro
someimage
Dockerイメージで/app
のUIDを1000に設定することをお勧めします。 または、それを制御できない場合は、作成ファイルのuser: ...
に、画像の作成者が意図したUIDまたはGIDを使用する必要があります。
もちろん、イメージの作成者がUID 0を使用していて、サービスをrootとして実行したくない場合(および非特権ユーザーとして実行できる場合)、Dockerイメージの作成者に問題を提起します。
@Redsandro次の回避策を確認してください: Dockerと--userns-remap、ホストとコンテナ間でデータを共有するためのボリューム権限を管理する方法は?
これはdockerが管理するものではないため、関連するコンテナーが開始する直前に、ボリュームをプロビジョニングするための別のコンテナーを作成できます。たとえば、 https://hub.docker.com/r/hasnat/volumes-provisionerを使用し
version: '2'
services:
volumes-provisioner:
image: hasnat/volumes-provisioner
environment:
PROVISION_DIRECTORIES: "65534:65534:0755:/var/data/prometheus/data"
volumes:
- "/var/data:/var/data"
prometheus:
image: prom/prometheus:v2.3.2
ports:
- "9090:9090"
depends_on:
- volumes-provisioner
volumes:
- "/var/data/prometheus/data:/prometheus/data"
Dockerがこれを修正しない理由がわかりません。開発目的でハッキングできることに同意しますが、本番環境では、方法はありません。
IMHO podmanは(非特権)ユーザーとして実行でき(ここもが作成ソリューションにも取り組んでおり、PodmanAPIはほとんどの部分で意図的にDockerと互換性があります。
[podman]は、大部分がDockerと互換性があるため、ここで一部の人々を助けるかもしれません。
完全に同意しますが、残念ながらpodmanはMacでは動作しません
完全に同意しますが、残念ながらpodmanはMacでは動作しません
そうですね、私見では、Dockerもpodmanもネイティブに動作することはありません。 しかし、OS / XへのDockerのインストールは、仮想マシンのものを非常にうまく隠しています。
ただし、適切な開発システムを構築するためにVMを手動でセットアップするのは面倒な場合があることに同意します。
ただし、ここでは少し話題から外れています。
私はもうOS / Xユーザーではありませんが、_experimental_ podmandmgがあることを確認しました。
podmanプログラマティックまたはpodman-composeにアクセスできるようになっているため、近い将来、同様のエコシステムが開発される可能性があると思い
これは、共有クラスターでsudo権限を持たないユーザーが、docker-composeを介してrootが所有するフォルダーを誤って作成し、それらのフォルダーを自分で削除できない場合に特に問題になります。
私もこの問題に遭遇しました。 jpetazzoの投稿でガイドされているように、 dockerを使用しようとしています。
このコンテナをdocker-composeファイルから起動し、dockerソケットをホストマシンからdockergroupの下のコンテナマシンにマウントできるようにします。 これは、root以外の別のユーザーを使用して、コンテナー内からdockerを実行できるようにするためです。
現在、バインドマウントファイルの所有権と権限を指定できないため、これは達成できません。
ここに私の2セントを入れてください:
docker-composeの「ネイティブ」ソリューションの場合、ほとんどの人がすでにイメージライブラリに高山を持っているので、これを行いました。
volumes:
media:
services:
mediainit:
image: alpine
entrypoint: /bin/sh -c "chown -v nobody:nogroup /mnt/media && chmod -v 777 /mnt/media"
container_name: mediainit
restart: "no"
volumes:
- "media:/mnt/media"
もちろん、最も安全な方法ではありませんが、コンテナーへの特権が付与されているコンテナーのみがそれを見るので、それほど大したことではありませんが、カーネルがサポートしている場合は、 user:userをchown
編集:少なくとも私のテストでは、chmodの前に最初にフォルダをchownする必要があるようです。そうしないと、「くっつきません」。
ボリュームの所有権はdocker-composeの制御下にないため、このディスカッションはmobyプロジェクトリポジトリの下で行う必要があります。
回避策を探している人のためのいくつかのメモ:
Dockerボリュームは、コンテナーによって最初に使用されるときに、コンテナーから継承された初期コンテンツとアクセス許可を取得します。 つまり、次のようにイメージを構成できます。
#Dockerfile
FROM alpine
RUN addgroup -S nicolas && adduser -S nicolas -G nicolas
RUN mkdir /foo && chown nicolas:nicolas /foo
# empty, but owned by `nicolas`. Could also have some initial content
VOLUME /foo
USER nicolas
このようなイメージは、明示的なボリューム(ランダムなIDを使用して意図的に作成されます)なしで実行された場合、またはまだ存在しない名前付きボリュームを使用して実行された場合、ボリュームへのアクセス許可を「伝播」します。
➜ docker run --rm -it -v some_new_volume:/foo myimage
/ $ ls -al /foo
total 8
drwxr-xr-x 2 nicolas nicolas 4096 Oct 18 08:30 .
drwxr-xr-x 1 root root 4096 Oct 18 08:30 ..
作成ファイルで宣言されたボリュームを使用する場合も同じことが当てはまります。
#docker-compose.yml
version: "3"
services:
web:
image: myimage
command: ls -al /foo
volumes:
- db-data:/foo
volumes:
db-data:
➜ docker-compose up
Creating volume "toto_db-data" with default driver
Creating toto_web_1 ... done
Attaching to toto_web_1
web_1 | total 8
web_1 | drwxr-xr-x 2 nicolas nicolas 4096 Oct 18 08:30 .
web_1 | drwxr-xr-x 1 root root 4096 Oct 18 08:37 ..
toto_web_1 exited with code 0
別のコンテナですでに使用されているボリュームを再接続した場合、これは機能しません。 ボリュームの所有権の変更、または作成時にこれを制御することは、エンジンによって、またはいくつかの特定のオプションを備えたボリュームドライバーによって実装する必要があります。 それ以外の場合は、提案されているように、いくつかのchown
トリックに依存する必要があります^。
お役に立てれば。
composeはボリュームの作成を制御できませんが、公開されたエンジンAPIを制御できるため、この問題を解決します。
最も参考になるコメント
実はここにニュースを持って来て、達成しようとしていることは実行可能のようですが、これが機能なのかバグなのかわかりません。 これが私が変更した理由です:
私のDockerfileで、_ユーザー 'postgres'に変更する
これは、ディレクトリ/ volume_dataを作成し、その権限を変更して、ユーザー 'postgres'が書き込みできるようにします。
これはDockerfileの部分です。
今、私はdocker-compose.ymlで何も変更していません:したがって、docker-composeはまだ名前付きボリューム
directory_name_db-data
を作成し、それを/volume_data
マウントし、権限は保持されています! 。つまり、名前付きボリュームが_pre-existing_ディレクトリ
/volume_data
マウントされ、アクセス許可が保持されているため、「postgres」で書き込むことができます。それで、これが意図された動作またはセキュリティの違反である場合はどうなりますか? (ただし、この場合は役に立ちます!)