家里装了 NAS,又顺手跑了个 Home Assistant,结果发现网页打不开——浏览器一直转圈。查了半天,原来是容器里服务监听的是 8123 端口,但宿主机没把这端口放出来。这就是典型的容器化应用管理不到位:服务跑起来了,却卡在了“门没开”这一步。
容器不是黑盒子,得知道它往外“开哪扇门”
容器默认是网络隔离的,像一个个带锁的小房间。你启动一个 Nginx 容器:
docker run -d --name my-nginx -p 8080:80 nginx这里 -p 8080:80 就是开门动作:把宿主机的 8080 端口,映射到容器内部的 80 端口。外面人访问 http://localhost:8080,请求就自动穿墙进去了。很多人习惯写成 -p 80:80,结果发现宿主机 80 被占了(比如 Apache 正在跑),直接报错。这时候别硬刚,换一个宿主机端口就行,比如 -p 8081:80,照样能用,只是地址变成 :8081。
多容器协作,端口别撞车
搭一套博客系统,可能要起 MySQL、Redis、Ghost 三个容器。MySQL 默认用 3306,Redis 用 6379,Ghost 用 2368——这些是容器内部端口,不用暴露全。实际只需暴露 Ghost 的 2368(映射到宿主机 80 或 8080),MySQL 和 Redis 只需内部互通,连宿主机端口都不用开:
docker network create blog-net
docker run -d --name mysql --network blog-net -e MYSQL_ROOT_PASSWORD=123 mysql:8.0
docker run -d --name redis --network blog-net redis:alpine
docker run -d --name ghost --network blog-net -p 8080:2368 -e url=http://localhost:8080 ghost:latest这样既安全,又清爽。端口冲突?根本不会发生。
动态端口和配置文件里写的不一致?先看容器里真正在听谁
有时候 Dockerfile 写了 EXPOSE 3000,但运行时忘了 -p,或者映射错了端口,服务就“隐身”。遇到打不开的情况,别急着重装,先确认两件事:
1. 容器里服务真在监听那个端口吗?进容器看看:
docker exec -it my-app sh
# 进去后执行:
netstat -tuln | grep :30002. 宿主机是否真把端口转发过去了?
docker port my-app这条命令会清楚列出所有映射关系,比如输出 3000/tcp -> 0.0.0.0:8000,说明访问 :8000 才对路。端口映射不是配一次就完事。改配置、升级镜像、换环境,都得重新核对这一环。把它当成容器管理的“开关钥匙”,每次启停前顺手 check 一下,省得后面满世界找“为什么打不开”。