aspnetcore+docker 容器目錄掛載


玩過docker容器的人,對數據掛載肯定不陌生,volume :幾種叫法,數據卷,資料卷

通過 -v 把宿主機目錄綁定到容器中的目錄

數據掛載的好處,僅僅是我認為的。不一定正確

1:數據能持久化保存,因為容器一旦刪除,啥都沒有了。但掛載的目錄是不會刪除的

2:修改和查看方便,比如要修改和查看數據,直接看本地,不用進去容器看,比較容器里面很多命令是沒有安裝的

 

這種方式是:-v 的方式稱之為:bind mount,要區別於volume

 

volume方式是在Dockerfile 指定,比如:

VOLUME /data

VOLUME ["/data1","/data2"]

 

bind mount

  容器以宿主機文件夾為准

volume

  宿主有數據時,以宿主機為准

  宿主無數據,從容器復制過來,再以宿主機為准

 

這里講的是bind mount方式,通過查看容器的inspect 就可以發現

 

 

 

首先來 看一個我們常用的netcore 打包成鏡像的Dockerfile

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
ENV TIMEZONE Asina/Shanghai
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY . .
RUN dotnet restore

RUN dotnet build

FROM build AS publish
RUN dotnet publish "mytest.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "mytest.dll"]

 

首先build成images

docker build -t test .

 

如果不掛載的方式,運行容器

docker run -d -p 8080:80 --restart=always --name my test

 

這樣netcore文件都在容器的/app中,每次查看,都必須 docker exec ... 進入容器

 

那么已掛載的方式呢,相比很快就會想到了-v,立馬嘗試

docker run -d -p 8080:80 --restart=always -v /root/data:/app --name my test

-v /root/data:/app  意思是把容器內的app目錄,掛載到宿主機的/root/data中,也就是2個目錄bind

首先明確下,我這里是沒有提前創建/root/data 這個目錄的。不過掛載后,docker會給我們創建

但run之后,這個容器是起不來的,不過我這里加了restart,所以一直重啟,

為什么這個容器run不起來?我們來分析下

只要理解了volume的意思,

 

bind 一定要注意,主機目錄為空的話,會清空容器的目錄,

也就是說,我們沒掛載的時候,容器內app是有東西的,當我們把本地一個空 目錄(/root/data)

掛載到容器內的/app下,就會清空容器內文件夾的內容,

就是說:你掛載了宿主機目錄,我就以宿主機目錄為主,容器的內有數據,我都給清空,所以導致容器無法啟動

因為你Dockefile 中的入口是:ENTRYPOINT ["dotnet", "mytest.dll"]

都沒有這個mytest.dll,自然無法啟動


也許有人會問,壓根就沒必要這樣掛載啊,我只掛載需要的,比如日志文件,配置文件,

那好,繼續干

docker run -d -p 8080:80 --restart=always -v /root/logs:/app/logs -v /root/appsettings.json:/app/appsettings.json --name my test

logs  一開始肯定是為空,項目跑起來才生成,沒問題

appsettings.json配置文件,手動拷貝即可

 

但我在開發的時候就有一個疑問,項目里面不僅僅這2個文件,還會有upload上傳文件

template 模板文件,nlog 配置文件我覺得寫多個-v不合適,

我就琢磨着。不能在容器啟動的時候,把內部的數據拷貝到宿主機器嗎。

容器數據拷貝到宿主機命令:

docker cp my:/app /root/myapp

 

宿主機拷貝到容器,反過來即可

docker cp /root/myapp my:/app

 

所以我想到了2種方法,估計不是最優的

1:數據掛載后,手動拷貝文件到本地目錄,但我們是通過dockerfile 運行的

難道我又手動 dotnet publish ....一次,繁瑣

 

2:容器運行后,把容器數據拷貝到本地,不行嗎?是行的

 

分析:

  既然數據在容器路徑app中,運行的時候,會清空,那為什么不事先保存在其他目錄中了

那修改下上面的Dockerfile

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
ENV TIMEZONE Asina/Shanghai
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY . .
RUN dotnet restore

RUN dotnet build

FROM build AS publish
RUN dotnet publish "mytest.csproj" -c Release -o /app/publish

FROM base AS final
# 創建一個文件夾,存放文件,同時是被復制到宿主機的 RUN mkdir -p /data # 這是程序的最終工作目錄,也就是宿主機掛載的目錄 WORKDIR /app COPY --from=publish /app/publish /data
ENTRYPOINT ["dotnet", "mytest.dll"]

 

加了一個data存放文件,程序啟動的時候,把data拷貝到宿主機目錄,綁定到宿主機app中

自己寫一個shell文件,init.sh,我是這樣寫的

#運行容器,設置了restart,會一直重啟,等待下面的拷貝完成,就會啟動成功
docker run -d -p 8802:80 --restart=always -v /root/data:/app --name my test
#把容器內部的數據拷貝到本地掛載目錄
docker cp my:/data /root
#刪除容器中的data文件,非必須的操作
docker exec my rm -rf /data

 

然后執行 sh init.sh,OK,訪問成功!

 

有沒有感覺這樣搞很麻煩。。確實,我自己看了都覺得麻煩,先是run,然后又cp。最后又exec

那為什么不把這些命令統一起來呢。仔細分析,上面的Dockerfile的入口是執行一個dll

ENTRYPOINT ["dotnet", "mytest.dll"]

當啟動主程序之前還需要執行大量的前置操作時, 可以將 ENTRYPOINT 的入口指令設置為一個腳本  ,我這里添加一個  start.sh

所以我們改進下:

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
ENV TIMEZONE Asina/Shanghai
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY . .
RUN dotnet restore

RUN dotnet build

FROM build AS publish
RUN dotnet publish "mytest.csproj" -c Release -o /app/publish

FROM base AS final
RUN mkdir -p /data WORKDIR /app COPY --from=publish /app/publish /data COPY start.sh /data RUN chmod +x /data/start.sh ENTRYPOINT ["/data/start.sh"]

我們依然是把publish 的文件放到data中。然后ENTRYPOINT 統一執行一個start.sh

start.sh腳本為:

#!/bin/bash
mv -f /data/* /app
dotnet mytest.dll

最后build和run就會按照預期的效果

docker build -t myimages .

docker run -d -p 8804:80 -v /root/mynew:/app --name my myimages

 

然后在測試一次,依然成功,洗漱睡覺!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM