Dockerfile
1. 介绍
简单来说,Dockerfile 就是一份自动化构建镜像的"说明书"或"脚本"。它详细定义了一个容器的环境,从基础操作系统,到应用程序代码的添加,再到环境变量的设置和启动命令的执行。通过这些指令,Docker 可以自动地将应用程序及其依赖打包成一个轻量级、可移植的容器镜像。
2. 常用指令
FROM
: 指定基础镜像。每个 Dockerfile 都必须以FROM
指令开始,它定义了后续指令的执行环境。例如FROM node:20-alpine3.20
或FROM python:3.9-slim
。WORKDIR
: 设置工作目录。后续的RUN
,CMD
,COPY
,ADD
等指令都会在这个目录下执行。COPY
或ADD
: 将本地文件或目录复制到镜像的文件系统中。ADD
支持解压和 URL 等高级功能。RUN
: 在镜像构建过程中执行命令。通常用于安装软件包、更新系统等。例如RUN pnpm i
。EXPOSE
: 声明容器在运行时监听的网络端口。这主要起到文档说明的作用,并不会实际发布端口。CMD
或ENTRYPOINT
: 指定容器启动时默认执行的命令。CMD
的命令可以被docker run
时传入的参数覆盖,而ENTRYPOINT
则会将docker run
的参数作为其自身的参数。一个 Dockerfile 通常至少包含两者之一。
3. 编写Dockerfile
jsx
# 第一阶段:基础镜像
FROM node:20-alpine3.20 AS base
# 第二阶段:依赖安装 (与基础镜像分离,优化构建缓存)
FROM base AS deps
# 安装兼容库 (某些 Node 模块需要 glibc 支持)
RUN apk add --no-cache libc6-compat
# 设置工作目录
WORKDIR /app
# 复制包管理相关文件
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
# 根据锁文件类型安装依赖 (支持 yarn/npm/pnpm)
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ # 如果使用 yarn
elif [ -f package-lock.json ]; then npm ci; \ # 如果使用 npm
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \ # 如果使用 pnpm
else echo "Lockfile not found." && exit 1; \ # 无锁文件则报错
fi
# 第三阶段:构建阶段
FROM base AS builder
# 设置工作目录
WORKDIR /app
# 从 deps 阶段复制已安装的依赖
COPY --from=deps /app/node_modules ./node_modules
# 复制所有源代码
COPY . .
# 根据包管理器执行构建命令
RUN \
if [ -f yarn.lock ]; then yarn run build; \ # yarn 构建
elif [ -f package-lock.json ]; then npm run build; \ # npm 构建
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \ # pnpm 构建
else echo "Lockfile not found." && exit 1; \ # 无锁文件报错
fi
# 第四阶段:生产运行镜像 (最终阶段)
FROM base AS runner
# 设置工作目录
WORKDIR /app
# 设置环境变量为生产模式
ENV NODE_ENV=production
# 创建系统用户组 (增强安全性)
RUN addgroup --system --gid 1001 nodejs
# 创建系统用户 (避免使用 root 运行)
RUN adduser --system --uid 1001 nextjs
# 复制公共静态资源
COPY --from=builder /app/public ./public
# 复制 Next.js 优化后的独立运行文件 (自动跟踪输出减少镜像大小)
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
# 复制静态资源 (保持用户权限)
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# 切换到非特权用户运行
USER nextjs
# 声明容器监听端口
EXPOSE 3001
# 设置应用端口环境变量
ENV PORT=3001
# 设置主机绑定 (允许外部访问)
ENV HOSTNAME="0.0.0.0"
# 容器启动命令 (运行 Next.js 服务)
CMD ["node", "server.js"]
tsx
// next.config.ts
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
output: "standalone",
};
export default nextConfig;
ps:nextjs官方提供的仓库文件github.com/vercel/next...
现在在当前项目目录下运行docker build -t nextjs-docker .
就可以构建一个名为nextjs-docker
的镜像,使用docker run -p 3000:3000 nextjs-docker
命令运行容器,访问http://localhost:3000/即可看到项目已经运行起来了。
Docker Compose
1. 介绍
简单来说,如果说 Dockerfile 是用来构建单个 容器镜像的"说明书",那么 Docker Compose 就是用来编排和管理一组相互关联的 容器(一个完整项目)的"总指挥"。它允许你使用一个 YAML 文件(通常命名为 docker-compose.yml
)来配置应用所需的所有服务(services)、网络(networks)和卷(volumes)。。然后,只需一条简单的命令,就可以根据这个配置文件同时创建并启动所有服务。
2. 编写docker-compose.yml
tsx
services:
portfolio:
# docker build -t nextjs-docker . 命令运行时定义的名称
image: nextjs-docker
# 容器名称
container_name: portfolio-container
# 端口映射
ports:
- "3001:3001"
# 重启方式
restart: always
# 挂载卷 就是把容器内的文件夹和服务器或你电脑上的文件夹进行映射
# 这样即便是容器被删除了 文件也能持久化存储
# volumes:
# - ./data:/app/data
# 启动命令 如果用到了docker-compose 那么Dockerfile里面的启动命令可以省略
command: ["node", "server.js"]
运行docker-compose up
命令启动容器,-d
参数表示在后台运行。
推送镜像至阿里云
首先需要开通阿里云的容器镜像服务,个人版的足够用了。
可以根据个人喜好,选择是手动构建推送镜像,还是自动构建镜像。自动构建在绑定仓库信息是选择上就行了。
- 自动构建镜像


-
手动构建镜像,上传至阿里云容器镜像服务。
使用
docker build -t nextjs-docker .
命令构建镜像后-
登录阿里云镜像服务
docker login --username=[username] crpi.cn-beijing..cr.aliyuncs.com
具体信息在仓库基本信息页面可以查看
-
打标签
使用
docker image ls
可以查看镜像iddocker tag [ImageId] [crpi-.cn-beijing.personal.cr.aliyuncs.com/[命名空间]/[仓库名称]:[镜像版本号]]
-
推送至阿里云
docker push [crpi.cn-beijing.personal.cr.aliyuncs.com/[命名空间]/[仓库名称]:[镜像版本号]
-
启动容器
- 首先服务器已经安装docker,进入服务器终端,拉取镜像
docker pull crpi.cn-beijing.personal.cr.aliyuncs.com/[命名空间]/[仓库名称]:[镜像版本号]
- 使用
docker run -p 3000:3000 nextjs-docker
命令启动容器,或者使用Docker Compose进行启动。 - 安全组放行3000端口,这时通过公网ip+端口号就可以访问项目了。
配置nginx
如果有域名还可以配置nginx进行反向代理,可以申请一张免费的ssl证书,就可以进行https访问了。
需要注意的问题 如果nginx是通过docker运行的容器,需要注意文件夹的挂载,否则配置项获取不到ssl证书。
例如:
jsx
// 将主机(宿主机)的 ./data 目录映射到容器内的 /app/data 目录
volumes:
- ./data:/app/data
此时你需要把ssl证书存放在服务器data目录下,nginx容器才能根据路径读取到。
jsx
# 仅处理HTTP请求,并强制跳转到HTTPS
server {
listen 80;
server_name [域名];
# 将所有HTTP请求永久重定向到HTTPS对应的地址
return 301 https://$host$request_uri;
}
# 专门处理HTTPS请求
server {
listen 443 ssl http2; # 建议开启http2
server_name [域名];
# SSL证书路径
ssl_certificate /app/data/ssl/fullchain.pem;
ssl_certificate_key /app/data/ssl/privkey.pem;
# SSL优化参数
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
# 日志文件
access_log /app/data/log/access.log;
error_log /app/data/log/error.log;
# 代理配置
location / {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
# 这些Header对于WebSocket和正确传递客户端信息至关重要
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
# 超时设置
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
}
}