第3章:Docker 容器 - 动态的运行实例
我们已经成功地使用 Dockerfile
为我们的 Node.js 应用构建了一个名为 my-app:1.0
的镜像。现在,这张"图纸"已经备好,是时候根据它来建造一所能对外提供服务的"房子"------也就是运行一个容器了。
本章,我们将深入学习 docker run
命令的各种强大参数,并掌握管理容器整个生命周期的核心技能。
3.1 [实战] 将我们的 Web 应用以容器形式运行起来
还记得我们在 Dockerfile
里用 EXPOSE 8080
指令声明了容器会监听 8080
端口吗?这就像是在房间里装了一部电话,分机号是8080,但外界并不知道总机号码,还是打不进来。
我们需要做一个端口映射 (Port Mapping) ,把主机(你的电脑)的一个端口,映射到容器的这个 8080
端口上。这样,所有访问你电脑特定端口的流量,都会被 Docker 自动转发到容器内部。
在命令行中执行以下命令:
bash
docker run -p 4000:8080 my-app:1.0
docker run
: 运行容器的命令。-p 4000:8080
: 这就是端口映射的关键。-p
是--publish
的缩写。它的格式是<host_port>:<container_port>
。这条命令的意思是,将主机的4000
端口,映射到容器的8080
端口。my-app:1.0
: 指定我们要运行哪个镜像。
命令执行后,你会看到和 node app.js
一样的输出 Running on http://0.0.0.0:8080
。但这次,它是在一个隔离的容器环境中运行的!
现在,打开你的浏览器,访问 http://localhost:4000
。
你应该能看到页面上显示出 "Hello, Docker World! This is our first image."。
成功了! 你已经通过主机的端口,访问到了容器内部运行的 Web 服务。
但是,你会发现你的命令行窗口被这个容器的日志占用了,你无法再输入其他命令。要停掉它,你只能按 Ctrl + C
。有没有办法让它在后台安静地运行呢?
3.2 docker run
命令的高级用法
docker run
是最核心的命令,它有许多强大的选项,可以让我们更灵活地控制容器。
后台运行 (Detached Mode)
要让容器在后台运行,我们只需要添加 -d
或 --detach
参数。
我们先按 Ctrl + C
停掉刚才的容器,然后执行新命令:
bash
docker run -d -p 4000:8080 my-app:1.0
这次,命令执行后,它不会打印应用日志,而是直接输出一长串十六进制的字符串。这个字符串是这个容器的唯一ID。你的命令行也立刻恢复了正常。
现在,再次访问 http://localhost:4000
,你会发现应用依然在正常运行。
给容器起个名字
每次都用那一长串的ID来操作容器,实在太不方便了。我们可以用 --name
参数在启动时给容器起一个好记的名字。
bash
# 先停掉并删除之前的容器,因为名字不能重复
# (我们会在 3.3 节详细讲解 stop 和 rm 命令)
docker stop <container_id>
docker rm <container_id>
# 启动一个有名字的容器
docker run -d -p 4000:8080 --name web-server my-app:1.0
现在,我们就可以用 web-server
这个名字来代替那串长长的ID了。
3.3 容器的生命周期管理
容器启动后,我们还需要对它进行管理,比如查看状态、停止、重启或删除。
-
查看正在运行的容器:
bashdocker ps # 或者 docker container ls
这个命令会列出所有正在运行的容器,以及它们的基本信息,如容器ID、所用镜像、启动命令、创建时间、状态、端口映射和容器名。
-
查看所有容器(包括已停止的):
bashdocker ps -a
你会看到一些
Exited
状态的容器,这些是你之前用Ctrl + C
停掉或者运行出错的容器。 -
停止一个容器:
bash# 使用名字或ID的前几位都可以 docker stop web-server
stop
命令会向容器发送一个信号,让它优雅地停止。 -
启动一个已停止的容器:
bashdocker start web-server
-
删除一个容器 : 注意: 只有停止状态的容器才能被删除。
bashdocker rm web-server
如果你想强制删除一个正在运行的容器,可以加上
-f
参数:docker rm -f web-server
。 -
查看容器日志: 对于后台运行的容器,我们如何看到它的输出呢?
bashdocker logs web-server
如果你想实时跟踪日志(像
tail -f
一样),可以加上-f
参数:docker logs -f web-server
。
3.4 如何"进入"一个正在运行的容器?(exec
)
有时候,我们需要进入容器内部,去看看文件系统,或者执行一些临时的调试命令。docker exec
命令就是为此而生的。
docker exec
允许你在一个正在运行的容器内,执行一个新命令。
最常见的用法是启动一个交互式的 shell(比如 bash
或 sh
):
bash
# 确保你的 web-server 容器正在运行
docker start web-server
# -it 参数是关键:
# -i (interactive): 保持标准输入打开,允许你进行交互
# -t (tty): 分配一个伪终端
docker exec -it web-server /bin/sh
执行后,你会发现你的命令行提示符变了,类似 /usr/src/app #
。这表示你已经成功进入了 web-server
容器的内部,并且当前位于我们在 Dockerfile
中设置的 WORKDIR
。
现在,你可以像在普通 Linux 环境中一样操作了:
- 输入
ls -l
,你会看到我们的app.js
,package.json
等文件。 - 输入
cat app.js
,可以查看应用代码。 - 输入
ps aux
,可以看到正在运行的node app.js
进程。
要退出容器,只需输入 exit
或按 Ctrl + D
。
3.5 本章小结 & 避坑指南
你现在已经完全掌握了如何驾驭一个 Docker 容器。
-
本章回顾:
- 我们学会了使用
-p
参数进行端口映射,让外部可以访问容器内的服务。 - 我们学会了使用
-d
和--name
参数,让容器后台运行 并拥有一个自定义的名字。 - 我们掌握了容器的生命周期管理 命令:
ps
,start
,stop
,rm
,logs
。 - 我们学会了使用
docker exec
这个强大的工具,进入容器内部进行调试。
- 我们学会了使用
-
避坑指南:端口冲突怎么办?
- 问题 :执行
docker run -p 4000:8080 ...
时,报错Error starting userland proxy: listen tcp4 0.0.0.0:4000: bind: address already in use
。 - 原因 :这个错误明确地告诉你,你主机上的
4000
端口已经被其他程序占用了。Docker 无法监听一个已经被占用的端口。 - 排查 :
- 你是不是已经启动了一个一模一样的容器,忘了关?用
docker ps
检查一下。 - 你电脑上是不是有其他开发工具(比如另一个Web服务)也正在使用
4000
端口?
- 你是不是已经启动了一个一模一样的容器,忘了关?用
- 解决 :
-
停掉占用端口的那个容器或程序。
-
更简单的方法是 :换一个主机的端口号!比如,改成
5000
:bashdocker run -d -p 5000:8080 --name web-server-2 my-app:1.0
现在,你就可以通过
http://localhost:5000
来访问了。 核心要点 :容器内的端口(8080
)是由Dockerfile
决定的,通常不轻易改变。而主机的端口,你可以根据实际情况随意选择一个未被占用的即可。
-
- 问题 :执行
我们的应用已经能跑起来了,但还有一个致命问题:如果容器被删除了,应用产生的所有数据(比如用户上传的文件、数据库记录)都会丢失。下一章,我们将学习如何解决这个问题,为容器装上"记忆硬盘"------数据卷。