Skip to content

Docker 部署 ​

一、概念 ​

Docker 有三个核心概念:Image、Container、Repository

Image: 镜像是Docker的基础构建块。镜像包含了创建Docker容器所需的所有文件和配置信息,如操作系统、应用程序、依赖项等。

Container: 容器是从镜像创建的运行实例。容器是一个沙箱环境,它包含了应用程序及其所有依赖项

Repository:仓库是集中存储和分发镜像的地方,类似于github。用户可以从仓库中拉取所需的镜像。常用的公共仓库有 Docker Hub: https://hub.docker.com/ 。也可搭建自己的私有镜像仓库,如阿里云容器镜像服务

文档:https://docs.docker.com/guides/get-started/

二、安装 ​

Mac:https://docs.docker.com/desktop/install/mac-install/

Windows:https://docs.docker.com/desktop/install/windows-install/

Linux:https://docs.docker.com/desktop/install/linux-install/

Docker Desktop 默认安装在C盘,因此只能通过命令行安装,使用管理员权限打开cmd,进行到 Docker Desktop Installer.exe 包目录后运行(提前在D盘创建Docker文件夹)

bash
"Docker Desktop Installer.exe" install --installation-dir="D:\Docker" --accept-license

运行之后会弹窗安装页面,点 ok 安装即可

提示:在windows环境中,如果以前安装过Docker,然后又重新安装最新的Docker。可能会因为wsl版本过低,导致Docker安装后一直打不开。此时可在cmd中执行:wsl --update,执行完后重启电脑

如果没有安装过WSL,可访问https://github.com/microsoft/WSL/releases,手动进行下载 wsl.2.5.6.0.x64.msi

三、设置镜像源 ​

与配置npm为淘宝源相似,docker同样需要设置镜像源,否则可能会因网络问题导致包下载失败

在windows中配置:docker desktop -> 设置 -> Docker Engine 添加配置

json
"registry-mirrors": ["https://dockerproxy.net"]

提示:dockerproxy.com已被封,使用https://dockerproxy.net来代理。可以访问https://dockerproxy.link/查询最新的代理地址

使用前执行命令docker builder prune,一键清除Build Cache缓存

或者使用阿里镜像,前提需使用docker login进行登录

四、自动化构建 ​

1. next.config.mjs ​

修改next.config.mjs,将生产环境所需要的安装包都打包进去(不包含devDependencies中的包)

js
const nextConfig = {
  output: "standalone",
};

配置之后,不需要在服务器上另外安装项目的node_modules

2. .dockerignore ​

根目录新增.dockerignore,过滤掉不需要包含在镜像中的文件和目录

text
Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.next
.git

3. Dockerfile ​

根目录新增Dockerfile,Dockerfile 包含了一系列用于构建Docker镜像的指令和配置信息

dockerfile
FROM node:18-alpine AS base

# 可选,自定义参数变量,在docker build时通过--build-arg ENV=参数

# ARG ENV

# Install dependencies only when needed

FROM base AS deps
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
RUN apk update
RUN apk add --no-cache libc6-compat
WORKDIR /app

COPY package.json  ./
COPY package-lock.json ./
RUN npm config set registry https://registry.npmmirror.com \
  && npm_config_platform=linux npm_config_arch=x64 npm_config_libc=glibc npm ci

# Rebuild the source code only when needed

FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

# 可使用自定义参数变量来打包

# RUN npm run ${ENV}

# Production image, copy all the files and run next

FROM base AS runner
WORKDIR /app

ENV NEXT_TELEMETRY_DISABLED 1

COPY --from=builder  /app/.next/standalone ./
COPY --from=builder  /app/.env /app
COPY --from=builder  /app/public /app/public
COPY --from=builder  /app/.next/static /app/.next/static

EXPOSE 3000

ENV PORT 3000

ENV HOSTNAME="0.0.0.0"

CMD node server.js

该配置文件主要有四个阶段:

阶段一,基础镜像:提供 Node.js 18 运行环境

阶段二,依赖安装:基于package-lock.json文件进行依赖安装,生成node_modules

阶段三,构建阶段:拷贝deps阶段的node_modules和本地文件,并运行npm run build进行打包

阶段四,运行阶段:将builder阶段的standalone,.env 等生产环境需要的文件拷贝到相应目录,配置完端口号后,执行node server.js运行Next.js程序

问题1:阶段二中为什么不直接拷贝本地的node_modules,而是重新在Docker镜像构建阶段去安装? ​

原因:为了兼容运行环境。例如Next.js的Image组件依赖的sharp包,在Windows安装的sharp包,运行到服务器Linux上会报错。因此在Docker构建阶段,配置npm_config_platform=linux,设置 npm 的平台环境变量为 linux

问题2:ENV NEXT_TELEMETRY_DISABLED 1配置的作用 ​

作用:这个环境变量的作用是禁用 Next.js 应用程序的遥测功能。Next.js 默认会收集一些匿名的使用数据,并将其发送回 Vercel (Next.js 的开发公司)的服务器

问题3:如何减小生成环境包的体积 ​

方法:配置中将public文件与static文件都拷贝到了镜像中,这些资源可以放到cdn进行访问

4. 构建镜像 ​

在项目根目录运行docker build,将会依据Dockerfile文件的配置内容进行镜像构建

bash
docker build -t next .

-t:给镜像命名,这里镜像名为next

. 基于当前目录的Dockerfile来构建镜像

如果需要传入自定义参数

bash
docker build --build-arg ENV=build:dev -t next .

五、查看镜像 ​

1. 查看镜像 ​

bash
docker images

2. 查看某个特定的镜像 ​

过滤并显示与“next”相关的Docker镜像

bash
docker images | grep next

六、删除镜像 ​

1. 删除镜像 ​

bash
docker rmi <image_name>

rmi:remove image的缩写

<image_name>:要删除的镜像名称或者镜像id

2. 删除所有没有标签的镜像 ​

bash
docker image prune

3. 删除所有未被容器使用的镜像 ​

bash
docker image prune -a

七、推送镜像 ​

1. 私有镜像库设置 ​

docker默认只支持https协议,如果私有库是http协议或者ip地址,需设置insecure-registries

windows配置,docker desktop -> 设置 -> Docker Engine 添加配置

json
//域名或ip地址,不用加协议
"insecure-registries": ["www.test.com","11.11.11.11"]

2. 阿里云镜像库 ​

除了搭建私有镜像仓库,还可以使用阿里云镜像库

阿里云容器镜像服务:https://cr.console.aliyun.com/cn-hangzhou/instances

(提示:先创建镜像仓库,然后根据提示,进行操作)

3. 登录镜像库 ​

bash
docker login --username=your_username registry.cn-hangzhou.aliyuncs.com

--username:用户名

registry.cn-hangzhou.aliyuncs.com:指定镜像仓库地址,如果未指定,默认为官方仓库 Docker Hub

4. 镜像标签 ​

给镜像打标签

bash
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

SOURCE_IMAGE[:TAG]:源镜像

TARGET_IMAGE[:TAG]:更改后的镜像名([]代表可选,不传为latest)

例如:

bash
docker tag next nodejs/next

5. 推送镜像 ​

bash
docker push NAME[:TAG]

NAME:要推送的镜像名称

[:TAG]: 可选的镜像标签。如果不指定标签,默认使用 latest 标签

bash
docker push nodejs/next

6. 退出登录 ​

bash
docker logout

八、构建容器 ​

1. 拉取镜像 ​

容器都是基于镜像构建的,在服务器先拉取刚刚推送的镜像

bash
docker pull nodejs/next

2. 构建容器 ​

bash
docker run -di --name=next --restart always -p 3000:3000 -v /data:/app/.next/cache nodejs/next

-d:容器在后台运行

-i:允许你对容器内的 STDIN 进行交互

--name:启动的容器名

--restart:设置启动类型

-p [主机]:[容器]:端口映射

-v /data:/app/.next/cache:将/app/.next/cache的文件与主机/data目录关联起来,实现docker数据持久化保存

nodejs/next:启动的镜像名

九、使用 yml 配置文件构建文件 ​

通过docker run构建容器,需手动输入多个参数,每次输入比较麻烦,可通过yml配置文件启动

1. 在根目录创建nextData文件夹,并修改文件夹权限 ​

bash
cd / && mkdir nextData && chmod -R 777 /nextData

2. 创建环境变量配置文件(可选,如果需要在外部指定环境变量的话) ​

在根目录新建.env.local

text
GATEWAY_NORMAL_URL=普通接口的网关地址
GATEWAY_DATAID_URL=dataid形式接口的网关地址

3. 在nextData文件夹中创建docker-compose.yml文件 ​

yaml
services:
  next:
    image: registry.cn-hangzhou.aliyuncs.com/your_namespace/next
    container_name: next
    ports:
      - "3000:3000"
    restart: always
    volumes:
      - /nextData:/app/.next/cache
      - /nextData/.env.local:/app/.env.local
    command: ["node", "server.js"]

image:是远程镜像地址

volumes:docker数据持久化保存,除了存储.next/cache,还将.env.local与家目录的.env.local进行关联,可在外部手动修改配置参数

4. 拉取远程镜像 ​

在docker-compose.yml文件目录运行

bash
docker compose pull

5. 启动服务,在后台运行 ​

bash
docker compose up -d

6. 停止服务 ​

bash
docker compose down

十、查看容器 ​

1. 进入容器内部 ​

bash
docker exec -it next /bin/sh

docker exec:进入容器内部

-it:以交互式模式进入容器

/bin/sh:进入容器后使用shell

2. 查看容器结构 ​

bash
ls -a

ls:列出当前目录下的所有文件和目录

-a:显示包括隐藏文件(以 . 开头的文件)在内的所有内容

3. 退出容器 ​

bash
exit

十一、删除容器 ​

1. 查看容器 ​

查看运行中的容器

bash
docker ps

查看所有容器

bash
docker ps -a

2. 删除容器 ​

根据 id 删除容器

bash
docker rm -f e31f

rm:remove缩写

-f:强制删除,即使容器在运行

3. 删除所有停止的容器 ​

bash
docker container prune

十二、Nginx配置 ​

nginx
server {
  listen 443 ssl; #SSL协议访问端口号为443。此处如未添加ssl,可能会造成Nginx无法启动。
  server_name www.example.com; #将localhost修改为您证书绑定的域名,例如:www.example.com。

  ssl_certificate domain/nuxt.pem; #将domain name.pem替换成您证书的文件名。
  ssl_certificate_key domain/nuxt.key; #将domain name.key替换成您证书的密钥文件名。
  ssl_session_timeout 5m;
  ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #使用此加密套件。
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #使用该协议进行配置。
  ssl_prefer_server_ciphers on;

  location / { #代理地址
    proxy_pass http://localhost:3000;
  }

  # etag on;

  # expires 7d;

}

十三、将SSR作为子应用部署 ​

1. 修改next.config.js,增加路由前缀 ​

js
const nextConfig = {
  basePath: "/docs",
  assetPrefix: "/docs", //正确读取静态资源
};

如果使用到了public文件夹下的资源,引入路由需从"/"变为"/docs"

2. 使用window.open进行跳转 ​

js
window.open("https://react.example.com/login", "_self");

3. 在服务端启动SSR项目 ​

4. 配置Nginx代理,代理/docs开头的路径 ​

nginx
server {
  listen 443 ssl; #SSL协议访问端口号为443。此处如未添加ssl,可能会造成Nginx无法启动。
  server_name react.example.com; #将localhost修改为您证书绑定的域名,例如:www.example.com。
  ssl_certificate domain/react.pem; #将domain name.pem替换成您证书的文件名。
  ssl_certificate_key domain/react.key; #将domain name.key替换成您证书的密钥文件名。
  ssl_session_cache shared:SSL:1m;
  ssl_session_timeout 5m;
  ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
  ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
  ssl_prefer_server_ciphers on;
  location / {
    root /static/react-manage;
    try_files $uri $uri/ /index.html;
    index index.html;
  }
  location /docs {
    proxy_pass http://127.0.0.1:3000;
  }
}

5. 访问https://react.example.com/docs将会看到SSR页面,再通过window.open跳转,能跳转到SPA项目的登录页 ​