在Docker中部署前端和后端的实现

目前我使用的是dockers desktop进行前后端和各种中间件的部署,都在同一个网络环境中,我们开始进行后端的部署.

1.编写Dockerfile文件,Java的版本是Java21

XML 复制代码
# 构建阶段
FROM eclipse-temurin:21-jre AS builder

WORKDIR /app
COPY target/*.jar app.jar

# 分层提取
RUN java -Djarmode=layertools -jar app.jar extract

# 运行阶段
FROM eclipse-temurin:21-jre

# 时区与用户设置(Ubuntu 使用 apt-get)
RUN apt-get update \
    && apt-get install -y tzdata \
    && rm -rf /var/lib/apt/lists/* \
    && ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && dpkg-reconfigure -f noninteractive tzdata \
    && groupadd -r appgroup && useradd -r -g appgroup appuser

WORKDIR /app

# 从构建阶段复制分层文件
COPY --from=builder /app/dependencies/ ./
COPY --from=builder /app/spring-boot-loader/ ./
COPY --from=builder /app/snapshot-dependencies/ ./
COPY --from=builder /app/application/ ./

# 创建日志目录,并赋予 appuser 完全的读写权限
RUN mkdir -p /app/logs && chown -R appuser:appgroup /app

# 切换到普通用户
USER appuser

EXPOSE 8090

# 启动命令(如果项目未启用虚拟线程,可去掉 -XX:+UseVirtualThreads)
ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]

这里稍微介绍以下用法:

关键指令拆解

指令 作用 使用技巧
FROM 指定基础镜像 优先选择 -alpine(轻量)或 -slim,明确版本号(如 17-jre)避免"滚动更新"带来的兼容风险
WORKDIR 设置工作目录 如果目录不存在会自动创建,建议使用绝对路径
COPY 从构建上下文复制文件 利用 Docker 层缓存:将变化最少的指令(如依赖文件)放在前面,变化最频繁的(如业务代码)放在最后,以加速重复构建
RUN 执行构建命令 每条 RUN 都会产生一个新层,尽量合并多条命令(如 && 连接),减少镜像层数
USER 切换为普通用户 生产环境务必使用非 root 用户运行应用,提高安全性
EXPOSE 声明容器监听端口 仅用于文档说明,不会自动映射端口,运行时仍需 -p 映射
ENTRYPOINT / CMD 设置容器启动命令 ENTRYPOINT 更适合作为固定启动命令,CMD 作为可覆盖的默认参数

其中Eclipse Temurin 是 Eclipse 基金会下的一个开源项目,它提供的是 OpenJDK(开源 Java 标准实现)的高质量、经过 TCK(技术兼容性工具包)测试的构建版本。

  • 它就是 Java 本身 。你可以把它看作是官方的 Oracle JDK 的免费、开源且可靠的替代品。

  • 在 Dockerfile 中的作用 :它为你的 Spring Boot 应用提供了运行所需的 Java 虚拟机(JVM) 和基础类库。

21-jre-alpine 拆解

这个标签名由三个部分组成,对应了你问的"版本号":

字段 含义 说明
21 Java 版本号 表示这个镜像内置了 Java 21 的运行时。这是目前 Spring Boot 3.x 版本的基线版本(必须 Java 17 及以上)。
-jre 运行环境类型 代表 Java Runtime Environment (Java 运行时环境) 。它只包含运行 Java 程序所需的虚拟机(JVM)和核心类库,不包含 编译工具(javac)、调试工具等。
-alpine 操作系统基础镜像 Alpine 是一个极其轻量级的 Linux 发行版 ,体积非常小(约 5 MB)。使用它作为基础,能让你的最终镜像体积骤减。例如,eclipse-temurin:21-jre-alpine 镜像大小通常在 80 MB 左右,而 eclipse-temurin:21-jre(基于标准 Ubuntu)可能在 200 MB 以上。

Spring Boot 分层构建原理(优化重点)

在 Spring Boot 2.3+ 中,可以通过 layertools 将 fat jar 拆分为四个层:

• dependencies:大部分外部依赖(稳定,很少变动)

• spring-boot-loader:Spring Boot 启动器

• snapshot-dependencies:快照依赖(适中变动)

• application:你的业务代码(频繁变动)

为什么要分层?

• 当业务代码改动时,只需要重建 application 层,前几层可以直接复用 Docker 缓存,大幅缩短构建时间(从几分钟缩短到几秒)。

• 推送/拉取镜像时也更省流量。

2.接下来我们就可以编译Dockerfile文件了,通过wind+x组合键选择"终端(管理员)"的powershell,进入到项目所在目录的Dockerfile文件夹下面,比如我的是E:\dev\client-agent,我们可以通过以下命令进行Dockerfile文件的执行:

XML 复制代码
# 编译项目,注意这里的有个点符号必须要有,不然就报错,它代表"当前目录",告诉 Docker 到哪里去找 Dockerfile 和相关文件
docker build --no-cache -t client-agent-backend:latest .

# 创建dockers 容器,并启动容器,容器名称是client-agent-backend,第一个8090是映射到外部的端口号,第二个8090是我们自己服务启动的端口号
docker run -d -p 8090:8090 --name client-agent-backend client-agent-backend:latest

# 如果发现容器执行不成功,可以删除容器
docker rm -f client-agent-backend

# 关闭容器
docker stop client-agent-backend

# 启动容器
docker start client-agent-backend

3.注意事项:

在我们的application.yml配置文件中,需要把所有的链接到其他服务的路径修改为host.docker.internal,这些服务也必须在相同的dockers服务路径下面,如果是其他的dockers服务路径,需要修改为相应的地址。

完成以上这些后,我们就可以正常启动dockers服务了。

接下来是前端服务的部署:

1.同样的我们在前端服务中配置Dockerfile文件,内容如下:

XML 复制代码
# 第一阶段:构建阶段 (build stage)
FROM node:20-alpine AS builder

# 设置工作目录
WORKDIR /app

# 复制依赖清单文件 (利用 Docker 层缓存)
COPY package*.json ./

# 安装依赖 (如果网络慢,可配置国内镜像源)
RUN npm config set registry https://registry.npmmirror.com \
    && npm ci

# 复制项目源代码
COPY . .

# 执行项目构建 (生成 dist 或 build 目录)
RUN npm run build

# 第二阶段:运行阶段 (production stage)
FROM nginx:1.27-alpine

# 安装 tzdata 并设置时区 (可选)
RUN apk add --no-cache tzdata \
    && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo "Asia/Shanghai" > /etc/timezone

# 复制自定义 Nginx 配置文件 (如果有)
COPY nginx.conf /etc/nginx/conf.d/default.conf

# 从构建阶段复制构建产物到 Nginx 的静态目录
COPY --from=builder /app/dist /usr/share/nginx/html

# 暴露 80 端口
EXPOSE 80

# 启动 Nginx (前台运行,保持容器存活)
CMD ["nginx", "-g", "daemon off;"]

2.我们还需要提供nginx.conf配置文件,内容如下:

XML 复制代码
server {
    listen 80;
    server_name localhost;
    root /usr/share/nginx/html;
    index index.html;

    # ========== 核心修改:处理 API 请求 ==========
    # 将所有 /api/ 开头的请求转发给后端服务
    location /api/ {
        # 后端服务地址(取决于你的部署环境)
        # 方案 A:后端也跑在 Docker 里,用容器名访问(如 http://backend-server:8090)
        # 方案 B:后端跑在宿主机上,用 host.docker.internal(Windows/Mac)或宿主机 IP
        proxy_pass http://host.docker.internal:8090;
        # 注意:如果后端地址带 /api/,则直接拼接;如果不带,比如 http://host:8090,可能会多一层路径,需留意斜杠

        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;
    }

    # ========== 处理前端路由(保留你原有的) ==========
    location / {
        try_files $uri $uri/ /index.html;
    }

    # 静态资源缓存(可选)
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

这里需要注意的是这里后端地址的配置,因为我们也是在同一个dockers下面,因此也配置成host.docker.internal,最后我们就可以启动前端服务了:

XML 复制代码
# 这个同后端启动过程一样,Dockerfile文件的执行
docker build --no-cache -t client-agent-front:latest

# 给容器起名并启动容器,其中5173端口号是web页面的访问地址端口,80端口号是nginx.conf里面配置的
docker run -d -p 5173:80 --name client-agent-front client-agent-front:latest

# 容器出错删除容器
docker rm -f client-agent-front

# 关闭容器
docker stop client-agent-front

# 启动容器
docker start client-agent-front

到这里我们就完成了前后端的dockers容器化服务,如图

相关推荐
wdfk_prog1 小时前
Docker 常用语法与命令:CLI、Dockerfile 与 Compose 速查
运维·docker·容器
无敌糖果1 小时前
K8S network namespace错误分析
docker·容器·kubernetes
skywalk81631 小时前
通过下载Ubuntu ova文件在Virtual Box快速安装ubuntu
linux·运维·ubuntu·virtualbox
姚不倒2 小时前
HAProxy 系列(四):多中间件统一 VIP 入口 — 架构模式与最佳实践
运维·中间件·架构·haproxy
happymade2 小时前
7000 台网络设备批量纳管 & 自动拓扑生成实战——MSRM3 完整操作流程与关键要点复盘
运维·服务器·网络·zabbix·grafana·msrm3
郝开2 小时前
Docker Compose 模块化多环境配置规范指南:示例搭建Kibana 9.4.2
docker·容器·kibana
做萤石二次开发的哈哈2 小时前
萤石蓝海 AIoT 一站式工作台:海康LCD会议平板接入,多端大屏运维应用一站生成
运维·物联网·电脑·萤石开放平台·会议室管理·蓝海aiot一站式工作台·otap物模型
运维老郭2 小时前
Prometheus 监控 K8s 从入门到入坑:工作原理 + 部署实操 + 避坑指南
云原生·容器·kubernetes
Shadow(⊙o⊙)2 小时前
Linux网络——文件与网络的连接桥梁struct sock {
linux·运维·网络