nextjs项目部署阿里云实践

Dockerfile

1. 介绍

简单来说,Dockerfile 就是一份自动化构建镜像的"说明书"或"脚本"。它详细定义了一个容器的环境,从基础操作系统,到应用程序代码的添加,再到环境变量的设置和启动命令的执行。通过这些指令,Docker 可以自动地将应用程序及其依赖打包成一个轻量级、可移植的容器镜像。

2. 常用指令

  • FROM: 指定基础镜像。每个 Dockerfile 都必须以 FROM 指令开始,它定义了后续指令的执行环境。例如 FROM node:20-alpine3.20FROM python:3.9-slim
  • WORKDIR: 设置工作目录。后续的 RUN, CMD, COPY, ADD 等指令都会在这个目录下执行。
  • COPYADD: 将本地文件或目录复制到镜像的文件系统中。ADD 支持解压和 URL 等高级功能。
  • RUN: 在镜像构建过程中执行命令。通常用于安装软件包、更新系统等。例如 RUN pnpm i
  • EXPOSE: 声明容器在运行时监听的网络端口。这主要起到文档说明的作用,并不会实际发布端口。
  • CMDENTRYPOINT: 指定容器启动时默认执行的命令。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 参数表示在后台运行。

推送镜像至阿里云

首先需要开通阿里云的容器镜像服务,个人版的足够用了。

可以根据个人喜好,选择是手动构建推送镜像,还是自动构建镜像。自动构建在绑定仓库信息是选择上就行了。

  1. 自动构建镜像
  1. 手动构建镜像,上传至阿里云容器镜像服务。

    使用 docker build -t nextjs-docker . 命令构建镜像后

    1. 登录阿里云镜像服务 docker login --username=[username] crpi.cn-beijing..cr.aliyuncs.com

      具体信息在仓库基本信息页面可以查看

    2. 打标签

      使用 docker image ls 可以查看镜像id

      docker tag [ImageId] [crpi-.cn-beijing.personal.cr.aliyuncs.com/[命名空间]/[仓库名称]:[镜像版本号]]

    3. 推送至阿里云

      docker push [crpi.cn-beijing.personal.cr.aliyuncs.com/[命名空间]/[仓库名称]:[镜像版本号]

启动容器

  1. 首先服务器已经安装docker,进入服务器终端,拉取镜像 docker pull crpi.cn-beijing.personal.cr.aliyuncs.com/[命名空间]/[仓库名称]:[镜像版本号]
  2. 使用docker run -p 3000:3000 nextjs-docker命令启动容器,或者使用Docker Compose进行启动。
  3. 安全组放行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;
    }
}
相关推荐
CF14年老兵39 分钟前
✅ Next.js 渲染速查表
前端·react.js·next.js
dyb1 小时前
开箱即用的Next.js SSR企业级开发模板
前端·react.js·next.js
CodeWolf1 小时前
docker的基础命令
docker
正经教主2 小时前
【问题】Docker 容器内的应用(如n8n),访问不到外部主机的应用(如mysql)
tcp/ip·docker·容器
Asuicao2 小时前
最新docker国内镜像源地址大全
运维·docker·容器
xhdll2 小时前
embodied复现所需docker环境配置粗略流程
运维·docker·容器
码农101号2 小时前
Linux中Docker Swarm介绍和使用
linux·spring cloud·docker
Nazi62 小时前
dockerfile基础
linux·运维·docker·容器·云计算
焚膏油以继晷,恒兀兀以穷年5 小时前
Docker设置容器时间
运维·docker·容器
Blessed_Li13 小时前
【dify+milvus避坑指南】将向量库milvus集成给dify作为知识库
docker·ai·llm·milvus·dify