乐趣区

关于docker:如何优雅地使用-Docker

如何优雅地应用 Docker

很久很久以前,就已经尝试过应用 Docker。然而因为没有足够的能源学习,导致屡次大功告成(就像学 vim 一样)。
终于,在想要应用 gitbook 转换开源书籍时,被放弃保护的 gitbook-cli 给教育了。因而重燃起学习 Docker 的能源。


原文公布于 集体博客
同步备份至知否、掘金、知乎、腾讯云、微信公众号、哔哩哔哩

如果有谬误斧正或探讨,倡议在原博客评论,多平台可能无奈保障及时回复。同时无奈保障各平台内容放弃最新。

Docker 是什么

容器和虚拟机

容器和虚拟机不同,或者说除了看上去像,他们齐全是两个没有关系的货色。

虚拟机是 在计算机中模仿另一个计算机 的技术,重点在于模仿和另一个计算机。因而虚拟机须要先将物理机的硬件进行封装,并部署一个独立的操作系统。独立的操作系统调用模仿的硬件,实现各种性能。对于运行在虚拟机内的零碎来说,它仿佛就在一个真正的物理机上运行,不会受到过多的限度。

沙盒,其用处是 隔离运行环境 ,而非模仿计算机。因而它不须要虚拟化硬件,也不须要装置独立的操作系统。晚期的沙盒(如 Sandboxie)往往用于运行一些不被信赖的软件,在计算机平安等方面大放异彩。运行在沙盒中的软件,即便是攻击性很强的病毒,依然很难危害到物理机(但就如同虚拟机一样,沙盒也存在被穿透的危险)。能够将其了解成依然执行在物理机的宿主零碎之中,然而外部所有程序的零碎调用都被沙盒截取(就像 proxychains 能够批改任意子过程的网络连接一样)替换为本人的虚构的零碎调用。当外部的程序须要写出、读入一个文件(狭义上所有货色都是文件)时,实际上操作的是虚构的文件并不会影响宿主零碎。
在较新版本的 Windows 中,有一个叫做 Sandbox 的利用,点击后会弹出一个窗口,窗口外部是一个 Windows 零碎,这就是一个 Windows 的沙盒。

而容器则相似于沙盒的增强版,其容许通过配置有目的性地容许某些穿透操作(如将容器端口映射到宿主零碎、拜访宿主零碎的某个目录)。同时,也容许在容器中部署一个与宿主零碎类似但不同的操作系统(这里次要指能够诸如在 Arch Linux 应用 Ubuntu 镜像,然而如果是 Windows,其无奈间接应用 Linux 镜像,须要先应用 Hyper-V 虚构一个 Linux)。

所以,绝对于虚拟机,容器更为轻量级(只是替换子过程的零碎调用,而非模仿硬件且装置残缺的操作系统);绝对于沙盒,容器可操作性更多(能够有选择性地容许与宿主零碎进行交互)。因而也能够将沙盒了解为一种非凡的容器。
这也就是 Docker 在开发中受到宽泛推崇的起因,它能够隔离出一个自定义环境、部署快、容许有选择地穿透。刚好满足开发和部署过程中容易遇到的环境不统一问题。

Docker 的分层

Docker 在上述容器的根底上,还有额定的一些长处。在 Docker 中,操作是分层的。试想,你是一个前端工程师,你有两个我的项目须要开发——React 我的项目、Vue 我的项目。假如他们都运行于 Ubuntu,并且应用雷同版本的 NodeJS。如果应用下述的图中的链式关系,用户须要保护两份 Ubuntu 环境、两份 NodeJS 环境。而在 Docker 中,对于这些共有的内容,将会将其划分为公共的层。也即,他们都基于 Ubuntu 下的 NodeJS 镜像生成,而非从头开始生成。将会共用后面独特须要的局部。

目前很多镜像实际上都会应用 Ubuntu 作为操作系统,并且应用官网的一些环境作为开发环境。因而用户可能会应用很多的 Docker 镜像来部署本人的服务,但实际上因为他们在底层共用了雷同镜像,因而空间占用近似于部署在物理机(只节约了局部 Docker 自身所占用的空间和资源)

该设计原理上很奇妙,但理论应用中,特地是作为镜像的发布者而非使用者,还是须要破费功夫思考设计的。

装置

对于失常环境(如 Windows、Linux)能够间接在官网装置 Docker 即可。
而如果想要在 WSL2 中应用 Docker,则须要参考 Docker Desktop WSL 2 backend 和 Using Docker in WSL2

Docker 分为两局部:服务端、客户端。
所有的容器都会保留、运行在服务端,客户端仅仅用于管制。以 WSL2 为例,实际上 Docker 运行在 Hyper-V 的虚拟机中,客户端在 WSL 中操作 Windows 下的 Docker 管制虚拟机中的 Docker。在大部分状况下可能不须要思考这些关系,然而在须要通过 IP 端口互联时,须要确定到底要连到哪一个局域网 IP。

如果要通过 Docker 连回服务端所在设施,能够应用host.docker.internal

镜像

镜像是对于一些环境的封装(打包好的环境)。能够将其了解成安装包、压缩包,其自身是 不可改变 的。一般而言,镜像会基于官网提供的一些零碎为根底(如罕用的是 Ubuntu,也能够基于没有操作系统的 scratch),装置相应依赖程序为某些特定程序提供服务。

镜像信息查看

应用 docker images 能够获取所有本地存在的镜像,蕴含 5 列信息:

  • 镜像名称(蕴含用户名、镜像名)
  • 标签(版本)
  • 镜像 ID(哈希值)
  • 创立工夫(镜像自身创立工夫,而非下载或本地生成工夫)
  • 镜像大小(本镜像所有分层总大小)

因为后面提到的分层概念,实际上这里的镜像大小之和应该大于或等于理论占用大小(多个镜像可能蕴含雷同的分层)。

镜像的拉取

如果须要获取某个镜像,能够应用 docker pull < 用户名 >/< 镜像名 >:< 版本号 >。这里用户名和镜像名针对于官网 Docker 仓库,如果省略镜像名,将会从官网保护的镜像中检索;如果省略版本号,将会应用最新版本latest
如果须要从公有仓库拉去镜像,则能够间接 pull 对应的 URL

镜像导出、导入

无论是应用 Dockerfile 生成,还是间接从仓库获取分层,都须要破费工夫下载、耗费性能生成。而本地多设施要部署雷同的镜像,也能够间接将整个镜像导出成单文件,再在另一台设施上导入。这样能够更不便地在本地之间传输 Docker 镜像。
导出后的镜像文件相似于 ghost 备份,相当于间接把零碎保留成为一个单文件环境。

export/import

要导出镜像,能够应用 docker export [镜像名称] > xxx.tar。其中镜像名称能够应用 用户名 / 镜像名: 标签 ,也能够间接指定镜像 ID(只须要前几位即可)。
要将镜像导入 Docker,应用 docker import [文件名] [镜像名]。如果文件名为-,也能够应用重定向符从 stdin 读入文件。
应用 export/import 将会失落镜像的历史,仅仅保留最终状态的快照(也因而会更小)。一般来说,能够用于公布根底镜像(用户不须要应用历史记录等信息)

save/load

另一种计划则是基于 save/load 命令。导出镜像与 export 相似,应用 docker save [镜像名称] > xxx.tar。如果想要导出多个镜像,也能够应用 docker save xxx.tar xxx1 xxx2
要从新载入,应用 docker load < xxx.tar
绝对于后面的 export/import,save/load 更相似于“存档”的概念,其蕴含镜像的所有信息(包含历史),因而也无奈批改镜像名称,同时其反对将多个镜像保留到一个文件中。因而其更实用于同步设施之间的状态。

Dockerfile

Dockerfile 是一种非凡的文件,其能够被 docker build 辨认,用于生成镜像。在很多状况下,配置一个环境所须要的可能只是简略的配置,如果每一个环境都导出一份镜像将会消耗大量空间。对于这种状况,只提供一个短短几行的 Dockerfile,由用户设施主动进行配置更为不便。

每一个镜像都是由多个分层形成,每个分层绝对于上一分层也仅仅是通过某个命令进行文件的增删改。因而只有将这些命令保留下来,即可形容一个镜像。而有幸的是,Linux 的各种命令(特地是 busybox),齐全能够实现绝大部分所须要的行为。

以一个启动一个 Nginx 服务,并显示特定页面的镜像为例,只须要如下局部:

FROM nginx
RUN echo '<h1>Hello Docker</h1>' > /usr/share/nginx/html/index.html

这里,应用 FROM 指定了根底镜像——官网公布的 Nginx 镜像,并在其根底上执行echo '<h1>Hello Docker</h1>' > /usr/share/nginx/html/index.html。如果对 Nginx 有所理解,应该能够很容易看出这就是批改了 Nginx 的根底页面。

Dockerfile 应用各种操作实现了各种操作

命令 解释 备注
FROM 应用的根底镜像 除去常见的零碎镜像外,如果只须要运行某个程序,也能够应用不蕴含零碎的 scratch 间接执行二进制程序,以减小镜像大小 <br/> 一个 Dockerfile 能够存在多个 FROM,每个FROM 作为一个构建阶段造成一个独自的镜像 (能够应用FROM xxx as xxx 来设定阶段名称,应用 docker build --target 只构建该阶段)
RUN 要执行的命令 其蕴含两种格局 RUN <shell 命令 >RUN ["可执行文件门路","参数 1","参数 2",...]。<br/> 因为每一行命令都会被认为是独自的一层,因而通常须要尽可能应用 & 来连贯多个命令
COPY 复制文件 蕴含两种格局 COPY < 源门路 > ... < 指标门路 >COPY ["< 源门路 1 >", ..."< 指标门路 >"]<br/> 能够同时复制多个文件,且反对通配符。复制后会保留权限等元数据
ADD 减少文件 某种非凡模式的复制,其源门路能够是互联网上的文件地址。因为其会在网络下载,因而能够实时更新,但也会使得构建缓存生效
CMD 容器启动默认命令 RUN 雷同的两种模式,用于指定 Docker 启动后的默认命令(可能会被 docker run 笼罩掉)<br/> 因为 Docker 容易的存活依赖于前台程序,因而诸如启动 Nginx 须要间接执行 nginx 二进制文件,而不应该应用systemctl
ENTRYPOINT 入口点 RUN 雷同的两种格局。与 CMD 性能类似,在配置 ENTRYPOINT 后,默认的执行程序将会形如 <ENTRYPOINT> "<CMD>"。<br/> 如果镜像性能为调用某个程序,并传递某个参数,能够应用该计划来在docker run 时配置参数(可参考 curl 镜像)<br/> 用户能够用 --entrypoint 笼罩
ENV 设置环境变量 格局为 ENV <key> <value>ENV <key1>=<value1> <key2>=<value2>
ARGS 构建参数 ENV 相似,但 ARGS 设置的环境变量只会在构建期间存在,用户能够应用 docker build --build-arg < 参数值 >=< 值 > 笼罩
VOLUME 匿名卷定义 格局为 VOLUME ["门路 1","门路 2"...]VOLUME < 门路 >。事后将可能被批改的目录挂载为匿名卷,如果用户在未挂载时删除,依然能够保留数据
EXPOSE 申明端口 EXPOSE < 端口 1 > [< 端口 2 >...],申明将会映射出的端口。<br/> 仅仅只是申明,不会进行任何映射操作,用户须要应用 -p < 宿主端口 >:< 容器端口 > 指定映射,或应用 -P 主动随机映射
WORKDIR 指定工作目录 Dockerfile 的每一行都处于独立的运行环境,因而在 cd 只会作用于单个RUN。如果须要批改后续所有命令的执行目录,应用WORKDIR < 门路 >
USER 指定运行用户 切换到某个已存在的用户执行后续命令,须要应用 RUN 事后建设好用户
HEALTCHECK 健康检查 查看容器衰弱状态,有两种模式 HEALTHCHECK [选项] CMD < 命令 >HEALTCHECK NONE。别离为设置查看的命令与不应用查看 <br/> 参数包含距离(--interval)、时长(--timeout)、次数(--retries),依据完结码判断是否存活
ONBUILD 只在构建上级镜像时执行 该局部不会在构建以后镜像时执行,只会在构建以该镜像为根底镜像时会执行

上述命令中,所有形如 ["aaa","bbb","ccc"] 的命令都应该应用双引号",因为这些命令将会以 JSON 的模式被读入 Docker,而 JSON 规定的字符串应用双引号。

下面有提到应该尽可能应用 & 来连贯命令。以 apt install 为例,只管大部分状况下能够间接下载二进制文件,然而某些程序可能须要本地编译,从而产生很多两头缓存的文件。如果不及时清理,则会将这些缓存也存入分层数据中(而这显然是不用的)。因而,大部分状况下,RUN应该是相似上面的模式

RUN buildDeps='gcc libc6-dev make'
    && apt-get update \
    && apt-get install -y $buildDeps \
    && wget -I xxx.tar \
    && tar -xzf xxx.tar -C xxx \
    && make -C xxx \
    && make -C xxx install \
    && rm -rf xxx \
    && rm xxx.tar \
    && apt-get purge -y --autoremove $buildDeps

在编写 Dockerfile 的时候,必须时刻明确本人的目标——不是在写 Shell,而是在执行某个明确的操作,应该防止在分层中引入无关的内容。

对于一个曾经编写实现的 Dockerfile 文件,应用 docker build -f ./dockerfile -t xxx:v1 . 来将其生成为一个镜像。
这里,-f参数能够疏忽,疏忽后默认应用当前目录的 Dockerfile 文件;-t参数也能够疏忽,示意不指定名称和标签;最初的 . 示意构建上下文目录,也即 Dockerfile 中 COPYADD命令的绝对目录。
Docker 在应用 Dockefile 构建镜像时,将会把上下文目录的所有货色载入到镜像中。因而很多状况下,会间接将 Dockerfile 放在其所须要的上下文目录中。同时,这也意味着上下文目录(或者说 Dockerfile 目录)不应该有其余文件,否则将会节约额定的空间。如果不得不存在其余文件,能够应用 .dockerignore 以相似 .gitignore 的模式防止文件被导入至 Docker 中

为了方便使用,用户能够间接针对一个 URL 连贯进行构建。这个 URL 能够是一个 Git 仓库,也能够是一个 tar 压缩包。Docker 会主动拉取、下载对应内容,并将其作为构建上下文进行构建。如果传入-,则会从 stdin 读入要编译的 Dockerfile 内容、

镜像历史

应用 docker history < 镜像名 > 能够查看镜像的提交历史(这可能会裸露镜像历史中的命令,造成安全隐患)

镜像删除

对于不再应用的镜像,能够应用docker rmi [镜像名称 /ID] 来删除镜像。删除镜像将会开释未被其余镜像应用的分层,同时会导致所有依赖该镜像的容器无奈间接运行。

容器

执行的镜像称为容器,能够了解为类与实例之间的区别。在任何状况下,都应该确保容器是 无状态 的——容器能够随便的敞开、删除、重启,而不会影响业务性能。
对于容器中须要保留的状态,应用存储卷来存储

要基于某个镜像运行容器,应用 docker run [选项] 镜像名 [命令] [参数...]。最常见的模式为docker run -it -p 80:80 -v ./data:/data xxxx /bin/bash
如果要启动的镜像不存在,将会主动调用 pull 命令下载镜像。
应用 docker help run 能够获取具体的解释,这里只介绍罕用的一些参数。

参数 解释 备注
-d 后盾运行 容器在后盾运行,所有输入将会输入至日志。能够应用 docker container logs < 容器名 > 查看
-e 环境变量 设置环境变量
--gpus 应用 GPU
-i 放弃 stdin 激活 程序将应用宿主的 stdin
--name 设置容器名称 默认会随机一个名字
-p 映射的端口号 格局为-p < 宿主机端口 >:< 容器端口 >,能够屡次传该参数映射多个端口
-P 随机映射端口号 将容器内凋谢的端口全副映射到宿主机的随机端口
--read-only 设置容器只读
--rm 容器完结后主动删除
-t 连贯到容器后应用的终端 须要绝对路径
-u 应用指定用户
-v 挂载的存储卷 格局为-v < 宿主机门路 >:< 容器绝对路径 >,能够屡次传该参数挂载多个存储卷(宿主机门路应用相对路径时,会基于存储卷目录)
-w 默认工作目录

容器状态

容器存在有运行、进行两种状态。对于已进行的容器,能够应用 docker container start < 容器名 > 再次启动它。而对于正在运行中的容器,应用 docker container stop < 容器名 > 终止。
对于用户应用 -it 连贯的容器,当用户应用 exit 或是 CTRL+D 退出后,会立刻终止。容器中没有正在运行的前台程序时,也会立刻终止。

能够应用 docker psdocker container list查看正在运行的容器状态,增加 -a 则能够查看所有(包含已进行)的容器状态

进入容器

对于后盾运行的容器,能够应用 docker attachdocker exec来进入容器。这两种的区别在于应用 attach 进入后退出,将会导致容器进行;而 docker exec 不会导致容器进行。
前者相似于间接挂入正在执行的前台程序,而后者更相似于 SSH 新建一个终端(能够应用 -it 指定应用的终端)

容器导出

容器与镜像一样,也能够应用 docker export 导出,不过其原理上是先将容器存储为镜像,再将镜像导出。因而应用 import 导入后,失去的是镜像,而非容器。

容器转换为镜像

对于无状态的容器,能够将其提交为镜像。应用 docker commit [选项] < 容器名 > [镜像名 [: 标签]] 能够将一个容器转换为镜像。与 Git 的 commit 相似,这实际上是一个提交,用户能够应用 -m 填写提交信息,应用 -a 填写用户名,应用 -p 在提交时暂停容器。

这是一种较为简单的镜像建设计划,然而正如同前文 Dockerfile 局部强调的,这种操作会建设并不会理论须要的分层,因而并不是较为优雅的实现计划。
在转换为镜像前,能够应用 docker diff < 容器名 > 查看容器的改变,来确定这是不是一个优雅的新镜像。

删除容器

应用 docker container rm 能够删除处于终止状态的容器。而对于正在应用中的容器,则能够应用 docker container rm -rf 强行删除(会在删除前先进行容器)

如果想要删除所有未运行的容器,能够应用docker container prune

存储卷(目录挂载)

在 Docker 中,存储卷 (volume) 或者说宿主机文件 / 目录挂载实际上是一个货色——将宿主机的特定文件夹 / 文件挂载到容器中,以不便容器外部读写。惟一的不同在于,目录挂载对应的宿主机目录往往是用户指定的,而存储卷寄存于 Docker 指定的非凡权限目录(可能在/var/lib/docker/volumes

因为后面提到容器应该是无状态的,因而所有长久化的数据应该被寄存在存储卷中,也即宿主机中。这很好了解,容器可能会被删除,甚至 Docker 都可能会被删除,然而起码宿主机自身的文件夹还是较为平安的。

存储卷中文件的状态将和容器外部完全一致。比方如果在容器外部应用非凡用户建设一个文件,那么宿主机中看到的也将是对应的用户的 UID(宿主机可能不存在该用户)。

空间治理

Docker 所占用的空间蕴含四局部:

  • 镜像
  • 容器
  • 本地卷
  • 缓存

应用下述命令能够查看 Docker 所占用的空间

docker system df -v

如果心愿对空间进行清理,能够

  • 应用 docker container prune 能够革除所有终止的容器
  • 应用 docker system prune 能够在上述根底上,革除未被应用的网络、悬空的镜像和缓存
  • 应用 docker system prune -a 能够在上述根底上,革除所有未被应用的镜像和所有缓存
  • 对于未被应用的存储卷,须要应用 docker volume prune 来革除

其余操作

服务端配置{#daemon_config}

Docker 的服务端的配置寄存在 /etc/docker/daemon.json 中(须要严格遵守 JSON 格局撰写,如列表的最初一项不带逗号)。

然而,大概率在很多状况下,间接改变 daemon.json 会导致 Docker 无奈启动。造成这个问题的起因是:官网认为,如果 systemctl 启动项和 daemon.json 有抵触,阐明用户配置不当,可能会造成意想不到的谬误,因而在抵触时会间接报错。
实践上这仿佛没什么故障,然而一般而言,systemctl默认会携带一些参数(如监听的地址),而这些参数可能又是咱们会常常改变的,这么就会导致无奈启动的概率会十分大。

要解决该问题也很简略,只须要批改 systemctl 启动参数即可。依照下面的链接,批改 /etc/systemd/system/docker.service.d/override.conf 文件为

[Service]
ExecStart=
ExecStart=/usr/bin/dockerd

接着应用上面的代码重载配置并重启 docker 即可

sudo systemctl daemon-reload
sudo service docker start

在这之后,因为 systemctl 未传递任何参数,因而无论 daemon.json 有哪些配置,都不会产生抵触导致出错。

调用近程服务端

上文提到过,Docker 的服务端和客户端实际上是拆散的,因而这里次要讲一下如何在本地调用近程 Docker 服务。须要留神的是,只管后果上与应用 SSH 到服务端后应用服务端上的 Docker 客户端后果一样,然而依然在某些非凡状况下存在意义(见下文)

应用上述的服务端配置局部,容许从 daemon.json 配置后。写入

{
    "hosts": [
        "unix:///var/run/docker.sock",
        "tcp://0.0.0.0:2375"
    ]
}

这里配置两种连贯到 Docker 服务端的形式:

  • 应用本地 Unix 域连贯
  • 应用凋谢到公网 2375 端口的 TCP 连贯(如果是127.0.0.1,则只容许本机拜访)

须要特地留神的是,如果凋谢了公网连贯,那么须要自行进行安全性防护。因为任何人都能够尝试连贯到该服务,甚至能够借助端口扫描工具扫到你的服务器存在凋谢的 docker 服务。这将造成 <span style=”color:red;font-weight:bold”> 安全隐患 </span>(存在主动扫描工具挂马)。因而倡议只在测试环境或局域网中凋谢近程连贯。

在这之后,即可在另一台电脑应用 IP 和端口进行近程连贯了。

镜像减速!

家喻户晓,因为网络起因,国内应用位于海内的官网源会十分慢。因而往往须要应用国内的镜像源。

/etc/docker/daemon.json 内配置如下内容(Windows 能够间接在图形界面内配置),即可抉择应用百度、网易、腾讯的镜像。享受高速的下载

{
    "registry-mirrors": [
        "https://mirror.baidubce.com",
        "https://hub-mirror.c.163.com",
        "https://mirror.ccs.tencentyun.com"
    ]
}

乏味的想法和测试

在 Docker 跑数据库?

依照上述思路以及 Docker 的一些数据库镜像。可能会有这样的想法:
将数据库在 Docker 中运行,长久化数据挂载到宿主机中。这样部署只须要做好数据库长久化文件即可

看上去仿佛没什么故障,然而具体执行起来可能存在一些问题。首先是数据库的重要性应该是高于程序的。程序挂了,重启即可,失落的状态无限。而数据库挂了,不仅仅会导致短时间所有程序无奈应用,还存在数据失落的隐患。当引入 Docker 这一额定因素后,Docker 自身故障也将会减少数据库故障的概率。而数据库的长久化也不是实时的,依然存在数据失落甚至损坏的可能性。
只管数据库也有隔离的需要,然而更好的方法是将其运行在独自的物理机上,这样还能够确保数据的平安。

也有人提出数据库将会被 IO 瓶颈限度,不过这更多应该是针对于同一个设施运行多个数据库 Docker。集体认为这实际上并不能作为一个理由。

如果用这里始终强调的内容来看,更实质的起因在于应用 Docker 跑数据库并不优雅——数据库是有状态的,即便挂载存储卷依然有状态。这其实更相似于个 能够但没必要 的状况,Docker 提供的劣势无限次要在于部署不便,这对于绝对较为确定的数据库(市面上罕用的数据库十分固定,绝对于程序运行环境的复杂度而言,约等于一键部署)并没有什么意义。与其减少其余危险,不如间接宿主机跑。然而,如果是为其余用户提供一个疾速部署的 Demo,那么应用 Docker 部署数据库还是极为优雅的。

Docker 容器在本地还是服务器执行?

要验证很容易,既然是两个设施,那么他们的公网 IP 必然是不同的。

咱们别离在本机和服务器获取公网 IP

很显著,前者(本机)是教育网 IP,而后者(服务器上的容器)是腾讯云 IP。那么该问题得以确定:容器在服务器执行

能够近似将其看作一个 SSH 连贯,咱们只是连贯到服务器上执行操作而已。

Docker 挂载的目录在本地还是服务器?

同上,能够将 /home 挂载到 Docker 容器中,依据挂载后的内容即可分辨到底挂载的是什么目录。

本地的用户名为 ohyee,而服务端的用户名为 ubuntu。那么很显著,这里实际上挂载的还是服务端的目录。

然而,这是存在例外的。 Docker 为 WSL 提供了特供版,在这个特供版里,Docker 挂载的将会是 WSL 内的目录,而非存在于 Windows 的服务端目录。
另外值得一提的是,Windows 中的 Docker 实际上是运行于虚拟机的,因而挂载 / 目录实际上挂在然而 Hyper-V 的 Docker 虚拟机目录。如果须要挂载某些 Windows 特定文件夹,能够应用/c/Users/...,当然也能够在 WSL 中应用/mnt/c/Users/...

参考资料

  • docker 容器与虚拟机有什么区别?
  • 《Docker 从入门到实际》
  • Docker 教程 | 菜鸟教程
  • Docker Volume – 目录挂载以及文件共享
  • 在 docker 容器中开数据库,是否适合?– 知乎
退出移动版