2. Docker 基础操作:镜像拉取、运行容器、进入容器、文件拷贝、端口映射
说实话,很多初学者觉得 Docker 基础操作就是背几个命令。但我告诉你,真正干活的时候,命令背后那些细节才是坑。我记得自己刚用 Docker 那会儿,一个端口映射写错,调试了一下午。所以今天咱们把这五个操作彻底掰开揉碎。
2.1 镜像拉取:从哪儿拿,怎么拿
镜像就像软件的安装包。Docker Hub 是全球最大的镜像仓库,但我建议你在公司场景下先配置一个国内镜像加速器,否则 pull 一个几 GB 的镜像能等到怀疑人生。
最常用的拉取命令长这样:
docker pull nginx:latest
这条命令会从 Docker Hub 拉取最新版的 nginx 镜像。你也可以指定版本号,比如 nginx:1.25。我个人习惯在生产环境里总是指定精确版本,因为 latest 可能会变——你想想看,今天跑得好好的,明天一拉变成新版本,兼容性问题就来了。
拉取过程中会显示分层下载的进度。每一层都是一个只读文件系统,Docker 会缓存它们。如果你拉取同一个镜像的不同版本,共享的层不会被重复下载。这个机制在实际项目中非常有用——我曾在 CI 流水线里利用它把构建时间从 8 分钟压到 2 分钟。
docker images 或 docker image ls。想删除镜像用 docker rmi <镜像名>,但注意要先删掉基于它的所有容器。
2.2 运行容器:镜像变实例
镜像拉下来了,怎么让它跑起来?用 docker run。这是整个 Docker 里最核心、参数最多的一个命令。咱们先看最简启动:
docker run nginx:latest
执行后终端会被 nginx 的前台日志刷屏。按 Ctrl+C 可以停止。但实际使用中我们通常让它后台运行:
docker run -d nginx:latest
-d 代表 detach,意思是在后台运行。命令会返回一串容器 ID,像 abc123def456。你可以用 docker ps 查看正在运行的容器列表。
有一个参数我几乎每次都用,就是 --name:
docker run -d --name my-nginx nginx:latest
给容器起个名字,后面操作起来就不用记那一长串 ID 了。我在管理二十几个微服务时,名字就是救命稻草。
| 参数 | 含义 | 常用组合 |
|---|---|---|
-d |
后台运行 | docker run -d --name web nginx |
-it |
交互式终端(后面会用到) | docker run -it ubuntu bash |
--rm |
容器退出后自动删除 | 测试环境常用 |
-p |
端口映射(详见 2.5) | -p 8080:80 |
-v |
挂载卷/目录 | -v /host/path:/container/path |
2.3 进入容器:和容器内部打交道
容器跑起来了,你想进去看看文件、跑个命令、查个日志,怎么办?用 docker exec。
先启动一个持续运行的容器,比如刚才的 nginx:
docker run -d --name my-nginx nginx:latest
然后进入它的 bash 环境:
docker exec -it my-nginx bash
进去之后就像登录了一台 Linux 机器。你可以执行 ls、cat、apt update 等操作。但要注意,很多镜像为了保持精简,并没有安装完整工具链。比如 apt 可能不存在,你得用 apt-get。我遇到过最坑的情况是 vi 都没有,只能靠 echo 和重定向来修改配置文件——嗯,后来我提前在 Dockerfile 里装好了 vim-tiny。
docker exec -it my-nginx bash 时,如果容器里没有 bash,可以试试 sh 或 ash。如果连 shell 都没有,你只能通过 docker cp 来操作文件了(下面会讲)。
除了交互式进入,你还可以直接执行单次命令:
docker exec my-nginx cat /etc/nginx/nginx.conf
这比进入容器再 cat 要快得多。我在排查问题时经常这样用——一条命令出结果,不用来回切换窗口。
2.4 文件拷贝:宿主机 ↔ 容器
有时你需要把宿主机上的文件拷进容器,或者把容器里的日志、配置拷出来。别去容器里装 scp,有现成的 docker cp。
把宿主机文件拷入容器:
docker cp ./my-config.conf my-nginx:/etc/nginx/conf.d/
把容器文件拷到宿主机:
docker cp my-nginx:/var/log/nginx/access.log ./
这个命令支持目录递归拷贝。我曾经在项目上线时,需要把一批 SSL 证书放进六个容器——用 docker cp 写个循环脚本,几秒钟就搞定了,比手动进容器粘贴效率高多了。
有一点要小心:docker cp 拷贝时不会自动创建不存在的目录。如果目标路径缺少中间目录,会报错。你需要在容器里提前用 docker exec 创建好。
2.5 端口映射:让外面能访问容器
容器默认有独立的网络命名空间。你在容器里启动了一个 nginx 监听 80 端口,但宿主机的 80 端口上什么都没跑——除非你做端口映射。
在 docker run 时加上 -p 参数:
docker run -d --name my-nginx -p 8080:80 nginx:latest
这条命令把宿主机的 8080 端口映射到容器的 80 端口。访问 http://localhost:8080 就能看到 nginx 欢迎页了。
映射规则是 宿主机端口:容器端口。可以多个端口映射:
docker run -d --name my-app -p 8080:8080 -p 8443:8443 my-app-image
docker run -p 8888:80 改为非标准端口,同时在前端 nginx 反向代理中加一条转发规则即可。千万不要硬改宿主机已有服务端口。
还有一种是随机端口映射:
docker run -d -P nginx:latest
大写 -P 会让 Docker 自动把容器内暴露的端口(Dockerfile 中的 EXPOSE)映射到宿主机的随机高位端口。用 docker ps 查看具体映射关系。这在测试环境偶尔用用,但生产里还是手动指定更可控。
本章知识图谱
下面这张图把五个操作串在一起,方便你理清关系:
docker pull nginx → docker run -d --name test-nginx -p 8888:80 nginx → docker exec -it test-nginx bash → 在容器里创建一个文件 → exit 后用 docker cp 拷出来。整个过程不要看笔记,自己敲两遍就熟了。
最后提醒一句:docker run 和 docker start 不一样。前者是“创建并启动一个新容器”,后者是“启动一个已存在的停止状态的容器”。我刚开始就搞混过——写了个启动脚本用的 docker start,结果容器每次重建后配置全丢了。