本篇随笔为Docker学习记录(2),所有内容均参考尚硅谷Docker实战教程以及云原生开发
安装mysql主从复制
-
新建主服务器容器实例3307
docker run -p 3307:3306 \ --name mysql-master \ --privileged=true \ -v /yiran/mysql-master/log:/var/log/mysql \ -v /yiran/mysql-master/data:/var/lib/mysql \ -v /yiran/mysql-master/conf:/etc/mysql/conf.d \ -e MYSQL_ROOT_PASSWORD=root \ -d mysql:5.7
-
进入/mydata/mysqI--master/conf目录下新建配置文件,my.cnf
-
修改完配置,重启mysql-master实例
docker restart mysql-master
-
进入 mysql-master 容器
-
master容器实例内创建数据同步用户
- 创建用户:
create user 'slave'@'%' identified by '123456';
- 用户授权:
grant replication slave, replication client on *.* to 'slave'@'%';
- 创建用户:
-
新建主服务器容器实例3308
-
进入
/mydata/mysq-slave/conf
目录下新建my.cnf
-
修改完配置后重启slave实例
docker restart mysql-slave
-
在主数据库中查看主从同步状态
-
进入mysql--slave容器
-
在从数据库中配置主从复制
change master to master_host='192.168.38.128',master_user='slave',master_password='123456',master_port=3307,master_log_file='mall-mysql-bin.000001',master_log_pos=154,master_connect_retry=30;
-
在从数据库中查看主从同步状态
show slave status \G;
-
在从数据库中开启主从同步
start slave;
-
查看从数据库状态,发现已经同步
show slave status \G;
-
主从复制测试
分布式存储
问题引入
12亿条数据需要缓存,请问如何设计这个存储案例?答:采用分布式存储
分布式存储的3种哈希方式:
- 哈希取余分区
- 一致性哈希算法分区
- 哈希槽分区
哈希取余
优点:分而治之+分布均衡
缺点:由于余数确定,扩容或缩容(故障)后,需要重新确定余数,哈希规则需要重新确定
一致性哈希算法
算法背景:一致性哈希算法在1997年由麻省理工学院中提出的,设计目标是为了解决分布式缓存数据交动和映射问题,某个机器宕机了,分母数量改变了,自然取余数不OK了。
实现思路:
- 算法构建一致性哈希
- 服务器IP节点映射
- key落到哈希环上,向前走落到服务器上
优缺点:
优点:容错性(一台宕机,只影响下一台机器),扩张性(方便扩张,不需要重新计算哈希)
缺点:数据倾斜(可引入虚拟节点来解决,参考ScyllaDB的设计原则)
哈希槽分区
- 为什么出现?
解决一致性哈希算法的数据倾斜问题
哈希槽实质是一个数组,数组[0 , 2^14 -1]形成的hash slot空间。
- 能干什么?
解决均匀分配的问题,在数据和节点之间又加入了一层,把这层称为哈希槽(slot)),用于管理数据和节点之间的关系,现在相当于节点上放的是槽,槽里放的是数据。
- 深入理解:
槽解决的是粒度问题,相当于把粒度变大了,便于数据移动。
哈希解决的是映射问题,使用key的哈希值来计算所在的槽,便于数据分配。
- 多少个hash槽
一个集群只能有16384个槽,编号0-16383(0 - 2^14 -1)。这些槽会分配给集群中的所有主节点,分配策略没有要求。可以指定哪些编号的槽分配给哪个主节点。集群会记录节点和槽的对应关系。解决了节点和槽的关系后,接下来就需要对key求哈希值,然后对16384取余,余数是几key就落入对应的槽里。slot=CRC16(key)%16384。以槽为单位移动数据,因为槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了。
案例:3主3从Redis集群配置
操作步骤:
- 关闭防火墙+启动docker后台服务
- 新建6个docker容器实例
- 进入容器redis-node-1,并为6台机器构建集群关系
- 链接进入6381作为切入点,查看集群状态
新建6个docker容器实例:命令分步解释
# 启动第1台节点
# --net host 使用宿主机的IP和端口,默认
# --cluster-enabled yes 开启redis集群
# --appendonly yes 开启redis持久化
# --port 6381 配置redis端口号
docker run -d --name redis-node-1 --net host --privileged=true -v /app/redis-cluster/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381
# 启动第2台节点
docker run -d --name redis-node-2 --net host --privileged=true -v /app/redis-cluster/share/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382
# 启动第3台节点
docker run -d --name redis-node-3 --net host --privileged=true -v /app/redis-cluster/share/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383
# 启动第4台节点
docker run -d --name redis-node-4 --net host --privileged=true -v /app/redis-cluster/share/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384
# 启动第5台节点
docker run -d --name redis-node-5 --net host --privileged=true -v /app/redis-cluster/share/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385
# 启动第6台节点
docker run -d --name redis-node-6 --net host --privileged=true -v /app/redis-cluster/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386
构建主从关系
- 进入redis-node-01:
docker exec -it redis-node-1 /bin/bash
- 构建主从关系:
redis-cli --cluster create 192.168.xxx.xxx:6381 192.168.xxx.xxx:6382 192.168.xxx.xxx:6383 192.168.xxx.xxx:6384 192.168.xxx.xxx:6385 192.168.xxx.xxx:6386 --cluster-replicas 1
自动分配主从服务器:6381-6384;6382-6385;6383-6386
查看集群状态
- 进入
redis-node-1
,使用redis-cli
连接到6381
节点:redis-cli -p 6381
- 查看cluster信息:
cluster info
- 查看cluster中Node信息:
cluster nodes
案例:主从容错切换迁移
数据读写存储
- 以单机的方式进行启动
redis-cli -p 6381
set k1 v1
后,报错:需要跳转到 12706 6386上上
- 以集群的方式进行启动
redis-cli -p 6381 -c
成功:redirected - 重定向到slot[12706] -- 12706对应6386机器
- 进入redis的docker容器,
redis-cli --cluster check IP地址:端口号
查询当前集群的信息
容错切换迁移:测试主机宕机后,从机能否正常工作
- 主机6381停机,模拟宕机场景
- docker 进入
redis-node-2
,查看集群信息,发现6381 slave, fail
- 还原原来宕机的机器,宕机前:主机 --》 恢复后:从机
案例:主从扩容/缩容
主从扩容(3主3从 --> 4主4从)
需求:Redis集群,增加6387(主)和6388(从),变为4主4从
- 新建6387,6388两个节点+新建后启动+查看是否有8个节点
# 新建6387以及6388节点
# 6387
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
# 6388
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
- 进入6387容器实例内部
docker exec -it redis-node-7 /bin/bash
- 将新增的6387节点(空槽号)作为master节点加入原集群
redis-cli --cluster add-node 192.168.38.128:6387 192.168.38.128:6381
- 检查集群情况(第1次)
redis-cli --cluster check 192.168.38.128:6381
加入集群,未分配哈希槽,未分配从机
- 重新分派槽号
redis-cli --cluster reshard 192.168.38.130:6381
- 输入给6387分配多少slot槽
- 输入接收这些槽位的节点ID,即6387的ID
- 检查集群情况(第2次)
redis-cli --cluster check 192.168.38.128:6381
- 分配4096个槽给6387
- 三个主机每个匀一部分给6387
- 优点:对原先的节点影响较小
- 为主节点6387分配从节点6388
redis-cli --cluster add-node 192.168.38.128:6388 192.168.38.128:6387 --cluster-slave --cluster-master-id 0fd50de894dfc8eab1f53124444c6a8b912b1f23(6387的ID)
- 检查集群情况(第3次)
redis-cli --cluster check 192.168.38.128:6381
- 主:6387 -- 从:6388
主从缩容
需求:Redis集群,删除6387和6388(6387和6388下线),恢复3主3从
- 检查集群情况1获得6388的节点id
redis-cli --cluster check 192.168.38.128:6381
- 将6388删除,从集群中将4号从节点6388删除
redis-cli --cluster del-node 192.168.38.128:6388 8d6caf02849b6c0087296c5e7e013fa0b129972f(6388的ID)
- 将6387的槽号清空,重新分配,本例将清出来的槽号都给6384
- 给
集群
重新分配槽位 redis-cli --cluster reshard 192.168.38.128:6381
- 移动4096个槽位 -- 谁接收槽位(6384的ID) -- 从何处来(6387的槽位)
- 检查集群情况第二次
- 6384的槽位从原先的4096变为8192(4096+分配的4096)
- 将6387删除
redis-cli --cluster del-node 192.168.38.128:6387 0fd50de894dfc8eab1f53124444c6a8b912b1f23(6387的ID)
- 检查集群情况第三次
是什么?
定义
Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
构建步骤:
编写Dockerfile -- docker build构建镜像 -- docker run 形成新的容器
DockersFile构建过程解析
- DockerFile内容基础知识:
- 每条保留字指令都必须为大写字母,且后面要跟随至少一个参数
- 指令按照从上到下,顺序执行
-
表示注释
- 每条指令都会创建一个新的镜像层并对镜像进行提交
- Docker执行Dockerfile的大致流程
- docker从基础镜像运行一个容器
- 执行一条指令并对容器作出修改
- 执行
类似docker commit
的操作提交一个新的镜像层 - docker再基于刚提交的镜像,运行一·个新容器
- 执行dockerfile中的下一条指令,直到所有指令都执行完成
- 总结
- 从应用软件的角度看,Dockerfile是软件的原材料,Docker image 是软件的交付品,Docker container 是按照镜像运行的容器实例
- Dockerfile:定义了进程需要的一切东西,涉及的内容包括代码、文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程……
- Docker 镜像:在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行Dockert镜像时,会真正开始提供服务
- Docker 容器:直接提供服务
DockerFile常用保留字指令
- FROM:基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板
- MAINTAINER:镜像维护者的姓名和邮箱地址
- RUN:容器构建时需要运行的命令
- shell格式:run <命令行工具>
# 等同于在终端操作的shell命令
# 格式:RUN <命令行命令>
RUN yum -y install vim
- exec格式:RUN ["可执行文件", "arg1", "arg2", ……]
# 格式:RUN ["可执行文件" , "参数1", "参数2"]
RUN ["./test.php", "dev", "offline"] # 等价于 RUN ./test.php dev offline
- EXPOSE:向外暴漏的端口号,-p, -P
- WORKDIR:指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
- USER:指定该镜像以什么样的用户去执行,如果都不指定,默认是root
- ENV:用来在构建镜像过程中设置环境变量【可理解为全局变量】
- ADD:将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包【COPY+tar解压】
- COPY:类似于 docker cp
- VOLUME:容器数据卷
- CMD:指定容器启动后的要干的事情
# CMD 指令的格式和 RUN 相似,也是两种格式:
# shell格式:
CMD <命令>
# exec格式:
CMD["可执行文件","参数1","参数2"...]
# 参数列表格式:CMD["可执行文件","参数1","参数2"...]
# 若制定了ENTRYPOINT指令,则用CMD指定具体参数
- 注意:Dockerfile中可以有多个CMD指令,但只有最后一个生效,CMD会被docker run之后的参数替换
# Dockerfile
EXPOSE 8080
CMD ["catalina.sh", "run"]
# 执行时
docker run -it -p 8080:8080 imageID /bin/bash
# 相当于替换CMD["catalina.sh", "run"] --> CMD["/bin/bash", "run"]
- 与RUN命令的区别:CMD在
docker run
时运行,RUN在docker build
时运行 - ENTRYPOINT:也是用来指定一个容器启动时要运行的命令
- 类似于CMD指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序
- 命令格式:
ENTRYPOINT["<executable>", "<parael1>", "<parael2>", ……]
- ENTRYPOINT 与 CMD 命令一起使用时,相当于CMD给ENTRYPOINT传参,等价于
" " - 案例:
Dockerfile构建案例
构建自定义镜像 my_centos_java8
- 从dockerhub上获取centos,并启动
- 新建/myfile,在该目录下,下载jdk-8u191-linux-x64.tar.gz
wget https://mirrors.yangxingzhen.com/jdk/jdk-8u191-linux-x64.tar.gz
- 新建Dockerfile:
vim Dockerfile
FROM ubuntu
MAINTAINER lee<lee@xxx.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN apt-get update
RUN apt-get install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "install ifconfig cmd into ubuntu success ....."
CMD /bin/bash
-
构建
docker build -t ubuntu:1.0.1 .
-
运行
docker run ubuntu:1.0.1
虚悬镜像
仓库名、标签名都是
在构建或者删除镜像时可能由于一些错误导致出现虚悬镜像。
# 列出docker中的虚悬镜像:
docker image ls -f dangling=true
# 虚悬镜像一般是因为一些错误而出现的,没有存在价值,可以删除:
# 删除所有的虚悬镜像
docker image prune
总结
Docker微服务
【待补充】
Docker网络
虚拟网桥 virbr0
- 在cenos7的安装过程中如果有选择相关虚拟化的服务安装系统后,启动网卡时会发现有一个以网桥连接的私网地址的virbr0网卡(virbr0网卡:它还有一个固定的默认IP地址192.168.122.1),是做虚拟机网桥使用的。其作用是为连接其上的虚拟网卡提供NAT访同外网的功能。
- 我们之前学习linux安装,勾选安装系统的时候附带了libvirt服务才会生成的一个东西,如果不需要可以直接将libvirt服务卸载
yum remove libvirt-libs.x86_64
- 启动docker后,另外会出现一个虚拟网桥
docker0
常用命令
- 查看docker网络模式
docker network ls
- 创建
docker network create aa_network
- 删除
docker network rm aa_network
- 检查network的信息
docker network inspect bridge
network作用
- 容器间的互联和通信以及端口映射
- 容器IP变动时,可以通过服务名直接进行网络通信,不会受到影响
网络模式
总体介绍
网络模式 | 简介 | 命令 |
---|---|---|
bridge | 为每一个容器分配、设置IP等,并将容器连接到一个docker0 虚拟网桥,默认为该模式。 |
--network bridge,默认使用docker0 |
host | 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。 | --network host |
none | 容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair和网桥连接,IP等。 | --network none |
container | 新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP、端口范围等。 | --network container:NAME或容器ID |
容器实例内默认网络IP生产规则
docker容器内部的 IP 会发生变化【一个容器宕机了,IP 会进行回收,以便下一次重新分配】
Bridge模式
host模式
none模式
禁用网络功能。
在none
模式下,并不为docker容器进行任何网络配置。进入容器内,使用ip addr
查看网卡信息,只能看到lo
(本地回环网络127.0.0.1
网卡)。
container模式
自定义网络
集群环境下,多台docker容器,需要自定义网络
- ping IP地址(能通,但IP地址可能变化)
- ping 容器名(推荐)
Docker-compose容器编排
是什么?
Compose是Docker公司推出的一个工具软件,可以管理多个Docker容器组成一个应用,你需要定义一个YAML格式的配置文件docker-compose.yml
,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器
docker-compose的作用
- docker 资源占用少,如果需要同时部署好多个服务,针对每个服务单独写Dockerfile,再构建?
- 操作繁琐,麻烦 --》 docker compose多服务部署
- Compose允许用户通过一个单独的
docker-compose.yml
模板文件(YAML格式)来定义一组相关联的应用容器为一个项目(project)。 - Docker-compose解决了容器与容器之间如何管理编排的问题
下载
参考官网Install Compose standalone操作步骤:
curl -SL [https://github.com/docker/compose/releases/download/v2.24.6/docker-compose-linux-x86_64](https://github.com/docker/compose/releases/download/v2.24.6/docker-compose-linux-x86_64) -o /usr/local/bin/docker-compose
compose核心概念
一个文件:docker-compose.yml
两个要素:
- 服务(service):一个个应用容器实例,比如订单微服务、库存微服务、mysql容器
- 工程(project):由一组关联的应用容器组成的一个完整业务单元,在docker-compose.yml文件中定义。
使用docker-compose的三个基本步骤
- 编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
- 使用
docker-compose.yml
,定义一个完整业务单元,安排好整体应用中的各个容器服务 - 最后,执行
docker-compose up
命令来启动并运行整个应用程序,完成一键部署上线
Compose常用命令
关注:检查yaml配置文件,docker-compose config -q
Compose编排微服务
改造升级微服务工程docker_boot
【待补充】
不使用compose
- 单独的mysql容器实例
- 新建mysql容器实例
- 进入mysql容器实例并新建库db01+新建表t_user
- 单独的redis容器实例
- 微服务工程
- 上面三个容器实例依次顺序启动成功
- swagger测试:http://localhost:服务端口/swagger-ui.html#/
出现了哪些问题?
- 先后顺序要求固定,先启动mysql,再启动redis,最后启动微服务
- 多个run命令……
- 容器间的启停或宕机,有可能导致 IP 地址对应的容器实例变化,映射出错,要么生产 IP 写死(可以但是不推荐),要么通过服务调用
使用Compose
Docker容器的监控与统计
轻量级监控工具
查看当前docker的状态:docker system df
Portainer是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。
安装:www.potainer.io
复杂监控工具
原生命令
操作:docker status
问题:通过docker stats
命令可以很方便的看到当前宿主机上所有容器的CPU,内存以及网络流量等数据,一般小公司够用了…… 但是,docker stats
统计结果只能是当前宿主机的全部容器,数据资料是实时的,没有地方存储、没有指标预警等功能
作用
容器监控:CAdvisor监控收集+InfluxDB存储数据+Granfana展示图表
compose容器编排
# 新建目录
mkdir cig
# 新建yaml文件
vim docker-compose.yml
# 检查yaml文件
docker-compose config -q
# 启动docker-compose
docker-compose up
# 查看三个服务容器是否启动
docker ps
# 测试
# 浏览CAdvisor收集服务,http://ip:8080/
# 浏览Influxdb存储服务,http://ip:8083/
# 浏览Grafana展现服务,http://ip:3000
标签:node,容器,记录,--,redis,学习,cluster,Docker,docker
From: https://www.cnblogs.com/syr463/p/18035391