docker-compose 容器掛載許可權問題
專案中遇到docker-compose啟動springboot的應用,掛載的日誌目錄沒有許可權寫入的問題;後來查了很多資料,終於有點眉目了,做個記錄,希望遇到的朋友少踩點坑~;
1.問題描述
專案框架是使用jhipster生成的,現在需要把生成的日誌掛載出去,以便檢視日誌記錄;首先修改下logback-spring.xml的配置,將系統生成的日誌檔案都存放在專案的logs目錄下面;程式碼如下
然後把這個目錄掛載到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 shell指令碼的具體內容
#!/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" "[email protected]"
這裡的通過java -jar 來啟動app,這裡的${HOME}目錄指的是linux的使用者目錄,/home/{使用者名稱},因為當前的使用者是jhipster,所以這裡的app目錄其實是/home/jhipster/app.war;這裡的${JHIPSTER_SLEEP}是上面的環境變數JHIPSTER_SLEEP=0;通過docker-compose -f app.yml up -d 命令來啟動之後,就報錯了,具體如圖所示,在linux中會報錯,docker在window上只能掛載到使用者目錄c:\\users\\test\\,不知為啥測試下來不會報錯的;
2.報錯原因及解決方案
錯誤的原因是,docker-compose啟動的時候會分別在容器和宿主機上建立目錄,在宿主機上是使用docker程序來建立目錄的,預設使用的角色是root,目錄掛載的時候會把這個使用者同步到容器裡面的目錄,所以容器裡面logs目錄許可權也是root,但是容器裡面的應用是使用jhipster使用者來執行的,當然沒有往logs目錄裡面寫的許可權,所以就報錯了;因為這兩個角色是會同步的,所以解決的辦法就是修改宿主機的日誌許可權為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,這個命令用來替換sudo,它是"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
#使用root使用者,下載sogu工具
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,注意使用alpine的版本,因為java應用構建是基於這個的,從dockerFile第一句話可以看出;
之後再到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" "[email protected]"
這樣就解決了;這種方式的話,每次打包映象的時候會去下載gosu,會慢一點,但是不用自己修改許可權了;
總結:文章參考了https://www.cnblogs.com/jackluo/p/5783116.html,但是文章裡面下載gosu的部分不能正常使用;所以做了一些修改;