一文带你走进Docker

基础知识

三要素

镜像(Image), 容器(Container), 仓库(Repository)

# 容器
	可以将容器看做是一个简易版的Linux环境和运行在其中的应用程序
		环境包括: root用户权限, 进程空间, 用户空间和网络空间, 

下载安装

# 1 安装gcc  gcc-c++
yum install -y gcc
yum install -y gcc-C++
# 2 安装需要的软件包
yum install -y yum-utils
# 3 设置stable仓库位置
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 4 建立 yum 索引
yum makecache fast
# 5 安装 Docker 引擎
yum install docker-ce docker-ce-cli containerd.io
# 6 配置阿里云镜像加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://am7dl19u.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

开始使用

# 开启 docker 服务
systemctl start docker
# 启动测试
docker run hello-world
Docker Run 运行流程
# 开始
Docker 在本机中寻找该镜像, 如果存在则以该镜像为模板生产容器实例运行
# 如果没有找到该镜像
去Docker hub 上查找该实例, 如果存在, 则镜像到本地, 然后以该镜像为模板生产容器实例运行
# 如果 Hub 上也没有该镜像
返回失败错误, 查找不到该镜像

Docker和Vm虚拟机对比

image-20220926165234283

Dockers为什么会比虚拟机更快
# 1 Docker 有着比虚拟机更少的抽象层
# 2 Docker 利用的是宿主机的内核, 而不需要加载操作系统的OS内核
	避免了引寻, 加载操作系统内核返回等比较费时费资源的过程, 当新建一个虚拟机时, 虚拟机软件需要加载OS, 返回新建过程时分钟级别的, 而Docker 由于直接利用宿主机的操作系统, 则省略了返回过程, 新建一个Docker 容器只需要几秒钟

Docker命令

帮助启动类

# 1 启动 Docker
systemctl start docker
# 2 关闭 Docker
systemctl stop docker
# 3 重启 Docker
systemctl restart docker
# 4 检查 Docker 状态
systemctl status docker
# 5 开机启动 Docker
systemctl enable docker
# 6 查看 Docker 概要信息
docker info
# 7 查看 Docker 总体帮助文档
docker --help
# 8 查看 Docker 命令帮助文档
docker 具体命令 --help

镜像命令

docker images
# 列出本地主机上的镜像
# 表头说明
	REPOSITORY: 镜像的仓库源
    TAG	: 镜像的标签版本号
    IMAGE ID: 镜像ID
    CREATED: 镜像的创建时间
    SIZE: 镜像大小
# 参数
	-a : 列出本地所有镜像(含历史镜像)
	-q : 只显示镜像ID
docker search
# docker search [OPTIONS] 镜像名称
查看远程仓库是否存在 目标镜像
# 案例
docker search redis
# 参数
	--limit: 只列出N个镜像, 默认25个
	docker search --limit 5 redis
docker pull
# docker pull 镜像名称[:TAG]
下载镜像
# 如果没有TAG 则下载最新版 等价于 docker pull 镜像名称:lastest
docker system df
# 查看镜像/容器/数据卷所占的空间
docker rmi
# docker rmi 镜像名称/Image ID
# 删除 单个镜像
	docker rmi -f 镜像ID
# 删除多个镜像
	docker rmi -f 镜像名1:TAG 镜像名2:TAG
# 删除全部
	docker rmi -f $(docker images -qa) 
# 参数
	-f : 强制删除

容器命令

# 新建并启动容器
	docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
	# 参数
		--name  : 为容器指定一个名称
		
		-d		: 后台运行容器并返回容器ID, 即启动守护式容器(后台运行) 
			# 在大部分的场景中, 我们希望docker的服务是在后台运行的
		-i		: 前台交互模式运行容器, 通常与 -t 同时使用
		-t		: 为容器重新分配一个伪输入终端, 通常与 -i 同时使用
		
		-P		: 随机端口映射, 大写P
		-p		: 指定端口映射, 小写p
# 列出容器列表
	docker ps [OPTIONS]
	# 默认列出所有正在进行的容器
	# 参数
		-a		: 列出当前所有正在运行 + 历史上运行过的容器
		-l		: 显示最近创建的容器
		-n		: 显示最近的n个创建的容器
		-q 		: 静默模式, 只显示容器编号
# 退出容器
	# 两种退出方式
		# exit
			run 进去容器, exit退出, 容器停止
		# ctrl + p + q
			run 进去容器, ctrl + p + q, 容器不停止
# 启动已停止运行的容器
	docker restart 容器名称/ID
# 停止容器
	docker stop 容器名称/ID
# 强制停止容器
	docker kill 容器名称/ID
# 删除已停止的容器
	docker rm 容器名称/ID
    # 一次性删除多个容器
    	docker rm -f $(docker ps -a -q)
    	docker rm -a -q | xargs docker rm
# 查看容器日志
	docker logs 容器ID
# 查看容器内运行的进程
	docker top 容器ID
# 查看容器内部细节
	docker inspect 容器ID
# 进入正在运行的容器, 并以命令行进行交互
	docker exec -t 容器ID bashShell # (推荐使用)
		在容器中打开新的终端, 并且可以启动新的进程, 用exit退出, 不会导致容器的停止
	docker attach 容器ID
		直接进入容器启动命令的终端, 不会启动新的进程, 用exit退出, 会导致容器的停止
# 复制容器内文件到主机
	docker cp 容器ID:容器内路径 目的主机路径

# 导入和导出容器
	docker export 容器ID > 文件名.tar
		导出容器内容流作为一个tar归档文件
	cat 文件名.tar | docker import -镜像用户/镜像名:镜像版本号
		从tar包中的内容创建一个新的文件系统在导入为镜像
	# 实例
		docker export ccc5370f6fae > redis.jar
		cat redis.jar | docker import ccc5370f6fae

Docker镜像

镜像

 一种轻量级, 可执行的独立软件包, 包含运行某个软件所需要的所有内容, 
	将应用程序和配置依赖打包好行程一个可交付的运行环境(包括代码, 运行时所需要的库, 环境变量和配置文件)
	这个打包好的运行环境就是 Image 镜像文件
	只有通过这个镜像文件才能生成Docker容器实例, (类似于Java中 New出来一个对象)

UnionFS(联合文件系统)

# Union文件系统
	一种分层, 轻量级并且高性能的文件系统
		支持对文件系统的修改作为一次提交来一层层的叠加, 同时可以将不同目录挂载到同一个虚拟文件系统下
	Union文件系统是Docker镜像的基础, 镜像可以通过分层来进行继承, 基于基础进行(没有父镜像), 可以制作各种具体的应用镜像
# 镜像分层结构优点			 
	共享资源, 方便复制迁移, 镜像复用

重点

Docker镜像层都是只读的, 容器层是可写的

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

为镜像增加功能

# 提交容器副本使之成为一个新的镜像
	docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
	# 实例 为原始Ubuntu系统添加 vim 命令
        # 1 进入原始Ubuntu系统
        docker run -it ubuntu /bin/bash 
        # 2 更新包管理工具
        apt-get update 
        # 3 下载 vim 命令
        apt-get install vim
        # 4 下载 ifconfig 命令
        apt-get install net-tools
        # 6 下载 ip addr 命令
        apt-get install iproute iproute-doc
        # 5 提交容器为镜像
        docker commit -m="add cmd: vim" -a="muu" e6578101222a muu/ubuntu:1.0

image-20220926203203682

容器数据卷

# docker容器产生的数据 如果不备份, 那么当容器删除后,容器内的数据自然会被删除, 为了能保存数据在 Docker中使用卷
# 类似于Redis里面的RDB和ROF
将docker容器内的数据保存进宿主机的磁盘中
	一容器数据卷的方式完成数据的持久化重要资料backup
	映射: 容器内的数据备份 + 持久化到本地主机目录
	
# 特点:
	1 数据卷可以在容器之间共享或者重用数据
	2 卷中的更改可以实时生效
	3 数据卷中的更高不会包含在镜像的更新中
	4 数据卷的生命周期一直持续到没有容器使用它为止
# 运行一个带有容器卷存储功能的容器实例
	docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名称
	# 查看数据卷是否挂载成功
		docker inspect 容器ID
# 容器和宿主机之间可以实现双向的数据共享

image-20220927161545941

# 读写规则映射添加说明		
	# 读写(默认)
		docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录路径:rw 镜像名称
	# 只读 容器内部只能读 不能写
		docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录路径:ro 镜像名称
		# 如果为只读模式 如果向文件夹写入文件
		Read-only file system  # 报错
# 卷的继承和共享
	容器1 完成和 宿主机的映射
		# docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录路径:rw 镜像名称 --name="u1"
	容器2 继承容器1 的卷规则		
		# docker run -it --privileged=true -v --volumes-from u1 镜像名称

image-20220927163350077

Docker 常规安装软件

总体步骤

1 搜索镜像 	
docker search 镜像名称
2 拉取镜像	# docker pull 镜像名称:版本号
3 查看镜像	# docker inspect 镜像名称:版本号
4 启动镜像容器 -- 服务端口映射 # docker run .. 镜像名称:版本号
5 停止容器 	# docker stop 容器名称/id
6 移除容器 	# docker rm 容器名称/id

MySQL

# 1 新建MySQL容器实例 卷映射 防止删除容器后数据丢失
docker run -d -p 3307:3306 --privileged=true -v /muu/mysql/log:/var/log/mysql -v /muu/mysql/data:/var/lib/mysql -v /muu/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql80 mysql:8.0.26
# 2 新建my.cnf -- 通过容器卷同步给 MySQL 容器实例
[client]
default_character_set=utf8mb4
[mysqld]
character_set_server=utf8mb4
collation_server=utf8_general_ci
# 3 重新启动 MySQL 容器实例再重新进入并查看字符编码 -- 解决中文乱码问题
show variables like 'character%';

Redis

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

redis.conf

# Minimal redis.conf

port 6379
daemonize no
dir .
save ""
appendonly yes
cluster-config-file nodes.conf
cluster-node-timeout 30000
maxclients 1001

分布式存储

哈希取余分区

# 理论
	假设有 N 台机器构成一个集群, 用户每次读写操作都是根据公式: hash(key) % N 计算出哈希值, 用来决定数据映射到哪一个节点上
# 优点
	简单粗暴, 直接有效, 只需要预估好数据, 规划好节点, 就能保证一段时间的数据支撑, 使用 hash 算法让固定的一部分请求落到同一台服务器上, 这样每台服务器固定处理一部分请求(并维护这些请求), 起到了 负载均衡 + 分而治之的作用
# 缺点
	扩容和缩容比较麻烦, 如果出现弹性扩容或者故障宕机时 N更改了 此时地址经过取余的结果发生很大变化 映射关系需要重新计算, 全部数据重新洗牌 
    会导致根据公式获取的服务器变得不可控

一致性哈希算法分区

# 目的
	当服务器个数(N)发生变动时, 尽量减少影响客户端到服务器的映射关系
# 构建步骤
	# 1 构建一致性哈希环
    	一致性哈希算法将整个哈希值空间组织成一个虚拟的圆环, 假设哈希值空间为0-2^31-1 整个哈希空间 按顺时针方向组织
    # 2 服务器IP节点映射
    	选择服务器的IP或者主机名作为关键字进行哈希, 得到的哈希结果 对应到哈希环空间的 对应位置
    # 3 落键规则
    	当存储一个kv键值对, 首先计算key的hash值, hash(key), 将这个key 使用相同的函数 hash计算出哈希值并确定此数据在环上的位置, 从此位置沿环顺时针姓周,第一台遇到的服务器就是其应该定位到的服务器, 并将该键值对存储在该节点上
# 优点
	# 提高了容错性
    	如果一台服务器不可用, 则受影响的仅仅是此服务器到其环空间中前一台服务器,(即沿着其逆时针行走遇到的第一台服务器)之间数据, 其他则不会受到影响
    # 提高了扩展性
    	数据量增加, 添加一台新的服务器X, 如果 X 在 A和B 之间, 那么受到影响的就是 A-X之间的数据, 重新将A-X的数据录入到X上即可, 不会导致全部数据洗牌
# 缺点
	# 数据倾斜问题
    	在服务节点太少的时候, 容易因为节点分布不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)的问题
        数据的分布和节点的位置有关, 因为这些节点不是均匀的分布在哈希环上的, 所以数据在存储的时候达不到均匀分布的效果

哈希槽分区

# 目的
	用于解决一致性哈希算法的数据倾斜问题
# 实质
	一个数组, 数组[0, 2^14-1] 形成 hash slot 空间
# 做什么的
	解决均匀分配的问题, 在数据和节点之间又加了一层, 将这层成为哈希槽(slot), 用于管理数据和节点之间的关系, 现在就相当于节点上放的是槽, 槽中放的是数据
    # 槽解决了问题
    	粒度问题, 将粒度变大, 利于数据移动
    # 哈希解决了什么问题
    	映射问题, 使用key的哈希值来计算所在的槽, 便于数据分配
# 哈希槽计算
	Redis集群中内置了16384个哈希槽, redis会根据节点数量大致均等的将哈希槽映射到不同的节点, 当需要在 Redis集群中放置一个K-V时, Redis先对Key使用crc16算法算出来一个结果, 然后将结果对16384求余数, 这样每个key都会对应一个编号在0-16383之间的哈希槽, 也就是映射到某个节点上
# 哈希槽的数量 为什么是16384个
	1 如果槽位是 65536 发送到心跳信息的信息头达8k, 发送的心跳包过于庞大
    2 redis 集群的主节点数量基本不肯能超过1000(集群节点越多, 心跳包的消息体内携带的数据越多, 如果节点超过1000, 也会导致网络拥堵)
  	3 槽位越小, 节点少的情况下, 压缩比高, 容易传输

Docker 复杂安装

MySQL 主从安装

# 1 新建主服务器容器实例 3308
docker run -d -p 3308:3306 --privileged=true -v /muu/mysqlCluster/mysql-master/log:/var/log/mysql -v /muu/mysqlCluster/mysql-master/data:/var/lib/mysql -v /muu/mysqlCluster/mysql-master/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=root --name mysqlMaster mysql:8.0.26
# 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
# 3 修改配置完成, 重启 Master
docker restart mysqlMaster
# 4 进入 mysql-master 容器
docker exec -it mysqlMaster /bin/bash
# 5 master 容器实例内创建数据同步用户
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
ALTER USER 'slave'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
# 6 新建从服务器容器3309
docker run -d -p 3309:3306 --privileged=true -v /muu/mysqlCluster/mysql-slave/log:/var/log/mysql -v /muu/mysqlCluster/mysql-slave/data:/var/lib/mysql -v /muu/mysqlCluster/mysql-slave/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=root --name mysqlSlave mysql:8.0.26
# 7 进入 /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
# 8 修改完配置后重启 slave 
docker restart mysqlSlave
# 9 在主数据库中查看主从同步状态
## 在主服务器的 mysql 命令行输入
show master status;
+-----------------------+----------+--------------+------------------+-------------------+
| File                  | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-----------------------+----------+--------------+------------------+-------------------+
| mall-mysql-bin.000001 |      712 |              | mysql            |                   |
+-----------------------+----------+--------------+------------------+-------------------+
# 10 进入 mysql-Slave 容器
docker exec -it mysqlSlave /bin/bash
mysql -u root -p
# 11 在从数据库中配置主从复制
change master to master_host='宿主机Ip',master_user='slave',master_password='123456',master_port=3308,master_log_file='mall-mysql-bin.000001',master_log_pos=712,master_connect_retry=30;
## 样例
change master to master_host='192.168.239.129',master_user='slave',master_password='123456',master_port=3308,master_log_file='mall-mysql-bin.000003',master_log_pos=156,master_connect_retry=30;
## 参数说明
	master_host		: 主数据库的IP地址
	master_port		: 主数据的运行端口
	master_user		: 在主数据库创建的用于同步数据的用户账号
	master_password	: 在主数据库创建的用于同步数据的用户密码
    master_log_file	: 指定从数据库要复制数据的日志文件, 通过查看主数据的状态获取 File 参数 		(#9 步)
    master_log_pos 	: 指定从数据库的哪个位置开始复制数据, 通过查看主数据的状态获取 Position 参数	(#9 步)
	master_connect_retry: 连接重试的时间间隔 单位: 秒
# 12 在从数据库中查看主从同步状态
show slave status \G;
## \G 以键值对的方式展示输出 当输出只有一行 且 列数过多的时候可以使用
# 13 在从数据库中开启主从同步
start slave;
# 14 查看从数据库状态
show slave status \G;
# 15 主从复制测试

Redis集群部署(三主三从)

基础部署
# 1 关闭防火墙 + 启动docker后台服务
# 2 新建 6 个docker容器实例 Master 6381 6382 6383 Slave 6384 6385 6386
docker run -d --name redis-node-1 --net host --privileged=true -v /muu/redis/cluster/redis-node-1:/data redis --cluster-enabled yes --appendonly yes --port 6381
docker run -d --name redis-node-2 --net host --privileged=true -v /muu/redis/cluster/redis-node-2:/data redis --cluster-enabled yes --appendonly yes --port 6382
docker run -d --name redis-node-3 --net host --privileged=true -v /muu/redis/cluster/redis-node-3:/data redis --cluster-enabled yes --appendonly yes --port 6383
docker run -d --name redis-node-4 --net host --privileged=true -v /muu/redis/cluster/redis-node-4:/data redis --cluster-enabled yes --appendonly yes --port 6384
docker run -d --name redis-node-5 --net host --privileged=true -v /muu/redis/cluster/redis-node-5:/data redis --cluster-enabled yes --appendonly yes --port 6385
docker run -d --name redis-node-6 --net host --privileged=true -v /muu/redis/cluster/redis-node-6:/data redis --cluster-enabled yes --appendonly yes --port 6386
	# 参数解释
		--net host 			: 使用宿主机的IP和端口, 默认
		--privileged=true	: 获取宿主机root用户权限
		--cluster-enabled yes : 开启redis集群
		--appendonly yes 	: 开启持久化
		--prot 6386			: redis端口号
# 3 进入容器 redis-node-1 并为6太机器构建集群关系(进入任意redis服务器均可)
redis-cli --cluster create 192.168.239.129:6381 192.168.239.129:6382 192.168.239.129:6383 192.168.239.129:6384 192.168.239.129:6385 192.168.239.129:6386 --cluster-replicas 1
	# 参数解释
		--cluster-replicas 1 	: 为每一个 master 创建一个 slave 节点
		
# 4 链接进入6381为切入点 查看集群状态
redis-cli -p 6381
CLUSTER INFO	# 查看集群状态
CLUSTER NODES	# 查看集群节点状态

开启Redis集群

查看集群状态

数据读写存储
# 1 启动 6 台机器构成的集群 并且 exec 进入
docker start redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5 redis-node-6
# 2 对 6381 添加数据
set k1 v1
set k2 v2
set k3 v3
# 3 防止路由失效加参数 -C 并添加数据
redis-cli -p 6381 -c
# 4 查看集群信息
redis-cli --cluster check 192.168.239.129:6381

启动redis集群

image-20220928191821466

当不添加参数-c时

image-20220928190843146

当以集群模式启动

image-20220928191151957

查看集群状态

image-20220928192858065

容错切换迁移
# 主6381和从机切换, 先停止6381
docker stop redis-node-1
# 再次查看集群信息
docker exec -it redis-node-2
redis-cli --cluster check 192.168.239.129:6381
redic-cli -p 6382 -c
cluster nodes
# 先还原之前的3主3从
docker start redis-node-1
# 查看集群状态
同上
# 重新将6381 变为主机
docker stop redis-node-6  # 
docker start redis-node-6

停止6381之后集群信息

image-20221003105601527

6381 重新连接之后查看集群信息, 发现6386 仍然是主机

image-20221003110102066D:\Programming\notes\knowledge\Java面经\docker.md

关闭6386 之后再次启动, 6381 再次变为主机

image-20221003110517479

主从扩容

image-20221003112644691

# 需求分析33 从 扩容到 44# 新增两台redis节点, 新建后 docker ps 查看是否为八个节点
docker run -d --name redis-node-7 --net host --privileged=true -v /muu/redis/cluster/redis-node-7:/data redis --cluster-enabled yes --appendonly yes --port 6387
docker run -d --name redis-node-8 --net host --privileged=true -v /muu/redis/cluster/redis-node-8:/data redis --cluster-enabled yes --appendonly yes --port 6388
# 进入6387实例内部
docker exec -it redis-node-7 /bin/bash
# 将新增的6387节点(空槽号)作为master节点加入到原有集群
redis-cli --cluster add-node 要加入集群的ip:port 原有集群的ip:port
redis-cli --cluster add-node 192.168.239.129:6387 192.168.239.129:6381
# 检查集群情况(第一次)
redis-cli --cluster check 192.168.239.129:6381
# 重新分配槽号
redis-cli --cluster reshard IP:PORT
redis-cli --cluster reshard 192.168.239.129:6381
	# 注
		新加入的master的槽位是3个新的区间, 以前的仍然为连续区间
		原因: 重新分配成本过高, 所以前面三家各自匀出来一部分, 分别从6381,6382,6383三个旧节点分别匀出1364个槽位给新的节点6387
# 检查集群情况(第二次)
redis-cli --cluster check 192.168.239.129:6381
# 为主节点6387分配从节点6388
redis-cli --cluster add-node 要添加的从机IP:PORT 目的主机IP:PORT --cluster-slave --cluster-master-id 目的主机ID 
redis-cli --cluster add-node 192.168.239.129:6388 192.168.239.129:6387 --cluster-slave --cluster-master-id 40e3254d180b593431b723be739a1d931da3d5bc
# 检查集群情况(第三次)
redis-cli --cluster check 192.168.239.129:6381
第一次检查集群情况, 6387未分配槽位,没有从节点

image-20221003115531759

重新分配槽位

image-20221003120042978

第二次检查集群状态

image-20221003133840336

添加从节点

image-20221003134141577

第三次检查集群状态

image-20221003134321625

主从缩容
# 目的63876388 下线
# 检查集群情况(第一次), 获取6388节点ID
redis-cli --cluster check 192.168.239.129:6381
# 从集群中将4号从节点6388下线
redis-cli --cluster del-node 节点IP:PORT 节点ID
redis-cli --cluster del-node 192.168.239.129:6388 5a5cc0454d8955188a7bb4440d52135e103beaef
# 将6387的槽号清空, 重新分配, 本例将清理出来的槽号全部分配给6381
redis-cli --cluster reshard 集群内任一主机IP:PORT
redis-cli --cluster reshard 192.168.239.129:6382
# 检查集群情况(第二次)
redis-cli --cluster check 192.168.239.129:6381
# 将6387下线
redis-cli --cluster del-node 192.168.239.129:6387 40e3254d180b593431b723be739a1d931da3d5bc
# 检查进群情况(第三次)
redis-cli --cluster check 192.168.239.129:6381
下线6388

image-20221003135150436

重新分配槽位
此处将6387的所有槽位全部分配给了6381
可以重复此过程平均分配给其他节点

image-20221003140004525

删除6387节点并检查集群状态

image-20221003140243749

Docker File 解析

Docker FIle 是用来构建Docker镜像的文本文件, 是由一条条构建镜像所需的指令和参数构成的脚本

从应用软件的角度来看, DockerFile, docker镜像与docker容器 分别代表软件的三个不同阶段
	DockerFile 		: 软件的原材料
	DockerImage		: 软件的交付品
	DockerContainer	: 可以认为是软件镜像的运行态, 也即镜像运行的容器实例
DockerFIle 面向开发, DockerImage 成为交付标准, Docker Container 则涉及部署和运维
三者缺一不可, 合理充当Docker体系的基石

image-20221005144459489

docker执行DockerFile的大致流程

# 1	docker 从基础镜像运行一个容器

# 2 执行一条指令并对容器进行修改

# 3 执行类似docker commit 的操作提交一个新的镜像层

# 4 docker 在基于刚提交的镜像运行一个新容器

# 5 执行 dockerfile 中的下一条指令 知道所有指令全部执行完成

image-20221005111752945

总结
# 1 DockerFile
	需要定义一个 DockerFile, DockerFile定义了进程需要的一切东西, DockerFile涉及的内容包括执行代码或者文件, 环境, 变量, 依赖包, 运行时环境, 动态链接库, 操作系统的发行版, 服务进程, 内核进程(当应用程序需要和系统服务和内核进程打交道, 这是需要考虑如何涉及namespace的权限控制)
# 2 Docker Image
	在使用 DockerFile 定义一个文件之后, docker bulid 会产生一个DOcker镜像, 当运行 Docker 镜像时会真正开始提供服务, 
# 3 Docker Container
	直接提供服务

保留字命令

# 构建时命令
# 01 From
	基础镜像, 当前新镜像是基于哪个镜像的, 指定一个已经存在的镜像作为模板, 第一条必须是From
# 02 MAINTAINER 
	镜像维护者的姓名, 邮箱地址
# 03 RUN 
	容器构建时需要的命令
	两种格式
		shell 格式
			RUN  <命令行命令>
				eg: RUN yum -y install vim
		exec  格式
			RUN ["可执行文件", "参数1", "参数2"]
				Eg: RUN ["./test.php", "dev", "offline"]
	RUN 在 Docker Build 运行

# 04 ADD
	将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
	Eg:	

# 05 COPY
	类似ADD, 拷贝文件和目录到镜像中
	将从构建上下文目录中 <源路径>的文件/目录复制到新的一层的镜像内的 <目标路径>位置
	EG:{
		COPY src dest / COPY ["src", "dest"]
		<src源路径>	: 源文件或者源路径
		<dest目标路径>	: 容器内指定的路径, 该路径可以自动创建
	}	
	
# 构建和执行时命令
# 06 WORKDIR
	指定在创建容器后, 终端默认登录进来的工作目录, 一个落脚点
# 07 USER (通常不指定)
	指定该镜像以什么样的用户去执行, 如果不指定, 则默认为root 

# 执行时命令                   
# 08 ENV
	用来在构建镜像的过程中设置环境变量
    	Eg: ENV MY_PATH /user/home
            这个环境变量可以在后续的任何RUN命令中使用, 如同在命令面前指定了环境变量前缀一样
            也可以在其他指令中直接使用这些环境变量
            	Eg: WORKDIR $MY_PATH
# 09 VOLUME
	容器数据卷, 用于数据保存和持久化工作
# 10 EXPOSE
	当前容器对外暴露的端口
# 11 CMD
	指定容器启动后要做的事情  Eg: /bin/bash
	CMD 指令的格式 与 RUN 相似:
		shell: CMD <命令>
		exec:  CMD ["可执行文件", "参数1", "参数2"]
		参数列表格式: CMD ["参数1", "参数2"], 在指定了 ENTRYPOINT 指令后, 用 CMD指定具体的参数
    注意:
    	DockerFile中可以有多个 CMD 指令, # 但是只有最后一个生效, CMD 会被 docker run 后面的参数替代
    	Eg:(Tomcat)
    		docker run -it -p 8080:8080 Tomcat /bin/bash # 只启动容器, 不启动Tomcat
    与 RUN 指令的区别
    	CMD 指令是在 docker run 时运行
    	RUN 指令是在 docker build 时运行
# 12 ENTRYPOINT
	指定一个容器启动时要运行的命令
	与 CMD 的区别:
		1. ENTRYPOINT 不会被 docker run 后面的指令覆盖
		2. 这些命令行参数会被当做参数送给 ENTRYPOINT 指令指定的程序
	优点: 
		在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数
	注意:
		如果 DockerFile 中存在多个 ENTRYPOINT指令, 仅最后一个生效
	命令格式:
		ENTRYPOINT ["<executeable>", "<param1>", "<param2>"]
		ENTRYPOINT 可以和 CMD 一起使用, 一般是 '变参' 才会使用 CMD 这里的 CMD 等于是给 ENTRYPOINT 传参
        Eg: 
        	FROM nginx
        	ENTRYPOINT ["nginx", "-c"]  # 定参
        	CMD ["/etc/ngin/nginx.conf"] # 实参

image-20221005141540180

虚悬镜像

# 构建时或者删除时出现一些错误 导致仓库名, 标签都是 <none> 的镜像, 俗称虚悬镜像 dangling image
# 虚悬镜像已经失去了存在价值且有可能会危害计算机, 看到删除即可
# 查出所有的虚悬净吸纳过
	docker image ls -f dangling=true
# 删除所有的虚悬镜像 
	docker image prune

Docker Network

网络情况

# Docker 不启动
	ens33
	Io
	virbr0
# Docker 启动
	在docker不启动的情况下增加 
		docker

常用基本命令

# 查看所有的docker network
	docker network ls
# 删除所有的无用网络
	docker network prune
# 删除一个或多个网络
	docker network rm 网络名称
# 展示一个或多个网络的信息
	docker network inspect 网络名称

Docker网络可以做什么

容器之间的互联和通信及端口映射

容器IP变动时候可以通过服务名直接网络通信而不受到影响

网络模式

总体介绍
网络模式作用命令参数
bridge为每一个容器分配, 设置IP等,
并将容器连接到docker0, 虚拟网桥, 默认为该模式
–network bridge 默认
host容器将不会虚拟出自己的网卡, 配置自己的IP等,
而是使用宿主机的IP和端口
–network host
none容器有独立的 Network namespace,
但并没有对其进行任何网络设置
如分配 veth pair 和网桥连接, IP 等
–network none
container新创建的容器不会创建自己的网卡和配置自己的IP,
而是和一个指定的容器共享IP, 端口范围等
–network container:name/id
容器实例内默认网络IP生产规则

docker容器内部的ip是动态变化的

bridge
Docker服务默认会创建一个docker0网校(其上有一个docker0内部接口), 该桥接网络的名称为docker0, 它在内核层连通了其他的物理机或虚拟网卡, 这就将所有容器和本地主机都放到同一个物理网络, Docker默认指定了docker0接口的IP地址和子网掩码, 让主机和容器之间可以通过网桥相互通信

image-202210051605202789

网桥docker0创建爱你一对对等虚拟设备接口一个叫 veth 另一个叫 eth0 成对匹配
	1. 整个宿主机的网桥模式都是 docker0 类似一个交换机有多个接口, 每个接口都叫 veth 在本地主机和容器内部分别创建一个虚拟接口, 并让他们彼此联通(这样一堆接口叫 veth pair)
	2. 每个容器实例内部也有一块网卡, 每个接口叫 eth0
	3. docker0上面的每个veth匹配某个容器实例内部eth0, 两两配对, 一一匹配

通过上述, 将宿主机上的所有容器都连接到这个内部网络上, 两个容器在同一网络下, 会从这个网关下各自拿到分配的ip, 此时两个容器的网络是互通的

image-20221005164324174

Host
# 介绍(不推荐使用)
    容器将不会获得一个独立的 Network Namespace 而是和宿主机公用一个 Network Namespace
    容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口

# 问题
	docker 启动时总会遇见警告: WARNING: Published ports are discarded when using host network mode
# 原因
	docker 启动时指定 --network=host 或者 -net=host, 如果还指定了 -p 映射端口, 那么这个时候就会有此警告
	并且通过 -p 设置端口参数不会起到任何作用, '端口号会以主机端口号为主' 重复则递增
# 解决方案
	使用 docker 的其他网络模式 eg: --net=bridge

image-20221005164335681

Container
# 介绍
	新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享, 新创建的容器不会创建自己的网卡, 配置自己的ip, 而是和一个指定的容器共享IP和端口范围, 同样, 两个容器除了网络方面,其他的如文件系统, 进程列表还是隔离的
# Eg 1
	docker run -d -p 8085:8080                              --name tomcat85 muu/tomcat8-jdk8
	docker run -d 0p 8086:8080 --network container:tomcat85 --name tomcat86 muu/tomcat8-jdk8 # 端口冲突
# Eg 2
	docker run -it 							   --name alpine1 alpine /bin/sh
	docker run -it --network container:aloine1 --name alpine2 alpine /bin/sh  
	# 两者公用一个网桥
	# 注:
		当 关闭 alpine1 时, alpine2 的网络也会停止

image-20221005170003367

自定义网咯
# 介绍
	自定义网络本身就维护好了主机名和ip的对应关系, 通过ip 和域名 都可以ping通
# 作用
	使得容器IP变动的时候可以通过服务名直接网络通信而不受影响
# 命令:
	docker network create muu_net
	docker network ps
	docker run -d --name a1 --network muu_net alpine /bin/sh
	docker run -d --name a2 --network muu_net alpine /bin/sh

Docker Compose

核心概念

# 一 文件
	docker-compose.yml
# 二 要素
	服务(service)
		一个个应用容器实例, 例如: 订单微服务, 库存微服务, mysql 容器 , redis容器
	工程(project)
		由一组关联的引用容器组成的一个完整业务单元, 在 docker-compose.yml 文件中定义

执行流程

# 一
	编写 DockerFile 定义各个微服务应用并构建出对应的镜像文件
# 二
	使用 Docker-compose 定义一个完整业务单元, 安排好整体应用中的各个容器服务
# 三
	执行 docker-compose up 命令, 启动并运行整个应用程序, 完成一键部署上线 

常用命令

命令解释
docker-compose-h查看帮助
docker-compose up启动所有docker-compose服务
docker-compose up -d启动所有docker-compose服务并后台运行
docker-compose down停止并删除容器、网络、卷、镜像。
docker-compose exec yml里面的服务id进入容器实例内部
docker-compose ps展示当前docker-compose编排过的运行的所有容器
docker-compose top展示当前docker-compose编排过的容器进程
docker-compose logs yml里面的服务id查看容器输出日志
dokcer-compose config检查配置
dokcer-compose config -q检查配置, 只输出有问题的位置
docker-compose restart重启服务
docker-compose start启动服务
docker-compose stop停止服务
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值