初探 Docker

分割线

概念速览

刚接触 Docker 时容易被一家子工具绕晕, 安装时也会冒出几个相关选项:

20210131002505 20210131004332
工具定位解决什么问题
Dockerfile构建镜像的脚本把环境/依赖/启动命令写死, 镜像可复现
docker-compose多服务编排一个 YAML 起一组容器 (DB + 后端 + 网关…)
docker-machine多 Docker 主机管理远程机器/集群上批量管理 Docker daemon (已淡出)

docker-machine 现在基本被 K8s / Swarm / Portainer 取代, 新项目用不到了, 只在老文档里偶尔见.

Dockerfile

构建镜像的文本脚本, 由一行行指令 (FROM / RUN / COPY / CMD 等) 组成, 描述"基础镜像 + 我装啥 + 我跑啥".

Docker Dockerfile - runoob

docker-compose

单机起多服务的编排工具. 一个 docker-compose.yml 描述所有服务、网络、卷, docker compose up -d 一键拉起.

新版 Docker 已内置 docker compose (空格分隔) 子命令, 不再依赖独立的 docker-compose Python 脚本.

docker-machine

跨主机管理 Docker daemon 的命令行工具. 现在生产环境一般用 K8s 或 Swarm, 这个工具维护停滞, 仅作了解.

Docker 三剑客之 docker-machine - 知乎

分割线

安装与升级

Windows

Docker 引擎本质是 Linux 内核技术 (namespace + cgroup), 不能直接跑在 Windows 上. Docker Desktop 在底层依赖 WSL2 提供 Linux 内核.

详见 🎇 尝试转投 wsl 生态.#名词解释

Ubuntu / Debian

Ubuntu-Server 装系统时勾选 Docker 选项即可一键装好. 默认 docker 命令需要 sudo, 把当前用户加进 docker 组就能免 sudo:

sudo groupadd docker          # 用户组通常已存在, 报 already exists 可忽略
sudo usermod -aG docker $USER
# 重新登录或 newgrp docker 让组权限生效

加入 docker 组等同于 root 权限 (能挂任意目录到容器再读 host 文件), 多人服务器慎用.

升级到最新版

Docker CE 通过官方 apt 源管理, 升级走标准 apt 流程, 不会动现有容器和卷:

sudo apt-get update
sudo apt-get install --only-upgrade docker-ce docker-ce-cli containerd.io docker-buildx-plugin
  • --only-upgrade: 只升级已装的, 不会拉新的依赖.
  • containerd.io: 容器运行时, 跟 docker-ce 是绑死版本关系, 一起升才不会版本错位.
  • docker-buildx-plugin: BuildKit 前端, 新版 docker build 默认走它.

升级完用 docker version 看 Client / Server 两个版本是否对齐. 如果只升了 client 没升 server, 容器拉不起来时会报 API 版本不兼容.

大版本跨越 (比如 20.x -> 24.x) 升级前最好 docker compose down 让所有服务停掉, 升完再 up -d. 在线升级 daemon 时正在运行的容器会被一起重启, 有状态服务可能丢数据.

服务管理 (systemctl)

# 启动
sudo systemctl start docker

# 开机自启
sudo systemctl enable docker

# 改完 /etc/docker/daemon.json 后, 先 reload 再 restart
sudo systemctl daemon-reload
sudo systemctl restart docker

分割线

加速与代理

镜像加速

国内直连 Docker Hub 经常慢甚至超时, 配镜像源是必备操作. Windows 在 Docker Desktop 的 Settings → Docker Engine 里改 JSON:

{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
20210205010825

Linux 改 /etc/docker/daemon.json, 然后 systemctl daemon-reload && systemctl restart docker. 用 docker info | grep -A 5 Mirrors 验证生效.

大厂镜像源近两年陆续失效或限速, 上面只是示例, 实际可用列表 DaoCloud 维护的清单 比较新.

Docker 自身走代理

配了镜像加速一般就够了; 镜像源也拉不到时再考虑挂代理.

Docker Desktop 在 Settings → Resources → Proxies 里设, 例如 http://localhost:7890.

Linux 走 systemd drop-in:

sudo mkdir -p /etc/systemd/system/docker.service.d/
sudo nano /etc/systemd/system/docker.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
Environment="NO_PROXY=localhost,127.0.0.1"
sudo systemctl daemon-reload
sudo systemctl restart docker

容器内使用宿主机代理

容器里跑的程序 (比如 docker-osx 里的虚拟机) 想用宿主机的代理时, 默认桥接网络下容器看不到宿主机的 localhost:7890.

两种方法:

  • docker run --net=host ... — 容器直接用宿主机网络栈, 简单粗暴, 但端口冲突风险高
  • 在容器里把代理填成 host.docker.internal:7890 — Docker 自动把这个域名解析到宿主机内网 IP, 推荐

host.docker.internal 在 Docker Desktop (Win/Mac) 默认可用; Linux 上需要 docker run --add-host=host.docker.internal:host-gateway ... 显式开启.

分割线

常用命令

跟 shell 相关的更多命令: 💧 一些常用终端命令.#docker

运行容器

很多文档的 docker run 命令带换行:

docker run -d \
-p 8088:8088 \
--name next-terminal \
--restart always ghcr.io/dushixiang/next-terminal:latest

行末的 \ 是 POSIX shell 续行符, Windows cmd / pwsh 不认. 直接拼成一行就行:

docker run -d -p 8088:8088 --name next-terminal --restart always ghcr.io/dushixiang/next-terminal:latest

pwsh 可以用 backtick ` 续行, cmd 用 ^, 但最稳的还是拼一行.

系统清理

跑久了磁盘会被一堆悬空镜像、停止的容器、未挂载的卷、构建缓存吃掉, 定期清理:

# 看占了多少
docker system df

# 安全清理: 只动当前没被任何容器使用的镜像/网络/缓存
docker system prune

# 激进清理: 加 -a 把所有未使用的镜像也清掉 (会清掉你 pull 但当前没跑的镜像)
docker system prune -a

# 跳过确认
docker system prune -a -f

# 精细化清理 (只清单个对象类型)
docker image prune # 悬空镜像 (untagged)
docker builder prune # 构建缓存
docker volume prune # 未挂载的卷 (注意: 卷里的数据会丢)

docker volume prune 是最容易误伤的, 没在跑的服务的数据卷也会被清, 跑之前先 docker volume ls 看一眼.

镜像导入导出

把镜像打包成 tarball 拷到内网或离线机器:

# 导出 (gzip 压缩节省空间)
docker save ollama/ollama:0.15.6 | gzip > ollama.tar.gz

# 导入
gunzip -c ollama.tar.gz | docker load

docker save 导出的是镜像 (image), 跨机器迁移用这个.
docker export 导出的是容器文件系统 (container), 会丢掉镜像层信息, 用途完全不同别搞混.

分割线

工具集成

VSCode Docker 扩展

在远程 Linux (Manjaro / Ubuntu) 上起 Docker 服务, VSCode 通过 SSH 连过去, 装 Docker 扩展, 容器/镜像/卷/网络全都能在侧边栏可视化点点点, 比纯命令行舒服很多.

20210206153528

搭配 Resource Monitor 扩展能在状态栏看远程机的 CPU / 内存 / 磁盘占用 (上图最下方那条).

分割线

借物表