ngxin、redis、docker、k8s等一些知识点

2021-08-11   


负载load average计算原理

计算了 5s 平均的 expoentially-damped moving sums 。最终得到的 1min、5min、15min 的 load averages 反映了超过 1、5、15 分钟的负荷。

Nginx

nginx负载

1、轮询:默认策略,每个请求按时间顺序逐一分配到不同得后端服务器,如果后端服务器down掉,能自动剔除。
2、weight(权重):server后面加上weight后,会指定轮询几率。weight和访问比率成正比,大多用于后端服务器性能				不均匀得情况。
3、ip_hash(访问进来的ip):每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session共享的问题。

nginx负载均衡session问题解决

使用ip_hash解决:
		- ip_hash要求nginx的一定是最前端服务器,否则nginx得不到正确的IP,就不能根据IP作哈希。
		- ip_hash是在upstream模块中配置的。
		缺点:如果后端服务器down掉的话,session的问题又将出现,无法做到真正的高可用。
		  
利用cookie同步:
		- 把用户访问页面产生的session放到客户端的cookie里面。
		缺点:如果客户端把cookie禁掉,那么将会无法进行同步;cookie的安全性不高,可以伪造。
		  
使用memcached:
		- 使用场景有:1、分布式应用。2、数据库前段缓存。3、服务器间数据共享。
		缺点:memcache不能完全利用内存,会产生内存碎片,如果存储块不足,还会产生内存溢出。
			
利用数据库实现:
		- 把产生的session存在数据库里,实现session共享。	
		缺点:用数据库来同步session,会加大数据库的负担,数据库本来就是一个容易产生瓶颈的地方,如果把session还放到数据库里面,那使得这个瓶颈更容易产生。

nginx优化

隐藏版本号				---->	server_tokens off;
最大文件打开数				---->	worker_rlimit_nofile 51200;
与系统的最大文件打开数相关联最大连接数	---->	worker_connections  51200;
不能超过最大文件打开数
打开同时接受多个新网络连接请求的功能  	---->	multi_accept  on;
开启文件高效传输模式			---->  	sendfile  on;
避免网络拥塞		  	        ----> 	tcp_nopush  on;
超时连接					---->	keepalive_timeout  120;
提高数据传输效率				---->	tcp_nodelay  on;

Mysql

mysql常用引擎对比

  • InnoDB:
    1、支持事务。
    2、支持外键约束,不支持全文索引。
    3、可以缓存数据和索引,高效的缓存特性。

  • MyISAM:
    -1、读的速度较快,适合读业务比较多的场景。
    -2、占用的资源比较少。
    -3、支持全文索引,不支持外键约束。

  • TokuDB:
    1、高压缩比
    2、非常快的先写入性能,适合用于记录流水账、日志、历史数据归档等场景。

MySQL优化

最大连接数		---->	max_connections		尽可能大,但最大也只能是三千。
索引缓冲区的大小	        ----> 	key_buffer_size		它决定索引处理的速度,尤其是索引读的速度。
表文件描述符的缓存大小	---->	table_open_cache	打开表后会把表的文件描述符缓存下来。
每表表空间	        ---->	innodb_file_per_table=1	让每个表都有自己的独立表空间,更容易进行维护。
临时表的大小	        ---->	tmp_table_size		也就是内存表,加快查询的速度。
超时时间	                ----> 	wait_timeout		避免数据库长连接

Zookeeper

zookeeper在kafka中的作用

1、Broker注册:在zookeeper上会有一个专门呢用来进行Broker服务器列表记录的节点---/brokers/ids

2、Topic注册:同一个Topic的消息会被分成多个分区并将其分区在多个Broker上,这些分区信息及Broker的对应关系也都是由zookeeper进行维护,由专门的节点来记录,/borkers/topics

3、生产者负载均衡:

4、消费者负载均衡:

5、控制器的选举:控制器负责管理整个集群所有分区和副本的状态,例如某个分区的 leader 故障了,控制器会选举新的 leader。

zookeeper的选举机制

zookeeper 默认的算法是 FastLeaderElection,采用投票数大于半数则胜出
的逻辑。

Kafka

kafka性能

kafka的replication设置为Broker的倍数。
高吞吐量性能。
一生产者可让多个消费者进行消费,一对多。

下面都可以决定Kafka的消费速度:

  • Topic的队列内容长度
  • Topic的消费者的消费能力(数据处理速度)
  • Topic的partition分区数目并增加消费者。

Kafka数据的处理过程

Producer 在 发 布 消 息 到 某 个 Partition 时 , 先 通 过ZooKeeper 找到该 Partition 的 Leader ,然后无论该Topic 的 Replication Factor 为多少(也即该 Partition 有多少个 Replica),Producer 只将该消息发送到该 Partition 的Leader。Leader 会将该消息写入其本地 Log。每个 Follower都从 Leader pull 数据。这种方式上,Follower 存储的数据顺序与 Leader 保持一致。Follower 在收到该消息并写入其Log 后,向 Leader 发送 ACK。一旦 Leader 收到了 ISR 中的所有 Replica 的 ACK,该消息就被认为已经 commit 了,Leader 将增加 HW(HighWatermark)并且向 Producer 发送ACK。

MongoDB

MongoDB分片集群

1、由mongos做路由层,避免了在主从时,所有请求都压在一个节点上的情况,使得压力更均匀。

2、数据都以分布式形式存储,且都有副本。

3、MongoDB支持事务性。

负载

LVS

  • 优点:
    1、抗负载能力强,性能高,能达到F5的60%,对内存和CPU资源消耗比较低;
    2、工作在网络4层,通过VRRP协议(仅作代理之用),具体的流量是由linux内核来处理,因此没有流量的产生;
    3、稳定,可靠性高,自身有完美的热备方案(Keepalived+lvs);
    4、支持多种负载均衡算法:rr(轮询),wrr(加权轮询)、lc(最小连接)、wlc(加权最小连接);
    5、LVS工作模式有4种: (1) nat 地址转换 (2) dr 直接路由 (3) tun 隧道 (4) full-nat;
    6、转发效率和稳定性比nginx和haproxy高。

  • 缺点:
    1、只能做代理使用,只支持四层协议;
    2、不支持正则处理,不支持动静分离。

LVS负载均衡软件常见的调度算法:

  • rr( 轮询算法):根据节点数量,把请求批量一个一个分配给节点,不管服务器性能如何,每个节点接收的请求基本相同。

  • wrr(加权轮询算法):根据不同服务器的性能,分配连接请求不同,性能好的服务器分配的请求多。

  • lc( 最小连接数算法):根据服务器连接请求数量而分配请求数量,服务器连接请求少就分配的请求多。

  • wlc(加权最小连接数算法):智能根据服务器的性能,和响应时间分配的请求多少。

LVS软件在企业架构中的组件位置及作用:

答:LVS一般在企业架构中最前面接收用户请求,它可以接收用户请求,然后根据算法把请求分配给比如nginx代理,充当整个架构的负载均衡的作用。

Haproxy

适用于负载特别大的web网站,可以支持万的并发连接,,可以保护你的web服务器不被暴露到网络上。

  • 优点:
    1、支持虚拟主机;
    2、其优点能够补充Nginx的一些缺点,比如支持Session的保持,Cookie的引导;同时支持通过获取指定的url来检测后端服务器的状态;
    3、跟LVS类似,本身就只是一款负载均衡软件;单纯从效率上来讲Haproxy会比Nginx有更出色的负载均衡速度,在并发处理上也是优于Nginx的;
    4、支持TCP协议的负载均衡转发,可以对MySQL读进行负载均衡,对后端的MySQL节点进行检测和负载均衡,可以用LVS+Keepalived对MySQL主从做负载均衡;
    5、负载均衡策略非常多(8种):roundrobin(轮询),static-rr(权重),leastconn(最少连接者优先处理),source(根据请求源IP),uri(根据请求的URI,做CDN需使用)..........

  • 缺点:
    1、不能做web服务器使用。

Nginx

  • 优点:
    1、对静态页面处理非常高效;
    2、对内存资源占用较小;
    3、可以做web服务器使用,也可以做反向代理,支持lnmp;
    4、支持四层七层转发,对复杂的网络功能得以实现(注:1.9版本后才支持tcp负5、主进程副进程分工明确,主进程接收请求,副进程处理请求,稳定性和高效率;
    6、支持很多模块,比如四层转发,进程数量自定义,最大合理利用cpu;
    7、Nginx对请求的异步处理可以帮助节点服务器减轻负载压力。

  • 缺点:
    1、不支持session会话保持。

总结

nginx

1、工作在网络7层之上,可针对http应用做一些分流的策略,如针对域名、目录结构,它的正规规则比HAProxy更为强大和灵活。
2、Nginx对网络稳定性的依赖非常小。
3、Nginx安装与配置比较简单,测试也比较方便。

LVS

1、抗负载能力强,工作在网络四层,仅作分发作用,没有流量产生,对内存贺cpu资源消耗比较低。
2、配置型低。

HAProxy

HAProxy支持TCP协议的负载均衡转发,可以对MySQL读进行负载均衡。

ELK分布式日志管理系统

1、Filebaet从各个服务器上收集日志到Kafka的Topic中。

2、Logstash从Topic中拿取日志,进行格式转换,推给es。

3、然后由Kibana进行展示。

4、es的索引?
ES如果数据量大过亿的数据时如何调优 数据缓存在磁盘当去搜索的时候才会缓存到Filesystem Cache,ES搜索非常依赖底层的Filesystem Cache,给足够内存它搜索会非常快

  • 1.分片适当减少如1-3个分片
  • 2.优化索引尽量用少的索引去搜索以及写入Filesystemcache中
  • 3.调整JVM的参数给足够内存ES
  • 4.ES默认没开启慢日志 可以通过慢日志查看是索引慢还是搜索慢
  • 5.禁止深度分页 (如果每页10条数据那么第100页时Shard搜寻的数据时1000条)
  • 6.优化查询返回字段减少内存占用
  • 7.禁止用all进行查询
  • 8.32G内存以上给ES提升不是特别大
  • 9.针对久数据做一个保留一个分片作为高可用
  • 10.半年之前的日志做适当的删出

5、ES节点分为主节点 数据节点 客户端节点

Redis

主从复制过程:

  • 从节点执行slaveof[masterIP][masterPort],保存主节点信息
  • 从节点中的定时任务发现主节点信息,建立和主节点的socket连接
  • 从节点发送Ping信号,主节点返回Pong,两边能互相通信
  • 连接建立后,主节点将所有数据发送给从节点(数据同步)
  • 主节点把当前的数据同步给从节点后,便完成了复制的建立过程。接下来,主节点就会持续的把写命令发送给从节点,保证主从数据一致性。

Redis常见的集群架构

  • 1、主从模式

  • 2、主从+哨兵模式

  • 3、三主三从去中心化(此为官方推荐的集群方案)

主从模式

  • 优点:
    可做读写分离,降低主库的压力。

  • 缺点:
    无法保证高可用
    写的压力一直在master上

哨兵模式

哨兵模式是一个分布式系统中监控redis主从服务器,并在主服务器宕机时自动进行故障转移。

  • 优点:
    保证高可用
    监控节点

  • 缺点:
    其本质还是主从模式,切换时需要时间,可能会造成数据丢失
    依然没能解决master写的压力

redis-cluster

cluster模式集群一般由多节点组成,节点数量最少6个,每个master节点都配带一个slave节点

概念:

1)由多个Redis服务器组成的分布式网络服务集群;

2)集群之中有多个Master主节点,每一个主节点都可读可写;

3)节点之间会互相通信,两两相连;

4)Redis集群无中心节点

在Redis-Cluster集群中,可以给每一个主节点添加从节点,主节点和从节点直接遵循主从模型的特性。

当用户需要处理更多读请求的时候,添加从节点可以扩展系统的读性能。

Redis优化

1、尽量使用短key

2、设置key有效期

3、选择合适生产的回收策略

  • volatile-lru :只对设置了过期时间的key进行LRU(默认值)
  • allkeys-lru : 是从所有key里 删除 不经常使用的key
  • volatile-random:随机删除即将过期key
  • allkeys-random:随机删除
  • volatile-ttl : 删除即将过期的
  • noeviction : 永不过期,返回错误

4、当业务场景不需要数据持久化时,关闭所有持久化。

Redis报内存溢出时

1、通过配置参数或命令限制内存大小

2、调整回收策略,例如:把key的过期回收时间调小一些。

Redis为什么快

1、纯内存操作

2、单线程操作,避免了频繁的上下文切换

3、采用了非阻塞I/O多路复用机制

Docker

Docker网络模式

docker有四种模式

  • host:容器和宿主机共享Network namespace。
  • container:容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。
  • none:容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair 和网桥连接,配置IP等。
  • bridge:网桥模式,也是默认模式。

Docker存储模式

  • bind mount :用于将 host 机器的目录 mount 到容器中。
  • volume:volume 是被 docker 管理,docker 会自动创建。

docker容器启动过程

1)客户端向dockerd请求启动容器

2)dockerd向linux内核申请一个空容器

3)linux创建一个只提供了虚拟硬件的空容器(未安装操作系统的裸机),docker通过cgroup实现容器隔离,cgroup同时还提供了限制、记录、隔离进程组 (process groups) 所使用的物理资源 (如 cpu memory i/o 等等) 的机制。另外linux还为这个空容器提供了namespace、文件系统、linux bridge等

4)dockerd检查本地是否有镜像文件,如果没有则会镜像源(私有仓库harbor或公有仓库hub等)下载

5)将镜像文件加载到容器中

限制与隔离

Linux Cgroup

  • Linux Cgroup的全程是Linux Contol Group。它最主要的作用,就是限制ige进程组能够使用的资源上限,包括CPU、内存、磁盘、网络带宽等等。

Linux隔离技术

  • PID Namespace
  • Mount Namespace
  • Net Namespace
  • IPC Namespace
  • User Namespace
  • UTS Namespace
  • Namespace技术实际上修改了应用进程看待整个计算机“视图”,即它的“视线”被操作系统做了限制,只能“看到”某些指定的内容。

常问问题

数据库为什么不建议部署在容器上

首先,Docker的官网也明确声明了不建议把数据库跑在容器上。然后从几个维度去分析。

1、数据不安全

  • 容器随时可以停止、或者删除。当容器被rm掉,容器里的数据将会丢失;
  • 哪怕你把 Docker 数据放在主机来存储 ,它依然不能保证不丢数据;因为Docker volumes 的设计围绕 Union FS 镜像层提供持久存储,但它仍然缺乏保证;使用当前的存储驱动程序,Docker 仍然存在不可靠的风险。 如果容器崩溃并数据库未正确关闭,则可能会损坏数据。
  • 另外,容器里共享数据卷组,对物理机硬件损伤也比较大。

2、性能问题

  • 拿MySQL举例子:MySQL 属于关系型数据库,对IO要求较高。当一台物理机跑多个时,IO就会累加,导致IO瓶颈,大大降低 MySQL 的读写性能。

3、网络问题

  • 维护成本高:您必须对网络虚拟化有深入的了解。也必须准备应付好意外情况。你可能需要在没有支持或没有额外工具的情况下,进行 bug 修复。

4、资源隔离

  • 资源隔离方面:Docker是利用Cgroup实现资源限制的,只能限制资源消耗的最大值,而不能隔绝其他程序占用自己的资源;如果其他应用过渡占用物理机资源,将会影响容器里 MySQL 的读写效率。
  • 额外说一句,这方面Docker确实不如KVM。

Kubernetes

k8s运行原理

Kubernetes(k8s)是跨主机集群的自动部署、扩展以及运行应用程序容器的开源平台,这些操作包括部署,调度和节点集群间扩展。

k8s是用于自动部署、扩展和管理容器化(containerized)应用程序的开源系统。

用法:

  • 自动化容器的部署和复制

  • 随时扩展或收缩容器规模

  • 将容器组织成组,并且提供容器间的负载均衡

  • 很容易地升级应用程序容器的新版本

  • 提供容器弹性,如果容器失效就替换它

Kubernetes组件

  • apiserver:整个集群的统一入口,所有组件,以及包括配置 RBAC 授权的 Pod,都需要通过 apiserver 跟整个集群进行通信。
  • scheduler:负责根据用户预设的污点、容忍、亲和、反亲和、资源申请等情况,再通过自己的预选和优选策略,把 Pod 分配到合适的 node 节点上。
  • controller-manager:控制器有很多,namespace controller、pod controller、node controller等,主要是为了控制 Pod 维持在一个期望值上。
  • kubelet:负责跟底层容器交互,通过与 apiserver 通信获取集群信息,根据信息拉起或者杀死容器。
  • kube-proxy:实现集群网络调度功能,通过 apiserver 把策略写入 etcd,并根据 etcd 储存的信息修改网络调度策略(ipvs 或者 iptables)

Kubernetes内部开放接口

  • CRI,容器运行时接口,提供计算资源
  • CNI,容器网络接口,提供网络资源
  • CSI,容器存储接口,提供存储资源

Kubernetes Master

Master指的是集群控制节点。每个K8s集群里需要有一个Ms节点负责整个集群的管理和控制。Kubernetes Master提供集群的独特视角,并且拥有一系列组件。

Kubernetes API Server(kube-apiserver),提供HTTP Rest接口的关键服务进程,是K8s里所有资源的增删改查等操作的唯一入口,也是集群控制的入口进程。API Server提供可以用来和集群交互的Rest端点。

Kubernetes Controller Master(kube-controller-manager)负责维护集群的状态,比如故障检测、自动扩展、滚动更新等;

Kubernetes Scheduler(kube-scheduler)负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器上;

Node

(1) Kubelet:与Master节点协作,是主节点的代理,负责Pod对应容器的创建,启动,停止等任务。默认情况下Kubelet会向Master注册自己。Kubelet定期向主机点汇报加入集群的Node的各类信息。

(2) Kube-proxy:Kubernetes Service使用其将链接路由到Pod,作为外部负载均衡器使用,在一定数量的Pod之间均衡流量。比如,对于负载均衡Web流量很有用。

(3) Docker或Rocket:Kubernetes使用的容器技术来创建容器。

Pod

Pod是K8s最重要也是最基础的概念!

每个Pod都有一个特殊的被称为“根容器”的Pause容器,此容器与引入业务无关并且不易死亡。且以它的状态代表整个容器组的状态!

Pause容器对应的镜像属于K8s平台的一部分,除了Pause容器,每个Pod还包含一个或多个用户业务容器。

Pod其实有两种类型:普通的Pod及静态Pod(static Pod),static Pod并不存放在Kubemetes的eted存储里,而是存放在某个具体的Node上的一个具体文件中,并且只在此Node上启动运行。而普通的Pod一旦被创建,就会被放入到etcd中存储,确后会被KubernetesMaster调度到某个具体的Node上并进行绑定(Binding),随后该Pod被对应的Node上的kubelet进程实例化成一组相关的Docker容器并启动起来。

在默认情况下,当Pod里的某个容器停止时,Kubemetes会自动检测到这个问题并且重新启动这个Pod(重启Podel)的所有容器),如果Pod所在的Node完机,则会将这个Node上的所有Pod重新调度到其他节点上。

同一个Pod里的容器共享同一个网络命名空间,可以使用localhost互相通信。

Lable

Lable类似Docker中的tag,一个是对“特殊”镜像、容器、卷组等各种资源做标记,一个是attach到各种诸如Node、Pod、Server、RC资源对象上。不同的是Lable是一对键值对!Lable类似Tag,可使用K8s专有的标签选择器(Label Selector)进行组合查询。

Replication Controller

  • Replication Controller,简称RC,用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的 Pod 来替代。
  • ReplicaSet,简称 RS,RS 全面替换了 RC ,因为 RS 支持集合操作,Deployment 来控制 RS 去创建 Pod,更新完毕之后,老的 RS 并不会删除,只是停用,方便后面回滚使用。

Service

每个Pod都会被分配一个单独的IP地址,而且每个Pod都提供了一个独立的Endpoint(Pod lP + ContainerPort)以被客户端访问,现在多个Pod副本组成了一个集群来提供服务,客户端要想访问集群,一般的做法是部署一个负载均衡器(软件或硬件),为这组Pod开启一个对外的服务端口如8000端口,并且将这些Pod的Endpoint列表加入8000端口的转发列表中,客户端就可以通过负载均衡器的对外IP地址 + 服务端口来访问此服务,而客户端的请求最后会被转发到哪个Pod,则由负载均衡器的算法所决定。

kube-proxy:

  • 1)iptables

  • 2)ipvs

pod网络模式

  • hostPort 不用创建svc,只在容器上面监听端口

  • hostNetwork 同上

  • nodePort 创建svc,会监听所有节点上的端口,service端口范围:30000-32767

  • externalIPs 创建svc,但是可以限定node ip地址来只监听node地址上面得端口

CNI网络插件

Flannel 有三种工作模式:

  • vxlan:隧道方案(默认模式)
  • host-gw:路由方案
  • directrouting(vxlan+host-gw):把前面两个结合起来使用。

pod状态

  • Pending:Pod 已被 K8s 系统接受,但有一个或者多个容器尚未创建亦未运行,此阶段包括等待 Pod 被调度 的时间和通过网络下载镜像的时间。

  • Running:Pod 已经绑定到了某个节点,Pod 中所有的容器已经被创建。至少有一个容器仍在运行,或者处 于启动或重启状态。

  • Succeeded:Pod 中所有的容器已经成功终止,并且不会再重启。

  • Failed:Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器时非0状态退出 或者被系统终止的。

  • Unknown:因为某些原因无法取得 Pod 的状态,这种情况通常因为与 Pod 所在的主机通信失败。

一旦调度器将 Pod 分派给某个节点, kubelet 就通过容器运行时为 Pod 创建容器,容器的状态有三种:Waiting(等待)、Running(运行中)和 Terminated(已终止)。

容器探针

Probe 是由 kubelet 对容器执行的定期诊断。有三种类型的处理程序:

  • ExecAction:在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
  • TCPSocketAction:对容器的 IP 地址上的指定端口执行 TCP 检查。如果端口打开,则诊断被认为是成功的。
  • HTTPGetAction:对容器的 IP 地址上指定端口和路径执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。

每次探测都将获得一下三种结果之一:

  • Success:容器通过了诊断。
  • Failure:容器未通过诊断。
  • Unknown:诊断失败,因此不会采取任何行动。

针对运行中的容器, kubelet 可以选择是否执行以下三种探针,以及如何针对探测结果作出反应:

  • livenessProbe:指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将根据其重启策略决定未来。如果容器不提供存活探针,则默认状态未 Success。
  • readinessProbe:指示容器是否准备好为请求提供服务,如果就绪态探测失败,端点控制器将从与 Pod 匹配的所有服务的端点列表删除该 Pod 的 IP 地址。初始延迟之前的就绪态的状态值默认为 Failure。如果容器不提供就绪态探针,则默认状态为 Success。
  • startupProbe:指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被禁用,直到探针成功为止。如果启动探测失败,kubelet 将杀死容器,而容器依其重启策略进行重启。如果容器没有提供启动探测,则默认状态为 Success。

k8s中得三种“IP”

  • 1>Node IP : Node节点的IP地址
    Node IP是Kubernetes集群中每个节点(服务器)物理网卡的IP地址,这是一个真实存在的物理网络(也可能是虚拟机网络),每个节点(服务器)之间可以通过这个网络通信,Kubernetes集群外的机器与集群内的机器也是通过这个网络通信。

  • 2>Pod IP:Pod的IP地址
    Pod IP是每个Pod 的IP地址,它是Docker Engine根据docker0网络的IP段进行分配的,通常是一个虚拟的二层网络,默认Kubernetes集群内不同Node上的Pod是不能通信的,需要对集群网络进行管理,确保Pod之间可以互相通信,Pod之前的通信是通过Node IP 物理网卡转发出去的。

  • 3>Cluster IP : Service 的IP地址
    Servicede Cluster IP,这是虚拟IP,只作用于Service这个对象,由kubernetes管理和分配。Cluster Ip 无法被ping,因为没有一个“实体网络对象”来响应。
    Cluster IP 只能结合Service Port组成具体的通信端口,他们属于kubernetes集群这样的一个封闭空间,集群之外的节点如果需要访问,需要特殊在处理。
    为了让集群外的用户或节点访问Service(微服务),需要给微服务制定NodePort,从而可以通过Node IP+ NodePort来访问。

k8s中遇到的问题

redis-cluster

  • 背景:一次 Redis 迁移改造上 k8s 中出现的问题,测试发现 k8s 集群外部连接 redis-cluster 时,插入数据进行测试时连接时常不可达,k8s集群内部访问无任何问题。

  • 经查阅资料以及按自己经验思考发现,是外部连接上 redis-cluster 后,当 redis-cluster 返回响应消息后,带的 IP 是 pod ip,外部再想沟通时,是直接通过获取 pod ip 进行连接,此时因为 k8s 集群外部不能直接访问到 pod ip,所以出现了连接不可达报错。

  • 然后查到解决办法:在 github 上有一个 redis-cluster-proxy 项目可以解决这个现象,部署上去后的连接流程是 clinet ---> redis-cluster-proxy ---> reids-cluster ,需要把 redis-cluster-proxy 以 nodeport 方式部署在 k8s 集群内,如果不想用 nodeport 方式,则需要在上层加一个 svc 访问入口;整一个握手流程是 clinet --->redis-cluster-proxy ---> redis-cluster,redis-cluster ---> redis-cluster-proxy ---> clinet。

步骤:

# 拉取github上的代理项目
]# git clone https://github.com/RedisLabs/redis-cluster-proxy.git

# 安装5.0以上版本的gcc
]# yum -y install centos-release-scl
]# yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
]# scl enable devtoolset-9 bash  # 此为临时环境

# 修改配置文件,配置redis-cluster-svc的入口
]# cd redis-cluster-proxy
]# make install
]# vim proxy.conf
cluster redis-cluster:6379		# 此处修改为svc-name:port
]# nohup ./src/redis-cluster-proxy -c proxy.conf >> output.log 2>&1 &
]# ss -nlpt 	# 默认是7777端口,查看开启了就没问题了

# 接下来是把该镜像暴露连接方式让外部程序能够连接上,此处我用的是nodeport方式暴露
]# kubectl expose pods centos --port=7777 --type=NodePort --target-port=7777 --name=centos

# 集群外部程序连接的方式
]# redis-cli -h <IP> -p <port>

滚动更新时,服务有可能出现报错

  • 背景:在业务程序版本更新时,业务持续访问,经常出现访问502报错,此时达不到客户无感知更新的效果。

  • 经查资料找到原因:apiserver 接收到指令,要更新指定 pod 时,会异步的分别指挥 pod 控制器与 service ,这时可能出现的是, service 上的 Endpoints 还没来得及剔除 更新时的 pod ip ,而 pod 已经关闭了,此时流量依然可能分发到关闭了的 pod ;这就导致了业务在更新时访问报错。

  • 解决方法:在 pod 的 yaml 文件上加上一段就绪态探针以及优雅退出的设定,接到退出指令时,先 showdown 程序,然后 sleep 30 左右,另外还要加上一个 grace period (最多可以容忍的时间)防止 pod 卡死,处理不了优雅退出命令或操作,超过这个时间,k8s 会强制 kill pod ;然后在启动一个新的Pod 时,会有一步就绪探针进行探测容器的端口、或者命令执行成功后,才开始向 Pod 发送请求流量。

  • 可参考地址:https://www.kubernetes.org.cn/7714.html

修改Pod配置:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: default
spec:
  containers:
  - name: nginx
    image: nginx
    # 存活检测
    livenessProbe:
      failureThreshold: 3
      initialDelaySeconds: 30
      periodSeconds: 30
      successThreshold: 1
      tcpSocket:
        port: 5084
      timeoutSeconds: 1
    # 就绪检测
    readinessProbe:
      failureThreshold: 3
      initialDelaySeconds: 30
      periodSeconds: 30
      successThreshold: 1
      tcpSocket:
        port: 5084
      timeoutSeconds: 1
    # 优雅退出
    lifecycle: 
      preStop: 
        exec: 
          command: 
          - sleep
          - 30
  terminationGracePeriodSeconds: 60

添加上优雅退出后即可达到零中断更新服务。

在无法访问的node上、Pod在超时后不会飘移到其他节点运行

1、kubernetes(1.5版本或者更新版本)不会因为一个节点无法访问而删除Pod。在无法访问的节点上运行的Pod在超时后会进入‘Terminating’或者'Unknown'状态。当用户尝试体面的删除无法访问的节点上的Pod时,Pod也可能会进入这些状态。从API服务器上删除处于这些状态的Pod的仅有可行方法如下:

  • 删除Node对象(要么你来删除,要么节点控制器删除)
  • 无响应节点上的kubelet开始响应,杀死Pod并从API服务器上移除Pod对象
  • 用户强制删除Pod

Spring Cloud --> Service Mesh

Isitio

目前Service Mesh(服务网格)是呼声最高的具体落地实现的一种。它是一个完全开源的服务网格,可以透明地分层到现有的分布式应用程序上。Isito的多样化功能使你能够成功高效的运行分布式微服务架构,并提供保护、连接和监控微服务的统一方法。

###Spring Cloud 与 Isito 功能对比

以下除了特殊说明,默认 Isito in kubenetes

服务注册与发现:

Spring Cloud :Eureka(服务注册中心)进行服务发现。

Isito:基于XDS接口获取服务信息,并依赖 “虚拟服务路由表” 实现服务发现。

配置中心:

Spring Cloud:config(配置中心)进行实现。

Isito:kubenetes 的 configmap 进行实现。

Q.E.D.