如何优雅地应用 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 中 COPY
或ADD
命令的绝对目录。
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 ps
或docker container list
查看正在运行的容器状态,增加 -a
则能够查看所有(包含已进行)的容器状态
进入容器
对于后盾运行的容器,能够应用 docker attach
和docker 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 容器中开数据库,是否适合?– 知乎