该文章根据B站“【狂神说Java】Docker最新超详细版教程通俗易懂”视频中记录而来
教学视频地址:https://www.bilibili.com/video/BV1og4y1q7M4
docker官网地址:https://www.docker.com
docker hub官网地址:https://hub.docker.com/
docker离线稳定版安装包:https://download.docker.com/linux/static/stable/x86_64/
docker安装说明官网地址:https://docs.docker.com/engine/install/centos/
目录
先决条件
操作系统要求
查看自己的内核
查看已安装的CentOS版本信息
docker信息查看命令
卸载docker旧版本
基础命令
docker启动/重启/状态/关闭命令:
镜像命令
容器命令
新建容器并启动
列出所有运行的容器
删除容器
退出容器
启动和停止容器的操作
其他常用命令
后台启动容器
查看日志
查看容器中的进程信息ps
查看镜像的元数据
进入当前正在运行的容器
从容器内拷贝文件到主机上
nginx、tomcat、es安装练习
docker安装nginx
docker安装tomcat
部署es
可视化portainer
commit镜像
docker commit
实战测试
容器数据卷
什么是容器数据卷?
使用数据卷
实战:安装MySQL
具名和匿名挂载
初识Dockerfile
Dockerfile是什么?
使用Dockerfile
数据卷容器
--volumes-from
多个mysql实现数据共享
DockerFile详解
构建步骤
DockerFile构建过程
DockerFile的指令
创建一个自己的centos,包含yum、ifconfig
实战:Tomcat镜像
发布自己的镜像
DockerHub
阿里云镜像服务
Docker小结
Docker网络
理解docker0
docker0原理
--link
域名访问容器
自定义网络
网络连通
不同段的容器网络连通
实战:部署Redis集群
SpringBoot微服务打包Docker镜像
结语
若要在 CentOS 上开始使用 Docker 引擎,请确保满足先决条件,然后安装Docker。
可直接参考:Linux安装Docker
要安装 Docker 引擎,您需要 CentOS 7 或 8 的维护版本。存档版本不受支持或测试。
要求系统为64位、系统内核版本为 3.10 以上。
uname命令用于打印当前系统相关信息(内核版本号、硬件架构、主机名称和操作系统类型等)。
cat /proc/version
docker version #显示docker的版本信息
docker info #显示docker的系统信息,包括镜像和容器的数量
docker --help #docker帮助命令
$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
如果报告未安装这些包,可以进行安装。
systemctl start docker # 启动
systemctl restart docker # 重启
systemctl status docker # 状态
systemctl stop docker # 停止
# 或者
service docker start # 启动
service docker restart # 重启
service docker status # 状态
service docker stop # 停止
systemctl enable docker # 设置开机启动
shutdown -r now # 重启linux服务器
systemctl status docker # 查看docker运行状态
docker images 查看所有本地主机上的镜像
docker search mysql 搜索镜像
docker pull mysql 下载镜像
docker pull mysql:5.7 指定版本下载
docker rmi -f ID/name 删除镜像
docker rmi -f 容器id 删除指定的镜像
docker rmi -f 镜像id 镜像id 镜像id 镜像id 删除多个镜像
docker rmi -f $(docker images -aq) #删除全部镜像
说明:有了镜像才可以创建容器,liunx,下载一个centos来测试学习
docker pull centos
docker run [可选参数] image
#参数说明
--name="Name" 容器名字 tomcat01 tomcat02 tomcat03,用来区分容器
-d 后台方式运行
-it 使用交互方式运行,进入容器查看内容
-p 制定容器的端口 -p 8080:8080
-p ip:主机端口:容器端口
-p 主机端口:容器端口
-p 容器端口
容器端口
-p 随机指定端口
#测试,启动并进入容器
docker run -it centos /bin/bash
docker ps 命令
-a #列出当前正在运行的容器+带出历史运行中的容器
-n=? #显示最近创建的容器
-q #只显示容器的编号
docker rm 容器id #删除指定的容器,不能删除在运行的容器,如果要强制删除 rm -f
docker rm -f $(docker ps -aq) #删除所有的容器
docker ps -a -q|xargs docker rm #删除所有的容器
exit #直接容器停止并退出
ctrl + P + Q #容器不停止退出
docker start 容器id #启动容器
docker restart 容器id #重启容器
docker stop 容器id #停止当前正在运行的容器
docker kill 容器id #停止当前容器
命令 docker run -d 镜像名
docker run -d centos
#问题docker ps,发现centos停止了
#常见的坑,docker容器使用后台运行,就必须要有一个前台进程,docker发现没有应用,就会自动停止
#nginx,容器启动后,发现自己没有提供服务,就会立即停止,就没有程序了。
docker logs -f -t --tail 容器
#显示日志
-tf #显示日志
-tail number #显示日志条数
docker logs -tf --tail 10 容器id
docker top 容器id
#命令
docker inspect 容器id
#我们通常都是使用后台的方式运行的,需要进入容器,修改一些配置
#命令
#方法一:
docker exec -it 容器id bashshell
eg:docker exec -it 容器id /bin/bash
ls
ps -ef
#方法二:
docker attach 容器id
docker exec #进入容器后开启一个新的终端,可以在里面操作(常用)
docker attach #进入容器正在执行的终端,不会启动新的进程
docker cp 容器id:容器内路径 目的主机路径
docker cp 容器id:/home/test.java /home
#拷贝是一个手动过程,未来我们使用 -v卷的技术,可以实现
# 搜索镜像search 建议大家去docker搜索,可以看到帮助文档
# 下载镜像 pull
# 运行测试
docker images
-d 后台运行
--name 给容器命名
-p 宿主机端口:容器内部端口
docker run -d --name nginx01 -p 3344:80 nginx
docker ps
curl localhost:3344
#进入容器
docker exec -it nginx01 /bin/bash
whereis nginx
cd /etc/nginx ls
docker run -it -rm tomcat:9.0
#我们之前的启动是后台,停止了容器之后,容器还是可以查到
docker run -it --rm,一般用来测试,用完之后就删除
#下载在启动
docker pull tomcat:9.0
#启动运行
docker run -d -p 3355:8080 --name tomcat01 tomcat
#测试访问没有问题
#进入容器
docker exec -it tomcat01 /bin/bash
#发现问题
1、linux命令少了
2、没有webapps 阿里云镜像的原因,默认是最小镜像,所有不必要的都剔除掉
#保证最小的可运行环境
思考:如果我们每次都要部署项目,每次进入容器是不是十分麻烦?我要是可以在容器外部提供一个映射路径,webapps,我们在外部部署项目,自动同步就好了!
#es暴露的端口很多
#es十分的消耗内存
#es的数据一般需要放置到安全目录,需要挂载
$ docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
#增加内存的限制,修改配置文件 -e 环境配置修改
$ docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2
什么是portainer?
Docker图形化界面管理工具,提供一个后台面板供我们操作
docker run -d -p 8088:9000 \
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
访问测试:http://ip:8088
docker commit 提交容器成为一个新的副本
#命令和git类似
docker commit -m "提交的描述信息" -a="作者" 容器id 目标镜像名:[tag]
#启动一个默认的tomcat
#发现这个默认的webapps是没有webapps应用的 镜像的原因,官方的镜像默认webapps是没有文件的
#自己拷贝进去了基本的文件
#将我们操作后的容器提交为一个镜像!我们以后就使用我们修改过后的镜像即可,这就是我们自己修改的一个镜像
学习方式说明:理解概念,但是一定要实践,最后理论和实践结合一次性搞定这个知识。
如果你想要保存当前容器的状态,就可以通过commit提交,获得一个镜像,就好比我们学习VM时候的快照,到这里才算是入门Docker!
docker理念回顾
将应用和环境打包成一个镜像
数据?如果数据都在容器中,那么我们删除容器,数据就会丢失! 需求:数据可以持久化
MySQL,容器删了,删库跑路! 需求:MySQL数据可以存储在本地!
容器之间可以有一个数据共享的技术!Docker容器中产生的数据,同步到本地!
这就是卷技术!目录的挂载,将我们容器里面的目录,挂载到Linux上面
总结一句话:容器的持久化和同步操作!容器间也是可以数据共享的!
方式一:直接用命令来挂载 -v
docker run -it -v 主机目录:容器内端目录
#测试
docker run -it -v /home/test:/home centos /bin/bash
#启动起来之后我们可以通过docker inspect 容器id
1、停止容器
2、宿主机上修改文件
3、启动容器
4、容器内的数据依旧是同步的
好处:我们以后修改只需要在本地修改,容器内会自动同步!
思考:MySQL的数据持久化问题
#获取镜像
docker pull mysql:5.7
#运行容器,需要做数据挂载: #安装启动mysql,需要配置密码,这是要注意的!
官方测试:docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
#启动我们的
-d 后台运行
-p 端口映射
-v 卷挂载
-e 环境配置
--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 -d mysql:5.7
# 启动成功之后,我们在本地使用Navicat连接测试一下
# Navicat 连接到服务器的3310
# 在本地测试创建一个数据库,查看一下我们映射的路径是否ok!
假设我们将容器删除
docker rm -f mysql01
发现我们挂载到本地的数据依旧没有丢失,这就实现了容器持久化的功能
#匿名挂载
-v 容器内路径
docker run -d -P --name nginx01 -v /etc/nginx nginx
#查看所有的volume情况
docker volume ls
# 结果
[root@localhost home]# docker volume ls
DRIVER VOLUME NAME
local 98b60dad5905b4fe8debe720439501022f270005c8bf5fbcfeac13c4cdbb0e38
#这里发现,这种就是匿名挂载,我们在-v只写了容器内的路径,没有写容器外的路径
#具名挂载
#通过 -v 卷名:容器内路径
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
#查看所有的volume情况
docker volume ls
# 结果
[root@localhost home]# docker volume ls
DRIVER VOLUME NAME
local 9addb3ec9635eedf180e977389ae9c9bdbb091984349d3bb2d0c04e9398bb682
local 98b60dad5905b4fe8debe720439501022f270005c8bf5fbcfeac13c4cdbb0e38
local juming-nginx
#查看一下这个卷
docker volume inspect juming-nginx
# 结果
[root@localhost home]# docker volume inspect juming-nginx
[
{
"CreatedAt": "2020-12-29T16:16:42+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data",
"Name": "juming-nginx",
"Options": null,
"Scope": "local"
}
]
所有的docker容器内的卷,没有指定目录的情况下都在:/var/lib/docker/volumes/xxxx/_data
我们通过具名挂载可以方便的找到我们的一个卷,大多数情况使用 具名挂载
如何确定是具名挂载路径,还是指定路径挂载!
-v 容器内路径 # 匿名挂载
-v 卷名:容器内路径 # 具名挂载
-v /宿主机路径::容器内路径 # 指定路径挂载
拓展:
#通过 -v 容器内路径:ro rw改变读写权限
ro readonly #只读
rw readwrite #读写
#一旦设置了容器权限,容器对我们挂在出来的内容就有限定了!
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx
ro 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部无法操作!
Dockerfile就是用来构建docker镜像的构建文件!命令参数脚本!先体验一下!
通过这个脚本可以生成镜像,镜像是一层一层的,脚本一个个的命令,每个命令都是一层!
# 创建一个dockerfile文件,名字可以随机 建议Dockerfile
# 文件中的内容 指令大写 参数
vim dockerfile01
FROM centos:7
VOLUME ["volume01","volume02"]
CMD echo "-----end-----"
CMD /bin/bash
:wq
# 这里的每个命令,就是镜像的一层
# 根据 dockerfile01 构建镜像
docker build -f dockerfile1 -t centos-yll:1.0 .
# -f dockerfile文件路径,-t 构建生成的镜像名字:版本号, . 生成路径
# 启动我们构建的镜像
docker run -it centos-yll:1.0 /bin/bash
这个卷和外部一定有一个同步的目录!
# 进入容器
docker run -it f8810f35da5f /bin/bash
cd volume01
touch ontainer.txt
确认目录中文件创建成功:
查看一下卷挂载的路径:
测试一下刚才的文件是否同步出去了!
进入宿主机对应路径查看:
这种方式我们以后用的会十分的多,因为通常我们自己构建镜像
假设构建镜像的时候没有挂载卷,要手动镜像挂载 -v 卷名 容器内路径!
使用 --volumes-from 实现多个容器间数据共享,测试:
# 启动第一个centos容器
docker run -it --name docker01 centosoyll:1.0
[root@2ff17142cc79 /]# ls
anaconda-post.log bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var volume01 volume02
# 启动第二个centos容器
docker run -it --name docker02 --volumes-from docker01 f8810f35da5f
[root@850fc4c2dc2e /]# ls
anaconda-post.log bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var volume01 volume02
# 确认两个容器中目录 /volume01 都为空
# 进入容器1目录 /volume01,并创建一个文件,查看容器2中对应目录是否同步
cd /volume01
touch docker01
同样可以启动第三个centos容器,可以挂载在 docker01 / docker02上,测试验证创建/删除文件依然同步。
# 启动第一个mysql容器
[root@localhost docker-test-volume]# docker run -d -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
# 启动第二个mysql容器,并挂载mysql01
[root@localhost docker-test-volume]# docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7
# 这个时候,就可以实现两个或多个mysql容器数据同步!
结论:
容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。
但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的!
再次说明Dockerfile就是用来构建docker镜像的构建文件!命令参数脚本!
构建步骤:
1、编写一个dockerfile文件
2、docker build 构建成为一个镜像
3、docker run 运行镜像
4、docker push 发布镜像(DockerHub、阿里云镜像仓库)
基础知识:
1、每个保留关键字(指令)都必须是大写字母
2、执行从上到下顺序执行
3、#表示注释
4、每一个指令都会创建提交一个新的镜像层,并提交!
DockerFile是面向开发的,我们以后要发布项目,做镜像,就要编写dockerfile文件,这个文件十分简单!
Docker镜像逐渐成为企业交付的标准,必须要掌握!
步骤:开发、部署、运维。。。
DockerFile:构建文件,定义了一切的步骤,源代码
Dockerimages:通过DockerFile构建生成的镜像,最终发布和运行的产品,原来是jar war
Docker容器:容器就是镜像运行起来提供服务的
FROM # 基础镜像,一切从这里开始构建
MAINTAINER # 镜像是谁写的,姓名+邮箱
RUN # 镜像构建时候需要运行的命令
ADD # 步骤,tomcat镜像,这个tomcat压缩包!添加内容
WORKDIR # 镜像的工作目录
VOLUME # 挂载的目录
EXPOSE # 保留端口配置
CMD # 指定这个容器启动时候运行的命令,只有最后一个会生效,可被代替
ENTRYPOINT # 指定这个容器启动时候运行的命令,可以追加命令
ONBUILD # 当构建一个被继承的Dockerfile 这个时候就会运行ONBUILD的指令,触发指令
COPY # 将文件拷贝到镜像中
ENV # 构建的时候设置环境变量
[root@localhost dockerfile]# cat mydockerfile-centos
FROM centos:7
MAINTAINER yaoll<[email protected]>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "------end------"
CMD /bin/bash
构建镜像:
docker build -f dockerfile文件路径 -t 镜像名:[tag]
docker build -f ./mydockerfile-centos -t my-centos:0.1 ./
构建成功最好会出现如上提示。
启动并进入容器,验证dockerfile中的命令:
可以列出本地进行的变更历史:
docker history 镜像id / 镜像名称:tag
我们平时拿到一个镜像,可以通过这个研究一下他是怎么做的了
1、准备镜像文件,tomcat压缩包,jdk压缩包
apache-tomcat-9.0.40.tar.gz
jdk-8u231-linux-x64.tar.gz
2、编写dockerfile文件,官方命名 "Dockerfile" ,build会自动寻找这个文件,就不需要 -f 指定了!
[root@localhost local]# cd dockerfile
[root@localhost local]# touch readme.txt
[root@localhost dockerfile]# vim Dockerfile
FROM centos:7
MAINTAINER yaoll<[email protected]>
COPY readme.txt /usr/local/readme.txt
ADD software/jdk-8u231-linux-x64.tar.gz /usr/local
ADD software/apache-tomcat-9.0.40.tar.gz /usr/local
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_231
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.40
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.40
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_BASH/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.40/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.40/bin/logs/catalina.out
# 保存退出
:wq!
# 构建镜像
[root@localhost dockerfile]# docker build -t my-tomcat:0.1 .
注意:ADD/COPY指令默认只能操作与 “Dockerfile” 同一级目录的文件,若需要操作其它目录的文件则需要配置;
3、查看构建成功的镜像:
docker images
4、启动镜像,并挂载发布目录和日志目录:
docker run -d -p 8080:8080 --name my-tomcat -v /usr/local/tomcat/test:/usr/local/apache-tomcat-9.0.40/webapps/test -v /usr/local/tomcat/logs:/usr/local/apache-tomcat-9.0.40/logs my-tomcat:0.1
5、确认目录挂载成功
6、访问测试
宿主机访问:curl localhost:8080
或本地浏览器:宿主机IP:8080
7、发布项目(由于做了卷挂载,我们直接在本地编写项目就可以发布了!)
宿主机操作:
[root@localhost test]# cd /usr/local/tomcat/test
[root@localhost test]# vim indexsuccess.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
Insert title here
登陆成功
# 保存退出
:wq!
8、浏览器访问:http://宿主机IP:8080/test/indexsuccess.jsp
1、地址:https://hub.docker.com/,注册自己的账号
2、确定这个账号可以登录
3、在我们自己的服务器上提交镜像
docker login --help
docker login -u xiaoming
password:
4、标记image
将本地映像与注册表上的存储库相关联的表示法是 username/repository:tag。标签是可选的,但建议使用,因为它是注册管理机构用来为Docker镜像提供版本的机制。为上下文提供存储库和标记有意义的名称,例如 get-started:part2。这会将图像放入get-started存储库并将其标记为part2。
现在,把它们放在一起来标记图像。docker tag image使用您的用户名,存储库和标记名称运行,以便将图像上载到所需的目标位置。该命令的语法是:
docker tag image username/repository:tag
# 例如:
docker tag my-tomcat:0.1 yaoll/tomcat:0.0.1
5、发布image
将标记的图像上传到存储库:
docker push username/repository:tag
# 例如
docker push yaoll/tomcat:0.0.1
完成后,此上传的结果将公开发布。如果您登录到Docker Hub,则会在其中看到新图像及其pull命令。
6、远程存储库中拉出并运行镜像
提交完成后,可以使用docker run以下命令在任何计算机上使用和运行您的应用程序:
docker run -p 4000:80 username/repository:tag
# 例如
docker run -d -p 9090:8080 yaoll/tomcat:0.0.1
无论在哪里docker run执行,它都会提取您的图像,以及tomcat和所有依赖项jdk,并运行您的代码。
它们都在一个镜像内,你不需要在主机上安装任何东西,以便Docker运行它。
如果映像在计算机上不可用,则Docker会从存储库中提取映像。
1、登录阿里云
2、找到容器镜像服务
3、创建命名空间
4、创建镜像仓库,仓库名字最好为要push的镜像名字,坑,下面截图讲
5、后面的步骤可按照镜像仓库中的“基本信息”执行
6、如果push成功,但在镜像版本中找不到,需要注意:
这也是第4点中所说的 - 坑!
docker 流程图
多个网络,docker是如何处理容器网络访问的?
# 启动一个tomcat容器
[root@localhost /]# docker run -d -P --name tomcat01 tomcat:10.0.0
# 查看容器的内部网络地址
[root@localhost /]# docker exec -it tomcat01 ip addr
1: lo: 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
15: eth0@if16: 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
# 会发现容器启动的时候会得到一个 eth0@if16 ip地址,是docker自动分配的!
# 思考,linux 能不能 ping 通容器内部?!
[root@localhost /]# 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.060 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.100 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.037 ms
# linux 可以 ping 通容器内部
1、我们每启动一个docker容器,docker就会分配一个ip,我们只要安装了docker,就会有一个网卡docker0,桥接模式,使用的技术是 evth-pair 技术!
2、容器内的网卡都是成对出现的,与宿主机新增的网卡地址对应
3、evth-pair 就是一对的虚拟设备接口,它们都是成对出现的,一端连着协议,一端彼此相连,正因为有这个特性,evth-pair 充当一个桥梁,连接各种虚拟网络设备,OpenStac,Docker容器之间的连接,ovs的连接,都是使用 evth-pair 技术
4、测试容器间也可以互相ping通
# 启动第二个tomcat容器
[root@localhost /]# docker run -d -P --name tomcat02 a9bea8c99312
45cb19c4d08262c7ab70c86e5a29ad08c849be456216399cd721eb1421ef6b29
[root@localhost /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
45cb19c4d082 a9bea8c99312 "catalina.sh run" 3 seconds ago Up 2 seconds 0.0.0.0:49154->8080/tcp tomcat02
df68a1c946d8 tomcat:10.0.0 "catalina.sh run" 20 minutes ago Up 20 minutes 0.0.0.0:49153->8080/tcp tomcat01
# 查看tomcat02的ip地址
[root@localhost /]# docker exec -it 45cb19c4d082 ip addr
1: lo: 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
17: eth0@if18: mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 进入tomcat02容器并ping tomcat01 的ip,发现可以ping通
[root@localhost /]# docker exec -it 45cb19c4d082 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.074 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.049 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.050 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.046 ms
64 bytes from 172.17.0.2: icmp_seq=5 ttl=64 time=0.045 ms
结论:
1、tomcat01和tomcat02是公用的一个路由器,docker0;
2、所有的容器不指定网络的情况下,都是docker0路由的,docker会给我们的容器分配一个默认的可用IP;
3、Docker使用的是Linux的桥接,宿主机中是一个Docker容器的网桥 docker0;
4、Docker中所有的网络接口都是虚拟的,虚拟的转发效率高!(内网传递文件!);
5、只要容器删除,对应的一对网桥也被删除!
思考一个场景,我们编写了一个微服务,配置中有:database url=ip:port,数据库容器重启后ip换掉了,项目不重启的情况下,我们希望可以处理这个问题,可以使用名字来进行访问容器?
[root@localhost /]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known
# 发现直接使用容器名字是ping不通的
# 使用 --link 启动tomcat03
[root@localhost /]# docker run -d -P --name tomcat03 --link tomcat02 tomcat:10.0.0
e90ed9449d27cb6a14be0648ec566d44a9b6de39393117649eb2c99dce8278de
[root@localhost /]# docker exec -it tomcat03 ping tomcat02
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.058 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.042 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=3 ttl=64 time=0.045 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=4 ttl=64 time=0.038 ms
# 发现通过容器名字 tomcat03 可以ping通 tomcat02
# 但 tomcat02 却ping不通 tomcat03
[root@localhost /]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known
tomcat03之所以能ping通tomcat02,是因为tomcat03在本地配置了tomcat02的IP映射
[root@localhost /]# 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 45cb19c4d082
172.17.0.4 e90ed9449d27
本质探究:--link 就是我们在hosts配置中增加了一个 172.17.0.3 tomcat02 45cb19c4d082 的配置
我们现在玩docker已经不建议使用 --link 了,--link适合新手使用
使用自定义网络,不使用docker0!
docker0问题:它不支持容器名连接访问
查看所有的docker网络
[root@localhost dockerfile]# docker network ls
NETWORK ID NAME DRIVER SCOPE
f601172c468f bridge bridge local
9a67b5ce79f6 host host local
6bcc6be90ce3 none null local
网络模式
bridge: 桥接 ,docker默认网络,自己创建网络也使用bridge模式,通过路由器来搭桥,比如路由器为0.1,0.2和0.3可以通过0.1来进行通信;
none: 不配置网络;
host: 和宿主机共享网络;
container: 容器网络连通,用的少,局限很大!
测试
# 直接启动的命令 --net bridge,而这个就是docker0
docker run -d -P --name tomcat01 tomcat:10.0.0
# 等同于
docker run -d -P --name tomcat01 --net bridge tomcat:10.0.0
docker0特点:默认使用,域名不能访问, --link可以打通连接,但是--link比较麻烦,不建议使用;
我们可以自定义一个网络!
# 创建一个 /16(255*255)个ip的网络 mynet, /24为 255 个ip
# --driver bridge 桥接模式
# --subnet 192.168.0.0/16 子网地址,范围: 192.168.0.2 ~ 192.168.255.255
# 192.168.0.0为自循环网络,192.168.0.1为网关
# --gateway 192.168.0.1 网关
# mynet 网络名称
[root@localhost dockerfile]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
797a77250ba995fa9252767df157353832114642354a99f1ad7c3528ce81595b
# 创建成功后查看所有docker网络,可以发现mynet
[root@localhost dockerfile]# docker network ls
NETWORK ID NAME DRIVER SCOPE
f601172c468f bridge bridge local
9a67b5ce79f6 host host local
797a77250ba9 mynet bridge local
6bcc6be90ce3 none null local
[root@localhost dockerfile]#
查看我们自己创建的网络信息
[root@localhost dockerfile]# docker inspect mynet
[
{
"Name": "mynet",
"Id": "797a77250ba995fa9252767df157353832114642354a99f1ad7c3528ce81595b",
"Created": "2021-01-05T09:48:31.328903129+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.0.0/16",
"Gateway": "192.168.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
测试我们自己创建的网络
# 启动两个tomcat容器,并指定使用自定义网络 mynet
[root@localhost dockerfile]# docker run -d -P --name tomcat-net-01 --net mynet tomcat:10.0.0
1b0309be559a0f95643908e4af84996f97aae534469ddb879c04b72849b8764b
[root@localhost dockerfile]# docker run -d -P --name tomcat-net-02 --net mynet tomcat:10.0.0
559243c96f2f5b2b9463a5f59c7aee76489249039cda1ab74a9dac77b5312ec0
# 再次查看自定义网络信息
[root@localhost dockerfile]# docker inspect mynet
# 查看刚启动的tomcat容器信息
[root@localhost dockerfile]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
559243c96f2f tomcat:10.0.0 "catalina.sh run" 4 minutes ago Up 4 minutes 0.0.0.0:49156->8080/tcp tomcat-net-02
1b0309be559a tomcat:10.0.0 "catalina.sh run" 4 minutes ago Up 4 minutes 0.0.0.0:49155->8080/tcp tomcat-net-01
# 使用tomcat-net-01 ping tomcat-net-02的IP,可以ping通
[root@localhost dockerfile]# docker exec -it tomcat-net-01 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.073 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.045 ms
64 bytes from 192.168.0.3: icmp_seq=3 ttl=64 time=0.049 ms
64 bytes from 192.168.0.3: icmp_seq=4 ttl=64 time=0.043 ms
^C
--- 192.168.0.3 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 4ms
rtt min/avg/max/mdev = 0.043/0.052/0.073/0.014 ms
# 使用tomcat-net-01 ping tomcat-net-02的容器名,可以ping通
[root@localhost dockerfile]# docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.046 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.046 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.052 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=4 ttl=64 time=0.141 ms
^C
--- tomcat-net-02 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3ms
rtt min/avg/max/mdev = 0.046/0.071/0.141/0.040 ms
# 使用tomcat-net-02 ping tomcat-net-01的IP,可以ping通
[root@localhost dockerfile]# docker exec -it tomcat-net-02 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.082 ms
64 bytes from 192.168.0.2: icmp_seq=2 ttl=64 time=0.135 ms
64 bytes from 192.168.0.2: icmp_seq=3 ttl=64 time=0.045 ms
^C
--- 192.168.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 3ms
rtt min/avg/max/mdev = 0.045/0.087/0.135/0.037 ms
# 使用tomcat-net-02 ping tomcat-net-01的容器名,可以ping通
[root@localhost dockerfile]# docker exec -it tomcat-net-02 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.038 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.054 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=3 ttl=64 time=0.043 ms
^C
--- tomcat-net-01 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 3ms
rtt min/avg/max/mdev = 0.038/0.045/0.054/0.006 ms
[root@localhost dockerfile]#
我们自定义的网络docker都已经帮我们维护好了对应的关系,推荐我们平时这样使用网络!
好处:redis集群、es集群...不同的集群使用不同的网络,保证集群是安全和健康的,
比如redis集群的网段为:192.168.*.*,es集群的网段为:192.161.*.*,保证各集群间网络的隔离,
同时各集群间的网络也可以连通,下面就是网络连通的操作------
# 再启动两个默认网络docker0的tomcat容器
[root@localhost dockerfile]# docker run -d -p 9090:8080 --name tomcat01 tomcat:10.0.0
07e104388f548729f190cc539723a9b8866e7856dbda35e2162e0c3e8c432999
[root@localhost dockerfile]# docker run -d -p 9091:8080 --name tomcat02 tomcat:10.0.0
b0af0d3af437d18b5f6dfe88a9195cdce0aaee03ea7c209242cc33f12c693222
# 总共有4个tomcat容器,2个默认网络,2个自定义网络
[root@localhost dockerfile]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b0af0d3af437 tomcat:10.0.0 "catalina.sh run" 3 seconds ago Up 2 seconds 0.0.0.0:9091->8080/tcp tomcat02
07e104388f54 tomcat:10.0.0 "catalina.sh run" 12 seconds ago Up 11 seconds 0.0.0.0:9090->8080/tcp tomcat01
559243c96f2f tomcat:10.0.0 "catalina.sh run" 31 minutes ago Up 31 minutes 0.0.0.0:49156->8080/tcp tomcat-net-02
1b0309be559a tomcat:10.0.0 "catalina.sh run" 31 minutes ago Up 31 minutes 0.0.0.0:49155->8080/tcp tomcat-net-01
# 测试连通性,发现ping不通
[root@localhost dockerfile]# docker exec -it tomcat01 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known
[root@localhost dockerfile]# docker exec -it tomcat01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
^C
--- 192.168.0.3 ping statistics ---
使用 docker network connect 命令进行容器间不同网段的网络连通
# docker network connect 网络名称 容器名称/ID
# 将网络mynet 和容器tomcat01进行连通
[root@localhost dockerfile]# docker network connect mynet tomcat01
# 查看mynet的变化
[root@localhost dockerfile]# docker inspect mynet
[
{
"Name": "mynet",
"Id": "797a77250ba995fa9252767df157353832114642354a99f1ad7c3528ce81595b",
"Created": "2021-01-05T09:48:31.328903129+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.0.0/16",
"Gateway": "192.168.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"07e104388f548729f190cc539723a9b8866e7856dbda35e2162e0c3e8c432999": {
"Name": "tomcat01",
"EndpointID": "90d82dcb927900c8a1237918e02ffc12f9555007e00b932df27e12a3c8f2c333",
"MacAddress": "02:42:c0:a8:00:04",
"IPv4Address": "192.168.0.4/16",
"IPv6Address": ""
},
"1b0309be559a0f95643908e4af84996f97aae534469ddb879c04b72849b8764b": {
"Name": "tomcat-net-01",
"EndpointID": "ad77b433899dae71b2622749c6b40f10d876d09723f5c316e88c7f95d04cb9cc",
"MacAddress": "02:42:c0:a8:00:02",
"IPv4Address": "192.168.0.2/16",
"IPv6Address": ""
},
"559243c96f2f5b2b9463a5f59c7aee76489249039cda1ab74a9dac77b5312ec0": {
"Name": "tomcat-net-02",
"EndpointID": "409fac443cda98e970ee839cdd57bddc44f7add278dbcb5d81f2ce507887bf32",
"MacAddress": "02:42:c0:a8:00:03",
"IPv4Address": "192.168.0.3/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
[root@localhost dockerfile]#
# 连通测试,发现都可以ping通了
[root@localhost dockerfile]# docker exec -it tomcat01 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.074 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.048 ms
64 bytes from 192.168.0.3: icmp_seq=3 ttl=64 time=0.044 ms
^C
--- 192.168.0.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.044/0.055/0.074/0.014 ms
[root@localhost dockerfile]# docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.057 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.044 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=3 ttl=64 time=0.044 ms
^C
--- tomcat-net-01 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.044/0.048/0.057/0.008 ms
[root@localhost dockerfile]# docker exec -it tomcat01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.043 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.052 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.050 ms
^C
--- tomcat-net-02 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 3ms
rtt min/avg/max/mdev = 0.043/0.048/0.052/0.006 ms
[root@localhost dockerfile]#
发现连通之后就是将 tomcat01 放到了 mynet 的网络配置下
实现了一个容器两个ip地址!比如阿里云服务,有公网ip和私网ip
但此时 tomcat02 是ping 不通 tomcat-net-01 的
[root@localhost dockerfile]# docker exec -it tomcat02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known
[root@localhost dockerfile]# docker exec -it tomcat02 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
^C
--- 192.168.0.3 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 1000ms
[root@localhost dockerfile]#
结论:假设要跨网络操作容器,就需要使用 docker network connect 网络名称 容器 进行连通!
集群模式:分片、高可用、负载均衡,总共6个redis节点,设置一个分片(3个数据节点,3个备份节点)
1、设置redis集群网卡及查看
# 创建reids网络
[root@localhost dockerfile]# docker network create redis --subnet 172.38.0.0/16
8ac75d3c4b983e465a7076e854fd749cd8b7198efaf3bd46956cc9b531d99064
# 查看docker所有网络
[root@localhost dockerfile]# docker network ls
NETWORK ID NAME DRIVER SCOPE
f601172c468f bridge bridge local
9a67b5ce79f6 host host local
797a77250ba9 mynet bridge local
6bcc6be90ce3 none null local
8ac75d3c4b98 redis bridge local
# redis网络信息查看
[root@localhost dockerfile]# docker inspect redis
[
{
"Name": "redis",
"Id": "8ac75d3c4b983e465a7076e854fd749cd8b7198efaf3bd46956cc9b531d99064",
"Created": "2021-01-05T12:37:10.059518687+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": {}
}
]
2、 redis节点创建及设置
使用脚本循环创建6个redis配置文件,直接复制粘贴,回车即可;
for port in $(seq 1 6);
do
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/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}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
3、拉取redis镜像并启动redis节点(6个)
[root@localhost /]# docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
> -v /mydata/redis/node-1/data:/data \
> -v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
> -d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
1d511f2f4aad6ef4bf9ea82de0fd0ebf81d5961bff9dbd803bddaf6ddaf73a91
[root@localhost /]# docker run -p 6372:6379 -p 16372:16379 --name redis-2 \
> -v /mydata/redis/node-2/data:/data \
> -v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \
> -d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
6c73a2adf1366e15e44d2cf67f0204360fc3f6d036c92842bc0775c19ad2028d
[root@localhost /]# docker run -p 6373:6379 -p 16373:16379 --name redis-3 \
> -v /mydata/redis/node-3/data:/data \
> -v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf \
> -d --net redis --ip 172.38.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
efbba0c74cc2b836af1f387501ad7a0ec12e894b2ec45b758a78c82cf326b3bd
[root@localhost /]# docker run -p 6374:6379 -p 16374:16379 --name redis-4 \
> -v /mydata/redis/node-4data:/data \
> -v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf \
> -d --net redis --ip 172.38.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
d7b03448c9cfc76b4216788cfb48b0a25f35b06d521a67535cd1b4f94b77e435
[root@localhost /]# docker run -p 6375:6379 -p 16375:16379 --name redis-5 \
> -v /mydata/redis/node-5/data:/data \
> -v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf \
> -d --net redis --ip 172.38.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
d09f1b5db5cfa9468ae19d43ebd132a841de8502221a1f2cd7ffd95fedb596b8
[root@localhost /]# docker run -p 6376:6379 -p 16376:16379 --name redis-6 \
> -v /mydata/redis/node-6/data:/data \
> -v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \
> -d --net redis --ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
da51b04bdb63fad2c9083811f420f8cd6d423460bf84366dceb712ca6968bdc3
[root@localhost /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
da51b04bdb63 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 3 seconds ago Up 3 seconds 0.0.0.0:6376->6379/tcp, 0.0.0.0:16376->16379/tcp redis-6
d09f1b5db5cf redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 10 seconds ago Up 9 seconds 0.0.0.0:6375->6379/tcp, 0.0.0.0:16375->16379/tcp redis-5
d7b03448c9cf redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 16 seconds ago Up 16 seconds 0.0.0.0:6374->6379/tcp, 0.0.0.0:16374->16379/tcp redis-4
efbba0c74cc2 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 24 seconds ago Up 24 seconds 0.0.0.0:6373->6379/tcp, 0.0.0.0:16373->16379/tcp redis-3
6c73a2adf136 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 34 seconds ago Up 33 seconds 0.0.0.0:6372->6379/tcp, 0.0.0.0:16372->16379/tcp redis-2
1d511f2f4aad redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 51 seconds ago Up 50 seconds 0.0.0.0:6371->6379/tcp, 0.0.0.0:16371->16379/tcp redis-1
4、以交互模式进入redis节点内
[root@localhost /]# docker exec -it redis-1 /bin/sh
/data # ls
appendonly.aof nodes.conf
# 默认进入data目录
5、创建redis集群
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
6、运行成功界面如下,(主从复制)集群创建成功
/data # 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: bb53e4c49dcc220a4f7deba8399d4d2cb291d8ed 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
M: f0a996ae22a7b808384a85a55d9a8dfed89ad772 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
M: 993a02689e7ab26cdf471034a2ed514a220101de 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
S: 744539fe1290d8b2757b1783d55fd876773fbb4e 172.38.0.14:6379
replicates 993a02689e7ab26cdf471034a2ed514a220101de
S: 77780712a9ba52272bade607d8222e4026b15b5e 172.38.0.15:6379
replicates bb53e4c49dcc220a4f7deba8399d4d2cb291d8ed
S: 29a6404a53c742d1eec53fd682e229a80abbfd37 172.38.0.16:6379
replicates f0a996ae22a7b808384a85a55d9a8dfed89ad772
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: bb53e4c49dcc220a4f7deba8399d4d2cb291d8ed 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 744539fe1290d8b2757b1783d55fd876773fbb4e 172.38.0.14:6379
slots: (0 slots) slave
replicates 993a02689e7ab26cdf471034a2ed514a220101de
M: f0a996ae22a7b808384a85a55d9a8dfed89ad772 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
M: 993a02689e7ab26cdf471034a2ed514a220101de 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: 77780712a9ba52272bade607d8222e4026b15b5e 172.38.0.15:6379
slots: (0 slots) slave
replicates bb53e4c49dcc220a4f7deba8399d4d2cb291d8ed
S: 29a6404a53c742d1eec53fd682e229a80abbfd37 172.38.0.16:6379
slots: (0 slots) slave
replicates f0a996ae22a7b808384a85a55d9a8dfed89ad772
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
7、创建集群成功后,可以进一步查看集群配置,并进行测试
# redis-cli -c 为集群连接,redis-cli 为单机
/data # redis-cli -c
# 查看集群信息
127.0.0.1:6379> cluster info
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:461
cluster_stats_messages_pong_sent:454
cluster_stats_messages_sent:915
cluster_stats_messages_ping_received:449
cluster_stats_messages_pong_received:461
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:915
# 查看节点信息,3主3从
127.0.0.1:6379> cluster nodes
744539fe1290d8b2757b1783d55fd876773fbb4e 172.38.0.14:6379@16379 slave 993a02689e7ab26cdf471034a2ed514a220101de 0 1609825408115 4 connected
f0a996ae22a7b808384a85a55d9a8dfed89ad772 172.38.0.12:6379@16379 master - 0 1609825409000 2 connected 5461-10922
993a02689e7ab26cdf471034a2ed514a220101de 172.38.0.13:6379@16379 master - 0 1609825409123 3 connected 10923-16383
77780712a9ba52272bade607d8222e4026b15b5e 172.38.0.15:6379@16379 slave bb53e4c49dcc220a4f7deba8399d4d2cb291d8ed 0 1609825408000 5 connected
bb53e4c49dcc220a4f7deba8399d4d2cb291d8ed 172.38.0.11:6379@16379 myself,master - 0 1609825408000 1 connected 0-5460
29a6404a53c742d1eec53fd682e229a80abbfd37 172.38.0.16:6379@16379 slave f0a996ae22a7b808384a85a55d9a8dfed89ad772 0 1609825407612 6 connected
8、关于redis集群高可用的简单测试
/data # redis-cli -c # 连接集群
127.0.0.1:6379> set a b # 设置值
-> Redirected to slot [15495] located at 172.38.0.13:6379
OK
# 发现是ip为 172.38.0.13 的节点保存的,取值看下
172.38.0.13:6379> get a
"b"
# 用docker stop模拟存储a值的redis主机宕机
[root@localhost /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
da51b04bdb63 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 19 minutes ago Up 19 minutes 0.0.0.0:6376->6379/tcp, 0.0.0.0:16376->16379/tcp redis-6
d09f1b5db5cf redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 19 minutes ago Up 19 minutes 0.0.0.0:6375->6379/tcp, 0.0.0.0:16375->16379/tcp redis-5
d7b03448c9cf redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 19 minutes ago Up 19 minutes 0.0.0.0:6374->6379/tcp, 0.0.0.0:16374->16379/tcp redis-4
efbba0c74cc2 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 19 minutes ago Up 19 minutes 0.0.0.0:6373->6379/tcp, 0.0.0.0:16373->16379/tcp redis-3
6c73a2adf136 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 19 minutes ago Up 19 minutes 0.0.0.0:6372->6379/tcp, 0.0.0.0:16372->16379/tcp redis-2
1d511f2f4aad redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 20 minutes ago Up 20 minutes 0.0.0.0:6371->6379/tcp, 0.0.0.0:16371->16379/tcp redis-1
# 发现是 redis-3存储的,我们将 redis-3 容器停掉
[root@instance-001 panhom]# docker stop redis-3
redis-3
# 确认 redis-3已经停掉
[root@localhost /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
da51b04bdb63 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 19 minutes ago Up 19 minutes 0.0.0.0:6376->6379/tcp, 0.0.0.0:16376->16379/tcp redis-6
d09f1b5db5cf redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 19 minutes ago Up 19 minutes 0.0.0.0:6375->6379/tcp, 0.0.0.0:16375->16379/tcp redis-5
d7b03448c9cf redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 20 minutes ago Up 20 minutes 0.0.0.0:6374->6379/tcp, 0.0.0.0:16374->16379/tcp redis-4
6c73a2adf136 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 20 minutes ago Up 20 minutes 0.0.0.0:6372->6379/tcp, 0.0.0.0:16372->16379/tcp redis-2
1d511f2f4aad redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 20 minutes ago Up 20 minutes 0.0.0.0:6371->6379/tcp, 0.0.0.0:16371->16379/tcp redis-1
//重新进入集群交互界面,并尝试获取a消息
^C
/data # redis-cli -c
127.0.0.1:6379> get a
-> Redirected to slot [15495] located at 172.38.0.14:6379
"b"
# 发现此时由备用机 172.38.0.14 返回a值
9、查看节点信息,说明docker搭建redis集群成功完成!
127.0.0.1:6379> cluster nodes
744539fe1290d8b2757b1783d55fd876773fbb4e 172.38.0.14:6379@16379 master - 0 1609826600000 7 connected 10923-16383
f0a996ae22a7b808384a85a55d9a8dfed89ad772 172.38.0.12:6379@16379 master - 0 1609826600776 2 connected 5461-10922
993a02689e7ab26cdf471034a2ed514a220101de 172.38.0.13:6379@16379 master,fail - 1609825988429 1609825985903 3 connected
77780712a9ba52272bade607d8222e4026b15b5e 172.38.0.15:6379@16379 slave bb53e4c49dcc220a4f7deba8399d4d2cb291d8ed 0 1609826600574 5 connected
bb53e4c49dcc220a4f7deba8399d4d2cb291d8ed 172.38.0.11:6379@16379 myself,master - 0 1609826599000 1 connected 0-5460
29a6404a53c742d1eec53fd682e229a80abbfd37 172.38.0.16:6379@16379 slave f0a996ae22a7b808384a85a55d9a8dfed89ad772 0 1609826600000 6 connected
# 发现 172.38.0.13 节点已经挂掉,但仍不影响我们存取数据
我们使用了docker之后,所有的技术都会慢慢的变得简单起来!
1、构建springboot项目,写一个简单的测试接口即可
2、打包应用,docker-test.jar
3、编写dockerfile,新建Dockerfile文件,写入一下内容:
# 基础镜像,基于java8环境
FROM java:8
# 将所有jar包复制到镜像中并重命名为app.jar,这里测试只有一个jar,实际可指定名称复制
COPY *.jar /app.jar
# jar包启动时指定端口参数
CMD ["--server.port=8088"]
# 暴露端口,以便外部访问
EXPOSE 8088
# 启动命令
ENTRYPOINT ["java","-jar","/app.jar"]
4、创建jar包放置目录,并上传jar和Dockerfile
[root@localhost /]# cd /usr/local
[root@localhost local]# mkdir app
[root@localhost local]# cd app
# 将jar包和Dockerfile上传至该目录
5、构建镜像
# 构建镜像
[root@localhost app]# docker build -t docker-test:0.1 .
# 构建成功后,查看镜像
[root@localhost app]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-test 0.1 26b7db4e084f About a minute ago 740MB
java 8 d23bdf5b1b1b 3 years ago 643MB
6、发布运行
# 启动容器
[root@localhost app]# docker run -d -p 9099:8088 --name docker-test docker-test:0.1
bfa69672d7fa2d4082280cc0cd99f4e329e4bdf9242bd3f83bc0f78c962571a1
# 查看容器
[root@localhost app]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bfa69672d7fa docker-test:0.1 "java -jar /app.jar …" 6 seconds ago Up 6 seconds 0.0.0.0:9099->8088/tcp docker-test
# 测试接口
[root@localhost app]# curl http://192.168.56.105:9099/docker-test/test/result/helloDocker
{"code":200,"msg":"Success","data":"访问成功了!helloDocker"}[root@localhost app]#
以后我们使用了docker之后,给别人交付一个镜像即可!
到目前为止我们已经掌握了Docker的基本知识,以及使用方式,这些已经足够玩转单机Docker;
但若是企业级的Docker应用,这些还远远不够,企业级的都是集群式部署,因此企业实战还要学习
Docker Compose
Docker Swarm
CI/CD jenkins
k8s
......
知道的越多,不知道的越多,
是不是再次点燃了求知的欲望!
加油!!!