docker 入门学习记录

该文章根据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原理

域名访问容器

自定义网络

网络连通

不同段的容器网络连通

实战:部署Redis集群

SpringBoot微服务打包Docker镜像

结语


先决条件

若要在 CentOS 上开始使用 Docker 引擎,请确保满足先决条件,然后安装Docker

可直接参考:Linux安装Docker

操作系统要求

要安装 Docker 引擎,您需要 CentOS 7 或 8 的维护版本。存档版本不受支持或测试。

要求系统为64位、系统内核版本为 3.10 以上。

查看自己的内核

uname命令用于打印当前系统相关信息(内核版本号、硬件架构、主机名称和操作系统类型等)。

查看已安装的CentOS版本信息

cat /proc/version

docker信息查看命令

docker version	#显示docker的版本信息
docker info	    #显示docker的系统信息,包括镜像和容器的数量
docker --help	#docker帮助命令

卸载docker旧版本

$ sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

如果报告未安装这些包,可以进行安装。

基础命令

docker启动/重启/状态/关闭命令:

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

查看容器中的进程信息ps

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卷的技术,可以实现

nginx、tomcat、es安装练习

docker安装nginx

# 搜索镜像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安装tomcat

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十分的消耗内存
#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

什么是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

commit镜像

docker commit

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

docker 入门学习记录_第1张图片

 1、停止容器

​ 2、宿主机上修改文件

​ 3、启动容器

​ 4、容器内的数据依旧是同步的

好处:我们以后修改只需要在本地修改,容器内会自动同步!

实战:安装MySQL

​ 思考: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

Dockerfile是什么?

​ Dockerfile就是用来构建docker镜像的构建文件!命令参数脚本!先体验一下!

​ 通过这个脚本可以生成镜像,镜像是一层一层的,脚本一个个的命令,每个命令都是一层!

使用Dockerfile

# 创建一个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 入门学习记录_第2张图片

# 启动我们构建的镜像
docker run -it centos-yll:1.0 /bin/bash

docker 入门学习记录_第3张图片

这个卷和外部一定有一个同步的目录!

# 进入容器
docker run -it f8810f35da5f /bin/bash
cd volume01
touch ontainer.txt

确认目录中文件创建成功:

查看一下卷挂载的路径:

docker 入门学习记录_第4张图片

测试一下刚才的文件是否同步出去了!

进入宿主机对应路径查看:

这种方式我们以后用的会十分的多,因为通常我们自己构建镜像

假设构建镜像的时候没有挂载卷,要手动镜像挂载 -v 卷名 容器内路径!

数据卷容器

--volumes-from

使用 --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实现数据共享

# 启动第一个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详解

构建步骤

再次说明Dockerfile就是用来构建docker镜像的构建文件!命令参数脚本!

构建步骤:

​ 1、编写一个dockerfile文件

​ 2、docker build 构建成为一个镜像

​ 3、docker run 运行镜像

​ 4、docker push 发布镜像(DockerHub、阿里云镜像仓库)

DockerFile构建过程

基础知识:

1、每个保留关键字(指令)都必须是大写字母

2、执行从上到下顺序执行

3、#表示注释

4、每一个指令都会创建提交一个新的镜像层,并提交!

docker 入门学习记录_第5张图片

DockerFile是面向开发的,我们以后要发布项目,做镜像,就要编写dockerfile文件,这个文件十分简单!

Docker镜像逐渐成为企业交付的标准,必须要掌握!

步骤:开发、部署、运维。。。

DockerFile:构建文件,定义了一切的步骤,源代码

Dockerimages:通过DockerFile构建生成的镜像,最终发布和运行的产品,原来是jar war

Docker容器:容器就是镜像运行起来提供服务的

DockerFile的指令

docker 入门学习记录_第6张图片

FROM	        # 基础镜像,一切从这里开始构建
MAINTAINER	    # 镜像是谁写的,姓名+邮箱
RUN	            # 镜像构建时候需要运行的命令
ADD	            # 步骤,tomcat镜像,这个tomcat压缩包!添加内容
WORKDIR		    # 镜像的工作目录
VOLUME		    # 挂载的目录
EXPOSE		    # 保留端口配置
CMD		        # 指定这个容器启动时候运行的命令,只有最后一个会生效,可被代替
ENTRYPOINT	    # 指定这个容器启动时候运行的命令,可以追加命令
ONBUILD		    # 当构建一个被继承的Dockerfile 这个时候就会运行ONBUILD的指令,触发指令
COPY	        # 将文件拷贝到镜像中
ENV		        # 构建的时候设置环境变量

创建一个自己的centos,包含yum、ifconfig

[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 ./

构建成功最好会出现如上提示。

docker 入门学习记录_第7张图片

 

启动并进入容器,验证dockerfile中的命令:

docker 入门学习记录_第8张图片

可以列出本地进行的变更历史:

docker history 镜像id / 镜像名称:tag 

docker 入门学习记录_第9张图片

我们平时拿到一个镜像,可以通过这个研究一下他是怎么做的了

实战:Tomcat镜像

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

docker 入门学习记录_第10张图片

发布自己的镜像

DockerHub

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、后面的步骤可按照镜像仓库中的“基本信息”执行

docker 入门学习记录_第11张图片

6、如果push成功,但在镜像版本中找不到,需要注意:

docker 入门学习记录_第12张图片

这也是第4点中所说的 - 坑!

Docker小结

docker 流程图

docker 入门学习记录_第13张图片

Docker网络

理解docker0

docker 入门学习记录_第14张图片

 多个网络,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 通容器内部

docker0原理

1、我们每启动一个docker容器,docker就会分配一个ip,我们只要安装了docker,就会有一个网卡docker0,桥接模式,使用的技术是 evth-pair 技术!

2、容器内的网卡都是成对出现的,与宿主机新增的网卡地址对应

docker 入门学习记录_第15张图片

docker 入门学习记录_第16张图片

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

docker 入门学习记录_第17张图片

# 查看刚启动的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 入门学习记录_第18张图片

# 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]#

docker 入门学习记录_第19张图片

# 连通测试,发现都可以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 网络名称 容器 进行连通!

实战:部署Redis集群

集群模式:分片、高可用、负载均衡,总共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之后,所有的技术都会慢慢的变得简单起来!

SpringBoot微服务打包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

......

知道的越多,不知道的越多,

是不是再次点燃了求知的欲望!

加油!!!

你可能感兴趣的:(docker,docker,linux)