docker基础

docker基础

1.docker 介绍

docker是什么

  • 使用最广泛的开源容器引擎
  • 一种操作系统级的虚拟化技术
    • 使用docker创建的容器以一种特殊进程的方式在宿主机上运行
  • 一个简单的应用程序打包工具

docker理念:一次构建封装到处运行

docker:解决了运行环境和配置问题软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术。

docker能干嘛

1.之前的虚拟机技术

2.容器虚拟化技术

3.开发/运维

4.企业级

与虚拟机的区别

虚拟机可以在一种操作系统里面运行另一种操作系统,比如在Windows里面运行linux系统。应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对与底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响。这类虚拟机完美的运行了另一套系统,能够使应用程序,操作系统和硬件三者之间的逻辑不变。

虚拟机的缺点

1.资源占用多 2.冗余步骤多 3.启动慢

比较docker和传统虚拟机的不同:
1.传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整的操作系统,在该系统上再运行所需应用进程;
2.而容器内的应用进程直接运行与宿主机的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便;
3.每个容器之间互相隔离,每个容器有自己的文件系统,容器之间进程不会互相影响,能区分计算资源。
docker容器虚拟机(VM)
操作系统与宿主机共享OS宿主机OS上运行虚拟机OS
存储大小镜像小,便于存储与传输镜像庞大
运行性能几乎无额外性能损失操作系统额外的CPU、内存消耗
移植性轻便、灵活、适应于linux笨重,与虚拟化技术耦合度高
硬件亲和性面向软件开发者面向硬件运维者
启动速度快速,秒级慢,分钟级

docker流程图

在这里插入图片描述

为什么用docker

更轻量: 基于容器的虚拟化,仅包含业务运行所需的runtime环境,CentOS/Ubuntu基础镜像仅170M;宿主机可部署100-1000个容器

更高效: 无操作系统虚拟化开销

计算:轻量,无额外开销
存储:系统盘aufs/dm/overlayfs;数据盘:volume
网络:宿主机网络,NS隔离

更敏捷、更灵活

分层的存储和包管理,devops理念
支持多种网络配置

docker的优势

轻量,秒级的快速启动速度

简单,易用,活跃的社区

标准统一的打包/部署/运行方案

镜像支持增量分发,易于部署

易于构建,良好的REST API ,也很适合自动化测试和持续集成

性能,尤其是内存和IO开销

docker官网: http://www.docker.com

docker中文网站: https://www.docker-cn.com

2.docker安装

docker基本组成:

仓库(repository):是集中存放镜像文件的场所
镜像(image):就是一个只读的模板,镜像可以用来创建docker容器,一个镜像可以创建很多容器。容器运行是需要环境的而镜像就是提供这些环境的。
容器(container):独立运行的一个或一组应用。容器是用镜像创建的运行实例。

总结:

Docker 本身是一个容器运行载体或称之为管理引擎。我们把应用程序和配置依赖打包好形成一个可交付的运行环境,这个打包好的运行环境就视乎image镜像文件。只有通过这个镜像文件才能生成Docker容器。image文件可以看做是容器的模板。Docker根据image文件生成容器的实例。同一个image文件,可以生成多个同时运行的容器实例。

image文件生成的容器实例,本身也是一个文件,称为镜像文件
一个容器运行一种服务,当我们需要的时候,就可以通过docker客户端创建一个对应的运行实例,也就是我们的容器
至于仓库,就是放了一推镜像的地方,我们可以把镜像发布到仓库中,需要的时候从仓库中拉下来就可以了

docker 安装:

# 卸载旧的版本
 yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
# 需要的安装包
yum install -y yum-utils

# 设置镜像仓库
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	# 推荐使用阿里云,快

# 更新yum软件包索引
yum makecache fist

# 安装docker
 yum -y install docker-ce docker-ce-cli containerd.io
 
# 启动docker
systemctl start docker

# 使用docker version查看是否安装成功

# 测试hello-world
docker run hello-world

# 查看镜像
[root@localhost ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED       SIZE
hello-world   latest    d1165f221234   5 weeks ago   13.3kB

# 解决:需要:container-selinux >= 2:2.74的问题
yum install --setopt=obsoletes=0 \
   docker-ce-17.03.2.ce-1.el7.centos.x86_64 \
   docker-ce-selinux-17.03.2.ce-1.el7.centos.noarch # on a new system with yum repo defined, forcing older version and ignoring obsoletes introduced by 17.06.0


# 使用脚本一键安装
# docker安装
curl -sSL https://get.daocloud.io/docker | sh

# 配置docker镜像站
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.io

docker 卸载

# 停止docker服务
systemctl stop docker

# 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io

# 删除资源
rm -rf /var/lib/docker	#docker默认工作路径

镜像加速器

# 1、登录阿里云,找到容器服务

# 2、找到镜像加速地址

# 3、配置
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://vrg74rno.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

# 也可以配置网易云镜像加速
{
  "registry-mirrors": ["http://hub-mirror.c.163.com"]
}

docker run 流程图

Yes
No
Yes
No
开始
docker在本机寻找镜像
判断本机有没有这个镜像
使用这个镜像运行
去DockerHub上下载
DockerHub能否找到
下载运行
返回错误

docker的底层原理

docker是怎样工作的:

  • docker是一个CS结构的系统,docker守护进程运行在主机上,然后通过socket连接从客户端访问,守护进程从客户端接收命令并管理运行在主机上的容器,docker-server接收到docker-client的指令,就会执行这个命令!

docker为什么比vm快:

  • docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机上的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。

  • docker不需要像虚拟机一样重新加载一个内核系统,避免引导,所以在启动速度上有较大的优势

3.docker常用命令

帮助命令

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

镜像命令

  • docker images # 列出本地主机上的镜像

选项 :

-a 	# 列出本地所有的镜像(含中间映像层)

-q	 # 只显示镜像的ID

--digests	# 显示镜像的摘要信息

--no-trunc	# 显示完整的镜像信息
[root@97 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              fce289e99eb9        15 months ago       1.84kB

# REPOSITORY:表示镜像的仓库源
# TAG:镜像的标签
# IMAGE ID:镜像的ID
# CREATED:镜像创建的时间
# SIZE:镜像大小
同一个仓库源可以有多个tag,代表这个仓库的不同个版本,我们使用 repository:tag 来定义不同的镜像。
  • docker search # 从http://hup.docker.com网站中查找镜像

语法:

docker search [options]镜像的名字

选项:

# 通过收藏来过滤
--filter=STARS=1000		# 搜索出来的镜像就是STARS大于1000的
[root@97 ~]# docker search nginx --filter=STARS=1000
NAME                  DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
nginx                 Official build of Nginx.                        14713     [OK]
jwilder/nginx-proxy   Automated Nginx reverse proxy for docker con…   2009                 [OK]
     
  • docker pull # 下载镜像
# 语法:
docker pull 镜像名[:tag]
docker pull tomcat 等价于 docker pull tomcat:latest	# 冒号后面不接版本号默认下载最新版

[root@localhost ~]# docker pull mysql
Using default tag: latest		# 如果不写tag,默认latest最新版
latest: Pulling from library/mysql
f7ec5a41d630: Already exists	# 分层下载,docker image的核心,联合文件系统
9444bb562699: Pull complete
6a4207b96940: Pull complete
181cefd361ce: Pull complete
8a2090759d8a: Pull complete
15f235e0d7ee: Pull complete
d870539cd9db: Pull complete
5726073179b6: Pull complete
eadfac8b2520: Pull complete
f5936a8c3f2b: Pull complete
cca8ee89e625: Pull complete
6c79df02586a: Pull complete
Digest: sha256:6e0014cdd88092545557dee5e9eb7e1a3c84c9a14ad2418d5f2231e930967a38	# 签名
Status: Downloaded newer image for mysql:latest	
docker.io/library/mysql:latest	# 真实地址


  • docker rmi #删除某个镜像
[root@localhost ~]# docker rmi -f 镜像ID				   # 删除指定镜像
[root@localhost ~]# docker rmi -f 镜像ID 镜像ID 镜像ID	# 删除指定的多个镜像
[root@localhost ~]# docker rmi -f $(docker images -qa)	# 删除全部镜像

容器命令

有镜像才能创建容器,这是根本前提(下载一个centos镜像演示)

docker pull centos

新建并启动镜像

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
OPTIONS 说明:
--name="容器新名字" :为容器指定一个名称,用于区分容器
-d:后台运行容器
-i:以交换模式运行容器,通常与 -t 同时使用
-t:为容器重新分配一个伪输入终端,通畅与 -i 同时使用
-P:随机端口映射
-p:指定端口映射,有以下四种格式
ip:hostPort:containerPort
ip:conrainerPort
hostPort:containerPort
containerPort

# 新建容器并启动,会在新的docker里面的centos的/目录下面
[root@97 ~]# docker run -it centos
[root@ab9486eb362f /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@ab9486eb362f /]# pwd
/

列出当前所有正在运行的容器

[root@97 ~]# docker ps
CONTAINER ID   IMAGE      COMMAND       CREATED      STATUS        PORTS      NAMES
ab9486eb362f   centos   "/bin/bash"  9 minutes ago   Up 9 minutes         musing_lalande

NAME就是 --name指定的别名,没有指定就使用默认NAME

docker ps 常用选项

-a	列出当前所有正在运行的容器和历史上运行过的容器
-l	显示最近创建的容器
-n	显示最近n个创建的容器
-q	静默模式,只显示容器编号
--no-trunc	不截断输出

[root@97 ~]# docker ps -q
ab9486eb362f

退出容器的两种方法

exit       容器停止退出

ctrl+P+Q		容器不停止退出

删除容器

[root@localhost ~]# docker rm 容器ID		# 删除指定容器,不可删除正在运行的容器,如过要删除请加 -f
[root@localhost ~]# docker rm -f $(docker ps -qa)	# 删除全部容器
docker ps -a -q | xargs docker rm		# 删除所有容器

启动停止容器

docker start 容器ID		# 启动容器
docker restart 容器ID		# 重启容器
docker stop 容器ID		# 停止容器
docker kill 容器ID		# 强制停止当前容器

删除已停止的容器

[root@97 ~]# docker stop 9edbc71d62bc
9edbc71d62bc
[root@97 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND     CREATED      STATUS      PORTS         NAMES
ab9486eb362f   centos  "/bin/bash"  4 days ago   Up 4 days            musing_lalande

[root@97 ~]# docker ps -n 2
CONTAINER ID   IMAGE    COMMAND     CREATED          STATUS        PORTS        NAMES
9edbc71d62bc   centos  "/bin/bash"  20 minutes ago   Exited (0) 2 minutes ago   myctos
ab9486eb362f   centos  "/bin/bash"   4 days ago      Up 4 days            musing_lalande
[root@97 ~]# docker rm 9edbc71d62bc
[root@97 ~]# docker rm ab9486eb362f -f	#删除没有停止的容器加-f强制删除

启动守护式容器

docker run -d 容器名
[root@97 ~]# docker run -d centos
74558d5b6bfb0034d99d2d675bdbaff8914647d8c463b21e134d63d20e4441d7

[root@97 ~]# docker ps
CONTAINER ID      IMAGE      COMMAND      CREATED      STATUS      PORTS       NAMES

# 问题:然后docker ps 进行查看,发现容器已经退出
  说明:如果不是那些一直挂起的命令(top tail)就是会自动退出的
  重点:docker容器后台运行就必须要有一个前台进程
  比如:nginx容器启动后,发现自己没有提供服务,就会立刻停止
[root@97 ~]# docker run -d centos /bin/bash -c "while true;do echo zz;sleep 2;done"
ec25dc5cafc03578d963cb129ea9cf0b215b716434019b7d08df93aa3c65a190
[root@97 ~]# docker ps
CONTAINER ID   IMAGE    COMMAND                 CREATED      STATUS   PORTS     NAMES
ec25dc5cafc0   centos  "/bin/bash -c 'while…"  3 seconds ago  Up 3second  bold_goldwasser

查看docker日志

docker logs -f -t --tail 容器ID
-t	是加入时间戳
-f 	是跟随最新的日志打印
--tail number 显示最后的多少条

[root@97 ~]# docker logs ec25dc5cafc0
zz
zz
zz
...

[root@97 ~]# docker logs -t -f --tail 3 ec25dc5cafc0
2020-04-15T09:09:08.290949108Z zz
2020-04-15T09:09:10.293420735Z zz
2020-04-15T09:09:12.296657506Z zz
...

查看容器内运行的进程

docker top 容器ID
[root@localhost ~]# docker top 14795dc7e6fa
UID        PID        PPID      C       STIME      TTY          TIME          CMD
root      41784       41761     0       16:29      pts/0       00:00:00     /bin/bash

查看容器的元数据

命令:
docker inspect 容器ID

进入正在运行的容器并以命令交互

docker attach 容器ID		# 是直接进入容器启动的命令终端,不会启动新的进程
docker exec -it 容器ID	# 是在容器中打开新的终端,可以在里面操作(常用)

[root@97 ~]# docker run -it centos
[root@7de493efe07b /]# Ctrl+p+q	#不停止退出

[root@97 ~]# docker attach 7de493efe07b			#attach方式进入
[root@7de493efe07b /]# ls /tmp
ks-script-_srt3u3c  ks-script-gpqu_kuo

[root@97 ~]# docker attach 7de493efe07b ls /tmp
"docker attach" requires exactly 1 argument.
See 'docker attach --help'.

[root@97 ~]# docker exec -it 7de493efe07b ls /tmp
ks-script-_srt3u3c  ks-script-gpqu_kuo
#exec方式登录可以不进入容器执行命令返回结果,attach方式必须先进去容器然后执行操作

从容器内拷贝文件到主机上

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

[root@97 ~]# docker exec -it 7de493efe07b touch aa.text
[root@97 ~]# docker exec -it 7de493efe07b ls
aa.text  dev  home  lib64	media  opt   root  sbin  sys  usr

[root@97 ~]# docker cp 7de493efe07b:aa.text /root
[root@97 ~]# ls
aa.text

docker部署nginx

# 搜索镜像
[root@localhost ~]# docker search nginx --filter=STARS=3000
NAME      DESCRIPTION                STARS     OFFICIAL   AUTOMATED
nginx     Official build of Nginx.   14718     [OK]

# 下载镜像
[root@localhost ~]# docker pull nginx

# 启动容器
[root@localhost ~]# docker run --name nginx01 -d -p 8080:80 nginx
--name	起个别名
-p	宿主机端口:容器内端口(映射)

// 现在访问宿主机的8080端口就可以访问到容器内的80端口

docker 部署 Tomcat

# 搜索镜像
[root@localhost ~]# docker search tomcat

# 下载镜像
[root@localhost ~]# docker pull tomcat

# 启动运行容器
[root@localhost ~]# docker run --name tomcat01 -d -p 8081:8080 tomcat
[root@localhost ~]# docker ps

# web访问没有问题,但是发现404

# 进入容器
[root@localhost ~]# docker exec -it tomcat01 /bin/bash
root@58d86d3ca8d3:/usr/local/tomcat# ls webapps
root@58d86d3ca8d3:/usr/local/tomcat#

# 发现问题:发现webapps为空,因为阿里云镜像的原因,默认是最小镜像,所有不必要的都会剔除,保证最小可运行环境
# 
root@58d86d3ca8d3:/usr/local/tomcat# cp -r webapps.dist/* webapps	# 再次访问就正常了

可视化

  • portainer

什么是portainer

docker 图形化界面管理工具,提供一个后台面板供我们操作!

[root@localhost ~]#  docker run -d -p 8088:9000 \
--restart=always -v "/var/run/docker.sock:/var/run/docker.sock" --privileged=true portainer/portainer

4.docker 镜像

镜像是什么

一种轻量级、可执行独立软件包,用来打包软件运行环境和基于运行环境开发的软件,包含软件所需的所有内容,代码、库、环境变量和配置文件。

所有的应用,直接打包docker镜像就可以直接跑起来

镜像的获取途径:

  • 从远程仓库获取

  • 朋友给你

  • 自己制作一个镜像DockerFile

docker镜像加载原理

UnionFS(联合文件系统)

是一种分层、轻量级并且高性能的文件系统,它支持对文件系统修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。union文件系统是docker镜像的基础。镜像可以通过分层来进行集成,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

特性:一次同时加载多个文件系统,但从外面看来只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

docker镜像加载原理

docker的镜像实际上是由一层一层的文件系统组成,这种层级的文件系统UnionFS。

bootfs(boot file system)主要包含BootLoader和kernel,BootLoader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在docker镜像的最底层是bootfs。这一层与我们典型的Linux系统是一样的。包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。

rootfs(root file system),在bootfs之上。包含的就是典型Linux系统中的 /dev,/proc,/bin,/etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。

平时我们安装虚拟机中的centos镜像都是好几个G,为什么到docker中才200M左右??

对于一个精简版的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就行了,因为底层直接用host的kernel,自己只需要提供rootfs就行了。由此可见对于不同的Linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以共用bootfs。

分层的镜像

以我们的pull为例,在下载的过程中我们可以看到docker的镜像好想是在一层一层的在下载。

为什么tomcat的镜像会有400多M这么大??

就是因为分层的镜像tomcat需要这些---->kernel–centos–jdk8–tomcat–docker容器

docker为何采用这种分层

最大的一个好处就是—资源共享

比如有多个镜像都从相同的base镜像构建而来,那么宿主机只需要在磁盘上保存一份base镜像,同时内存中也只需加载一份base镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。

docker镜像的特点

docker镜像都是只读的

当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称为“容器层”,"容器层"之下的都叫镜像层。

docker commit

docker commit提交容器副本使之成为一个新镜像

docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的新的镜像名:[标签名]

案例演示

hub上下载tomcat镜像到本地运行,然后故意删除tomcat容器的帮助文档,此时将没有文档的tomcat容器为模板commit一个新的镜像,名为 atguigu/tomcat02

# 从hub上下载tomcat镜像到本地并成功运行
[root@97 ~]# docker images tomcat
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
tomcat              latest              e36064f7c6f0        3 weeks ago         528MB

[root@97 ~]# docker run -it -p 8888:8080 tomcat  # 这样就启动了tomcat
-P 主机端口:docker容器端口
-p 随机分配端口
-i 交互
-t 终端
[root@97 ~]# docker run -it -P tomcat
[root@97 ~]# docker ps
CONTAINER ID  IMAGE      COMMAND          CREATED             STATUS      
893b6a90f5fc  tomcat  "catalina.sh run" 54 seconds ago      Up 53 seconds    
     PORTS                        NAMES
0.0.0.0:32768->8080/tcp   recursing_cohen   #(这里可以看到使用-P随机分配的映射端口为32768)
# 此时使用localhost:32768即可访问到tomcat的首页



# 故意删除上一步镜像生产tomcat容器的文档
[root@97 ~]# docker run -it -p 8888:8080 tomcat
[root@97 ~]# docker ps
CONTAINER ID     IMAGE   COMMAND             CREATED             STATUS    
58ff859e46b5     tomca   "catalina.sh run"   21 seconds ago      Up 20 seconds       
PORTS                     NAMES
0.0.0.0:8888->8080/tcp   competent_gates
[root@97 ~]# docker exec -it 58ff859e46b5 /bin/bash
root@58ff859e46b5:/usr/local/tomcat# rm -rf webapps/docs
再次访问localhost:8888的时候文档就没有了


# 也即当前的tomcat运行实例是一个没有文档内容的容器,以它为模板commit一个没有doc的tomcat新镜像atguigu/tomcat02
[root@97 ~]# docker commit -a="zzyy" -m="tomcat del docs" 58ff859e46b5 atguigu/tomcat02
sha256:8848761752371b74c6bf4b30348e675565ed51eba918179947340170bd125219

[root@97 ~]# docker images	# 查看新生成的镜像
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
atguigu/tomcat02    latest              884876175237        About a minute ago   528MB
tomcat              latest              e36064f7c6f0        3 weeks ago          528MB

[root@97 ~]# docker rm -f $(docker ps -q)	# 删除所有正在运行的容器
[root@97 ~]# docker run -it -p 8888:8080 atguigu/tomcat02	#此时使用新镜像启动后是没有文档的

5.docker容器数据卷

是什么

在docker容器中运行的数据我们想把它保存下来就会使用卷,类似一个外置的活动硬盘。有点类似我们redis里面的rdb和aof文件。

将运用运行的环境打包形成容器运行,运行可以伴随着容器,但是我们对数据的要求希望是持久化的,容器之间希望有可能共享数据

docker容器产生的数据,如果不通过dockercommit生成新的镜像,使得数据做为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了

为了能保存数据在docker中,我们使用卷。

能干嘛

主要做数据共享和数据持久化的工作

特点:

1.数据卷可在容器之间共享或重用数据

2.卷中的更改可以之间生效

3.数据卷中的更改不会包含在镜像的更新中

4.数据卷的生命周期一直持续到没有容器使用它为止

数据卷添加

直接-V命令添加
docker run -it -v /宿主机绝对路径目录:/容器内目录  镜像名
[root@97 ~]# docker run -it -v /MyData:/MyDataContainer centos 
# 会在宿主机生成/MyData在容器内生成/MyDataContainer
[root@d2cd5bada4b1 /]# ls
MyDataContainer
[root@97 ~]# ls /
MyData

# 查看数据是否挂载成功
[root@97 ~]# docker inspect d2cd5bada4b1
...
  "Binds": [
                "/MyData:/MyDataContainer"
            ],
...
  "Mounts": [
            {
                "Type": "bind",
                "Source": "/MyData",			# 主机地址
                "Destination": "/MyDataContainer",	# 容器内地址
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
...

# 容器和宿主机之间数据共享
[root@97 ~]# cd /MyData/
[root@97 MyData]# touch aa	# 宿主机创建文件

[root@d2cd5bada4b1 /]# cd MyDataContainer/
[root@d2cd5bada4b1 MyDataContainer]# ls			# 容器内可以看到并修改
aa
[root@d2cd5bada4b1 MyDataContainer]# echo '123'>aa
[root@d2cd5bada4b1 MyDataContainer]# touch bb

[root@97 MyData]# ls			# 实现了数据共享
aa  bb
[root@97 MyData]# cat aa
123

# 容器退出后主机修改的内容能否同步?
# 退出容器
[root@d2cd5bada4b1 MyDataContainer]# exit
# 宿主机新建文件
[root@97 MyData]# touch text
[root@97 MyData]# ls
aa  bb  text
# 重新启动容器
[root@97 ~]# docker ps
CONTAINER ID    IMAGE    COMMAND     CREATED     STATUS    PORTS     NAMES
[root@97 ~]# docker ps -l
CONTAINER ID   IMAGE    COMMAND      CREATED     STATUS   PORTS       
d2cd5bada4b1  centos  "/bin/bash" 30 minutes ago  Exited (0) About a minute ago
NAMES
vigorous_gates
[root@97 ~]# docker start d2cd5bada4b1
d2cd5bada4b1
[root@97 ~]# docker attach d2cd5bada4b1		# 即使容器退出后宿主机的数据还是可以实现共享
[root@d2cd5bada4b1 /]# ls MyDataContainer/
aa  bb	text

备注:docker挂载主机目录docker访问出现cannot open director Permission denied(不能写)

解决办法:在挂载目录后多加一个 --privileged=true

Mysql 数据同步

# 获取镜像
[root@localhost ~]# 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 容器名
[root@localhost ~]# docker run -d  -p 3300:3306 -v /home/mysql01/conf:/etc/mysql/conf.d \
-v /home/mysql01/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=admin123 --name mysql01 mysql:5.7

# 查看映射的目录
[root@localhost ~]# cd /home/mysql01/
[root@localhost mysql01]# ls
conf  data
[root@localhost mysql01]# ls data/
auto.cnf    ca.pem           client-key.pem  ibdata1      ib_logfile1  mysql               private_key.pem  server-cert.pem  sys
ca-key.pem  client-cert.pem  ib_buffer_pool  ib_logfile0  ibtmp1       performance_schema  public_key.pem   server-key.pem


# 本地测试连接
# 连接服务器的3300 --- 容器的3306(映射)
[root@localhost ~]# mysql -uroot -padmin123 -h127.0.0.1 -P 3300
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.33 MySQL Community Server (GPL)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]>create database test;	# 创建一个数据库

# 查看本地映射目录
[root@localhost mysql01]# ls data/
auto.cnf    ca.pem           client-key.pem  ibdata1      ib_logfile1  mysql               private_key.pem  server-cert.pem  sys
ca-key.pem  client-cert.pem  ib_buffer_pool  ib_logfile0  ibtmp1       performance_schema  public_key.pem   server-key.pem   test

# 发现新创建的test库已经同步

# 删除容器之后,本地挂载(映射)的数据不会丢失
# 实现了数据同步
[root@localhost ~]# docker rm mysql01 -f
mysql01

[root@localhost mysql01]# ls data/
auto.cnf    ca.pem           client-key.pem  ibdata1      ib_logfile1  mysql               private_key.pem  server-cert.pem  sys
ca-key.pem  client-cert.pem  ib_buffer_pool  ib_logfile0  ibtmp1       performance_schema  public_key.pem   server-key.pem   test

具名和匿名挂载
# 匿名挂载
-v 容器内路径

# 只写容器内路径 /etc/nginx
[root@localhost ~]# docker run -d -v /etc/nginx -P --name nginx01 nginx

# 查看所有 volume 信息
[root@localhost ~]# docker volume ls
DRIVER    VOLUME NAME
local     68eaaa44a6c52dc1207fafea0396a9963f6d08143e080521b3a98027c30ee72f
# 这就是匿名挂载,启动容器时 -v 只写了容器内路径

# 具名挂载
-v 卷名:容器内路径
[root@localhost ~]# docker run -d --name nginx02 -P -v jm:/etc/nginx nginx

# 查看所有volume信息
[root@localhost ~]# docker volume ls
DRIVER    VOLUME NAME
local     jm
# 这就是具名挂载,通过 -v 卷名:容器内路径

# 那么容器内的目录挂载到了本地什么地方?
# 查看一下卷的inspect
[root@localhost ~]# docker volume inspect jm
[
    {
        "CreatedAt": "2021-04-18T00:27:59+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/jm/_data",	# 就是挂载到了本地的这个目录
        "Name": "jm",
        "Options": null,
        "Scope": "local"
    }
]

所有没有指定目录的情况下,都会挂载到本地的 /var/lib/docker/volumes/卷名/_data

通过具名挂载,可以方便的找到我们的卷,比较常用

如何区分,具名,匿名,指定路径,这几种挂载方式

-v 容器内路径	# 匿名挂载
-v 卷名:容器内路径		# 具名挂载
-v 宿主机路径:容器内路径	# 直径路径挂载

命令带权限

# 命令带权限
ro: 只读
rw: 可读可写
# 这个权限是对容器而言的,一旦设置了ro,容器内部就不能进行写操作,外部是可以的,默认权限是rw

docker run -it -v /宿主机绝对路径目录:/容器内目录:ro  镜像名
[root@97 ~]# docker run -it -v /Host:/Container:ro centos
[root@30e7325ecd69 /]# ls
Container

[root@97 ~]# cd /
[root@97 /]# ls
Host

[root@30e7325ecd69 /]# cd Container/	# 容器中不能往宿主机端增删改
[root@30e7325ecd69 Container]# touch a
touch: missing file operand
Try 'touch --help' for more information.

[root@97 /]# cd Host/
[root@97 Host]# echo '123'>abc
[root@30e7325ecd69 Container]# ls	# 而宿主机端可以向容器端进行增删改
abc
[root@30e7325ecd69 Container]# cat abc 
123

初识DockerFile

dockerfile就是用来构建docker镜像的构建文件,命令脚本!

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

# 创建一个dockerfile文件,名字可以随机,建议就用dockerfile
mkdir /home/docker-test-volume
cd /home/docker-test-volume
vim dockerfile1

# 文件中的内容:指令(大写) 参数
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "-----end-----"
CMD /bin/bash

# 生成镜像
-f dockerfile的路径
-t ‘name:tag’
docker build -f dockerfile1 -t scl/contos:1.0 .

# 查看生成的镜像
[root@localhost docker-test-volume]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
scl/contos            1.0       79d7251626b6   12 minutes ago   209MB

# 使用镜像运行容器
docker run -it 79d7251626b6 /bin/bash

# 进入容器,可以看到我们挂载的数据卷目录volume01和volume02
[root@localhost docker-test-volume]# docker exec -it 44f5b69616e6 /bin/bash
[root@44f5b69616e6 /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  volume01	volume02

# 查看容器的inspect可以看到容器外部对应的挂载目录
[root@localhost ~]# docker inspect 44f5b69616e6
        "Mounts": [
            {
                "Type": "volume",
                "Name": "3c3a232b92451405debb36659eacdd3f19d76568ee08c0b595a05e86ede0a5a2",
                "Source": "/var/lib/docker/volumes/3c3a232b92451405debb36659eacdd3f19d76568ee08c0b595a05e86ede0a5a2/_data",
                "Destination": "volume01",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            },
            {
                "Type": "volume",
                "Name": "13d98e2870b98cfbc7e06a0b1d31f5604e147601c11433d86bc919acfeca9cd5",
                "Source": "/var/lib/docker/volumes/13d98e2870b98cfbc7e06a0b1d31f5604e147601c11433d86bc919acfeca9cd5/_data",
                "Destination": "volume02",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

# 测试能否同步
[root@localhost ~]# cd /var/lib/docker/volumes/3c3a232b92451405debb36659eacdd3f19d76568ee08c0b595a05e86ede0a5a2/_data
[root@localhost _data]# touch container01.txt
[root@localhost _data]# ls
container01.txt

# 查看容器内部是否同步
[root@localhost _data]# docker exec -it 44f5b69616e6 ls volume01
container01.txt

以后我们构建自己的镜像的时候这种方式会经常用到

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

数据卷容器

命名的容器挂载数据卷,其他容器通过挂载这个(父容器)实现数据共享,挂载数据卷的容器,称之为数据卷容器。

容器与容器之间的数据同步就要用到容器数据卷

# 启动3个容器,3个容器之间实现数据共享(就使用前面用dockerfile构建的镜像)

# 启动第一个容器
[root@localhost ~]# docker run -it --name docker01 scl/contos:1.0
[root@264b84f04e0a /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  volume01	volume02

# 启动第二个容器
--volumes-from 父容器名  # 通过这个参数就可以让运行的子容器和父容器实现数据共享,父容器叫做数据卷容器
[root@localhost ~]# docker run -it --name docker02 --volumes-from docker01 scl/contos:1.0
[root@9d8e2db59cae /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  volume01	volume02

# 测试两个容器之间的数据能否同步
# 第一个容器,往卷里面创建一个文件
[root@264b84f04e0a /]# touch volume01/test.txt && ls volume01
test.txt

# 在第二个容器里面对应的volume01查看数据是否同步
[root@30783b56ac1c /]# ls volume01/
test.txt

# 启动第三个容器
[root@localhost ~]# docker run -it --name docker03 --volumes-from docker01 scl/contos:1.0
[root@a4973931ca03 /]# ls volume01/		# 发现数据已经同步过来了
test.txt


## 第一个容器(父容器)没了,后面的两个容器还能否实现数据同步
# 先删除第一个容器docker01
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED          STATUS          PORTS     NAMES
a4973931ca03   scl/contos:1.0   "/bin/sh -c /bin/bash"   2 minutes ago    Up 2 minutes              docker03
30783b56ac1c   scl/contos:1.0   "/bin/sh -c /bin/bash"   20 minutes ago   Up 20 minutes             docker02
264b84f04e0a   scl/contos:1.0   "/bin/sh -c /bin/bash"   24 minutes ago   Up 24 minutes             docker01

[root@localhost ~]# docker rm -f 264b84f04e0a
264b84f04e0a

[root@localhost ~]# docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED          STATUS          PORTS     NAMES
a4973931ca03   scl/contos:1.0   "/bin/sh -c /bin/bash"   2 minutes ago    Up 2 minutes              docker03
30783b56ac1c   scl/contos:1.0   "/bin/sh -c /bin/bash"   21 minutes ago   Up 21 minutes             docker02

# 测试发现即使父容器被删了,剩下的2个容器还是可以实现数据共享
[root@30783b56ac1c /]# touch volume01/test2.txt && ls
test.txt  test2.txt

[root@a4973931ca03 /]# ls volume01/
test.txt  test2.txt

# 只要有一个容器还在使用数据,数据就不会丢失
# 它不是共享机制,而是一种双向拷贝的机制,即使父容器没了,但是数据已经被其他容器拷贝出去了
总结
  • 容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止

  • 只有使用这些数据的所有容器都被删除了,数据才会没有

  • 但是一旦卷被挂载到了本地,那么数据将不会丢失

6. DockerFile

DockerFile介绍

docker是用来构建docker镜像的文件,命令参数脚本

1、编写一个 dockerfile 文件

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

3、docker run 运行镜像

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

很多官方镜像都是基础包,很多功能没有,我们通常会构建自己的镜像

DockerFile构建过程

基础知识:

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

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

3、# 表示注释

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

步骤:

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

Docker镜像:通过 DockerFile 构建生成的镜像,最终发布和运行的产品(用来是jar包或者war包的形式)

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

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

在 Docker Hub 中 %99 的镜像都是从这个基础的镜像过来的,然后配置需要的软件和配置来构建

创建一个自己的centos

我们在官方下载的centos镜像是阉割版的,很多基础命令无法使用,vim , ifconfig等,现在使用DockerFile构建一个新的centos把这两个命令添加进去

# 编写dockerfile文件
FROM centos
MAINTAINER scl<123456@qq.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 777

CMD echo "$MYPATH"
CMD echo "---end---"
CMD /bin/bash

# 构建镜像
-f dockerfile的路径
-t ‘镜像名:[tag][root@localhost dockerfile]# docker build -f dockerfile-centos -t mycentos:1.0 .
...
Successfully built 347eac4d8903
Successfully tagged mycentos:1.0
# 出现这个就构建成功了
...

# 查看images
[root@localhost ~]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
mycentos              1.0       347eac4d8903   4 minutes ago   291MB


# 运行测试
[root@localhost ~]# docker run -it mycentos:1.0
[root@35a6ac33be4b local]# vi
vi        view      vigr      vim       vimdiff   vimtutor  vipw

[root@35a6ac33be4b local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 8  bytes 656 (656.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
# 发现新加的vim和ifconfig命令都可以使用了

# 可以通过history查看别人的镜像怎么构建的
[root@localhost ~]# docker history mycentos:1.0
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
347eac4d8903   46 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "/bin…   0B
acf27fc4746d   46 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B
006f9aa94a91   46 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B
4dd1e6594c91   46 minutes ago   /bin/sh -c #(nop)  EXPOSE 777                   0B
f44dbb7c7caf   46 minutes ago   /bin/sh -c yum -y install net-tools             23.3MB
dc2c37c873d8   46 minutes ago   /bin/sh -c yum -y install vim                   58MB
29cb5ccbc0d1   47 minutes ago   /bin/sh -c #(nop) WORKDIR /usr/local            0B
ac53dc0d97ab   47 minutes ago   /bin/sh -c #(nop)  ENV MYPATH=/usr/local        0B
35c356ba27c1   47 minutes ago   /bin/sh -c #(nop)  MAINTAINER scl<123456@qq.…   0B
300e315adb2f   4 months ago     /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
<missing>      4 months ago     /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B
<missing>      4 months ago     /bin/sh -c #(nop) ADD file:bd7a2aed6ede423b7…   209MB

CMD 和 ENTRYPOINT 的区别

CMD				# 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT		# 指定这个容器启动的时候要运行的命令,可以追加命令
  • cmd测试
# 编写 DockerFile 文件
[root@localhost dockerfile]# vim dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]

# 构建镜像
[root@localhost dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest .

# 运行镜像
[root@localhost dockerfile]# docker run -it 86dc225f6a27
.   .dockerenv	dev  home  lib64       media  opt   root  sbin	sys  usr
..  bin		etc  lib   lost+found  mnt    proc  run   srv	tmp  var

# 运行镜像的时候加上一个参数,发现会报错
# cmd构建的镜像,后面的命令会替代DockerFile里的命令参数,而 -l 也不是完整的命令所以报错
# 所以在cmd构建的镜像中容器运行时添加的命令参数必须是完整的命令+参数
[root@localhost dockerfile]# docker run -it 86dc225f6a27 -l
ERRO[0000] error waiting for container: context canceled

[root@localhost dockerfile]# docker run -it 86dc225f6a27 ls -al
total 0
drwxr-xr-x    1 root root   6 Apr 20 18:40 .
drwxr-xr-x    1 root root   6 Apr 20 18:40 ..
-rwxr-xr-x    1 root root   0 Apr 20 18:40 .dockerenv
lrwxrwxrwx.   1 root root   7 Nov  3 15:22 bin -> usr/bin
drwxr-xr-x    5 root root 360 Apr 20 18:40 dev
drwxr-xr-x.   1 root root  66 Apr 20 18:40 etc
drwxr-xr-x.   2 root root   6 Nov  3 15:22 home

  • entrypoint测试
# 编写 DockerFile 文件
[root@localhost dockerfile]# vim dockerfile-entyrpoint-test
FROM centos
ENTRYPOINT ["ls","-a"]

# 构建镜像
[root@localhost dockerfile]# docker build -f dockerfile-entyrpoint-test -t entyrpointtest .

# 运行镜像
[root@localhost dockerfile]# docker run -it entyrpointtest
.   .dockerenv	dev  home  lib64       media  opt   root  sbin	sys  usr
..  bin		etc  lib   lost+found  mnt    proc  run   srv	tmp  var

# 发现DockerFile里面指定的 ls -a 在容器运行的时候会被执行
# 那现在我们在容器运行的时候加上一个参数看看会发生什么
# 直接类似于在DockerFile文件中的 ENTRYPOINT ["ls","-a","-l"] 追加了参数
[root@localhost dockerfile]# docker run -it entyrpointtest -l
total 0
drwxr-xr-x    1 root root   6 Apr 20 18:24 .
drwxr-xr-x    1 root root   6 Apr 20 18:24 ..
-rwxr-xr-x    1 root root   0 Apr 20 18:24 .dockerenv
lrwxrwxrwx.   1 root root   7 Nov  3 15:22 bin -> usr/bin
drwxr-xr-x    5 root root 360 Apr 20 18:24 dev
drwxr-xr-x.   1 root root  66 Apr 20 18:24 etc
drwxr-xr-x.   2 root root   6 Nov  3 15:22 home

tomcat镜像

1、准备镜像文件 Tomcat 压缩包,jdk的压缩包

[root@localhost ~]# mkdir /scl/build/tomcat
[root@localhost tomcat]# ll
total 165956
-rw-r--r-- 1 root root  10914435 Sep 22  2020 apache-tomcat-9.0.24.tar.gz
-rw-r--r-- 1 root root 159019376 Apr 20 20:40 jdk-8u11-linux-x64.tar.gz

2、编写DockerFile文件

官方命名Dockerfile,这样在build的时候就不需要使用-f去指定了,build会自动找到DockerFile文件

[root@localhost tomcat]# vim Dockerfile
FROM centos

MAINTAINER whell<1539163444@qq.com>

COPY readme.txt /usr/local/readme.txt

ADD jdk-8u11-linux-x64.tar.gz /usr/local
ADD apache-tomcat-9.0.24.tar.gz /usr/local

RUN yum -y install vim

ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_11
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.24
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.24
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.24/bin/startup.sh && tail -f /usr/local/apache-tomcat-9.0.24/logs/catalina.out

3、构建镜像

[root@localhost tomcat]# docker build -t tomcat-diy .
...
Successfully built 1cf20abcb26a
Successfully tagged diy-tomcat:latest

# 查看镜像
[root@localhost tomcat]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
mytomcat     latest    d6f25b8d2b51   2 minutes ago   607MB
centos       latest    300e315adb2f   4 months ago    209MB

4、启动运行

[root@localhost tomcat]# docker run -d --name mytomcat01 -p 9090:8080 -v /root/scl/build/tomcat/test:/usr/local/apache-tomcat-9.0.24/webapps/test -v /root/scl/build/tomcat/tomcatlogs:/usr/local/apache-tomcat-9.0.24/logs d6f25b8d2b51

[root@localhost tomcat]# docker ps
CONTAINER ID     IMAGE        COMMAND   CREATED          STATUS          PORTS         NAMES
866d8da21035   d6f25b8d2b51    "..."      ...	  :9090->8080/tcp, :::9090->8080/tcp   mytomcat01

5、测试

# 浏览器访问tomcat首页正常
http://192.168.100.200:9090/

# 进去挂载目录创建一个jsp文件
[root@localhost tomcat]# cd test/
[root@localhost test]# pwd
/root/scl/build/tomcat/test

[root@localhost test]# cat index.jsp
<html>
<head>
        <title>test page</title>
</head>
<body>
        <%
            out.println("Hello World");
        %>
</body>
</html>

# 访问验证 
[root@localhost test]# curl http://192.168.100.200:9090/test/
<html>
<head>
        <title>test page</title>
</head>
<body>
        Hello World

</body>
</html>
# 或者浏览器访问,http://192.168.100.200:9090/test/

#会发现我们在本机挂载目录修改的项目会自动同步到容器内部,日志文件也会同步,不用经常的进出容器了
[root@localhost tomcatlogs]# ll
total 24
-rw-r-----. 1 root root 6566 Apr 26 17:48 catalina.2021-04-26.log
-rw-r-----. 1 root root 6566 Apr 26 17:48 catalina.out
-rw-r-----. 1 root root    0 Apr 26 17:48 host-manager.2021-04-26.log
-rw-r-----. 1 root root  408 Apr 26 17:48 localhost.2021-04-26.log
-rw-r-----. 1 root root 1370 Apr 26 18:26 localhost_access_log.2021-04-26.txt
-rw-r-----. 1 root root    0 Apr 26 17:48 manager.2021-04-26.log


发布镜像

发布镜像到dockerhub

  • 地址https://hub.docker.com/ 注册自己的账号

  • 登录账号

  • 在服务器上提交镜像

# docker登录成功
-u # dockerhub的用户名
-p # dockerhub的密码
[root@localhost test]# docker login -u 1539163444
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
[root@localhost test]#


# 增加一个tag
# 注意:添加tag时必须在前面加上自己的dockerhub的username
[root@localhost ~]# docker tag d6f25b8d2b51 1539163444/tomcat:1.0
[root@localhost tomcat]# docker images
REPOSITORY                TAG       IMAGE ID       CREATED              SIZE
1539163443/mytomcat-diy   1.0       d6f25b8d2b51  About a minute ago   607MB
mytomcat-diy              latest    d6f25b8d2b51   About a minute ago   607MB


# 提交 docker push
[root@localhost tomcat]# docker push 1539163444/mytomcat-diy:1.0
The push refers to repository [docker.io/1539163444/mytomcat-diy]
581b8a0b4636: Pushing [=====>                                             ]  6.001MB/58.03MB
b7ade13dd0f4: Pushing [==========>                                        ]  3.151MB/15.42MB
917daac03648: Pushing [>                                                  ]  3.266MB/324MB
1c9697fc6ef2: Pushed
2653d992f4ef: Pushing [>                                                  ]  2.167MB/209.3MB
# 可以发现提交的时候也是按照镜像的层级来提交的

# 提交成功之后,可以在dockerhub上面看到我们提交的镜像,也可以使用docker pull下载我们自己的镜像
[root@localhost tomcat]# docker pull 1539163444/centos:1.0
1.0: Pulling from 1539163443/centos
7a0437f04f83: Downloading [=======================>                           ]  36.08MB/75.18MB
809ba0bafaa3: Downloading [====================================>              ]   20.6MB/28.43MB
bab541a28d78: Download complete

7. docker网络

理解docker0

docker创建的容器的网络能否与宿主机(Linux服务器)互通

# 启动一个tomcat镜像
[root@localhost ~]# docker run -d --name tomcat01 tomcat

# 查看一下容器内部的ip
[root@localhost ~]# docker exec -it tomcat01 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
24: eth0@if25: <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

# 查看外部服务器的ip
[root@localhost ~]# 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
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:4d:60:46 brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.200/24 brd 192.168.100.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::7a7b:9a8d:634f:34bb/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:d8:8d:47:25 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:d8ff:fe8d:4725/64 scope link
       valid_lft forever preferred_lft forever
25: vethbe938ed@if24: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
    link/ether 02:6f:ad:d1:9d:b2 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::6f:adff:fed1:9db2/64 scope link
       valid_lft forever preferred_lft forever

# 发现docker0的ip和容器内部的IP(docker分配!)相同网段
# 可以直接ping通
172.17.0.1 172.17.0.2
[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.115 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.041 ms

原理

我们每启动一个容器,docker都会分配一个ip给容器,我们只要安装了docker就会有一个网卡docker0

测试:

# 再启动一个容器
[root@localhost ~]# docker run -d --name tomcat02 tomcat

# 容器内ip
[root@localhost ~]# docker exec -it tomcat02 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
26: eth0@if27: <BROADCAST,MULTICAST,UP,LOWER_UP> 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

# 容器外ip
[root@localhost ~]# 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
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:4d:60:46 brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.200/24 brd 192.168.100.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::7a7b:9a8d:634f:34bb/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:d8:8d:47:25 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:d8ff:fe8d:4725/64 scope link
       valid_lft forever preferred_lft forever
25: vethbe938ed@if24: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
    link/ether 02:6f:ad:d1:9d:b2 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::6f:adff:fed1:9db2/64 scope link
       valid_lft forever preferred_lft forever
27: veth62d9317@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
    link/ether fe:2f:46:ad:a4:d7 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::fc2f:46ff:fead:a4d7/64 scope link
       valid_lft forever preferred_lft forever

### 发现没创建一个容器,服务器就会多出一个网卡,并且服务器多出的网卡和每个容器内的网卡是可以对的上好的 

# 我们发现这个容器带来的网卡都是一对一对的出现
# Veth-pair 就是一对虚拟设备接口,他们都是成对出现,一段连着协议,一段彼此连接
# 正是因为这个特性, veth-pair 充当一个桥梁,连接各种虚拟网络设备
# openstack、docker容器之间的互连,OVS的连接,都是使用 veth-pair 这个技术

刚刚启动了2个容器,这两个容器是否能ping通

[root@localhost ~]# docker exec -it tomcat01 ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.286 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.079 ms

网络模型图

在这里插入图片描述

结论

tomcat01 和 tomcat02 是共用的一个路由器也就是 docker0

所有的容器不指定网络的情况下,都是由 docker0 来路由的,docker 会给我们的容器分配一个默认的可用ip

容器之间的连接都是通过Veth-pair技术来转发的

docker所有的网络接口都是虚拟的,虚拟的转发效率高

在这里插入图片描述

–link

docker0的问题:他不支持容器名连接访问!

通过名字来访问容器

# 通常通过名字无法访问
[root@localhost ~]# docker exec -it tomcat01 ping tomcat02
ping: tomcat02: Name or service not known

# 启动一个Tomcat03
[root@localhost ~]# docker run -d --name tomcat03 --link tomcat02 tomcat

# 通过 tomcat03 来ping tomcat02,发现使用--link创建后的03可以直接ping 02的名字
[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.091 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.051 ms

# 反过来tomcat02 来ping tomcat03, 发现不行
[root@localhost ~]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known

查看 docker network inspect

[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
6c782efeea0d   bridge    bridge    local
ef72364e9231   host      host      local
1b4f2b80c780   none      null      local
[root@localhost ~]# docker network inspect 6c782efeea0d
    {
        "Name": "bridge",
        "Id": "6c782efeea0d82c2a0abefb3da0c0ca29424f9e225a699e4d70a094f3cb42a34",
        "Created": "2021-04-27T14:46:01.820447557+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",			# 这就是我们的docker0
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
                
## 三个容器的详细信息

        "ConfigOnly": false,
        "Containers": {
            "3460fad21735d72aec11c37c701ebf4fb737dab1eb464d5724e495d6cbc8499b": {
                "Name": "tomcat03",
                "EndpointID": "3c6ba0dbcaf55e497c324e2db963fc0e5729f42787b1c4c729c8ecce2952c93b",
                "MacAddress": "02:42:ac:11:00:04",
                "IPv4Address": "172.17.0.4/16",
                "IPv6Address": ""
            },
            "4a62f71fdac97b2964705e39c7f24f3220b0bf4ec46eca7fdc3f2b811f2fc88f": {
                "Name": "tomcat01",
                "EndpointID": "c8a48beb2f97d60546346fe9461fca2d0df5ae2336419b4eb28c4f53eaadf307",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "93a0487e38424f9b28004b8133182deb81c625d619bcbcc60e3f7d813bda07d8": {
                "Name": "tomcat02",
                "EndpointID": "ddb21166e697e32532b466d613a9024b5507b774b7e38fcb70f3ae1523a69525",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }

其实Tomcat03 就是 在本地配置了 Tomcat02 的配置

[root@localhost ~]# docker exec -it 3460fad21735 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 93a0487e3842		# 访问tomcat02这个容器直接映射到本地
172.17.0.4	3460fad21735

结论

--link就是在hosts配置中增加了一个172.17.0.3	tomcat02 93a0487e3842 映射
我们现在玩docker已经不建议使用--link了
自定义网络

查看所有的docker网络

[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
6c782efeea0d   bridge    bridge    local
ef72364e9231   host      host      local
1b4f2b80c780   none      null      local

网络模式

bridge : 桥接 docker默认

none : 不配置网络

host : 和宿主机共享网络

container: 容器内网络连通(用的少,局限性很大)

测试

# 我们通常直接启动的命令,其实有个默认的参数 ——net bridge ,而这个就是docker0
[root@localhost ~]# docker run -d -P --name tomcat01 tomcat
[root@localhost ~]# docker run -d -P --name tomcat01 --net bridge tomcat

# 自定义一个网络
-d bridge  桥接(默认)
--subnet 192.168.0.0/16	子网
--gateway 192.168.0.1	网关
[root@localhost ~]# docker network create -d bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
6c782efeea0d   bridge    bridge    local
ef72364e9231   host      host      local
0c61d27ddb34   mynet     bridge    local
1b4f2b80c780   none      null      local

# 查看刚创建的网络信息
[root@localhost ~]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "0c61d27ddb3417219a712f1839b2b48d99c9a4e918cd1263ab50e3c7a3d30224",
        "Created": "2021-04-28T16:40:08.378640581+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": {}
    }
]

# 启动两个容器,不走docker0,走我们刚刚创建好的网络mynet
[root@localhost ~]# docker run -d -P  --name tomcat-mynet-01 --net mynet tomcat
[root@localhost ~]# docker run -d -P  --name tomcat-mynet-02 --net mynet tomcat


# 再次查看我们创建的网络的详细信息,发现创建好的两个容器就在里面了
[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
6c782efeea0d   bridge    bridge    local
ef72364e9231   host      host      local
0c61d27ddb34   mynet     bridge    local
1b4f2b80c780   none      null      local
[root@localhost ~]# docker network inspect 0c61d27ddb34

        "Containers": {
            "499b2d7963e9f7c54081933b808dd22b44726d7a997f46982a6727158d9aa401": {
                "Name": "tomcat-mynet-01",
                "EndpointID": "0fdbabad2c18af90c7c0c88b38ede357c9236650e6b52a5b39e1c3338ab58b7f",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            },
            "71e4675d62cb64055df633c4aa53cf3b955d260982a777c80316bb975e4f3360": {
                "Name": "tomcat-mynet-02",
                "EndpointID": "f02f3683250ed9e9b4dfae00733afbb90829e056e10df6111fb7c0c68b9afec7",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            }
        },

# 再次测ping连接
[root@localhost ~]# docker exec -it tomcat-mynet-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.092 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.047 ms

[root@localhost ~]# docker exec -it tomcat-mynet-01 ping tomcat-mynet-02
PING tomcat-mynet-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-mynet-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.052 ms
64 bytes from tomcat-mynet-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.051 ms

[root@localhost ~]# docker exec -it tomcat-mynet-02 ping tomcat-mynet-01
PING tomcat-mynet-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-mynet-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.044 ms
64 bytes from tomcat-mynet-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.048 ms

# 测试发现
没有使用--link也可以直接ping名字了
容器1 ping 容器2(ip) 可以通
容器1 ping 容器2(名字) 可以通
反过来ping也是可以通的

好处:

  • 不同的集群使用不同的网络,保证集群是安全和健康的
网络连通

如图,两个不同网络中的容器,他们之间怎么互连

不同的两个网卡之间是不能连通的,但是容器和网卡是可以连通的

在这里插入图片描述

# 创建两个docker0网络中的容器
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat02 tomcat

[root@localhost ~]# docker ps
CONTAINER ID   IMAGE         CREATED          STATUS          PORTS                                      NAMES
bd4acf85d4ed   tomcat    13 minutes ago   Up 13 minutes   0.0.0.0:49158->8080/tcp, :::49158->8080/tcp   tomcat02
b8dc0d6c10d0   tomcat    13 minutes ago   Up 13 minutes   0.0.0.0:49157->8080/tcp, :::49157->8080/tcp   tomcat01
71e4675d62cb   tomcat    22 hours ago     Up 22 hours     0.0.0.0:49156->8080/tcp, :::49156->8080/tcp   tomcat-mynet-02
499b2d7963e9   tomcat    22 hours ago     Up 22 hours     0.0.0.0:49155->8080/tcp, :::49155->8080/tcp   tomcat-mynet-01

# 尝试用tomcat01 ping tomcat-mynet-01
# 发现不行,他们属于两个不同的网络
[root@localhost ~]# docker exec -it tomcat01 ping tomcat-mynet-01
ping: tomcat-mynet-01: Name or service not known
# 测试打通tomcat01 与 mynet
# 通过docker network connect 网络名 容器名 将一个容器加到某一个网络
# 连通之后就是tomcat01一个容器两个ip
[root@localhost ~]# docker network connect mynet tomcat01
[root@localhost ~]# docker network inspect mynet

        "Containers": {
            "499b2d7963e9f7c54081933b808dd22b44726d7a997f46982a6727158d9aa401": {
                "Name": "tomcat-mynet-01",
                "EndpointID": "0fdbabad2c18af90c7c0c88b38ede357c9236650e6b52a5b39e1c3338ab58b7f",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            },
            "71e4675d62cb64055df633c4aa53cf3b955d260982a777c80316bb975e4f3360": {
                "Name": "tomcat-mynet-02",
                "EndpointID": "f02f3683250ed9e9b4dfae00733afbb90829e056e10df6111fb7c0c68b9afec7",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            },
            
            # 这边看到直接将tomcat01加入到了mynet
            
            "b8dc0d6c10d06fd959319456723f35d93b4152f1f347e4766ccc59624963f3a3": {
                "Name": "tomcat01",
                "EndpointID": "ba341ab92524604c9f4a1d39551079ed2d8d219925c2a1a9caa1567bff8b2892",
                "MacAddress": "02:42:c0:a8:00:04",
                "IPv4Address": "192.168.0.4/16",
                "IPv6Address": ""
            }
        },

# 再次测试,发现可以互通
[root@localhost ~]# docker exec -it tomcat01 ping tomcat-mynet-01
PING tomcat-mynet-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-mynet-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.218 ms
64 bytes from tomcat-mynet-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.057 ms

redis集群部署
# 创建redis的网络
[root@localhost ~]# docker network create --subnet 172.38.0.0/16 redis

# 通过脚本创建六个配置文件
#!/bin/bash
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
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

# 六个节点和配置文件都创建好了
[root@localhost redis]# ls
node-1  node-2  node-3  node-4  node-5  node-6

# 启动redis容器,通过for循环创建六个redis容器
for i in `seq 6`;do
docker run -d --name redis-$i -p 637$i:6379 -p 1637$i:16379 -v /mydata/redis/node-$i/data:/data -v /mydata/redis/node-$i/conf/redis.conf:/etc/redis/redis.conf --net redis --ip 172.38.0.1$i redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
done

# 创建集群
# 随便进去一个redis容器
[root@localhost redis]# docker exec -it redis-1 /bin/sh
/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

# 验证集群
/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:252
cluster_stats_messages_pong_sent:249
cluster_stats_messages_sent:501
cluster_stats_messages_ping_received:244
cluster_stats_messages_pong_received:252
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:501

127.0.0.1:6379> cluster nodes
b99032c696586c0de1608350eeeabc8f5dc2c750 172.38.0.14:6379@16379 slave a10c9f0e389d8add55d609ebabb4c190229d9a1a 0 1619765797409 4 connected
8d8b328e095a8e77a5e021551ae715f509934cac 172.38.0.12:6379@16379 master - 0 1619765797000 2 connected 5461-10922
a10c9f0e389d8add55d609ebabb4c190229d9a1a 172.38.0.13:6379@16379 master - 0 1619765797913 3 connected 10923-16383
e755a2159044c9a4a141c804614fea6a5f0ed9f8 172.38.0.11:6379@16379 myself,master - 0 1619765796000 1 connected 0-5460
5c6fe8c46f32b1add603dd407722c03b7784383b 172.38.0.15:6379@16379 slave e755a2159044c9a4a141c804614fea6a5f0ed9f8 0 1619765796401 5 connected
3e91c0e39f423def2a9cbf0cf1b58d96fe1903c3 172.38.0.16:6379@16379 slave 8d8b328e095a8e77a5e021551ae715f509934cac 0 1619765797000 6 connected

# 验证高可用
# set一个值,看到是172.38.0.13(master)处理的
127.0.0.1:6379> set a b
-> Redirected to slot [15495] located at 172.38.0.13:6379
OK

# 那现在把172.38.0.13这个容器停掉
[root@localhost ~]# docker stop redis-3

# 重新连接后,发现从172.38.0.14(slave) get到了这个值
/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.13:6379@16379 master,fail,之前的172.38.0.13(master)故障转移
# 发现172.38.0.14 从slave变成了master
# redis集群搭建完毕
172.38.0.14:6379> cluster nodes
3e91c0e39f423def2a9cbf0cf1b58d96fe1903c3 172.38.0.16:6379@16379 slave 8d8b328e095a8e77a5e021551ae715f509934cac 0 1619766297101 6 connected
b99032c696586c0de1608350eeeabc8f5dc2c750 172.38.0.14:6379@16379 myself,master - 0 1619766298000 7 connected 10923-16383
e755a2159044c9a4a141c804614fea6a5f0ed9f8 172.38.0.11:6379@16379 master - 0 1619766299416 1 connected 0-5460
8d8b328e095a8e77a5e021551ae715f509934cac 172.38.0.12:6379@16379 master - 0 1619766298000 2 connected 5461-10922
5c6fe8c46f32b1add603dd407722c03b7784383b 172.38.0.15:6379@16379 slave e755a2159044c9a4a141c804614fea6a5f0ed9f8 0 1619766299000 5 connected
a10c9f0e389d8add55d609ebabb4c190229d9a1a 172.38.0.13:6379@16379 master,fail - 1619766136592 1619766136089 3 connected

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值