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 搭建了"舞台"并指挥"演出"。

相关推荐
techdashen20 分钟前
Cloudflare 为何抛弃 NGINX,用 Rust 自研了一个代理
运维·nginx·rust
南城猿33 分钟前
保姆级 Ubuntu 部署 禅道
linux·运维·ubuntu
珠海西格电力1 小时前
零碳园区产业园管理系统的全场景源网荷储氢协同调度功能是如何实现的
大数据·运维·人工智能·物联网·能源
木雷坞1 小时前
K8s GPU 推理服务 ImagePullBackOff 排查与预热
云原生·容器·kubernetes·gpu算力
wj3055853782 小时前
CC-Switch 在 WSL Ubuntu 中安装记录
linux·运维·ubuntu
人生匆匆2 小时前
通过nginx解决跨域问题
运维·nginx
原来是猿2 小时前
【Socket编程预备知识】
linux·运维·服务器·网络
吴爃2 小时前
Spring Boot 项目在 K8S 中的打包、部署与运维发布实践
运维·spring boot·kubernetes
Elastic 中国社区官方博客3 小时前
在 Elastic 中使用 MCP 自动化用户旅程以进行合成监控
大数据·运维·人工智能·elasticsearch·搜索引擎·自动化·可用性测试
长安链开源社区3 小时前
学者观察 | 基于区块链的隐私计算技术——北京理工大学教授祝烈煌
运维·区块链