Docker
Docker篇
由于每台服务器的运行环境不同,你写好的安装流程、部署脚本并不一定在每个服务器都能正常运行,经常会出错。这就给系统的部署运维带来了很多困难。
那么,有没有一种技术能够避免部署对服务器环境的依赖,减少复杂的部署流程呢?
答案是肯定的,这就是我们今天要学习的Docker技术。你会发现,有了Docker以后项目的部署如丝般顺滑,大大减少了运维工作量。
即便你对Linux不熟悉,你也能轻松部署各种常见软件、Java项目。
通过今天的学习,希望大家能达成下面的学习目标:
- 能看懂DockerCompose文件
- 能利用Docker部署常见软件
- 能利用Docker打包并部署Java应用
- 理解Docker数据卷的基本作用
1.快速入门
要想让Docker帮我们安装和部署软件,肯定要保证你的机器上有Docker. 由于大家的操作系统各不相同,安装方式也不同。为了便于大家学习,我们统一在CentOS的虚拟机中安装Docker,统一学习环境。
1.1安装docker
安装时可能出现无法安装的问题,参考这位大佬的解决方案
yum安装出现问题:
已解决:Cannot find a valid baseurl for repo: base/7/x86_64-CSDN博客
安装Docker出错:
参考视频:换源、安装docker、1panel_哔哩哔哩_bilibili
参考文档:CentOS7配置阿里yum源 超详细!!!https://developer.aliyun.com/article/1366034
1.1.1卸载旧版
首先如果系统中已经存在旧的Docker,则先卸载:
1 | yum remove docker \ |
1.1.2配置Docker的yum库
首先要安装一个yum工具
1 | sudo yum install -y yum-utils device-mapper-persistent-data lvm2 |
安装成功后,执行命令,配置Docker的yum源(已更新为阿里云源):
1 | sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo |
更新yum,建立缓存
1 | sudo yum makecache fast |
1.1.3安装Docker
最后,执行命令,安装Docker
1 | yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin |
1.1.4启动和校验
1 | #启动Docker |
1.1.5配置镜像加速
镜像地址可能会变更,如果失效可以百度找最新的docker镜像。
配置镜像步骤如下:
1 | #创建目录 |
1.2部署MySQL
在命令行输入下面的命令(建议采用CV大法):
1 | docker run -d \ |
运行效果如图:

MySQL安装完毕!通过任意客户端工具即可连接到MySQL.

当我们执行命令后,Docker做的第一件事情,是去自动搜索并下载了MySQL,然后会自动运行MySQL,我们完全不用插手。
而且,这种安装方式你完全不用考虑运行的操作系统环境,它不仅仅在CentOS系统是这样,在Ubuntu系统、macOS系统、甚至是装了WSL的Windows下,都可以使用这条命令来安装MySQL。
要知道,不同操作系统下其安装包、运行环境是都不相同的!如果是手动安装,必须手动解决安装包不同、环境不同的、配置不同的问题!
而使用Docker,这些完全不用考虑。就是因为Docker会自动搜索并下载MySQL。注意:这里下载的不是安装包,而是镜像。镜像中不仅包含了MySQL本身,还包含了其运行所需要的环境、配置、系统级函数库。因此它在运行时就有自己独立的环境,就可以跨系统运行,也不需要手动再次配置环境了。这套独立运行的隔离环境我们称为容器。
说明:
- 镜像:英文是image
- 容器:英文是container
总结一下:
Docker本身包含一个后台服务,我们可以利用Docker命令告诉Docker服务,帮助我们快速部署指定的应用。Docker服务部署应用时,首先要去搜索并下载应用对应的镜像,然后根据镜像创建并允许容器,应用就部署完成了。

1.3命令解读
利用Docker快速的安装了MySQL,非常的方便,不过我们执行的命令到底是什么意思呢?
1 | docker run -d \ |
解读:
docker run -d:创建并运行一个容器,-d则是让容器以后台进程运行
--name`` mysql: 给容器起个名字叫mysql,你可以叫别的```
-p 3306:3306
1
2
3
4
5
6
7
8
9
: 设置端口映射。
- **容器是隔离环境**,外界不可访问。但是可以**将****宿主机****端口****映射容器内到端口**,当访问宿主机指定端口时,就是在访问容器内的端口了。
- 容器内端口往往是由容器内的进程决定,例如MySQL进程默认端口是3306,因此容器内端口一定是3306;而宿主机端口则可以任意指定,一般与容器内保持一致。
- 格式: `-p 宿主机端口:容器内端口`,示例中就是将宿主机的3306映射到容器内的3306端口
- ```
-e TZ=Asia/Shanghai配置容器内进程运行时的一些参数
- 格式:
-e KEY=VALUE,KEY和VALUE都由容器内进程决定- 案例中,
TZ``=Asia/Shanghai是设置时区;MYSQL_ROOT_PASSWORD=123是设置MySQL默认密码```
mysql
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
73
74
75
76
77
78
79
80
设置镜像名称,Docker会根据这个名字搜索并下载镜像
- 格式:`REPOSITORY:TAG`,例如`mysql:8.0`,其中`REPOSITORY`可以理解为镜像名,`TAG`是版本号
- 在未指定`TAG`的情况下,默认是最新版本,也就是`mysql:latest`
## 2.Docker基础
接下来,我们来学习Docker使用的一些基础知识,为将来部署项目打下基础。具体用法可以参考Docker官方文档:
[Docker Docs](https://docs.docker.com/)
### 2.1.常见命令
首先我们来学习Docker中的常见命令
#### 2.1.1.命令介绍
其中,比较常见的命令有:
| **命令** | **说明** | **文档地址** |
| -------------- | ------------------------------ | ------------------------------------------------------------ |
| docker pull | 拉取镜像 | [docker pull](https://docs.docker.com/engine/reference/commandline/pull/) |
| docker push | 推送镜像到DockerRegistry | [docker push](https://docs.docker.com/engine/reference/commandline/push/) |
| docker images | 查看本地镜像 | [docker images](https://docs.docker.com/engine/reference/commandline/images/) |
| docker rmi | 删除本地镜像 | [docker rmi](https://docs.docker.com/engine/reference/commandline/rmi/) |
| docker run | 创建并运行容器(不能重复创建) | [docker run](https://docs.docker.com/engine/reference/commandline/run/) |
| docker stop | 停止指定容器 | [docker stop](https://docs.docker.com/engine/reference/commandline/stop/) |
| docker start | 启动指定容器 | [docker start](https://docs.docker.com/engine/reference/commandline/start/) |
| docker restart | 重新启动容器 | [docker restart](https://docs.docker.com/engine/reference/commandline/restart/) |
| docker rm | 删除指定容器 | [docs.docker.com](https://docs.docker.com/engine/reference/commandline/rm/) |
| docker ps | 查看容器 | [docker ps](https://docs.docker.com/engine/reference/commandline/ps/) |
| docker logs | 查看容器运行日志 | [docker logs](https://docs.docker.com/engine/reference/commandline/logs/) |
| docker exec | 进入容器 | [docker exec](https://docs.docker.com/engine/reference/commandline/exec/) |
| docker save | 保存镜像到本地压缩文件 | [docker save](https://docs.docker.com/engine/reference/commandline/save/) |
| docker load | 加载本地压缩文件到镜像 | [docker load](https://docs.docker.com/engine/reference/commandline/load/) |
| docker inspect | 查看容器详细信息 | [docker inspect](https://docs.docker.com/engine/reference/commandline/inspect/) |
用一副图来表示这些命令的关系:

#### 2.1.2.演示
以Nginx为例给大家演示上述命令。
需求:
- 在DockerHub中搜索Nginx镜像,查看镜像的名称
- 拉取Nginx镜像
- 查看本地镜像列表
- 创建并运行Nginx容器
- 查看容器
- 停止容器
- 再次启动容器
- 进入Nginx容器
- 删除容器

保存nginx.tar

删除nginx后,再通过load重新加载回来

创建并允许Nginx容器

#### 2.1.3.命令别名
给常用Docker命令起别名,方便我们访问:

然后,执行命令使别名生效source /root/.bashrc
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
73
74
75
76
77
测试:别名生效

### 2.2.数据卷
容器是隔离环境,容器内程序的文件、配置、运行时产生的容器都在容器内部,我们要读写容器内的文件非常不方便。大家思考几个问题:
- 如果要升级MySQL版本,需要销毁旧容器,那么数据岂不是跟着被销毁了?
- MySQL、Nginx容器运行后,如果我要修改其中的某些配置该怎么办?
- 我想要让Nginx代理我的静态资源怎么办?
因此,容器提供程序的运行环境,但是**程序运行产生的数据、程序运行依赖的配置都应该与容器****解耦**。
#### 2.2.1.什么是数据卷
**数据卷(volume)**是一个虚拟目录,是**容器内目录**与**宿主机****目录**之间映射的桥梁。
以Nginx为例,我们知道Nginx中有两个关键的目录:
- `html`:放置一些静态资源
- `conf`:放置配置文件
如果我们要让Nginx代理我们的静态资源,最好是放到`html`目录;如果我们要修改Nginx的配置,最好是找到`conf`下的`nginx.conf`文件。
但遗憾的是,容器运行的Nginx所有的文件都在容器内部。所以我们必须利用数据卷将两个目录与宿主机目录关联,方便我们操作。如图:

在上图中:
- 我们创建了两个数据卷:`conf`、`html`
- Nginx容器内部的`conf`目录和`html`目录分别与两个数据卷关联。
- 而数据卷conf和html分别指向了宿主机的`/var/lib/docker/volumes/conf/_data`目录和`/var/lib/docker/volumes/html/_data`目录
这样以来,容器内的`conf`和`html`目录就 与宿主机的`conf`和`html`目录关联起来,我们称为**挂载**。此时,我们操作宿主机的`/var/lib/docker/volumes/html/_data`就是在操作容器内的`/usr/share/nginx/html/_data`目录。只要我们将静态资源放入宿主机对应目录,就可以被Nginx代理了。
**小提示**:
`/var/lib/docker/volumes`这个目录就是默认的存放所有容器数据卷的目录,其下再根据数据卷名称创建新目录,格式为`/数据卷名/_data`。
**为什么不让容器目录直接指向****宿主机****目录呢**?
- 因为直接指向宿主机目录就与宿主机强耦合了,如果切换了环境,宿主机目录就可能发生改变了。由于容器一旦创建,目录挂载就无法修改,这样容器就无法正常工作了。
- 但是容器指向数据卷,一个逻辑名称,而数据卷再指向宿主机目录,就不存在强耦合。如果宿主机目录发生改变,只要改变数据卷与宿主机目录之间的映射关系即可。
不过,我们通过由于数据卷目录比较深,不好寻找,通常我们也**允许让容器直接与****宿主机****目录挂载而不使用数据卷**,具体参考2.2.3小节。
#### 2.2.2.数据卷命令
数据卷的相关命令有:
| **命令** | **说明** | **文档地址** |
| --------------------- | -------------------- | ------------------------------------------------------------ |
| docker volume create | 创建数据卷 | [docker volume create](https://docs.docker.com/engine/reference/commandline/volume_create/) |
| docker volume ls | 查看所有数据卷 | [docs.docker.com](https://docs.docker.com/engine/reference/commandline/volume_ls/) |
| docker volume rm | 删除指定数据卷 | [docs.docker.com](https://docs.docker.com/engine/reference/commandline/volume_prune/) |
| docker volume inspect | 查看某个数据卷的详情 | [docs.docker.com](https://docs.docker.com/engine/reference/commandline/volume_inspect/) |
| docker volume prune | 清除数据卷 | [docker volume prune](https://docs.docker.com/engine/reference/commandline/volume_prune/) |
**注意**:容器与数据卷的挂载要在创建容器时配置,对于创建好的容器,是不能设置数据卷的。而且**创建容器的过程中,数据卷会自动创建**。
教学**演示环节**:
#### 案例一演示一下nginx的html目录挂载



#### 案列二:演示一下MySQL的匿名数据卷
1.查看MySQL容器详细信息
docker inspect mysql
关注其中.Config.Volumes部分和.Mounts部分
1
2
3
我们关注两部分内容,第一是`.Config.Volumes`部分:{
“Config”: {
// … 略
“Volumes”: {"/var/lib/mysql": {}}
// … 略
}
}
1
2
3
4
5
6
7
8
9


可以发现这个容器声明了一个本地目录,需要挂载数据卷,但是**数据卷未定义**。这就是匿名卷。
然后,我们再看结果中的`.Mounts`部分:{
“Mounts”: [
{"Type": "volume", "Name": "ed27d03813337603def151291209582bc1b420c01f5a268b4cf7a47171a4f128", "Source": "/var/lib/docker/volumes/ed27d03813337603def151291209582bc1b420c01f5a268b4cf7a47171a4f128/_data", "Destination": "/var/lib/mysql", "Driver": "local",}
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13

可以发现,其中有几个关键属性:
- Name:数据卷名称。由于定义容器未设置容器名,这里的就是匿名卷自动生成的名字,一串hash值。
- Source:宿主机目录
- Destination : 容器内的目录
上述配置是将容器内的`/var/lib/mysql`这个目录,与数据卷`ed27d03813337603def151291209582bc1b420c01f5a268b4cf7a47171a4f128`挂载。于是在宿主机中就有了`/var/lib/docker/volumes/ed27d03813337603def151291209582bc1b420c01f5a268b4cf7a47171a4f128/_data`这个目录。这就是匿名数据卷对应的目录,其使用方式与普通数据卷没有差别。
接下来,可以查看该目录下的MySQL的data文件:ls -l /var/lib/docker/volumes/29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f/_data
1
2
3
4
5
6
7
注意:每一个不同的镜像,将来创建容器后内部有哪些目录可以挂载,可以参考DockerHub对应的页面
#### 2.2.3.挂载本地目录或文件
可以发现,数据卷的目录结构较深,如果我们去操作数据卷目录会不太方便。在很多情况下,我们会直接将容器目录与宿主机指定目录挂载。挂载语法与数据卷类似:挂载本地目录
-v 本地目录:容器内目录
挂载本地文件
-v 本地文件:容器内文件
1
2
3
4
5
**注意**:本地目录或文件必须以 `/` 或 `./`开头,如果直接以名字开头,会被识别为数据卷名而非本地目录名。
例如:-v mysql:/var/lib/mysql # 会被识别为一个数据卷叫mysql,运行时会自动创建这个数据卷
-v ./mysql:/var/lib/mysql # 会被识别为当前目录下的mysql目录,运行时如果不存在会创建目录
1
2
3
4
5
6
7
#### **教学演示**,删除并重新创建mysql容器,并完成本地目录挂载:
- 挂载`/root/mysql/data`到容器内的`/var/lib/mysql`目录
- 挂载`/root/mysql/init`到容器内的`/docker-entrypoint-initdb.d`目录(初始化的SQL脚本目录)
- 挂载`/root/mysql/conf`到容器内的`/etc/mysql/conf.d`目录(这个是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 \
mysql4.查看root目录,可以发现~/mysql/data目录已经自动创建好了
ls -l mysql
结果:
总用量 4drwxr-xr-x. 2 root root 20 5月 19 15:11 confdrwxr-xr-x. 7 polkitd root 4096 5月 19 15:11 datadrwxr-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没有问题
6.查看数据
6.1.查看数据库
show databases;
6.2.切换到hmall数据库
use hmall;
6.3.查看表
show tables;
1 |
|
基础镜像
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”]1
2
3
4
5
6
7
8
9
10
11
12
13
是不是简单多了。
### 2.3.3.构建镜像
当Dockerfile文件写好以后,就可以利用命令来构建镜像了。
在课前资料中,我们准备好了一个demo项目及对应的Dockerfile:
首先,我们将课前资料提供的`docker-demo.jar`包以及`Dockerfile`拷贝到虚拟机的`/root/demo`目录:
然后,执行命令,构建镜像:
进入镜像目录
cd /root/demo
开始构建
docker build -t docker-demo:1.0 .1
2
3
4
5
6
7
8
9
10
11
12
13
命令说明:
- `docker build `: 就是构建一个docker镜像
- `-t docker-demo:1.0` :`-t`参数是指定镜像的名称(`repository`和`tag`)
最后的点是指构建时Dockerfile所在路径,由于我们进入了demo目录,所以指定的是.代表当前目录,也可以直接指定Dockerfile目录:

查看镜像列表:
查看镜像列表:
docker images
结果
REPOSITORY TAG IMAGE ID CREATED SIZEdocker-demo 1.0 d6ab0b9e64b9 27 minutes ago 327MBnginx latest 605c77e624dd 16 months ago 141MBmysql latest 3218b38490ce 17 months ago 516MB1
2
3
然后尝试运行该镜像:
1.创建并运行容器
docker run -d —name dd -p 8080:8080 docker-demo:1.0
2.查看容器
dps
结果CONTAINER ID IMAGE PORTS STATUS NAMES78a000447b49 docker-demo:1.0 0.0.0.0:8080->8080/tcp, :::8090->8090/tcp Up 2 seconds ddf63cfead8502 mysql 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp Up 2 hours mysql
3.访问
curl localhost:8080/hello/count
结果:欢迎访问黑马商城, 这是您第1次访问
1 |
|
1.用基本命令,寻找Networks.bridge.IPAddress属性
docker inspect mysql
也可以使用format过滤结果
docker inspect —format=’‘ mysql
得到IP地址如下:
172.17.0.2
2.然后通过命令进入dd容器
docker exec -it dd bash
3.在容器内,通过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.053 ms64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.059 ms64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.058 ms
1 |
|
1.首先通过命令创建一个网络
docker network create hmall
2.然后查看网络
docker network ls
结果:
NETWORK ID NAME DRIVER SCOPE639bc44d0a87 bridge bridge local403f16ec62a2 hmall bridge local0dc0f72a0fbb host host localcd8d3e8df47b 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 ms64 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 ms64 bytes from mysql.hmall (172.18.0.2): icmp_seq=2 ttl=64 time=0.054 ms1
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
OK,现在无需记住IP地址也可以实现容器互联了。
**总结**:
- 在自定义网络中,可以给容器起多个别名,默认的别名是容器名本身
- 在同一个自定义网络中的容器,可以通过别名互相访问
## 3.项目部署
项目说明:
- hmall:商城的后端代码
- hmall-portal:商城用户端的前端代码
- hmall-admin:商城管理端的前端代码
部署的容器及端口说明:
| **项目** | **容器名** | **端口** | **备注** |
| ------------ | ---------- | ------------------ | ------------------- |
| hmall | hmall | 8080 | 黑马商城后端API入口 |
| hmall-portal | nginx | 18080 | 黑马商城用户端入口 |
| hmall-admin | 18081 | 黑马商城管理端入口 | |
| mysql | mysql | 3306 | 数据库 |
在正式部署前,我们先删除之前的nginx、dd两个容器:
docker rm -f nginx dd1
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
mysql容器中已经准备好了商城的数据,所以就不再删除了。
## 3.1.部署Java项目
`hmall`项目是一个maven聚合项目,使用IDEA打开`hmall`项目,查看项目结构如图:

我们要部署的就是其中的`hm-service`,其中的配置文件采用了多环境的方式:

其中的`application-dev.yaml`是部署到开发环境的配置,`application-local.yaml`是本地运行时的配置。
查看application.yaml,你会发现其中的JDBC地址并未写死,而是读取变量:

这两个变量在`application-dev.yaml`和`application-local.yaml`中并不相同:

在dev开发环境(也就是Docker部署时)采用了mysql作为地址,刚好是我们的mysql容器名,只要两者在一个网络,就一定能互相访问。
我们将项目打包:

结果:

将`hm-service`目录下的`Dockerfile`和`hm-service/target`目录下的`hm-service.jar`一起上传到虚拟机的`root`目录:

部署项目:
1.构建项目镜像,不指定tag,则默认为latest
docker build -t hmall .
2.查看镜像
docker images
结果
REPOSITORY TAG IMAGE ID CREATED SIZEhmall latest 0bb07b2c34b9 43 seconds ago 362MBdocker-demo 1.0 49743484da68 24 hours ago 327MBnginx latest 605c77e624dd 16 months ago 141MBmysql latest 3218b38490ce 17 months ago 516MB
3.创建并运行容器,并通过—network将其加入hmall网络,这样才能通过容器名访问mysql
docker run -d —name hmall —network hmall -p 8080:8080 hmall1
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
### 3.2.部署前端
`hmall-portal`和`hmall-admin`是前端代码,需要基于nginx部署。在课前资料中已经给大家提供了nginx的部署目录:

其中:
- `html`是静态资源目录,我们需要把`hmall-portal`以及`hmall-admin`都复制进去
- `nginx.conf`是nginx的配置文件,主要是完成对`html`下的两个静态资源目录做代理
我们现在要做的就是把整个nginx目录上传到虚拟机的`/root`目录下:

然后创建nginx容器并完成两个挂载:
- 把`/root/nginx/nginx.conf`挂载到`/etc/nginx/ng``inx.conf`
- 把`/root/nginx/html`挂载到`/usr/share/nginx/html`
由于需要让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 \
nginx1
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
测试,通过浏览器访问:http://你的虚拟机ip:18080

### 3.3.DockerCompose
大家可以看到,我们部署一个简单的java项目,其中包含3个容器:
- MySQL
- Nginx
- Java项目
而稍微复杂的项目,其中还会有各种各样的其它中间件,需要部署的东西远不止3个。如果还像之前那样手动的逐一部署,就太麻烦了。
而Docker Compose就可以帮助我们实现**多个相互关联的Docker容器的快速部署**。它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器。
### 3.3.1.基本语法
docker-compose.yml文件的基本语法可以参考官方文档:
https://docs.docker.com/compose/compose-file/compose-file-v3
docker-compose文件中可以定义多个相互关联的应用容器,每一个应用容器被称为一个服务(service)。由于service就是在定义某个应用的运行时参数,因此与`docker run`参数非常相似。

举例来说,用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
mysql1
2
3
如果用`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: hmall1
2
3
4
5
6
7
8
9
10
11
12
13
对比如下:
| **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: hmall1
2
3
4
5
6
7
8
9
### 3.3.2.基础命令
编写好docker-compose.yml文件,就可以部署项目了。常见的命令:
https://docs.docker.com/compose/reference
基本语法如下:
docker compose [OPTIONS] [COMMAND]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
其中,OPTIONS和COMMAND都是可选参数,比较常见的有:
| **类型** | **参数或指令** | **说明** |
| -------- | ------------------------------------------------------------ | --------------------------- |
| Options | -f | 指定compose文件的路径和名称 |
| -p | 指定project名称。project就是当前compose文件中设置的多个service的集合,是逻辑概念 | |
| 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
6.查看镜像
docker compose images
7.查看容器
docker compose ps
```
打开浏览器,访问:http://yourIp:8080