image-20240324201829664

Docker的安装

Mac

brew installl docker安装Docker Desktop

打开docker图形界面->settings->Docker Engine->添加阿里云镜像

示例:部署MySQL

1
2
3
4
5
6
docker run -d \
--name mysql \
-p 3307:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123 \
mysql

-d:让容器在后台运行

--name:给容器起个名字

-p 3306:3306:端口映射 宿主机端口:容器端口【连接要连接宿主机端口】

-e:环境变量:KEY=VALUEE 来设置环境变量

mysql:5.7:指定运行的镜像的名字:版本

docker run是一条龙服务,会先检查本地镜像是否存在,然后拉取,然后创建容器

常见命令

image-20240322233738345

docker pull:从镜像仓库拉取镜像到本地

docker build:创建自定义镜像

docker push:把镜像推到镜像仓库

docker images:查看本地镜像

docker rmi:删除本地镜像

docker run:创建并运行容器

docker stop:停止容器(并不会删除容器,只是停止镜像线程)

docker start:启动容器

docker ps:查看当前容器的运行状态

1
2
3
4
5
# 也可以加格式化方式访问,格式会更加清爽
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"

# 可以设置命令别名简化
dps

docker ps -a:查看当前所有所有容器,包括stop的容器

docker rm:删除容器

docker logs:查看容器运行的日志

docker exec进入容器内部

1
2
# 进入mysql容器的bash窗口
docker exec -t mysql bash

挂载

数据卷挂载

数据卷(volume)是一个虚拟目录,是容器内目录宿主机目录之间映射的桥梁

以Nginx为例,我们知道Nginx中有两个关键的目录:

  • html:放置一些静态资源
  • conf:放置配置文件

image-20240324144926392

注意:容器与数据卷的挂载要在创建容器时配置,对于创建好的容器,是不能设置数据卷的。而且创建容器的过程中,数据卷会自动创建

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
# 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 1228 2021 50x.html
-rw-r--r--. 1 root root 615 1228 2021 index.html

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

本地目录挂载

可以发现,数据卷的目录结构较深,如果我们去操作数据卷目录会不太方便。在很多情况下,我们会直接将容器目录与宿主机指定目录挂载。挂载语法与数据卷类似:

1
2
3
4
# 挂载本地目录
-v 本地目录:容器内目录
# 挂载本地文件
-v 本地文件:容器内文件

注意:本地目录或文件必须以 /./开头,如果直接以名字开头,会被识别为数据卷名而非本地目录名。

1
2
-v mysql:/var/lib/mysql # 会被识别为一个数据卷叫mysql,运行时会自动创建这个数据卷
-v ./mysql:/var/lib/mysql # 会被识别为当前目录下的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
# 1.删除原来的MySQL容器
docker rm -f mysql


# 3.创建并运行新mysql容器,挂载本地目录
docker run -d \
--name mysql \
-p 3307:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=zrh015658 \
-v /Users/zrh/DockerFile/mysql/data:/var/lib/mysql \
-v /Users/zrh/DockerFile/mysql/conf:/etc/mysql/conf.d \
-v /Users/zrh/DockerFile/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

自定义镜像

镜像文件不是随意堆放的,而是按照操作的步骤分层叠加而成,每一层形成的文件都会单独打包并标记一个唯一id,称为Layer)。这样,如果我们构建时用到的某些层其他人已经制作过,就可以直接拷贝使用这些层,而不用重复制作。

Dockerfile

  1. 镜像打包

由于制作镜像的过程中,需要逐层处理和打包,比较复杂,所以Docker就提供了自动打包镜像的功能。我们只需要将打包的过程,每一层要做的事情用固定的语法写下来,交给Docker去执行即可。

而这种记录镜像结构的文件就称为Dockerfile,其对应的语法可以参考官方文档:

例如,要基于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"]
  1. 构建镜像

在/root/demo里准备个jar包及对应的Dockerfile

1
2
3
4
# 直接指定Dockerfile目录
docker build -t docker-demo:1.0 /root/demo
# 当前文件夹
docker build -t docker-demo:1.0 .
  1. 创建容器运行镜像
1
2
# 1.创建并运行容器
docker run -d --name dd -p 8080:8080 docker-demo:1.0

网络互联

而Java项目往往需要访问其它各种中间件,例如MySQL、Redis等。现在,我们的容器之间能否互相访问呢

可以互联,但是,容器的网络IP其实是一个虚拟的IP,其值并不固定与某一个容器绑定,如果我们在开发时写死某个IP,而在部署时很可能MySQL容器的IP会发生变化,连接会失败。所以,我们必须借助于docker的网络功能来解决这个问题:

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

项目部署

分别部署

一般来说,项目会多环境开发:

image-20240324180928266

其中的application-dev.yaml是部署到开发环境的配置,application-local.yaml是本地运行时的配置

image-20240324182046200

查看application.yaml,你会发现其中的JDBC地址并未写死,而是读取变量

image-20240324182020122

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

部署完后端,部署前端,Nginx,MySQL等….

关联部署

DockerCompose

示例:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
version: "3.8"

services:
# MySQL镜像
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容器的服务
- mysql
# Nginx镜像
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
1
2
# 在当前yml文件的位置启动
docker compose up -d