从零开始:Dockerfile 编写与 Spring Cloud 项目部署到 Docker Compose

从零开始:Dockerfile 编写与 Spring Cloud 项目部署到 Docker Compose

大家好!今天我们来聊聊如何用 Docker 把一个 Spring Cloud 项目跑起来。如果你是个完全的小白,不用担心,我会一步步带你搞清楚 Dockerfile 里的每一行是什么意思,以及如何把你的服务塞进 Docker Compose 里,和中间件一起愉快地运行。我们还会讲讲 Docker 启动时的 -v 参数和"挂载",以及 context 路径的设置问题。

什么是 Dockerfile?

简单来说,Dockerfile 就是一个"说明书",告诉 Docker 如何打包你的程序。它就像一个食谱,列出了所有原料和步骤,最后烤出一个可以运行的"程序蛋糕"(Docker 镜像)。有了镜像,你就可以用 Docker Compose 像搭积木一样把服务和中间件组合起来。

假设你有一个 Spring Cloud 项目,可能包含多个微服务(比如用户服务、订单服务),每个服务都需要跑在自己的容器里。我们先从单个服务的 Dockerfile 开始讲起,然后再扩展到 Docker Compose。


Dockerfile 详解:以 Spring Cloud 服务为例

我们以一个简单的 Spring Cloud 服务(比如"用户服务")为例,假设它是用 Java 写的,跑在一个 Spring Boot 项目里,打包成了一个 user-service.jar 文件。下面是一个典型的 Dockerfile:

dockerfile 复制代码
# 第一行:选择一个基础镜像
FROM openjdk:11

# 第二行:设置工作目录
WORKDIR /app

# 第三行:复制文件到容器里
COPY target/user-service.jar /app/user-service.jar

# 第四行:暴露端口
EXPOSE 8080

# 第五行:运行命令
CMD ["java", "-jar", "user-service.jar"]

每一行是什么意思?

  1. FROM openjdk:11

    • 作用:这是基础镜像,相当于给你的程序找一个"操作系统+运行环境"。因为 Spring Cloud 是 Java 项目,我们选了 OpenJDK 11(Java 11 的运行环境)。
    • 小白理解 :就像你要做饭,得先有个厨房。openjdk:11 就是这个厨房,里面已经装好了 Java 11 的工具。
  2. WORKDIR /app

    • 作用:设置容器里的工作目录,之后的操作都在这个文件夹里进行。
    • 小白理解 :就像你在厨房里找了个桌子(/app),接下来都在这个桌子上切菜、炒菜。
  3. COPY target/user-service.jar /app/user-service.jar

    • 作用 :把你本地的 user-service.jar 文件复制到容器里的 /app 文件夹下。
    • 小白理解 :你把家里做好的蛋糕(user-service.jar)搬到厨房的桌子上(/app),名字还是叫 user-service.jar
  4. EXPOSE 8080

    • 作用:告诉 Docker 这个容器会用 8080 端口跑服务,但只是声明,不是真的开放(开放端口得靠 Docker Compose 或运行命令)。
    • 小白理解:就像你在厨房门口贴了个告示:"我这里会用 8080 号窗口送菜",但门还没开。
  5. CMD ["java", "-jar", "user-service.jar"]

    • 作用:容器启动时执行的命令,这里是运行你的 Spring Boot 应用。
    • 小白理解 :相当于你告诉厨房:"开火,用 Java 这个锅,把 user-service.jar 这个蛋糕热一下端出去"。

怎么用这个 Dockerfile?

  1. 把上面内容保存成一个文件,名字就叫 Dockerfile(没后缀)。

  2. 在项目根目录下,确保 target/user-service.jar 存在(通常用 mvn package 打包生成)。

  3. 打开终端,跑这个命令生成镜像:

    bash 复制代码
    docker build -t user-service:latest .
    • -t user-service:latest:给镜像取名叫 user-service,版本是 latest
    • .:告诉 Docker 在当前目录找 Dockerfile。
  4. 跑容器试试:

    bash 复制代码
    docker run -p 8080:8080 user-service:latest
    • -p 8080:8080:把本地的 8080 端口映射到容器的 8080 端口,这样你就能通过 localhost:8080 访问服务。

Docker 启动时的 -v 是什么意思?挂载又是啥?

你可能听说过 docker run 时可以用 -v 参数,比如:

bash 复制代码
docker run -p 8080:8080 -v /my/local/logs:/app/logs user-service:latest

这里多了个 -v /my/local/logs:/app/logs,它是什么意思呢?别急,我们慢慢拆开。

什么是挂载?

挂载(Volume Mount)是 Docker 的一种功能,让你把本地电脑上的文件夹或文件"连接"到容器里的某个文件夹。简单来说,就是让容器能用你电脑上的东西,或者把容器里的东西保存到你电脑上。

  • 小白理解 :想象你的容器是一个独立的小房子,里面有自己的桌子(/app/logs)。挂载就像在房子外接了一根管子,把你家里的抽屉(/my/local/logs)和房子的桌子连起来。房子可以用抽屉里的东西,桌子上的东西也能存到抽屉里。

-v 的格式

-v 后面跟的是两个路径,用冒号 : 分开:

  • 左边/my/local/logs):你电脑上的路径。
  • 右边/app/logs):容器里的路径。

比如 -v /my/local/logs:/app/logs

  • 意思是把你电脑上的 /my/local/logs 文件夹挂载到容器里的 /app/logs 文件夹。
  • 如果你的服务在 /app/logs 里写日志,这些日志会直接出现在你电脑的 /my/local/logs 里。

为什么要用挂载?

  1. 数据持久化

    • 容器就像一个临时小房子,关掉就没了(除非你特意保存)。如果你的服务生成了日志、配置文件之类的东西,不挂载的话,容器一停这些数据就丢了。
    • 挂载后,数据会存到你电脑上,容器重启也不会丢。
  2. 调试方便

    • 比如你的 Spring Cloud 服务需要读取一个本地的配置文件(比如 application.yml),可以用挂载把文件传进去。

举个例子

假设你的 user-service 会生成日志到 /app/logs,你想把日志保存到本地:

  1. 本地创建一个文件夹,比如 /home/user/logs

  2. 启动容器时加 -v

    bash 复制代码
    docker run -p 8080:8080 -v /home/user/logs:/app/logs user-service:latest
  3. 服务跑起来后,日志会出现在 /home/user/logs 里,你可以用文本编辑器直接看。


Docker Compose 登场:服务和中间件一起跑

你提到 Docker Compose 文件里只有中间件(比如 MySQL、Redis)的部署,但没写你的服务。别急,我们来扩展一下,把你的 Spring Cloud 服务加进去,还可以用挂载。

假设你的 docker-compose.yml 长这样:

yaml 复制代码
version: '3'
services:
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: user_db
    ports:
      - "3306:3306"
  redis:
    image: redis:latest
    ports:
      - "6379:6379"

这是中间件的部署,跑了个 MySQL 和 Redis。我们把 user-service 加进去:

yaml 复制代码
version: '3'
services:
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: user_db
    ports:
      - "3306:3306"
  redis:
    image: redis:latest
    ports:
      - "6379:6379"
  user-service:
    build:
      context: ./user-service
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    depends_on:
      - mysql
      - redis
    environment:
      - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/user_db?useSSL=false
      - SPRING_REDIS_HOST=redis
    volumes:
      - /home/user/logs:/app/logs

context: ./user-service 是什么意思?

build 部分,context: ./user-service 告诉 Docker Compose 去哪里找构建镜像需要的文件(包括 Dockerfile 和你的 user-service.jar)。这里的路径是相对于 docker-compose.yml 文件所在目录的。

  • 小白理解 :就像你告诉管家(Docker Compose):"去我家旁边的 user-service 小店拿材料做蛋糕。" docker-compose.yml 是管家的家,./user-service 是从管家家门口出发的路。
如果 Spring Cloud 项目不在 Docker Compose 下属文件夹怎么办?

你提到你的 Spring Cloud 项目可能不在 docker-compose.yml 旁边的文件夹里,而是比它更高一级。比如你的目录可能是这样:

sql 复制代码
my-spring-cloud-project/
├── user-service/
│   ├── Dockerfile
│   ├── target/
│   │   └── user-service.jar
├── order-service/
│   ├── Dockerfile
│   ├── target/
│   │   └── order-service.jar
├── docker-compose/
│   └── docker-compose.yml

在这里,docker-compose.ymldocker-compose/ 文件夹里,而 user-service/ 在上一级(my-spring-cloud-project/)。如果你直接写 context: ./user-service,Docker Compose 会找不到,因为从 docker-compose/ 出发,旁边没有 user-service/

  • 问题 :那 ./user-service 是指哪个地址?是指我的 Spring Cloud 某个具体服务的 Dockerfile 的地址吗?
  • 答案 :是的,context 指向的是某个服务的构建上下文,也就是包含 Dockerfile 和相关文件(比如 JAR 文件)的文件夹。但路径要从 docker-compose.yml 的位置算起。
解决方案:调整路径

你需要用相对路径或绝对路径告诉 Docker Compose 正确的地址。假设 docker-compose.ymldocker-compose/ 里,user-service/my-spring-cloud-project/

  1. 用相对路径

    • docker-compose/ 往上一级是 ../,然后再进 user-service/

    • 所以改成:

      yaml 复制代码
      build:
        context: ../user-service
        dockerfile: Dockerfile
  2. 用绝对路径(更明确,但不灵活):

    • 假设你的项目在 /home/user/my-spring-cloud-project/

      yaml 复制代码
      build:
        context: /home/user/my-spring-cloud-project/user-service
        dockerfile: Dockerfile

更新后的 docker-compose.yml 可能是这样:

yaml 复制代码
version: '3'
services:
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: user_db
    ports:
      - "3306:3306"
  redis:
    image: redis:latest
    ports:
      - "6379:6379"
  user-service:
    build:
      context: ../user-service
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    depends_on:
      - mysql
      - redis
    environment:
      - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/user_db?useSSL=false
      - SPRING_REDIS_HOST=redis
    volumes:
      - /home/user/logs:/app/logs
小白理解
  • 相对路径 ../user-service :就像管家站在 docker-compose/ 门口,抬头一看,旁边没有 user-service,得先退回大门口(../),再走进旁边的 user-service 小店拿材料。
  • user-service 是具体服务的地址:是的,它就是你 Spring Cloud 项目里某个微服务(比如用户服务)的文件夹,里面有 Dockerfile 和 JAR 文件。

其他部分的含义

  1. ports: - "8080:8080"

    • 把本地的 8080 端口映射到容器的 8080 端口。
    • 小白理解:在店门口开了个 8080 号窗口,顾客能直接点单。
  2. depends_on

    • 表示 user-service 依赖 mysqlredis,启动时会先跑中间件。
    • 小白理解:你得先把水电(MySQL、Redis)接好,店才能开张。
  3. environment

    • 设置环境变量,让你的 Spring Cloud 服务知道去哪连数据库和 Redis。
    • 小白理解 :就像给店员写了张纸条:"水管接在 mysql 上,电线接在 redis 上"。
  4. volumes: - /home/user/logs:/app/logs

    • 把本地的 /home/user/logs 挂载到容器里的 /app/logs,保存日志。
    • 小白理解:给店里接了根管子,把日志抽屉连到桌子。

文件夹结构

你的项目可能是这样:

sql 复制代码
my-spring-cloud-project/
├── user-service/
│   ├── Dockerfile
│   ├── target/
│   │   └── user-service.jar
├── docker-compose/
│   └── docker-compose.yml
  • user-service/ 是你的服务代码目录,里面有 Dockerfile 和打包好的 JAR。
  • docker-compose.ymldocker-compose/ 里,管理所有服务。
  • 本地的 /home/user/logs 文件夹需要你手动创建,用来存日志。

怎么跑?

  1. 进入 docker-compose/ 目录,跑:

    bash 复制代码
    docker-compose up --build
    • --build:每次都重新构建镜像,确保最新代码生效。
  2. 访问 localhost:8080,应该能看到你的服务跑起来了!日志会出现在 /home/user/logs 里。


小结与扩展

  • Dockerfile :负责把你的 Spring Cloud 服务打包成镜像,核心是 FROMCOPYCMD
  • Docker Compose :像个大管家,把你的服务和中间件(MySQL、Redis)组合起来跑,靠 buildenvironment 连接一切。
  • 挂载(-vvolumes:让容器和本地共享数据,比如保存日志、传配置文件。
  • context 路径 :告诉 Docker Compose 去哪找 Dockerfile 和文件,路径要从 docker-compose.yml 的位置算起。如果项目层级更高,用 ../ 或绝对路径调整。
  • 如果你有多个微服务(比如 order-service),就再写一个 Dockerfile,然后在 docker-compose.yml 里加一个服务,重复上面的步骤。

希望这篇博客能帮你从零开始搞定 Docker 部署,尤其是弄明白路径问题!有问题欢迎留言,我会尽量解答。

相关推荐
ONE_Gua11 分钟前
chromium魔改——navigator.webdriver 检测
前端·后端·爬虫
可乐加.糖16 分钟前
一篇关于Netty相关的梳理总结
java·后端·网络协议·netty·信息与通信
Kagol17 分钟前
macOS 和 Windows 操作系统下如何安装和启动 MySQL / Redis 数据库
redis·后端·mysql
无名之逆18 分钟前
Rust 开发提效神器:lombok-macros 宏库
服务器·开发语言·前端·数据库·后端·python·rust
9号达人19 分钟前
java9新特性详解与实践
java·后端·面试
Aurora_NeAr26 分钟前
深入理解Java虚拟机-类加载机制
后端
用户984022766791827 分钟前
基于 BFF + GRPC 实现数据聚合的功能
后端·grpc
lqstyle29 分钟前
序列化界的"复仇者联盟":谁才是拯救你数据的超级英雄?
后端
struggleupwards33 分钟前
Go 语言flag库使用指南
后端
Asthenia041236 分钟前
电商项目-支付模块交易链路梳理与时序图
后端