Docker

yin_bo_ Lv2

1. 初识Docker

  • Docker是一个快速交付应用、运行应用的技术,具备以下优势
    • 可将程序及其依赖、运行环境一起打包为一个镜像,可以迁移到任意Linux操作系统
    • 运行时利用沙箱机制形成隔离容器,各个应用互不干扰
    • 启动、移除都可以通过一行命令完成,方便快捷

1.1分布式项目遇到的问题

  • 微服务虽然有各种各样的优势,但是服务的拆分通常给部署带来很大的麻烦
    • 分布式系统中,依赖的组件非常多,不同组件之间部署往往会产生一些冲突
    • 在成百上千台服务器中重复部署,环境会不一致,依赖关系复杂,会导致兼容性问题,并且开发,测试,生产的环境也有差异
    • 如果项目部署依赖node.js,Redis,RocketMQ,MYSQL等,这些服务部署时用到的函数库,依赖各不相同。
      alt 分布式系统错综复杂
      alt 分布式系统错综复杂

1.2 Docker解决依赖兼容等问题

  • Docker解决了依赖兼容的问题,是如何实现的呢?
    • Docker为了解决依赖的兼容问题,采用了两个手段
      1. 将应用的函数库(Libs),依赖(Deps),配置与应用一起打包
      2. 将每个应用都放到一个隔离容器里运行,避免相互干扰
        alt Docker的解决方法
        alt Docker的解决方法

1.3 Docker解决系统环境差异等问题

  • 虽然解决了不同应用的兼容问题,但是开发,测试等环节也会存在差异,操作系统版本也会有差异

  • 例如:如果有一个Ubuntu版本的MySQL安装到CentOS系统,MySQL在调用Ubuntu函数时会找不到

  • 要解决不同操作系统差异问题,要先了解操作系统结构,以一个Ubuntu操作系统为例,结构如下

    • 系统应用:操作系统本身提供的应用,函数库这些数据是对内核指令的封装,使用更加方便
    • 系统内核:所有Linux发行版的内核都是linux,例如CentOS,UbuntuFedira等。内核可以与计算机硬件交互,对外提供内核指令用于操作计算机硬件
    • 计算机硬件:cpu,内存,磁盘等
  • Docker的解决方法

    • Docker将用户程序所需要的系统(比如Ubuntu)函数库一起打包
    • Docker运行到不同操作系统时,直接基于打包的函数库,借助于操作系统的Linux内核来运行

1.4 Docker和虚拟机的区别

  • Docker可以让一个应用在任何操作系统都能十分方便的运行,而我们之前接触的虚拟机,也能在一个操作系统中运行另外一个操作系统
  • 两者的差异:
    • 虚拟机VM(Virtual machine)时操作系统中模拟硬件设备,然后运行另一个操作系统。
    • 而Docker只是封装函数库,并没有模拟完整的操作系统
      alt Docker和虚拟机的区别
      alt Docker和虚拟机的区别

2. Docker架构

  • 我们要使用Docker来操作镜像、容器,那就必须安装Docker
  • Docker是一个CS架构的程序,由两部分组成
    1. 服务端(server):Docker守护进程,负责处理Docker指令,管理镜像、容器等
    2. 客户端(client):通过命令或RestAPI向Docker服务端发送指令,可以在本地或远程向服务端发送指令
      alt Docker工作原理图
      alt Docker工作原理图

2.1 镜像与容器

  • Docker中有两个重要的概念:

    1. 镜像(Image):Docker将应用程序以及其所需依赖,函数库,环境,配置配置**打包在一起,称为镜像。
    2. 容器(Controller):镜像中应用程序形成后的进程就是容器,Docker会给容器进程做隔离,对外不可见。
  • 一切应用最终都是代码组成,都是硬盘中一个个字节形成的文件,只有运行时才会加载到内存形成进程

    • 镜像就是把一个应用在硬盘上的文件,机器运行环境,部分系统函数库文件一起打包的文件包,这个文件包时只读的(防止对镜像文件进行修改或污染,从而导致镜像不可用,容器从镜像中拷贝一份文件到自己的空间来写数据)
    • 容器就是把这些文件编写的程序,函数等加载到内存中形成进程,不过要隔离起来,因此一个镜像可以启动多次,形成多个容器进程
      alt Docker的架构图
      alt Docker的架构图

2.2 DockerHub

  • 开源应用程序非常多,打包这些应用往往是重复性劳动,为了避免这些重复劳动,人们就会将自己打包的应用镜像,例如Redis,MySQL镜像放在网络上来共享。
    • DockerHub:官方的Docker镜像托管平台。
    • 国内也有类似于DockerHub的公开服务,例如网易云镜像服务阿里云镜像服务
  • 我们一方面可以将自己的镜像共享到DockerHub,另一方面也可以从DockerHub拉取镜像

3. 安装Docker

  • Docker分为CE(社区版)和EE(企业版)两个版本,我们准备使用免费的社区版

  • Docker分为stabletestnightly三个频道

  • 我们这里使用的操作系统版本号为Ubuntu 24.04 LTS LTS(Long-Term Support)是长期支持版本的意思

  • 查询官方Docs关于安装Ubuntu版本的教程 https://docs.docker.com/engine/install/ubuntu/

  1. 如果之前有安装过Docker,先卸载所有冲突的软件包

    1
    sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc | cut -f1)
  2. 更新系统软件并且设置Dockerapt仓库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # Add Docker's official GPG key:
    sudo apt update
    sudo apt install ca-certificates curl
    sudo install -m 0755 -d /etc/apt/keyrings
    sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
    sudo chmod a+r /etc/apt/keyrings/docker.asc

    # Add the repository to Apt sources:
    sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
    Types: deb
    URIs: https://download.docker.com/linux/ubuntu
    Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
    Components: stable
    Signed-By: /etc/apt/keyrings/docker.asc
    EOF
    sudo apt update
  3. 安装Docker软件包

    1
    sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  4. 启动Docker

    • 安装完成后,Docker服务会自动启动,可以使用下面的命令来验证是否正在运行
    1
    sudo systemctl status docker
    • 查看Docker版本
    1
    sudo docker version

超时问题以及更改镜像源

我们安装Docker之后运行sudo docker run hello-world发现超时了。
原因就是没有更改国内的镜像源,导致下载不了
这里需要我们创建一个daemon,用来导入国内的镜像

  1. 创建并且编辑daemon.json
    • 如果没有nano编辑器就去下载一个
    1
    2
    sudo mkdie -p /etc/docker
    sudo nano /etc/docker/daemon.json
  2. 把下面这段复制进去
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    {
    "registry-mirrors": [
    "https://do.nark.eu.org",
    "https://dc.j8.work",
    "https://docker.m.daocloud.io",
    "https://dockerproxy.com",
    "https://docker.mirrors.ustc.edu.cn",
    "https://docker.nju.edu.cn"
    ]
    }
  3. 保存并退出(ctrl+o保存,然后回车之后ctrl+x),然后重启Docker服务
    1
    2
    sudo systemctl daemon-reload
    sudo systemctl restart docker
  1. 运行sudo docker run hello-world
    • 这段代码是启动一个容器去运行hello-world镜像,如果你本地没有就去DockerHub拉取一个
    • 运行完会显示Hello from Docker!
    • 至此Docker安装成功🌸

4. Docker基本操作

4.1 镜像操作

  1. 镜像名称
  • 镜像的名称组成[repository]:[tag]
  • 例如mysql:5.7 代表5.7版本的MySQL镜像
  • 在没有指定tag时,默认是latest,代表最新版本的镜像,例如mysql就是mysql:latest
  1. 镜像相关命令
    • 常见的镜像命令如下图
      alt Docker镜像命令
      alt Docker镜像命令

4.1.1 案例一

  • 这个案例里,我们练习拉取和查看镜像

    需求:从DockerHub拉取一个Nginx镜像并查看

  1. 通过命令docker pull nginx来拉取最新的nginx镜像
  2. 通过命令docker images查看拉取的镜像
    1
    2
    3
    IMAGE                ID             DISK USAGE   CONTENT SIZE   EXTRA
    hello-world:latest f7931603f70e 20.3kB 3.96kB U
    nginx:latest 553f64aecdc3 225MB 59.8MB

4.1.2 案例二

  • 这个案例中,我们练习保存和导入镜像

  • 需求:利用docker save将nginx导出磁盘,然后通过docker load加载回来

  • 保存镜像成压缩包语法docker save -o[保存的目标文件名称][镜像名称]

  • 将压缩包导入镜像语法docker load -i[镜像压缩文件名]

  1. 将镜像导出到磁盘,然后用ls命令就可以看到nginx.tar文件

    1
    sudo docker save -o nginx.tar nginx
  2. 使用docker load加载镜像,在此之前,我们使用命令删除本地nginx镜像

    1
    docker rmi nginx # rmi为 remove image的缩写

    然后使用load加载镜像

    1
    docker load -i nginx.tar

4.2 容器操作

  1. 容器相关命令
    • 操作命令如图
      alt Docker容器命令
      alt Docker容器命令
  • 容器包括三个状态
    • 运行:进程正常运行
    • 暂停:进程暂停,CPU不再运行,但是不释放内存
    • 停止:进程终止,回收进程占用的内存,CPU等资源

暂停和停止的处理方式的区别

  • 暂停是操作系统将容器内的进程挂起,容器关联的内存暂存起来,CPU不再执行这个程序,使用unpause命令恢复,内存空间被恢复,程序继续运行。
  • 停止是直接将进程杀死,容器占的内存被回收,保存静态资源。
    docker rm是将文件系统也彻底删除,也就是将容器彻底删除
  • docker ps:查看容器
  • docker ps -a查看所有容器,包括已停止的
  • docker run:创建并运行一个容器,处于运行状态
  • docker pause:暂停一个运行的容器
  • docker unpause:运行一个暂停的容器
  • docker stop:停止一个运行的容器
  • docker start:运行一个停止的容器
  • docker rm:删除一个容器

4.2.1 案例一

  • 需求:创建并运行nginx容器,然后查看

  • 创建并运行容器的语法docker run --name [容器名] -p [宿主机端口]:[容器端口] -d [镜像名称]

  • 创建并运行nginx容器

    1
    docker run --name myNginx -p 80:80 -d nginx
  • 这里的-p参数,是将容器端口映射到宿主机端口

  • 因为我们这里用的是WSL,所以宿主机端口也是在本地IP里

  • 访问localhost:80即可看到nginx默认页面

4.2.2 案例二

  • 需求:进入Nginx容器,修改HTML文件内容,添加God Drinks Java
  • 提示:进入容器要用到docker exec命令
  1. 进入我们刚刚创建好的Nginx容器

    1
    docker exec -it myNginx bash
    • 命令解读:
      • -it:给当前进入的容器创建一个标准输入输出终端,允许我们与容器交互
      • bash:进入容器后执行的命令,Bash是Linux终端交互命令,Windows的是PowerShell
  2. 进入nginx的HTML所在目录

    • 容器内部会模拟一个独立的Linux系统文件,看起来就如同一个Linux服务器一样,Nginx的环境,配置,运行文件全都在这个文件系统中,包括我们要修改的HTML文件
    • 查看DockerHub网站中的Nginx网页,可以知道Nginx的HTML目录位置在/usr/share/nginx/html
    • 我们执行下面的命令进去这个目录
    1
    cd /usr/share/nginx/html
    • 输入ls查看该目录下的文件
    1
    2
    root@0a4b3ad8e316:/usr/share/nginx/html# ls
    50x.html index.html
  3. 修改index.html的内容

    • 容器内没有vi命令,无法直接修改,我们使用下面的命令来修改
    1
    sed -i -e 's#Welcome to nginx!#God Drinks Java#g' index.html
    • 然后访问localhost:80或者localhost就会发现已经修改了

现在是不是感觉修改文件好麻烦,因为没给提供vi命令,不能直接编辑,所以这就要用到我们下面说的数据卷了

4.3 数据卷

  • 在之前的Nginx案例中,修改Nginx的HTML页面需要进入到Nginx内部。

  • 并且也没有编译器,修改文件很麻烦,这就是容器与数据(容器内文件)耦合带来的效果

  • 如果我们另外运行一台新的Nginx容器,那么这台新的Nginx容器也不能直接使用我们改好的HTML文件,具有很多缺点

    1. 不便于修改:当我们要修改Nginx的HTML内容时,要进入容器内部修改,很不方便
    2. 数据不可复用:由于容器内的修改对外不可见,所有的修改对新建的容器也是不可服用的。
    3. 升级维护困难:数据在容器内,如果要升级容器必然删除旧容器,那么旧容器中所有数据也跟着被删除了(包括改好的HTML文件)。
  • 要解决这个问题,必须将数据和容器解耦,这就用到了数据卷

  • 什么是数据卷

    • 数据卷(volume)是一个虚拟目录,指向宿主机文件系统的某个目录
      alt 数据卷分析
      alt 数据卷分析
    • 一旦完成数据卷挂载,对容器的一切操作都会对应的宿主机目录。
    • 这样我们宿主机的/var/lib/docker/volumes/html目录就等同于容器内的/usr/share/nginx/html
    • 数据卷的作用:将容器和数据分离,解耦合,方便操作容器内数据,保证数据安全

4.3.1 数据卷操作命令

  • 数据卷操作的基本语法如图下
    1
    docker volume [COMMAND]
    • 其中有以下的命令
    • create:创建一个volume
    • inspect:显示一个或多个volume的信息
    • ls:列出来所有的volume
    • prune:删除未使用的volume
    • rm:删除一个或多个指定的volume

4.3.2 创建和查看数据集

需求:创建一个数据卷,并查看数据卷在宿主机的目录位置

  1. 创建数据卷
    1
    docker volume create html
  2. 查看所有数据卷
    1
    docker volume ls
  3. 查看数据卷的详细信息
    1
    docker volume inspect html
    • 可以看到我们创建的html这个数据卷关联的宿主机目录(MountPoint)为/var/lib/docker/volumes/html/_data

4.3.3 挂载数据卷

  • 我们在创建容器时,可以通过-v参数来挂载一个数据卷到某个容器内目录,命令格式如下:
    1
    2
    3
    4
    5
    docker run \
    --name myNginx \
    -v html:/root/html \
    -p 80:80 \
    nginx \
    • 这里的-v就是挂载数据卷的地方
    • -v html:/root/html:把html数据卷挂载到容器内的/root/html这个目录下

4.3.4 案例一

需求:创建一个nginx容器,修改容器内的HTML目录的index.html内容
分析:我们已经知道了nginx的html目录所在位置是/usr/share/nginx/html,我们需要把这个目录挂载到html这个数据卷上

  1. 创建容器并挂载数据卷到容器内的HTML目录

    • 首先删除我们之前创建的容器和数据卷
    1
    docker run --name myNginx -v html:/usr/share/nginx/html -p 80:80 -d nginx
  2. 进入html数据卷所在位置,并且修改HTML内容

    1
    2
    3
    4
    # 查看数据卷位置
    docker volume inspect html
    # 修改文件
    nano /var/lib/docker/volumes/html/_data/index.html

4.3.5 案例二

  • 容器不仅仅可以挂载数据卷,也可以直接挂载到宿主机目录上,关系如下:

    • 数据卷挂载模式:宿主机目录–>数据卷–>容器内目录
    • 直接挂载模式:宿主机目录–>容器内目录
      alt 直接挂载分析
      alt 直接挂载分析
  • 目录挂载和数据卷挂载的语法是类似的

    • -v [宿主机目录]:[容器内目录]
    • -v [宿主机文件]:[容器内文件]

需求:创建并运行一个MySQL容器,将宿主机目录直接挂载到容器

  1. 拉取一个MySQL镜像

    1
    docker pull mysql
  2. 创建目录/tmp/mysql/data

    1
    mkdir -p /tmp/mysql/data
  3. 按照上面指令再创建/tmp/mysql/conf,将myCnf.cnf文件上传到这里

    1
    2
    3
    4
    5
    [mysqld]
    skip-name-resolve
    character_set_server=utf8
    datadir=/var/lib/mysql
    server-id=1000
  4. 去DockerHub查询资料,找到mysql容器的conf目录和data目录的位置

    • conf目录:/etc/mysql/conf.d
    • data目录:/var/lib/mysql
  5. 创建并运行MySQL容器,要求:

    • 挂载/tmp/mysql/data到mysql容器内数据存储目录
    • 挂载/tmp/mysql/conf/myCnf.cnf到mysql容器的配置文件
    • 设置mysql密码
    • 注意因为是WSL,所以主机的3306被占用了 这里我们使用3300来挂载容器的3306
    1
    2
    3
    4
    5
    6
    7
    8
    docker run \
    --name mysql \
    -e MYSQL_ROOT_PASSWORD=密码 \
    -v /tmp/mysql/conf:/etc/mysql/conf.d \
    -v /tmp/mysql/data:/var/lib/mysql \
    -p 3300:3306 \
    -d \
    mysql:8.0
  6. 使用IDEA或者DataGrip连接3030接口的数据库

5. Dockerfile自定义镜像

  • 常见的镜像在DockerHub就能找到,但是我们自己写的项目就必须自己构建镜像了,而要自定义镜像,则必须先连接镜像的结构才行

5.1 镜像结构

  • 镜像是将应用程序以及其所需要的系统函数库,环境,配置,依赖打包而成的
  • 以MySQL为例,看看他的镜像组成
    alt MySQL镜像结构
    alt MySQL镜像结构
  • 简单来说,镜像就是在系统函数库,运行环境的基础上,添加应用程序文件,配置文件,依赖文件等组合,然后编写好启动脚本打包在一起形成的文件
  • 我们要构建镜像,其实就是实现上述打包过程

5.2 Dockerfile语法

  • 构建自定义镜像时,并不需要一个个文件去拷贝,打包
  • 我们只需要告诉Docker我们的镜像组成,需要哪些BaseImage,需要拷贝什么文件,需要安装什么依赖,启动脚本是什么,Docker会帮助我们构建镜像
  • 而描述上述信息的就是Dockerfile文件
  • Dockerfile就是一个文本文件,其中包括一个个指令(Instruction),用指令说明要执行什么操作来构建镜像,每一个指令都会形成一层Layer
    指令 说明 示例
    FROM 指定基础镜像 FROM centos:6
    ENV 设置环境变量,可在后面指令使用 ENV key value
    COPY 拷贝本地文件到镜像的指定目录 COPY ./mysql-5.7.rpm /tmp
    RUN 执行Linux的shell命令,一般是安装过程的命令 RUN yum install gcc
    EXPOSE 指定容器运行时监听的端口,是给镜像使用者看的 EXPOSE 8080
    ENTRYPOINT 镜像中应用的启动命令,容器运行时调用 ENTRYPOINTjava -jar xxjar

5.3 构建Java项目

5.3.1 基于Ubuntu构建Java项目

需求:基于Ubuntu镜像构建一个新镜像,运行一个Java项目

  1. 创建一个空文件夹docker-demo

    1
    mkdir /tmp/docker-demo
  2. docker-demo.jar文件拷贝到docker-demo这个目录

  3. 拷贝jdk8.tar.gz文件到docker-demo这个目录

  4. 在docker-demo目录下新建Dockerfile,并写入以下内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    # 指定基础镜像
    FROM ubuntu:16.04
    # 配置环境变量,JDK的安装目录
    ENV JAVA_DIR=/usr/local

    # 拷贝jdk和java项目的包
    COPY ./jdk8.tar.gz $JAVA_DIR/
    COPY ./docker-demo.jar /tmp/app.jar

    # 安装JDK
    RUN cd $JAVA_DIR \
    && tar -xf ./jdk8.tar.gz \
    && mv ./jdk1.8.0_144 ./java8

    # 配置环境变量
    ENV JAVA_HOME=$JAVA_DIR/java8
    ENV PATH=$PATH:$JAVA_HOME/bin

    # 暴露端口
    EXPOSE 8090
    # 入口,java项目的启动命令
    ENTRYPOINT java -jar /tmp/app.jar
  5. 在docker-demo目录下使用docker build命令构建镜像

    • 注意最后有一个空格+一个. 这个.代表dockerfile构建的目录
    1
    docker build -t docker_demo:1.0 .
  6. 使用docker images命令 可以看到我们的镜像

    1
    docker_demo:1.0      e556ad421144       1.18GB          441MB
  7. 创建并运行一个docker_demo容器

    1
    docker run --name testDemo -p 8090:8090 -d docker_demo:1.0
  8. 浏览器访问localhost:8090/hello/count,可以查到页面效果

    alt 页面效果
    alt 页面效果

5.3.2 基于Java8构建项目

  • 虽然我们可以基于Ubuntu基础镜像,添加任意自己需要的安装包来构建镜像,但是比较麻烦,所以大多数情况下我们都可以在一些安装了部分软件的基础镜像上改造
  • 我们刚刚构建的Java项目有一个固定的死步骤,那就是安装JDK并配置环境变量,我们每次构建Java项目的镜像都需要这个步骤,所以我们可以找到一个已经安装好了JDK的基础镜像,然后在其基础上构建我们的Java项目的镜像

    需求:基于java:8-alpine镜像,将一个Java项目构建为镜像

  1. 使用/tmp/docker-demo目录,修改Dockerfile
    1
    2
    3
    4
    5
    6
    7
    8
    ## 将openjdk:8作为基础镜像
    FROM openjdk:8
    ## 拷贝java项目的包到指定目录下,我这里是/tmp/app.jar
    COPY ./docker-demo.jar /tmp/app.jar
    ## 暴露端口
    EXPOSE 8090
    ## 入口
    ENTRYPOINT java -jar /tmp/app.jar
  2. 构建镜像
    1
    docker build -t docker_demo:2.0 .

6. Docker-Compose

  • Docker Compose可以基于Compose文件帮我们快速的部署分布式应用,无需手动一个个创建和运行容器

6.1 初识DockerCompose

  • Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行,格式如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
      version: "3.8"
    services:
    ## docker run --name mysql -e MYSQL_ROOT_PASSWORD=root -p 3306:3306 -v /tmp/mysql/data:/var/lib/mysql -v /tmp/mysql/conf/myCnf.cf:/etc/mysql/conf.d/myCnf.cnf -d mysql:5.7.25
    mysql: ## 对应docker run中的 --name
    image: mysql:5.7.25 ## 对应docker run中最后声明的镜像
    enviroment: ## 对应docker run中的 -e MYSQL_ROOT_PASSWIRD=root
    MYSQL_ROOT_PASSWORD: root
    volumes: ## 对应docker run中的 -v /tmp/mysql/data:/var/lib/mysql
    - "/tmp/mysql/data:/var/lib/mysql"
    - "/tmp/mysql/conf/myCnf.cf:/etc/mysql/conf.d/myCnf.cnf"
    ## 这里并不需要-d参数来后台运行,因为此种方法默认就是后台运行
    ## 同时也不需要暴露端口,在微服务集群部署中,MySQL仅仅是供给给集群内的服务使用的,所以不需要对外暴露端口

    ## 临时构建镜像并运行,下面的配置文件包含了docker build和docker run两个步骤
    ## docker build -t web:1.0 .
    ## docker run --name web -p 8090:8090 -d web:1.0
    web:
    build: .
    ports:
    - "8090:8090"
  • 上面的Compose文件就描述一个项目,其中有两个容器

    • mysql:一个基于mysql:5.7.25镜像构建的容器,并且挂载了两个项目
    • web:一个基于docker build临时构建的镜像容器,映射端口为8090
  • 其实DockerCompose文件可以看做是将多个docker run命令写到一个文件,只是语法稍有差异

6.2 安装DockerCompose

  • 使用curl下载

    1
    2
    # 安装
    curl -L https://github.com/docker/compose/releases/download/1.23.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
  • 修改文件权限

    1
    chmod +x /usr/local/bin/docker-compose
  • Base自动补全命令

    1
    curl -L https://raw.githubusercontent.com/docker/compose/1.29.1/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose

7. 部署微服务集群

需求:将SpringCloud里学习的cloud-demo微服务集群利用DockerCompose部署

  • 实现思路
    1. 编写docker-compose文件
    2. 修改cloud-demo项目,将数据库,nacos地址都重命名为docker-compose的服务名
    3. 使用maven打包工具,将项目中的每个微服务都打包为app.jar(打包名与Dockerfile中一致即可)
    4. 将打包好的app.jar拷贝到cloud-demo中的每一个对应的子目录,编写Dockerfile文件
    5. 将cloud-demo上传至虚拟机,利用docker-compose up -d来部署
  1. 我们看一下黑马给出的docker-compose.yml文件

    • $PWD是执行linux命令,获取当前目录
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    version: "3.2"
    services:
    nacos:
    image: nacos/nacos-server
    environment:
    MODE: standalone
    ports:
    - "8848:8848"
    mysql:
    image: mysql:5.7.25
    environment:
    MYSQL_ROOT_PASSWORD: 123
    volumes:
    - "$PWD/mysql/data:/var/lib/mysql"
    - "$PWD/mysql/conf:/etc/mysql/conf.d/"
    userservice:
    build: ./user-service
    orderservice:
    build: ./order-service
    gateway:
    build: ./gateway
    ports:
    - "10010:10010"
    • 其中包括了五个服务
      1. nacos:作为注册中心和配置中心
        • image:nacos/nacos-server 基于nacos/nacos-server镜像构建
        • environment:环境变量
          • MODE:standalone:单点模式启动
        • port:端口 这里是8848
      2. mysql:数据库
        • image:mysql:5.7.25 mysql5的镜像
        • environment:环境变量
          • MYSQL_ROOT_PASSWORD:mysql密码
        • volumes:数据卷挂载地址
      3. userservice:基于Dockerfile临时构建,userservice不需要暴露端口,网关才是微服务的入口,如果暴露了userservice的端口,那么网关的身份认证,权限校验就形同虚设了
      4. orderservice:基于Dockerfile临时构建,不需要暴露端口,理由同上
      5. gateway:基于Dockerfile临时构建,网关需要暴露端口,它是其他微服务的入口
  2. 修改微服务配置

    • 使用Docker Compose部署时,所有服务之间都可以用服务名互相访问(不同于正常开发环境)
    • 那我们现在就修改我们cloud-demo中微服务的yml配置文件,将所有地址都改成服务名称
    • 将user-service,order-service,gateway的所有暴露的端口都用微服务名代替
  3. 使用maven打包工具,将每个微服务都打包为app.jar

    • 查看user-service的pom文件,发现
    1
    2
    3
    4
    5
    6
    7
    8
    9
        <build>
    <finalName>app</finalName>
    <plugins>
    <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    </plugins>
    </build>

    这就是打包之后的名称为app,将其加到order-service和gateway的pom文件中
    打包完将app.jar拷贝到cloud-demo的每个子目录下

  4. 编写Dockerfile文件

    1. gateway
    1
    2
    3
    FROM openjdk:8
    COPY ./app.jar /tmp/app.jar
    ENTERPOINT java -jar /tmp/app.jar
    1. order-service
    1
    2
    3
    FROM openjdk:8
    COPY ./app.jar /tmp/app.jar
    ENTERPOINT java -jar /tmp/app.jar
    1. user-service
    1
    2
    3
    FROM openjdk:8
    COPY ./app.jar /tmp/app.jar
    ENTERPOINT java -jar /tmp/app.jar
  5. 将cloud-demo上传到虚拟机 利用docker-conpose -d部署

8. Docker镜像仓库

  • 标题: Docker
  • 作者: yin_bo_
  • 创建于 : 2025-11-25 18:43:15
  • 更新于 : 2025-11-27 14:41:03
  • 链接: https://www.blog.yinbo.xyz/2025/11/25/微服务/Docker/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。