当前位置: 首页 > news >正文

Docker学习其二(容器卷,Docker网络,Compose)

文章目录

  • 6,数据容器卷
    • 6.0容器的理解
    • 6.1容器数据卷
    • 6.2常用操作命令
    • 6.3具名&匿名&绑定挂载
    • 6.4容器共享数据卷
    • 6.5实例:Mysql数据卷
  • 7,DockerFile
    • 7.1概述
    • 7.2编写规范&指令
    • 7.3构建自己的centos镜像
    • 7.4部署SpringBoot项目
  • 8,Docker网络
    • 8.1Docker0
      • 基础概念与原理
      • 通信机制
    • 8.2通过名称通信
    • 8.3自定义网络
    • 8.4跨网络通信
  • 9,Compose
    • 9.1Compose的安装
    • 9.2docker-compose.yml
    • 9.3部署若依项目
      • (1)Linux目录
      • (2)相关命令
      • (3)配置文件
        • 解析
        • 原配置

6,数据容器卷

6.0容器的理解

在非运行态(静态)下,容器可以看作是多个镜像层加上一个可写层的集合。在这里插入图片描述

可写层的定义

可写层是在基于镜像创建容器时,Docker 自动添加到容器最上层的一个特殊文件系统层。它是容器中唯一可进行写入操作的层,而其下方的镜像层(Read Layer) 都是只读的。

可写层的作用

  • 保存容器运行时的修改:当容器运行时,对文件系统进行的任何操作,比如创建新文件、修改现有文件内容、删除文件等,这些更改都不会影响到下方只读的镜像层,而是被记录在可写层中。例如,在一个基于centos镜像创建的容器里,使用touch命令创建一个新文件,该文件就会被创建在可写层;如果修改了镜像层中已有的文件,那么 Docker 会使用写时复制(Copy - on - Write,COW)技术,先将该文件从镜像层复制到可写层,然后在可写层中进行修改 。
  • 维持容器状态:可写层使得每个容器都能拥有独立于镜像以及其他容器的状态。即使多个容器基于同一个镜像创建,它们各自的可写层也互不干扰,保证了容器数据的独立性和隔离性。

6.1容器数据卷

数据容器卷(Data Volume)是一种用于持久化存储容器数据的机制,它可以独立于容器的生命周期存在,方便数据共享和持久化。

数据容器卷的核心特点

  1. 数据卷可以在容器之间共享和重用
  2. 数据卷数据会持久化,即使删除使用它的容器
  3. 可以直接对数据卷中的数据进行修改
  4. 数据卷的变化不会影响镜像的更新

6.2常用操作命令

创建数据卷

docker volume create mydata

查看所有数据卷

docker volume ls

查看数据卷详情

docker volume inspect mydata

使用数据卷运行容器

# 将数据卷挂载到容器的指定路径
docker run -d --name mycontainer -v mydata:/app/data nginx

绑定挂载主机目录作为数据卷

# 将主机的/path/on/host目录挂载到容器的/container/path目录
docker run -d --name mycontainer -v /path/on/host:/container/path nginx

使用匿名卷

# 创建匿名卷,Docker会自动生成卷名
docker run -d --name mycontainer -v /app/data nginx

删除数据卷

# 删除未被使用的数据卷
docker volume prune# 删除指定数据卷(需确保没有容器使用)
docker volume rm mydata

测试

docker run -it -v 主机目录:容器内目录 -p 主机端口:容器内端口docker run -it -v /home/ceshi:/home centos /bin/bash

6.3具名&匿名&绑定挂载

具名挂载(Named Volumes)和匿名挂载(Anonymous Volumes)是两种常用的数据卷挂载方式,它们的主要区别在于是否为数据卷指定了明确的名称。

具名挂载是指为数据卷指定一个明确的名称,便于管理和识别。

# 创建具名卷(可选,运行容器时会自动创建不存在的卷)
docker volume create myappdata# 使用具名卷挂载
docker run -d \--name mycontainer \-v myappdata:/app/data \  # 具名卷myappdata挂载到容器的/app/data目录nginx

匿名挂载没有为数据卷指定名称,Docker 会自动生成一个随机的唯一标识符作为卷名。

# 使用匿名卷挂载(不指定卷名,只指定容器内路径)
docker run -d \--name mycontainer \-v /app/data \  # 匿名卷挂载到容器的/app/data目录nginx

绑定挂载:格式为 -v 宿主机绝对路径:容器内路径(如你的命令中 /home/ceshi:/home),直接将主机的具体目录 / 文件挂载到容器,不属于 Docker 管理的卷

docker run -it -v /home/ceshi:/home centos /bin/bash

6.4容器共享数据卷

--volumes-from 是 Docker 中用于在容器之间共享数据卷的命令参数,它允许一个容器复用用另一个容器中定义的卷(包括匿名名卷、具名卷或绑定挂载的目录),实现容器间的数据共享。

基本用法

docker run --volumes-from 源容器名称/ID 新容器镜像
  • 作用:新容器会继承 “源容器” 中所有的卷配置(包括挂载路径和数据)。
  • 特点
    • 无需手动指定卷名或路径,直接复用源容器的卷配置。
    • 源容器可以是运行中或已停止的(只要未被删除)。
    • 共享的是卷本身,数据会在所有复用该卷的容器间实时同步。

注意事项

  1. 源容器必须存在--volumes-from 依赖源容器的元数据(即使源容器已停止),如果源容器被删除,新容器会挂载失败。
  2. 卷的生命周期独立:复用卷的容器删除后,卷本身不会被删除(需用 docker volume rm 手动删除)。
  3. 避免多写冲突:多个容器共享卷时,若同时写入同一文件可能导致数据损坏(如 MySQL 等数据库不支持多实例同时写同一数据文件)。
  4. 权限问题:不同容器的用户 ID(UID)可能不同,可能导致文件权限冲突,需确保容器内用户对共享卷有正确的读写权限。

6.5实例:Mysql数据卷

# 创建具名卷
docker volume create mysql_data
docker volume create mysql_conf# 使用具名卷启动
docker run -d \-p 3307:3306 \-v mysql_conf:/etc/mysql/conf.d \-v mysql_data:/var/lib/mysql \-e MYSQL_ROOT_PASSWORD=123456 \--name mysql01 \mysql:5.7

现在使用了具名卷(mysql_confmysql_data 来持久化数据,即使删除了 mysql01 容器,重新创建新容器时只要挂载相同的卷,数据依然会保留。

如何实现多容器mysql数据共享

  docker run -d \-p 3308:3306 \-e MYSQL_ROOT_PASSWORD=123456 \--name mysql04 \mysql:5.7docker run -d -p 3309:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql05 --volumes-from mysql03 mysql:5.7

mysql04正常启动但没有03的数据,05无法启动,docker log mysql05会有错误日志。原因:MySQL 数据文件不支持多实例同时读写,使用 --volumes-from 共享数据卷时,必须确保源容器已停止。

那如何实现?

  1. 通过 MySQL 自身的 主从复制(Master-Slave) 机制,实现数据自动同步,多个容器各自拥有独立的数据文件,但数据保持一致。
    • 多容器独立运行,无文件锁冲突
    • 主库写入,从库可读,可分担查询压力
    • 数据自动同步,延迟低
  2. 如果是在云环境中,可直接使用 云数据库服务(如 RDS),多个 Docker 容器通过网络连接到同一个数据库实例,无需关心数据文件共享。

这里不再先说mysql的主从复制。

7,DockerFile

7.1概述

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。通过定义一系列命令和参数,Dockerfile 指导 Docker 构建一个自定义的镜像。

7.2编写规范&指令

  1. 注释格式

    使用 # 开头

  2. 指令大小写
    虽然 Docker 对指令大小写不敏感,但行业规范要求指令必须大写(如 FROMRUN),参数小写,便于区分指令和内容。

  3. 执行顺序与缓存
    Docker 构建镜像时会按指令顺序从上到下顺序执行,且会缓存每一层的结果。如果某层指令未修改,下次构建会直接使用缓存。因此:

    • 频繁变动的指令(如复制 COPY 应用代码)应放在文件末尾,减少缓存失效带来的构建时间增加。

    • 多个命令尽量合并为一个RUN(用&&连接),减少镜像层数:

      # 推荐:合并命令,清理缓存
      RUN yum update -y && \yum install -y gcc && \rm -rf /var/cache/yum/*
      
  4. 关键字(命令)大写字母

指令作用与细节常见误区
FROM指定基础镜像(如 FROM centos:7FROM scratch 构建空镜像)。必须是 Dockerfile 第一条指令;尽量使用官方精简镜像(如 alpine 版本)减小体积。
MAINTAINER标注维护者信息(已过时,推荐用 LABEL)。示例:LABEL maintainer="dev@example.com" version="1.0"
RUN构建时执行命令(如安装软件、配置环境)。避免单独使用 RUN yum update(无意义且增大镜像体积);及时清理缓存(如 apt clean)。
ADD复制文件到镜像,支持自动解压本地 tar 包和下载网络文件。不推荐用于下载网络文件(建议用 RUN wget 替代,更可控);避免解压不必要的文件。
COPY仅复制本地文件到镜像,功能更纯粹(推荐优先使用)。路径必须是构建上下文内的文件(不能用 ../ 访问外部文件)。
CMD容器启动时执行的命令(可被 docker run 后的命令覆盖)。一个 Dockerfile 中仅最后一个 CMD 生效;推荐使用数组格式:CMD ["nginx", "-g", "daemon off;"]
ENV设置环境变量(如 ENV JAVA_HOME /usr/local/jdk),容器运行时可继承。变量可在后续指令中引用:RUN echo $JAVA_HOME
EXPOSE声明容器对外暴露的端口(仅文档作用,不实际映射)。需配合 docker run -p 才能真正暴露端口;可声明多个端口:EXPOSE 80 443
VOLUME定义匿名卷(持久化数据),避免容器删除时数据丢失。运行时可通过 -v 覆盖为具名卷或绑定目录:docker run -v mydata:/data ...
WORKDIR设置后续指令的工作目录(类似 cd,但更推荐,避免 RUN cd 的临时生效)。可多次使用,路径相对于前一次的工作目录:WORKDIR /appWORKDIR config 最终为 /app/config

7.3构建自己的centos镜像

**核心流程:**编写 DockerFile → docker build 构建镜像 → docker run 运行容器 → docker push 发布镜像(到 DockerHub 或私有仓库)

因为centos镜像并没有vim指令,这里将vim指令加上去然后构建自己的镜像。

1,编写DockerFile

vim DockerFile
------------------编写---------------
FROM centos:7#维护者信息
LABEL maintainer="saber@123456@qq.com"#设置工作目录
ENV MYPATH /usr/local
WORKDIR &MYPATH# 更换yum源为阿里云(解决官方源失效问题)RUN rm -f /etc/yum.repos.d/*.repo && \curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo && \yum clean all && \yum makecache
# 安装vim编辑器
RUN yum install -y vim && \yum clean all#暴露端口
EXPOSE 80CMD ["/bin/bash"]

在 Dockerfile 的 CMD ["/bin/bash"] 中,中括号 [] 的作用,第一个元素是要执行的命令,后续元素是该命令的参数。例如:

CMD ["echo", "Hello Docker"]

2,构建镜像

# 在 Dockerfile 所在目录执行,-t 指定镜像名称和标签
# . :指定 Dockerfile 所在的路径为当前目录。
docker build -t my-centos:with-vim .
#-f指定文件名称
docker build -f dockerfile-test-cmd -t cmd-test:0.1 .

3,运行容器

docker run -it --name my-centos01 my-centos:with-vim

测试,使用vim指令成功。

7.4部署SpringBoot项目

基于docker原生方式 部署我们的springboot项目。

1,导入jar包

位置Dockerfile 所在目录nginx-cross-study-1.0-SNAPSHOT.jar

如果是Dockerfile 所在目录下的app/nginx-cross-study-1.0-SNAPSHOT.jar,那下面就改成app/nginx-cross-study-1.0-SNAPSHOT.jar就可以。

2,配置dockerFile(这里的名字是springboot-test)

# 基础镜像:使用官方JDK 8(推荐使用openjdk,体积更小)
FROM openjdk:8-jdk-alpine# 维护者信息
LABEL maintainer="saber"# 临时目录挂载(Spring Boot 内嵌Tomcat默认使用/tmp作为工作目录)
VOLUME /tmp# 将本地Jar包复制到容器中(重命名为app.jar,简化命令)
# 注意:Jar包路径需与Dockerfile相对应(若不在同一目录,需写相对路径)
COPY nginx-cross-study-1.0-SNAPSHOT.jar app.jar# 修复容器内随机数生成慢的问题(加速Spring Boot启动)
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar"]# 暴露项目端口(与Spring Boot配置的server.port一致,默认8080)
EXPOSE 8089

3,构建

docker build -f springboot-test -t springboot-test:nginx .

4,启动

docker run -p 8089:8089 -it --name springboot-test-nginx02 springboot-test:nginx

8,Docker网络

Docker 网络是 Docker 容器与外部世界(包括其他容器、主机、外部网络)通信的基础,它通过虚拟化技术为容器提供独立的网络环境,并支持多种网络模式以满足不同场景的需求。

8.1Docker0

docker0 是 Docker 在安装时自动创建的一个虚拟网桥(Bridge)设备,它是 Docker 容器默认网络模式(bridge 模式)下实现网络连接的关键组件。简而言之,docker0 主要作用是为容器提供与宿主机、容器与容器之间通信的基础网络能力

基础概念与原理

  • 虚拟网桥角色:从本质上来说,docker0 是一个基于 Linux 内核的虚拟网络设备,属于网桥类型。它类似于一个软件交换机,能够连接多个网络接口,在容器和宿主机之间,以及容器与容器之间转发数据包。当 Docker 创建一个容器时,会同时创建一对 veth-pair 接口(虚拟以太网对),其中一个接口放置在容器内作为 eth0(容器的网卡),另一个接口则连接到 docker0 网桥上,通过这种方式,容器就能够接入到 docker0 所构建的虚拟网络中。
  • IP 地址分配:docker0 默认会被分配一个本地未被占用的私有 IP 地址,例如常见的 172.17.42.1,子网掩码通常为 255.255.0.0 (对应网段为 172.17.0.0/16)。当容器以默认的 bridge 模式启动时,Docker 会从这个网段中为容器分配一个唯一的 IP 地址,从而使得容器之间、容器与宿主机之间能够基于 IP 进行通信。

什么是veth-pair?

它是 Linux 内核提供的一种虚拟网络设备技术,常用于在不同网络命名空间(Network Namespace)之间建立点对点的网络连接。

veth-pair 本质上是一对 “虚拟网卡”,它们像一根 “虚拟网线” 的两端。当创建一对 veth-pair 时,会生成两个虚拟网络接口(例如 veth0veth1)。其中一个接口发送的数据包,会被直接转发到另一个接口(反之亦然),就像物理网线连接的两个网卡。通常会将这两个接口分别放入不同的网络命名空间(如容器的网络命名空间和宿主机的命名空间),从而实现不同命名空间之间的网络互通。

veth-pair 是容器网络(如 Docker、Kubernetes)的核心技术之一,比如:

容器与宿主机的通信
Docker 容器默认运行在独立的网络命名空间中,通过 veth-pair 连接容器内的 eth0 接口和宿主机的虚拟接口(如 vethxxxx),并将宿主机侧的接口挂载到 docker0 网桥,使容器能与宿主机及其他容器通信。

示意图:

容器命名空间          宿主机命名空间
+------------+        +------------+
|  eth0      |<------>| vethxxxx   |
+------------+        +------------+|v+------------+| docker0 网桥 |+------------+

在这里插入图片描述

通信机制

  • 容器与容器通信:处于同一 docker0 网桥上的容器,它们在网络层面处于同一个广播域。只要容器之间的防火墙等安全策略允许,容器可以直接通过对方的 IP 地址进行通信。比如,容器 A 的 IP 是 172.17.0.2,容器 B 的 IP 是 172.17.0.3,容器 A 就可以使用 ping 172.17.0.3 等方式与容器 B 通信,docker0 网桥会根据 MAC 地址表来转发数据包。
  • 容器与宿主机通信:容器通过 veth-pair 连接到 docker0,docker0 再通过宿主机的物理网卡与外部网络通信。同时,宿主机可以通过 iptables 等工具进行端口映射,将宿主机的端口映射到容器的端口上,从而实现从宿主机访问容器内的服务。例如,使用 docker run -p 8080:80 nginx 命令,就将宿主机的 8080 端口映射到了容器内的 80 端口,此时在宿主机上访问localhost:8080就相当于访问容器内的 Nginx 服务。
$ docker exec -it 容器id$ ip addr
# 查看容器内部网络地址 发现容器启动的时候会得到一个 eth0@if551 ip地址,docker分配!
550: eth0@if551: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever# 思考? linux能不能ping通容器内部! 可以 容器内部可以ping通外界吗? 可以!
$ ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.069 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.074 ms

8.2通过名称通信

思考一个场景:我们编写了一个微服务,database url=ip: 项目不重启,数据ip换了,我们希望可以处理这个问题,可以通过名字来进行访问容器?

$ docker exec -it tomcat02 ping tomca01 # ping不通
ping: tomca01: Name or service not known
# 运行一个tomcat03 --link tomcat02
$ docker run -d -P --name tomcat03 --link tomcat02 tomcat
5f9331566980a9e92bc54681caaac14e9fc993f14ad13d98534026c08c0a9aef
# 用tomcat03 ping tomcat02 可以ping通
$ docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.115 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.080 ms
# 用tomcat02 ping tomcat03 ping不通

–-link 本质就是在hosts配置中添加映射,现在使用Docker已经不建议使用–link了!

–link劣势:

  • 但这种方式是单向的(tomcat03 能访问 tomcat02,反之不行)
  • 不支持动态更新,当被链接的容器 IP 变化时,链接方不会自动更新
  • 扩展性差,不适合多容器复杂网络环境

建议自定义网络,不适用docker0!docker0问题:不支持容器名连接访问!

8.3自定义网络

Docker 容器的网络连接基于 Linux 桥接技术,宿主机的 docker0 网桥是容器网络的核心枢纽,而 veth-pair 技术则像 “连接线” 一样,将每个容器接入到这个网桥上,从而实现了容器与宿主机、容器与容器之间的网络互通。这种设计保证了容器网络的隔离性与连通性的平衡。

所有容器不指定网络的情况下,默认docker路由,接着docker给容器分配ip。

网络模式

bridge :桥接 docker(默认,自己创建也是用bridge模式)

none :容器启动时不配置任何网络,没有网卡、IP、路由,仅保留lo(本地回环)接口,完全与网络隔离。

  • 极致隔离,容器内无法访问外部网络,外部也无法访问容器。
  • 仅能通过docker exec在容器内部操作,适合纯本地计算场景(如数据处理脚本,无需网络交互)。

host :和所主机共享网络。容器不创建独立网络命名空间,直接共享宿主机的网络栈(使用宿主机的 IP、端口、路由等)。容器内的服务端口直接占用宿主机端口,无需端口映射。

  • 网络性能最优(无网桥转发开销),但完全没有网络隔离(容器端口与宿主机端口冲突风险高)。
  • 容器内的localhost指向宿主机的localhost
  • 对网络性能要求极高的场景(如高频通信的服务)

container :容器联网模式(用得少!局限很大)新容器不创建独立网络命名空间,而是共享另一个已存在容器的网络栈(IP、端口、网卡等均与被共享容器一致)。两个容器通过lo接口直接通信,外部网络访问需通过被共享容器的端口映射。

# 我们直接启动的命令,会有一个默认参数 --net bridge,而这个就是docker0
# bridge就是docker0
$ docker run -d -P --name tomcat01 tomcat
等价于 => docker run -d -P --name tomcat01 --net bridge tomcat# docker0,特点:默认,域名不能访问。 --link可以打通连接,但是很麻烦!
# 我们可以 自定义一个网络
$ docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
docker network create \--driver bridge \          # 指定网络驱动类型为桥接模式--subnet 192.168.0.0/16 \  # 指定网络的子网网段--gateway 192.168.0.1 \    # 指定网络的网关地址mynet                      # 自定义网络的名称

如果不指定 --gateway,Docker 会自动分配一个网关 IP(通常是网段的第一个可用 IP,如 192.168.0.1),并非 “没有网关”。

#查看docker网络
docker network ls#查看自己创建的网络
docker network inspect mynet;--------------测试----------
[root@VM-8-4-centos ~]# docker run -d --name tomcat-net-01 --network mynet tomcat
9d71fc7db5c7abb118bffab1dbb170a574b59a4934daf879901989d2bd78e6e6
[root@VM-8-4-centos ~]# docker run -d --name tomcat-net-02 --network mynet tomcat
e77c412dd11aa1578a59860bf2f6032d0065d18b7baa77ebdf0af067d0862b61
[root@VM-8-4-centos ~]# docker network inspect mynet
[{"Name": "mynet","Id": "096589a184cc8eb875beb1a42a18fdd17d2591fd5a86e08c569d07e1cfe89ab8","Created": "2025-08-01T16:26:08.811562225+08:00","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": {},"Config": [{"Subnet": "192.168.0.0/24","Gateway": "192.168.0.1"}]},"Internal": false,"Attachable": false,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {"9d71fc7db5c7abb118bffab1dbb170a574b59a4934daf879901989d2bd78e6e6": {"Name": "tomcat-net-01","EndpointID": "f66e15c145d261441f1ac5c6e980050bb081f93e6ca78514072fa0e6a0585410","MacAddress": "02:42:c0:a8:00:02","IPv4Address": "192.168.0.2/24","IPv6Address": ""},"e77c412dd11aa1578a59860bf2f6032d0065d18b7baa77ebdf0af067d0862b61": {"Name": "tomcat-net-02","EndpointID": "44903cc353e977dbf4dbb590cc1c84a6e4f549e587359b7c0005c0bfc83f789e","MacAddress": "02:42:c0:a8:00:03","IPv4Address": "192.168.0.3/24","IPv6Address": ""}},"Options": {},"Labels": {}}
]
---------------tomcat镜像(尤其是官方精简版)默认没有安装ping命令-----------
#进入容器内部
#exec用于在运行中的容器内部执行指定命令。
docker exec -it tomcat-net-01 bash# 更新apt源(首次安装需要)
apt-get update# 安装ping工具
apt-get install -y iputils-ping# 在tomcat-net-01容器内ping tomcat-net-02
ping tomcat-net-02

在自定义的网络下,服务可以互相ping通,不用使用–link。自定义网络(如bridge驱动的网络)会自动维护一个 DNS 解析服务,同一网络内的容器无需配置,即可通过容器名(或--name指定的名称)直接通信。

我们自定义的网络docker当我们维护好了对应的关系,推荐我们平时这样使用网络!

好处:

redis -不同的集群使用不同的网络,保证集群是安全和健康的

mysql-不同的集群使用不同的网络,保证集群是安全和健康的

8.4跨网络通信

默认情况下,一个容器只能属于它启动时指定的网络(通过 --network 参数)。而 docker network connect 可以让容器额外加入其他网络,实现:

  • 同一个容器与多个网络中的服务通信
  • 跨网络的容器间互联互通(突破默认的网络隔离)

基础用法

docker network connect [网络名/网络ID] [容器名/容器ID]
docker network disconnect [网络名/网络ID] [容器名/容器ID]

9,Compose

9.1Compose的安装

安装Docker Compose

github太慢了,该指令源自38-docker compose 是什么以及如何安装_哔哩哔哩_bilibili

curl -SL https://bmshare.oss-cn-beijing.aliyuncs.com/docker/docker-compose/v2.29.2/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose

docker-compose 文件添加可执行权限

chmod +x /usr/local/bin/docker-compose

检测是否安装成功,如果输出版本信息证明安装成功。

docekr-compose -v

9.2docker-compose.yml

docker-compose.yml 是用于定义和运行多容器 Docker 应用的配置文件,其语法基于 YAML,核心是通过 servicesnetworksvolumes 等关键字定义应用的各个组件。

# 可选:指定 Compose 文件版本(v2/v3 是主流,v3.8 是较新稳定版)
# 注意:最新 Docker 版本已淡化版本差异,可省略
version: '3.8'# 定义所有服务(容器)
services:服务1名称:# 服务1的配置...服务2名称:# 服务2的配置...# 定义网络(可选,用于服务间通信)
networks:网络名称:# 网络配置...# 定义数据卷(可选,用于数据持久化)
volumes:卷名称:# 卷配置...

每个服务对应一个容器,常用配置如下:

1. 镜像相关

services:app:image: nginx:alpine  # 直接使用现有镜像(名称:标签)# 或通过 Dockerfile 构建镜像(二选一)build:context: ./app     # Dockerfile 所在目录dockerfile: Dockerfile  # 自定义 Dockerfile 文件名(默认 Dockerfile)args:              # 构建时参数(对应 Dockerfile 中的 ARG)- ENV=production

2. 容器配置

services:app:container_name: my-app  # 自定义容器名称(默认:项目名_服务名_序号)restart: always         # 重启策略:always(总是)、on-failure(失败时)、no(默认)command: ["nginx", "-g", "daemon off;"]  # 覆盖容器启动命令entrypoint: /app/start.sh  # 覆盖容器入口点

3. 网络配置

services:app:networks:- my-network  # 加入自定义网络(需在 networks 中定义)ports:- "8080:80"   # 端口映射:宿主机端口:容器内端口(格式:[宿主机IP:]宿主机端口:容器端口)- "9000-9002:9000-9002"  # 端口范围映射expose:- 8080  # 暴露容器端口(仅允许内部网络访问,不映射到宿主机)

4. 环境变量

services:app:environment:  # 直接指定环境变量(键值对)- DB_HOST=mysql- DB_PORT=3306env_file:     # 从文件加载环境变量(每行格式:KEY=VALUE)- .env      # 相对路径或绝对路径

5. 数据持久化(卷挂载)

services:app:volumes:- ./data:/app/data  # 绑定挂载:宿主机目录:容器内目录(双向同步)- my-volume:/app/logs  # 命名卷:使用 volumes 中定义的卷(数据持久化)- /app/temp  # 匿名卷:仅容器内使用,容器删除后数据丢失

9.3部署若依项目

(1)Linux目录

shuangchauang/
├── docker-compose.yml       # 容器编排主配置
├── backend/                 # 后端服务
│   ├── Dockerfile           # 后端镜像构建文件
│   └── xxx.jar       # Spring Boot 打包的 JAR
├── frontend/                # 前端服务
│   ├── Dockerfile           # 前端镜像构建文件
│   └── dist/                # 前端打包好的静态文件(Vue/React 等)
├── nginx/                   # Nginx 配置
│   ├── Dockerfile           # Nginx 镜像构建文件
│   └── nginx.conf           # Nginx 反向代理配置
├── mysql/                   # MySQL 配置
│   └── init.sql             # 数据库初始化脚本
└── redis/                   # Redis 自定义配置└── redis.conf           # Redis 自定义配置文件怎么改变

(2)相关命令

--------------防火墙相关-------
# 临时开放80端口(重启防火墙后失效)
sudo firewall-cmd --zone=public --add-port=80/tcp# 永久开放80端口(需要重新加载规则)
sudo firewall-cmd --zone=public --add-port=80/tcp --permanent# 重新加载防火墙规则,使设置生效
sudo firewall-cmd --reload# 验证是否已开放
sudo firewall-cmd --zone=public --list-ports | grep 80#查看相应端口占用情况
sudo netstat -tulpn | egrep '80|3306|6379|8079'
----------docker-compose相关-----------
#停止并删除所有通过当前docker-compose.yml启动的容器、网络,同时保留数据卷
docker-compose down#第一次启动,构建并启动
docker-compose up -d# 重新构建并启动
docker-compose up -d --build#检查容器状态
docker-compose ps#eg:打印后端日志
docker-compose logs backend#只启动mysql服务
docker-compose up -d mysql
docker-compose down mysql

(3)配置文件

解析

后端的application.yml连接的数据库ip地址换成mysql和redis.

不需要配置ip的原因:Docker的容器间通信(在docker-compose.yml中也不需要配置端口映射)

# redis 配置
redis:# 地址# 地址:使用 Docker 网络中的 Redis 服务名host: redis# 端口,默认为6379port: 6379# 数据库索引database: 0# 密码password:# 连接超时时间timeout: 10s
----------------------------
url: jdbc:mysql://mysql:3306/subsystem useUnicode=true&charac..........username: rootpassword: 220314

流程

  1. 请求进入宿主机
    外部请求(如 http://49.232.7.34:8090)首先到达宿主机的 8090 端口,该端口通过 docker-compose.yml 中 Nginx 服务的 ports: "8090:8090" 映射到 Nginx 容器的 8090 端口。
  2. Docker 端口转发
    Docker 守护进程(docker daemon)负责端口映射,将宿主机 8090 端口的请求转发到 Nginx 容器内部的 8090 端口。
  3. Nginx 处理请求
    • 若请求是静态资源(如 index.htmlcssjs),Nginx 直接从容器内的前端静态目录(如 /usr/share/nginx/html)返回文件。
    • 若请求是 API 接口(如 /prod-api/user/list),Nginx 通过配置 proxy_pass http://backend:8079/ 将请求转发到后端容器。
  4. 后端容器处理业务
    后端容器(scweb-backend)接收到请求后:
    • 通过 jdbc:mysql://mysql:3306/... 连接 MySQL 容器(scweb-mysql)读写数据。
    • 通过 spring.redis.host=redis 连接 Redis 容器(scweb-redis)操作缓存。
  5. 响应返回
    后端处理结果经 Nginx 反向代理返回给外部客户端,完成一次请求。

在这里插入图片描述

原配置

frontend 服务本质是前端打包环境(通过 Dockerfile 构建 dist 目录),但最终前端静态文件是通过 Nginx 容器直接提供服务的:

  • 目前前端 dist 目录的文件是通过挂载到 nginx 容器的(/usr/share/nginx/html),frontend 容器本身并不参与请求处理。
  • frontend 容器启动后,既没有暴露端口,也没有被其他服务依赖,属于 “闲置容器”,不影响整体架构运行。

故可以删除相关配置。后者一个一个的启动,留下frontend,正常运行。

docker-compsoe.yml

services:# 后端服务(Spring Boot)backend:build: ./backendcontainer_name: scweb-backendrestart: alwaysenvironment:# 后端连接MySQL和Redis的配置(需与后端application.yml一致)SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/subsystem?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8SPRING_DATASOURCE_USERNAME: rootSPRING_DATASOURCE_PASSWORD: 220314SPRING_REDIS_HOST: redisSPRING_REDIS_PORT: 6379SPRING_REDIS_PASSWORD:  # 与Redis配置的密码一致depends_on:- mysql- redisnetworks:- scweb-network# 前端服务(Nginx托管静态静态文件)frontend:build: ./frontendcontainer_name: scweb-frontendrestart: alwaysdepends_on:- backendnetworks:- scweb-network# Nginx反向代理(处理前端请求和API转发)nginx:build: ./nginxcontainer_name: scweb-nginxrestart: alwaysports:- "8090:8090"  # 对外暴露80端口depends_on:- frontend- backendnetworks:- scweb-network# 新增:挂载前端 dist 目录到容器内的 Nginx 静态目录volumes:- ./frontend/dist:/usr/share/nginx/html  # 宿主机 dist 目录映射到容器内目录# MySQL数据库mysql:image: mysql:8.0container_name: scweb-mysqlrestart: alwaysenvironment:MYSQL_ROOT_PASSWORD: 220314MYSQL_DATABASE: subsystemMYSQL_PASSWORD: 220314volumes:- ./mysql/subsystem.sql:/docker-entrypoint-initdb.d/init.sql- mysql-data:/var/lib/mysqlnetworks:- scweb-networkports:- "3306:3306" command: --default-authentication-plugin=mysql_native_password# Redis缓存(带自定义配置)redis:image: redis:6.2-alpinecontainer_name: scweb-redisrestart: alwaysvolumes:- ./redis/redis.conf:/usr/local/etc/redis/redis.conf  # 挂载自定义配置- redis-data:/data  # 数据持久化command: redis-server /usr/local/etc/redis/redis.conf  # 使用自定义配置启动networks:- scweb-network# 添加端口映射:宿主机端口:容器端口ports:- "6379:6379"# 数据卷(持久化数据)
volumes:mysql-data:redis-data:# 自定义网络(服务间通信)
networks:scweb-network:driver: bridge

backend–Dockerfile

FROM nginx:alpine
# 替换Nginx默认配置为自定义配置
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 8090

frontend–Dockerfile

FROM nginx:alpine
# 将前端打包的dist目录复制到Nginx默认静态文件目录
COPY dist/ /usr/share/nginx/html/
# 暴露80端口(内部端口,通过nginx服务转发)
EXPOSE 80

nginx–Dockerfile

FROM nginx:alpine
# 替换Nginx默认配置为自定义配置
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 8090

nginx.conf

server {listen 8090;server_name xx.xxx.x.xx;  # 替换为你的服务器公网IP或域名# 双创项目前端 - 主配置location / {root   /usr/share/nginx/html;index  index.html;try_files $uri $uri/ /index.html;}# 双创项目后端API代理location /prod-api/ {proxy_pass http://backend:8079/;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}
}
http://www.lryc.cn/news/607092.html

相关文章:

  • cocosCreator2.4 googlePlay登录升级、API 35、16KB内存页面的支持
  • 特征工程 --- 特征提取
  • (一)LoRA微调BERT:为何在单分类任务中表现优异,而在多分类任务中效果不佳?
  • 【C++】类和对象 上
  • 逻辑回归算法中的一些问题
  • Leetcode——53. 最大子数组和
  • elementui中rules的validator 用法
  • 在线教程丨全球首个 MoE 视频生成模型!阿里 Wan2.2 开源,消费级显卡也能跑出电影级 AI 视频
  • Windows11 WSL安装Ubntu22.04,交叉编译C语言应用程序
  • 网站建设服务器从入门到上手
  • 《n8n基础教学》第一节:如何使用编辑器UI界面
  • 如何优雅删除Docker镜像和容器(保姆级别)
  • 服务器地域选择指南:深度分析北京/上海/广州节点对网站速度的影响
  • FreeSWITCH与Java交互实战:从EslEvent解析到Spring Boot生态整合的全指南
  • 分布式弹幕系统设计
  • Git 误删分支怎么恢复
  • ABP VNext + Dapr Workflows:轻量级分布式工作流
  • stl的MATLAB读取与显示
  • Blender 4.5 安装指南:快速配置中文版,适用于Win/mac/Linux系统
  • 【Mysql】字段隐式转换对where条件和join关联条件的影响
  • 安全专家发现利用多层跳转技术窃取Microsoft 365登录凭证的新型钓鱼攻击
  • 基于Pipeline架构的光存储读取程序 Qt版本
  • 九、Maven入门学习记录
  • 学习游戏制作记录(各种水晶能力以及多晶体)8.1
  • k8s之NDS解析到Ingress服务暴露
  • Wisdom SSH开启高效管理服务器的大门
  • Git之远程仓库
  • 【全网首个公开VMware vCenter 靶场环境】 Vulntarget-o 正式上线
  • Linux(15)——进程间通信
  • VMware 下 Ubuntu 操作系统下载与安装指南