K8S基础

Posted 顿悟树下你和我

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了K8S基础相关的知识,希望对你有一定的参考价值。

dashboard登录秘钥查看

kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep kubernetes-dashboard-admin-token | awk 'print $1')
eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZC1hZG1pbi10b2tlbi1ncmc2NiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZC1hZG1pbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjJkMDE0ZTVmLThjY2EtMTFlYS04MmExLTAwNTA1NjI0YjJhZCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlLXN5c3RlbTprdWJlcm5ldGVzLWRhc2hib2FyZC1hZG1pbiJ9.lj8wYI4iN7TKKQoXzWus4nSE52RUSsfs1GUIwIoWXdkEmOhxjq4Y0mGlZi7Ktem8TGhzwsGpxhdgNtCBkSbo8DzwJxNZJNVZtbm4tjRj1e2QIQ1ZvdJjbIrC1PsX_4FXzsCj7BpTvujRHiQm_65EXt-gLDLHV5d5ohQ1QS-4a79RkEG4gXkvRfir3hkHCZar3JEG0QiXmwLlyi_VXVLl2Gqs2WSQVF0-PKjFdDDrczvb-C2iXZGSSfHwBdbmSg1u80Gf8kbIo3pTqEmy9z3j1ICVz0RIxuEQVgRP0AL092oziWPPGdlnbPK3hl_Wg67Q1hHe-EaTdtgVfgGGEqfzGQ

k8s与docker区别

docker部署mysql挂载本地就可以

k8S部署mysql需要有持久卷pv,需要把mysql文件挂载到持久卷上,因为pod可能会在任意一个节点

configmap pod的应用程序配置文件

容器->pod->rs->deploy->services

rc保证了pod运行的副本数

deploy保证了软件的升级与更新,回滚,参考 https://www.jianshu.com/p/6fd42abd9baa

K8S 端口

组件端口参数默认值协议必须开启说明
kube-apiserver安全端口–secure-port6443HTTPS-
kube-apiserver非安全端口–insecure-port8080HTTP否,0表示关闭deprecated
kubelet健康检测端口–healthz-port10248HTTP否,0表示关闭-
kube-proxy指标端口–metrics-port10249HTTP否,0表示关闭-
kubelet安全端口–port10250HTTPS认证与授权
kube-scheduler非安全端口–insecure-port10251HTTP否,0表示关闭deprecated
kube-controller-manager非安全端口–insecure-port10252HTTP否,0表示关闭deprecated
kubelet非安全端口–read-only-port10255HTTP否,0表示关闭-
kube-proxy健康检测端口–healthz-port10256HTTP否,0表示关闭-
kube-controller-manager安全端口–secure-port10257HTTPS否,0表示关闭认证与授权
kube-scheduler安全端口–secure-port10259HTTPS否,0表示关闭认证与授权

参考官网

https://kubernetes.feisky.xyz/concepts/components

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PQOU7ov0-1680158062096)(pic/K8S基础/image-20210222165810020.png)]

K8S常用命令

kubectl 命令行的语法

kubectl [command][TYPE] [NAME]

command: 例如create,delete,describe ,get ,apply ,label 等

常用操作

查看pod
kubectl get pod  podname  -n <namespaces>
进入pod容器中
kubectl exec -it podname /bin/bash
查看pod描述
kubectl describe  po  podname 
kubectl delete pod PODNAME --force --grace-period=0
查看日志
	1、查看指定pod的日志
	kubectl logs -f <pod_name>
	2、查看指定多个容器的pod中指定容器的日志
	kubectl logs <pod_name> -c <container_name>
	
	
创建应用
	kubectl create -f deployment.yaml
删除应用
	kubectl delete -f deployment.yaml
查看节点 标签
kubectl get node/po/svc --show-labels


文件拷贝  注意 拷贝出来要指定文件吗
kubectl cp $podname:/opt/test.tar  -c $container /bml_data/wjl/test.tar


kubectl输出格式
 kubectl 命令可以用多种格式对结果进行显示,输出的格式通过-o参数指定:

$ kubectl [command][TYPE] [NAME] -o=<output_format>
 根据不同子命令的输出结果,可选的输出格式如表2.12所示。

输出格式 说明
-o=custom-columns= 根据自定义列名进行输出,以逗号分隔
-o=custom-colimns-file= 从文件中获取自定义列名进行输出
-o=json 以JSON格式显示结果
-o=jsonpath= 输出jsonpath表达式定义的字段信息
-o=jsonpath-file= 输出jsonpath表达式定义的字段信息,来源于文件
-o=name 仅输出资源对象的名称
-o=wide 输出额外信息。对于Pod,将输出Pod所在的Node名
-o=yaml 以yaml格式显示结果

K8S高可用俩种方式

keepallived

对外暴露一个keepalived的虚拟ip(vip),这样数据会按照权重走到master,

master本地进行haproxy代理,负载均衡转发到三个master节点,这样就是实现了k8s高可用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XlI0IhVZ-1680158062096)(./pic/K8S技术总结.assets/k8s高可用架构.png)]

利用k8s自身

kubectl label nodes node-1 node-role.kubernetes.io/master=
kubectl label nodes node-2 node-role.kubernetes.io/node=
kubectl label nodes node-3 node-role.kubernetes.io/node=

K8S 架构 与组件

架构图

架构一

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GOLJnfQE-1680158062097)(pic/K8S技术总结.assets/1349539-20190119143437957-1879674594.png)]

架构二

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hr15l0rM-1680158062097)(pic/K8S技术总结.assets/k8s.jpg)]

架构三

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jwl170rX-1680158062097)(pic/K8S技术总结.assets/architecture.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-axOnuX1j-1680158062098)(pic/K8S技术总结.assets/o7leok.png)]

K8S基本组件

以下是k8s全部组件

default       myapp-deploy-5df64577c-4t8jf     1/1       Running   1          79d
default       myapp-deploy-5df64577c-rcsd7     1/1       Running   1          78d
default       nginx-56f766d96f-6vrxc           1/1       Running   1          79d
kube-system   etcd-node-1                      1/1       Running   16         92d
kube-system   kube-apiserver-node-1            1/1       Running   17         92d
kube-system   kube-controller-manager-node-1   1/1       Running   18         92d
kube-system   kube-dns-86f4d74b45-7qwtj        3/3       Running   3          79d
kube-system   kube-flannel-ds-amd64-k584w      1/1       Running   21         92d
kube-system   kube-flannel-ds-amd64-mwh6l      1/1       Running   19         92d
kube-system   kube-flannel-ds-amd64-wkmrd      1/1       Running   15         92d
kube-system   kube-proxy-qfgwg                 1/1       Running   17         92d
kube-system   kube-proxy-sd4pv                 1/1       Running   15         92d
kube-system   kube-proxy-vxhv9                 1/1       Running   19         92d
kube-system   kube-scheduler-node-1            1/1       Running   16         92d

Master 组件:

kube-apiserver

如下可以看出只有一个容器

kube-system   kube-apiserver-node-1            1/1       Running   17         92d

如果有三个 主节点

kube-system   kube-apiserver-node-1            1/1       Running   17         92d
kube-system   kube-apiserver-node-2            1/1       Running   17         92d
kube-system   kube-apiserver-node-3            1/1       Running   17         92d

Kubernetes API 集群的统一入口,各组件的协调者,以RESTful API提供接口方式,所有的对象资源(比如pod,svc,pv等等)的增删改查和监听操作都交给APIServer处理后再提交给etcd数据库做持久化存储。

​ APIServer负责对外提供RESTful的Kubernetes API服务,它是系统管理指令的统一入口,任何对资源进行增删改查的操作都要交给APIServer处理后再提交给etcd。

kubectl是直接和APIServer交互的(Kubernetes提供的客户端工具,该工具内部就是对Kubernetes API的调用)。

只有API Server与存储通信,其他模块通过API Server访问集群状态。这样第一,是为了保证集群状态访问的安全。第二,是为了隔离集群状态访问的方式和后端存储实现的方式:API Server是状态访问的方式,不会因为后端存储技术etcd的改变而改变。加入以后将etcd更换成其他的存储方式,并不会影响依赖依赖API Server的其他K8s系统模块。

Kube-controller-manager

每一个主节点都有一个

kube-system   kube-controller-manager-node-1   1/1       Running   18         92d

处理集群中常规后台任务,一个资源对应一个控制器,而controllerManager就是负责处理这些控制器的

kube-scheduler

每一个主节点都有一个

kube-system   kube-scheduler-node-1            1/1       Running   16         92d

根据调度算法为新创建的pod选择一个Node节点,可以任意部署,可以部署在同一个节点上,也可以部署在不同的节点上

etcd

分布式键值存储系统,用于保存集群状态数据,比如Pod,Service等对象信息

kube-system   etcd-node-1                      1/1       Running   16         92d

Node组件:

kubelet

查看日志

journalctl -xefu kubelet
systemctl start kubelet;

kubelet 是Master在Node节点上的Agent,管理本机运行容器的生命周期,比如创建容器,Pod挂载数据卷,下载secret,获取容器和节点状态等工作,kubelet 将每个Pod转换成一组容器

​ kubelet是node的agent,当Scheduler确定在某个Node上运行Pod后,会将Pod的具体配置信息(image、volume等)发送给该节点的kubelet,kubelet会根据这些信息创建和运行容器,并向master报告运行状态。

​ 在每个节点(node)上都要运行一个 worker 对容器进行生命周期的管理,这个 worker 程序就是kubelet。kubelet的主要功能就是定时从某个地方获取节点上 pod/container 的期望状态(运行什么容器、运行的副本数量、网络或者存储如何配置等等),并调用对应的容器平台接口达到这个状态。kubelet 还要查看容器是否正常运行,如果容器运行出错,就要根据设置的重启策略进行处理。kubelet 还有一个重要的责任,就是监控所在节点的资源使用情况,并定时向 master 报告。知道整个集群所有节点的资源情况,对于 pod 的调度和正常运行至关重要。

kube-proxy:

在Node节点上实现Pod网络代理,维护网络规则和四层负载均衡工作。实现让Pod节点(一个或者多个容器)对外提供服务

​ service在逻辑上代表了后端的多个Pod,外借通过service访问Pod。service接收到请求就需要kube-proxy完成转发到Pod的。每个Node都会运行kube-proxy服务,负责将访问的service的TCP/UDP数据流转发到后端的容器,如果有多个副本,

kube-proxy会实现负载均衡,有2种方式:LVS或者Iptables

Cluster IP是怎么被kube-proxy管理的

​ 每个节点(node)都有一个组件kube-proxy,实际上是为service服务的,通过kube-proxy,实现流量从service到pod的转发

它负责TCP和UDP数据包的网络路由,kube-proxy也可以实现简单的负载均衡功能。其实就是管理service的访问入口,包括集群内Pod到Service的访问和集群外访问service。 kube-proxy管理sevice的Endpoints,该service对外暴露一个Virtual IP,也成为Cluster IP, 集群内通过访问这个Cluster IP:Port就能访问到集群内对应的serivce下的Pod。

​ kube-proxy通过查询和监听API server中service和endpoint的变化。为每个service都建立了一个服务代理对象。并自动同步。服务代理对象是proxy程序内部的一种数据结构,它包括一个用于监听此服务请求的socketserver,socketserver的端口是随机选择的一个本地空闲端口。此外,kube-proxy内部也创建了一个负载均衡器-LoadBalancer,LoadBalancer上保存了service到对应的后端endpoint列表的动态转发路由表。而具体的路由选择则取决于Round Robin负载均衡算法及service的session会话保持这两个特性。

docker或rocket

容器引擎,运行容器

kube-dns

每个node节点都有一个

在k8s中使用Calico或者Flannel这种网络通信方案,这个方案提供了k8s集群中所有pod的ip互相通信的解决方案。
优点:简单
缺点:pod重启之后,ip是重新自动获取,不是pod的唯一标识

k8s提供的DNS名称和k8s集群默认的集群名字有关系,默认k8s集群的域名为cluster.local,则所有DNS的全名称都会以cluster.local为后缀。

服务注册过程指的是在服务注册表中登记一个服务,以便让其它服务发现。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HFDUAKTz-1680158068161)(null)]

Kubernetes 使用 DNS 作为服务注册表。

为了满足这一需要,每个 Kubernetes 集群都会在 kube-system 命名空间中用 Pod 的形式运行一个 DNS 服务,通常称之为集群 DNS。

kube-flannel

每个node节点都有一个

K8S原理

服务自动发现与DNS解析

因为Pod存在生命周期,有销毁,有重建,无法提供一个固定的访问接口给客户端。并且可能同时存在多个副本的。

kubernetes服务发现
1.环境变量:

Pod创建的时候,服务的ip和port会以环境变量的形式注入到pod里,比如pod创建时有一个redis-master服务,服务ip地址是10.0.0.11,port是6379,则会把下面一系列环境变量注入到pod里,通过这些环境变量访问redis-master服务。

REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
2.dns:

K8s集群会内置一个dns服务器,service创建成功后,会在dns服务器里导入一些记录,想要访问某个服务,通过dns服务器解析出对应的ip和port,从而实现服务访问

bml的服务发现方式
bml@instance-q2pzfrcc bin]$ curl bml-image:8086
"code":"AuthenticateError","message":"User authentication failed"[bml@instance-q2pzfrcc bin]$ 
[bml@instance-q2pzfrcc bin]$ env | grep  image
[bml@instance-q2pzfrcc bin]$ env | grep  IMAGE
BML_IMAGE_SERVICE_PORT=8086
BML_IMAGE_PORT_8086_TCP=tcp://10.233.23.206:8086
BML_IMAGE_PORT_8086_TCP_PROTO=tcp
BML_IMAGE_SERVICE_PORT_LISTEN=8086
BML_IMAGE_PORT=tcp://10.233.23.206:8086
BML_IMAGE_PORT_8086_TCP_PORT=8086
BML_IMAGE_PORT_8086_TCP_ADDR=10.233.23.206
BML_IMAGE_SERVICE_HOST=10.233.23.206
[bml@instance-q2pzfrcc bin]$ ping  bml-image
PING bml-image.default.svc.cluster.local (10.233.23.206) 56(84) bytes of data.
64 bytes from bml-image.default.svc.cluster.local (10.233.23.206): icmp_seq=1 ttl=64 time=0.077 ms
64 bytes from bml-image.default.svc.cluster.local (10.233.23.206): icmp_seq=2 ttl=64 time=0.051 ms
64 bytes from bml-image.default.svc.cluster.local (10.233.23.206): icmp_seq=3 ttl=64 time=0.052 ms
^C
--- bml-image.default.svc.cluster.local ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2032ms
rtt min/avg/max/mdev = 0.051/0.060/0.077/0.012 ms
[root@instance-q2pzfrcc ~]# kubectl get cm bml-image-config -o yaml 
apiVersion: v1
data:
  server.conf: |
    --env=private
    --listen-port=8086
    --run-mode=debug
    --audit-log-path=log/bml-image.AUDIT
    --log-level=DEBUG

    --docker-registry-addr=10.233.0.100:5000
    --docker-registry-auth=787f5fe5195c40ef924ac8d67948e15a
    --docker-registry-api-version=v2
    --docker-api-version=1.32
    --docker-image-max-size-gb=100
    --image-build-type=DockerfileBuild,NotebookExport,TarPackageLoad
    --docker-daemon-image=10.233.0.100:5000/docker:rootless
    --user-id-in-k8s-job=601

    --k8s-config=conf/kube.config
    --local-storage-path=/mnt/docker-build

    --auth-host=bml-user-manager
    --auth-port=8080
    --auth-conn-timeout-in-seconds=10

    --image-server-access-key=9dd19a75-bc25-11e8-b3b2-90e2ba1fdc4c
    --image-server-secret-key=9dd19a75-bc25-11e8-b3b2-90e2ba1fdc4c

    --mysql-host=10.233.10.1
    --mysql-port=8806
    --mysql-user=bdl
    --mysql-password=Bdl@Ape2018
    --mysql-database=ape_online
    --mysql-driver-params=charset=utf8

    --storage-service-host=bml-unified-storage
    --storage-service-port=8813
    --storage-service-timeout=10

    --notebook-service-host=bml-notebook-svc
    --notebook-service-port=8097
    --notebook-service-timeout=10

    --resource-service-host=bml-resource
    --resource-service-port=8448
    --resource-service-timeout=10

    --service-authentication-endpoints=192.168.0.4:8081
kind: ConfigMap
metadata:
  creationTimestamp: "2020-10-29T08:06:52Z"
  name: bml-image-config
  namespace: default
  resourceVersion: "9401369"
  selfLink: /api/v1/namespaces/default/configmaps/bml-image-config
  uid: 7dd20a09-e87d-4bd8-8890-34b909e24592	

可以看出bml是通过dns来实现服务访问,因为代码里面读取的resource-service-host与端口的配置进行服务的访问。

dns解析

pod的dns解析

https://kubernetes.io/zh/docs/concepts/services-networking/dns-pod-service/

在集群中定义的每个 Service(包括 DNS 服务器自身)都会被指派一个 DNS 名称。

“正常” Service会以 my-svc.my-namespace.svc.cluster.local 这种名字的形式被指派一个 DNS A 记录。这会解析成该 Service 的 Cluster IP。

默认k8s集群的域名为cluster.local

k8s为service资源分配了DNS名称,通过DNS名称可以访问到service对用的pod。而通过statefulset创建的pod,并依赖service headless能实现给statefulset管理的pod提供固定的DNS名称pod-name.service-headless-name.namespace.svc.cluster-domain.example

参考https://blog.51cto.com/leejia/2584207

K8S证书

先从Etcd算起:

1、Etcd对外提供服务,要有一套etcd server证书

2、Etcd各节点之间进行通信,要有一套etcd peer证书

3、Kube-APIserver访问Etcd,要有一套etcd client证书

再算kubernetes:

4、Kube-APIserver对外提供服务,要有一套kube-apiserver server证书

5、kube-scheduler、kube-controller-manager、kube-proxy、kubelet和其他可能用到的组件,需要访问kube-APIserver,要有一套kube-APIserver client证书

6、kube-controller-manager要生成服务的service account,要有一对用来签署service account的证书(CA证书)

7、kubelet对外提供服务,要有一套kubelet server证书

8、kube-APIserver需要访问kubelet,要有一套kubelet client证书

#一般key是私钥,crt是公钥																																											

加起来共8套,但是这里的“套”的含义我们需要理解。

同一个套内的证书必须是用同一个CA签署的,签署不同套里的证书的CA可以相同,也可以不同。例如,所有etcd server证书需要是同一个CA签署的,所有的etcd peer证书也需要是同一个CA签署的,而一个etcd server证书和一个etcd peer证书,完全可以是两个CA机构签署的,彼此没有任何关系。这算两套证书。

为什么同一个“套”内的证书必须是同一个CA签署的

原因在验证这些证书的一端。因为在要验证这些证书的一端,通常只能指定一个Root CA。这样一来,被验证的证书自然都需要是被这同一个Root CA对应的私钥签署,不然不能通过认证。

其实实际上,使用一套证书(都使用一套CA来签署)一样可以搭建出K8S,一样可以上生产,但是理清这些证书的关系,在遇到因为证书错误,请求被拒绝的现象的时候,不至于无从下手,而且如果没有搞清证书之间的关系,在维护或者解决问题的时候,贸然更换了证书,弄不好会把整个系统搞瘫。

master节点:
for i in $(find /etc/kubernetes -type f -name "*.crt");do  echo "crt: $i" &&  openssl x509 -in $i -noout -text|grep Not; done
for i in $(find /etc/kubernetes -type f -name "*.pem");do  echo "crt: $i" &&  openssl x509 -in $i -noout -text|grep Not; done
node节点:
openssl x509 -in /var/lib/kubelet/pki/kubelet-client-current.pem   -noout -dates

etcd证书

kubectl create secret generic etcd-client-cert --from-file=etcd-ca=/etc/ssl/etcd/ssl/ca.pem --from-file=etcd-client=/etc/ssl/etcd/ssl/node-bmlc-test-cpu.bcc-bjdd.baidu.com.pem --from-file=etcd-client-key=/etc/ssl/etcd/ssl/node-bmlc-test-cpu.bcc-bjdd.baidu.com-key.pem

网络原理

只查看物理网卡

 ls /sys/class/net/ | grep -v "`ls /sys/devices/virtual/net/`"

只查看虚拟网卡

ls /sys/devices/virtual/net/

查看所有网卡

ls /sys/class/net/

查看网卡下面的参数

ifconfig  | grep -A 6  vethff22f52e
grep -C 5 foo   匹配foo字串那行以及上下5行

grep -B 5 foo   显示foo及前5行

grep -A 5 foo   显示foo及后5行

什么是cni (network plugin)

CNI**(container network interface)**

CNI插件是可执行文件,会被kubelet调用。启动kubelet --network-plugin=cni,–cni-conf-dir 指定networkconfig配置,默认路径是:/etc/cni/net.d,并且,–cni-bin-dir 指定plugin可执行文件路径,默认路径是:/opt/cni/bin;

CNI plugin 只需要通过 CNI 库实现两类方法, 一类事创建容器时调用, 一类是删除容器时调用.

CNI Plugin负责给容器配置网络,它包括两个基本的接口:
配置网络: AddNetwork(net NetworkConfig, rt RuntimeConf) (types.Result, error)
清理网络: DelNetwork(net NetworkConfig, rt RuntimeConf) error

t**ype CNI interface 
  AddNetworkList(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
  DelNetworkList(net *NetworkConfigList, rt *RuntimeConf) error
  AddNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
  DelNetwork(net *NetworkConfig, rt *RuntimeConf) error

kubernetes配置了cni网络插件后,其容器网络创建流程为:

  • kubernetes先创建pause容器生成对应的network namespace
  • 调用网络driver,因为配置的是CNI,所以会调用CNI相关代码
  • CNI driver根据配置调用具体的CNI插件
  • CNI插件给pause容器配置正确的网络,pod中其他的容器都是用pause的网络

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MtgRaMuw-1680158062098)(pic/K8S基础/image-20210304112618461.png)]

k8s的网络基础实现

k8s的网络实现是通过iptables加路由的方式

iptables 五链四表
概览

我们知道kube-proxy支持 iptables 和 ipvs 两种模式;

Kubernetes 在版本v1.6中已经支持5000个节点,但使用 iptables 的 kube-proxy 实际上是将集群扩展到5000个节点的瓶颈。 在5000节点集群中使用 NodePort 服务,如果有2000个服务并且每个服务有10个 pod,这将在每个工作节点上至少产生20000个iptable 记录,这可能使内核非常繁忙。

启动ipvs的要求:

  • k8s版本 >= v1.11
  • 使用ipvs需要安装相应的工具来处理”yum install ipset ipvsadm -y“
  • 确保 ipvs已经加载内核模块, ip_vs、ip_vs_rr、ip_vs_wrr、ip_vs_sh、
    nf_conntrack_ipv4。如果这些内核模块不加载,当kube-proxy启动后,会退回到iptables模式。

表和链实际上是netfilter的两个维度。

table(表):iptables内置4个table,不同的table代表不同的功能,每个table可以包含许多chain,不同类型的table对所能包含的chain和策略中的target的使用做了限定,一些target不能在一些table中使用。用户不能自定义table;

chain(链):chain可用包括一系列的策略,通过配置不同的chain可以对不同作用的策略进行分类,iptables内置5个chain对应netfilter的5个hook,用户也可以自定义chain;

PREROUTING 路由前
INPUT 发到本机某进程的报文
OUTPUT 本机某进程发出的报文
FORWARD 转发
POSTROUTING 路由后

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g7dAgUaN-1680158062099)(pic/K8S基础/image-20210209153342379.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NO7IXNVg-1680158062099)(pic/K8S基础/image-20210218105557868.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eN9fBPx8-1680158062099)(pic/K8S基础/image-20210218170306054.png)]

1)当一个数据包进入网卡时,它首先进入PREROUTING链,内核根据数据包目的IP判断是否需要转送出去。
2)如果数据包就是进入本机的,它就会沿着图向下移动,到达INPUT链。数据包到了INPUT链后,任何进程都会收到它。本机上运行的程序可以发送数据包,这些数据包会经过OUTPUT链,然后到达POSTROUTING链输出。
3)如果数据包是要转发出去的,且内核允许转发,数据包就会如图所示向右移动,经过FORWARD链,然后到达POSTROUTING链输出。

参考https://www.cnblogs.com/kevingrace/p/6265113.html

具体的四表
  • filter表——涉及FORWARD、INPUT、OUTPUT三条链,多用于本地和转发过程中数据过滤;(负责过滤工程,防火墙 )
  • Nat表——涉及PREROUTING、OUTPUT、POSTROUT三条链,多用于源地址/端口转换和目标地址/端口的转换;

​ (网络地址转换功能 network address translate )

  • Mangle表——涉及整条链,可实现拆解报文、修改报文、重新封装,可常见于IPVS的PPC下多端口会话保持。

    ​ (拆解报文,做出修改,并重新封装 )

  • Raw表——涉及PREROUTING和OUTPUT链,决定数据包是否被状态跟踪机制处理,需关闭nat表上的连接追踪机制。

    ​ (关闭nat表上启用的连接追踪机制)

具体的五链
  • INPUT——进来的数据包应用此规则链中的策略
  • OUTPUT——外出的数据包应用此规则链中的策略
  • FORWARD——转发数据包时应用此规则链路中的策略
  • PREROUTING——对数据包作路由选择前应用此链中的规则(所有的数据包进来的时候都先由这个链处理)
  • POSTROUTING——对数据包作路由选择后应用此链中的规则(所有的数据包出来的时候都先由这个链处理)
链表关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gLj1UFoZ-1680158062099)(./pic/K8S基础/image-20210209152020269.png)]

链表关系
PREROUTING 的规则可存在于:nat表、mangle表、raw表
INPUT 的规则可存在于:mangle表、filter表(nat表centos6没有,centos7有)
FORWARD 的规则可存在于:mangle表、filter表
OUTPUT 的规则可存在于:raw表、mangle表、nat表、filter表
POSTROUTING 的规则可存在于:mangle表、nat表

这个不用硬记,有方法的(iptables -t 表 -L)

当4张表出现在同一条链上的时候,优先级别是:
raw—>mangle—->nat—>filter

iptables语法格式
iptables  [-t 表名] 选项 [链名] [条件] [-j 控制类型 ]
-P设置默认策略 iptable
-F清空规则链
-L查看规则链(查看详细规则是对-S的补充)
-A在规则链的末尾加入新规则
-Inum 在规则链的头部加入新规则
-Dnum 删除某一条规则
-s匹配来源地址 IP/MASK,加叹号“ !”表示除这个IP外
-S使用 -S 命令可以查看这些rules是如何建立的
-d匹配目标地址
-i网卡名称 匹配从这块网卡流入的数据 入站口
-o网卡名称 匹配从这块网卡流出的数据 出站口
-p匹配协议,如tcp,udp,icmp
–dport num匹配目标端口号
–sport num匹配来源端口号

如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HSe8ZLXv-1680158062100)(pic/K8S基础/image-20210209160733656.png)]

iptables处理动作除了 ACCEPT、REJECT、DROP、REDIRECT 、MASQUERADE 以外,还多出 LOG、ULOG、DNAT、RETURN、TOS、SNAT、MIRROR、QUEUE、TTL、MARK等。

详细参考https://blog.csdn.net/reyleon/article/details/12976341

增删改查

查看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2PqdlHes-1680158062100)(pic/K8S基础/image-20210209155934998.png)]

可以看到,使用-v选项后,iptables为我们展示的信息更多了,那么,这些字段都是什么意思呢?我们来总结一下,看不懂没关系,等到实际使用的时候,自然会明白,此处大概了解一下即可。

其实,这些字段就是规则对应的属性,说白了就是规则的各种信息,那么我们来总结一下这些字段的含义。

pkts:对应规则匹配到的报文的个数。

bytes:对应匹配到的报文包的大小总和。

·target:规则对应的target,往往表示规则对应的"动作",即规则匹配成功后需要采取的措施。

prot:表示规则对应的协议,是否只针对某些协议应用此规则。

opt:表示规则对应的选项。

in:表示数据包由哪个接口(网卡)流入,我们可以设置通过哪块网卡流入的报文需要匹配当前规则。

out:表示数据包由哪个接口(网卡)流出,我们可以设置通过哪块网卡流出的报文需要匹配当前规则。

source:表示规则对应的源头地址,可以是一个IP,也可以是一个网段。

destination:表示规则对应的目标地址。可以是一个IP,也可以是一个网段。

增加

如果报文来自"192.168.1.146",则表示满足匹配条件,而"拒绝"这个报文,就属于对应的动作,好了,那么怎样用命令去定义这条规则呢?使用如下命令即可

iptables 	-t filter -I INPUT -s 192.168.1.146  -j DROP

使用 -t选项指定了要操作的表,此处指定了操作filter表,与之前的查看命令一样,不使用-t选项指定表时,默认为操作filter表。

使用-I选项,指明将"规则"插入至哪个链中,-I表示insert,即插入的意思,所以-I INPUT表示将规则插入于INPUT链中,即添加规则之意。

使用-s选项,指明"匹配条件"中的"源地址",即如果报文的源地址属于-s对应的地址,那么报文则满足匹配条件,-s为source之意,表示源地址。

使用-j选项,指明当"匹配条件"被满足时,所对应的动作,上例中指定的动作为DROP,在上例中,当报文的源地址为192.168.1.146时,报文则被DROP(丢弃)。

再次查看filter表中的INPUT链,发现规则已经被添加了,在iptables中,动作被称之为"target",所以,上图中taget字段对应的动作为DROP。

** 注意**

-i 是有顺序的 先插入的规则会拦截追加的规则。

iptables 	-t filter -I INPUT -s 162.162.1.146  -j DROP
iptables 	-t filter -A INPUT -s 162.162.1.146  -j ACCEPT
这个-A追加的规则 会被之前的DROP掉,还是不能接受到
iptables 	-t filter -I INPUT -s 162.162.1.146  -j ACCEPT 这样会重新接收

使用–line-number选项可以列出规则的序号

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1LszQabW-1680158062100)(pic/K8S基础/image-20210209162943407.png)]

指定规则插入

iptables 	-t filter -I INPUT 2  -s 192.168.1.146  -j DROP

删除

[root@yq01-aip-aikefu08 ~]# iptables -L INPUT --line
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    ACCEPT     all  --  162.162.1.146        anywhere            
2               all  --  162.162.1.146        anywhere            
3    DROP       all  --  162.162.1.146        anywhere            
4    KUBE-EXTERNAL-SERVICES  all  --  anywhere             anywhere             ctstate NEW /* kubernetes externally-visible service portals */
5    KUBE-FIREWALL  all  --  anywhere             anywhere            
6    ACCEPT     all  --  162.162.1.146        anywhere            
[root@yq01-aip-aikefu08 ~]# iptables -D INPUT 1
[root@yq01-aip-aikefu08 ~]# iptables -L INPUT --line
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         
1               all  --  162.162.1.146        anywhere            
2    DROP       all  --  162.162.1.146        anywhere            
3    KUBE-EXTERNAL-SERVICES  all  --  anywhere             anywhere             ctstate NEW /* kubernetes externally-visible service portals */
4    KUBE-FIREWALL  all  --  anywhere             anywhere            
5    ACCEPT     all  --  162.162.1.146        anywhere   					

修改

[root@yq01-aip-aikefu08 ~]# iptables -L INPUT --line
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         
1               all  --  162.162.1.146        anywhere            
2    DROP       all  --  162.162.1.146        anywhere            
3    KUBE-EXTERNAL-SERVICES  all  --  anywhere             anywhere             ctstate NEW /* kubernetes externally-visible service portals */
4    KUBE-FIREWALL  all  --  anywhere             anywhere            
5    ACCEPT     all  --  162.162.1.146        anywhere            
[root@yq01-aip-aikefu08 ~]# iptables -t filter -R INPUT 1 -s 162.162.1.146 -j REJECT 
[root@yq01-aip-aikefu08 ~]# iptables -L INPUT --line
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    REJECT     all  --  162.162.1.146        anywhere             reject-with icmp-port-unreachable
2    DROP       all  --  162.162.1.146        anywhere            
3    KUBE-EXTERNAL-SERVICES  all  --  anywhere             anywhere             ctstate NEW /* kubernetes externally-visible service portals */
4    KUBE-FIREWALL  all  --  anywhere             anywhere            
5    ACCEPT     all  --  162.162.1.146        anywhere 														

保存

我们对"防火墙"所做出的修改都是"临时的",换句话说就是,当重启iptables服务或者重启服务器以后,我们平常添加的规则或者对规则所做出的修改都将消失,为了防止这种情况的发生,我们需要将规则"保存"。

centos6中,使用"service iptables save"命令即可保存规则,规则默认保存在/etc/sysconfig/iptables文件中,如果你刚刚安装完centos6,在刚开始使用iptables时,会发现filter表中会有一些默认的规则,这些默认提供的规则其实就保存在/etc/sysconfig/iptables中,

当我们对规则进行了修改以后,如果想要修改永久生效,必须使用service iptables save保存规则,当然,如果你误操作了规则,但是并没有保存,那么使用service iptables restart命令重启iptables以后,规则会再次回到上次保存/etc/sysconfig/iptables文件时的模样。

centos7中,已经不再使用init风格的脚本启动服务,而是使用unit文件,所以,在centos7中已经不能再使用类似service iptables start这样的命令了,所以service iptables save也无法执行,同时,在centos7中,使用firewall替代了原来的iptables service,不过不用担心,我们只要通过yum源安装iptables与iptables-services即可(iptables一般会被默认安装,但是iptables-services在centos7中一般不会被默认安装),在centos7中安装完iptables-services后,即可像centos6中一样,通过service iptables save命令保存规则了,规则同样保存在/etc/sysconfig/iptables文件中。

iptables应用demo

第一种

输入以下命令:
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8081-8082

iptables -t nat -A PREROUTING -p tcp --dport 8901  -j REDIRECT --to-ports 3306

[root@yq01-aip-aikefu15 ~]# iptables -t nat -L -n --line-number
Chain PREROUTING (policy ACCEPT)
num  target     prot opt source               destination         
1    cali-PREROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* cali:6gwbT8clXdHdC1b1 */
2    KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
3    DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL
4    REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8901 redir ports 3306

# 把8901端口的数据 转发到3306mysql服务上。

通过NAT表的方式吧从端口80接收到的数据随机转发到8001,8002端口

请求还是打在一台机器上,单机器性能

第二种

iptables -t nat -A PREROUTING -d 10.192.0.65/32 -p tcp -m tcp --dport 8080 -m statistic --mode nth --every 2 --packet 0 -j DNAT --to-destination 10.1.160.14:8080
iptables -t nat -A POSTROUTING -d 10.1.160.14/32 -p tcp -m tcp --dport 8080 -j SNAT --to-source 10.192.0.65

iptables -t nat -A PREROUTING -d 10.192.0.65/32 -p tcp -m tcp --dport 8080 -m statistic --mode nth --every 1 --packet 0 -j DNAT --to-destination 10.1.160.15:8080
iptables -t nat -A POSTROUTING -d 10.1.160.15/32 -p tcp -m tcp --dport 8080 -j SNAT --to-source 10.192.0.65

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3jvOFhXE-1680158062101)(pic/K8S基础/image-20210209170840720.png)]

Linux的iptable转发和nginx转发各自优势和差别,分别在什么场景下适用,怎么选择呢?

层次不一样,nginx转发属于应用层,iptables是网络层。
iptables转发一般用于nat内网服务器提供外网应用。比如一个ip做公网,服务器放在内网,公共ip就一个,把服务器就放在公网ip的电脑上话会有些问题,一般还要提供上网服务(做路由器),需要提供的服务可能也很多,比如,www,ftp,mail,那么通过iptables实现端口映射,把不同服务放到不同服务器上,又不需要很多公网ip。
nginx转发主要是负载均衡,而且比较灵活,比如部分转发,转发到不同的服务器上。iptables只能实现全部转发,按照端口,到达端口的数据全部转发给一台服务器。nginx转发http请求就灵活很多,比如对于静态内容,js,css,图片,可以利用memcache等缓存,直接提供服务,而其他复杂的请求可以转发过应用服务器,而且支持多个服务器。

第三种

iptables -t nat -A PREROUTING -d 10.200.36.6 -p tcp -m tcp --dport 3308  -j DNAT --to-destination 10.200.36.7:3309
iptables -t nat -A POSTROUTING -d 10.200.36.7 -p tcp -m tcp --dport 3309 -j SNAT --to-source 10.200.36.6:3308


# 将172.36.20.204:25009 (内网) 的请求转发至10.157.94.208:25009 (外网) @杨子哲 
iptables -t nat -A OUTPUT -d 172.36.20.204 -p tcp --dport 25009 -j DNAT --to-destination 10.157.94.208:25009

此Demo 把36.6:3308 转发到 36.7的3309上 。(要在36.6的服务器上执行)

iptables在k8s的作用

kube-proxy只修改了filter和nat表,它对iptables的链进行了扩充,自定义了
KUBE-SERVICES,
KUBE-NODEPORTS,
KUBE-POSTROUTING,
KUBE-MARK-MASQ
KUBE-MARK-DROP
五个链,并主要通过为 KUBE-SERVICES链(附着在PREROUTING和OUTPUT)增加rule来配制traffic routing 规则。

kubernetes的service通过iptables来做后端pod的转发和路由,下面来跟踪具体的规则

SNAT: 改变数据包的源地址。当内网数据包到达防火墙后,防火墙会使用外部地址替换掉数据包的源IP地址(目的IP地址不变),使网络内部主机能够与网络外部主机通信。

DNAT: 改变数据包的目的地址。当防火墙收到来自外网的数据包后,会将该数据包的目的IP地址进行替换(源IP地址不变),重新转发到内网的主机。

DNAT是发送数据的时候隐藏了服务地址,与之对应的是SNAT 隐藏了客户端的ip

SNAT: Source Network Address Translation,是修改网络包源ip地址的。
DNAT: Destination Network Address Translation,是修改网络包目的ip地址的。

[root@yq01-aip-aikefu08 ~]# kubectl get svc --all-namespaces  | grep redis-cluster-proxy
default         redis-cluster-proxy         NodePort       10.233.0.55     <none>        7777:8777/TCP  
[root@yq01-aip-aikefu08 ~]# kubectl describe svc redis-cluster-proxy 
Name:                     redis-cluster-proxy
Namespace:                default
Labels:                   app=redis-cluster-proxy
                          chart=redis-cluster-0.1.1-107446491
                          heritage=Tiller
                          release=redis-cluster
Annotations:              <none>
Selector:                 app=redis-cluster-proxy
Type:                     NodePort
IP:                       10.233.0.55
Port:                     proxy  7777/TCP
TargetPort:               7777/TCP
NodePort:                 proxy  8777/TCP
Endpoints:                10.233.64.160:7777,10.233.64.162:7777
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

cluster ip : 10.233.0.55

pod ip : 10.233.64.160 ,10.233.64.162

查看nat转发表(KUBE-SERVICES 是k8s自定义链表)

[root@yq01-aip-aikefu08 ~]# iptables -t nat -nvL  
Chain PREROUTING (policy ACCEPT 84 packets, 5040 bytes)
 pkts bytes target     prot opt in     out     source               destination         
5216M  752G KUBE-SERVICES  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
  37M 2240M CNI-HOSTPORT-DNAT  all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

查看svc的链 iptables -t nat -nvL KUBE-SERVICES

[root@yq01-

Python 详解K-S检验与3σ原则剔除异常值

文章目录


一、引言

异常值分析是检验数据是否有录入错误,是否含有不合常理的数据。忽视异常值的存在是十分危险的,不加剔除地将异常值放入数据的计算分析过程中,会对结果造成不良影响;重视异常值的出现,分析其产生的原因,经常成为发现问题进而改进决策的契机。

异常值是指样本中的个别值,其数值明显偏离其他的观测值。异常值也称为离群点,异常值分析也称为离群点分析。

而对于数据异常值的处理,3σ 原则是一种基于统计的方法,简单实用。


二、3σ原则

什么叫 3σ 原则呢?

  • 3σ 原则,又叫拉依达原则,它是指假设一组检测数据中只含有随机误差,需要对其进行计算得到标准偏差,按一定概率确定一个区间,对于超过这个区间的误差,就不属于随机误差而是粗大误差,需要将含有该误差的数据进行剔除。
  • 局限性:仅局限于对正态或近似正态分布的样本数据处理,它是以测量次数充分大为前提(样本>10),当测量次数少的情形用准则剔除粗大误差是不够可靠的。在测量次数较少的情况下,最好不要选用该准则。

3σ 原则:

  • 数值分布在(μ-σ,μ+σ)中的概率为 0.6827
  • 数值分布在(μ-2σ,μ+2σ)中的概率为 0.9545
  • 数值分布在(μ-3σ,μ+3σ)中的概率为 0.9973

其中,μ 为平均值,σ 为标准差。一般可以认为,数据 Y 的取值几乎全部集中在(μ-3σ,μ+3σ)区间内,超出这个范围的可能性仅占不到 0.3%,这些超出该范围的数据可以认为是异常值。

在实验科学中有对应正态分布的 3σ 定律(Three-sigma Law),是一个简单的推论,内容是 “几乎所有” 的值都在平均值正负三个标准差的范围内,也就是在实验上可以将 99.7% 的机率视为 “几乎一定” 。不过上述推论是否有效,会视探讨领域中 “显著” 的定义而定,在不同领域,“显著” 的定义也随着不同,例如在社会科学中,若置信区间是在正负二个标准差(95%)的范围,即可视为显著。但是在粒子物理中,若是发现新的粒子,置信区间要到正负五个标准差(99.99994%)的程度。

即使在不是正态分布的情形下,也有另一个对应的 3σ 定律(three-sigma rule)。即使是在非正态分布的情形下,至少会有 88.8% 的机率会在正负三个标准差的范围内,这是依照切比雪夫不等式的结果。若是单模分布(unimodal distributions)下,正负三个标准差内的机率至少有95%,若符合特定一些条件的分布,机率可能会到 98% 。所以如果数据不服从正态分布,也可以用远离平均值的标准差的自定义倍数来描述。


三、K-S检验

可以使用 K-S 检验一列数据是否服从正态分布

from scipy.stats import kstest

kstest(rvs, cdf, args=(), N=20, alternative='two-sided', mode='auto')
https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.kstest.html

补充学习:


四、Python实现

Python实现步骤具体步骤如下:

  • 首先需要保证数据列大致上服从正态分布(可以使用 box-cox 变换等);
  • 计算需要检验的数据列的平均值 μ 和标准差 σ;
  • 比较数据列的每个值与平均值的偏差是否超过 3 倍标准差,如果超过 3 倍,则为异常值;
  • 剔除异常值,得到规范的数据。

K-S 正态分布检验和 3σ 原则剔除异常值,Python 代码如下:

import numpy as np
import pandas as pd
from scipy.stats import kstest
from scipy.special import boxcox1p
from scipy.stats import boxcox_normmax
from scipy.special import inv_boxcox


def KsNormDetect(df):
    # 计算均值
    u = df['value'].mean()
    # 计算标准差
    std = df['value'].std()
    # 计算P值
    print(kstest(df['value'], 'norm', (u, std)))
    res = kstest(df['value'], 'norm', (u, std))[1]
    print('均值为:%.2f,标准差为:%.2f' % (u, std))
    # 判断p值是否服从正态分布,p<=0.05 拒绝原假设 不服从正态分布
    if res <= 0.05:
        print('该列数据不服从正态分布')
        print("-" * 66)
        return True
    else:
        print('该列数据服从正态分布')
        return False


def OutlierDetection(df, ks_res):
    # 计算均值
    u = df['value'].mean()
    # 计算标准差
    std = df['value'].std()
    if ks_res:
        # 定义3σ法则识别异常值
        outliers = df[np.abs(df['value'] - u) > 3 * std]
        # 剔除异常值,保留正常的数据
        clean_data = df[np.abs(df['value'] - u) < 3 * std]
        # 返回异常值和剔除异常值后的数据
        return outliers, clean_data

    else:
        print('请先检测数据是否服从正态分布')
        return None


if __name__ == '__main__':
    # 构造数据  某一列数据  含有异常值
    data = np.random.normal(60, 5, 200)
    data[6], data[66], data[196] = 16, 360, 180
    print(data)
    
    print("-" * 66)
    # 可以转换为pandas的DataFrame 便于调用方法计算均值和标准差
    df = pd.DataFrame(data, columns=['value'])
    # box-cox变换
    lam = boxcox_normmax(df["value"] + 1)
    df["value"] = boxcox1p(df['value'], lam)
    # K-S检验
    ks_res = KsNormDetect(df)
    outliers, clean_data = OutlierDetection(df, ks_res)
    # 异常值和剔除异常值后的数据
    outliers = inv_boxcox(outliers, lam) - 1
    clean_data = inv_boxcox(clean_data, lam) - 1
    print(outliers)
    print("-" * 66)
    print(clean_data)

剔除异常值结果如下:


补充学习:

以上是关于K8S基础的主要内容,如果未能解决你的问题,请参考以下文章

零基础学kubernetes(k8s)必看教程,带你10分钟快速实战入门k8s

零基础学kubernetes(k8s)必看教程,带你10分钟快速实战入门k8s

容器技术Docker K8s 4 容器编排技术基础-Kubernetes

Kubernetes的基础概念

kubernetes(k8s)资源管理/清单配置基础

kubernetes--基础--k8s的pod之间的服务访问