• 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

    然后在测试一次,依然成功,洗漱睡觉!!

  • 相关阅读:
    Div添加滚动条
    JAVA正则表达式 Pattern和Matcher类
    颜色代码对应表
    Java排序方法
    Windows切换窗口
    SVN错误信息汇总
    @RequestMapping 用法详解
    java——国际化详解
    Java NIO学习笔记九 NIO与IO对比
    ROS学习笔记十二:使用gazebo在ROS中仿真
  • 原文地址:https://www.cnblogs.com/nsky/p/13358142.html
Copyright © 2020-2023  润新知