2、Docker基础回顾:Docker架构、核心概念(镜像、容器、仓库)、常用命令

好,咱们正式开始。这一章我打算带大家快速过一遍 Docker 的核心基础。你可能会想:「我都来学迁移和改造了,还要回顾基础?」

嗯,我理解这个想法。但根据我这些年带团队的经验,很多容器化翻车事故,恰恰就出在基础概念没吃透。比如镜像层搞混了,容器数据卷没挂对,仓库标签打错了——这些看似小问题,上了生产就是大麻烦。

所以,咱们花点时间,把地基夯实。我保证,不会啰嗦,全是干货。

2.1 Docker 架构:Client-Server 与守护进程

Docker 用的是典型的 C/S 架构。说白了,就是两个角色在干活:

  • Docker Client(客户端):你敲命令的那个终端。比如 docker rundocker build
  • Docker Daemon(守护进程):真正干活的家伙。它负责管理镜像、容器、网络、存储卷。

它们之间通过 REST API 通信。你想想看,你在笔记本上敲 docker ps,命令先发给本地的 daemon,daemon 再返回结果。但如果你把 DOCKER_HOST 环境变量设成远程地址,客户端就能操作远程的 daemon 了。我在项目中就经常用这个技巧,远程调试测试环境的容器,省得来回跳板机。

核心要点:

  • Client 只管发指令,不干活。
  • Daemon 是大脑,负责所有脏活累活。
  • 通信走 REST API,端口默认 2375(未加密)或 2376(TLS)。

注意:千万不要把 2375 端口暴露到公网!我曾经见过一个团队,为了方便调试,直接把 Docker 的 TCP 端口开到了公网 IP 上。结果呢?被人植入了挖矿容器,整个集群的资源被吃光。教训深刻啊。

2.2 三大核心概念:镜像、容器、仓库

这三个概念,是 Docker 的基石。我习惯用一个类比来理解:

  • 镜像(Image) = 类(Class)
  • 容器(Container) = 实例(Instance)
  • 仓库(Registry) = 代码仓库(Git Repo)

是不是一下子就清晰了?咱们一个一个拆开讲。

2.2.1 镜像(Image)

镜像是只读的模板。它包含了运行应用所需的一切:代码、运行时、系统工具、库、配置。你可以把它理解成一个「压缩包」,但这个压缩包是分层构建的。

为什么会这样?因为分层可以复用。比如你基于 Ubuntu 20.04 做镜像,又基于它做 Nginx 镜像,那 Ubuntu 那一层就可以被多个镜像共享,不用重复下载。我在项目中遇到过,一个团队把同一个基础镜像打了 10 个不同的应用镜像,结果磁盘占用飙升。后来我让他们用 docker image ls 一看,全是重复的基础层。优化后,磁盘占用直接降了 60%。

小技巧:docker image history <镜像名> 可以查看镜像的构建历史,每一层做了什么一目了然。排查镜像体积问题时特别好用。

2.2.2 容器(Container)

容器是镜像的运行实例。你可以启动、停止、删除、暂停它。每个容器都是隔离的,有自己的文件系统、网络、进程空间。

嗯,这里要注意:容器是「有状态」的。你可以在容器里写文件,但容器一旦被删除,这些数据就没了。除非你用了数据卷(Volume)或绑定挂载(Bind Mount)。

我记得有一次,一个同事在容器里跑数据库,数据全写在容器内部。结果容器因为 OOM 被自动重启了,重启后数据全丢了。他当时脸都绿了。从那以后,我要求所有有状态数据必须挂载到宿主机或持久卷上。

一句话总结:镜像负责「是什么」,容器负责「怎么跑」。

2.2.3 仓库(Registry)

仓库就是存放镜像的地方。有公开的 Docker Hub,也有私有的 Harbor、Nexus、AWS ECR 等。

镜像的命名规则是:[仓库地址/]用户名/镜像名:标签。比如 nginx:latest 其实是 docker.io/library/nginx:latest 的简写。

我个人习惯,在私有仓库里一定要打上明确的版本标签,比如 myapp:v1.2.3,而不是 latest。因为 latest 是个「移动靶」,你永远不知道它指向哪个版本。生产环境用 latest,迟早要出问题。

避坑指南:我曾经接手过一个项目,所有镜像都只打了 latest 标签。结果某次部署时,有人不小心 push 了一个有 bug 的版本上去,所有节点自动拉取了新镜像,线上直接崩了。从那以后,我强制要求:生产环境必须使用固定版本标签,禁止使用 latest

2.3 常用命令:从入门到日常

命令这东西,不用全记住,记住最常用的就行。我平时用的最多的,也就下面这些。我按场景分类,方便你记忆。

2.3.1 镜像操作

命令 说明 示例
docker pull 拉取镜像 docker pull nginx:1.25
docker images 列出本地镜像 docker images
docker rmi 删除镜像 docker rmi nginx:1.25
docker build 构建镜像 docker build -t myapp:v1 .
docker tag 打标签 docker tag myapp:v1 myreg.com/myapp:v1
docker push 推送镜像到仓库 docker push myreg.com/myapp:v1

个人习惯:我每次构建完镜像,都会先用 docker image prune 清理一下 <none> 标签的悬空镜像。不然时间长了,磁盘会被这些「僵尸镜像」占满。

2.3.2 容器操作

命令 说明 示例
docker run 创建并启动容器 docker run -d --name web -p 80:80 nginx
docker ps 列出运行中的容器 docker ps -a(列出所有)
docker stop 停止容器 docker stop web
docker start 启动已停止的容器 docker start web
docker rm 删除容器 docker rm -f web(强制删除)
docker logs 查看容器日志 docker logs -f web(实时跟踪)
docker exec 进入容器内部 docker exec -it web bash

这里我特别想强调一下 docker run 的常用参数:

  • -d:后台运行(detached)
  • --name:给容器起个名字,方便管理
  • -p:端口映射,宿主机端口:容器端口
  • -v:挂载数据卷
  • -e:设置环境变量
  • --restart=always:容器退出后自动重启

实战示例:启动一个 MySQL 容器,挂载数据卷,设置密码:

docker run -d \
  --name mysql8 \
  -p 3306:3306 \
  -v /data/mysql:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=my-secret-pw \
  --restart=always \
  mysql:8.0

2.3.3 仓库与网络操作

命令 说明 示例
docker login 登录仓库 docker login myreg.com
docker search 搜索镜像 docker search nginx
docker network ls 列出网络 docker network ls
docker network create 创建网络 docker network create mynet
docker network connect 将容器连接到网络 docker network connect mynet web

避坑指南:我曾经在项目中,两个容器之间通信一直不通。排查了半天,发现它们不在同一个 Docker 网络里。默认的 bridge 网络只能通过 IP 通信,而且容器重启后 IP 会变。后来我创建了一个自定义网络,用容器名通信,问题就解决了。记住:自定义网络支持 DNS 解析,用容器名代替 IP 才是正道

2.4 本章小结

好了,这一章的内容就这些。咱们回顾一下:

  • Docker 是 C/S 架构,Client 发指令,Daemon 干活。
  • 镜像是只读模板,容器是运行实例,仓库是存放镜像的地方。
  • 常用命令分三类:镜像操作、容器操作、仓库与网络操作。

这些基础,是后续所有容器化迁移和改造的根基。下一章,我会带你深入 Dockerfile 的编写技巧,以及如何把遗留应用一步步「塞」进容器里。到时候,咱们会用到很多今天讲的内容。

嗯,先消化这些吧。有问题随时翻回来看看。