1. ホーム
  2. ドッカー

docker-composeコンテナのマウント権限の問題

2022-03-03 22:31:45

       プロジェクトは、docker - composeの起動springbootアプリケーションに遭遇し、マウントされたログディレクトリは、問題を記述する権限を持っていない、その後、多くの情報をチェックし、最終的にいくつかの眉は、レコードを作る、その友人が少ないピットの〜を踏んで発生したことを願っています。

1. 問題の説明

        プロジェクトのフレームワークはjhipsterを使って生成されています。さて、ログの記録を見るためには、生成されたログをマウントする必要があります。まず、システムが生成したすべてのログファイルをプロジェクトのlogsディレクトリに格納するためにlogback-spring.xmlの設定を変更します。コードは以下のとおりです。

     次に、このディレクトリをlinuxの/temp/logs/bbb/ディレクトリにマウントします。以下は、app.ymlのコードです。

version: '2'
services:
    aiops-app:
        image: aiops
        volumes:
            - /temp/logs/bbb/:/home/jhipster/logs/
        environment:
            # - _JAVA_OPTIONS=-Xmx512m -Xms256m
            - SPRING_PROFILES_ACTIVE=prod,swagger
            - SPRING_DATASOURCE_URL=jdbc:mysql://test-mysql:3306/aiops?useUnicode=true&characterEncoding=utf8&useSSL=false
            - JHIPSTER_SLEEP=10 # gives time for the database to boot before the application
        ports:
            - 9999:8080

ここで、logs ディレクトリを /temp/logs/bbb/ にマウントし、dockerFile ファイルを見ます。このファイルは、Java アプリケーションを docker イメージとしてパッケージするために使用します。

FROM openjdk:8-jre-alpine

ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \
    JHIPSTER_SLEEP=0 \
    JAVA_OPTS=""

# Add a jhipster user to run our application so that it doesn't need to run as root
RUN adduser -D -s /bin/sh jhipster
WORKDIR /home/jhipster

ADD entrypoint.sh entrypoint.sh
RUN chmod 755 entrypoint.sh && chown jhipster:jhipster entrypoint.sh
USER jhipster

ADD *.war app.war

ENTRYPOINT [". /entrypoint.sh"]

EXPOSE 8080


ここでは、ユーザ jhipster を作成し、作業ディレクトリ /home/jhipster を設定します。次に、起動コマンド entrypoint.sh をイメージにコピーし、entrypoint.sh を jhipster ユーザに割り当て、jhipster ユーザでアプリケーションを起動します。entrypoint .sh シェルスクリプトは、次のとおりです。

#! /bin/sh

echo "The application will start in ${JHIPSTER_SLEEP}s... " && sleep ${JHIPSTER_SLEEP}
exec java ${JAVA_OPTS} -Djava.security.egd=file:/dev/. /urandom -jar "${HOME}/app.war" "$@"


ここで${HOME}ディレクトリはlinuxのユーザディレクトリである/home/{username}を指し、現在のユーザはjhipsterなので、ここでのappディレクトリは実際には/home/jhipster/app.warです。${JHIPSTER_SLEEP }は上記の環境変数JHIPSTER_SLEEP=0で、 docker-compose -f appで起動後、app.warを実行します。 yml up -d コマンドで起動すると、図のようにエラーが報告されます。linuxでは、docker on windowはユーザーディレクトリc:gucciにしかマウントできないのに、なぜかtest downはエラーが報告されない。

2. エラー報告の理由と解決策

エラーの原因は、docker-composeの起動時に、コンテナとホストにディレクトリを作成し、ホストではdockerプロセスでディレクトリを作成するためです。しかし、コンテナ内のアプリケーションはjhipsterユーザーで実行されており、当然ながらlogsディレクトリへの書き込み権限がないため、エラーが報告されます。2つのロールは同期されるため、解決策は、ホストログのパーミッションをdockerユーザーのパーミッションに変更します。以下のコマンドで、ホストログのディレクトリのパーミッションを変更することができます。

chown -R 1000:1000 "/temp/logs/bbb/"

修正前と修正後を比較すると、このようになります。

修正後、デフォルトのbbbディレクトリのパーミッションがrootからjhipsterに変わったことがわかります。1000はdockerのユーザーIDで、デフォルトのdockerユーザーIDは1000です。修正後、dockerコンテナのディレクトリlogsロールもjhipsterになり、パーミッションを統一して、アプリケーションがjhipsterで動き、ログファイルのディレクトリパーミッションもjhipsterになって、当然このディレクトリへのログ書き込みができるようになっています。

この方法のメリットは、修正が容易なことですが、デメリットは、手作業が増えることで、複数のディレクトリが絡むと面倒なので、別の方法を紹介します。

3. root 権限でコマンドラインに入り、権限を変更した後、jhipster ユーザーでアプリケーションを起動します。

基本は、rootユーザでコンテナ内のlogsディレクトリのパーミッションをjhipsterに割り当て、jhipsterユーザでアプリケーションを起動します。ここでは、gosuコマンドがあり、以下の場所にあります。 https://github.com/tianon/gosu このコマンドは、"su" と "sudo" に代わる軽量なコマンドで、tty やシグナリングに関する問題の一部を解決するものです。まず、以下のように dockerFile ファイルを修正して sudo コマンドのサポートを追加する必要があります。

FROM openjdk:8-jre-alpine

ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \
    JHIPSTER_SLEEP=0 \
    JAVA_OPTS=""

# Add a jhipster user to run our application so that it doesn't need to run as root
RUN adduser -D -s /bin/sh jhipster
WORKDIR /home/jhipster
ADD *.war app.war
ADD entrypoint.sh entrypoint.sh
RUN chmod 755 entrypoint.sh && chown jhipster:jhipster entrypoint.sh

# Use the root user and download the sogu tool
USER root
ENV GOSU_VERSION 1.11
RUN set -eux; \
	\
	apk add --no-cache --virtual .gosu-deps \
		dpkg \
		gnupg \
	\
	\\
	dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
	wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \
	wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \
	\
# verify the signature
	export GNUPGHOME="$(mktemp -d)"; \
# for flaky keyservers, consider https://github.com/tianon/pgp-happy-eyeballs, ala https://github.com/docker-library/php/pull/666
	gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \
	gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \
	command -v gpgconf && gpgconf --kill all || :; \
	rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \
	\
# clean up fetch dependencies
	apk del --no-network .gosu-deps; \
	\
	chmod +x /usr/local/bin/gosu; \
# verify that the binary works
	gosu --version; \
	gosu nobody true

ENTRYPOINT [". /entrypoint.sh"]

EXPOSE 8080




以前の内容と比較して、rootに切り替えてgosuツールをダウンロードするコードが追加されています。具体的なダウンロードコマンドは、gosuのgithubにあります。 https://github.com/tianon/gosu/blob/master/INSTALL.md というのも、dockerFileの最初の文にあるように、javaアプリケーションのビルドはこれに基づいているからです。

その後、entrypoint.shに移動して権限を与え、以下のようにjhipsterでアプリを起動します。ここで、rootユーザに切り替えなければならない理由は、chownを使用するとエラーが報告されるからです。

#! /bin/sh
chown -R 1000:1000 "logs"
echo "The application will start in ${JHIPSTER_SLEEP}s... " && sleep ${JHIPSTER_SLEEP}
exec gosu jhipster java ${JAVA_OPTS} -Djava.security.egd=file:/dev/. /urandom -jar "app.war" "$@"


これで解決です。この方法では、イメージをパッケージ化するたびにgosuをダウンロードすることになり、少し遅くなりますが、パーミッションを変更する必要はありません。

要約すると、この記事で紹介されているのは https://www.cnblogs.com/jackluo/p/5783116.html が、gosuをダウンロードする部分がうまく動作しないため、一部変更しました。