1.1.1、主服务器配置
1、运行主服务器 mysql-master
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=root \
-d mysql:5.7
2、修改配置文件
vim /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
3、创建数据同步用户 laptoy
CREATE USER 'laptoy'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'laptoy'@'%';
4、主机查看主从同步状态
show master status;
1.1.2、从服务器配置
1、创建从服务器 mysql-laptoy
docker run -p 3308:3306 --name mysql-laptoy \
-v /mydata/mysql-laptoy/log:/var/log/mysql \
-v /mydata/mysql-laptoy/data:/var/lib/mysql \
-v /mydata/mysql-laptoy/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
2、修改配置文件
vim /mydata/mysql-laptoy/conf/my.cnf
[mysqld]
## 设置server_id,同一个局域网需要唯一
server_id=102
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能,以备slave作为其他数据库实例的master
log-bin=mall-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_update表示slave将复制事件写进自己的二进制日志
log_slave_updates=1
## slave设置只读(具有super权限的用户除外)
read_only=1
重启mysql-laptoy
3、在从数据库中配置主从复制
4、从机客户端执行:
change master to master_host=‘192.168.88.129’, \
master_user='laptoy', \
master_password='123456', \
master_port=3307, \
master_log_file='mall-mysql-bin.000001', \
master_log_pos=154, \
master_connect_retry=30;
5、从机查看主从同步状态
show slave status \G;
主机同意了但是从机没有开启主从同步
6、从机开启主从同步
start slave;
证明主从开始同步
1.1.3、测试
1~2亿数据需要缓存,请问如何设计这个存储案例?
2亿条数据就是2亿个k,v,采用分布式存储,每次读写根据公式hash(key)%N台机器台数,计算出哈希值,用来决定映射到哪个节点上
优点:
只要预估好节点数量,就能采用Hash算法让固定的一部分请求落到同一台服务器,这样每台服务器处理一部分请求(并维护请求信息),起到负载均衡+分而治之的作用
缺点
服务扩容或宕机会导致取模公式出现变化:Hash(key)/3->Hash(key)/?,服务器会变得不可控
提出一致性Hash解决方案,解决服务器个数变化时,尽量减少影响客户端到服务器的映射关系
1、三大步骤
1、算法构建一致性哈希环
按照hash取模的方法对2^32取模,将整个哈希值空间形成一个虚拟的圆环,整个空间按顺时针0- 2 ^32-1组织形成Hash环
2、服务器IP节点映射
将服务器的IP或者主机名作为关键字进行哈希,每台机器分布在Hash环的各个位置,假如有4个节点NodeA B C D,经过哈希函数计算,对应位置为:
3、key落键规则
当需要存储kv键值对时,首先计算key的hash值确认此数据环的位置,从此位置沿环顺时针行走,遇到的第一个节点就是其应该存储进的服务器
2、优点
容错性:
假如C宕机,C对象kv被重新顺时针定位到D。受影响的仅仅时此服务器到其环空间中前一台服务器(即沿逆时针方向遇到的第一台服务器)之间数据
扩展性
增加节点X,假设定位在A和B之间,受到影响的仅仅只有A-X之间的数据
3、缺点
数据倾斜问题
节点太少时,因为节点分布不均匀导致数据倾斜(被缓存的对象大部分集中在一台服务器)
为了 解决一致性哈希算法的数据倾斜问题
1、哈希槽实质上就是一个数组,数组[0,2^14-1]形成的空间
解决均匀分配问题,在数据和节点之间加入了一层,把这层称为哈希槽(slot),用于管理数据和节点之间的关系,现在就相当于节点上存放哈希槽,槽里存放数据kv
槽解决的是粒度问题,相当于把粒度变大了,这样便于数据移动
哈希解决的是数据问题,使用key的哈希值来计算所在的槽,便于数据分配
2、多少个哈希槽
一个集群只能有16384个槽,编号0-16383(0,2^14-1),这些槽会分配给集群中所有主节点,分配策略没有要求,可以指定哪些编号的槽分配给哪个主节点。集群会记录节点和槽的对应关系。解决了节点和槽的关系后,接下来就对key求哈希值,然后对16384取余,余数是几key就落到对应的槽里。slot=CRC16(key)%16384。以槽为单位移动数据,槽的数量是固定的,方便处理
参考Redis6 入门到精通 —— 十三、集群配置
1、启动6台redis服务
docker run --name redis-node-x \
--net host --privileged=true \
-v /data/redis/share/redis-node-x:/data \
-d redis:6.0.8 \
--cluster-enabled yes --appendonly yes \
--port 638x
--net host
使用宿主机的ip和端口,默认
依次执行
docker run --name redis-node-1 --net host --privileged=true -v /data/redis/share/redis-node-1:/data -d redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381
docker run --name redis-node-2 --net host --privileged=true -v /data/redis/share/redis-node-2:/data -d redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382
docker run --name redis-node-3 --net host --privileged=true -v /data/redis/share/redis-node-3:/data -d redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383
docker run --name redis-node-4 --net host --privileged=true -v /data/redis/share/redis-node-4:/data -d redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384
docker run --name redis-node-5 --net host --privileged=true -v /data/redis/share/redis-node-5:/data -d redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385
docker run --name redis-node-6 --net host --privileged=true -v /data/redis/share/redis-node-6:/data -d redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386
2、进入任意容器内部执行搭建集群命令(执行后输入yes)
redis-cli --cluster create \
192.168.88.129:6381 \
192.168.88.129:6382 \
192.168.88.129:6383 \
192.168.88.129:6384 \
192.168.88.129:6385 \
192.168.88.129:6386 \
--cluster-replicas 1
--cluster-replicas 1
为每一个master创建一个slave
当前主从情况及插槽情况
M:6381[0-5460] <---S:6384
M:6382[5461-10922] <---S:6385
M:6383[10923-16383] <---S:6386
重点:主从容错 :
主机宕机从机判断心跳超时后自动上位
旧主机重启后变为从机
假如6381宕机,重新上位后变为6384的slave,还原主从关系可以通过停止6384,再重启6384
3、集群命令
redis-cli -c -p 638x 去中心化连接
`-c` 代表了可以自动重定向到相对应的槽位的master
redis-cli --cluster check 192.168.88.129:638x 查看集群状态(去中心化连接638x,只要是主机node都可以)
cluster info 查看当前节点信息
cluster nodes 查看所有节点信息
先扩入主机,再将从机挂载到主机上
当前主从情况及插槽情况
M:6381[0-5460] <---S:6384
M:6382[5461-10922] <---S:6385
M:6383[10923-16383] <---S:6386
1、新建6387,6388节点
docker run --name redis-node-7 --net host --privileged=true -v /data/redis/share/redis-node-7:/data -d redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387
docker run --name redis-node-8 --net host --privileged=true -v /data/redis/share/redis-node-8:/data -d redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388
2、将新增的6387作为master加入集群
docker exec -it redis-node-7 bash 进入node7容器
redis-cli --cluster add-node 新master节点ip:port 集群master节点ip:port
redis-cli --cluster add-node 192.168.88.129:6387 192.168.88.129:6381
3、检查集群状态
redis-cli --cluster check 192.168.88.129:6381
redis-cli --cluster reshard 192.168.88.129:6381
检查集群槽位状态(每台原主机分配部分槽位给新主机)
M:6381[1365-5460]
M:6382[6827-10922]
M:6383[12288-16383]
M:6387[0-1364],[5461-6826],[10923-12287]
5、为新主机添加从机
redis-cli --cluster add-node 从机ip:port 主机ip:port --cluster-slave --cluster-master-id 主机id
redis-cli --cluster add-node 192.168.88.129:6388 192.168.88.129:6387 --cluster-slave --cluster-master-id e6077c25dc3707da577c3d1af2c56e00637afaa7
需要先删除从机,因为主机负责写操作,从机负责读操作,先将读操作的删除
1、删除从机6388节点
redis-cli --cluster del-node 从机ip:port 从机id
redis-cli --cluster del-node 192.168.88.129:6388 90ad89cec1455c1c3139725841cba7159b9311ce
检查集群状态此时从机已删除
2、清除主机槽位(此处例子将槽位转移给6381)
redis-cli --cluster reshard 192.168.88.129:6381
检查集群状态此时6388槽位为0,6381获得6387的槽位
3、删除主机6387节点
redis-cli --cluster del-node 192.168.88.129:6387 e6077c25dc3707da577c3d1af2c56e00637afaa7
# 检查集群状态此时恢复3主3从
官方文档
DockerFile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成
1、基础知识
2、执行流程
3、小总结
从应用软件的角度看,DockerFile,Docker镜像,Docker容器分别代表软件的三个不同阶段:
DockerFile面向开发,Docker镜像成为交付标准,Docker容器涉及部署与运维,三者缺一不可,合力充当Docker体系的基石
保留字 | 说明 |
---|---|
FROM | 基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from |
MAINTAINER | 镜像维护者的姓名和邮箱地址 |
RUN | 容器构建时需要运行的命令,在docker build时运行, shell和exec两种格式 |
EXPOSE | 当前容器堆外暴露出的端口 |
WORKDIR | 指定在创建容器后,终端默认登录进来的工作目录,一个落脚点,默认/ |
USER | 指定该镜像以什么样的用户取执行,默认ROOT |
ENV | 用来在构建镜像时设置环境变量 |
VOLUME | 容器数据卷,用于数据保存和持久化 |
ADD | 将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包 |
COPY | 类似ADD,拷贝文件和目录到镜像中,将从构建上下文目录中<源路径>的文件/目录复制到新的一层镜像内的<目标路径> |
CMD | 指定这个容器启动的时候要运行的命令,但只有最后一个生效,CMD会被docker run之后的参数覆盖 |
ENTRYPOINT | 指定这个容器启动的时候要运行的命令,可以追加命令,可以和CMD一起使用,一般时变参才会使用CMD,这里的CMD相当于给ENTRYPOINT传参 |
特殊说明:
1、RUN
参考tomcat的dockerfile文件
默认CMD [“catalina.sh”,“run”] 执行开启tomcat服务
如果运行容器的docker run /bin/bash 会导致覆盖该操作直接进入容器,容器启动了但tomcat没有开启服务
2、ENTRYPOINT
1、创建/myfile目录
2、当前目录引入jdk8.tar.gz
3、创建Dockerfile文件
FROM centos:7
MAINTAINER Laptoy
ENV MYPATH /usr/local
WORKDIR $MYPATH
# 安装vim
RUN yum -y install vim
# 安装ifconfig命令查看网络ip
RUN yum -y install net-tools
# 安装java8及类库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
# 将该压缩包添加到容器中并自动解压
ADD jdk-8u171-linux-x64.tar.gz /usr/local/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
4、在当前目录构建新镜像
docker build -t 新镜像名字:TAG . 注意.不能漏掉
5、启动镜像测试
镜像名和版本为
docker image ls -f dangling=true 查看所有虚悬镜像
docker image prune 删除
2、新建文件夹/mydocker 存放该jar包
3、编写Dockerfile
FROM java:8
MAINTAINER laptoy
VOLUME /tmp
ADD docker-springboot-0.0.1-SNAPSHOT.jar laptoy_docker.jar
RUN bash -c 'touch /laptoy_docker.jar'
ENTRYPOINT ["java","-jar","/laptoy_docker.jar"]
EXPOSE 6001
4、打包为镜像
docker build -t laptoy_docker:2.0 .
当你安装Docker时,它会自动创建三个网络。你可以使用以下docker network ls命令列出这些网络:
[root@server1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
0147b8d16c64 bridge bridge local
2da931af3f0b host host local
63d31338bcd9 none null local
Docker内置这三个网络,运行容器时,你可以使用该–network标志来指定容器应连接到哪些网络。
该bridge网络代表docker0所有Docker安装中存在的网络。除非你使用该docker run --network=选项指定,否则Docker守护程序默认将容器连接到此网络。
为了解决
docker network ls 列出所有
creater xxx 创建
inspect xxx 查看详情
rm xxx 删除
--help
网络模式 | 简介 |
---|---|
Host | 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。 |
Bridge | 此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机通信。默认为该模式 |
None | 该模式关闭了容器的网络功能。 |
Container | 创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围。 |
容器实例内默认IP生产规则
测试:docker容器内部的ip是有可能发生改变的
docker inspect xxx|tail -n 20
1、是什么
Docker服务默认会创建一个docker0网桥,内核层联通了其他的物理或虚拟网卡。Docker默认指定了Docker0的IP地址和子网掩码,让主机和容器可以通过网桥互相通信
2、说明
默认run时使用的就是bridge
网桥dokcer0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配
docker run -d -p 8081:8080 --name centos centos:8
1、说明
相当于Vmware中的桥接模式,与宿主机在同一个网络中,但没有独立IP地址。
众所周知,Docker使用了Linux的Namespaces技术来进行资源隔离,如PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等。
一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离。一个Docker容器一般会分配一个独立的Network Namespace。但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
直接使用宿主机的IP地址与外界进行通信,不需要额外进行NAT转换
容器不会虚拟出自己的网卡而是使用宿主机的IP和端口
2、代码测试
docker run -d -p 8080:8080 --network host --name tomcat tomcat:8
host模式此时-p端口号映射失效,加不加都可以
docker run -d --network host --name tomcat tomcat:8
进入容器查看,网络与主机几乎一样
新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。
被借用的容器停止后借用的容器也失去网络
alpine是一块独立非商业的linux发行版6M左右非常小
借用alpine1的网络
docker run -it --name alpine1 alpine /bin/sh
docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh
禁用网络功能,只有lo(就是127.0.0.1表示本地回环)
该模式将容器放置在它自己的网络栈中,但是并不进行任何配置。实际上,该模式关闭了容器的网络功能,在以下两种情况下是有用的:容器并不需要网络(例如只需要写磁盘卷的批处理任务)。
before
1、运行两个alpine
docker run -it --name alpine1 -d alpine
docker run -it --name alpine2 -d alpine
2、ip addr
查看网络
ip地址可以互相ping通
无法通过服务名ping通
after
1、创建自定义网络模式
docker network creater laptoy_network
2、运行的容器加入网络
docker run -it --network laptoy_network --name alpine1 -d alpine
docker run -it --network laptoy_network --name alpine2 -d alpine
3、通过服务名ping通
采用yml文件实现对Docker集群的快速编排
# GitHub比较慢
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 使用国内仓库
curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
# 设置权限
chmod +x /usr/local/bin/docker-compose
# 查看是否安装成功
docker-compose --version
一文件:docker-compose.yml
两要素:
服务:一个个的应用容器实例
工程:由一组关联的应用容器组成的完整业务单元,在docker-compose.yml 中定义
docker-compose -h # 查看帮助
up # 启动
up-d # 启动并后台运行
down # 停止并删除容器,网络,卷,镜像
exec id # 进入容器内部
ps # 显示当前编排运行过的所有容器
top # 显示当前编排过的容器进程
logs id # 查看容器输出日志
config # 检查配置
config -q # 检查配置,有问题才输出
restart
start
stop
1、运行容器
docker run -p 8000:8000 -p 9000:9000 --name portainer --restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
-d portainer/portainer
2、连接
192.168.88.129:9000
通过docker stats
可以方便地查看当前宿主机的所有容器的CPU,内存及网络数据,但无法存储,没有健康指标
1、通过compose容器编排一键运行
version: '3.1'
volumes:
grafana_data: {}
services:
influxdb:
image: tutum/influxdb:0.9
restart: always
environment:
- PRE_CREATE_DB=cadvisor
ports:
- "8083:8083"
- "8086:8086"
volumes:
- ./data/influxdb:/data
cadvisor:
image: google/cadvisor
links:
- influxdb:influxsrv
command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086
restart: always
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
grafana:
user: "104"
image: grafana/grafana
user: "104"
restart: always
links:
- influxdb:influxsrv
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
environment:
- HTTP_USER=admin
- HTTP_PASS=admin
- INFLUXDB_HOST=influxsrv
- INFLUXDB_PORT=8086
- INFLUXDB_NAME=cadvisor
- INFLUXDB_USER=root
- INFLUXDB_PASS=root
2、后台运行
docker-compose up -d
3、浏览
http://ip:8080/ CAdvisor
http://ip:8083/ InfluxDB
http://ip:3000/ Granfana
4、Granfana配置