Docker概述:

容器是什么?

容器就是运行环境和,容器基础镜像的集合;
image.png

容器与虚拟机的区别

image.png

  • **启动速度:**每个虚拟都机是一个完整的操作系统包括操作系统和内核,所以它是一个重量级的系统;而容器是轻量级的,因为容器只打包了操作系统的基础文件和库文件、还有应用程序及所有的依赖,他的运行速度就如同在系统中创建一个进程一样快,所以启动速度较快。
  • **运行性能:**由于虚拟机增加了虚拟化层用于虚拟化硬件,势必会增加一定的开销,所以运行性能有所损失;而容器是直接运行在物理操作系统上的,他本身与系统上其他进程并没有太大区别,所以运行性能是接近原生的。
  • **磁盘占用:**虚拟机是一个完整的操作系统,是 GB 级别的,而容器只包含了一些系统启动的必要组件和程序依赖,是 MB 级别的。
  • **数量:**运行一个操作系统的开销较大,运行一个进程的开销较小,同样的服务器资源可以运行更多的容器。
  • **隔离性:**虚拟机是一个完整的操作系统级别的隔离,要比容器好很多;容器是进程级别的隔离,隔离的不彻底,因为多个容器之间使用的是同一个宿主机的操作系统内核。
  • **封装速度:**虚拟机封装会包含操作系统,封装速度比较慢,容器只封装操作系统的基础文件和库文件、应用程序、依赖,封装速度较快。

总结:
点击查看【bilibili】

Docker 和容器的关系

容器是一种虚拟化技术,docker 是实现容器的一种工具,我们称它为容器引擎;
可以驱动容器的引擎还有 podman、containerd 等,docker 是目前市面上应用范围最广的一种容器引擎。

自己构建一个容器:

构建镜像需要使用 dockerfile 文件,我们以 Nginx 为例,编写一个 Nginx 镜像的 dockerfile:

1
vi dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FROM centos:7.9.2009

WORKDIR /opt

ADD nginx-1.24.0.tar.gz /opt


RUN yum install -y nc net-tools gcc-c++ pcre pcre-devel zlib zlib-devel openssl openssl-devel && \
yum clean all && \
rm -rf /tmp/* rm -rf /var/cache/yum/* && \
cd /opt/nginx-1.24.0 && \
./configure --user=nobody --group=nobody --prefix=/opt/nginx --with-http_gzip_static_module --with-http_ssl_module --with-stream && \
make && make install && \
rm -rf /opt/nginx-1.24.0

CMD /opt/nginx/sbin/nginx && tail -f /dev/null

构建镜像

1
2
3
4
5
6
# 在 dockerfile 同目录下执行命令
docker build -t nginx:v2 .

注释:
-t #构建镜像的名称
. #表示 dockerfile 文件在当前目录下


构建后的镜像名为 nginx:v2 ,在创建容器时可以这样使用:

1
docker run -f nginx_test nginx:v2

镜像服务器:

  • 提供存储、管理Docker镜像的服务器,被称为DockerRegistry,可以翻译为镜像仓库。DockerHub网站是官方仓库,阿里云、华为云会提供一些第三方仓库,我们也可以自己搭建私有的镜像仓库。
  • image.png
  • image.png
1
2
3
4
5
# Docker开机自启
systemctl enable docker

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

镜像:

之前我们说过,镜像之所以能让我们快速跨操作系统部署应用而忽略其运行环境、配置,就是因为镜像中包含了程序运行需要的系统函数库、环境、配置、依赖。
因此,自定义镜像本质就是依次准备好程序运行的基础环境、依赖、应用本身、运行配置等文件,并且打包而成。

1.Linux-ubuntu20.04 docker的镜像加速配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#1、 建立deamon.json 配置docker国内镜像加速地址
$ sudo vim /etc/docker/daemon.json
#添加镜像的内容如下:这行注释在添加的时候要删除的
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com/",
"https://reg-mirror.qiniu.com",
"https://registry.docker-cn.com"]
}
#2、添加完成之后重启docker服务
sudo systemctl reload docker
sudo systemctl restart docker
#注意:如果重启docker服务时遇到 docker.service is not active,cannot reload问题需要重启ubuntu系统
#3、查看docker 相关信息
sudo docker info
#使用命令之后在最后几行出现一下信息代表配置成功
Registry Mirrors:
https://docker.mirrors.ustc.edu.cn/
https://hub-mirror.c.163.com/
https://reg-mirror.qiniu.com/
https://registry.docker-cn.com/

2.相关概念:

  1. 容器(Container):容器是Docker中运行应用程序的实例。它们是基于镜像创建的,可以独立运行,并且具有自己的文件系统、进程空间和网络接口。容器提供了一个轻量级、可移植和隔离的环境,使应用程序可以在不同的计算机或环境中一致地运行。
  2. 镜像(Image):镜像是Docker中用于创建容器的模板。它包含了一个完整的文件系统,其中包括应用程序所需的所有文件、库和依赖项。镜像是只读的,可以从一个基础镜像构建,然后通过在其上应用更改和配置来定制。镜像是构建和分发应用程序的基本单元,可以在不同的环境中重复使用。
  3. 仓库(Repository):仓库是用于存储和共享Docker镜像的地方。它类似于代码仓库,可以存储多个镜像,并提供版本控制和标签管理。Docker Hub是一个公共仓库,其中包含了大量的官方和社区维护的镜像。此外,你也可以创建私有仓库来存储和管理自己的镜像。

常用的命令:

一张脑图整理Docker常用命令-腾讯云开发者社区-腾讯云
Docker最常见的命令就是操作镜像、容器的命令,详见官方文档: https://docs.docker.com/
image.png

1.从 Docker 镜像仓库获取镜像的命令是 docker pull。其命令格式为:

1
$ docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
1
docker run -it --rm ubuntu:18.04 bash以交互式启动一个容器,如果启动后想退出,输入exit就可以了

Docker部署Mysql:

image.png
mysql中的数据卷是由容器运行时创建的卷,称为匿名卷image.png
Docker 安装 MySQL | 菜鸟教程

挂载数据卷以及配置文件:

虽然官网上说默认配置文件在/etc/mysql/my.cnf但是有些镜像的配置文件实际位置不确定,不如我的默认配置文件在/etc/my.cnf,所以创建临时镜像查询默认配置文件的位置,然后复制出来,用来绑定本地配置文件。

1. 为了获取默认mysql配置文件,创建一个临时容器

每个人部署的 MySQL 内,可能文件路径不一致。我们可以先创建个测试的 MySQL 容器,然后再根据查找出的文件具体路径位置,重新创建我们符合我们需求的 MySQL 容器,命令如下:

1
2
3
4
docker run --name mysqltest \
-p 3307:3306 -e MYSQL_ROOT_PASSWORD=root \
-d mysql

进入Docker容器内:
1
docker exec -it mysqltest bash

找到配置文件的默认位置。

1
2
3
4
5
6
7
# 查找Docker内,MySQL配置文件my.cnf的位置
mysql --help | grep my.cnf
# 显示如下,意思是路径按优先排序,会是在以下路径里:
order of preference, my.cnf, $MYSQL_TCP_PORT,
/etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf
# 配置文件的路径不一定都一样,有些博客介绍的位置是在/etc/my.cnf。而Ubuntu系统上,实际存在位置是在/etc/mysql/my.cnf

创建本地路径并挂载Docker内数据

接下来,我们需要在物理机上,创建指定好一个数据和配置文件的挂载路径。
创建两个文件夹存放mysql的配置文件和数据

1
2
mkdir -p /docker/mysql/config && mkdir -p /docker/mysql/data

创建好本地的挂载数据路径后,我们再将临时容器里 MySQL 的配置文件复制到该路径。日后需改配置,直接在挂载路径的配置文件上修改即可。

1
2
docker cp mysqltest:/etc/my.cnf /docker/mysql/config/

创建 MySQL 容器并启动

1
2
3
4
5
6
7
8
docker run \
--name mysql \
-v /docker/mysql/config/my.cnf:/etc/my.cnf \
-v /docker/mysql/data:/var/lib/mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123 \
--restart=on-failure:3 \
-d mysql:8

MySQL8.0设置远程访问权限

1
2
3
#进入容器
docker exec -it mysql bash

  1. 登录MySQL
1
2
mysql -u root -p

  1. 选择 mysql 数据库
1
2
use mysql;

  1. 在 mysql 数据库的 user 表中查看当前 root 用户的相关信息
1
2
select host, user, authentication_string, plugin from user; 

执行完上面的命令后会显示一个表格
查看表格中 root 用户的 host,默认应该显示的 localhost,只支持本地访问,不允许远程访问。

  1. 授权 root 用户的所有权限并设置远程访问
1
2
GRANT ALL ON *.* TO 'root'@'%';

GRANT ALL ON 表示所有权限,% 表示通配所有 host,可以访问远程。

  1. 刷新权限
1
2
flush privileges;

  1. 查看 root 用户的 host
1
2
select host, user, authentication_string, plugin from user; 

再次执行步骤 2,root 用户的 host 已经变成 %,说明我们的修改已经成功,可以远程访问了。
注意事项

1. 针对现有数据库创建容器

如果您使用mysql已经包含数据库的数据目录启动容器实例,$MYSQL_ROOT_PASSWORD则应从运行命令行中省略该变量;

Docker部署nginx:

image.png
nginx镜像只包括了nginx运行所需要的资源,当我们想要修改nginx中的index.html的时候,在该容器中无法用vi等编辑器修改;因为nginx镜像中没有vi等编辑器的资源。如果我们想要修改index.html的时候可以通过数据卷的方式修改;
挂载:
image.png

1
docker run -d -p 80:80 -v html:/usr/share/nginx/html --name my-nginx nginx

这里的html是我们的数据卷,是一个虚拟目录;/usr/share/nginx/html是一个映射容器内的目录;
image.pngimage.png

数据卷:

数据卷只是虚拟的目录只是当成件容器内的目录和主机目录联系起来。
image.pngimage.png

自定义镜像:

image.png
image.png

网络:

image.pngimage.png

IDEA运行Docker

入门:
https://www.cnblogs.com/mayhot/p/15904506.html
Idea使用Docker部署SpringBoot项目_idea docker springboot-CSDN博客
1.配置pom.xml的build:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
    <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<!--使用docker-maven-plugin插件-->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.0.0</version>
<!--将插件绑定在某个phase执行-->
<executions>
<execution>
<id>build-image</id>
<!--用户只需执行mvn package ,就会自动执行mvn docker:build-->
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<!--指定生成的镜像名-->
# ${project.artifactId}是一个Maven变量,它代表项目的构件ID,即项目的唯一标识符。
<imageName>zrs/${project.artifactId}</imageName>
<!--指定标签-->
<imageTags>
<imageTag>latest</imageTag>
</imageTags>
<!-- 指定 Dockerfile 路径-->
#${project.basedir} 是一个Maven变量,它代表项目的根目录路径。在Maven构建过程中,
# ${project.basedir}会被解析为项目根目录的实际路径。
<dockerDirectory>${project.basedir}</dockerDirectory>

<!-- 指定远程 docker api地址,其中指定的ip地址是远程主机的ip地址,
2375是Docker监听的端口-->
<dockerHost>http://192.168.44.130:2375</dockerHost>
<!-- 这里是复制 jar 包到 docker 容器指定目录配置 -->
<resources>
<resource>
# <targetPath>:这是指定资源在Docker容器中的目标路径。在这里,/表示根目录,即将资源复制到容
# 器的根目录。

# <directory>:这是指定资源所在的目录。${project.build.directory}是一个Maven变量,它代表项
# 目构建的输出目录,通常是target目录。这意味着插件将从${project.build.directory}目录中寻找资源。

# <include>:这是指定要包含在Docker容器中的jar包的文件名。${project.build.finalName}.jar是
# 一个Maven变量,它代表项目构建的最终名称,通常是项目的名称加上版本号和构建时间。这个变量将被
# 解析为实际的jar包文件名。

# 因此,这段代码的作用是将${project.build.directory}/${project.build.finalName}.jar这个
# jar包复制到Docker容器的根目录(/)下。
<targetPath>/</targetPath>
<!--jar 包所在的路径 此处配置的 即对应 target 目录-->
<directory>${project.build.directory}</directory>
<!-- 需要包含的 jar包 ,这里对应的是 Dockerfile中添加的文件名 -->
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>

Dockerfile的书写:位置在项目根路径下:

1
2
3
4
5
6
7
8
9
10
11
12
FROM openjdk:17
# 作者信息
LABEL maintainer="reda"
# 挂载临时目录
VOLUME /tmp
# 将jar包添加到容器中并更名
COPY ./target/DockerDome-0.0.1-SNAPSHOT.jar pms.jar
# 运行jar
RUN sh -c 'touch /pms.jar'
# 容器启动命令

ENTRYPOINT [ "java", "-jar", "/pms.jar" ]

Dockerfile:

由于制作镜像的过程中,需要逐层处理和打包,比较复杂,所以Docker就提供了自动打包镜像的功能。我们只需要将打包的过程,每一层要做的事情用固定的语法写下来,交给Docker去执行即可。
而这种记录镜像结构的文件就称为Dockerfile,其对应的语法可以参考官方文档:
https://docs.docker.com/engine/reference/builder/
其中的语法比较多,比较常用的有:

指令 说明 示例
FROM 指定基础镜像 FROM centos:6
ENV 设置环境变量,可在后面指令使用 ENV key value
COPY 拷贝本地文件到镜像的指定目录 COPY ./xx.jar /tmp/app.jar
RUN 执行Linux的shell命令,一般是安装过程的命令 RUN yum install gcc
EXPOSE 指定容器运行时监听的端口,是给镜像使用者看的 EXPOSE 8080
ENTRYPOINT 镜像中应用的启动命令,容器运行时调用 ENTRYPOINT java -jar xx.jar

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 指定基础镜像
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"]

同学们思考一下:以后我们会有很多很多java项目需要打包为镜像,他们都需要Linux系统环境、JDK环境这两层,只有上面的3层不同(因为jar包不同)。如果每次制作java镜像都重复制作前两层镜像,是不是很麻烦。
所以,就有人提供了基础的系统加JDK环境,我们在此基础上制作java镜像,就可以省去JDK的配置了:

1
2
3
4
5
6
7
8
9
# 基础镜像
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文件写好以后,就可以利用命令来构建镜像了。
image.png
将课前资料提供的docker-demo.jar包以及Dockerfile拷贝到虚拟机的/root/demo目录:
image.png

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

命令说明:

  • docker build : 就是构建一个docker镜像
  • -t docker-demo:1.0 :-t参数是指定镜像的名称(repository和tag)
  • . : 最后的点是指构建时Dockerfile所在路径,由于我们进入了demo目录,所以指定的是.代表当前目录,也可以直接指定Dockerfile目录:
1
2
# 直接指定Dockerfile目录
docker build -t docker-demo:1.0 /root/demo

运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1.创建并运行容器
docker run -d --name dd -p 8080:8080 docker-demo:1.0
# 2.查看容器
dps
# 结果
CONTAINER ID IMAGE PORTS STATUS NAMES
78a000447b49 docker-demo:1.0 0.0.0.0:8080->8080/tcp, :::8090->8090/tcp Up 2 seconds dd
f63cfead8502 mysql 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp Up 2 hours mysql

# 3.访问
curl localhost:8080/hello/count
# 结果:
<h5>欢迎访问黑马商城, 这是您第1次访问<h5>

网络:

13-Docker网络

  • 容器的网络IP其实是一个虚拟的IP,其值并不固定与某一个容器绑定,如果我们在开发时写死某个IP,而在部署时很可能MySQL容器的IP会发生变化,连接会失败。
  • 自定义网络
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 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
  • 在自定义网络中,可以给容器起多个别名,默认的别名是容器名本身
  • 在同一个自定义网络中的容器,可以通过别名互相访问
  • docker安装并启动服务后,会在宿主机中添加一个虚拟网卡。
  • 作用:
    • 容器间的互联和通信以及端口映射
    • 容器IP变动时候可以通过服务名直接网络通信而不受到影响

Docker 网络模式

网络模式 简介 使用方式
bridge 为每一个容器分配、设置IP等,并将容器连接到一个docker0
虚拟网桥,默认为该模式
--network bridge
host 容器将不会虚拟出自己的网卡、配置自己的IP等,而是使用宿主机的IP和端口 --network host
none 容器有独立的 Network namespace,但并没有对齐进行任何网络设置,如分配veth pari
和 网桥连接、IP等
--network none
container 新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP、端口范围等 --network container:NAME或者容器ID

docker0

Docker 服务默认会创建一个docker0网桥(其上有一个docker0内部接口),该桥接网络的名称为 docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。
Docker默认指定了docker0接口的IP地址和子网掩码,让主机和容器之间可以通过网桥互相通信。

Docker可视化管理工具:

1Panel:

  • 设置云服务器的安全组放行其端口
  • 跟着下面的文档安装即可:

在线安装 - 1Panel 文档

docker-compose

docker-copose 介绍

14-Docker-compose容器编排

  • docker-compose 是一个容器编排工具(自动化部署、管理);
  • 它用来在单台 Linux 服务器上运行多个 Docker 容器;
  • docker-compose 使用YAML文件来配置所有需要运行的 Docker 容器,该 YAML 文件的默认名称为 docker-compose.yml

docker-compose 安装

1
2
3
4
curl -L "https://github.com/docker/compose/releases/download/v2.18.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
docker-compose version

使用 docker-compose 启动一个容器

1
2
3
4
5
6
7
8
9
version: '2.1'
services:
nginx:
image: nginx:latest
container_name: nginx_test
ports:
- 8080:80
volumes:
- /opt/nginx:/opt/nginx/html

启动容器
在 docker-compose 所在目录执行

1
docker compose up -d

Dockerdocker-compose 命令总结

启动容器

1
docker-compose up -d

停止容器

1
docker-compose down

重启容器

1
docker-compose restart

重载 docker-compose.yml

1
docker-compose up --force-recreate -d

docker-compose 创建多个容器

使用 docker-compose 启动 Nginx 和 Redis 两个容器:
docker-compose.yml 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
version: '2.1'
services:

nginx:
image: nginx:latest
container_name: nginx_host1
ports:
- 8081:80
volumes:
- /opt/nginx:/opt/nginx/html
networks:
- host1-network

redis:
image: redis:latest
container_name: redis_host1
ports:
- 63790:6379
networks:
- host1-network

networks:
host1-network:
driver: bridge
ipam:
driver: default
config:
- subnet: 192.168.11.0/24
gateway: 192.168.11.254

参数:
networks 定义容器网络,host1-network 为定义的网络名称,
config 网络配置,subnet 代表网段,gateway 代表网关。
执行创建命令

1
docker-compose up -d

可以看到成功创建了 Nginx 和 Redis 两个容器

可以进入 nginx_host1 容器查看一下端口和 IP

上图可见,nginx_host1 的 IP 为:192.168.11.2 ,符合 docker-compose 中定义的 192.168.11.0/24 网段;
如果访问 Redis 可以直接使用docker-compose 定义的 redis_host1 容器名访问即可。
12-Docker发布微服务

容器启动顺序:

depends_on只能保证容器的启动和销毁顺序,不能确保依赖的容器是否ready。

1
2
3
4
5
6
7
8
9
10
11
version: "3.9"
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres

在这个例子中,depends_on只能保证web容器在dbredis之后启动,不会关注他们的状态是否启动完成或准备就绪。
要确保应用服务在数据库初始化完成后再启动,需要配合[condition](https://docs.docker.com/compose/compose-file/#depends_on)[healthcheck](https://docs.docker.com/compose/compose-file/#healthcheck)使用。

1
2
3
4
5
6
7
8
9
10
11
12
services:
web:
build: .
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
redis:
image: redis
db:
image: postgres

ondition有三种状态:
service_started容器已启动
service_healthy容器处于健康状态
service_completed_successfully容器执行完成且成功退出(退出状态码为0)
我们来改造一下我们自己的docker-compose.yaml文件,完整例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
services: 

ruoyi-app:
# docker run --name ruoyi-app \
# -p 8080:8080 \
# --network ruoyi-net \
# -v /home/app/ruoyi-admin.jar:/usr/local/src/ruoyi-admin.jar \
# -d openjdk:8u342-jre \
# java -jar /usr/local/src/ruoyi-admin.jar
image: openjdk:8u342-jre
restart: always
ports:
- 8080:8080
networks:
- ruoyi-net
volumes:
- /home/app/ruoyi-admin.jar:/usr/local/src/ruoyi-admin.jar
command: [ "java", "-jar", "/usr/local/src/ruoyi-admin.jar" ]
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
depends_on:
ruoyi-db:
condition: service_healthy

ruoyi-db:
# docker run --name ruoyi-db -p 3303:3306 \
# --network ruoyi-net \
# -v ruoyi-data:/var/lib/mysql \
# -v /home/app/sql:/docker-entrypoint-initdb.d \
# -e MYSQL_DATABASE=ry \
# -e MYSQL_ROOT_PASSWORD=123456 \
# -d mysql:5.7 \
# --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --skip-character-set-client-handshake
image: mysql:5.7
environment:
- MYSQL_DATABASE=ry
- MYSQL_ROOT_PASSWORD=123456
volumes:
- ruoyi-data:/var/lib/mysql
- /home/app/sql:/docker-entrypoint-initdb.d
networks:
- ruoyi-net
command:
[
"--character-set-server=utf8mb4",
"--collation-server=utf8mb4_unicode_ci",
"--skip-character-set-client-handshake"
]
healthcheck:
test: ["CMD", 'mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', '-p$$MYSQL_ROOT_PASSWORD']
interval: 10s
timeout: 5s
retries: 5
start_period: 10s

volumes:
ruoyi-data:

networks:
ruoyi-net: