avatar


Docker-1.基础

简介

Docker,一种容器技术。旨在解决运行环境和配置问题,方便做持续集成,有助于整体发布。

安装

配置Docker的yum库

  1. 安装yum工具
    1
    yum install -y yum-utils device-mapper-persistent-data lvm2
  2. 配置Docker的yum源
    1
    2
    yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
  3. 更新yum,建立缓存
    1
    yum makecache fast

安装Docker

1
yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

启动和校验

  • 启动:systemctl start docker
  • 停止:systemctl stop docker
  • 重启:systemctl restart docker
  • 查看状态:systemctl status docker
  • 开机自启:systemctl enable docker

配置镜像加速

/etc/docker新建文件daemon.json,内容如下:

1
2
3
4
5
{
"registry-mirrors": [
"https://docker.m.daocloud.io"
]
}

然后:

  1. 重新加载配置:systemctl daemon-reload
  2. 重启Docker:systemctl restart docker

关于docker.m.daocloud.io,可以参考如下链接
https://github.com/DaoCloud/public-image-mirror

开始

我们基于Docker安装部署MySQL。

示例代码:

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

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Unable to find image 'mysql:latest' locally
latest: Pulling from library/mysql
2c0a233485c3: Pull complete
cb5a6a8519b2: Pull complete
570d30cf82c5: Pull complete
a841bff36f3c: Pull complete
80ba30c57782: Pull complete
5e49e1f26961: Pull complete
ced670fc7f1c: Pull complete
0b9dc7ad7f03: Pull complete
cd0d5df9937b: Pull complete
1f87d67b89c6: Pull complete
Digest: sha256:0255b469f0135a0236d672d60e3154ae2f4538b146744966d96440318cc822c6
Status: Downloaded newer image for mysql:latest
d1e3d4945b35a5d28922d258f918b60a0af0934ad53a3c54c80978bc3be469ad

解释说明:

  • Docker首先查找本地的"mysql",在本地没有后,再从"library/mysql"下载(Pulling)。
  • 上述过程,就是自动搜索下载镜像,然后创建并运行容器。
  • 上述命令,已经把MySQL安装部署完毕。

命令解释:

  • docker run -d
    创建并运行一个容器,-d是让容器以后台进程运行。
  • --name mysql
    给容器起个名字,在本文是"mysql"。
  • -p 3306:3306
    设置端口映射,-p 宿主机端口:容器内端口
  • -e TZ=Asia/Shanghai-e MYSQL_ROOT_PASSWORD=123
    配置容器内进程运行时的一些参数。
    格式:-e KEY=VALUEKEYVALUE都由容器内进程决定
  • mysql,镜像名称,Docker会根据这个名字搜索并下载镜像。
    REPOSITORY:TAG,例如"mysql:8.0",其中REPOSITORY可以理解为镜像名,TAG是版本号。
    在未指定TAG的情况下,默认是最新版本,也就是mysql:latest
  • 镜像的名称不是任意的,而是要到DockerRegistry中寻找。
  • 镜像运行时的配置也不是任意的,要参考镜像的帮助文档。

这些在DockerHub网站或者软件的官方网站中都能找到。

这里下载的不是安装包,而是镜像(image)。这个镜像中不仅包含了MySQL本身,还包含了其运行所需要的环境、配置、系统级函数库。因此MySQL在运行时就有独立的环境,就可以跨系统运行,也不需要手动再次配置环境了。这套独立运行的隔离环境我们称为容器(container)。
我们甚至可以为一个镜像运行多个容器,例如在一台机器上,运行两个MySQL镜像的容器。

Docker官方提供了一个专门管理、存储镜像的网站,并对外开放了镜像上传、下载的权利。各大软件公司也在这个网站发布镜像。
https://hub.docker.com

Docker

我们在安装完Docker后,会启动一个Docker的服务,是我们通过systemctl start docker启动的那个服务;然后我们输入命令docker run,会通过Docker服务,去镜像仓库中寻找MySQL镜像,拉取到本地;最后,基于镜像运行容器。

常见命令

命令

命令 说明 文档地址
docker pull 拉取镜像 docker pull
docker push 推送镜像到DockerRegistry docker push
docker images 查看本地镜像 docker images
docker rmi 删除本地镜像 docker rmi
docker run 创建并运行容器(不能重复创建) docker run
docker stop 停止指定容器 docker stop
docker start 启动指定容器 docker start
docker restart 重新启动容器 docker restart
docker rm 删除指定容器 docker rm
docker ps 查看容器 docker ps
docker logs 查看容器运行日志 docker logs
docker exec 进入容器 docker exec
docker save 保存镜像到本地压缩文件 docker save
docker load 加载本地压缩文件到镜像 docker load
docker inspect 查看容器详细信息 docker inspect

命令之间的关系如下:

命令

案例

在本文,我们创建一个nginx容器。
步骤如下:

  1. 在DockerHub查看nginx镜像仓库及相关信息
    https://hub.docker.com/_/nginx
  2. 拉取nginx镜像
    1
    docker pull nginx
  3. 查看镜像
    1
    docker images
    运行结果:
    1
    2
    3
    REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
    nginx latest f876bfc1cc63 4 weeks ago 192MB
    mysql latest 56a8c14e1404 2 months ago 603MB
  4. 创建并运行nginx容器
    1
    docker run -d --name nginx -p 80:80 nginx
  5. 查看运行中容器
    示例代码:
    1
    docker ps
    运行结果:
    1
    2
    3
    CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                                                  NAMES
    ae50fcc4e066 nginx "/docker-entrypoint.…" 20 seconds ago Up 19 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp nginx
    1c397faed580 mysql "docker-entrypoint.s…" 4 days ago Up 4 days 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp mysql
  6. 访问网页
    访问网页
  7. 停止容器
    1
    docker stop nginx
  8. 查看所有容器
    示例代码:
    1
    docker ps -a
    运行结果:
    1
    2
    3
    CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS                     PORTS                                                  NAMES
    ae50fcc4e066 nginx "/docker-entrypoint.…" 5 minutes ago Exited (0) 5 seconds ago nginx
    1c397faed580 mysql "docker-entrypoint.s…" 4 days ago Up 4 days 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp mysql
  9. 再次启动nginx容器
    示例代码:
    1
    docker start nginx
  10. 查看容器详细信息
    示例代码:
    1
    docker inspect nginx
  11. 查看容器日志
    1
    2
    # 查看MySQL这个容器的日志
    docker logs mysql
    与通过tail查看日志类似,可以加上-f参数,docker logs -f mysql
  12. 进入nginx容器,再执行exit退出容器。
    1
    docker exec -it nginx bash
    • exec:执行
    • -it:添加一个可输入的终端
    • nginx:容器名
    • bash:命令行交互
  13. 进入MySQL容器,执行mysql -uroot -p
    1
    docker exec -it mysql mysql -uroot -p
  14. 删除容器
    1
    docker rm nginx
    -f强制删除容器(删除运行中的容器)
    1
    docker rm -f nginx

数据卷

引例

容器是隔离环境,容器内程序的文件、配置、运行时产生的容器都在容器内部。

那么,如果我们要读写容器内的文件呢?例如:

  • 如果要升级MySQL版本,需要销毁旧容器,那么数据岂不是跟着被销毁了?
  • MySQL、nginx容器运行后,如果需要修改其中的某些配置该怎么办?
  • 想要让nginx代理我们的静态资源怎么办?

虽然我们进入容器内部,进行各种操作。但总归是不方便。

什么是数据卷

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

以nginx为例,我们知道nginx中有两个关键的目录:html(存放静态资源)、(conf)存放配置文件。

我们利用数据卷将两个目录与宿主机目录关联,方便我们操作。

数据卷

在上图中:

  • 我们创建了两个数据卷:confhtml
  • nginx容器内部的conf目录html目录分别与两个数据卷关联。
  • 而数据卷confhtml分别指向了宿主机的/var/lib/docker/volumes/conf/_data目录和/var/lib/docker/volumes/html/_data目录。

这样一来,容器内的confhtml目录就与宿主机的confhtml目录关联起来,我们称之为挂载。

此时,我们操作宿主机的/var/lib/docker/volumes/html/_data就是在操作容器内的/usr/share/nginx/html目录。
只要我们将静态资源放入宿主机对应目录,就可以被nginx代理了。

/var/lib/docker/volumes是默认的存放所有容器数据卷的目录,其下再根据数据卷名称创建新目录,格式为/数据卷名/_data

数据卷命令

命令 说明 文档地址
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

注意:

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

数据卷案例

数据卷挂载(nginx)

首先创建容器并指定数据卷,注意通过-v参数来指定数据卷

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

-v html:/usr/share/nginx/html,冒号左侧的是数据卷名称,冒号右侧是容器内目录。

查看数据卷,示例代码:

1
docker volume ls

运行结果:

1
2
3
DRIVER    VOLUME NAME
local a6e07ecc9124df7e8f98ef4c5af92d201ddf8a8f700288a7151af2a024141d3e
local html

查看数据卷详情,示例代码:

1
docker volume inspect html

运行结果:

1
2
3
4
5
6
7
8
9
10
11
[
{
"CreatedAt": "2024-12-28T23:41:31-08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/html/_data",
"Name": "html",
"Options": null,
"Scope": "local"
}
]

然后,我们修改宿主机的/var/lib/docker/volumes/html/_data/index.html,会发现nginx部署的静态网页的内容也被修改了。

匿名数据卷(MySQL)

我们查看MySQL容器详细信息,docker inspect mysql,关注其中.Config.Volumes部分和.Mounts部分。

示例代码:

1
docker inspect mysql

.Config.Volumes部分:

1
2
3
4
5
"Config": {
"Volumes": {
"/var/lib/mysql": {}
},
},

.Mounts部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
"Mounts": 
[
{
"Type": "volume",
"Name": "73fb45ea40970faca937fa74ff3e21ad9aef6f53ea00e5fc5068b721f61f971a",
"Source": "/var/lib/docker/volumes/73fb45ea40970faca937fa74ff3e21ad9aef6f53ea00e5fc5068b721f61f971a/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],

解释说明:

  • Name:数据卷名称。由于定义容器未设置容器名,这里的就是匿名卷自动生成的名字,一串hash值。
  • Source:宿主机目录。
  • Destination:容器内的目录。

上述配置是将容器内的/var/lib/mysql这个目录,与数据卷73fb45-XXXXXX挂载。于是在宿主机中就有了/var/lib/docker/volumes/73fb45-XXXXXX/_data
这个目录。这就是匿名数据卷对应的目录,其使用方式与普通数据卷没有差别。

挂载本地目录或文件

我们除了挂载数据卷,还可以挂载本地目录。

执行docker run命令时,使用-v 本地目录:容器内目录,即可完成本地目录挂载。

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

例如:
-v mysql:/var/lib/mysql,会被识别为一个数据卷叫mysql,运行时会自动创建这个数据卷。
-v ./mysql:/var/lib/mysql,会被识别为当前目录下的mysql目录,运行时如果不存在会创建目录。

创建并运行新的mysql容器,挂载本地目录

1
2
3
4
5
6
7
docker run -d \
--name mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123 \
-v ./mysql/data:/var/lib/mysql \
mysql

镜像

如果我们要部署一个Java项目,并将其打包为一个镜像该怎么做呢?

镜像结构

镜像之所以能让我们快速跨操作系统部署应用而忽略其运行环境、配置等,就是因为镜像中包含了程序运行需要的系统函数库、环境、配置、依赖。

自定义镜像本质就是依次准备好程序运行的基础环境、依赖、应用本身、运行配置等文件,并且打包。

例如,我们从零部署一个Java应用,大概步骤是:准备一个Linux服务、安装并配置JDK、上传Jar包、运行jar包。

同样的,我们打包镜像的步骤如下:

  1. 准备Linux运行环境
  2. 安装并配置JDK
  3. 拷贝jar包
  4. 配置启动脚本

Docker镜像

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

例如,我们拉取一个redis的镜像,示例代码:

1
docker pull redis

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
Using default tag: latest
latest: Pulling from library/redis
fd674058ff8f: Already exists
f3615eb0792b: Pull complete
e0b2e54213f5: Pull complete
d334c6665cc1: Pull complete
47cee545c70a: Pull complete
76f0f8a4aae4: Pull complete
4f4fb700ef54: Pull complete
4c9c306fe0ac: Pull complete
Digest: sha256:bb142a9c18ac18a16713c1491d779697b4e107c22a97266616099d288237ef47
Status: Downloaded newer image for redis:latest
docker.io/library/redis:latest

注意:Already exists

Dockerfile

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
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
22
23
24
25
26
27
28
# 指定基础镜像
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镜像,就可以省去JDK的配置了:

1
2
3
4
5
6
7
8
9
10
11
12
# 基础镜像
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"]

构建镜像

执行命令docker build -t docker-demo:1.0 ./,构建镜像

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

示例代码:

1
docker build -t docker-demo:1.0 ./

运行结果:

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
[+] Building 115.9s (8/8) FINISHED                                                                                                                                                                  docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 359B 0.0s
=> [internal] load metadata for docker.io/library/openjdk:11.0-jre-buster 1.8s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/3] FROM docker.io/library/openjdk:11.0-jre-buster@sha256:569ba9252ddd693a29d39e81b3123481f308eb6d529827a40c93710444e421b0 113.5s
=> => resolve docker.io/library/openjdk:11.0-jre-buster@sha256:569ba9252ddd693a29d39e81b3123481f308eb6d529827a40c93710444e421b0 0.0s
=> => sha256:569ba9252ddd693a29d39e81b3123481f308eb6d529827a40c93710444e421b0 549B / 549B 0.0s
=> => sha256:0b489110c503fc781fea676ea3550679969b5de8bd237c21eb5dca7077ef2869 7.52kB / 7.52kB 0.0s
=> => sha256:7e6a53d1988fa8e19db6bcfc96ee6783afb079c38dbe047528e691815d19a9fa 50.44MB / 50.44MB 103.0s
=> => sha256:4fe4e1c58b4af82939a918665dd1e7b5b636dd73c710b4bccb530edbb15470d2 7.86MB / 7.86MB 15.1s
=> => sha256:cc915d298757b72963f0d061cc16ca4925e9f4481446b87a5297b4043ffc8033 10.00MB / 10.00MB 20.3s
=> => sha256:fa46ae940938ca17b5634fac0d58da875f0d7c53688cb7a8a4d6ac47f658d4d3 1.58kB / 1.58kB 0.0s
=> => sha256:0f795594794cd5bee4c556ac9e51dde9dface10e4512f611fd067ad2a357d0bd 5.53MB / 5.53MB 25.7s
=> => sha256:6cd61a4b7a06678967e883d8b11485979d28989d5306ba06bf2c6b483c05b516 211B / 211B 20.3s
=> => sha256:62acc5f6f7aae46e03d13e9f65af350b1bca82d942b72a1c7ff81c012bd384ed 45.77MB / 45.77MB 111.7s
=> => extracting sha256:7e6a53d1988fa8e19db6bcfc96ee6783afb079c38dbe047528e691815d19a9fa 2.7s
=> => extracting sha256:4fe4e1c58b4af82939a918665dd1e7b5b636dd73c710b4bccb530edbb15470d2 0.3s
=> => extracting sha256:cc915d298757b72963f0d061cc16ca4925e9f4481446b87a5297b4043ffc8033 0.3s
=> => extracting sha256:0f795594794cd5bee4c556ac9e51dde9dface10e4512f611fd067ad2a357d0bd 0.2s
=> => extracting sha256:6cd61a4b7a06678967e883d8b11485979d28989d5306ba06bf2c6b483c05b516 0.0s
=> => extracting sha256:62acc5f6f7aae46e03d13e9f65af350b1bca82d942b72a1c7ff81c012bd384ed 1.6s
=> [internal] load build context 0.2s
=> => transferring context: 17.70MB 0.2s
=> [2/3] RUN ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo Asia/Shanghai > /etc/timezone 0.4s
=> [3/3] COPY docker-demo.jar /app.jar 0.0s
=> exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:b41763632aa49aba7f64c0000b54b9b7a9f3452add15f15192537a65f1c808fd 0.0s
=> => naming to docker.io/library/docker-demo:1.0 0.0s

查看镜像列表。示例代码:

1
docker images

运行结果:

1
2
3
4
REPOSITORY    TAG       IMAGE ID       CREATED              SIZE
docker-demo 1.0 b41763632aa4 About a minute ago 315MB
nginx latest f876bfc1cc63 4 weeks ago 192MB
mysql latest 56a8c14e1404 2 months ago 603MB

基于该镜像,创建并运行容器。示例代码:

1
docker run -d --name demo -p 8080:8080 docker-demo:1.0

查看容器,示例代码:

1
docker ps

运行结果:

1
2
3
4
CONTAINER ID   IMAGE             COMMAND                  CREATED          STATUS          PORTS                                                  NAMES
04463c09f05b docker-demo:1.0 "java -jar /app.jar" 19 seconds ago Up 18 seconds 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp demo
21762cf868c8 mysql "docker-entrypoint.s…" 37 minutes ago Up 37 minutes 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp mysql
f4085c8e18e3 nginx "/docker-entrypoint.…" 48 minutes ago Up 48 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp nginx

网络

bridge模式

默认情况下,所有容器都是以bridge方式连接到Docker的一个虚拟网桥。

《基于Java的后端开发入门:13.Servlet、Filter和Listener》,我们讨论过Use bridged networking(使用桥接网络),此时虚拟机相当于网络上的一台独立计算机,与主机一样,拥有一个独立的IP地址。

bridge

而且,同一个bridge下,容器是互通的。
如下:

  1. 我们查看下MySQL容器的详细信息,重点关注其中的网络IP地址Networks.bridge.IPAddress属性。
    示例代码:
    1
    docker inspect --format='{{range .NetworkSettings.Networks}}{{println .IPAddress}}{{end}}' mysql
    运行结果:
    1
    172.17.0.2
  2. 通过命令进入上文Java项目的容器,并通过命令检查。发现可以ping通。
    1
    2
    docker exec -it demo bash
    ping 172.17.0.2

引例

但是,容器的网络IP其实是一个虚拟的IP,其值并不固定与某一个容器绑定,如果我们在开发时写死某个IP,而在部署时很可能MySQL容器的IP会发生变化,连接会失败。

所以?自建DNS服务?修改HOST文件?

不用这么复杂,我么可以基于Docker的网络功能实现。

命令

官方文档:https://docs.docker.com/engine/reference/commandline/network

常用的有:

命令 说明 文档地址
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. 通过命令创建一个网络,示例代码:
    1
    docker network create kaka
  2. 然后我们执行ip addr,会发现多了一张虚拟网卡。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    【部分运行结果略】

    5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:91:f6:63:22 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
    valid_lft forever preferred_lft forever
    inet6 fe80::42:91ff:fef6:6322/64 scope link
    valid_lft forever preferred_lft forever

    【部分运行结果略】

    22: br-0e8626d168c6: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:95:dc:8d:b4 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global br-0e8626d168c6
    valid_lft forever preferred_lft forever
  3. 执行docker network ls,查看网络。
    1
    2
    3
    4
    5
    NETWORK ID     NAME      DRIVER    SCOPE
    3f1486bd98a7 bridge bridge local
    8c5822a2f9ef host host local
    0e8626d168c6 kaka bridge local
    91131376287b none null local
    • 其中,除了kaka以外,其它都是默认的网络。
  4. demo容器和mysql容器加入该网络。
    在加入网络时可以通过--alias给容器起别名。
    例如,mysql容器,指定别名为db,示例代码:
    1
    2
    docker network connect kaka mysql --alias db
    docker network connect kaka demo
  5. 进入demo容器,通过别名 db容器名 mysql,都能访问。

host模式

假如有这么一个现象,公司正在进行容器化改造。
比如,A服务和B服务有通信,A服务已经上了容器化,B服务还没有上容器化,此时A服务在Docker的bridge网段内,无法访问B服务。

这时候,可以考虑host模式。

默认情况下,docker使用的是bridge模式启动服务,如果使用host模式启动,Docker容器与宿主机共享同一个网络命名空间,即Docker容器将直接使用宿主机的网络。

docker run命令中,添加--network host,即可使用host模式。

DockerCompose

作用

通过上文的讨论,已经非常简化了我们的项目部署。
现在,我们部署一个简单且常规的现代JavaWeb项目,一般需要三个容器,MySQL、Java、nginx。
那么,可以更简单一些吗?

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

基本语法

Docker Compose

官方文档:https://docs.docker.com/compose/compose-file/compose-file-v3/

例如,我们通过docker run部署一个MySQL容器,示例代码:

1
2
3
4
5
6
7
8
docker run -d \
--name mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123 \
-v ./mysql/data:/var/lib/mysql \
--network kaka
mysql

如果用docker-compose.yml文件来定义,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
version: "3.8"

services:
mysql:
image: mysql
container_name: mysql
ports:
- "3306:3306"
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD:
volumes:
- "./mysql/data:/var/lib/mysql"
networks:
- new-net
networks:
new-net:
name: kaka
  • version: "3.8",DockerCompose的语法的版本。

对比如下:

docker run 参数 docker compose 指令 说明
--name container_name 容器名称
-p ports 端口映射
-e environment 环境变量
-v volumes 数据卷配置
--network networks 网络

基础命令

官方文档:https://docs.docker.com/compose/reference/

docker compose,整体语法:

1
docker compose [OPTIONS] [COMMAND]
  • OPTIONS,可选参数
    • -f,指定compose文件的路径和名称。
    • -p,指定project名称。project就是当前compose文件中设置的多个service的集合,是逻辑概念。
  • COMMAND,可选参数
    • up,创建并启动所有service容器。
    • down,停止并移除所有容器、网络。
    • ps,列出所有启动的容器。
    • logs,查看指定容器的日志。
    • stop,停止容器。
    • start,启动容器。
    • restart,重启容器。
    • top,查看运行的进程。
    • exec,在指定的运行中容器中执行命令。

案例

本文,我们以部署一个常规且简单的JavaWeb项目为例。
这个项目的前端通过nginx部署;后端是SpringBoot框架的,通过Java部署;数据库是MySQL。

Dockerfile:

1
2
3
4
5
6
7
8
9
10
11
12
# JDK8
FROM openjdk:8u342-jdk

# 设定时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 拷贝jar包
COPY ./client-0.0.1-SNAPSHOT.jar ./app.jar

# 入口
ENTRYPOINT ["java", "-jar", "app.jar"]

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
version: "3.8"

services:
mysql:
image: mysql
container_name: mysql
ports:
- "3306:3306"
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: 【密码】
volumes:
- "./mysql/data:/var/lib/mysql"
networks:
- lawllm-net
lawllm:
build:
context: .
dockerfile: Dockerfile
container_name: lawllm
ports:
- "8080:8080"
networks:
- lawllm-net
depends_on:
- mysql
nginx:
image: nginx
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- "./nginx/html:/usr/share/nginx/html"
depends_on:
- lawllm
networks:
- lawllm-net
networks:
lawllm-net:
name: lawllm-net

启动:

1
docker compose up -d

lawllm

文章作者: Kaka Wan Yifan
文章链接: https://kakawanyifan.com/12401
版权声明: 本博客所有文章版权为文章作者所有,未经书面许可,任何机构和个人不得以任何形式转载、摘编或复制。

留言板