docker容器化部署项目流程

一、 前言

简单介绍项目背景:这是一个前后端分离的社区项目,后端使用 Spring Boot,前端使用 Vue,数据库使用 MySQL,缓存使用 Redis。 记录将原本在本地运行的项目,迁移到阿里云 CentOS 服务器并通过 Docker Compose 一键编排的过程。

二、 项目目录结构

首先规划好服务器上的目录结构,清晰明了:

复制代码
/usr/local/src/docker/aicommunity
├── backend
│   ├── Dockerfile
│   └── app.jar
├── frontend
│   ├── Dockerfile
│   ├── nginx.conf
│   └── dist/
├── database
│   ├── init/ (存放 .sql 初始化脚本)
│   └── data/ (存放数据库文件挂载)
└── docker-compose.yml

三、 核心配置文件 (经过千锤百炼的最终版)

1. docker-compose.yml

重点说明: 解决了服务依赖、端口映射冲突、以及 Redis 的加入。

复制代码
version: '3.8'

services:
  # 1. MySQL 服务
  mysqldb:
    image: mysql:8.0
    container_name: mysqldb
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: 你的强密码
      MYSQL_DATABASE: community          # 自动创建库名
    ports:
      - "3307:3306"                      # 宿主机3307,防止和本机MySQL冲突
    volumes:
      - ./database/data:/var/lib/mysql
      - ./database/init:/docker-entrypoint-initdb.d # 初始化脚本挂载

  # 2. Redis 服务 (验证码必备)
  redis:
    image: redis:alpine
    container_name: redis-server
    restart: always
    ports:
      - "6300:6379"                      # 宿主机用6300查看,容器内部还是6379

  # 3. 后端服务
  backend:
    build: ./backend
    container_name: backend-app
    restart: always
    ports:
      - "8086:8080"
    depends_on:
      - mysqldb
      - redis
    environment:
      SERVER_PORT: 8080                  # 强制容器内端口为8080
      # 数据库连接 (注意 host 写服务名 mysqldb)
      SPRING_DATASOURCE_URL: jdbc:mysql://mysqldb:3306/community?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: 你的强密码
      # Redis 连接 (注意 host 写服务名 redis,端口写内部端口 6379)
      SPRING_REDIS_HOST: redis
      SPRING_REDIS_PORT: 6379

  # 4. 前端服务
  frontend:
    build: ./frontend
    container_name: frontend-app
    restart: always
    ports:
      - "86:80"
    depends_on:
      - backend
2. 后端 Dockerfile (解决验证码报错的关键)

重点说明: Alpine 镜像默认没有字体,会导致 EasyCaptchaNullPointerException

复制代码
FROM openjdk:8-jdk-alpine

# ✅ 关键一步:安装字体库,解决验证码无法生成的问题
RUN apk add --no-cache fontconfig ttf-dejavu

WORKDIR /app
COPY *.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
3. 前端 Nginx 配置 (解决跨域与路径问题)

重点说明: /prod-api/ 的反向代理配置。

复制代码
server {
    listen       80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
    }

    # 反向代理后端接口
    location /prod-api/ {
        # 注意:这里 proxy_pass 结尾加 / 表示去掉前缀
        proxy_pass http://backend:8080/;
    }
}

四、 部署过程中遇到的那些"坑" (精华部分)

这部分是博客最有价值的地方,把您遇到的错误和解法列出来:

坑点 1:Docker 镜像拉取失败 (403 Forbidden)
  • 现象: openjdk:8-jdk-alpine 拉不下来。

  • 原因: 国内 Docker 源不稳定。

  • 解决: 配置阿里云镜像加速器,修改 /etc/docker/daemon.json

坑点 2:后端连不上数据库 (Host 误区)
  • 现象: 报错 Communications link failure

  • 原因: 以前在本地写 localhost:3306,但在 Docker 里,localhost 指的是容器自己。

  • 解决: 将连接地址改为 Docker Compose 服务名 jdbc:mysql://mysqldb:3306/...

坑点 3:缺少 Redis 导致 502 Bad Gateway
  • 现象: 前端访问验证码报 502,后端日志显示连接拒绝。

  • 原因: 忘记部署 Redis 容器,或者后端配置里没有指定 Redis 地址。

  • 解决: 在 compose 文件中添加 Redis 服务,并配置 SPRING_REDIS_HOST: redis

坑点 4:验证码报空指针异常 (NullPointerException)
  • 现象: 后端报错 java.lang.NullPointerException at sun.awt.FontConfiguration

  • 原因: 使用了 Alpine 极简镜像,系统里没有字体库,Java 的 AWT 绘图功能无法使用。

  • 解决: 修改 Dockerfile,添加 RUN apk add --no-cache fontconfig ttf-dejavu

坑点 5:端口映射的认知误区
  • 现象: Redis 映射为 6300:6379,后端去连 6300 连不上。

  • 原因: Docker 容器间通信(Internal)使用的是原始端口 6379,映射端口 6300 是给宿主机外部用的。

  • 解决: 后端配置文件里 SPRING_REDIS_PORT 必须写 6379

坑点 6:数据库初始化脚本不执行
  • 现象: init.sql 挂载了,但表没创建。

  • 原因: MySQL 容器只有在数据目录为空时才会执行初始化脚本。如果之前启动过一次,已经有数据了,它就会忽略脚本。

  • 解决: docker compose down 后,手动删除挂载的数据目录 rm -rf ./database/data/*,再重新启动。


五、 最终启动命令

复制代码
# 1. 一键构建并启动
docker compose up -d --build

# 2. 查看所有服务状态
docker compose ps

# 3. 查看后端日志 (排错必备)
docker compose logs -f backend

六、 总结

容器化部署虽然初期配置麻烦,通过 Docker Compose,我们成功实现了"一次配置,到处运行"。这次经历让我深刻理解了 Docker 网络通信机制、镜像构建细节以及 Linux 环境差异带来的影响。

Dockerfile是Docker Compose之间的区别

Dockerfile 是用来"造人"的(构建镜像),Docker Compose 是用来"排兵布阵"的(管理运行)。

1. 核心定义区别

特性 Dockerfile Docker Compose (docker-compose.yml)
作用对象 单个镜像 (Image) 多容器应用 (Multi-Container App)
核心职责 构建 (Build):决定容器里装什么软件、什么代码、什么环境。 编排 (Orchestrate):决定怎么启动容器、端口怎么开、容器间怎么连。
执行时机 在容器运行之前(打包阶段)。 在容器运行之时(启动阶段)。
对应命令 docker build docker compose up
比喻 食谱:决定了一道菜里放什么料(盐、糖、肉)。 套餐菜单:决定了一桌饭包含哪些菜(汉堡+薯条+可乐),以及怎么摆盘。

2. 深度功能对比

🛠 Dockerfile:关注"内部"

它只关心容器里面有什么。

  • 安装软件: 比如 RUN apk add fontconfig(你刚才加字体就是改这里)。

  • 复制代码: 比如 COPY *.jar app.jar

  • 配置环境: 比如 ENV JAVA_HOME /usr/jdk

  • 启动命令: 比如 ENTRYPOINT ["java", "-jar", "app.jar"]

  • 特点: 一旦构建成镜像,里面内容就固定了,不可变。

🕹 Docker Compose:关注"外部"与"关系"

它关心容器之间 怎么配合,以及和宿主机的关系。

  • 端口映射: 比如 ports: "8086:8080"(把内部的8080暴露给外部8086)。

  • 依赖关系: 比如 depends_on: - redis(先启 Redis 再启后端)。

  • 环境变量注入: 比如 SPRING_REDIS_HOST: redis(告诉后端 Redis 在哪)。

  • 数据挂载: 比如 volumes: ./data:/var/lib/mysql(把数据存在外面)。

  • 特点: 它可以随时修改,改完重启容器就生效,不需要重新编译代码。


3. 结合你刚才的实战案例

回想一下你刚刚遇到的两个经典报错,最能说明问题:

  • 案例一:验证码报错(缺字体)

    • 问题: 操作系统里没字体库。

    • 修改位置: Dockerfile

    • 为什么? 因为这是镜像内部缺少了基础软件,必须重修"重新制造"这个镜像(Rebuild)。

  • 案例二:连不上 Redis(502/500错误)

    • 问题: 没启动 Redis 容器,或者后端不知道 Redis 的地址。

    • 修改位置: docker-compose.yml

    • 为什么? 因为这是架构问题。你需要增加一个服务(Redis),并配置后端怎么去连接它。这不需要修改代码,也不需要重新安装 Linux 软件,只是调整"兵力部署"。


4. 它们的关系图

可以想象成一个建筑工程

  1. Dockerfile预制板工厂的图纸

    • 负责生产标准的"墙板"、"地板"、"窗户"(即镜像)。

    • 工厂里只管把东西造好,不管这块板子将来装在哪。

  2. Docker Compose施工现场的蓝图

    • 它指挥工人:"把这块墙板(后端镜像)立在这里,把那个地板(数据库镜像)铺在那里"。

    • 它负责接通水电(网络),开好门窗(端口)。

5. 总结口诀(送给你的博客)

  • 要改环境、装软件、换代码 ------ 找 Dockerfile

  • 要改端口、配网络、加数据库 ------ 找 Docker Compose

  • Dockerfile 造出了"演员",Docker Compose 搭建了"舞台"并指挥"演出"。

相关推荐
Trouvaille ~3 小时前
TCP Socket编程实战(三):线程池优化与TCP编程最佳实践
linux·运维·服务器·网络·c++·网络协议·tcp/ip
大大大反派3 小时前
CANN 生态中的自动化部署引擎:深入 `mindx-sdk` 项目构建端到端 AI 应用
运维·人工智能·自动化
WHD3064 小时前
苏州勒索病毒加密 服务器数据解密恢复
运维·服务器
骇客野人4 小时前
通过脚本推送Docker镜像
java·docker·容器
蜡笔小炘4 小时前
LVS -- 持久链接(Persistent Connection)实现会话粘滞
运维·服务器
liux35285 小时前
基于kubeadm部署Kubernetes 1.26.4 集群指南
云原生·容器·kubernetes
HalvmånEver5 小时前
Linux:线程同步
linux·运维·服务器·线程·同步
岁杪杪5 小时前
关于运维:LINUX 零基础
运维·服务器·php
Zfox_5 小时前
CANN GE 深度解析:图编译器与执行引擎的后端优化策略、OM 文件结构与 Stream 调度机制
容器·节点小宝