Docker

一、简介

1.Docker是什么?

​ Docker是一种容器技术,就像虚拟机,在自己的电脑中模拟出一台或多台子电脑,“子电脑”和“子电脑”之间,是相互隔离的,互不影响。

​ 容器技术,也是虚拟化技术,属于轻量级的虚拟化,因为虚拟机的占用空间更大,一般都需要几个G,启动也慢,而容器技术恰好没有这些缺点。它不需要虚拟出整个操作系统,因为容器内的应用直接运行在宿主机的内核中,所以它启动时间很快,几秒钟就能完成。

2.Docker可以做什么?

​ Docker可以让开发者构建应用程序时,将它与其依赖环境一起打包到一个容器中,然后很容易地发布和应用到任意平台中。

  • 可移植性:本地开发的项目想要放在服务器上,需要在服务器上再安装一次项目所依赖的环境,Docker将一整套环境封装成镜像,无需重复配置环境,解决运行环境不一致所导致的问题。这样就不会产生“本地运行没问题,可一到服务器上就不行了”的情况。
  • 隔离:不同的项目所依赖的环境不一样,如果把他们依赖的软件都安装在一个服务器上,不仅安装时间长,而且可能会有冲突。Docker容器使应用程序不仅彼此隔离,而且与底层系统隔离。

文档教程:https://docs.docker.com/

中文文档:https://vuepress.mirror.docker-practice.com/

仓库地址:https://hub.docker.com/

3.Docker的核心

Docker有3大核心:镜像、容器、仓库

Docker运行一个程序的过程: 去仓库镜像拉到本地,然后用一条命令把镜像运行起来,变成容器

镜像(Images)

​ 镜像是一个特殊的文件系统。它除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

​ 类似于Linux镜像文件(镜像),可以使用同一个镜像文件创建多个Linux系统(容器)。

​ 比如有一个Tomcat镜像,镜像是不能启动的,要使用run命令变成容器,服务/项目运行就是在容器中,当然一个镜像可以创建多个容器。

graph LR;
  Tomcat镜像--run-->Tomcat01容器
  Tomcat镜像--run-->Tomcat02容器
  Tomcat镜像--run-->Tomcat03容器

容器(Containers)

容器是运行程序的地方,里面运行着我们指定的应用,通过镜像来创建的。

镜像=类,容器=实例

仓库(Repository)

存放镜像的地方,和Git类似。

负责对Docker镜像进行管理的,最常用的Registry公开服务,是官方的Docker Hub,这也是默认的 Registry。阿里云等也都有自己的容器服务器,毕竟Docker是在国外的

二、安装Docker

1.环境查看

不同的操作系统安装方式也不同,这里为ubuntu https://www.runoob.com/docker/ubuntu-docker-install.html

1
2
3
4
5
6
7
8
9
10
#查看系统架构
root:~# uname -a
Linux iZbp1aq6c9kbbexg9cxsqiZ 4.4.0-93-generic #116-Ubuntu SMP Fri Aug 11 21:17:51 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
#查看系统信息
root:~# lsb_release -a
LSB Version: core-9.20160110ubuntu0.2-amd64:core-9.20160110ubuntu0.2-noarch:security-9.20160110ubuntu0.2-amd64:security-9.20160110ubuntu0.2-noarch
Distributor ID: Ubuntu
Description: Ubuntu 16.04.3 LTS
Release: 16.04
Codename: xenial

2.安装

设置仓库

首次安装之前,需要设置 Docker 仓库。之后可以从仓库安装和更新Docker

1
2
3
4
5
6
7
8
9
10
11
12
13
1.更新源和安装apt 依赖包,用于通过HTTPS来获取仓库
# apt-get update
# apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release

2.添加软件源的GPG密钥。这里采用中科大的
curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -

3.添加Docker软件源。同样中科大
# add-apt-repository "deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu $(lsb_release -cs) stable"

安装 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
36
37
1.再次更新源
# apt-get update

2.安装 docker-ce社区版
# apt-get install docker-ce docker-ce-cli containerd.io

3.验证是否安装成功
# docker run hello-world

4. 这个命令会下载一个hello-world镜像并运行在容器中,打印出以下信息则安装成功
root@iZbp1aq6c9kbbexg9cxsqiZ:~# docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:cc15c5b292d8525effc0f89cb299f1804f3a725c8d05e158653a563f15e4f685
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/

For more examples and ideas, visit:
https://docs.docker.com/get-started/

卸载Docker

1
2
3
4
1.卸载依赖
# apt-get remove docker docker-engine docker.io containerd runc
2.删除镜像、容器、配置文件等内容:
# rm -rf /var/lib/docker

Run流程

Docker首先会从本地查找这个镜像,找到的话直接运行;找不到就去仓库上查找,找到的话返回该镜像运行

image-20211121212242352

三、Docker常用命令

1.帮助命令

1
2
3
docker 命令 --help	#显示某命令的帮助信息
docker version #显示docker的版本信息
docker info #显示docker的系统、镜像、容器信息

2.镜像命令

查看镜像

docker images

  • REPOSITORY:仓库源
  • TAG:标签(版本)
  • IMAGE ID:镜像的ID
  • CREATED:镜像创建的时间
  • SIZE:大小
1
2
3
[root]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 8 weeks ago 13.3kB

搜索镜像

docker search

  • NAME:镜像仓库源
  • DESCRIPTION: 镜像的描述
  • OFFICIAL:是否 docker 官方发布
  • STARS: 类似 Github 里面的 star
  • AUTOMATED: 自动构建
1
2
3
4
5
[root]# docker search mysql
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 11708 [OK]
mariadb MariaDB Server is a high performing open sou… 4459 [OK]
mysql/mysql-server Optimized MySQL Server Docker images. Create… 870 [OK]

下载镜像

docker pull

默认下载最新版,可以指定版本:docker pull 镜像名:tag

1
2
3
4
5
6
#下载最新的
[root]# docker pull mysql
[root]# docker pull docker.io/librara/mysql:latest

#指定版本
[root]# docker pull mysql:5.7

删除镜像

docker rmi

rm删除 + i镜像 = rmi删除镜像

可以根据镜像ID或名字来删

1
2
3
4
5
6
7
8
[root]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql 5.7 8b43c6af2ad0 4 days ago 448MB
hello-world latest feb5d9fea6a5 8 weeks ago 13.3kB
[root]# docker rmi 8b43c6af2ad0

#批量删除使用-f,后面的参数代表镜像ID,docker images -q展示出本地所有镜像的ID
[root]# docker rmi -f $(docker images -q)

打包镜像

docker save 镜像ID/名 > 打包后的文件名

1
2
3
[root]# docker save mycentos:1.0 > mycentos.tar
[root]# ls
mycentos.tar

加载镜像

docker load < 打包的文件

1
2
3
4
#首先使用docker rmi mycentos:1.0删除镜像
[root]# docker rmi mycentos:1.0
[root]# docker load < mycentos.tar

3.容器命令

容器是基于镜像的,所以要先下载一个镜像

1
root@host:~# docker pull centos

新建容器并启动

docker run

1
2
3
4
5
6
7
8
9
10
11
docker run [可选参数] image

#参数
--name="Name" 容器名字,比如一个Tomcat镜像,启动多个就要给个名字区分
-d 后台运行
-it 使用交互式运行。-i交互式操作,-t终端
-p 容器端口,可与主机端口进行映射
-p ip:主机端口:容器端口
-p 主机端口:容器端口
-p 容器端口
-P 大P,随机指定端口
1
2
3
4
5
#启动并进入容器,host为主机名
root@host:~# docker run -it centos bash

#进入容器后主机名变为了caa2db760d6a,镜像的ID
[root@caa2db760d6a /]#

run命令的延伸:

1
2
3
4
5
6
--restart=always  		#容器的自动启动(容器服务启动后容器自动,相当于开机自启动)
-h x.xx.xx #设置容器主机名,相当于linux的hostname命令,不同的是-h是永久设置
--dns xx.xx.xx.xx #设置容器使用的DNS服务器,因为容器也需要上网
--dns-search #DNS搜索设置
--add-host hostname:IP #注入hostname<>IP解析,相当于linux改host文件,加入--add-host www.baidu.com:127.0.0.1 当然也可以exec进去改
--rm #服务停止时自动删除(容器停止后会自动删除)

退出容器

1
2
exit			#容器停止并退出	
Ctrl + P + Q #容器不停止(后台运行)并退出

查看容器

docker ps

-a:查看正在运行的+历史运行过的容器

  • CONTAINER ID:容器 ID

  • IMAGE:使用的镜像

  • COMMAND:启动容器时运行的命令

  • CREATED:容器的创建时间

  • STATUS:容器状态

  • PORTS:容器的端口信息和使用的连接类型(tcp\udp)

  • NAMES:容器名称

1
2
3
4
5
root@host:~# docker ps
root@host:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
caa2db760d6a centos "/bin/bash" 5 minutes ago Exited (0) 2 minutes ago crazy_stonebraker
6e417c0d39ee feb5d9fea6a5 "/hello" 19 hours ago Exited (0) 19 hours ago trusting_dhawan

删除容器

docker rm

1
2
3
4
#删除指定容器,不能删除正在运行的容器。强制删除使用rm -rf
docker rm 容器id
#删除所有容器
docker rm -f $(docker ps -aq)

启动容器

1
2
docker start 容器id
docker restrat 容器id

停止容器

1
2
docker stop 容器id
docker kill 容器id #强制停止

其他命令

查看容器日志

-f:展示日志输出

-t:显示时间

1
docker logs -f -t --tail n 容器id

查看容器中进程信息

docker top

1
docker top 容器id

查看镜像的元数据

docker inspect

1
docker inspect 镜像id

进入当前正在运行的容器

  1. docker exec

    进入容器后开启一个新的终端

1
docker exec -it 容器id /bin/bash
  1. docker attach

    进入容器正在执行的终端

1
docker attach 容器id

将容器内文件拷贝到主机

docker cp

1
docker cp 容器id:容器内路径 目的主机路径

提交自己的镜像

docker commit 提交容器成为一个新的镜像,和git类似

1
docker commit -m="描述信息" -a="作者" 容器id 目标镜像名:[tag]

镜像是分层的文件,镜像运行就是容器增加了一层,而这一层是可更改的(镜像不可更改),提交=将镜像原本的层+容器层打包成一个新的镜像

image-20211124152101069

Tomcat9.0镜像层文件:

image-20211123141708366

Tomcat9.0镜像运行后修改webapps中的文件,进行commit成新的镜像Tomcat:v2。多了一层

image-20211123141914653

四、数据卷

我们将一个项目和运行环境(JDK、Tomcat、MySQL)放在容器中运行,如果容器删了,那么容器中的数据全都会丢失(删库跑路),所以不能将MySQL数据存储在容器中

数据卷:Docker容器的数据同步到本地(目录的挂载,将容器中目录挂载到本地目录)

容器间也可以数据共享,称为数据卷容器

1.指定路径挂载

使用命令来挂载 -v

1
docker run -v 主机目录:容器目录

Tomcat默认访问页面目录为 webapps/ROOT,将该目录映射到主机目录,主机目录中有index.html

image-20211123154846373

-P:映射随机端口

1
[root]# docker run -d -v /data/niujiaming:/usr/local/tomcat/webapps/ROOT -P --name="tomcat06" tomcat:v2

docker inspect找到Mounts这一块,已经挂载成功

  • Source:主机内地址
  • Destination:容器内地址

docker ps看到端口为49153

1
2
3
[root@k8s-node-201]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
27b4a04e5f89 tomcat:v2 "catalina.sh run" 8 minutes ago Up 8 minutes 0.0.0.0:49153->8080/tcp tomcat06

访问该地址

2.匿名挂载

-v后面只指定容器目录

1
docker run -v /usr/local/tomcat tomcat:9.0

3.具名挂载

-v后面指定一个卷名和容器目录

1
docker run -d -P --name tomcat07 -v juming:/usr/local/tomcat tomcat:9.0

查看所有挂载信息

1
2
3
[root]# docker volume ls
DRIVER VOLUME NAME
local juming

查看卷名挂载信息
docker容器内的卷,没有指定主机目录的话都是在 /var/lib/docker/volumes 这个目录下

1
2
3
4
5
6
7
8
9
10
11
12
[root]# docker inspect juming
[
{
"CreatedAt": "2021-11-23T16:59:53+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/juming/_data",
"Name": "juming",
"Options": null,
"Scope": "local"
}
]

进入主机的 /var/lib/docker/volumes/juming/_data目录下,该目录的文件就是容器目录/usr/local/tomcat

image-20211123170712573

五、数据卷容器

容器之间配置信息的传递

  1. 创建父容器 ngnix01

    匿名挂载,数据卷为/usr/share/nginx/html

    1
    [root]# docker run -d -p 9555:80 --name="nginx01" -v /usr/share/nginx/html nginx

    修改index.html文件内容

    1
    2
    3
    root@7ac95a402565:/usr/share/nginx/html# echo 'this is nginx01 container'>index.html
    root@7ac95a402565:/usr/share/nginx/html# cat index.html
    this is nginx01 container
  2. 创建子容器 nginx02

    --volumes-from:指定父容器的数据卷,这样nginx02的/usr/share/nginx/html指向nginx01的/usr/share/nginx/html

    1
    [root]# docker run -d -p 9556:80 --name="nginx02" --volumes-from nginx01 nginx
  3. 访问

    nginx01端口、nginx02端口

image-20211124115143577

image-20211124115226038

查看nginx01容器的数据卷

image-20211124115802674

查看nginx02容器的数据卷

image-20211124115850270

它们两个都指向了主机的目录

六、Dockerfile

用来构建docker镜像的的构建文件(脚本)

镜像是一层层的文件,而Dockerfile中每个命令都是一层

1.创建Dockerfile

FROM:定制需要的基础镜像

VOLUME:定义匿名数据卷,镜像中会有volume01、volume02文件夹,如果在run的时候没有挂载数据卷,会自动挂载到匿名卷

RUN:用于执行后面跟着的命令行命令

1
2
3
4
5
[root]# vim dockerfile01
[root]# cat dockerfile01
FROM nginx
VOLUME ["volume01","volume02"]
RUN echo 'this is nginx image' > /usr/share/nginx/html/index.html

2.构建镜像

docker build

-f:指定文件,Docker默认指定的文件名称为Dockerfile,如果构建文件叫这个名字,就不需要-f

-t:镜像的名字和tag

.:上下文路径,指docker在构建镜像时,如想要使用到本机的文件,docker build 命令得知这个路径后,会将路径下的所有内容打包。构建过程实际是由docker引擎来完成的,所以无法使用本机文件,需要将上下文路径下的文件一起打包给docker引擎使用,默认为 Dockerfile 所在的位置 (不要放无用的文件,会一起打包的,如果文件过多会造成过程缓慢)

1
2
3
4
5
6
7
8
9
10
[root]# docker build -f dockerfile01 -t niujiaming/nginx:1.0 .
Sending build context to Docker daemon 3.072kB
Step 1/2 : FROM nginx
---> 4f380adfc10f
Step 2/2 : RUN echo 'this is nginx image' > /usr/share/nginx/html/index.html
---> Running in 95bd82f5c70d
Removing intermediate container 95bd82f5c70d
---> f6838b1e004f
Successfully built f6838b1e004f
Successfully tagged niujiaming/nginx:1.0

查看构建的镜像

1
2
3
[root]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
niujiaming/nginx 1.0 f6838b1e004f 7 minutes ago 133MB

3.运行镜像

Dockerfile没有指定数据卷,run也没有指定数据卷,所以是匿名挂载

1
[root]# docker run -d -P  niujiaming/nginx:1.0

查看容器信息

docker inspect 容器id

Mounts有数据卷信息

Dockfile指令

规则:

  1. 每个指令都必须是大写字母
  2. 执行从上到下执行
  3. #表示注释
  4. 每个指令都会创建提交一个新的镜像层
指令 描述 语法
FROM 指定基础镜像,并且必须是第一条指令 FROM < image>[:< tag>]
MAINTAINER 设置镜像作者 MAINTAINER < name>
LABEL 为镜像指定标签 LABEL < key>=< value>
RUN 镜像构建 docker build 时执行的命令 RUN < command> | RUN [“executeable”, “param1”]
CMD 镜像运行 docker run 时执行的命令。如果写了多条则只有最后一条生效。如果在docker run时添加命令,则会替换CMD设置的命令 同上👆
ENTRYPOINT 类似于 CMD 指令,但不会被docker run命令覆盖,而是将命令当作字符串,传递给ENTRYPOINT作为参数。例:ENTRYPOINT [“ls”,”-a”] ,docker run -l,最后执行的是ls -la ENTRYPOINT [“< executeable>”,”< param1>”]
ADD 复制文件到镜像中。如果是压缩文件,add会自动解压。默认编译目录(上下文路径)寻找文件,dest为镜像中的绝对路径或者相对于WORKDIR的路径 ADD < src>… < dest>
COPY 复制文件到镜像中。指令和ADD相似 同上👆
WORKDIR 镜像的工作目录 WORKDIR < Path>
VOLUME 定义匿名数据卷。启动容器时,会新建挂载点,并用镜像中的数据初始化挂载点,可以将主机目录或数据卷容器挂载到这里 VOLUME [“/dir”]
EXPOSE 暴露镜像端口。但需要启动容器时使用-P/-p映射端口,才能通过外部访问容器提供的服务 EXPOSE < port> < port> …
ONBUILD 后面跟的是其它指令,比如 RUN、COPY 等,这些指令在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行 ONBUILD [INSTRUCTION]
ENV 设置镜像中的环境变量。后续的指令,就可以使用这个环境变量$key ENV < key>=< value>…
ARG 构建参数,作用同ENV,但ARG 的环境变量仅对 Dockerfile 内有效 ARG < key>[=< value>]

一些练习

1.centos

创建dockerfile-centos

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root]# cat dockerfile-centos
#镜像源
FROM centos
#标签 设置作者
LABEL author=niujiaming
#定义环境变量
ENV MYPATH=/usr/local
#定义工作路径,为环境变量MYPATH
WORKDIR $MYPATH
#构建时安装vim等常用命令,每个run都会创建一层,\ 可换行,&& 连接
RUN yum -y install vim \
&& yum -y install net-tools
#运行时输出的信息
CMD echo "---end---"

构建

1
[root]# docker build -f dockerfile-centos -t mycentos:1.0 .

运行 也可以将/bin/bash作为CMD命令放在构建文件中

1
2
3
4
5
#因为docker run 的命令为/bin/bash,覆盖了CMD echo "---end---",所以没有输出
[root]# docker run -it mycentos:1.0 /bin/bash
#工作目录
[root@94ce9a8571ab local]# pwd
/usr/local

2.tomcat

下载tomcat、jdk压缩包

1
2
[root]# wget https://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-9/v9.0.54/bin/apache-tomcat-9.0.54.tar.gz 
[root]# wget https://repo.huaweicloud.com/java/jdk/8u192-b12/jdk-8u192-linux-x64.tar.gz

编写Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#镜像源
FROM centos
#添加jdk和tomcat,ADD会自动解压
ADD jdk-8u192-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.54.tar.gz /usr/local/
#安装vim
RUN yum -y install vim
#设置环境变量
ENV MYPATH=/usr/local
#设置工作目录
WORKDIR $MYPATH
#添加jdk、tomcat环境变量
ENV JAVA_HOME=/usr/local/jdk1.8.0_192 CLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar CATALINA_HOME=/usr/local/apache-tomcat-9.0.54 CATALINA_BASH=$CATALINA_HOME PATH=$PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#暴露8080端口
EXPOSE 8080
#启动Tomcat
CMD /usr/local/apache-tomcat-9.0.54/bin/startup.sh && tail -F =/usr/local/apache-tomcat-9.0.54/bin/logs/catalina.out

构建

因为构建文件名称为Dockerfile,这里不需要指定

1
[root]# docker build -t mytomcat:1.0 .

启动

这里将webapps作为数据卷,/data/niujiaming下有index.html

1
[root]# docker run -d  -p 9556:8080 --name mytomcat04 -v /data/niujiaming:/usr/local/apache-tomcat-9.0.54/webapps mytomcat:1.0

image-20211125133930622

Docker全流程图

七、Docker网络

1.Docker0

使用ip addr命令查看网卡

docker0就是docker的地址。docker使用的是桥接模式,使用的技术是veth-pair技术

1
2
3
4
5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
link/ether 02:42:63:5e:e7:d2 brd ff:ff:ff:ff:ff:ff
inet 172.29.42.1/24 brd 172.29.42.255 scope global docker0
valid_lft forever preferred_lft forever

启动一个容器并查看它的网卡,有一个80: eth0@if81,为172.29.42.2

1
2
3
4
5
6
7
8
9
[root]# docker exec -it 529ca5d42ba3 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
80: eth0@if81: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:1d:2a:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.29.42.2/24 brd 172.29.42.255 scope global eth0
valid_lft forever preferred_lft forever

主机也会增加一个网卡81: veth702c876@if80,这里的80指的就是容器的网卡80: eth0@if81

1
2
81: veth702c876@if80: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
link/ether 8a:96:ba:26:6d:97 brd ff:ff:ff:ff:ff:ff link-netnsid 0

主机网卡81: veth702c876@if80

容器网卡80: eth0@if81

这就是前面说的veth-pair(Virtual Ethernet)技术。veth-pair就是一对虚拟设备接口,它们都是成对出现的,一端连着协议,一端彼此相连,所以可以通信。veth-pair可以充当一个桥梁。

查看docker网络配置

1
2
3
[root]# docker network ls
NETWORK ID NAME DRIVER SCOPE
0701b7e4eba0 bridge bridge local

查看桥接 0701b7e4eba0

1
[root]# docker network inspect 0701b7e4eba0

Docker0地址

image-20211125170905239

容器地址。启动容器时docker分配的ip

image-20211125171042963

主机上启动的Docker容器会连接到这个Docker0虚拟网桥上,这样主机上的所有容器就通过交换机连在了一个二层网络中

graph TB;
  主机host-->Docker0/172.29.42.1;
   Docker0/172.29.42.1--veth-eth0-->容器1/172.29.42.2;
    Docker0/172.29.42.1--veth-eth0-->容器2/172.29.42.3;

2.自定义网络

自定义网络来控制哪些容器可以相互通信

docker network ls

查看所有网络

1
2
3
4
5
[root]# docker network ls
NETWORK ID NAME DRIVER SCOPE
0701b7e4eba0 bridge bridge local
e95169f22189 host host local
6aab19df3032 none null local
网络模式 简介
bridge 桥接。此模式会为每一个容器分配IP,并将容器连接到docker0虚拟网桥,
host 使用主机地址
none 关闭了容器的网络功能
自定义网络

这3个网络是docker内置的,当我们运行一个容器需要指定网络时,可以通过--net参数来指定容器连接的网络。默认运行已经添加了--net bridge

1.创建一个网络

docker network create [参数] 网络名

  • -d / --driver:驱动程序管理网络,默认为bridge

  • --subnet:子网

  • --gateway:网关

1
[root]#  docker network create -d bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 网络名

查看

1
2
3
4
5
6
[root@k8s-node-201 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
0701b7e4eba0 bridge bridge local
e95169f22189 host host local
6aab19df3032 none null local
4b40a9e01c65 testnet bridge local

ip addr也会增加一个网络

image-20211126140359910

2.启动容器,指定网络

1
2
[root]# docker run -d -P --name="mytomcat05" --net testnet  mytomcat:1.0
[root]# docker run -d -P --name="mytomcat06" --net testnet mytomcat:1.0

docker network inspect testnet

可以看到这两个容器

image-20211126141145230

通过自定义网络可以实现两个容器之间网络的互通

1
2
3
4
5
6
[root]# docker exec -it mytomcat05 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.128 ms
[root]# docker exec -it mytomcat06 ping 192.168.0.2
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=0.083 ms

3连接容器至网络

mytomcat05、mytomcat06位于192.168.0.0/16网段中

mytomcat01位于Docker0(172.29.42.0/24)网段中

那么怎么让01访问05、06(将mytomcat01容器连接到testnet网络中)

docker network connect 网络名 容器名

1
docker network connect testnet mytomcat01

查看docker network inspect testnet

mytomcat01容器被加到testnet网络中了(相当于用一根网线把一台机器接入另一个局域网中)

image-20211126155347907

八、Docker Compose

定义和运行多个 Docker容器的应用,负责实现对Docker容器集群的快速编排

使用一个Dockerfile文件,可以定义一个单独的应用容器,但是有时需要多个容器相互配合来完成某项任务,例如要实现Web项目,需要Web服务容器,还要数据库容器、负载均衡容器等

compose满足了这样的需求,用户通过一个单独的docker-compose.yml 模板文件来定义一组相关联的应用容器为一个项目(project)

核心概念:

  • 服务(service):一个应用的容器,比如web、redis、mysql,服务=容器,一堆容器组成一个项目
  • 项目(project):多个服务共同组成的完整业务单元。在docker-compose.yml中定义,定义项目中用到的所有服务

docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}

1.安装Compose

下载二进制文件

1
[root]# curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

2.授权

1
[root]# chmod +x /usr/local/bin/docker-compose

3.测试

1
2
3
4
5
[root]# docker-compose version
docker-compose version 1.18.0, build 8dd22a9
docker-py version: 2.6.1
CPython version: 3.6.8
OpenSSL version: OpenSSL 1.0.2k-fips 26 Jan 2017

2.使用Compose

  1. docker-compose.yml 定义应用所需要的环境(web、redis)

    • version:版本
    • services:服务,可包含多个
      • 服务名(要唯一)
        • image:创建当前这个服务使用的镜像
        • ports:端口映射,注意格式
    1
    2
    3
    4
    5
    6
    version: '3'
    services:
    tomcat:
    image: "tomcat:8.0"
    ports:
    - "9555:8080"
  2. 运行docker-compose

    docker-compose up启动这个项目的所有服务。默认前台启动

    • -d:后台执行
  3. docker ps -a查看

    1
    2
    3
    [root]# docker ps -a
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    5c9ed5cbd86d tomcat:8.0 "catalina.sh run" 3 minutes ago Exited (143) 2 minutes ago composetest_tomcat_1

    也会创建一个相应的网络,yml中所有的服务都位于该网络下

    1
    2
    3
    [root]# docker network ls
    NETWORK ID NAME DRIVER SCOPE
    101dbead5e52 composetest_default bridge local

3.yml模板命令

标准模板文件应该包含version、services、networks 三大部分,最关键的是services和networks两个部分

version

版本号

image

指定服务的镜像名称.。想当于run image

1
2
3
services:
tomcat:
image: "tomcat:8.0"

build

服务除了可以基于指定的镜像,还可以基于Dockerfile

compose会根据build中的Dockerfile自动构建镜像,然后使用镜像启动服务

1
2
3
4
5
6
7
8
9
services:
#相对路径,指定为从上下文路径 ./dir/Dockerfile
webapp01:
build: ./dir
#使用dockerfile文件来构建,必须指定构建路径
webapp02:
build:
context: ./dir
dockerfile: Dockerfile02

container_name

Compose的容器默认名称格式是:项目名称_ 服务名称_序号

自定义容器名称。相当于run –name

1
2
3
4
services:
tomcat01:
container_name: tomcat01
image: "tomcat:8.0"

ports

映射端口。相当于run -p

1
2
3
4
5
services:
tomcat:
image: "tomcat:8.0"
ports:
- "9555:8080"

volumes

完成主机与容器目录数据卷共享。相当于run -v

1
2
3
4
5
6
7
8
9
10
11
12
13
services:
tomcat:
image: "tomcat:8.0"
volumes:
#只指定一个路径,Docker 会自动在创建一个数据卷(这个路径是容器内部的)
- /usr/local/tomcat/webapps
#使用绝对路径挂载数据卷
- /opt/data:/usr/local/tomcat/webapps
#已经存在的命名的数据卷。datavolume必须存在,引用顶级 volumes 下的条目
- datavolume:/var/lib/conf

volumes:
datavolume: #声明指定的卷名(最后生成的卷名为:项目名_卷名)

networks

配置容器连接的网络,需引用顶级 networks 下的条目。相当于run –net

1
2
3
4
5
6
7
8
9
10
11
12
13
services:
tomcat01:
image: "tomcat:8.0"
#当前服务使用哪个网络桥
networks:
- net01
tomcat02:
image: "tomcat:8.0"
networks:
- net01
#定义服务用到的桥
networks:
net01: #默认bridge模式

command

覆盖容器 启动后默认执行的命令

1
2
3
4
services:
tomcat01:
image: "tomcat:8.0"
command: "/usr/local/tomcat/bin/startup.sh "

environment

添加环境变量,可以用数组或字典两种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
services:
mysql01:
image: "mysql:5.7"
container_name: mysql01
ports:
- "3306:3306"
volumes:
- mysqldata:/var/lib/mysql
- mysqlconf:/etc/mysql
environment:
- MYSQL_ROOT_PASSWORD=123456
- SHOW=true

# 字典方式的布尔型要加引号
environment:
MYSQL_ROOT_PASSWORD:123456
SHOW:"true"
volumes:
mysqldata:
mysqlconf:

env_file

从文件中获取环境变量,可以指定一个文件路径或路径列表,其优先级低于 environment 指定的环境变量

如果通过docker-compose -f 文件名来指定yml模板文件的话,env_file变量的路径会基于模板文件的路径

1
2
3
4
5
6
7
8
services:
mysql01:
image: "mysql:5.7"
container_name: mysql01
ports:
- "3306:3306"
environment:
- ./mysql.env

环境变量文件格式,类似properties

1
MYSQL_ROOT_PASSWORD=123456

depends_on

设置依赖关系,写的是服务名

web服务依赖于mysql和redis,所以要先启动mysql和redis

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

healthcheck

通过命令检查容器(服务)是否健康运行

1
2
3
4
5
healthcheck:
test: ["CMD","curl","-f","http://localhost"] # 设置检测程序
interval: 1m30s # 设置检测间隔
timeout: 10s # 设置检测超时时间
retries: 3 # 设置重试次数

sysctls

配置容器内核参数,可以使用数组或字典格式

1
2
3
4
5
6
7
sysctls:
net.core.somaxconn: 1024
net.ipv4.tcp_syncookies: 0

sysctls:
- net.core.somaxconn=1024
- net.ipv4.tcp_syncookies=0

ulimits

修改容器内系统的最大进程数

1
2
3
4
5
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000

4.compose常用指令

docker-compose [-f=<agr>] [option] [COMMAND] [ARGS...]

-f:指定compose模板文件,默认是当前目录的的docker-compose.yml

-p:指定项目名称,默认使用当前目录的名称作为项目名

--verbose:输出更多调试信息

up

自动完成包括构建镜像,创建服务,启动服务,并关联服务相关容器的一系列操作。

大部分时候都可以直接通过该命令来启动一个项目

-d:后台运行

service:某个服务,默认启动所有服务

1
docker-compose up [options] [service...]

down

关闭所有的docker-compose服务,并移除网桥

1
docker-compose down

stop

关闭所有的docker-compose服务,不会移除网桥

1
docker-compose stop

rm

删除(停止状态的)服务容器

-f:强制删除,包括正在运行的

-v:删除容器所挂载的数据卷

1
docker-compose rm [option] [service...]

exec

docker exec一样,进入容器,但是使用的是服务名,也不需要使用-it

1
docker-compose exec 服务名 bash

ps

列出该项目中所有容器,与docker ps不同

1
docker-compose ps

top

查看服务容器内运行的进程

1
docker-compose top 

start、restart

启动、重启项目中的服务

-t:指定重启前停止容器的超时(默认10秒)

1
docker-compose restart [option] [service...]

练习 部署mysql和后台应用

mysql采用dockerfile:

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM mysql:5.7
# 设置工作目录、数据库密码
ENV WORK_DIR=/usr/local/mysql
ENV MYSQL_ROOT_PASSWORD=1351740185
#定义会被容器自动执行的目录
ENV AUTO_RUN_DIR /docker-entrypoint-initdb.d

WORKDIR $WORK_DIR
#将sql脚本放在自动执行的目录
COPY dian-jz.sql $AUTO_RUN_DIR
#增加权限
RUN chmod a+x $AUTO_RUN_DIR/dian-jz.sql
EXPOSE 3306

后台:连接数据采用的是数据库服务名:3306

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
version: '3'
services:
jz01:
image: "java:8"
volumes:
#jar包和logs
- /data/niujiaming/jz/java/jz-0.0.1-SNAPSHOT.jar:/jz.jar
- /data/niujiaming/jz/java/logs:/logs
ports:
- "9555:8002"
networks:
- jznet
depends_on:
- jzmysql
#运行命令
entrypoint: java -jar jz.jar
jzmysql:
build:
context: ./mysql
volumes:
- /data/niujiaming/jz/mysql/data:/var/lib/mysql
- /data/niujiaming/jz/mysql/logs:/var/log/mysql
ports:
- "3307:3306"
networks:
- jznet
networks:
jznet:

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!