华为云 ECS 上用 Docker 部署静态网站:重启策略、端口映射与回滚实操
本文记录一次在华为云 ECS 上用 Docker 部署静态网站的完整过程,重点不是“能跑起来”就结束,而是把生产环境最容易踩的坑一次讲清:容器重启策略怎么选、端口映射怎么写、日志怎么看、发布失败怎么回滚。
一、环境与目标
服务器:华为云 ECS,系统自带 Docker 环境或已自行安装 Docker。
服务:一个纯静态网站,HTML、CSS、图片,不依赖数据库和后端接口。
部署方式:不直接在宿主机装 Nginx,而是用官方 nginx:alpine 镜像跑容器,宿主机只负责 Docker 和端口放行,网站内容随镜像版本走。
先确认 Docker 可用:
docker version
docker ps
如果 docker ps 提示权限问题,先确认当前用户是否在 docker 组,或临时用 sudo 执行,不要直接把 Docker socket 暴露给外部。
二、准备静态文件和 Dockerfile
在 ECS 上建一个工作目录,结构越简单越不容易错:
mkdir -p ~/static-site/site
cd ~/static-site
site/index.html 里至少放一个可区分版本的标识,例如页面底部写“版本:v1”,后续验证回滚就靠它,不要只看“页面能打开”,因为浏览器缓存可能让你误判。
Dockerfile 内容如下:
FROM nginx:alpine
COPY site/ /usr/share/nginx/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
注意两点:第一,COPY 的源路径是构建上下文里的 site 目录,不是宿主机任意路径;第二,EXPOSE 80 只是声明容器内端口,并不等于对外发布端口,真正对外靠后面 run 命令的 -p 参数。
三、构建镜像并打版本标签
docker build -t static-site:v1 .
用版本号打标签是回滚的前提。如果只用 latest,出了问题你根本不知道当前跑的是哪一次构建,也没法一键回到上一版。构建完成后确认:
docker images | grep static-site
四、启动容器:重启策略与端口映射
启动命令:
docker run -d --name static-site --restart unless-stopped -p 80:80 --log-opt max-size=10m --log-opt max-file=3 static-site:v1
逐项解释:
-d:后台运行,终端退出后容器不退出。
--name static-site:固定名字,后续查看日志、停止、回滚都靠它。
-p 80:80:冒号左边是宿主机端口,右边是容器端口。外网访问宿主机 80,就转发到容器 80。如果宿主机 80 已被占用,可以改成 -p 8080:80,这时外网就要访问 8080 端口,同时安全组也要放行 8080,不要只改一处。
--restart unless-stopped:这是静态网站最常用的策略。服务器重启、Docker 重启、容器异常退出后都会自动拉起;只有你手动 docker stop 后,它才不会自动再起,适合需要人工停机的场景。
重启策略对照:
no:不自动重启,调试时用。
on-failure:仅非零退出时重启,可加 on-failure:3 限制次数。
always:任何情况下都重启,包括手动 stop 后 Docker 重启也会拉起,适合不允许停的核心服务。
unless-stopped:除手动停止外都重启,兼顾自动恢复和人工控制。
验证启动结果:
docker ps
docker inspect static-site --format '{{.State.Status}} {{.NetworkSettings.Ports}}'
五、验证:本机、外网、日志三段都要过
1. 本机验证:
curl -I http://127.0.0.1/
curl http://127.0.0.1/ | grep 版本
返回 200 且能看到 v1 标识,说明容器内 Nginx 和文件都没问题。
2. 宿主机端口验证:
ss -tlnp | grep :80
能看到 Docker 监听 80,说明端口映射生效。
3. 外网验证:在自己电脑浏览器访问 ECS 的弹性公网 IP,地址就是 http://弹性公网IP/。如果本机通、外网超时,先查安全组入方向是否放行 TCP 80、是否绑定到这台 ECS,再确认访问的是弹性公网 IP 而不是内网 IP。
六、日志查看:不要只会 docker logs
实时看日志:
docker logs -f --tail 100 static-site
只看最近一段:
docker logs --tail 200 --since 10m static-site
容器里 Nginx 的访问日志默认走标准输出,所以 docker logs 就能看到请求记录。如果容器反复重启,先看退出状态和日志,而不是反复 run 新容器:
docker ps -a
docker logs static-site
启动时加的 --log-opt max-size=10m --log-opt max-file=3 也很重要:默认 json-file 日志不轮转,长期运行的静态站可能把磁盘写满,轮转后最多保留 3 个 10MB 文件。
七、发布新版本与回滚:先留旧镜像,再换新容器
发布 v2 的正确顺序是先构建、不删旧镜像:
docker build -t static-site:v2 .
docker stop static-site
docker rm static-site
docker run -d --name static-site --restart unless-stopped -p 80:80 --log-opt max-size=10m --log-opt max-file=3 static-site:v2
验证 v2:
curl http://127.0.0.1/ | grep 版本
docker ps
如果页面标识变成 v2 且状态为 Up,发布成功。
回滚时不需要重新构建,直接用旧标签再起一个同名容器:
docker stop static-site
docker rm static-site
docker run -d --name static-site --restart unless-stopped -p 80:80 --log-opt max-size=10m --log-opt max-file=3 static-site:v1
回滚后必须再做一次验证:本机 curl 看到 v1、外网刷新能看到 v1(必要时用无痕窗口或加查询参数绕过缓存,例如 http://弹性公网IP/?v=1)。只有验证通过,回滚才算完成。
如果想做到发布时几乎不停机,可以先用另一个端口起 v2 做灰度验证:
docker run -d --name static-site-v2 --restart unless-stopped -p 8080:80 static-site:v2
先访问 8080 端口确认 v2 没问题,再停掉旧容器、把 v2 换到 80 端口。这个方法多一步,但比直接覆盖生产容器稳得多。
八、常见故障速查
端口被占用:ss -tlnp 找到占用 80 的进程,换宿主机端口或停掉冲突服务,不要同时起两个都绑定 80 的容器。
容器状态为 Exited:先 docker logs 看报错,常见是 Dockerfile 里 COPY 路径写错或端口配置冲突。
页面 404:检查 site 目录是否真的复制到了 /usr/share/nginx/html,index.html 文件名大小写是否正确。
本机通、外网不通:查安全组绑定、弹性公网 IP、本地网络,不要反复重建容器。
磁盘告警:查 docker logs 轮转和 docker system df,及时清理无用的旧镜像,但不要在生产高峰直接 docker system prune -a。
九、收尾检查清单
1. docker ps 显示 static-site 为 Up。
2. 本机 curl 返回 200 且版本标识正确。
3. 外网用弹性公网 IP 能打开。
4. docker logs 能看到正常访问记录。
5. 旧版本镜像 static-site:v1 仍保留,可随时回滚。
总结:静态网站用 Docker 部署并不复杂,复杂的是上线后的运维。固定镜像版本号、选 unless-stopped 重启策略、写清宿主机与容器端口映射、做好日志轮转、发布前保留旧镜像,这五件事做到了,后续更新和回滚都会从容很多。
- 点赞
- 收藏
- 关注作者
评论(0)