Docker实战-高级篇
一、Docker复杂安装
MySQL主从复制
看ShardingSphere一节,已经部署过
1~2亿条数据需要缓存,请问如何设计存储案例
单机单台肯定不可能
哈希取余
哈希取余:优点:简单粗暴,直接有效,只需要预估好机器数,就能保证一段时间的数据支撑;缺点:集群扩缩容麻烦,映射关系需要重新计算;
一致性哈希算法
一致性哈希算法:解决服务器个数变动时的映射关系变化;
需要构建一致性哈希环:
一致性哈希算法必然有个Hash函数并按照算法产生Hash值,这个算法的所有可能哈希值会构成一个全量集,这个集合可以成为一个Hash空间(大概0-2^32-1),这个是一个线性空间,通过适当的逻辑控制使其首位相连,这样在逻辑上形成一个环形空间
它也是按照取模的方法,不过是对2^32取模
第二步是服务器IP节点映射:
将集群中某个IP节点映射到环上的某一个位置,将哥哥服务器使用Hash获得一个哈希值,具体可以使用服务器的IP或者主机名作为关键字进行哈希,这样每台机器都能确定在哈希环上的位置
第三步是key落到服务器上的规则:
当需要存储一个kv对,首先计算key的Hash值,将这个key使用相同的函数hash计算处hash值并确定在此环上的位置,从此位置沿着环顺时针行走,遇到的第一台服务器就是它存储的服务器
优点:
- 解决了哈希取余的容错性:假设某台服务器宕机,只会影响到其前面的那台机器,数据转移到后一台服务器
- 扩展性:扩容后不会影响
缺点:
- 会有数据倾斜问题:当节点太少的情况下,缓存对象会集中缓存到某一台服务器上
哈希槽分区
为了解决一致性哈希算法的数据倾斜问题
哈希槽实质上就是一个数组,数组0,2^14-1形成Hash Slot空间
解决了均匀分配的问题,在数据和节点之间又加入了一层,这层被称为哈希槽,用于管理数据和节点之间的关系,现在就相当于节点上放的是槽,槽里面是数据
槽解决的是粒度问题,相当于把粒度变大了,这样便于数据移动
哈希解决的是映射问题,使用key的哈希值来计算所在的槽,便于数据分配
一个集群只能有16484个槽,便好0-16383,这些槽会集中分配给集群中的所有主节点,分配策略没有要求,可以指定哪些便好的槽分配给哪个主节点,集群会记录节点和槽的对应关系,解决了节点和槽的问题之后,接下来对key进行哈希,然后对16384取余,余数是几,key就落到哪个槽中,以槽为单位移动数据
Redis集群实现
三主三从
创建虚拟网卡,主要用于Redis集群与外界的网络通信,一般常用桥接模式
docker network create --subnet=192.168.100.0/24 rcn
创建redis.conf配置文件:
mkdir docker-redis-cluster && cd docker-redis-cluster
新建6台实例
进入容器,构建集群关系
二、DockerFile解析
介绍
Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需要的指令和参数构成的脚本
Dockerfile构建
步骤:
- 编写Dockerfile文件
- docker build命令构建镜像
- docker run依照镜像运行实例
Dockerfile内容基础知识:
- 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
- 指令按照从上到下顺序执行
- #表示注解
- 每条指令都会创建一个新的镜像层并对镜像进行提交
Docker执行Dockerfile的流程:
- Docker从基础镜像运行一个容器
- 执行一条指令并对容器做出修改
- 执行类似Docker commit的操作提交一个新的镜像层
- docker再基于刚才提交的镜像运行一个新容器
- 执行Dockerfile中的下一条指令直到所有指令都执行完成
从应用软件角度看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个阶段
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署和运维,三者缺一不可
Dockerfile常用保留字
FROM
基础镜像,当前新镜像是基于哪个镜像,指定一个已经存在的镜像作为模板,第一条必须是FROM
MAINTAINER
镜像维护者的姓名和邮箱
RUN
容器构建时运行的命令
两种格式:
- shell格式:RUN后面直接跟命令,如:RUN yum -y install vim
- exec格式:格式:
RUN ["可执行文件", "参数1", "参数2"]
RUN是在docker build时运行的
EXPOSE
当前容器对外暴露的端口
WORKDIR
指定在创建容器后,终端默认登录进来的工作目录
USER
指定该镜像以什么样的用户去执行,如果都不指定,默认是root
ENV
用来在构建镜像过程中设置环境变量
也可以在其他指令中使用这些环境变量
ADD
将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
COPY
类似ADD,拷贝文件和目录到镜像中
COPY src dest
VOLUME
容器数据卷,用于数据保存和持久化工作
CMD
指定容器启动后要干的事情
CMD指令格式与RUN相似
Dockerfile中可以有多个CMD指令,但只有最后一个生效,CMD会被docker run之后的参数替换
和RUN指令的区别:
- RUN是在docker build时运行
- CMD是容器启动后运行
ENTRYPOINT
也是用来指定一个容器启动时要运行的命令
类似于CMD指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当做参数传给ENTRYPOINT指令指定的程序
命令格式:ENTRYPOINT ["<executable>", "param1", ...]
ENTRYPOINT可以和CMD一起使用,一般是变参才会使用CMD,这里的CMD相当于给ENTRYPOINT传参
当指定了ENTRYPOINT之后,CMD的含义就发生了变化
自定义镜像centosjdk8
将centos中具备vim、ifconfig、jdk8等环境
拉取centos镜像
docker pull centos:centos7.9.2009
运行并进入实例:
docker run -it eeb6ee3f44bd /bin/bash
下载jdk
编写Dockerfile文件:vim Dockerfile
FROM centos:centos7.9.2009 MAINTAINER wang<no> ENV MYPATH /usr/local WORKDIR $MYPATH RUN sed -i 's|^mirrorlist=|#mirrorlist=|g' /etc/yum.repos.d/CentOS-Base.repo && \ sed -i 's|^#baseurl=http://mirror.centos.org|baseurl=http://mirrors.aliyun.com|g' /etc/yum.repos.d/CentOS-Base.repo && \ yum clean all && yum -y makecache RUN yum -y install vim RUN yum -y install net-tools RUN yum -y install glibc.i686 RUN mkdir /usr/local/java ADD jdk-8u421-linux-x64.tar.gz /usr/local/java/ ENV JAVA_HOME /usr/local/java/jdk1.8.0_421 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运行构建命令:别忘了后面的.
docker build -t 新镜像名字:TAG .
此时镜像就构建成功了,可以运行一个容器查看
虚悬镜像
仓库名和标签名都是none的镜像,俗称dangling image
通过以下命令查看虚悬镜像:
docker image ls -f dangling=true
通过如下命令删除虚悬镜像:
docker image prune
三、Docker微服务实战
新建一个SpringBoot工程,将其上传到Linux上
编写Dockerfile文件:
FROM openjdk:8u111-jdk
MAINTAINER wang
VOLUME /tmp
ADD docker-demo-0.0.1-SNAPSHOT.jar docker-demo.jar
RUN bash -c 'touch /docker-demo.jar'
ENTRYPOINT ["java", "-jar", "/docker-demo.jar"]
EXPOSE 30000
构建镜像
docker build -t docker-demo:1.0 .
四、Docker网络
介绍
Docker不启动,默认的网络情况:
virbr0:虚拟网桥服务
Docker启动后:
会有一个docker0虚拟网桥
使用命令:docker network ls命令展示docker网络列表:
NETWORK ID NAME DRIVER SCOPE dd18f3c90671 bridge bridge local 6035c624bb1b host host local f546edbfc3ba none null local
docker默认创建3个网络模式
docker网络命令
create:创建网络
rm:删除一个或多个网络
inspect:查看网络情况
ls:展示网络列表
作用
容器间的互联通信以及端口映射
容器IP变动的时候可以通过服务名直接网络通信而不受到影响
网络模式
bridge:桥接,为每一个容器分配、设置IP,并将容器连接到docker0,默认模式
host:容器不会虚拟出自己的网卡,配置自己的IP,而是使用宿主机的IP和端口
none:容器有独立的network namespace,但并没有对其进行任何网络设置
container:新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP、端口范围
使用参数:--network args来指定网络模式
docker容器内IP是会发生变化的
bridge模式
Docker会默认创建一个docker0网桥,其上有个docker0内部接口,它在内核层联通了其他的物理或虚拟网卡,这将所有容器和本地主机都放到了同一个物理网络,Docker默认指定了docker0的IP地址和子网掩码,让主机和容器之间可以通过网桥互相通信
虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
当创建一个 Docker 容器的时候,同时会创建了一对 veth pair接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即 eth0;另一端在本地并被挂载到docker0 网桥,名称以 veth 开头(例如 vethAQI2QT)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker 就创建了在主机和所有容器之间一个虚拟共享网络。

host模式
相当于Vmware中的NAT模式,与宿主机在同一个网络中,但没有独立IP地址。一个Docker容器一般会分配一个独立的Network Namespace。但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。可以通过 --net=host 指定使用 host 网络。

container模式
Docker网络container模式是指定其和已经存在的某个容器共享一个 Network Namespace,此时这两个容器共同使用同一网卡、主机名、IP 地址,容器间通讯可直接通过本地回环 lo 接口通讯。但这两个容器在其他的资源上,如文件系统、进程列表等还是隔离的。

none模式
容器有自己的网络命名空间,但不做任何配置,它与宿主机、与其他容器都不连通的。
这种模式很少用到
自定义网络
不使用自定义网络,使用IP可以相互ping通,但是使用服务名不可以
五、Docker-Compose容器安排
Docker-Compose是Docker官方推出,用于实现对Docker容器集群的快速编排
需要定义一个YAML格式的配置文件,写好多个容器之间的调用关系,然后只要一个命令就可以同时启动或关闭这些容器
最新版的docker安装时会自动以插件的形式安装docker compose
核心概念
一个文件,两个要素
文件是指:docker-compose.yaml
两个要素:
- 服务:一个个容器实例
- 工程:由一组关联的应用容器组成的一个完整业务单元,在docker-compose.yaml中定义
使用步骤:
- 编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
- 使用docker-compose.yaml定义一个完整业务单元,安排好整体应用中的各个容器服务
- 最后,执行docker compose up命令来启动并运行整个应用程序,完成一键部署上线
常用命令
格式:
docker compose [OPTIONS] COMMAND
build:格式为 docker-compose build [options] [SERVICE...],构建(重新构建)项目中的服务容器,服务容器一旦构建后,将会带上一个标记名,例如对于 web 项目中的一个 db 容器,可能是 web_db。
docker compose --help:查看帮助
docker compose up:启动所有docker comose服务
docker compose up -d:启动所有服务并后台运行
docker compose down:停止并删除容器、网络、卷、镜像
docker compose exec yml里面的服务ID:进入容器内部执行yaml中的服务ID /bin/bash
docker compose ps:展示当前编排过的所有运行中的容器
docker compose top:展示运行的容器进程
logs:查看容器输出日志
config -q:检查配置,有问题才输出
config:检查配置
start、stop、restart:启动、停止、重启三板斧
命令选项
-f, --file FILE指定使用的 Compose 模板文件,默认为docker-compose.yml,可以多次指定。-p, --project-name NAME指定项目名称,默认将使用所在目录名称作为项目名。--verbose输出更多调试信息。-v, --version打印版本并退出。
compose模板文件
默认的模板文件:
version: "3"
services:
webapp:
image: examples/web
ports:
- "80:80"
volumes:
- "/data"
注意每个服务都必须通过image指令指定镜像或者build指令(需要Dockerfile)来自动构建生成镜像
如果使用build指令,在Dockerfile中设置的选项将会自动被获取,无需在docker-compose.yaml中重复设置
build指令
指定Dockerfile所在文件夹的路径(可以是绝对路径,或者相对docker-compose.yml文件的路径);compose将会利用它自动构建这个镜像,然后使用这个镜像
也可以使用contex指令指定Dockerfile所在文件夹的路径
使用dockerfile指令指定Dockerfile文件名
使用arg指令指定构建镜像时需要用到的变量
image
指定为镜像名称或者镜像ID,如果镜像在本地不存在,compose会尝试拉取这个镜像
ports
暴露端口信息,可以使用容器端口格式(HOST:CONTAINER),或者仅仅指定容器的端口,宿主机会随机选择端口
注意:当使用 *HOST:CONTAINER* 格式来映射端口时,如果你使用的容器端口小于 60 并且没放到引号里,可能会得到错误结果,因为 *YAML* 会自动解析 *xx:yy* 这种数字格式为 60 进制。为避免出现这种问题,建议数字串都采用引号包括起来的字符串格式。
volumes
数据卷挂载的路径设置,可以设置为宿主机路径或者数据卷名称,并且可以设置访问模式
该指令支持相对路径
volumes:
- /var/lib/mysql
- cache/:/tmp/cache
- ~/configs:/etc/configs/:ro
networks
配置容器连接的网络
version: "3"
services:
some-service:
networks:
- some-network
- other-network
networks:
some-network:
other-network:
container_name
指定容器名称。默认将会使用 项目名称_服务名称_序号 这样的格式。
注意: 指定容器名称后,该服务将无法进行扩展(scale),因为 Docker 不允许多个容器具有相同的名称。
depends_on
解决容器的依赖、启动先后的问题。
注意:web 服务不会等待 redis db 「完全启动」之后才启动。
environment
设置环境变量,可以使用数组或者字典两种格式
只给定名称的变量会自动获取compose主机上对应的变量值,可以用来防止泄漏不必要的数据
如果变量名称或者值中用到 true|false,yes|no 等表达 布尔 含义的词汇,最好放到引号里,避免 YAML 自动解析某些内容为对应的布尔语义。
expose
暴露端口,但不映射到宿主机,只被连接的服务访问。
仅可以指定内部端口为参数
command
覆盖容器启动后默认执行的命令。
六、Portainer
Docker可视化工具
方便管理单机和集群环境