Docker

快速构建、运行、管理应用的运维工具【开发了解即可,k8s也是运维学的】。

之前用Linux命令、脚本部署。还是很麻烦。同时,在一台主机中不便于部署多个项目,可能会产生依赖冲突。

传统方式:检查系统中是否已有数据库软件->在官网现在对应版本安装包->解压安装包->删除已有数据库软件【系统可能自带】->按顺序执行解压出的文件【中间可能报错->安装需要的依赖】->安装完成->基础配置【用户名、密码和字符集等】

有了docker,给他一条命令,就可以安装了。

特别是即将进入微服务阶段,微服务项目动辄就是几十台、上百台服务需要部署,有些大型项目甚至达到数万台服务。而由于每台服务器的运行环境不同,写好的安装流程、部署脚本并不一定在每个服务器都能正常运行,经常会出错。这就给系统的部署运维带来了很多困难。

Docker使部署对服务器环境的依赖,减少复杂的部署流程。

安装Docker

  1. 卸载旧版

    yum remove docker \
        docker-client \
        docker-client-latest \
        docker-common \
        docker-latest \
        docker-latest-logrotate \
        docker-logrotate \
        docker-engine \
        docker-selinux 
    
  2. 安装配置yum源。看最后是否显示成功

    首先要安装一个yum工具

    sudo yum install -y yum-utils device-mapper-persistent-data lvm2
    

    安装成功后,执行命令,配置Docker的yum源

    # 删除可能存在的旧 Docker 源
    sudo rm -f /etc/yum.repos.d/docker-ce.repo
    # 添加华为云 Docker 源
    sudo yum-config-manager --add-repo https://repo.huaweicloud.com/docker-ce/linux/centos/docker-ce.repo
    # 清理 Docker 源缓存
    sudo yum clean all --enablerepo=docker-ce-stable
    sudo yum makecache fast --enablerepo=docker-ce-stable
    

    更新yum,建立缓存

    sudo yum makecache fast
    
  3. 安装Dockers【验证docker -v】

    yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    
  4. 启动和校验【查看是否有进程docker images】

    # 启动Docker
    systemctl start docker
    
    # 停止Docker
    systemctl stop docker
    
    # 重启
    systemctl restart docker
    
    # 设置开机自启
    systemctl enable docker
    
    # 执行docker ps命令,如果不报错,说明安装启动成功
    docker ps
    
  5. 配置镜像加速【直接搜】

    镜像地址可能会变更,如果失效可以百度找最新的docker镜像。

    配置镜像步骤如下:

    # 创建配置目录
    mkdir -p /etc/docker
    # 写入华为云镜像配置
    sudo tee /etc/docker/daemon.json <<-'EOF'
    {
        "registry-mirrors": ["https://mirrors.huaweicloud.com"]
    }
    EOF
    
    # 重新加载配置
    systemctl daemon-reload
    
    # 启动 Docker 并设置开机自启
    sudo systemctl start docker
    sudo systemctl enable docker
    
  6. 验证安装与配置

    • 检查 Docker 运行状态(显示 active (running) 为成功)

      sudo systemctl status docker
      
    • 验证镜像源配置(显示华为云地址为成功)

      docker info | grep "Registry Mirrors" -A 5
      

快速入门

为了感受Docker的优势,我们可以用它安装MySQL。先停掉虚拟机中的MySQL,确保你的虚拟机已经安装Docker,且网络开通的情况下,执行下面命令即可安装MySQL。

docker run -d \
  --name mysql \
  -p 3306:3306 \ 
  -e TZ=Asia/Shanghai \
  -e MYSQL_ROOT_PASSWORD=123 \
  mysql

镜像和容器

Docker安装应用时,Docker会自动在搜索并下载应用镜像(image)。镜像不仅包含应用本身,还包含应用运行所需要的环境、配置、系统函数库【就像所说的绿色免安装一样,直接把应用的文件依赖等打包安装,因为这些都是文件,这样就能跨系统安装,centos Ubuntu Windows都可以用】。

Docker会在运行镜像时创建一个隔离环境,这个环境称为容器(container)【这样支持运行多个镜像了,避免依赖冲突】。

镜像仓库:存储和管理镜像的平台,Docker官方维护了一个公共仓库:Docker Hub。

image-20251029114635003

命令解读

通过解读一下上面案例的命令,我们认识了解docker的基础命令。

docker run -d \
  --name mysql \
  -p 3306:3306 \ 
  -e TZ=Asia/Shanghai \
  -e MYSQL_ROOT_PASSWORD=123 \
  mysql
  • docker run -d :创建并运行一个容器【创个环境】,-d则是让容器以后台进程运行

  • --name`` mysql : 给容器起个名字叫。必须唯一

  • -p 3306:3306 : 设置端口映射,是宿主机端口:容器端口的映射。容器是隔离环境,外界不可访问。但是可以将宿主机端口映射容器内到端口,当访问宿主机指定端口时,就是在访问容器内的端口了。容器有直接的一套端口,但多个容器不能共用一个宿主机端口。所以,要进行映射。

    image-20251029174830955

  • -e KEY=VALUE :是设置环境变量。具体设什么,可以根据不同的需要什么去设置。

    案例中,TZ``=Asia/Shanghai是设置时区;MYSQL_ROOT_PASSWORD=123是设置MySQL默认密码

  • mysql :指定运行的镜像的名字,Docker会根据这个名字搜索并下载镜像

    • 格式:REPOSITORY:TAG,例如mysql:8.0,其中REPOSITORY可以理解为镜像名,TAG是版本号
    • 在未指定TAG的情况下,默认是最新版本,也就是mysql:latest

镜像的名称不是随意的,而是要到DockerRegistry中寻找,镜像运行时的配置也不是随意的,要参考镜像的帮助文档,这些在DockerHub网站或者软件的官方网站中都能找到

Docker基础

常用命令

也可以单步下载,比如docker pull,单拉镜像。给我们提供了很多个基本命令

Docker最常见的命令就是操作镜像、容器的命令,详见官方文档: https://docs.docker.com/

image-20251029191318222

命令 说明
docker pull 拉取镜像
docker push 推送镜像到DockerRegistry
docker images 查看本地镜像,可以看下载是否成功
docker rmi 删除本地镜像
docker build 基于DOCKERFILE文件自定义镜像
docker run 创建并运行容器(不能重复创建)
docker stop 停止指定容器
docker start 启动指定容器
docker restart 重新启动容器
docker rm 删除指定容器
docker ps 查看当前容器运行状态
docker logs 查看容器运行日志,排错
docker exec 进入容器内部
docker save [-o --文件名] 镜像名 保存镜像到本地压缩文件
docker load 加载本地压缩文件到镜像
docker inspect 查看容器详细信息

补充:

默认情况下,每次重启虚拟机我们都需要手动启动Docker和Docker中的容器。通过命令可以实现开机自启:

# Docker开机自启
systemctl enable docker

# Docker容器开机自启
docker update --restart=always [容器名/容器id]

案例

查看DockerHub,拉取Nginx镜像,创建并运行Nginx容器

一般也就是如下这个流程

  • 在DockerHub中搜索Nginx镜像,查看镜像的名称
  • 拉取Nginx镜像
  • 查看本地镜像列表
  • 创建并运行Nginx容器
  • 查看容器
  • 停止容器
  • 再次启动容器
  • 进入Nginx容器
  • 删除容器

当不知道命令怎么用时,可以在这条命令后加--help,查看帮助信息

流程代码:

# 第1步,去DockerHub查看nginx镜像仓库及相关信息

# 第2步,拉取Nginx镜像
docker pull nginx

# 第3步,查看镜像
docker images
# 结果如下:
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
nginx        latest    605c77e624dd   16 months ago   141MB
mysql        latest    3218b38490ce   17 months ago   516MB

# 第4步,创建并允许Nginx容器
docker run -d --name nginx -p 80:80 nginx

# 第5步,查看运行中容器
docker ps #输出的字段分别是:容器id、镜像、启动命令……端口映射。
# 也可以加格式化方式访问,格式会更加清爽
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"

# 第6步,访问网页,地址:http://虚拟机地址

# 第7步,停止容器
docker stop nginx

# 第8步,查看所有容器。默认查看的时运行容器
docker ps -a --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"

docker logs nginx  #查看日志
docker logs -f nginx  #持续更新日志,调试时常用

# 第9步,再次启动nginx容器
docker start nginx

# 第10步,再次查看容器
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"

# 第11步,查看容器详细信息
docker inspect nginx

# 第12步,进入容器,查看容器内目录。模拟了一个计算机。这也是其功能的实现所在
docker exec -it nginx bash
# 或者,可以进入MySQL
docker exec -it mysql mysql -uroot -p

exit #推出

# 第13步,删除容器
docker rm nginx
# 发现无法删除,因为容器运行中,强制删除容器。也可以先停再删
docker rm -f nginx

命令别名

给常用Docker命令起别名,方便我们访问,避免重复的输入冗长的命令:

格式是别名=原命令

# 修改/root/.bashrc文件
vi /root/.bashrc
内容如下:
# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
alias dps='docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"'
alias dis='docker images'

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

然后,执行命令使别名生效

source /root/.bashrc

数据卷

案例:利用Nginx容器部署静态资源

需求:

  • 创建Nginx容器,修改nginx容器内的html目录下的index.html文件,查看变化
  • 将静态资源部署到nginx的html目录

在操作过程中,我们发现,容器内部无法识别llvi等命令,这是因为容器只提供了应用运行必备的工具,对应不影响运行的就没有提供了。那如何去操作容器文件数据呢。Docker给我们提供了通过数据卷的方式实现。

数据卷(volume)是一个虚拟目录,是容器内目录与宿主机目录之间映射的桥梁。这样实现类双向绑定。直接可以在宿主机中操作文件即可。这也实现了程序运行产生的数据、程序运行依赖的配置都应该与容器解耦

image-20251029203400227

那如何用命令实现这个过程呢。下面是一些常用命令

命令 说明 文档地址
docker volume create 创建数据卷 docker volume create
docker volume ls 查看所有数据卷 docker volume ls
docker volume rm 删除指定数据卷 docker volume rm
docker volume inspect 查看某个数据卷的详情 docker volume inspect
docker volume prune 清除数据卷 docker volume prune
  • 在执行docker run命令时,使用 -v 数据卷:容器内目录 可以完成数据卷挂载。【若容器已经创建,是无法挂在的】
  • 当创建容器时,如果挂载了数据卷且数据卷不存在,会自动创建数据卷【宿主机对应的文件也会被创建】

案例的示例:

# 1.首先创建容器并指定数据卷,注意通过 -v 参数来指定数据卷,数据卷名[自己起]:容器内目录
docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx

# 2.然后查看数据卷
docker volume ls
# 结果
DRIVER    VOLUME NAME
local     29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f
local     html

# 3.查看数据卷详情
docker volume inspect html
# 结果
[
    {
        "CreatedAt": "2024-05-17T19:57:08+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/html/_data",
        "Name": "html",
        "Options": null,
        "Scope": "local"
    }
]

# 4.查看/var/lib/docker/volumes/html/_data目录
ll /var/lib/docker/volumes/html/_data
# 可以看到与nginx的html目录内容一样,结果如下:【自动创好了】
总用量 8
-rw-r--r--. 1 root root 497 12月 28 2021 50x.html
-rw-r--r--. 1 root root 615 12月 28 2021 index.html

# 5.进入该目录,并随意修改index.html内容
cd /var/lib/docker/volumes/html/_data
vi index.html

# 6.打开页面,查看效果

# 7.进入容器内部,查看/usr/share/nginx/html目录内的文件是否变化。结果是一致的
docker exec -it nginx bash

匿名卷

容器运行时自己生成的卷,就叫匿名卷

我们查看一下之前安装mysql容器的发现,它默认用一个数据卷。但我们命令中没有指明,是它自己生成的,因为mysql需要存数据,为了防止随着数据越来越多,导致容器越来越大。docker默认挂在出去了,卷名也是默认生成的。一般会很长。比较麻烦。所以运行时要指明。

# 1.查看MySQL容器详细信息
docker inspect mysql
# 关注其中.Config.Volumes部分和.Mounts部分

本地目录挂载

除了用默认方式挂载。还支持直接指定本地的目录【很灵活】去挂载

案例:

需求:

  • 查看mysql容器,判断是否有数据卷挂载
  • 基于宿主机目录实现MySQL数据目录、配置文件、初始化脚本的挂载(查阅官方镜像文档)
    • 挂载/root/mysql/data到容器内的/var/lib/mysql目录
    • 挂载/root/mysql/init到容器内的/docker-entrypoint-initdb.d目录,把文件放到这地方就自动生效了
    • 挂载/root/mysql/conf到容器内的/etc/mysql/conf.d目录,把文件放到这地方就自动生效了

注意:

  • 在执行docker run命令时,使用 -v 本地目录 : 容器内目录 可以完成本地目录挂载
  • 本地目录必须以“/”或 "./" 开头,如果直接以名称开头,会被识别为数据卷而非本地目录
    • - v mysql : /var/lib/mysql 会被识别为一个数据卷叫mysql
    • -v ./mysql : /var/lib/mysql 会被识别为当前目录下的mysql目录
# 1.删除原来的MySQL容器
docker rm -f mysql

# 2.进入root目录
cd ~

# 3.创建并运行新mysql容器,挂载本地目录。记得先建好本地的目录
docker run -d \
  --name mysql \
  -p 3306:3306 \
  -e TZ=Asia/Shanghai \
  -e MYSQL_ROOT_PASSWORD=123 \
  -v ./mysql/data:/var/lib/mysql \
  -v ./mysql/conf:/etc/mysql/conf.d \
  -v ./mysql/init:/docker-entrypoint-initdb.d \
  mysql

# 4.查看root目录,可以发现~/mysql/data目录已经自动创建好了
ls -l mysql
# 结果:
总用量 4
drwxr-xr-x. 2 root    root   20 5月  19 15:11 conf
drwxr-xr-x. 7 polkitd root 4096 5月  19 15:11 data
drwxr-xr-x. 2 root    root   23 5月  19 15:11 init

# 查看data目录,会发现里面有大量数据库数据,说明数据库完成了初始化
ls -l data

# 5.查看MySQL容器内数据
# 5.1.进入MySQL
docker exec -it mysql mysql -uroot -p123
# 5.2.查看编码表
show variables like "%char%";
# 5.3.结果,发现编码是utf8mb4没有问题
+--------------------------+--------------------------------+
| Variable_name            | Value                          |
+--------------------------+--------------------------------+
| character_set_client     | utf8mb4                        |
| character_set_connection | utf8mb4                        |
| character_set_database   | utf8mb4                        |
| character_set_filesystem | binary                         |
| character_set_results    | utf8mb4                        |
| character_set_server     | utf8mb4                        |
| character_set_system     | utf8mb3                        |
| character_sets_dir       | /usr/share/mysql-8.0/charsets/ |
+--------------------------+--------------------------------+

自定义镜像

镜像结构

镜像就是包含了应用程序、程序运行的系统函数库、运行配置等文件的文件包。构建镜像的过程其实就是把上述文件打包的过程。

我们可以通过部署一个Java应用,来理解构建一个Java镜像的步骤。

image-20251030112231839

这里java项目并不需要完整的操作系统,仅仅是基础运行环境即可。

上述步骤中的每一次操作其实都是在生产一些文件(系统运行环境、函数库、配置最终都是磁盘文件),所以镜像就是一堆文件的集合

镜像文件不是随意堆放的,而是按照操作的步骤分层叠加而成,每一层形成的文件都会单独打包并标记一个唯一id,称为Layer)。这样,如果我们构建时用到的某些层其他人已经制作过,就可以直接拷贝使用这些层,而不用重复制作。这就是分层的优点。例如,可以共享基础层【基础镜像】,通用性就很强。不同镜像可以共用基础的层。可以在下载日志看出。一行一行的就是一层一层的,如果已有,会提示已存在,就不用下载了。

image-20251030113620050

  • 入口(Entrypoint)
    镜像运行入口,一般是程序启动的脚本和参数
  • 层( Layer )
    添加安装包、依赖、配置等,每次操作都形成新的一层。
  • 基础镜像(BaseImage)
    应用依赖的系统函数库、环境、配置、文件等

Dockerfile

具体如何分层打包,看起了是挺麻烦。但docker帮我们做了,我们只需要描述清楚镜像结构就可以。那我们就是用Dockerfile去描述镜像结构。其实,很多成docker是已经有了。只需要告诉它需要什么,它自动会找好。

指令 说明 示例
FROM 指定基础镜像 FROM centos:6
ENV 设置环境变量,可在后面指令使用 ENV key value
COPY 拷贝本地文件到镜像的指定目录【会自动创建目录】 COPY ./jre11.tar.gz /tmp
RUN 执行Linux的shell命令,一般是安装过程的命令 RUN tar -zxvf /tmp/jre11.tar.gz&& EXPORTS path=/tmp/jre11:$path
EXPOSE 指定容器运行时监听的端口,是给镜像使用者看的【描述指明要用什么端口作映射】 EXPOSE 8080
ENTRYPOINT 镜像中应用的启动命令,容器运行时调用。【启动脚本】 ENTRYPOINT java -jar xx.jar

如果要基于Ubuntu镜像来构建一个Java应用,其Dockerfile内容如下:

# 指定基础镜像
FROM ubuntu:16.04
# 配置环境变量,JDK的安装目录、容器内时区
ENV JAVA_DIR=/usr/local
ENV TZ=Asia/Shanghai
# 拷贝jdk和java项目的包
COPY ./jdk8.tar.gz $JAVA_DIR/
COPY ./docker-demo.jar /tmp/app.jar
# 设定时区
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 安装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 8080
# 入口,java项目的启动命令
ENTRYPOINT ["java", "-jar", "/app.jar"]

可以发现如果对于不同的项目,我们主要的差别就是jar包,和启动命令。其他一般不会明显变化。因此,我们可把不变的打包作为基础镜像【有人这么做了,直接用就行】,我们只需要告诉docker变的就行了。

image-20251030201702366

# 基础镜像
FROM openjdk:11.0-jre-buster
# 设定时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷贝jar包
COPY docker-demo.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]

构建镜像

当Dockerfile文件写好以后,就可以利用命令来构建镜像了。

首先需要获取openjdk镜像,我们可以pull,也可以用tar的方式获取。

首先,将要构建的jar包【如docker-demo.jar包】以及Dockerfile拷贝到虚拟机的目录【如/root/demo】:

# 进入镜像目录
cd /root/demo
# 开始构建
docker build -t docker-demo:1.0 .

命令说明:

  • docker build : 就是构建一个docker镜像

  • -t docker-demo:1.0-t参数是指定镜像的名称(repositorytag

  • . : 最后的点是指构建时Dockerfile所在路径,由于我们进入了demo目录,所以指定的是.代表当前目录,也可以直接指定Dockerfile目录:【在命令没有指定Dockerfile文件名字的情况下,文件就必须叫“Dockerfile”】。如果是.,那么Dockerfile和jar包要在一起,名字也要叫Dockerfile。

    # 直接指定Dockerfile目录
    docker build -t docker-demo:1.0 /root/demo
    

网络

我们部署Java应用,还需要随意来的环境,如mysql,redis。还要互相访问。

我们可以用docker inspect命令查看容器详情。可以发现,不同的容器的IP在同一网段中的。虽然环境是隔离的,但是他们有相同的网关。这是为什么呢?

image-20251030210636814

其实,默认情况下,所有容器都是以bridge方式连接到Docker的一个虚拟网桥上。安装docker时,它会默认创建一张虚拟的网卡docker0,并且为其创造网桥。然后安装运行容器时会桥接并分配地址。所以默认时能ping通的。

那还配置什么呢。因为分配给容器的地址不固定,这次启动的ip地址可能和下次的不一样。所以,在代码中可不能跟着变。

所以,我们用到自定义网络。我们创建新的自定义网络。加入自定义网络的容器才可以通过容器名互相访问,Docker的网络操作命令如下

命令 说明 文档地址
docker network create 创建一个网络 docker network create
docker network ls 查看所有网络 docker network ls
docker network rm 删除指定网络 docker network rm
docker network prune 清除未使用的网络 docker network prune
docker network connect 使指定容器连接加入某网络 docker network connect
docker network disconnect 使指定容器连接离开某网络 docker network disconnect
docker network inspect 查看网络详细信息 docker network inspect

示例:

# 1.首先通过命令创建一个网络
docker network create hmall

# 2.然后查看网络
docker network ls
# 结果:
NETWORK ID     NAME      DRIVER    SCOPE
639bc44d0a87   bridge    bridge    local
403f16ec62a2   hmall     bridge    local
0dc0f72a0fbb   host      host      local
cd8d3e8df47b   none      null      local
# 其中,除了hmall以外,其它都是默认的网络

# 3.让dd和mysql都加入该网络,注意,在加入网络时可以通过--alias给容器起别名
# 这样该网络内的其它容器可以用别名互相访问!
# 3.1.mysql容器,指定别名为db,另外每一个容器都有一个别名是容器名
docker network connect hmall mysql --alias db
# 3.2.db容器,也就是我们的java项目
docker network connect hmall dd

# 4.进入dd容器,尝试利用别名访问db
# 4.1.进入容器
docker exec -it dd bash
# 4.2.用db别名访问
ping db
# 结果
PING db (172.18.0.2) 56(84) bytes of data.
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=2 ttl=64 time=0.056 ms
# 4.3.用容器名访问
ping mysql
# 结果:
PING mysql (172.18.0.2) 56(84) bytes of data.
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=1 ttl=64 time=0.044 ms
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=2 ttl=64 time=0.054 ms

这样就方便多了。现在再查看容器详情,会发现多了一个自定义网络。

我们也可以再创建容器时直接加入某个网络,示例如下:【加入--network heima】

docker run -d --name dd -p 8080:8080 --network heima docker-demo

项目部署

Java后端

这里先Java后端部署,后端与之前部署在docker容器内的mysql数据库来连接。在真实项目部署中,数据库是不会对外作端口映射的,只能后端通过容器名进行来连接。在后端配置文件的的jdbc连接的网址host【如192.168.150.101】替换成容器名即可【如mysql】。

asynccode

然后在父工程中进行打包,就有jar包了,再加上Dockerfile就可以构建镜像了。然后创建并运行容器。同时加入和mysql容器一起的网络。然后可以查看容器日志和访问接口是否正常运行。

# 1.构建项目镜像,不指定tag,则默认为latest
docker build -t hmall .

# 2.查看镜像
docker images
# 结果
REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
hmall         latest    0bb07b2c34b9   43 seconds ago   362MB
docker-demo   1.0       49743484da68   24 hours ago     327MB
nginx         latest    605c77e624dd   16 months ago    141MB
mysql         latest    3218b38490ce   17 months ago    516MB

# 3.创建并运行容器,并通过--network将其加入hmall网络,这样才能通过容器名访问mysql
docker run -d --name hmall --network hmall -p 8080:8080 hmall

前端

hmall-portalhmall-admin是前端代码,需要基于nginx部署。

准备两个东西即可

  • html是静态资源目录,我们需要把hmall-portal以及hmall-admin都复制进去

    示例结构

    image-20251101164218568

  • nginx.conf是nginx的配置文件,主要是完成对html下的两个静态资源目录做代理

    示例内容如下

    worker_processes  1;
    
    events {
        worker_connections  1024;
    }
    
    http {
        include       mime.types;
        default_type  application/json;
    
        sendfile        on;
        
        keepalive_timeout  65;
    
        server {
            listen       18080;
            # 指定前端项目所在的位置
            location / {
                root /usr/share/nginx/html/hmall-portal;
            }
    
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
            location /api {
                rewrite /api/(.*)  /$1 break;
                proxy_pass http://hmall:8080;
            }
        }
        server {
            listen       18081;
            # 指定前端项目所在的位置
            location / {
                root /usr/share/nginx/html/hmall-admin;
            }
    
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
            location /api {
                rewrite /api/(.*)  /$1 break;
                proxy_pass http://hmall:8080;
            }
        }
    }
    

其中可以看出:nginx的配置文件中的host连接后端,也要写成后端的容器名字。

由于需要让nginx同时代理hmall-portal和hmall-admin两套前端资源,因此我们需要暴露两个端口:

  • 18080:对应hmall-portal
  • 18081:对应hmall-admin

示例命令如下:

docker run -d \
  --name nginx \
  -p 18080:18080 \
  -p 18081:18081 \
  -v /root/nginx/html:/usr/share/nginx/html \
  -v /root/nginx/nginx.conf:/etc/nginx/nginx.conf \
  --network hmall \
  nginx

DockerCompose

认识

通过前面的操作,虽然比之前要方便很多。但是对于稍微复杂的项目不仅包含前后端和数据库,可能还包含各种各样的中间件等。还是有点麻烦的,也很容易出错。要一个一个创建镜像,创建容器,加入网络。同时,也没体现出项目的整体性、没有统一的管理。

那现在有个工具,可以解决上述问题。就叫DockerCompose

Docker Compose通过一个单独的docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器,帮助我们实现多个相互关联的Docker容器的快速部署。

image-20251101170502537

我们在文件中描述清楚我们的项目信息即可。

信息和docker run命令中的信息差不多,只是语法上有区别。

语法介绍

docker-compose.yml文件的基本语法可以参考官方文档:Legacy versions | Docker Docs

docker-compose文件中可以定义多个相互关联的应用容器,每一个应用容器被称为一个服务(service)。由于service就是在定义某个应用的运行时参数,因此与docker run参数非常相似。

例如,对于之前部署的MySql的命令如下

docker run -d \
  --name mysql \
  -p 3306:3306 \
  -e TZ=Asia/Shanghai \
  -e MYSQL_ROOT_PASSWORD=123 \
  -v ./mysql/data:/var/lib/mysql \
  -v ./mysql/conf:/etc/mysql/conf.d \
  -v ./mysql/init:/docker-entrypoint-initdb.d \
  --network hmall
  mysql

对应到的docker-compose.yml 的内容就是这样

version: "3.8"

services:
  mysql:
    image: mysql
    container_name: mysql
    ports:
      - "3306:3306"
    environment:
      TZ: Asia/Shanghai
      MYSQL_ROOT_PASSWORD: 123
    volumes:
      - "./mysql/conf:/etc/mysql/conf.d"
      - "./mysql/data:/var/lib/mysql"
    networks:
      - new
networks:
  new:
    name: hmall

对应关系

docker run 参数 docker compose 指令
--name container_name
-p ports
-e environment
-v volumes
--network networks

那那么要部署整个项目的话,就可以写成如下内容了

version: "3.8"

services:
  mysql:
    image: mysql
    container_name: mysql
    ports:
      - "3306:3306"
    environment:
      TZ: Asia/Shanghai
      MYSQL_ROOT_PASSWORD: 123
    volumes:
      - "./mysql/conf:/etc/mysql/conf.d"
      - "./mysql/data:/var/lib/mysql"
      - "./mysql/init:/docker-entrypoint-initdb.d"
    networks:
      - hm-net
  hmall:
    build: 
      context: .
      dockerfile: Dockerfile
    container_name: hmall
    ports:
      - "8080:8080"
    networks:
      - hm-net
    depends_on:
      - mysql
  nginx:
    image: nginx
    container_name: nginx
    ports:
      - "18080:18080"
      - "18081:18081"
    volumes:
      - "./nginx/nginx.conf:/etc/nginx/nginx.conf"
      - "./nginx/html:/usr/share/nginx/html"
    depends_on:
      - hmall
    networks:
      - hm-net
networks:
  hm-net:
    name: hmall

可以看到,构建镜像的过程也可以包含。depends_on就是说依赖,根据这个,有个先后创建容器的顺序。如果后面还有,接着往下写就行。之后也会创建网络,通过前面可以知道,hm-net网络标识,知道容器在同一个网络。在最下面再生命这个网络。hm-net是网络表示。网络名字还是hamll。

基础命令

然后就可以用命令去部署了。

可以在官网找到常见命令:docker compose | Docker Docs

常用命令如下:

docker compose [OPTIONS] [COMMAND]

选项命令如下:

类型 参数或指令 说明
Options -f 指定compose文件的路径和名称
-p 指定project名称
Commands up 创建并启动所有service容器
down 停止并移除所有容器、网络
ps 列出所有启动的容器
logs 查看指定容器的日志
stop 停止容器
start 启动容器
restart 重启容器
top 查看运行的进程
exec 在指定的运行中容器中执行命令

示例命令代码:【通过命令中的目录,可以看出文件应该放到哪里。或者说根据实际文件的位置去调整命令中的目录】

# 1.进入root目录
cd /root

# 2.删除旧容器
docker rm -f $(docker ps -qa)

# 3.删除hmall镜像
docker rmi hmall

# 4.清空MySQL数据
rm -rf mysql/data

# 5.启动所有, -d 参数是后台启动
docker compose up -d
# 结果:
[+] Building 15.5s (8/8) FINISHED
 => [internal] load build definition from Dockerfile                                    0.0s
 => => transferring dockerfile: 358B                                                    0.0s
 => [internal] load .dockerignore                                                       0.0s
 => => transferring context: 2B                                                         0.0s
 => [internal] load metadata for docker.io/library/openjdk:11.0-jre-buster             15.4s
 => [1/3] FROM docker.io/library/openjdk:11.0-jre-buster@sha256:3546a17e6fb4ff4fa681c3  0.0s
 => [internal] load build context                                                       0.0s
 => => transferring context: 98B                                                        0.0s
 => CACHED [2/3] RUN ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo   0.0s
 => CACHED [3/3] COPY hm-service.jar /app.jar                                           0.0s
 => exporting to image                                                                  0.0s
 => => exporting layers                                                                 0.0s
 => => writing image sha256:32eebee16acde22550232f2eb80c69d2ce813ed099640e4cfed2193f71  0.0s
 => => naming to docker.io/library/root-hmall                                           0.0s
[+] Running 4/4
 ✔ Network hmall    Created                                                             0.2s
 ✔ Container mysql  Started                                                             0.5s
 ✔ Container hmall  Started                                                             0.9s
 ✔ Container nginx  Started                                                             1.5s

# 6.查看镜像
docker compose images
# 结果
CONTAINER           REPOSITORY          TAG                 IMAGE ID            SIZE
hmall               root-hmall          latest              32eebee16acd        362MB
mysql               mysql               latest              3218b38490ce        516MB
nginx               nginx               latest              605c77e624dd        141MB

# 7.查看容器
docker compose ps
# 结果
NAME                IMAGE               COMMAND                  SERVICE             CREATED             STATUS              PORTS
hmall               root-hmall          "java -jar /app.jar"     hmall               54 seconds ago      Up 52 seconds       0.0.0.0:8080->8080/tcp, :::8080->8080/tcp
mysql               mysql               "docker-entrypoint.s…"   mysql               54 seconds ago      Up 53 seconds       0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp
nginx               nginx               "/docker-entrypoint.…"   nginx               54 seconds ago      Up 52 seconds       80/tcp, 0.0.0.0:18080-18081->18080-18081/tcp, :::18080-18081->18080-18081/tcp

其实DockerCompose的功能远不止如此,还可以集群部署,多服务器的互联。多实例部署,负载均衡等操作,但这不是后端人员的主要工作。

posted @ 2025-10-30 21:20  韩熙隐ario  阅读(8)  评论(0)    收藏  举报