Docker
解决的问题
环境一致性的打包和分发
不要把程序"单独"送过去,要把程序 + 它需要的一切(glibc、Python、依赖库、系统工具)打包成一个 标准容器,送到哪里都是一样地跑
实现(Linux)
Docker 依赖 Linux 内核能力,尤其是 namespace、cgroup、overlay filesystem、iptables/nftables
docker CLI ↓ dockerd / containerd ↓ Linux kernel ↓ namespace / cgroup / overlayfs / 网络栈 ↓ 容器进程
docker 是由一个有 root 权限的 dockerd 守护进程管理
docker-cli 处理命令行的命令,dockerd 调用容器运行时 containerd,它再通过 runc 与操作系统交互
人们认为 dockerd 有 root 很坏,不安全
容器不是传统虚拟机。它们共享宿主机 Linux 内核,只是被 namespace/cgroup 隔离起来。
实现(Windows)
Docker Desktop(这个 exe 应用程序)使用 WSL2 创建一个名为 docker-desktop 的 Linux 虚拟机。这个虚拟机的系统文件和数据都存储在 docker_data.vhdx 这个虚拟硬盘文件中
即 Docker 的一切(包括容器镜像存储卷、引擎)被放在这里(后续可能还会变,并且你也可以换)
它在 设置 -> 资源 -> 进阶 里可以看到,那个"Disk image location":
%AppData%\Local\Docker\wsl\disk\docker_data.vhdx
备注:wsl2 里是可以构造好几个虚拟机的,不是只有 docker-desktop,你可以装自己的。(安装 Docker 时,它建议是用 wsl,所以可能不一定要基于 wsl)
(Windows 不只可以跑 Linux containers,也可以跑 Windows containers,不过一般都是前者)
实现(Mac)
也是跑一个内置的虚拟机,在 Mac 上,此虚拟机可选(在设置里可换),默认是 Apple Virtualization Framework。
Docker VMM 是一个 Beta 选择,但是它的提示是性能更优
并默认开启 Rosetta 来转译 x64 程序
磁盘在 ~/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw
命令行
命令行使用 docker,你需要本机先启动 docker,别在没启动 docker 时使用,而不知道哪里错了
检查:docker version 必须显示 Server,而不只是 Client
镜像与容器
镜像类似于可执行文件本身
容器类似于跑起来的进程
所以和普通程序一样,数据并不能放在镜像里,而是放在镜像外面
镜像位置及复用
镜像的位置众说纷,我也没找到
https://stackoverflow.com/questions/42250222/where-is-docker-image-location-in-windows-10
建议是,有需要导出的时候
docker image save myimagename -o myimagename.zip镜像复用的处理比较复杂
Dockerfile 的每一条指令,代表产生了一个新的"层",每一层有一个唯一 hash
如果你 pull 一个新的镜像,Docker 会检查这个镜像的清单文件,检查所有的层
即,如果你两个不同的镜像,第一条语句都是安装 ubuntu20.04 那确实会复用到
外部仓库
Docker Hub 是默认的源,里面存储着 Docker 镜像(无论是否登陆,都限速),镜像名字不需要声明 url,直接写
GHCR 是 GitHub 版的镜像仓库,镜像名字必须是 ghcr.io/owner/repo:tag
GITHUB_TOKEN 自带写权限
存储卷
“被系统抽象出来、可以挂载使用的存储区域”,被 Docker 管理的一个持久化目录
Volumes 设计为持久存储可读写,但是镜像 Images 是只读的,Volumes 让数据独立于容器生命周期
在 Linux 上,卷默认被放在 /var/lib/docker/volumes/mysql-data/_data
Windowsw 上,在 \\wsl.localhost\docker-desktop\mnt\docker-desktop-disk\data\docker\volumes (Docker version 27.5.1, build 9f9e405);这个位置,只有在 docker 启动后,才能看到。一旦 docker 结束,该位置会变成一个 json
当然你在 GUI 界面的 Volumes 里可以直接看到所有卷
对于 Linux,就是直接占你的本机磁盘的空间;对于 win/mac 则是占你虚拟机内部的空间,最后体现在 vhdx 里
生命周期:
1、卷 和 镜像 是独立的
2、一个卷可以被多个容器同时使用
命令:
docker volume create mysql-data
docker run -v mysql-data:/var/lib/mysql mysql绑定挂载
Docker 存储数据的两种主要“流派”:具名卷 (Named Volumes) 和 绑定挂载 (Bind Mounts)
即直接拿本记目录去挂载(都是挂载目录,一个在本机,你可以自己看见,修改;一个被 Docker 管理)
n8n 是前者,Milvus 是后者
放在 yml 旁边的好处是所见即所得,迁移简单
追求性能用 Volumes
命令:
docker run -v ~/project:/app node网络
在 Mac/Windows 上,Docker 在一个虚拟机里,虚拟机的网络是 NAT 模式
在 Linux 上,Docker 会创建自己的虚拟网卡,容器内依然有自己的网络命名空间
应用程序(容器)监听的端口一直是容器内部的
所以需要端口映射 -p (ports)
expose 只声明容器内部服务端口,主要给同一个 Docker 网络里的其他容器看
Dockerfile
描述如何制作一个容镜像所需的步骤
大致包含:OS、Python、各种包等等
你自己去 build,默认和其他网上下载的镜像放在同一个位置,并不会出现在你的当前目录
Compose
(compose:组成)
很多项目,都是通过提供 docker-compose.yml 来配置多个容器(前后端分离),在 UI 里,就是 Containers 下一个可以展开的东西
你如果不知道你那个 Container 是从哪个 yml 来的,你可以点击它的名字,然后在这里看到

有一些 docker-compose.yml 只依赖远程镜像,这种你可以把它拿走,在任何位置跑起来
还有一些依赖于当前目录,比如 duild .,或者依赖 env 文件之类的
从命令行运行容器
docker compose up -d
docker compose -p "myproject" up -ddocker compose up:根据当前目录下的 docker-compose.yml 文件(或指定文件)启动所有定义的服务。
d 表示以“后台模式”(detached)运行容器,即容器启动后不会占用当前终端
p 项目准备叫什么,如果不给,似乎是 yml 所在的文件夹的名字
f yml 文件名
docker compose 和 docker-compose 是同一个效果
是死是活?
docker run -it --rm --name n8n -p 5678:5678 -v n8n_data:/home/node/.n8n docker.n8n.io/n8nio/n8n
这个 n8n 的命令,因为有 rm 所以结束后就似了
比如 dify 的命令,它是让你下载 yml,然后和compose up -d
Q:为什么删了 git 仓库,容器还在跑,下次重启电脑后,应该找不到 yml 了,按理说应该起不来了
A:yml 是建筑图纸,而容器是根据图纸盖出来的大楼,楼盖好以后,删了图纸楼并不会塌(包括重启)
你最开始 compose up -d时,属于一个 yml 的容器会有同一个 Labels,所以 UI 上能给你放在一起
服务是什么
Docker Compose 和 Kubernetes 都以声明式的 YAML 文件来描述“我要运行哪些容器,以及它们之间如何协作”,但是 k8s 功能更多,并且可以跨机器
docker-compose.yml 里面可以配置多个容器,统一部署
服务是对容器的声明式管理与编排,而容器是服务运行时的具体实例
在 docker 里,写 dockerfile 就是写服务
服务是对容器组(或容器集群)的声明式描述:你在服务里告诉编排系统(Docker Swarm、Kubernetes、Compose 等)想要运行多少个副本(replicas)、用哪个镜像(image)、要挂载哪些网络或存储卷、采用怎样的更新策略(rolling update)