Docker-基础
一、Docker概述
Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。
docker架构
Docker使用了C/S体系架构,Docker客户端与Docker守护进程通信,Docker守护进程负责构建,运行和分发Docker容器。Docker客户端和守护进程可以在同一个系统上运行,也可以将Docker客户端连接到远程Docker守护进程。Docker客户端和守护进程使用REST API通过UNIX套接字或网络接口进行通信。
1. Client(客户端)
Client即Docker客户端,也就是上一小节Docker Engine中介绍的docker CLI。开发者通过这个客户端使用Docker的相关指令与Docker守护进程进行交互,从而进行Docker镜像的创建、拉取和运行等操作。
2. DOCKER_HOST(Docker主机)
DOCKER_HOST即Docker内部引擎运行的主机,主要指Docker daemon(Docker守护进程)。可以通过Docker守护进程与客户端还有Docker的镜像仓库Registry进行交互,从而管理Images(镜像)和Containers(容器)等。
Images(镜像)
Docker镜像就是一个只读的模板,包含了一些创建Docker容器的操作指令。通常情况下,一个Docker镜像是基于另一个基础镜像创建的,并且新创建的镜像会额外包含一些功能配置。例如:开发者可以依赖于一个 Ubuntu 的基础镜像创建一个新镜像,并可以在新镜像中安装Apache等软件或其他应用程序。
Containers(容器)
Docker 容器属于镜像的一个可运行实例(镜像与容器的关系其实与 Java 中的类与对象相似),开发者可以通过API接口或者CLI命令行接口来创建、运行、停止、移动、删除一个容器,也可以将一个容器连接到一个或多个网络中,将数据存储与容器进行关联。
3. Registry(注册中心)
Registry即Docker注册中心,实质就是Docker镜像仓库,默认使用的是Docker官方远程注册中心Docker Hub,也可以使用开发者搭建的本地仓库。Registry中包含了大量的镜像,这些镜像可以是官网基础镜像,也可以是其他开发者上传的镜像。
我们在实际使用 Docker 时,除了会涉及图中的 3 个主要部分外,还会涉及很多Docker Objects(Docker对象),例如Images(镜像)、Containers(容器)、Networks(网络)、Volumes (数据卷)、Plugins(插件)等。其中常用的两个对象Image和Containers的说明如下。
二、Docker安装
2.1、安装
#1、卸载旧版本
yum remove docker
docker-client
docker-client-latest
docker-common
docker-latest
docker-latest-logrotate
docker-logrotate
docker-engine
#2、需要的安装包
yum install -y yum-utils
#3、设置镜像仓库
#国外镜像地址(不推荐,速度慢)
yum-config-manager
--add-repo
https://download.docker.com/linux/centos/docker-ce.repo
#国内阿里云镜像地址(推荐,速度快)
yum-config-manager
--add-repo
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#4、更新yum软件索引包
yum makecache fast
#5、安装docker ce-社区办 ee-企业版
yum install docker-ce docker-ce-cli containerd.io
#安装指定docker版本
#yum install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io
#6、启动docker
systemctl start docker
#7、查看docker安装的版本
docker version
#下面为docker version操作命令出现的信息,说明docker安装成功
Client: Docker Engine - Community
Version: 19.03.13
API version: 1.40
Go version: go1.13.15
Git commit: 4484c46d9d
Built: Wed Sep 16 17:03:45 2020
OS/Arch: linux/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 19.03.13
API version: 1.40 (minimum version 1.12)
Go version: go1.13.15
Git commit: 4484c46d9d
Built: Wed Sep 16 17:02:21 2020
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.3.7
GitCommit: 8fba4e9a7d01810a393d5d25a3621dc101981175
runc:
Version: 1.0.0-rc10
GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd
docker-init:
Version: 0.18.0
GitCommit: fec3683
#8、运行镜像
docker search hello-world #查找hello-world镜像,得到所有的版本
docker run hello-world #找到仓库中最新版本的镜像,运行
docker images #查看镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest bf756fb1ae65 9 months ago 13.3kB
docker run hello-world 的运行流程图:
2.2、卸载
#1、卸载docker
yum remove docker-ce docker-ce-cli containerd.io
#2、删除docker资源
rm -rf /var/lib/docker #docker的默认资源地址 /var/lib/docker
2.3、配置阿里云镜像加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://tdzq633y.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
三、Docker的常用命令
3.1、帮助命令
3.2、镜像命令
当运行容器时,使用的镜像如果在本地中不存在,docker 就会自动从 docker 镜像仓库中下载,默认是从 Docker Hub 公共镜像源下载。
3.2.1、列出镜像列表
[root@zxone ~]# docker images #列出本地存在影响列表
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat 1.0 c82080e5255f 3 days ago 640MB
mycentos 1.0 39a4c2226cd0 3 days ago 295MB
zxone/centos 1.0 aac11c067c6f 3 days ago 215MB
nginx latest 992e3b7be046 7 days ago 133MB
mysql 5.7 ef08065b0a30 4 weeks ago 448MB
centos latest 0d120b6ccaa8 2 months ago 215MB
hello-world latest bf756fb1ae65 9 months ago 13.3kB
- REPOSITORY:表示镜像的仓库源
- TAG:镜像的标签
- IMAGE ID:镜像ID
- CREATED:镜像创建时间
- SIZE:镜像大小
3.2.2、搜索镜像
#使用命令search查询镜像,返回仓库上存在的镜像列表
docker search hello-world
3.2.3、获取镜像
当我们在本地主机上使用一个不存在的镜像时 Docker 就会自动下载这个镜像。如果我们想预先下载这个镜像,我们可以使用 docker pull 命令来下载它。
[root@zxone ~]# docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete
Digest: sha256:4cf9c47f86df71d48364001ede3a4fcd85ae80ce02ebad74156906caff5378bc
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest
3.2.4、删除镜像
镜像删除使用 docker rmi 命令,比如我们删除 hello-world 镜像:
docker rmi hello-world #需要把这个镜像运行启动的容器全部删除才能删除镜像
docker rmi $(docker images -q) #删除所有的镜像
3.2.5、创建镜像
当我们从 docker 镜像仓库中下载的镜像不能满足我们的需求时,我们可以通过以下两种方式对镜像进行更改。
- 1、从已经创建的容器中更新镜像,并且提交这个镜像
- 2、使用 Dockerfile 指令来创建一个新的镜像
3.2.6、更新镜像
更新镜像之前,我们需要使用镜像来创建一个容器。
docker run -t -i ubuntu:15.10 /bin/bash
在运行的容器内使用 apt-get update 命令进行更新。
在完成操作之后,输入 exit 命令来退出这个容器。
此时 ID 为 e218edb10161 的容器,是按我们的需求更改的容器。我们可以通过命令 docker commit 来提交容器副本。
docker commit -m="has update" -a="xxxxx" e218edb10161 runoob/ubuntu:v2
sha256:70bf1840fd7c0d2d8ef0a42a817eb29f854c1af8f7c59fc03ac7bdee9545aff8
各个参数说明:
- -m: 提交的描述信息
- -a: 指定镜像作者
- e218edb10161:容器 ID
- runoob/ubuntu:v2: 指定要创建的目标镜像名
我们可以使用 docker images 命令来查看我们的新镜像 runoob/ubuntu:v2:
3.3、容器命令
3.3.1、启动/退出容器
- -d:让容器在后台运行。
- -P:将容器内部使用的网络端口随机映射到我们使用的主机上。
- -p:指定端口映射
#-i: 交互式操作。
#-t: 终端。
#--name 给启动的容器起一个名字
#centos: ubuntu 镜像。
#/bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。
[root@zxone ~]# docker run -it --name centos01 centos /bin/bash
[root@64886e359a33 /]# exit
exit
[root@zxone ~]# docker ps #查看运行中的容器
[root@zxone ~]# docker ps -a #查看所有容器
[root@zxone ~]# docker stop <容器id> #停止容器
[root@zxone ~]# docker start <容器id> #启动容器
[root@zxone ~]# docker restart <容器id> #重新启动容器
[root@zxone ~]# docker rm <容器id> #删除容器,命令docker ps -a 就查询不到这个容器了
#-d 后台运行容器
[root@zxone ~]# docker run -itd --name centos01 centos /bin/bash
3.3.2、进入容器
在使用 -d 参数时,容器启动后会进入后台。此时想要进入容器,可以通过以下指令进入:
- docker attach
- docker exec:推荐大家使用 docker exec 命令,因为此退出容器终端,不会导致容器的停止。
[root@zxone ~]# docker attach b3806743f966
[root@b3806743f966 /]# exit #使用attach进入容器,然后在使用exit命令退出时,容器会停止
exit
[root@zxone ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@zxone ~]# docker start b3806743f966
b3806743f966
[root@zxone ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b3806743f966 centos "/bin/bash" 2 minutes ago Up 1 second centos01
[root@zxone ~]# docker exec -it b3806743f966 /bin/bash
[root@b3806743f966 /]# exit #使用exec进入容器,然后在使用exit命令退出时,不会导致容器的停止
exit
[root@zxone ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b3806743f966 centos "/bin/bash" 3 minutes ago Up 51 second centos01
3.3.3、导出和导入容器
导出容器
如果要导出本地某个容器,可以使用 docker export 命令。
docker export 1e560fca3906 > ./home/docker/app.tar #导出到本地的地址和名称
导入容器
可以使用 docker import 从容器快照文件中再导入为镜像,以下实例将快照文件 ubuntu.tar 导入到镜像 test/ubuntu:v1:
cat docker/app.tar | docker import - test/app:v1
也可以通过指定 URL 或者某个目录来导入
docker import http://example.com/exampleimage.tgz example/imagerepo
3.3.4、删除容器
删除容器使用 docker rm 命令:
docker rm -f <容器id>
docker rm -f $(docker ps -aq) #删除docker ps -a 查询出来的所有容器
docker container prune #清理掉所有处于终止状态的容器
3.4、常用其他命令
3.5、实例
在docker安装redis
[root@zxone ~]#docker pull redis:6.0 #拉取镜像
[root@zxone ~]#docker run -itd --name myredis -p 6379:6379 redis:6.0 #运行redis容器
[root@zxone ~]# docker exec -it myredis /bin/bash #进入容器
root@4316428b7944:/data# redis-cli
127.0.0.1:6379> set a 1
OK
127.0.0.1:6379> get a
"1"
四、容器数据卷
4.1、什么是容器数据卷
4.2、使用容器数据卷
方式一:使用命令来挂载 -v
#docker运行centos,-v 主机目录:docker容器目录
docker run -it -v /home/ceshi:/home centos /bin/bash
#通过inspect 容器id 查看运行的容器
docker inspect 1efc76b9d29f
#在容器信息中会出现Mounts这一项挂载内容
"Mounts": [
{
"Type": "bind",
"Source": "/home/ceshi", #主机内地址
"Destination": "/home", #docker容器内地址
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
这样就将 主机目录:docker容器内目录 双向同步绑定。
4.3、实例
#1、拉取mysql镜像
docker pull mysql:5.7
#2、运行mysql镜像
#官方:docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
#-d 后台运行
#-p 端口映射 主机端口:容器端口
#-v 数据卷挂载 可以多个
#-e 环境配置,MYSQL_ROOT_PASSWORD为mysql密码
#--name 容器名字
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d
-v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
4.4、匿名和具名挂载
4.4.1、匿名挂载
docker run -P -v juming-nginx:/etc/nginx --name nginx01 nginx
4.4.1、具名挂载
docker run -P -v juming-nginx:/etc/nginx --name nginx02 nginx
docker volume ls
DRIVER VOLUME NAME
local ce89be7f4e2d5a4685b2da2c93bf4189d64ccfd44c07e2e3a708a46eebd775bb #匿名
local juming-nginx #具名
#查看具名挂载的信息
[root@zxone ~]# docker volume inspect juming-nginx
[
{
"CreatedAt": "2020-10-09T17:04:38+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data", #具体的挂载地址
"Name": "juming-nginx",
"Options": null,
"Scope": "local"
}
]
三种挂载:
-v 卷名:容器内目录 #具名径挂载(一般使用具名挂载)
-v 主机目录:容器内目录 #指定路径挂载
-v 容器内目录 #匿名挂载
4.5、DockerFile
方式二:使用DockerFile挂载数据卷
#dockerfile文件内容
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "-----------end------"
CMD /bin/bash
执行dockerfile
# -f dockerfile的路径
# -t 生成的镜像名称
docker build -f /home/docker-file-test/dockerfile1 -t zxone/centos:1.0 . #最后的. 不能少
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos
---> 0d120b6ccaa8
Step 2/4 : VOLUME ["volume01","volume02"]
---> Running in 7484e5b21f8c
Removing intermediate container 7484e5b21f8c
---> 87a782ccfde9
Step 3/4 : CMD echo "-----------end------"
---> Running in 8fda12bf10a0
Removing intermediate container 8fda12bf10a0
---> b205c8aab45b
Step 4/4 : CMD /bin/bash
---> Running in ad9e2cf16a61
Removing intermediate container ad9e2cf16a61
---> aac11c067c6f
Successfully built aac11c067c6f
Successfully tagged zxone/centos:1.0
#查看镜像 存在根据dockerfile创建的zxone/centos 镜像
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
zxone/centos 1.0 aac11c067c6f About a minute ago 215MB
#运行zxone/centos镜像 ,可以看到volume01 和 volume02 目录,这是挂载的数据卷(属于匿名挂载)
[root@zxone docker-file-test]# docker run -it aac11c067c6f
[root@7cf487bddb8d /]# ls
bin etc lib lost+found mnt proc run srv tmp var volume02
dev home lib64 media opt root sbin sys usr volume01
#在宿主机上查看数据卷
docker inspect 7cf487bddb8d #容器ID
"Mounts": [
{
"Type": "volume",
"Name": "a164f072e68f6fdb171d786fd9cda23c4f95fe939e81135acf001551c17ba107",
"Source": "/var/lib/docker/volumes/a164f072e68f6fdb171d786fd9cda23c4f95fe939e81135acf001551c17ba107/_data",
"Destination": "volume01",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "3a8567cab2dcaad853319fb870847a0301fc774b3a19606785d08b91bce1d11b",
"Source": "/var/lib/docker/volumes/3a8567cab2dcaad853319fb870847a0301fc774b3a19606785d08b91bce1d11b/_data",
"Destination": "volume02",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
#查看容器内和宿主机数据卷的同步,通过dockerfile实现卷挂载
cd /var/lib/docker/volumes/XXXX/_data
4.6、数据卷容器
#通过 --volumes-from 命令多个容器实现挂载同步数据
#比如:
#1、启动mysql01
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d
-v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
#2、启动mysql02
docker run -d -p 3311:3306 -v /home/mysql/conf:/etc/mysql/conf.d
-v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql02
--volumes-from mysql01 mysql:5.7
#3、启动mysql03
docker run -d -p 3312:3306 -v /home/mysql/conf:/etc/mysql/conf.d
-v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql03
--volumes-from mysql01 mysql:5.7
#这样使得mysql01、mysql02、mysql03共享了同一个数据卷的数据/home/mysql/data中的数据
#如果mysql01容器删除,mysql02、mysql03中的数据不会存在变化,因为/home/mysql/data中的数据没有变化
#相当于备份拷贝机制
五、DockerFile
5.1、DockerFile介绍
dockerfile是用来构建docker镜像的文件。命令参数脚本。
构建步骤:
- 1).编写一个dockerfile文件
- 2).docker build 构建一个镜像
- 3).docker run 运行一个镜像
- 4).docker push 发布镜像(Dockerhub和阿里云镜像仓库)
5.2、DockerFile构建过程
基础知识:
1、每个保留关键字(指令)都必须是大写字母
2、从上到下按照顺序执行
3、#表示注释
4、每一个指令都会创建一个新的镜像层,并提交。
DockerFile:构建文件,定义了一切的步骤,源代码
DockerImages:通过DockerFIle构建生成的镜像,最终发布和运行的产品。
Docker容器:容器就是镜像运行起来提供服务的服务器。
5.3、DockerFile指令
FROM #基础镜像,一切从这里构建
MAINTAINER #镜像是谁写的,姓名+邮箱
RUN #镜像构建的时候需要运行的命令
ADD #步骤,tomcat镜像,这个tomcat压缩包,添加内容
WORKDIR #镜像的工作目录
VOLUME #挂载的目录
EXPOSE #暴露端口配置
CMD #指定这个容器启动的时候要运行的命令,只有最后一个会生效,会被覆盖
ENTRYPOINT #指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD #当构建一个被继承DockerFile,这个时候就会运行ONBUILD的指令,触发指令
COPY #类型ADD,将文件拷贝到镜像中
ENV #构建的时候设置环境变量
创建自己的centos镜像,首先创建一个DockerFile文件
#DockerFile文件 内容
FROM centos
MAINTAINER zxone
ENV MYPATH /usr/local #配置环境变量
WORKDIR $MYPATH #进入容器之后直接就到了工作目录
RUN yum -y install vim #给基础镜像添加vim插件
RUN yum -y install net-tools #给基础镜像 ifconfig命令等
EXPOSE 80 #暴露端口
CMD echo $MYPATH
CMD echo "------------end------------"
CMD /bin/bash
通过DockerFile文件mydockerfile-centos构建镜像mycentos
docker build -f mydockerfile-centos -t mycentos:1.0 .
docker images #查看镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos 1.0 39a4c2226cd0 About a minute ago 295MB
docker run -it 39a4c2226cd0 #启动容器,验证
docker history 39a4c2226cd0 #查看镜像的历史
5.4、实战创建一个Tomcat镜像
5.4.1、新建Dockerfile
FROM centos #基础镜像
MAINTAINER zxone #作者信息
#拷贝readme.txt说明
COPY readme.txt /usr/local/readme.txt
#加入jdk和tomcat,到了/usr/local/ 目录会自动解压
ADD jdk-8u261-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.37.tar.gz /usr/local/
#加入vim插件
RUN yum -y install vim
#设置工作目录
ENV MYPATH /usr/local
WORKDIR $MYPATH
#配置环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_261
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.37
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.37
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#暴露端口
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.37/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.37/logs/catalina.out
5.4.2、利用Dockerfile构建镜像
#如果文件名称是:Dockerfile 则不需要-f指定DockerFile文件, 默认找Dockerfile文件
docke build -t mytomcat:1.0 .
#查询构建成功的镜像
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat 1.0 c82080e5255f 31 minutes ago 640MB
5.4.3、运行镜像
#可以使用-v命令设置数据卷,
docker run -d --name diytomcat -p 8090:8080 mytomcat:1.0
#浏览器输入宿主IP:8090验证tomcat是否成功启动
5.4.4、发布镜像
可以将自己新建的镜像发布到dockerHub或者阿里云镜像库。
需要先登录dockerHub或者阿里云镜像库,然后docker push 镜像:tag
六、Docker网络
6.1、docker0网络
阿里云linux服务器存在三个网络
#lo :本地回环地址
#eth0 :阿里云内网地址
#docker0 :docker0地址
[root@zxone home]# 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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:16:3e:06:82:4d brd ff:ff:ff:ff:ff:ff
inet 172.18.40.159/20 brd 172.18.47.255 scope global dynamic eth0
valid_lft 312045955sec preferred_lft 312045955sec
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:3c:8a:b1:15 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
6.2、veth pair
veth pair充当一个桥梁,连接各种虚拟设备。
安装运行tomcat容器
docker run -d -P --name tomcat01 tomcat #后台运行tomcat
docker exec -it tomcat01 ip addr # ip addr查询容器内的地址
#lo:docker0地址 127.0.0.1
#eth0@if81:tomcat01容器地址 172.17.0.2
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:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
#本地linux ping容器地址,可以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.061 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.041 ms
#在运行一个tomcat02
docker run -d -P --name tomcat02 tomcat
#tomcat02 ping 172.17.0.2 tomcat01 可以ping 通。结论:两个容器之间是可以通信的
#tomcat01,tomcat02 公用一个路由docker0
docker exec -it tomcat02 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.070 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.043 ms
#但是直接tomcat02 ping tomcat01是ping不通的
docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known
#再次查看主机ip addr
#两个tomcat 容器就会新增两对网络81: vethe11d492@if80 和 83: vethdba7f4d@if82
#docker就是这样使用veth pair设备连接宿主机网络与容器网络。
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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:16:3e:06:82:4d brd ff:ff:ff:ff:ff:ff
inet 172.18.40.159/20 brd 172.18.47.255 scope global dynamic eth0
valid_lft 312044434sec preferred_lft 312044434sec
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:3c:8a:b1:15 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
81: vethe11d492@if80: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 96:f8:b3:1e:b4:9a brd ff:ff:ff:ff:ff:ff link-netnsid 0
83: vethdba7f4d@if82: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether d2:e6:d6:66:dc:03 brd ff:ff:ff:ff:ff:ff link-netnsid 1
6.3、--link
#需要解决tomcat02 ping tomcat01是ping不通的
docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known
#再启动一个tomcat03时使用--link tomcat02,然后tomcat03 ping tomcat02 可以ping通
docker run -d -P --name tomcat03 --link tomcat02 tomcat
docker exec -it tomcat03 ping tomcat02 #tomcat03 ping tomcat02 可以ping通
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.077 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.046 ms
#但是反过来tomcat02 ping tomcat03 是不可以ping通的
docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known
#tomcat03 ping tomcat02 的原理是因为在tomcat03容器的/etc/hosts文件中存在tomcat02的地址映射
docker exec -it tomcat03 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 tomcat02 34542a3c3516
172.17.0.4 695a4eeff44d
6.4、自定义网络
6.4.1、网络模式
- bridge:桥接docker(默认)
- none:不配置网络
- host:和宿主机共享网络
- container:容器网络连通
#创建一个网络
#--driver bridge 网络模式
#--subnet 192.168.0.0/16 子网掩码
#--gateway 192.168.0.1 路由,网关
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
33c734a366fcffe91b9cb62bc26ff61e8b24c204841ed8cc9ccdc659f944508e
#查看网络,创建的mynet网络存在
docker network ls
NETWORK ID NAME DRIVER SCOPE
7b68f4376a1d bridge bridge local
08e934c7d648 host host local
33c734a366fc mynet bridge local
8ff0b0130dfe none null local
测试
通过使用自定义的网络mynet 启动两个容器tomcat01 tomcat02,然后tomcat01 tomcat02相互通过容器名是可以ping同的。
[root@zxone home]# docker run -d -P --name tomcat01 --net mynet tomcat
295f47531e32611ed9c4c1e099f3d086b6e4050c98de2fda2d389f4820acbe08
[root@zxone home]# docker run -d -P --name tomcat02 --net mynet tomcat
701f8c0031b30be96b84eba9911f93771ec8d3a9840987d848ecbf8f0aee3853
[root@zxone home]# docker exec -it tomcat02 ping tomcat01
PING tomcat01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.046 ms
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.045 ms
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=3 ttl=64 time=0.044 ms
[root@zxone home]# docker exec -it tomcat01 ping tomcat02
PING tomcat02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.029 ms
64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.047 ms
64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.047 ms
6.5、网络联通
容器分别连接找各自网络(比如自定义多个网络),现在容器之间需要跨网络连接。使用命令:docker network connect [OPTIONS] NETWORK CONTAINER
#tomcat03是另外一个自定义网络下的容器,现在将tomcat03 加入到mynet网络下,这样tomcat03 就连接mynet网络下容器了
docker network connect mynet tomcat03
七、部署Redis集群
7.1、新建一个redis的网络
[root@zxone home]# docker network create redis --subnet 172.38.0.0/16
3fc4705601a15e4fb166fd1ba7008d0a8bbaff49c452ec68d393043796f8d897
[root@zxone home]# docker network ls
NETWORK ID NAME DRIVER SCOPE
7b68f4376a1d bridge bridge local
08e934c7d648 host host local
33c734a366fc mynet bridge local
8ff0b0130dfe none null local
3fc4705601a1 redis bridge local
[root@zxone home]# docker network inspect redis #查询redis网络信息
[
{
"Name": "redis",
"Id": "3fc4705601a15e4fb166fd1ba7008d0a8bbaff49c452ec68d393043796f8d897",
"Created": "2020-10-19T22:26:02.261189338+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.38.0.0/16"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
7.2、新建redis的配置文件
#创建shell脚本创建redis集群配置文件,redis.sh 内容如下:
[root@zxone dockerredis]# cat redis.sh
#!/bin/bash
for port in $(seq 1 6);
do
mkdir -p /home/dockerredis/node-${port}/conf
touch /home/dockerredis/node-${port}/conf/redis.conf
cat << EOF >/home/dockerredis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port} #172.38.0.1${port} 是因为docker创建的网络redis在这个网段内
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
#给redis.sh 脚本授权
[root@zxone dockerredis]# chmod +x ./redis.sh
#执行redis.sh 脚本,创建了node-1到node-6 6个文件和redis配置文件
[root@zxone dockerredis]# ./redis.sh
[root@zxone dockerredis]# ll
total 28
drwxr-xr-x 3 root root 4096 Oct 19 22:48 node-1
drwxr-xr-x 3 root root 4096 Oct 19 22:48 node-2
drwxr-xr-x 3 root root 4096 Oct 19 22:48 node-3
drwxr-xr-x 3 root root 4096 Oct 19 22:48 node-4
drwxr-xr-x 3 root root 4096 Oct 19 22:48 node-5
drwxr-xr-x 3 root root 4096 Oct 19 22:48 node-6
-rwxr-xr-x 1 root root 420 Oct 19 22:47 redis.sh
#执行脚本之后得到6个集群redis.conf 配置文件内容
[root@zxone conf]# cat redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.11
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
7.3、启动redis集群
#1、拉取redis镜像
[root@zxone dockerredis]# docker pull redis
Using default tag: latest
latest: Pulling from library/redis
bb79b6b2107f: Pull complete
1ed3521a5dcb: Pull complete
5999b99cee8f: Pull complete
f99a38f44786: Pull complete
d6fc863042e2: Pull complete
9bd1af4eae13: Pull complete
Digest: sha256:33ca074e6019b451235735772a9c3e7216f014aae8eb0580d7e94834fe23efb3
Status: Downloaded newer image for redis:latest
docker.io/library/redis:latest
[root@zxone dockerredis]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat latest 891fcd9c5b3a 5 days ago 647MB
redis latest bd571e6529f3 5 days ago 104MB
#2、新建一个redis集群启动脚本 runredis.sh
[root@zxone dockerredis]# cat runredis.sh
#!/bin/bash
for port in $(seq 1 6)
do
docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port}
-v /home/dockerredis/node-${port}/data:/data
-v /home/dockerredis/node-${port}/conf/redis.conf:/etc/redis/redis.conf
-d --net redis --ip 172.38.0.1${port} redis redis-server /etc/redis/redis.conf;
done
#3、给runredis.sh 授权,执行脚本
[root@zxone dockerredis]# chmod +x ./runredis.sh
[root@zxone dockerredis]# ./runredis.sh
c9969729f17fbc25009dffe8b617663ba7f32cfa29f2f8687d2854593595ec15
7b7dce0911831e503ffef22fd2eb0fb218aa5326072da9b40242c9e709dd9937
16e04f2915ad649f7990ac612fd75eef121cd47a2093cfc9d35204bbe462ca96
2248f90bcec0e5b4c4bfff300cdd70f348991edbb62fe13d155526a961210797
6fa98d2bb53619e2f6efdd42a7a6f4c76da2d3d0ab01bff7341750de6060e0fb
2931cbfad6c70eb8c8c969e53cfac22491c6e35836453163b9cabd4f1bc6c059
#4、 查看容器,6个redis容器已经全部启动
[root@zxone dockerredis]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2931cbfad6c7 redis "docker-entrypoint.s…" 27 seconds ago Up 26 seconds 0.0.0.0:6376->6379/tcp, 0.0.0.0:16376->16379/tcp redis-6
6fa98d2bb536 redis "docker-entrypoint.s…" 27 seconds ago Up 27 seconds 0.0.0.0:6375->6379/tcp, 0.0.0.0:16375->16379/tcp redis-5
2248f90bcec0 redis "docker-entrypoint.s…" 28 seconds ago Up 27 seconds 0.0.0.0:6374->6379/tcp, 0.0.0.0:16374->16379/tcp redis-4
16e04f2915ad redis "docker-entrypoint.s…" 28 seconds ago Up 27 seconds 0.0.0.0:6373->6379/tcp, 0.0.0.0:16373->16379/tcp redis-3
7b7dce091183 redis "docker-entrypoint.s…" 28 seconds ago Up 28 seconds 0.0.0.0:6372->6379/tcp, 0.0.0.0:16372->16379/tcp redis-2
c9969729f17f redis "docker-entrypoint.s…" 29 seconds ago Up 28 seconds 0.0.0.0:6371->6379/tcp, 0.0.0.0:16371->16379/tcp redis-1
#5、进入其中一个redis容器内
[root@zxone dockerredis]# docker exec -it redis-1 /bin/sh
# pwd
/data
# ls
appendonly.aof nodes.conf
#执行创建集群的命令,创建一个副本。就会成功创建一个redis集群,3主3从。
redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.38.0.15:6379 to 172.38.0.11:6379
Adding replica 172.38.0.16:6379 to 172.38.0.12:6379
Adding replica 172.38.0.14:6379 to 172.38.0.13:6379
M: 1b110449b00aebc36a1c891569dc6899e0214d15 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
M: 55a531cfc5433c17b84e54427b1c90720f3cf1e3 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
M: 80f7f00d7597f52f5d4d602f362badcbc371f8c4 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
S: 44392d1fec245d0d37b447daeb4ec869c7c051e7 172.38.0.14:6379
replicates 80f7f00d7597f52f5d4d602f362badcbc371f8c4
S: c314511de10a93a68a75eb68edc860a57492d3d6 172.38.0.15:6379
replicates 1b110449b00aebc36a1c891569dc6899e0214d15
S: 1f6e6e0356181d270f305d13c3901a54a938d7bd 172.38.0.16:6379
replicates 55a531cfc5433c17b84e54427b1c90720f3cf1e3
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
.
>>> Performing Cluster Check (using node 172.38.0.11:6379)
M: 1b110449b00aebc36a1c891569dc6899e0214d15 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: c314511de10a93a68a75eb68edc860a57492d3d6 172.38.0.15:6379
slots: (0 slots) slave
replicates 1b110449b00aebc36a1c891569dc6899e0214d15
M: 80f7f00d7597f52f5d4d602f362badcbc371f8c4 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: 44392d1fec245d0d37b447daeb4ec869c7c051e7 172.38.0.14:6379
slots: (0 slots) slave
replicates 80f7f00d7597f52f5d4d602f362badcbc371f8c4
S: 1f6e6e0356181d270f305d13c3901a54a938d7bd 172.38.0.16:6379
slots: (0 slots) slave
replicates 55a531cfc5433c17b84e54427b1c90720f3cf1e3
M: 55a531cfc5433c17b84e54427b1c90720f3cf1e3 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
# redis-cli -c #进入redis集群
127.0.0.1:6379> cluster info #查看redis集群信息
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:317
cluster_stats_messages_pong_sent:323
cluster_stats_messages_sent:640
cluster_stats_messages_ping_received:318
cluster_stats_messages_pong_received:317
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:640
127.0.0.1:6379> cluster nodes #查看集群nodes信息 3主3从
c314511de10a93a68a75eb68edc860a57492d3d6 172.38.0.15:6379@16379 slave 1b110449b00aebc36a1c891569dc6899e0214d15 0 1603121747539 1 connected
80f7f00d7597f52f5d4d602f362badcbc371f8c4 172.38.0.13:6379@16379 master - 0 1603121747539 3 connected 10923-16383
44392d1fec245d0d37b447daeb4ec869c7c051e7 172.38.0.14:6379@16379 slave 80f7f00d7597f52f5d4d602f362badcbc371f8c4 0 1603121747000 3 connected
1b110449b00aebc36a1c891569dc6899e0214d15 172.38.0.11:6379@16379 myself,master - 0 1603121747000 1 connected 0-5460
1f6e6e0356181d270f305d13c3901a54a938d7bd 172.38.0.16:6379@16379 slave 55a531cfc5433c17b84e54427b1c90720f3cf1e3 0 1603121746539 2 connected
55a531cfc5433c17b84e54427b1c90720f3cf1e3 172.38.0.12:6379@16379 master - 0 1603121746539 2 connected 5461-10922
7.4、操作redis集群
#1、操作redis。先设置一个a的健值。
127.0.0.1:6379> set a 1
-> Redirected to slot [15495] located at 172.38.0.13:6379
OK
172.38.0.13:6379> get a
"1"
172.38.0.13:6379>
#2、停止172.38.0.13 这个redis
#可以查到172.38.0.13这个网段是redis-3这个容器在使用
[root@zxone data]# docker inspect redis-3
"Networks": {
"redis": {
"IPAMConfig": {
"IPv4Address": "172.38.0.13"
},
"Links": null,
"Aliases": [
"16e04f2915ad"
],
"NetworkID": "3fc4705601a15e4fb166fd1ba7008d0a8bbaff49c452ec68d393043796f8d897",
"EndpointID": "dfa7f3693540ce6f04efcc6a5bc05765b5fe78ca5865f75cbe54adced6bb9fc2",
"Gateway": "172.38.0.1",
"IPAddress": "172.38.0.13",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:26:00:0d",
"DriverOpts": null
}
}
#停止redis-3这个容器
docker stop redis-3
停止redis-3容器之后,推出redis-3,再进去redis集群,执行get a
命令,可以从得到172.38.0.14:6379这个redis上获取到值。
查看nodes信息,172.38.0.13已经停止,现在172.38.0.14是master
八、SpringBoot微服务打包docker镜像部署
8.1、构建SpringBoot项目
构建一个最简单的springboot项目,本地运行
8.2、打包应用
执行package命令,打成jar,然后java -jar 运行jar包
8.3、编写Dockerfile
FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
8.4、构建镜像
上传jar和Dockerfile到linux中
[root@zxone springboot]# ll
total 17184
-rw-r--r-- 1 root root 122 Oct 20 00:44 Dockerfile
-rw-r--r-- 1 root root 17591766 Oct 20 00:44 dockertest-1.0-SNAPSHOT.jar
#利用Dockerfile构建镜像springweb
[root@zxone springboot]# docker build -t springweb:1.0 .
#构建镜像完成之后,得到springweb镜像
[root@zxone springboot]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
springweb 1.0 fc8ab2fb6f8d 6 seconds ago 661MB
tomcat latest 891fcd9c5b3a 5 days ago 647MB
redis latest bd571e6529f3 5 days ago 104MB
java 8 d23bdf5b1b1b 3 years ago 643MB
8.5、发布运行
#运行容器
[root@zxone springboot]# docker run -d -P --name springweb-1 springweb:1.0
2bcca6ca2e0862f328873659cedd4d3b5d1ef89c30816591087bdb91d173eb88
#查看端口
[root@zxone springboot]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2bcca6ca2e08 springweb:1.0 "java -jar /app.jar …" 9 seconds ago Up 8 seconds 0.0.0.0:32776->8080/tcp springweb-1
#请求
[root@zxone springboot]# curl localhost:32776
{"timestamp":"2020-10-19T16:49:17.982+0000","status":404,"error":"Not Found","message":"No message available","path":"/"}
[root@zxone springboot]# curl localhost:32776/hello/docker
hello world docker[root@zxone springboot]#
#能够正常返回请求,说明正常运行,达到目标