Docker Next.js 本地部署技能
目的
使用此技能通过带有版本号的镜像标签来构建并运行 Next.js 应用程序的 Docker 镜像。
此技能不得硬编码项目名称。除非用户提供了具体名称,否则应从当前仓库推断镜像名称。
项目名称解析
在构建之前,确定以下值:
PROJECT_NAME=<解析后的项目名称>
IMAGE_NAME=<解析后的镜像名称>
IMAGE_VERSION=<解析后的版本>
IMAGE_TAG=${IMAGE_NAME}:${IMAGE_VERSION}
CONTAINER_NAME=<解析后的容器名称>
ENV_FILE=<解析后的环境变量文件>
HOST_PORT=<解析后的主机端口>
CONTAINER_PORT=<解析后的容器端口>
解析规则:
-
如果用户提供了镜像名称,则使用该名称。
-
否则,读取
package.json并使用其中的name字段。 -
如果
package.json中没有name,则使用当前文件夹名称。 -
规范化镜像名称:
- 小写
- 将空格和下划线替换为连字符
- 移除 Docker 镜像名称中的非法字符
-
如果用户提供了版本,则使用该版本。
-
否则,默认为
1.0.0。 -
如果用户提供了容器名称,则使用该名称。
-
否则,使用规范化后的镜像名称作为容器名称。
-
如果用户提供了环境变量文件,则使用该文件。
-
否则,默认为
.env.production。 -
如果用户提供了端口,则使用它们。
-
否则,默认
HOST_PORT=4000和CONTAINER_PORT=3000。
示例:
package.json 中的名称: nextjs-skill-app-workshop
PROJECT_NAME=nextjs-skill-app-workshop
IMAGE_NAME=nextjs-skill-app-workshop
IMAGE_VERSION=1.0.0
IMAGE_TAG=nextjs-skill-app-workshop:1.0.0
CONTAINER_NAME=nextjs-skill-app-workshop
ENV_FILE=.env.production
HOST_PORT=4000
CONTAINER_PORT=3000
安全规则
在执行任何构建或运行命令之前:
-
确认当前工作目录是项目根目录。
-
确认
Dockerfile存在。 -
确认环境变量文件存在。
-
确认 Docker 已安装并正在运行。
-
检查请求的镜像标签是否已存在于本地。
-
检查请求的容器名称是否已存在。
-
切勿打印环境变量文件中的密钥。
-
除非用户明确要求,否则不要使用
latest标签。 -
不要运行破坏性清理命令,例如:
docker system prunedocker image prunedocker volume prune
-
未经用户明确确认,不得停止、移除或替换已有的容器。
-
除非用户明确确认,否则不要重建已有的版本标签。
预检检查
首先运行这些检查:
pwd
ls -la
test -f package.json && echo "OK: package.json 找到" || echo "WARN: package.json 未找到"
test -f Dockerfile && echo "OK: Dockerfile 找到" || echo "ERROR: Dockerfile 未找到"
test -f "$ENV_FILE" && echo "OK: 环境变量文件找到: $ENV_FILE" || echo "ERROR: 环境变量文件未找到: $ENV_FILE"
docker --version
docker info >/dev/null && echo "OK: Docker 守护进程正在运行" || echo "ERROR: Docker 守护进程未运行"
如果缺少 Dockerfile,停止并报告问题。
如果缺少环境变量文件,停止并报告问题。除非用户要求,否则不要创建占位环境变量文件。
如果 Docker 守护进程未运行,停止并告知用户启动 Docker Desktop 或 Docker Engine。
建议的辅助命令
从 package.json 推断镜像名称:
node -p "require('./package.json').name"
如果 package.json 不存在或没有 name,则使用当前目录名称:
basename "$PWD"
手动规范化项目名称时,使用小写短横线命名法(kebab-case)。
示例:
My Next App -> my-next-app
nextjs_skill_app -> nextjs-skill-app
版本标签检查
在构建之前,检查请求的镜像标签是否已存在:
docker image inspect "$IMAGE_TAG" >/dev/null 2>&1 \
&& echo "EXISTS: $IMAGE_TAG" \
|| echo "AVAILABLE: $IMAGE_TAG"
同时列出此镜像已有的本地版本:
docker images "$IMAGE_NAME" --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.CreatedSince}}\t{{.Size}}"
如果请求的镜像标签已存在:
- 不要运行
docker build。 - 报告该版本已存在于本地。
- 建议下一个补丁版本,例如
1.0.1。 - 询问用户是使用新版本还是明确重建同一标签。
仅当用户明确确认时,才重建现有标签。
容器名称检查
在运行容器之前,检查容器名称是否已存在:
docker ps -a --filter "name=^/${CONTAINER_NAME}$" \
--format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
如果已存在同名的容器:
- 不要使用相同名称运行另一个容器。
- 报告已有容器的状态。
- 询问用户是停止/移除它还是使用不同的容器名称。
- 不要自动移除它。
构建命令
如果镜像标签不存在,运行:
docker build -t "$IMAGE_TAG" .
构建后,验证镜像是否存在:
docker image inspect "$IMAGE_TAG" >/dev/null \
&& echo "OK: 镜像构建成功: $IMAGE_TAG" \
|| echo "ERROR: 构建后未找到镜像: $IMAGE_TAG"
运行命令
如果镜像存在且容器名称可用,运行:
docker run --restart=always -d \
--name "$CONTAINER_NAME" \
--env-file "$ENV_FILE" \
-p "${HOST_PORT}:${CONTAINER_PORT}" \
"$IMAGE_TAG"
运行后验证
运行容器后,使用以下命令验证:
docker ps --filter "name=^/${CONTAINER_NAME}$" \
--format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
docker logs --tail=80 "$CONTAINER_NAME"
curl -I "http://localhost:${HOST_PORT}"
预期结果:
- 容器状态应为
Up。 - 端口映射应包含
${HOST_PORT}->${CONTAINER_PORT}。 - 日志不应显示致命错误。
curl -I应返回 HTTP 响应,例如200、301、302、307或308。
如果 curl 失败,检查日志并报告可能的原因。
常见故障处理
镜像标签已存在
报告:
镜像标签已存在于本地:
<IMAGE_TAG>
建议操作:
- 使用新的补丁版本,例如 1.0.1
- 或明确确认重建同一标签
容器名称已存在
报告:
容器已存在:
<CONTAINER_NAME>
请确认是否停止/移除它,或提供不同的容器名称。
端口已被占用
检查:
lsof -i :"$HOST_PORT"
报告占用该端口的进程,并询问用户是否要更改 HOST_PORT。
环境变量文件缺失
报告:
未找到环境变量文件:
<ENV_FILE>
在此文件存在之前,我无法使用 --env-file 运行容器。
不要打印或推断密钥。
Docker 守护进程未运行
报告:
Docker 已安装,但守护进程未运行。
请启动 Docker Desktop 或 Docker Engine,然后再次运行预检检查。
最终响应格式
完成后,报告:
结果:
- 项目:<PROJECT_NAME>
- 镜像:<IMAGE_TAG>
- 容器:<CONTAINER_NAME>
- 环境变量文件:<ENV_FILE>
- 端口:http://localhost:<HOST_PORT>
- 重启策略:always
- 验证:通过/失败
使用的命令:
<列出重要命令>
备注:
<任何警告、已有的镜像/容器冲突或后续操作>
如果工作流程因版本标签已存在、环境变量文件缺失、容器已存在、Docker 错误或端口冲突而停止,请明确说明阻塞问题以及最安全的下一步命令。