Loading
0

Docker容器安装及使用知识总结(持续更新)

技术小学生微信公众号
腾讯云服务器大促销。
华为服务器

前言:很久没看过docker知识了,已忘记大半,最近重新拾起,从安装开始,将学习的笔记以及知识点总结一下,防止自己忘记,希望对大家有帮助。本文以Centos7.x为例安装docker容器。
Docker官方帮助文档:https://docs.docker.com/engine/install/centos/
Docker三要素:镜像、容器、仓库

准备篇:
1、卸载旧版本的docker(可省去,根据实际情况狂选择是否卸载)

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

若上面方法无法卸载,可参考如下方法:
查询安装的docker包:

rpm -qa |grep docker

卸载:

rpm -e 包名

2、安装yum-utils以及配置docker源为阿里云。

sudo yum install -y yum-utils
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

3、更新yum源

yum makecache fast



安装篇:
1、安装docker

sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin

2、查看已安装的docker软件包(可以忽略)

yum list docker-ce --showduplicates | sort -r

3、启动Docker

sudo systemctl start docker

4、验证docker安装是否成功,执行如下命令如果页面有显示hello-world 等字样则说明成功了。

sudo docker run hello-world

5、如果要查看docker版本信息可执行如下命令

docker version



卸载篇:
卸载Docker

sudo systemctl stop docker
sudo yum remove docker-ce docker-ce-cli containerd.io docker-compose-plugin
 sudo rm -rf /var/lib/docker
 sudo rm -rf /var/lib/containerd



设置篇:
配置阿里云的镜像加速器
可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器
请将xxxxxx.mirror.aliyuncs.com换成自己的加速地址

sudo mkdir -p /etc/docker

sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://xxxxxx.mirror.aliyuncs.com"]
}
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker



命令篇:
帮助启动类命令
启动docker

systemctl start docker

停止docker

systemctl stop docker

重启docker

systemctl restart docker

查看docker状态

systemctl status docker

开机自启:

systemctl enable docker

查看docker摘要信息:

docker info

查看已拉取的docker镜像

docker images

参数:
  1. -a:列出本地所有镜像,包含历史镜像
  2. -q:只显示镜像ID

[root@blog.tag.gg ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
hello-world   latest    feb5d9fea6a5   10 months ago   13.3kB

REPOSITORY:镜像的仓库源
TAG:镜像版本
IMAGE ID:镜像id
CREATED:镜像创建时间
SIZE:镜像大小
注意:如果不指定Tag版本,默认是latest 表示最新版。

镜像类命令:
搜索镜像:

docker search xxxx

参数:
  • --limit:只列出N个镜像,默认25个
  • 范例:docker search --limit 5 nginx
拉取镜像:

docker pull xxxx  (下载最新版)

docker pull xxxx:1.6 (下载指定版本的镜像)

查看镜像/容器/数据卷所占用的空间:(类似于linux的df命令)

docker system df

[root@blog.tag.gg ~]# docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          2         1         133.3MB   133.2MB (99%)
Containers      2         0         0B        0B
Local Volumes   0         0         0B        0B
Build Cache     0         0         0B        0B

删除某个镜像:

docker rmi 镜像ID/镜像名

强制删除:

docker rmi -f 镜像ID/镜像名

同时删除多个镜像:

docker rmi -f  A B C

删除全部镜像(谨慎操作

docker rmi -f $(docker images -qa)

docker images -qa:显示全部镜像且只显示镜像id。
虚悬镜像:
仓库名、标签都是<none>的镜像,俗称虚悬镜像,dangling image
删除虚悬镜像:(谨慎操作,建议做好快照后操作,否则数据删除无法恢复

docker rmi $(docker images -q -f dangling=true)



容器类命令:
通过镜像拉起一个容器,例如nginx
docker run -itdp 80:80 --name nginxtest 容器名或镜像ID

docker run -itdp 80:80 --name nginxtest nginx

docker run -d --name nginx_mirrors -p 80:80 605c77e624dd

如果报错“docker: Error response from daemon: No command specified”可以在后面加上 /bin/bash在执行,例如

docker run -itdp 80:80 --name nginxtest nginx /bin/bash

注意:例如nginx默认监听的是80,如果设置为80:88 那么端口外部不会通,因为容器中监听的是80而不是88,可以进入容器,将80监听改成88即可
新建+启动容器命令:

docker run 选项 镜像名 命令

参数:
  • --name=“容器新名字” 为容器指定一个名称;
  • -d:后台运行容器并返回容器ID,也即启动守护式容器(后台运行);
  • -i:以交互模式运行容器,通畅与-t同时使用;
  • -t:为容器重新分配一个伪输入终端,等待交互;
  • -P:随机段鸥映射,大写P
  • -p:指定端口映射,小写p

docker run -it 镜像ID /bin/bash

启动容器并修改name:

docker run -it --name=bzyyc  0d493297b409 /bin/bash

查看已启动的容器:

docker ps

[root@blog.tag.gg ~]# docker ps
CONTAINER ID   IMAGE          COMMAND       CREATED              STATUS              PORTS             NAMES
7ec7065fa89f   0d493297b409   "/bin/bash"   About a minute ago   Up About a minute   80/tcp, 443/tcp   gracious_hoover

参数:
  • -a:列出当前所有正在运行的容器+历史上运行过的容器
  • -l:显示最近创建的容器
  • -n:显示最近n个创建的容器
  • -q:静默模式,只显示容器编号
退出容器:
两种退出方式:
  • exit:run进去容器,exit退出,容器停止
  • ctrl+p+q:run进去容器,ctrl+p+q退出,容器不停止
启动已停止的容器:

docker start 容器ID/容器名

重启容器:

docker restart 容器ID/容器名

停止容器:

docker stop 容器ID/容器名

强制停止容器:

docker kill 容器ID/容器名

删除已停止的容器:

docker rm 容器ID/容器名

强制删除运行中的容器(高危

docker rm -f 容器ID/容器名

一次性删除所有容器(高危
强制是删除所有容器,包含运行中的
docker ps -a -q显示所有容器的id

docker rm -f $(docker ps -a -q)
docker ps -a -q |xargs docker rm (传参方式)

启动守护式容器(后台运行) -d后台运行。

docker run -d 容器名

注意:很容易混淆的问题
比如:使用了docker run -d centos 后台运行这个容器,但使用docker ps 看不到容器,使用docker ps -a 查看到容器是退出状态,所以,docker容器后台运行,就必须有一个前台进程,容器运行的命令如果不是那些一直挂起的命令(比如top、tail命令等)就会自动退出。
这是docker的机制问题,比如是web容器,以nginx为例,正常情况下配置了启动服务只需要启动相应的service即可,例如 service nginx start 但是这样做nginx为进程模式运行,就导致docker 前台没有运行应用。这样的容器后台启动后会立即自杀因为他觉得他没事情做了。
所以,最佳的解决方案是:将您要运行的程序以前太进程的形式运行。常见就是命令行模式,表示我还有交互操作,别中断。则用docker run -it cenots    退出时可以用ctrl+q+p
查看容器的日志:

docker logs 容器ID

注意:(待定)某些情况下执行上面命令没有返回任何日志,原因 docker log只能记录输出到终端的内容(stdout或者stderr),输出到文件的无法显示
比如:(待定)运行了redis的容器,可以用这个命令查看,因为redis日志本身是直接输出到终端的。运行了nginx的容器这个命令则无法查看,因为nginx服务日志是记录在文件中的,若要查看,则需要打开nginx日志文件看
查看最近2条日志: docker logs --tail 2 容器名
查看容器内运行的进程:

docker top 容器ID

 查看容器内部细节:

docker inspect 容器ID

运行后可以看到该容器的配置信息,以json格式显示。
进入正在运行的容器,并以命令行交互:

docker exec -it 容器ID bashshell

docker attach 容器ID  

注意:exec和attach区别如下:
exec:在容器中打开新的终端,并且可以启动新的进程用于exit退出,不会导致容器停止。
attach :直接进入容器启动命令的终端,不会启动新的进程用于exit退出,会导致容器停止
如果不需要容器停止,请使用exec

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

docker cp 容器ID:容器内内路径 宿主机路径

例如:

docker cp fb869f8045a4:/blog.tag.gg.txt /root/

拷贝文件后并重命名:

docker cp fb869f8045a4:/blog.tag.gg.txt /root/blog.tag.gg.docker.txt

镜像导入导出方法:
export:导出容器的内容留作为一个tar归档文件(将容器导出备份)
import:从tar报中的内容创建一个新的文件系统在导入镜像(将备份的镜像导入)
导出:

docker export 容器ID >文件名.tar

范例:

docker export fb869f8045a4 > /root/abcd.tar

导入:

cat 文件名.tar|docker import - 镜像用户/镜像名:镜像版本号

范例:

cat abcd.tar|docker import - blog.tag.gg/nginx:1.8

blog.tag.gg/nginx:1.8(镜像用户/镜像名:镜像版本号)对应的是 REPOSITORY    TAG  
导入后执行命  docker images 可以看到镜像,在执行命令 docker start 7d0a7a994226 启动容器,并执行 docker run -it 7d0a7a994226 /bin/bash 则可启动查看。

将本地镜像发布到阿里云:
1、创建命名空间

2、创建镜像仓库

blog.tag.gg.test一般为镜像名字
推送镜像:
将如下的信息换成自己的
执行命令登录仓库:

docker login --username=261****@qq.com registry.cn-shenzhen.aliyuncs.com

执行如下命令设置镜像版本([镜像版本号]可以自己指定,比如我指定的是1.5.5)
原始命令:

docker tag [ImageId] registry.cn-shenzhen.aliyuncs.com/blog_tag_gg/blog.tag.gg.test:[镜像版本号]

我执行的命令:

docker tag 72c3668f916e registry.cn-shenzhen.aliyuncs.com/blog_tag_gg/blog.tag.gg.test:1.5.5

推送镜像:
原始命令:

docker push registry.cn-shenzhen.aliyuncs.com/blog_tag_gg/blog.tag.gg.test:[镜像版本号]

我执行的命令:

docker push registry.cn-shenzhen.aliyuncs.com/blog_tag_gg/blog.tag.gg.test:1.5.5

推送完成后会有显示。

推送后可参考如图查看

将阿里云自己的镜像拉取到本地使用
登录服务器执行命令即可拉取到本地

docker pull registry.cn-shenzhen.aliyuncs.com/blog_tag_gg/blog.tag.gg.test:1.5.5


搭建本地私有仓库
安装:registry

docker pull registry

运行私有仓库:registry

docker run -d -p 5000:5000 -v /usr/local/registry:/var/lib/registry registry

用CURL命令验证私有仓库上有什么镜像:

curl -XGET 192.168.0.222:5000/v2/_catalog

如果显示“{"repositories":[]}”这表示为空。
将mysql镜像修改为符合私有镜像规范的Tag
原来如下:

[root@blog.tag.gg ~]#  docker images
REPOSITORY                                                       TAG       IMAGE ID       CREATED         SIZE
blog.tag.gg_nginx/nginx                                          1.5.5     efba7e9d4652   4 hours ago     199MB
registry.cn-shenzhen.aliyuncs.com/blog_tag_gg/blog.tag.gg.test   1.5.5     efba7e9d4652   4 hours ago     199MB
nginx                                                            latest    605c77e624dd   9 months ago    141MB
mysql                                                            latest    3218b38490ce   10 months ago   516MB
registry                                                         latest    b8604a3fe854   11 months ago   26.2MB

执行如下命令将 mysql镜像修改为192.168.0.222:5000/mysql_test

docker tag mysql:latest 192.168.0.222:5000/mysql_test:9.0

说明:将mysql:latest修改为192.168.0.222:5000/mysql_test:9.0
修改配置文件使之支持http
 编辑:/etc/docker/daemon.json文件增加如下代码:

,"insecure-registries":["192.168.0.222:5000"]

注意,该文件是json格式,"insecure-registries"前面有一个逗号不能省略,否则会报错。
完整的格式如下:

{
  "registry-mirrors": ["https://v8gxxxxx.mirror.aliyuncs.com"],
"insecure-registries":["192.168.0.222:5000"]
}

push推送到私有仓库

docker push 192.168.0.222:5000/mysql_test:9.0

推送完成后再执行如下命令查看仓库中的镜像

curl -XGET 192.168.0.222:5000/v2/_catalog

从私有仓库下载镜像安装

docker pull 192.168.0.222:5000/mysql_test:9.0


Docker容器数据卷
 注意(坑):Docker挂载主机目录访问如果出现:cannot open directory /xx/: Permission denied
原因是权限不足,解决方法是在挂载目录后面多加一个参数 :--privileged=true 即可解决,并将selinux关闭
完整范例如下:

docker run -i -t -v /soft:/soft --privileged=true 686672a1d0cc /bin/bash

docker run -d -p 80:80 -v /blog-tag-gg/miir:/rongqi/miir --privileged=true blogtaggg

添加docker容器卷实现数据持久化:
容器卷作用:将docker容器内的数据保存到宿主磁盘中,达到数据持久化存储,更安全。

格式:

docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 --name=名称  镜像名 /bin/bash

默认情况下是双向读写,也就是rw,等同于:

docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw --name=名称  镜像名 /bin/bash

范例:

docker run -p 80:80 -it --privileged=true -v /blog.tag.gg/rong_nginx_data:/blog.tag.gg/data --name=nginx_test nginx /bin/bash

docker run -it --privileged=true -v /blog.tag.gg/rong_nginx_data:/blog.tag.gg/data --name=nginx_test nginx /bin/bash

-v /宿主机绝对路径目录:/容器内目录 可以同时绑定多个目录,届时多添加相应路径即可,比如日志、配置、数据目录等。
特点:
  1. 数据卷可在容器自检共享或重用数据
  2. 卷中的更改可以直接实时生效
  3. 数据卷中的更改不会包含在镜像的更新中
  4. 数据卷的生命周期一直持续到没有容器使用它为止。
查看容器是否有设置持久化存储(是否有添加容器卷)

docker inspect c3e6a7695923

其中会显示如下:
"Type": "bind",
                "Source": "/blog.tag.gg/rong_nginx_data",
                "Destination": "/blog.tag.gg/data",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
Source:宿主路径
Destination:容器内路径
  1. docker修改、宿主内也会同步
  2. 宿主内修改、docker也会同步
  3. docker容器停止,宿主修改文件或添加文件,docker容器启动后数据也会同步。
注意:删除文件后对应一端的文件也会删除。
限制容器内只能读取不能写

docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro --name=名称  镜像名

 0
此时在宿主中创建的文件可以同步到容器中,但若在容器中创建或修改文件会报错如图,原因是设置了容器只读。

root@6b6254fd024b:/gg/data# echo "test" >blog.tag.gg.txt
bash: blog.tag.gg.txt: Read-only file system

容器卷的继承和共享:
1、容器1完整与主机的映射

docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 --name=U1  镜像名

2、容器2集成容器1映射的目录

docker run -it --privileged=true --volumes-from 父类 --name=U2 镜像名 /bin/bash

范例:

docker run -it --privileged=true --volumes-from u1 --name=U2 nginx  /bin/bash

说明:
父类:表示U1,也就是--name=U1 
设置后表示容器2映射的目录与容器1一样,在宿主机容器1或者容器2中读写及修改都会相互生效,即便将容器1停止,容器2的读写也会与宿主同步,将容器1启用后之前容器2的读写内容也会同步。
Docker容器中常见软件的安装部署:
总体步骤:搜索镜像(docker search 镜像名)、拉取镜像(docker pull 镜像名)、查看镜像(docker images)、启动镜像及端口映射(docker run -itd -p 80:80 tomcat)、停止容器(docker stop tomcat)、移除容器(docker rm tomcat)
安装Tomcat:
1、搜索tomcat版本:

docker search tomcat

2、拉取tomcat镜像到本地

docker pull tomcat

默认表示最新版。
3、启动并后台运行tomcat

docker run -itd -p 80:8080 --name=tomcat_test tomcat /bin/bash

注意(坑):
1、安装好后看80端口有正常被docker监听,但端口不通,原因是容器里面tomcat服务没启动起来,进入容器/usr/local/tomcat/bin目录,然后执行 startup.sh启动脚本即可。
2、访问后提示404,并没有显示tomcat默认猫的页面,原因是tomcat10这个版本后 /usr/local/tomcat/webapps 目录为空,所以没有文件报404,若要显示默认界面,可以执行如下命令即可

mv webapps ./webapps_bak
mv webapps.dist ./webapps

tomcat默认页面存放在webapps.dist 改名为webapps即可正常看到。
3、tomcat网站根目录默认为:/usr/local/tomcat/webapps/ROOT
简单安装mysql:(没有设置持久存储,该方法只用于测试)
1、拉取mysql5.7

docker pull mysql:5.7

[root@blog-tag-gg ~]#  docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
mysql                 5.7       c20987f18b13   10 months ago   448MB

2、生成mysql容器并设置数据库的root密码

docker run -p 3306:3306  --name=myslq_test -e MYSQL_ROOT_PASSWORD=blogtagggpw -d mysql:5.7

3、进入mysql容器

docker exec -it cbc87ba3f507 /bin/bash

4、进入mysql数据库

mysql -uroot -p

回车后输入数据库的root即可进入数据库,能正常进入,则表示正常
创建数据库及创建表及字段以及设置字段值:

mysql> create database db01;
Query OK, 1 row affected (0.00 sec)

mysql> use db01;
Database changed
mysql> create table t1(id int,name varchar(30));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t1 values(1,'zhangsan');
Query OK, 1 row affected (0.02 sec)

mysql> select * from t1;
+------+----------+
| id   | name     |
+------+----------+
|    1 | zhangsan |
+------+----------+
1 row in set (0.00 sec)

注意1:默认情况下mysql是有开启root远程权限的,这有安全隐患,若不需要外部调用mysql,建议禁止数据库root远程。
注意2超级坑:
默认情况下插入中文数据时会报错.
例如插入:

insert into t1 values(2,'技术小学生');

会报错:

[SQL]insert into t1 values(2,'技术小学生');
[Err] 1366 - Incorrect string value: '\xE6\x8A\x80\xE6\x9C\xAF...' for column 'name' at row 1

报错原因:是数据库字符编码的问题,需调整编码
再次注意:查看字符编码必须登录容器里面查看,如果使用第三方工具查看,例如Navicat查看,工具会自动将编码修改为utf-8,实际行数据库中的编码没有改变。
查看编码:
mysql> SHOW VARIABLES LIKE 'character%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     |
| character_set_connection | latin1                     |
| character_set_database   | latin1                     |
| character_set_filesystem | binary                     |
| character_set_results    | latin1                     |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
第三方工具查询结果

解决方法可参考下面
运行mysql容器并设置持久存储(容器卷)

docker run -d -p 3306:3306 --privileged=true -v /blogtaggg/mysql/log:/var/log/mysql -v /blogtaggg/mysql/data:/var/lib/mysql -v /blogtaggg/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=blogtagggpw --name=mysql_test mysql:5.7

容器中数据库存放路径及配置文件路径可以在/etc/mysql/mysql.cnf 或 /etc/mysql/mysql.conf.d下的mysqld.cnf查看,不同版本可能略微不同,可以自己查找,具体请根据自己路径填写。

 

解决编码问题:
进入:/blogtaggg/mysql/conf目录,创建 my.cnf文件,并写入如下代码再重启mysql即可。

[mysqld]
character_set_server=utf8
collation_server=utf8_general_ci
[mysql]
default-character-set = utf8
[mysql.server]
default-character-set = utf8
[mysqld_safe]
default-character-set = utf8
[client]
default-character-set = utf8

重启mysql容器后在插入中文后正常。

mysql> select * from t1;
+------+-----------------+
| id   | name            |
+------+-----------------+
|    1 | lisi            |
|    2 | 技术小学生      |
+------+-----------------+
2 rows in set (0.00 sec)

编码如下:

mysql> SHOW VARIABLES LIKE 'character%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

结论:亲测,设置好之久存储(容器卷后)数据会同步到宿主目录里面,即便将mysql容器删除,重新运行容器后数据库数据还存在。
将容器内的软件源(yum)修改为阿里云的源方法.
查看容器所使用的操作系统:
不同系统查看方法不一样可以都试下。

cat /etc/issue
cat /etc/redhat-release

1、debian(亲测)

cp /etc/apt/sources.list /etc/apt/sources.list.bak
echo "" > /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/debian buster main" >> /etc/apt/sources.list ;
echo "deb http://mirrors.aliyun.com/debian-security buster/updates main" >> /etc/apt/sources.list ;
echo "deb http://mirrors.aliyun.com/debian buster-updates main" >> /etc/apt/sources.list ;

部分容器没有安装wget或者vi或者mv命令只有通过echo命令实现修改。
其他版本还没测试过。
简单安装redis:(没有加容器卷,持久存储)
1、从仓库拉取版本为6的redis镜像

docker pull redis:6

2、使用镜像生成redis容器

docker run -itd -p 6379:6379 redis:6


3、进入redis容器

docker exec -it 53c51c649bae /bin/bash

4、检测redis是否正常

redis-cli

返回:

root@53c51c649bae:/data# redis-cli
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> get k1
"v1"

复杂安装redis(添加容器卷(持久存储))
 拉起redis容器,并设置持久化存储

docker run -p 6379:6379 --name=redis_test --privileged=true -v /app/redis/redis.conf:/etc/redis/redis.conf -v /app/redis/data:/data -d redis:6 redis-server /etc/redis/redis.conf

daemonize 参数必须为no,否则 与docker中的-d参数冲突
Docker高级篇:
容器中mysql主从搭建:
1、新建主服务器容器实例:端口为3307

docker run -p 3307:3306 --name=mysql-master \
-v /mydata/mysql-master/log:/var/log/mysql \
-v /mydata/mysql-master/data:/var/lib/mysql \
-v /mydata/mysql-master/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=blogtagggpw  \
-d mysql:5.7

2、进入/mydata/mysql-master/conf目录,创建my.cnf文件,并写入如下内容。

[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=101
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql  
## 开启二进制日志功能
log-bin=mall-mysql-bin  
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M  
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed  
## 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7  
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062

重启mysql-master容器。

docker restart mysql-master

重启后一定要执行如下命令看下是否有启动成功,若启动成功,则说明配置正常,容器正常。

docker ps -a

[root@blog-tag-gg conf]# docker ps -a
CONTAINER ID   IMAGE       COMMAND                  CREATED         STATUS         PORTS                                                  NAMES
a1308309a139   mysql:5.7   "docker-entrypoint.s…"   6 minutes ago   Up 4 seconds   33060/tcp, 0.0.0.0:3307->3306/tcp, :::3307->3306/tcp   mysql-master

3、进入mysql-master容器内部:

docker exec -it mysql-master /bin/bash


输入如下命令回车并输入数据库root密码看是否可进入数据库,若能进入,则正常。

mysql -uroot -p

4、mysql-master容器实例内部创建数据同步用户
创建slave用户并设置密码,以及设置连接权限为%

CREATE USER 'slave'@'%' IDENTIFIED BY 'blogtagggpw';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';

创建后:

mysql> CREATE USER 'slave'@'%' IDENTIFIED BY 'blogtagggpw';
Query OK, 0 rows affected (0.01 sec)

mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
Query OK, 0 rows affected (0.00 sec)

mysql>

5、新建从服务器容器实例 端口为:3308

docker run -p 3308:3306 --name mysql-slave \
-v /mydata/mysql-slave/log:/var/log/mysql \
-v /mydata/mysql-slave/data:/var/lib/mysql \
-v /mydata/mysql-slave/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=blogtagggpw  \
-d mysql:5.7

[root@blog-tag-gg conf]# docker ps -a
CONTAINER ID   IMAGE       COMMAND                  CREATED          STATUS          PORTS                                                  NAMES
738d0b3cc403   mysql:5.7   "docker-entrypoint.s…"   25 seconds ago   Up 23 seconds   33060/tcp, 0.0.0.0:3308->3306/tcp, :::3308->3306/tcp   mysql-slave
a1308309a139   mysql:5.7   "docker-entrypoint.s…"   17 minutes ago   Up 11 minutes   33060/tcp, 0.0.0.0:3307->3306/tcp, :::3307->3306/tcp   mysql-master

6、进入/mydata/mysql-slave/conf目录,创建my.cnf文件并写入如下代码

[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=102
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql  
## 开启二进制日志功能,以备Slave作为其它数据库实例的Master时使用
log-bin=mall-mysql-slave1-bin  
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M  
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed  
## 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7  
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062  
## relay_log配置中继日志
relay_log=mall-mysql-relay-bin  
## log_slave_updates表示slave将复制事件写进自己的二进制日志
log_slave_updates=1  
## slave设置为只读(具有super权限的用户除外)
read_only=1

7、重启从服务器容器。

docker restart mysql-slave

重启后执行如下命令看是否有启动成功。(有up表示启动成功)

docker ps -a

8、在主数据库中查看主从同步状态。
登录主服务器容器进入数据库,执行如下命令查看同步状态

show master status;

结果如下:表示设置成功。

mysql> show master status;
+-----------------------+----------+--------------+------------------+-------------------+
| File                  | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-----------------------+----------+--------------+------------------+-------------------+
| mall-mysql-bin.000001 |      617 |              | mysql            |                   |
+-----------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

9、进入从容器服务器 mysql-slave

docker exec -it mysql-slave

10、在从数据库中配置主从复制:
通过数据库密码进入数据库后执行如下命令配置

change master to master_host='192.168.16.4',master_user='slave',master_password='blogtagggpw',master_port=3307,master_log_file='mall-mysql-bin.000001',master_log_pos=617,master_connect_retry=30;

各项说明可参考:
master_host:主数据库的IP地址;可以通过ifconfig 命令查看。
master_port:主数据库的运行端口;
master_user:在主数据库创建的用于同步数据的用户账号;
master_password:在主数据库创建的用于同步数据的用户密码;
master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数;
master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数;
master_connect_retry:连接失败重试的时间间隔,单位为秒。
11、在从数据库中查看主从同步状态

show slave status \G;

结果:

mysql> show slave status \G;
*************************** 1. row ***************************

               Slave_IO_State:
                  Master_Host: 192.168.16.4
                  Master_User: slave
                  Master_Port: 3307
                Connect_Retry: 30
              Master_Log_File: mall-mysql-bin.000001
          Read_Master_Log_Pos: 617
               Relay_Log_File: mall-mysql-relay-bin.000001
                Relay_Log_Pos: 4
        Relay_Master_Log_File: mall-mysql-bin.000001
             Slave_IO_Running: No
            Slave_SQL_Running: No

              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 617
              Relay_Log_Space: 154
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 0
                  Master_UUID:
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State:
           Master_Retry_Count: 86400
                  Master_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set:
                Auto_Position: 0
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:
1 row in set (0.00 sec)


ERROR:
No query specified

显示如下则表示还没开始同步

             Slave_IO_Running: No
            Slave_SQL_Running: No

12、在从数据库中开启主从同步:

mysql> start slave;
Query OK, 0 rows affected (0.38 sec)

13、查看从数据库中状态,此时发现已同步
执行命令

show slave status \G;

返回结果:发现编程了yes,则表示正常了。

mysql> show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.16.4
                  Master_User: slave
                  Master_Port: 3307
                Connect_Retry: 30
              Master_Log_File: mall-mysql-bin.000003
          Read_Master_Log_Pos: 154
               Relay_Log_File: mall-mysql-relay-bin.000004
                Relay_Log_Pos: 377
        Relay_Master_Log_File: mall-mysql-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 154
              Relay_Log_Space: 812
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 101
                  Master_UUID: 5a4efa74-552b-11ed-a3c5-0242ac110002
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set:
                Auto_Position: 0
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:
1 row in set (0.13 sec)

ERROR:
No query specified

14、主从复制测试:
在主数据库中创建数据库及表以及写入信息

mysql> create database blogtaggg_db;
Query OK, 1 row affected (0.11 sec)

mysql> use blogtaggg_db;
Database changed
mysql> create table t1(id int,name varchar(20));
Query OK, 0 rows affected (0.09 sec)

mysql> insert into t1 values(1,'blog.tag.gg');
Query OK, 1 row affected (0.02 sec)

mysql> select * from t1;
+------+-------------+
| id   | name        |
+------+-------------+
|    1 | blog.tag.gg |
+------+-------------+
1 row in set (0.00 sec)

登录从数据库,看是否可以直接打开 blogtaggg_db 这个数据库并查看数据。

mysql> use blogtaggg_db;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from t1;
+------+-------------+
| id   | name        |
+------+-------------+
|    1 | blog.tag.gg |
+------+-------------+
1 row in set (0.03 sec)

查看数据已经同步到从数据库了,大工搞成。
亿级别3主3从Redis集群扩容缩容实战案例说明
3主3从集群配置:
1、拉取Redis镜像,这里忽略。
2、拉取后执行如下命令拉起6台redis容器实例。

docker run -d --name redis-node-1 --net host --privileged=true -v /data/redis/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381
docker run -d --name redis-node-2 --net host --privileged=true -v /data/redis/share/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382
docker run -d --name redis-node-3 --net host --privileged=true -v /data/redis/share/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383
docker run -d --name redis-node-4 --net host --privileged=true -v /data/redis/share/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384
docker run -d --name redis-node-5 --net host --privileged=true -v /data/redis/share/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385
docker run -d --name redis-node-6 --net host --privileged=true -v /data/redis/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386

参数说明:

docker run:创建并运行容器
--name redis-node-6:容器的名字
--net host:使用宿主机的ipHE 端口
--privileged=true:获取宿主机root权限
-v /data/redis/share/redis-node-6:/data:容器卷,宿主机地址:docker内部地址
redis:6.0.8:redis镜像和版本号
--cluster-enabled yes:开启redis集群
--appendonly yes:开启持久化
--port 6386:redis的端口号

查看是否有运行成功:(目前六台机器不分主从)

[root@blog.tag.gg ~]# docker ps -a
CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS          PORTS     NAMES
ea1e315e6661   redis:6.0.8   "docker-entrypoint.s…"   11 seconds ago   Up 10 seconds             redis-node-6
a2f50b8b242a   redis:6.0.8   "docker-entrypoint.s…"   12 seconds ago   Up 11 seconds             redis-node-5
0ddf1b14abf5   redis:6.0.8   "docker-entrypoint.s…"   12 seconds ago   Up 12 seconds             redis-node-4
a647cff0653d   redis:6.0.8   "docker-entrypoint.s…"   13 seconds ago   Up 12 seconds             redis-node-3
1d342b9e7d0a   redis:6.0.8   "docker-entrypoint.s…"   13 seconds ago   Up 12 seconds             redis-node-2
19f7c6d53b20   redis:6.0.8   "docker-entrypoint.s…"   13 seconds ago   Up 12 seconds             redis-node-1

3、构建主从关系,进入其中一台机器:

docker exec -it redis-node-1 /bin/bash

redis-cli --cluster create 192.168.0.170:6381 192.168.0.170:6382 192.168.0.170:6383 192.168.0.170:6384 192.168.0.170:6385 192.168.0.170:6386 --cluster-replicas 1

注意:
1、将ip地址和端口替换为自己的信息
2、--cluster-replicas 1 表示为每个master创建一个slave节点(一主一从,刚好三主三从)
3、 --cluster 表示构建集群
操作完后会自动分配三台主服务器及从服务器。
执行后显示如下:

root@blog.tag.gg:/data# redis-cli --cluster create 192.168.0.170:6381 192.168.0.170:6382 192.168.0.170:6383 192.168.0.170:6384 192.168.0.170:6385 192.168.0.170:6386 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460 --->第一个主服务器,哈希槽位是0-5640
Master[1] -> Slots 5461 - 10922 ---> 第二个主服务器,哈希槽位是5461-10922
Master[2] - > Slots 10923 - 16383 --->第三个主服务器,哈希槽位是10923-16383
Adding replica 192.168.0.170:6385 to 192.168.0.170:6381
Adding replica 192.168.0.170:6386 to 192.168.0.170:6382   
这三个是主从映射关系
Adding replica 192.168.0.170:6384 to 192.168.0.170:6383
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: a7d3b130cd14ad6877881cd717244ff8520444c0 192.168.0.170:6381
   slots:[0-5460] (5461 slots) master
M: ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 192.168.0.170:6382
   slots:[5461-10922] (5462 slots) master
M: fdaa13136f44c0be3139edfc2ef48eb00579caaf 192.168.0.170:6383
   slots:[10923-16383] (5461 slots) master
S: 433118ba0840594c14716fba173a7895a3836662 192.168.0.170:6384
   replicates ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
S: fb9fa790b29cafa1ff84c7a3173d806f72a2d4f3 192.168.0.170:6385
   replicates fdaa13136f44c0be3139edfc2ef48eb00579caaf
S: b567fd9306230772798b02845296ad3948d3e1fa 192.168.0.170:6386
   replicates a7d3b130cd14ad6877881cd717244ff8520444c0
Can I set the above configuration? (type 'yes' to accept):   ---->提示 如果确认上面的配置,输入yes回车即可。

输入yes后完成配置(m代表主,S代表从)

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 192.168.0.170:6381)
M: a7d3b130cd14ad6877881cd717244ff8520444c0 192.168.0.170:6381
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: fdaa13136f44c0be3139edfc2ef48eb00579caaf 192.168.0.170:6383
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: b567fd9306230772798b02845296ad3948d3e1fa 192.168.0.170:6386
   slots: (0 slots) slave
   replicates a7d3b130cd14ad6877881cd717244ff8520444c0
S: fb9fa790b29cafa1ff84c7a3173d806f72a2d4f3 192.168.0.170:6385
   slots: (0 slots) slave
   replicates fdaa13136f44c0be3139edfc2ef48eb00579caaf
S: 433118ba0840594c14716fba173a7895a3836662 192.168.0.170:6384
   slots: (0 slots) slave
   replicates ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
M: ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 192.168.0.170:6382
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
root@blog.tag.gg:/data#

查看集群状态:(以6381节点为例)

redis-cli -p 6381
cluster info

root@blog.tag.gg:/data# redis-cli -p 6381
127.0.0.1:6381> 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   --4个节点
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:264
cluster_stats_messages_pong_sent:239
cluster_stats_messages_sent:503
cluster_stats_messages_ping_received:234
cluster_stats_messages_pong_received:264
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:503
127.0.0.1:6381>

cluster nodes命令使用说明

cluster nodes

执行结果下:

127.0.0.1:6381> cluster nodes
fdaa13136f44c0be3139edfc2ef48eb00579caaf 192.168.0.170:6383@16383 master - 0 1667053731700 3 connected 10923-16383
b567fd9306230772798b02845296ad3948d3e1fa 192.168.0.170:6386@16386 slave a7d3b130cd14ad6877881cd717244ff8520444c0 0 1667053730000 1 connected
fb9fa790b29cafa1ff84c7a3173d806f72a2d4f3 192.168.0.170:6385@16385 slave fdaa13136f44c0be3139edfc2ef48eb00579caaf 0 1667053730699 3 connected
433118ba0840594c14716fba173a7895a3836662 192.168.0.170:6384@16384 slave ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 0 1667053729000 2 connected
a7d3b130cd14ad6877881cd717244ff8520444c0 192.168.0.170:6381@16381 myself,master - 0 1667053727000 1 connected 0-5460
ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 192.168.0.170:6382@16382 master - 0 1667053730000 2 connected 5461-10922
127.0.0.1:6381>

说明:
1、16381 myself:则表示当前是在 6381这个节点中执行命令
2、6383、6382、6381 这三台服务器是master,也就是主节点。
3、注意:谁挂载谁的下面了?以6382为例,该主节点的id为:ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 他下面挂载了 6384这个从节点,从id为:433118ba0840594c14716fba173a7895a3836662

主从容错切换迁移案例:
数据读写存储:
进入例如6381节点执行命令

127.0.0.1:6381> keys *
(empty array)
127.0.0.1:6381> set k1 v1
(error) MOVED 12706 192.168.0.170:6383
127.0.0.1:6381> set k2 v2
OK
127.0.0.1:6381> set k3 v3
OK
127.0.0.1:6381> set k4 v4
(error) MOVED 8455 192.168.0.170:6382
127.0.0.1:6381>

问题:为什么k1和k4执行后无法写入数据?
答:因为目前是单机登录的redis,set k1 v1 和set k4 v4的槽点分别是12706和 8455  没有在当前6381这个redis节点中,所以无法写入。其他能写入的是因为刚好槽点在这个范围内。
解决该问题:
需要防止路由失效,添加参数 -c以集群方式连接,并新增两个key

redis-cli -p 6381 -c

root@blog.tag.gg:/data# redis-cli -p 6381 -c
127.0.0.1:6381> FLUSHALL 清空之前的数据
OK
127.0.0.1:6381> set k1 v1
-> Redirected to slot [12706] located at 192.168.0.170:6383 
OK
192.168.0.170:6383> set k2 v2
-> Redirected to slot [449] located at 192.168.0.170:6381
OK
192.168.0.170:6381> set k3 v3
OK
192.168.0.170:6381> set k4 v4
-> Redirected to slot [8455] located at 192.168.0.170:6382
OK
192.168.0.170:6382>

说明:
1、执行 set k1 v1 后槽点为:12706 是在6383节点,目前是集群构架进入,所以会自动跳转到6383节点。
2、执行 set k2 v2 后槽点为:449 是在6381节点,会自动从6383节点跳转回6381节点。
3、执行 set k3 v3 后槽点刚好是在当前6381节点范围内,所以显示ok并且不会重定向到其他节点。
4、执行 set k4 v4 后槽点为:8455,这个槽点刚好在6382节点,所以会从6381节点重定向到6382节点并执行成功。
查看集群信息2:

redis-cli --cluster check 192.168.0.170:6381

执行后如下:

root@blog.tag.gg:/data# redis-cli --cluster check 192.168.0.170:6381
192.168.0.170:6381 (a7d3b130...) -> 2 keys | 5461 slots | 1 slaves.
192.168.0.170:6383 (fdaa1313...) -> 1 keys | 5461 slots | 1 slaves.
192.168.0.170:6382 (ca8b40b5...) -> 1 keys | 5462 slots | 1 slaves.
[OK] 4 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 192.168.0.170:6381)
M: a7d3b130cd14ad6877881cd717244ff8520444c0 192.168.0.170:6381
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: fdaa13136f44c0be3139edfc2ef48eb00579caaf 192.168.0.170:6383
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: b567fd9306230772798b02845296ad3948d3e1fa 192.168.0.170:6386
   slots: (0 slots) slave
   replicates a7d3b130cd14ad6877881cd717244ff8520444c0
S: fb9fa790b29cafa1ff84c7a3173d806f72a2d4f3 192.168.0.170:6385
   slots: (0 slots) slave
   replicates fdaa13136f44c0be3139edfc2ef48eb00579caaf
S: 433118ba0840594c14716fba173a7895a3836662 192.168.0.170:6384
   slots: (0 slots) slave
   replicates ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
M: ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 192.168.0.170:6382
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

容错切换迁移:
1、主6381和从机切换,先停止6381节点(此时6381的从节点为6386)

[root@blog.tag.gg ~]# docker stop redis-node-1
redis-node-1
[root@blog.tag.gg ~]# docker ps -a
CONTAINER ID   IMAGE         COMMAND                  CREATED        STATUS                      PORTS     NAMES
ea1e315e6661   redis:6.0.8   "docker-entrypoint.s…"   25 hours ago   Up 25 hours                           redis-node-6
a2f50b8b242a   redis:6.0.8   "docker-entrypoint.s…"   25 hours ago   Up 25 hours                           redis-node-5
0ddf1b14abf5   redis:6.0.8   "docker-entrypoint.s…"   25 hours ago   Up 25 hours                           redis-node-4
a647cff0653d   redis:6.0.8   "docker-entrypoint.s…"   25 hours ago   Up 25 hours                           redis-node-3
1d342b9e7d0a   redis:6.0.8   "docker-entrypoint.s…"   25 hours ago   Up 25 hours                           redis-node-2
19f7c6d53b20   redis:6.0.8   "docker-entrypoint.s…"   25 hours ago   Exited (0) 12 seconds ago             redis-node-1

停止后随便进入一个容器,例如:redis-node-2 并连接redis集群

[root@blog.tag.gg ~]# docker exec -it redis-node-2 /bin/bash
root@blog.tag.gg:/data# redis-cli -p 6382 -c
127.0.0.1:6382> cluster nodes 再次查看进群信息。
433118ba0840594c14716fba173a7895a3836662 192.168.0.170:6384@16384 slave ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 0 1667056567481 2 connected
fdaa13136f44c0be3139edfc2ef48eb00579caaf 192.168.0.170:6383@16383 master - 0 1667056566000 3 connected 10923-16383
ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 192.168.0.170:6382@16382 myself,master - 0 1667056567000 2 connected 5461-10922
a7d3b130cd14ad6877881cd717244ff8520444c0 192.168.0.170:6381@16381 master,fail - 1667056454231 1667056450000 1 disconnected
fb9fa790b29cafa1ff84c7a3173d806f72a2d4f3 192.168.0.170:6385@16385 slave fdaa13136f44c0be3139edfc2ef48eb00579caaf 0 1667056566479 3 connected
b567fd9306230772798b02845296ad3948d3e1fa 192.168.0.170:6386@16386 master - 0 1667056565477 7 connected 0-5460

说明:
从上面信息可以看出6381原来是主节点,现在变成了“master,fail ”而“6386 ”原来是6381的从节点,现在变成了主节点。
此时已完成故障切换.
重新启动6381节点,看下状态

[root@blog.tag.gg ~]# docker exec -it redis-node-1 /bin/bash
root@blog.tag.gg:/data# redis-cli -p 6381 -c
127.0.0.1:6381> cluster nodes
433118ba0840594c14716fba173a7895a3836662 192.168.0.170:6384@16384 slave ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 0 1667057037443 2 connected
ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 192.168.0.170:6382@16382 master - 0 1667057036000 2 connected 5461-10922
fdaa13136f44c0be3139edfc2ef48eb00579caaf 192.168.0.170:6383@16383 master - 0 1667057037000 3 connected 10923-16383
a7d3b130cd14ad6877881cd717244ff8520444c0 192.168.0.170:6381@16381 myself,slave b567fd9306230772798b02845296ad3948d3e1fa 0 1667057035000 7 connected
b567fd9306230772798b02845296ad3948d3e1fa 192.168.0.170:6386@16386 master - 0 1667057034000 7 connected 0-5460
fb9fa790b29cafa1ff84c7a3173d806f72a2d4f3 192.168.0.170:6385@16385 slave fdaa13136f44c0be3139edfc2ef48eb00579caaf 0 1667057036000 3 connected

说明:
如果之前主节点死掉从节点上位后,即便在主节点恢复后,原来6381主节点变成了6386的从节点了,他们的身份交换了一下。
也就是说,主节点死掉恢复后会变成从节点。
问题:那么如何还原为之前的状态呢?也就是如何还原6381为主节点、6386为从节点??
答:将6386节点停止,此时6381会从从节点变成主节点,在启动6386节点,此时6386会变成从节点了,即可还原为第一次的架构。
主从扩容扩容案例:
两个方面:新增机器、重新分配哈希槽位
需求:目前是三主三从,扩容为四主四从:
新增两台机器(一主一从)

docker run -d --name redis-node-7 --net host --privileged=true -v /data/redis/share/redis-node-7:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387
docker run -d --name redis-node-8 --net host --privileged=true -v /data/redis/share/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388

进入redis-node-7这个节点

docker exec -it redis-node-7 /bin/bash

说明:
将新增的6387作为master节点加入集群
redis-cli --cluster add-node 自己实际IP地址:6387 自己实际IP地址:6381
6387 就是将要作为master新增节点
6381 就是原来集群节点里面的领路人,相当于6387拜拜6381的码头从而找到组织加入集群
命令:

redis-cli --cluster add-node 192.168.0.170:6387 192.168.0.170:6381

加入成功,执行后如下:

root@blog.ta.gg:/data# redis-cli --cluster add-node 192.168.0.170:6387 192.168.0.170:6381
>>> Adding node 192.168.0.170:6387 to cluster 192.168.0.170:6381
>>> Performing Cluster Check (using node 192.168.0.170:6381)
S: a7d3b130cd14ad6877881cd717244ff8520444c0 192.168.0.170:6381
   slots: (0 slots) slave
   replicates b567fd9306230772798b02845296ad3948d3e1fa
S: 433118ba0840594c14716fba173a7895a3836662 192.168.0.170:6384
   slots: (0 slots) slave
   replicates ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
M: ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 192.168.0.170:6382
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: fdaa13136f44c0be3139edfc2ef48eb00579caaf 192.168.0.170:6383
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
M: b567fd9306230772798b02845296ad3948d3e1fa 192.168.0.170:6386
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: fb9fa790b29cafa1ff84c7a3173d806f72a2d4f3 192.168.0.170:6385
   slots: (0 slots) slave
   replicates fdaa13136f44c0be3139edfc2ef48eb00579caaf
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Send CLUSTER MEET to node 192.168.0.170:6387 to make it join the cluster.
[OK] New node added correctly.

检查集群情况第一次:

redis-cli --cluster check 192.168.0.170:6381

执行后如下可以看到四个M主节点,但会显示没有槽位“ 0 keys | 0 slots | 0 slaves.

root@blog.tag.gg:/data# redis-cli --cluster check 192.168.0.170:6381
192.168.0.170:6382 (ca8b40b5...) -> 1 keys | 5462 slots | 1 slaves.
192.168.0.170:6383 (fdaa1313...) -> 1 keys | 5461 slots | 1 slaves.
192.168.0.170:6387 (f3825e0d...) -> 0 keys | 0 slots | 0 slaves.
192.168.0.170:6386 (b567fd93...) -> 2 keys | 5461 slots | 1 slaves.
[OK] 4 keys in 4 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 192.168.0.170:6381)
S: a7d3b130cd14ad6877881cd717244ff8520444c0 192.168.0.170:6381
   slots: (0 slots) slave
   replicates b567fd9306230772798b02845296ad3948d3e1fa
S: 433118ba0840594c14716fba173a7895a3836662 192.168.0.170:6384
   slots: (0 slots) slave
   replicates ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
M: ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 192.168.0.170:6382
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: fdaa13136f44c0be3139edfc2ef48eb00579caaf 192.168.0.170:6383
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
M: f3825e0d9e03fa0330207e47de958a81a2ec7a92 192.168.0.170:6387
   slots: (0 slots) master
M: b567fd9306230772798b02845296ad3948d3e1fa 192.168.0.170:6386
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: fb9fa790b29cafa1ff84c7a3173d806f72a2d4f3 192.168.0.170:6385
   slots: (0 slots) slave
   replicates fdaa13136f44c0be3139edfc2ef48eb00579caaf
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

重新分派槽号
命令:

redis-cli --cluster reshard IP地址:端口号

redis-cli --cluster reshard 192.168.0.170:6381

执行后如下:

root@blog.tag.gg:/data# redis-cli --cluster reshard 192.168.0.170:6381
>>> Performing Cluster Check (using node 192.168.0.170:6381)
S: a7d3b130cd14ad6877881cd717244ff8520444c0 192.168.0.170:6381
   slots: (0 slots) slave
   replicates b567fd9306230772798b02845296ad3948d3e1fa
S: 433118ba0840594c14716fba173a7895a3836662 192.168.0.170:6384
   slots: (0 slots) slave
   replicates ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
M: ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 192.168.0.170:6382
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: fdaa13136f44c0be3139edfc2ef48eb00579caaf 192.168.0.170:6383
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
M: f3825e0d9e03fa0330207e47de958a81a2ec7a92 192.168.0.170:6387
   slots: (0 slots) master
M: b567fd9306230772798b02845296ad3948d3e1fa 192.168.0.170:6386
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: fb9fa790b29cafa1ff84c7a3173d806f72a2d4f3 192.168.0.170:6385
   slots: (0 slots) slave
   replicates fdaa13136f44c0be3139edfc2ef48eb00579caaf
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)? 4096
What is the receiving node ID? f3825e0d9e03fa0330207e47de958a81a2ec7a92
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1: all

Ready to move 4096 slots.
  Source nodes:
    M: ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 192.168.0.170:6382
       slots:[5461-10922] (5462 slots) master
       1 additional replica(s)
    M: fdaa13136f44c0be3139edfc2ef48eb00579caaf 192.168.0.170:6383
       slots:[10923-16383] (5461 slots) master
       1 additional replica(s)
    M: b567fd9306230772798b02845296ad3948d3e1fa 192.168.0.170:6386
       slots:[0-5460] (5461 slots) master
       1 additional replica(s)
  Destination node:
    M: f3825e0d9e03fa0330207e47de958a81a2ec7a92 192.168.0.170:6387
       slots: (0 slots) master
  Resharding plan:
    Moving slot 5461 from ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
    Moving slot 5462 from ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
    Moving slot 5463 from ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
    Moving slot 5464 from ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
    Moving slot 5465 from ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
    Moving slot 5466 from ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
    Moving slot 5467 from ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
    Moving slot 5468 from ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
    Moving slot 5469 from ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
    Moving slot 5470 from ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a

解释:
How many slots do you want to move (from 1 to 16384)? 4096
问:为什么是4096个槽位?
答:目前四个主从,一共是16384个槽位,16384/4=4096表示每个主从分配 4096个槽位
What is the receiving node ID? f3825e0d9e03fa0330207e47de958a81a2ec7a92
问:这里的id是什么id?
答:是新增加的例如6387主节点id
Source node #1: all
问:all表示什么?
答:表示所有。

第二次查看分配情况:

redis-cli --cluster check 192.168.0.170:6381

显示如下:此时每个节点的槽位变了
注意:此时6387节点的哈希槽位是:[0-1364],[5461-6826],[10923-12287]  (一共是4096)三个区间,并且显示:0 slaves
为什么6387是3个新的区间,以前的还是连续?
重新分配成本太高,所以前3家各自匀出来一部分,从之前三个节点分别匀出1364个坑位给新节点6387
 

root@blog.tag.gg:/data# redis-cli --cluster check 192.168.0.170:6381
192.168.0.170:6382 (ca8b40b5...) -> 1 keys | 4096 slots | 1 slaves.
192.168.0.170:6383 (fdaa1313...) -> 1 keys | 4096 slots | 1 slaves.
192.168.0.170:6387 (f3825e0d...) -> 1 keys | 4096 slots | 0 slaves.
192.168.0.170:6386 (b567fd93...) -> 1 keys | 4096 slots | 1 slaves.
[OK] 4 keys in 4 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 192.168.0.170:6381)
S: a7d3b130cd14ad6877881cd717244ff8520444c0 192.168.0.170:6381
   slots: (0 slots) slave
   replicates b567fd9306230772798b02845296ad3948d3e1fa
S: 433118ba0840594c14716fba173a7895a3836662 192.168.0.170:6384
   slots: (0 slots) slave
   replicates ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
M: ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 192.168.0.170:6382
   slots:[6827-10922] (4096 slots) master
   1 additional replica(s)
M: fdaa13136f44c0be3139edfc2ef48eb00579caaf 192.168.0.170:6383
   slots:[12288-16383] (4096 slots) master
   1 additional replica(s)
M: f3825e0d9e03fa0330207e47de958a81a2ec7a92 192.168.0.170:6387
   slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master
M: b567fd9306230772798b02845296ad3948d3e1fa 192.168.0.170:6386
   slots:[1365-5460] (4096 slots) master
   1 additional replica(s)
S: fb9fa790b29cafa1ff84c7a3173d806f72a2d4f3 192.168.0.170:6385
   slots: (0 slots) slave
   replicates fdaa13136f44c0be3139edfc2ef48eb00579caaf
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

为6387主节点重新分配从节点6388:
命令格式:

redis-cli --cluster add-node ip:新slave端口 ip:新master端口 --cluster-slave --cluster-master-id 新主机节点ID

执行如下命令:

redis-cli --cluster add-node 192.168.0.170:6388 192.168.0.170:6387 --cluster-slave --cluster-master-id f3825e0d9e03fa0330207e47de958a81a2ec7a92

说明:新主机节点ID:这个是6387的编号,按照自己实际情况
执行后如下:

root@blog.tag.gg:/data# redis-cli --cluster add-node 192.168.0.170:6388 192.168.0.170:6387 --cluster-slave --cluster-master-id f3825e0d9e03fa0330207e47de958a81a2ec7a92
>>> Adding node 192.168.0.170:6388 to cluster 192.168.0.170:6387
>>> Performing Cluster Check (using node 192.168.0.170:6387)
M: f3825e0d9e03fa0330207e47de958a81a2ec7a92 192.168.0.170:6387
   slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master
M: b567fd9306230772798b02845296ad3948d3e1fa 192.168.0.170:6386
   slots:[1365-5460] (4096 slots) master
   1 additional replica(s)
S: 433118ba0840594c14716fba173a7895a3836662 192.168.0.170:6384
   slots: (0 slots) slave
   replicates ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
S: a7d3b130cd14ad6877881cd717244ff8520444c0 192.168.0.170:6381
   slots: (0 slots) slave
   replicates b567fd9306230772798b02845296ad3948d3e1fa
M: ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 192.168.0.170:6382
   slots:[6827-10922] (4096 slots) master
   1 additional replica(s)
S: fb9fa790b29cafa1ff84c7a3173d806f72a2d4f3 192.168.0.170:6385
   slots: (0 slots) slave
   replicates fdaa13136f44c0be3139edfc2ef48eb00579caaf
M: fdaa13136f44c0be3139edfc2ef48eb00579caaf 192.168.0.170:6383
   slots:[12288-16383] (4096 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Send CLUSTER MEET to node 192.168.0.170:6388 to make it join the cluster.
Waiting for the cluster to join

>>> Configure node as replica of 192.168.0.170:6387.
[OK] New node added correctly.

再次检测集群情况:

redis-cli --cluster check 192.168.0.170:6381

如下,现在看每个节点都正常了,现在是四主四从集群了

root@blog.tag.gg:/data# redis-cli --cluster check 192.168.0.170:6381
192.168.0.170:6382 (ca8b40b5...) -> 1 keys | 4096 slots | 1 slaves.
192.168.0.170:6383 (fdaa1313...) -> 1 keys | 4096 slots | 1 slaves.
192.168.0.170:6387 (f3825e0d...) -> 1 keys | 4096 slots | 1 slaves.
192.168.0.170:6386 (b567fd93...) -> 1 keys | 4096 slots | 1 slaves.
[OK] 4 keys in 4 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 192.168.0.170:6381)
S: a7d3b130cd14ad6877881cd717244ff8520444c0 192.168.0.170:6381
   slots: (0 slots) slave
   replicates b567fd9306230772798b02845296ad3948d3e1fa
S: 433118ba0840594c14716fba173a7895a3836662 192.168.0.170:6384
   slots: (0 slots) slave
   replicates ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
M: ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 192.168.0.170:6382
   slots:[6827-10922] (4096 slots) master
   1 additional replica(s)
M: fdaa13136f44c0be3139edfc2ef48eb00579caaf 192.168.0.170:6383
   slots:[12288-16383] (4096 slots) master
   1 additional replica(s)
S: 81b45f21ca7d758112aeed4ef7e0343b7e312362 192.168.0.170:6388
   slots: (0 slots) slave
   replicates f3825e0d9e03fa0330207e47de958a81a2ec7a92
M: f3825e0d9e03fa0330207e47de958a81a2ec7a92 192.168.0.170:6387
   slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master
   1 additional replica(s)
M: b567fd9306230772798b02845296ad3948d3e1fa 192.168.0.170:6386
   slots:[1365-5460] (4096 slots) master
   1 additional replica(s)
S: fb9fa790b29cafa1ff84c7a3173d806f72a2d4f3 192.168.0.170:6385
   slots: (0 slots) slave
   replicates fdaa13136f44c0be3139edfc2ef48eb00579caaf
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

主从缩容案例
需求:访问量下去了,需要恢复到原来的三主三从,将6387和6388主从释放掉,需先删除从再删除主
1、检查集群节点情况,获取6388的节点ID

redis-cli --cluster check 192.168.0.170:6382

检查情况如下:

[root@blog-tag-gg ~]# docker exec -it redis-node-2 /bin/bash
root@hecs-76160:/data# redis-cli --cluster check 192.168.0.170:6382
192.168.0.170:6382 (ca8b40b5...) -> 1 keys | 4096 slots | 1 slaves.
192.168.0.170:6383 (fdaa1313...) -> 1 keys | 4096 slots | 1 slaves.
192.168.0.170:6387 (f3825e0d...) -> 1 keys | 4096 slots | 1 slaves.
192.168.0.170:6386 (b567fd93...) -> 1 keys | 4096 slots | 1 slaves.
[OK] 4 keys in 4 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 192.168.0.170:6382)
M: ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 192.168.0.170:6382
   slots:[6827-10922] (4096 slots) master
   1 additional replica(s)
S: 433118ba0840594c14716fba173a7895a3836662 192.168.0.170:6384
   slots: (0 slots) slave
   replicates ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
M: fdaa13136f44c0be3139edfc2ef48eb00579caaf 192.168.0.170:6383
   slots:[12288-16383] (4096 slots) master
   1 additional replica(s)
M: f3825e0d9e03fa0330207e47de958a81a2ec7a92 192.168.0.170:6387
   slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master
   1 additional replica(s)
S: a7d3b130cd14ad6877881cd717244ff8520444c0 192.168.0.170:6381
   slots: (0 slots) slave
   replicates b567fd9306230772798b02845296ad3948d3e1fa
S: fb9fa790b29cafa1ff84c7a3173d806f72a2d4f3 192.168.0.170:6385
   slots: (0 slots) slave
   replicates fdaa13136f44c0be3139edfc2ef48eb00579caaf
M: b567fd9306230772798b02845296ad3948d3e1fa 192.168.0.170:6386
   slots:[1365-5460] (4096 slots) master
   1 additional replica(s)
S: 81b45f21ca7d758112aeed4ef7e0343b7e312362 192.168.0.170:6388
   slots: (0 slots) slave
   replicates f3825e0d9e03fa0330207e47de958a81a2ec7a92
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

2、从集群中4号从节点删除6388(先删从在删主)
命令格式:

redis-cli --cluster del-node ip:从机端口 从机6388节点ID

 完整命令:

redis-cli --cluster del-node 192.168.0.170:6388 81b45f21ca7d758112aeed4ef7e0343b7e312362

执行后返回:删除成功。

root@blog.tag.gg:/data# redis-cli --cluster del-node 192.168.0.170:6388 81b45f21ca7d758112aeed4ef7e0343b7e312362
>>> Removing node 81b45f21ca7d758112aeed4ef7e0343b7e312362 from cluster 192.168.0.170:6388
>>> Sending CLUSTER FORGET messages to the cluster...
>>> Sending CLUSTER RESET SOFT to the deleted node.

再执行命令:

redis-cli --cluster check 192.168.0.170:6382

从返回的节点信息看只有三个S从节点了。
3、将6387的哈希槽号清空,重新分配,本利是将清出来的槽号以6381节点为入口将槽号重新分配给其他所有集群节点。

redis-cli --cluster reshard 192.168.0.170:6381

执行上面命令后会提示:

How many slots do you want to move (from 1 to 16384)? 4096(输入4096)
解释:意思是您想移动多少个槽号?因为之前我们6387是4096个槽点,那么这里就输入4096回车即可。
What is the receiving node ID? ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
解释:哪一个节点来接收已删除的槽点?比如我们这里想放到6382节点,则输入6382的节点ID (注意:接收的节点必须是主节点)
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1:f3825e0d9e03fa0330207e47de958a81a2ec7a92
Source node #2:done

解释:Source node #1:要删除的节点ID,我们要删除6387 则输入6387的节点id
解释:done表示所有节点
执行后会自动删除
再次查看节点情况:

root@blog.tag.gg:/data# redis-cli --cluster check 192.168.0.170:6382
192.168.0.170:6382 (ca8b40b5...) -> 2 keys | 8192 slots | 1 slaves.
192.168.0.170:6383 (fdaa1313...) -> 1 keys | 4096 slots | 1 slaves.
192.168.0.170:6387 (f3825e0d...) -> 0 keys | 0 slots | 0 slaves.
192.168.0.170:6386 (b567fd93...) -> 1 keys | 4096 slots | 1 slaves.
[OK] 4 keys in 4 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 192.168.0.170:6382)
M: ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 192.168.0.170:6382
   slots:[0-1364],[5461-12287] (8192 slots) master
   1 additional replica(s)
S: 433118ba0840594c14716fba173a7895a3836662 192.168.0.170:6384
   slots: (0 slots) slave
   replicates ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
M: fdaa13136f44c0be3139edfc2ef48eb00579caaf 192.168.0.170:6383
   slots:[12288-16383] (4096 slots) master
   1 additional replica(s)
M: f3825e0d9e03fa0330207e47de958a81a2ec7a92 192.168.0.170:6387
   slots: (0 slots) master
S: a7d3b130cd14ad6877881cd717244ff8520444c0 192.168.0.170:6381
   slots: (0 slots) slave
   replicates b567fd9306230772798b02845296ad3948d3e1fa
S: fb9fa790b29cafa1ff84c7a3173d806f72a2d4f3 192.168.0.170:6385
   slots: (0 slots) slave
   replicates fdaa13136f44c0be3139edfc2ef48eb00579caaf
M: b567fd9306230772798b02845296ad3948d3e1fa 192.168.0.170:6386
   slots:[1365-5460] (4096 slots) master
   1 additional replica(s)
[ERR] Nodes don't agree about configuration!
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

说明:
1、目前查看6387节点还存在,但槽点显示为0:0 keys | 0 slots | 0 slaves
2、之前将槽点转交给了6382,所以该节点会显示:8192 slots ,4096个槽位都指给6382,它变成了8192个槽位,相当于全部都给6382了
4、将6387删除:
命令格式:

redis-cli --cluster del-node ip:端口 6387节点ID

完整命令:

redis-cli --cluster del-node 192.168.0.170:6387 f3825e0d9e03fa0330207e47de958a81a2ec7a92

显示如下:删除成功。

root@blog.tag.gg:/data# redis-cli --cluster del-node 192.168.0.170:6387 f3825e0d9e03fa0330207e47de958a81a2ec7a92
>>> Removing node f3825e0d9e03fa0330207e47de958a81a2ec7a92 from cluster 192.168.0.170:6387
>>> Sending CLUSTER FORGET messages to the cluster...
>>> Sending CLUSTER RESET SOFT to the deleted node.

5、再执行如下命令看下节点情况

redis-cli --cluster check 192.168.0.170:6382

会显示如下:恢复到了原来的三主三从

root@blog.tag.gg:/data# redis-cli --cluster check 192.168.0.170:6382
192.168.0.170:6382 (ca8b40b5...) -> 2 keys | 8192 slots | 1 slaves.
192.168.0.170:6383 (fdaa1313...) -> 1 keys | 4096 slots | 1 slaves.
192.168.0.170:6386 (b567fd93...) -> 1 keys | 4096 slots | 1 slaves.
[OK] 4 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 192.168.0.170:6382)
M: ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a 192.168.0.170:6382
   slots:[0-1364],[5461-12287] (8192 slots) master
   1 additional replica(s)
S: 433118ba0840594c14716fba173a7895a3836662 192.168.0.170:6384
   slots: (0 slots) slave
   replicates ca8b40b5ae55c32210d783b0f0cdf0965bcd5b8a
M: fdaa13136f44c0be3139edfc2ef48eb00579caaf 192.168.0.170:6383
   slots:[12288-16383] (4096 slots) master
   1 additional replica(s)
S: a7d3b130cd14ad6877881cd717244ff8520444c0 192.168.0.170:6381
   slots: (0 slots) slave
   replicates b567fd9306230772798b02845296ad3948d3e1fa
S: fb9fa790b29cafa1ff84c7a3173d806f72a2d4f3 192.168.0.170:6385
   slots: (0 slots) slave
   replicates fdaa13136f44c0be3139edfc2ef48eb00579caaf
M: b567fd9306230772798b02845296ad3948d3e1fa 192.168.0.170:6386
   slots:[1365-5460] (4096 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.


DockerFile知识介绍
1、什么是DockerFile:
DockerFile是用来构建docker镜像的文本文件,是由多条构建镜像所需的指令集构成的脚本,类似于shell脚本。
DockerFile官方文档说明:https://docs.docker.com/engine/reference/builder/
2、DockerFile构建三部曲:
  1. 编写DockerFile文件规则
  2. Docker build命令构建镜像
  3. Docker run用镜像运行容器
3、DockerFlile必要知识:
  1. 每条保留命令(关键字)都必须为大写字母,且后面至少要跟随一个参数。
  2. 什么是保留命令:例如:FROM、RUN、CMD、ENV、ADD、COPY等,更多保留命令可以看官方文档。
  3. 指令是从上到下依次执行。
  4. #表示注释,与linux配置文件一样。
  5. 每条指令都会创建一个新的镜像层进行提交。
4、Docker中执行DockerFile的流程:
  1. Docker从基础镜像中运行一个容器
  2. 执行一条命令并对容器做出修改
  3. 执行类似docker commit的操作提交一个新的镜像层
  4. docker再基于刚提交的镜像运行一个新的容器
  5. 执行dockerfile中的下一条命令知道所有命令都执行完成
总结:


从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,
*  Dockerfile是软件的原材料
*  Docker镜像是软件的交付品
*  Docker容器则可以认为是软件镜像的运行态,也即依照镜像运行的容器实例
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。
graphic
1 Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
2 Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时会真正开始提供服务;
3 Docker容器,容器是直接提供服务的。
DockerFile常用的指令介绍:
DockerFile范例可参考:https://github.com/docker-library/tomcat/blob/master/10.0/jdk8/corretto-al2/Dockerfile或如下:
1、DockerFile范例:

#
# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh"
#
# PLEASE DO NOT EDIT IT DIRECTLY.
#

FROM amazoncorretto:8-al2-jdk

ENV CATALINA_HOME /usr/local/tomcat
ENV PATH $CATALINA_HOME/bin:$PATH
RUN mkdir -p "$CATALINA_HOME"
WORKDIR $CATALINA_HOME

# let "Tomcat Native" live somewhere isolated
ENV TOMCAT_NATIVE_LIBDIR $CATALINA_HOME/native-jni-lib
ENV LD_LIBRARY_PATH ${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$TOMCAT_NATIVE_LIBDIR

# see https://www.apache.org/dist/tomcat/tomcat-10/KEYS
# see also "versions.sh" (https://github.com/docker-library/tomcat/blob/master/versions.sh)
ENV GPG_KEYS A9C5DF4D22E99998D9875A5110C01C5A2F6059E7

ENV TOMCAT_MAJOR 10
ENV TOMCAT_VERSION 10.0.27
ENV TOMCAT_SHA512 33c51be9410eaa0ce1393f8ce80a42a9639b68c7b7af1e9e642045614c170a12f8841ce4142933d1f4d18ba7efc85c630f91c312e959dcdc64aae396c46bdd97

RUN set -eux; \
    \
# http://yum.baseurl.org/wiki/YumDB.html
    if ! command -v yumdb > /dev/null; then \
        yum install -y --setopt=skip_missing_names_on_install=False yum-utils; \
        yumdb set reason dep yum-utils; \
    fi; \
# a helper function to "yum install" things, but only if they aren't installed (and to set their "reason" to "dep" so "yum autoremove" can purge them for us)
    _yum_install_temporary() { ( set -eu +x; \
        local pkg todo=''; \
        for pkg; do \
            if ! rpm --query "$pkg" > /dev/null 2>&1; then \
                todo="$todo $pkg"; \
            fi; \
        done; \
        if [ -n "$todo" ]; then \
            set -x; \
            yum install -y --setopt=skip_missing_names_on_install=False $todo; \
            yumdb set reason dep $todo; \
        fi; \
    ) }; \
    _yum_install_temporary gzip tar; \
    \
    ddist() { \
        local f="$1"; shift; \
        local distFile="$1"; shift; \
        local mvnFile="${1:-}"; \
        local success=; \
        local distUrl=; \
        for distUrl in \
# https://issues.apache.org/jira/browse/INFRA-8753?focusedCommentId=14735394#comment-14735394
            "https://www.apache.org/dyn/closer.cgi?action=download&filename=$distFile" \
# if the version is outdated (or we're grabbing the .asc file), we might have to pull from the dist/archive :/
            "https://downloads.apache.org/$distFile" \
            "https://www-us.apache.org/dist/$distFile" \
            "https://www.apache.org/dist/$distFile" \
            "https://archive.apache.org/dist/$distFile" \
# if all else fails, let's try Maven (https://www.mail-archive.com/users@tomcat.apache.org/msg134940.html; https://mvnrepository.com/artifact/org.apache.tomcat/tomcat; https://repo1.maven.org/maven2/org/apache/tomcat/tomcat/)
            ${mvnFile:+"https://repo1.maven.org/maven2/org/apache/tomcat/tomcat/$mvnFile"} \
        ; do \
            if curl -fL -o "$f" "$distUrl" && [ -s "$f" ]; then \
                success=1; \
                break; \
            fi; \
        done; \
        [ -n "$success" ]; \
    }; \
    \
    ddist 'tomcat.tar.gz' "tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz" "$TOMCAT_VERSION/tomcat-$TOMCAT_VERSION.tar.gz"; \
    echo "$TOMCAT_SHA512 *tomcat.tar.gz" | sha512sum --strict --check -; \
    ddist 'tomcat.tar.gz.asc' "tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz.asc" "$TOMCAT_VERSION/tomcat-$TOMCAT_VERSION.tar.gz.asc"; \
    export GNUPGHOME="$(mktemp -d)"; \
    for key in $GPG_KEYS; do \
        gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key"; \
    done; \
    gpg --batch --verify tomcat.tar.gz.asc tomcat.tar.gz; \
    tar -xf tomcat.tar.gz --strip-components=1; \
    rm bin/*.bat; \
    rm tomcat.tar.gz*; \
    command -v gpgconf && gpgconf --kill all || :; \
    rm -rf "$GNUPGHOME"; \
    \
# https://tomcat.apache.org/tomcat-9.0-doc/security-howto.html#Default_web_applications
    mv webapps webapps.dist; \
    mkdir webapps; \
# we don't delete them completely because they're frankly a pain to get back for users who do want them, and they're generally tiny (~7MB)
    \
    nativeBuildDir="$(mktemp -d)"; \
    tar -xf bin/tomcat-native.tar.gz -C "$nativeBuildDir" --strip-components=1; \
    _yum_install_temporary \
        apr-devel \
        gcc \
        make \
        openssl11-devel \
    ; \
    ( \
        export CATALINA_HOME="$PWD"; \
        cd "$nativeBuildDir/native"; \
        aprConfig="$(command -v apr-1-config)"; \
        ./configure \
            --libdir="$TOMCAT_NATIVE_LIBDIR" \
            --prefix="$CATALINA_HOME" \
            --with-apr="$aprConfig" \
            --with-java-home="$JAVA_HOME" \
            --with-ssl \
        ; \
        nproc="$(nproc)"; \
        make -j "$nproc"; \
        make install; \
    ); \
    rm -rf "$nativeBuildDir"; \
    rm bin/tomcat-native.tar.gz; \
    \
# mark any explicit dependencies as manually installed
    find "$TOMCAT_NATIVE_LIBDIR" -type f -executable -exec ldd '{}' ';' \
        | awk '/=>/ && $(NF-1) != "=>" { print $(NF-1) }' \
        | xargs -rt readlink -e \
        | sort -u \
        | xargs -rt rpm --query --whatprovides \
        | sort -u \
        | tee "$TOMCAT_NATIVE_LIBDIR/.dependencies.txt" \
        | xargs -r yumdb set reason user \
    ; \
    \
# clean up anything added temporarily and not later marked as necessary
    yum autoremove -y; \
    yum clean all; \
    rm -rf /var/cache/yum; \
    \
# sh removes env vars it doesn't support (ones with periods)
# https://github.com/docker-library/tomcat/issues/77
    find ./bin/ -name '*.sh' -exec sed -ri 's|^#!/bin/sh$|#!/usr/bin/env bash|' '{}' +; \
    \
# fix permissions (especially for running as non-root)
# https://github.com/docker-library/tomcat/issues/35
    chmod -R +rX .; \
    chmod 777 logs temp work; \
    \
# smoke test
    catalina.sh version

# verify Tomcat Native is working properly
RUN set -eux; \
    nativeLines="$(catalina.sh configtest 2>&1)"; \
    nativeLines="$(echo "$nativeLines" | grep 'Apache Tomcat Native')"; \
    nativeLines="$(echo "$nativeLines" | sort -u)"; \
    if ! echo "$nativeLines" | grep -E 'INFO: Loaded( APR based)? Apache Tomcat Native library' >&2; then \
        echo >&2 "$nativeLines"; \
        exit 1; \
    fi

EXPOSE 8080
CMD ["catalina.sh", "run"]

2、DockerFile常见指令说明:
  • FROM:基础镜像,当前镜像是基于哪一个镜像创建的,指定一个已经存在的镜像作为模板,dockerfile第一条必须是FROM,格式:FROM amazoncorretto:8-al2-jdk
  • MAINTAINER:作者或者维护者,一般是维护者的姓名或邮箱,格式:MAINTAINER <name>
  • RUN:容器构建时需要执行的命令,一般两种格式:1、shell格式:RUN yum -y install vim   2、exec格式:RUN ["可执行文件","参数1","参数2"]   RUN [".test.php","dev","offline"] 等价于 RUN .test.php dev offline 。RUN命令是在docker build构建时运行。
  • EXPOSE:当前容器对外暴露出的端口。
  • WORKDIR:执行在创建容器后,终端默认登录进来的工作目录,一个落脚点,也就是进入容器后默认的目录。
  • USER:执行该镜像以什么样的用户去执行,若都不指定,则默认是root。
  • ENV:用来在构建镜像过程中设置环境变量。
  • ADD:将宿主目录下的文件拷贝到镜像且会自动处理RUL和解压tar压缩包。(相当于copy复制+解压操作,相比用得多)
  • COPY:类似ADD,拷贝文件和目录到镜像中。类似于docker cp命令。
  • VOLUME:容器卷
  • CMD:指定容器启动后要做的操作,可以有多个CMD指令,只有最后一个生效。CMD会被docker run之后的参数替换。
  • ENTRYPOINT:也是用来指定一个容器启动时要运行的命令,类似于CMD命令,但ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令参数会被当做参数传给ENTRYPOINT指令指定的程序。可以结合CMD命令运行,格式:ENTRYPOINT "CMD命令"例如:ENTRYPOINT ["nginx","-c"] #定参     CMD ["/etc/nginx/nginx.conf] #变参   变成:nginx -c /etc/nginx/nginx.conf
关于CMD命令详细说明:
以上面tomcat镜像为例:
执行

docker run -it -p 8080:8080 2d2bccf89f53

或者

docker run -itd -p 8080:8080 2d2bccf89f53

可以监听8080且容器也会启动8080,外部能访问8080(d参数是后台运行,不加d则是前台运行,终端关闭后结束运行)
但执行如下命令后端口有监听,但8080端口不通,宿主有8080监听,但容器里面不会有8080监听。

docker run -itd -p 8080:8080 2d2bccf89f53 /bin/bash

为什么加上 /bin/bash 后端口不通?原因如下:
1、执行docker run命令后 最后会执行 CMD ["catalina.sh", "run"] 这个命令,这个命令表示会启动容器里面的这个脚本,脚本是启动tomcat服务的。
2、若加上/bin/bash参数后则变为如下执行顺序
CMD ["catalina.sh", "run"]
CMD ["/bin/bash", "run"]
只会有最后一个CMD命令才会生效,会覆盖原来CMD ["catalina.sh", "run"] ,也就说,镜像拉起容器后执行了CMD ["/bin/bash", "run"]  不会执行sh脚本,所以容器里面不会有tomcat服务启动,端口不会监听
解决方法:
1、在拉起容器时不加/bin/bash
2、进入容器手动执行catalina.sh脚本启动tomcat服务即可。
通过DockerFile构建一个自己需要的镜像:
需求:对默认的centos镜像增加四个功能
  • 1、具备vim编辑命令。
  • 2、安装ifconfig命令
  • 3、安装好jdk8环境
  • 4、安装好ip这个命令
编写、构建、运行
1、编写DockerFile文件:D字母必须大写
 进入某个目录,例如 /blogtest/ 在这个目录下载jdk文件,下载地址:https://mirrors.yangxingzhen.com/jdk/jdk-8u171-linux-x64.tar.gz

cd /blogtest/
wget https://mirrors.yangxingzhen.com/jdk/jdk-8u171-linux-x64.tar.gz

执行vi DockerFile编辑文件写入如下代码

FROM centos:7
MAINTAINER yangmazi<blog.tag.gg>
 
ENV MYPATH /usr/local
WORKDIR $MYPATH
 
#安装vim编辑器
RUN yum -y install vim
#安装ifconfig命令查看网络IP
RUN yum -y install net-tools
#安装ip命令
RUN yum -y install iproute2
#安装java8及lib库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java

#ADD 是相对路径jar,把jdk-8u171-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_171
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH
 
EXPOSE 80
 
CMD echo $MYPATH
CMD echo "success--------------ok成功"
CMD /bin/bash

2、构建镜像
格式:

docker build -t 新镜像名字:tag .

范例:(有个点号,表示当前目录)

docker build -t centos_test:6.6 .

在dockerfile文件当前目录执行命令,结果如下表示安装成功

 ---> c3250c024505
Step 8/17 : RUN mkdir /usr/local/java
 ---> Running in 968d01b0469e
Removing intermediate container 968d01b0469e
 ---> 39b28e0fda93
Step 9/17 : ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/
 ---> 3c33d055d513
Step 10/17 : ENV JAVA_HOME /usr/local/java/jdk1.8.0_171
 ---> Running in bedd48f73cff
Removing intermediate container bedd48f73cff
 ---> f691fa41c364
Step 11/17 : ENV JRE_HOME $JAVA_HOME/jre
 ---> Running in b6a311b74590
Removing intermediate container b6a311b74590
 ---> bee962f68fac
Step 12/17 : ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
 ---> Running in aafdcb488c92
Removing intermediate container aafdcb488c92
 ---> e4e1c8202e87
Step 13/17 : ENV PATH $JAVA_HOME/bin:$PATH
 ---> Running in d53b2970bb69
Removing intermediate container d53b2970bb69
 ---> 6a1af3e50711
Step 14/17 : EXPOSE 80
 ---> Running in ec013a2776e5
Removing intermediate container ec013a2776e5
 ---> 8e69a03ff5ba
Step 15/17 : CMD echo $MYPATH
 ---> Running in 1e449e712ef6
Removing intermediate container 1e449e712ef6
 ---> 5f5b196abbf6
Step 16/17 : CMD echo "success--------------ok"
 ---> Running in eefc77bd928b
Removing intermediate container eefc77bd928b
 ---> 5e4cde2bfc4b
Step 17/17 : CMD /bin/bash
 ---> Running in 62da6abd873a
Removing intermediate container 62da6abd873a
 ---> abadc0f24536
Successfully built abadc0f24536
Successfully tagged centos_test:6.6

[root@blog-tag-gg blogtest]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
centos_test   6.6       abadc0f24536   9 seconds ago   1.24GB


虚悬镜像:
什么是虚悬镜像:进项是none标签的是虚悬镜像
虚悬镜像是怎样产生的:安装镜像或操作镜像出现异常。
虚悬镜像已经失去了存在价值,可以删除。
删除虚悬镜像命令:

docker images ls -f dangling=true


Docker网络:
1、查看docker网络

docker network ls

显示:(常用是前两种)

[root@blog-tag-gg ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
040d7bd470aa   bridge    bridge    local
258ddf6a447a   host      host      local
5c74c7287431   none      null      local

2、创建一个网络

docker network create test_network

查询结果:

[root@blog-tag-gg ~]# docker network ls
NETWORK ID     NAME           DRIVER    SCOPE
040d7bd470aa   bridge         bridge    local
258ddf6a447a   host           host      local
5c74c7287431   none           null      local
61ef3f4e29b9   test_network   bridge    local

3、删除一个网络

docker network rm test_network  

4、查看网络:

docker network inspect test_network  

Docker网络能干什么?
  1. 容器间的互联和通信以及端口映射
  2. 容器IP变动时候可以通过服务名直接网络通信而不受到影响
  • bridge:为每一个容器分配、设置IP等,并将容器连接到一个docker0(虚拟网桥,默认为该模式)
  • host:容器将不会虚拟出自己的网卡,配置自己的ip等,而是使用宿主的ip和端口
  • none:容器有独立的network namespace,但并没有堆起进行任何网络设置,如分配veth pait和网桥连连接,ip等。
  • container:新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP,端口范围等。
  • bridge模式:使用--network bridge 指定,默认使用docker0
  • host模式:使用--network host指定
  • none模式:使用--network none指定
  • container模式:使用--network container:NAME或容器ID指定。
注意: 默认情况下docker容器内部的ip是有可能会发生改变的,如果ip变化了,调用的服务也会变化,这种情况就需要用网络模式调用。

bridge网络:
1、bridge是什么?
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
# 查看 bridge 网络的详细信息,并通过 grep 获取名称项

docker network inspect bridge | grep name

2、案例:
每个容器内部都有自己的网卡比如eth0,该网卡与宿主ip addr命令看到的是一一对应的。宿主显示:veth
例如在容器中执行 ip addr显示如下:

root@d985c2bc9055:/# 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
7: eth0@if8: <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 addr 如下

[root@blog-tag-gg ~]# ip addr |tail -n 4
8: veth214ece3@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
    link/ether f2:86:42:12:e5:5a brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::f086:42ff:fe12:e55a/64 scope link
       valid_lft forever preferred_lft forever

Host网络:
1、什么是host网络
  • 直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。
  • 容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。
2、案例警告:

docker run -d -p 8083:8080 --network host --name tomcat83 billygoo/tomcat8-jdk8

[root@blog-tag-gg ~]# docker run -d -p 8083:8080 --network host --name tomcat83 billygoo/tomcat8-jdk8
WARNING: Published ports are discarded when using host network mode
86dbd86804b08b8e155c0cc2db82960a370d5ea5d1b308e3fa3fe79fdeb2f432

注意:执行命令后会出现“WARNING: Published ports are discarded when using host network mode”这个只是一个警告对使用没影响。
问题:
     docke启动时总是遇见标题中的警告
原因:
    docker启动时指定--network=host或-net=host,如果还指定了-p映射端口,那这个时候就会有此警告,
并且通过-p设置的参数将不会起到任何作用,端口号会以主机端口号为主,重复时则递增。

解决:
    解决的办法就是使用docker的其他网络模式,例如--network=bridge,这样就可以解决问题,或者直接无视。
正确的执行方法

docker run -d --network host --name tomcat83 billygoo/tomcat8-jdk8

将端口映射去掉即可,此时可以使用 docker inspect 容器名查看网络模式会显示host
none网络:
1、什么是none网络
禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)(很少用)
在none模式下,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo,需要我们自己为Docker容器添加网卡、配置IP等。
2、案例:

docker run -d -p 8084:8080 --network none --name blogtaggg tomcat

none网络模式下容器内部没有网络,也无法使用命令安装任何业务
如何修改docker容器已运行实例端口等配置文件信息
1、建议将容器停止,进入 /var/lib/docker/containers/XXXXXX 对应容器目录
2、打开该容器文件夹下config.v2.json文件和hostconfig.json文件,进行修改(修改前建议复制备份一份,防止改错)
3、修改完成后在启动容器。
container网络:
新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
案例1:
1、坑:
先运行一个容器tomcat85

docker run -d -p 8085:8080  --name tomcat85 tomcat

再运行一个容器 tomcat86共用tomcat85的网络。

docker run -d -p 8086:8080 --network container:tomcat85  --name tomcat86 tomcat

执行后会提示

[root@blog-tag-gg /]# docker run -d -p 8085:8080  --name tomcat85 tomcat
[root@blog-tag-gg /]# docker run -d -p 8086:8080 --network container:tomcat85  --name tomcat86 tomcat
docker: Error response from daemon: conflicting options: port publishing and the container type network mode.
See 'docker run --help'.

有报错,原因是:相当于tomcat86和tomcat85公用同一个ip同一个端口,导致端口冲突,则说明当前镜像不用于container网络模式。
案例2(正确演示)
可以换个其他镜像演示:
Alpine Linux 是一款独立的、非商业的通用 Linux 发行版,专为追求安全性、简单性和资源效率的用户而设计。 可能很多人没听说过这个 Linux 发行版本,但是经常用 Docker 的朋友可能都用过,因为他小,简单,安全而著称,所以作为基础镜像是非常好的一个选择,可谓是麻雀虽小但五脏俱全,镜像非常小巧,不到 6M的大小,所以特别适合容器打包。

docker pull alpine

1、拉起alpine第一个容器:

docker run -it  --name alpine1  alpine /bin/sh

2、拉起第二个容器并设置共用第一个容器的网络

docker run -it --network container:alpine1 --name alpine2  alpine /bin/sh

3、验证:分别登录容器执行命令 ip addr 命令可以看到网络都是一样的。
4、注意:将alpine1 停止或删除后 alpine2  的网卡设置也将消失还原到none状态。
自定义网络:
什么是link:dokcer官方在新版本中已删除了这个存在,可以忽略了
1、为什么要使用自定义网络?
答:默认启动的docker是bridge网络模式,相同网络模式下的容器用ip能ping通,但ip地址是不固定的,容器停止或者再次启动重新创建ip地址会变化,如果ip变化了您的业务也无法访问另一个容器数据,同时此时ping容器名(服务名)—相互之间也无法ping通的。
自定义网络:
1、自定义桥接网络,自定义网络默认使用的是桥接网络bridge
2、新建自定义网络

docker network create blog_tag_gg_network_Test

查看网络情况:

[root@blog-tag-gg /]# docker network ls
NETWORK ID     NAME                       DRIVER    SCOPE
f1404287fa8a   blog_tag_gg_network_Test   bridge    local
040d7bd470aa   bridge                     bridge    local
258ddf6a447a   host                       host      local
5c74c7287431   none                       null      local
61ef3f4e29b9   test_network               bridge    local

3、新建容器加入新建的自定义网络

docker run -d -p 8081:8080 --network blog_tag_gg_network_Test  --name tomcat81 tomcat
docker run -d -p 8082:8080 --network blog_tag_gg_network_Test  --name tomcat82 tomcat

届时分别进入两个容器ping tomcat82  或者 ping tomcat81 可以ping通的。
自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)
提醒:生产场景下,不建议写死ip,建议写在同一个网络下的服务名。
Docker-Compose容器编排
1、什么是Compose容器编排?
答:Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器。
2、Compose容器编排能干什么?
答:docker建议我们每一个容器中只运行一个服务,因为docker容器本身占用资源极少,所以最好是将每个服务单独的分割开来但是这样我们又面临了一个问题?
如果我需要同时部署好多个服务,难道要每个服务单独写Dockerfile然后在构建镜像,构建容器,这样累都累死了,所以docker官方给我们提供了docker-compose多服务部署的工具
例如要实现一个Web微服务项目,除了Web服务容器本身,往往还需要再加上后端的数据库mysql服务容器,redis服务器,注册中心eureka,甚至还包括负载均衡容器等等。。。。。。
Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose 解决了容器与容器之间如何管理编排的问题。
3、怎样安装Compose?
官网地址:https://docs.docker.com/compose/compose-file/compose-file-v3/
官网下载地址:https://docs.docker.com/compose/install/

DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
mkdir -p $DOCKER_CONFIG/cli-plugins
curl -SL https://github.com/docker/compose/releases/download/v2.12.2/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose

chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose

对所有用户有效
sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose

查看是否安装成功,查看版本

docker compose version

卸载Compose:

rm $DOCKER_CONFIG/cli-plugins/docker-compose


卸载所有用户下的compose组件。

rm /usr/local/lib/docker/cli-plugins/docker-compose


Compose核心概念:
1、一个文件:docker-compose.yml
2、两个要素
  • 服务:一个个应用容器实例,比如订单微服务,库存微服务,mysql容器,nginx容器。
  • 工程:有一组关联的应用容器组成的一个完整业务单元,在docker-compose.yml文件中定义。
3、Compose使用的三个步骤:
  • 编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
  • 使用 docker-compose.yml​ 定义一个完整业务单元,安排好整体应用中的各个容器服务。
  • 最后,执行docker-compose up命令​,来启动并运行整个应用程序,完成一键部署上线
4、Compose常用命令

docker-compose -h                           # 查看帮助
docker-compose up                           # 启动所有docker-compose服务
docker-compose up -d                        # 启动所有docker-compose服务并后台运行
docker-compose down                         # 停止并删除容器、网络、卷、镜像。
docker-compose exec  yml里面的服务id                 # 进入容器实例内部  docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
docker-compose ps                      # 展示当前docker-compose编排过的运行的所有容器
docker-compose top                     # 展示当前docker-compose编排过的容器进程
docker-compose logs  yml里面的服务id     # 查看容器输出日志
docker-compose config     # 检查配置
docker-compose config -q  # 检查配置,有问题才有输出
docker-compose restart   # 重启服务
docker-compose start     # 启动服务
docker-compose stop      # 停止服务























 
技术小学生微信公众号
华为服务器
腾讯云服务器大促销。

声明:站长码字很辛苦啊,转载时请保留本声明及附带文章链接:https://blog.tag.gg/showinfo-3-36227-0.html
亲爱的:若该文章解决了您的问题,可否收藏+评论+分享呢?
上一篇:FileZilla FTP软件通过SFTP协议登录Linux系统方法
下一篇:解决:SQLSTATE[08001]: [Microsoft][ODBC Driver 17 for SQL Server]SSL Provider: [error:1425F102:SSL rout