1. 程式人生 > >docker-compose 容器掛載許可權問題

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的部分不能正常使用;所以做了一些修改;