v1.16
介绍:
service 资源实现了kubenetes中用来自动查找后端pod的功能, 在集群私有网络中的任何节点都可以通过访问service ip来访问后端的pod。但是service只是逻辑上的,相当于是配置。 而kube-proxy就是真正实现功能的组件。
有兴趣可以看看这里:
https://www.yxingxing.net/archives/kubernetes-20191104-service-network
kube-proxy 有三种模式,userspace, iptables, ipvs。
userspace:
是老版本的模式了, 在这个模式下kube-proxy就是一个代理,类似haproxy,通过iptables把流量转发到kube-proxy用户进程,由Kube-proxy再发送到目的pod。
iptables:
是现在最稳定的模式, 也是添加iptables规则,只不过是直接通过DNAT发送到后端pod。 而负载均衡的实现是通过添加多条规则,内容是iptables的statistic模块的random产生的不同随机值做运算来随机匹配规则。如:
-A KUBE-SVC-NPX46M4PTMTKRN6Y -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-LKAO6JA5PQWHK647
-A KUBE-SVC-NPX46M4PTMTKRN6Y -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-6AATE2IAMBDY74K4
-A KUBE-SVC-NPX46M4PTMTKRN6Y -j KUBE-SEP-LGKM7LHKYURGBIAK
因为iptables是为防火墙设计的, 是线性的数据结构,规则是一条一条的匹配, 所以在service很多的情况下,很影响性能, 并且在一些极端的情况下可能还会出现规则丢失的情况。
ipvs:
是新的模式, 在v1.11 进入GA版。 ipvs 与iptables的数据机构不同,在大量的service情况下,影响微乎其微。
通过添加ipvs规则实现转发与负载均衡,不过iptables也还是要用的,需要添加一些辅助的规则,如外部访问NodePort的service需要SNAT还要DNAT。还会添加一个kube-ipvs网卡,设置所有service的地址到上面, 同时local route也会更新。 我想是因为ipvs是添加在网络input上的钩子实现的,所以本机想要访问service需要进入input, 通过进入另外一个网卡来实现。
有兴趣可以看看这个:
https://www.yxingxing.net/archives/kubernetes-20191108-kubeproxy-network
kube-proxy通过watch apiserver的service, endpoint, node资源,实时监控资源的变化,来近乎实时的更新本机的相关规则。
这里使用的参数很少,大部分都是默认的,不过还是建议看一下其他参数,特别是conntrack-max-per-core
参数:
https://www.yxingxing.net/archives/kubernetes-20191213-proxy-parameter
两种安装方式
安装方式一般是两种,一种是二进制在宿主机上安装,使用证书认证,这种方式已经被官方网站称为旧方法了:
https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#other-authenticating-components
还有就是用DaemonSet启动,使用serviceaccount认证,这种方式更加的简单点。
kube-proxy如何区分的
就是以有没有提供kubeconfig文件, 或者是连接apiserver的变量。
[root@k8snode1 bin]# ./kube-proxy --cluster-cidr=10.1.0.0/16 --logtostderr=false --log-dir=/var/log --proxy-mode=ipvs
F1220 09:24:51.783346 3066 server.go:495] unable to load in-cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined
如果提供变量,kube-proxy就会自动去找ServiceAccount
[root@k8snode1 bin]# export KUBERNETES_SERVICE_HOST=https://192.168.1.231
[root@k8snode1 bin]# export KUBERNETES_SERVICE_PORT=6443
[root@k8snode1 bin]# ./kube-proxy --cluster-cidr=10.1.0.0/16 --logtostderr=false --log-dir=/var/log --proxy-mode=ipvs
F1220 09:36:46.057337 6764 server.go:495] open /var/run/secrets/kubernetes.io/serviceaccount/token: no such file or directory
反过来,如果提供了kubeconfig文件, 自然是按文件的设置了。
二进制方式
1、生成证书
可以使用网上的一些工具,如: cfssl。 我这里使用自己的脚本。
https://www.yxingxing.net/archives/kubernetes-20191025-ca
主要就是注意证书的common name, 因为跟授权有关系。
kubernetes专门内置了kube-proxy 使用的 clusterrolebinding
, 名字叫做system:node-proxier
。
[root@k8s-master1 ~]# kubectl describe clusterrolebinding/system:node-proxier
Name: system:node-proxier
Labels: kubernetes.io/bootstrapping=rbac-defaults
Annotations: rbac.authorization.kubernetes.io/autoupdate: true
Role:
Kind: ClusterRole
Name: system:node-proxier
Subjects:
Kind Name Namespace
---- ---- ---------
User system:kube-proxy
绑定了用户system:kube-proxy
。所以证书的common name使用system:kube-proxy
就可以
[root@k8s-master ca]# ./openssl.sh build kube-proxy
Generating RSA private key, 2048 bit long modulus
.............................................................................................+++
...........................................................................................+++
e is 65537 (0x10001)
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [CN]:
State or Province Name (full name) [BJ]:
Locality Name (eg, city) [BJ]:
Organization Name (eg, company) [atest.pub]:
Organizational Unit Name (eg, section) [op]:
Common Name (eg, your name or your server's hostname) [kube-proxy]:system:kube-proxy
Email Address [op@atest.pub]:
......
创建出来的证书:
2、生成kubeconfig文件。
生成用于kube-proxy访问apiserver的kubeconfig文件。
需要kubectl命令生成,还需要ca证书,这些master节点都有, 把kube-proxy证书与key传到master节点任意目录就可以了。 在其他节点也可以,生成配置文件只是kubectl自身的功能,不需要权限。
[root@k8s-master kube-proxy]# tree
.
├── kube-proxy.crt
└── kube-proxy.key
0 directories, 2 files
[root@k8s-master kube-proxy]# kubectl config set-cluster mycluster --server=https://172.100.102.70:6443 --certificate-authority=/usr/local/k8s/ssl/cacert.pem --embed-certs --kubeconfig=kube-proxy.kubeconfig.yaml
Cluster "mycluster" set.
[root@k8s-master kube-proxy]# kubectl config set-credentials myuser --client-certificate=kube-proxy.crt --client-key=kube-proxy.key --embed-certs --kubeconfig=kube-proxy.kubeconfig.yaml
User "myuser" set.
[root@k8s-master kube-proxy]# kubectl config set-context mycontext --cluster=mycluster --user=myuser --kubeconfig=kube-proxy.kubeconfig.yaml
Context "mycontext" created.
[root@k8s-master kube-proxy]# kubectl config use-context mycontext --kubeconfig=kube-proxy.kubeconfig.yaml
Switched to context "mycontext".
1、创建连接集群的配置,指定apiserver地址与集群ca证书(在连接的时候验证apiserver的真实性), --embed-certs表示把证书写到文件里, --kubeconfig表示把配置写到指定的文件,而不是默认的kubectl配置文件的路径。
2、创建用户信息,指定用户证书与key。
3、创建配置的上下文。 配置文件里可以写多套集群与用户的配置, 这个上下文就是把指定的集群信息与用户信息组合起来。
4、指定当前使用的上下文。
接下来把kube-proxy.kubeconfig.yaml文件传到kube-proxy的节点就行了,这里的证书不用,已经写到文件里了。
3、创建Unit文件
现在的目录结构:
[root@k8s-node1 k8s]# tree
.
├── bin
│ ├── kubelet
│ └── kube-proxy
├── conf
│ ├── bootstrp-kubeconfig
│ ├── kubeconfig
│ └── kube-proxy.kubeconfig.yaml
├── logs
└── ssl
├── kubelet-client-2019-11-24-02-03-44.pem
├── kubelet-client-current.pem -> /usr/local/k8s/ssl/kubelet-client-2019-11-24-02-03-44.pem
├── kubelet.crt
└── kubelet.key
4 directories, 9 files
kubelet是之前安装kubelet的时候生成的,因为kube-proxy启动以后会去获取节点信息,如果本节点不是集群节点,会报错, 所以kubelet需要先运行。
flannel 也要先运行,kube-proxy有个参数需要获取本机的pod网段信息,用于生成相关的iptables规则。flannel可以提供。
[root@k8s-node1 k8s]# cat /lib/systemd/system/kube-proxy.service
[Unit]
Description=kubelet
After=network.target
[Service]
EnvironmentFile=/var/run/flannel/subnet.env
ExecStart=/usr/local/k8s/bin/kube-proxy\
--kubeconfig=/usr/local/k8s/conf/kube-proxy.kubeconfig.yaml \
--proxy-mode=ipvs \
--log-dir=/usr/local/k8s/logs \
--logtostderr=false \
--metrics-bind-address=0.0.0.0 \
--v=4 \
--cluster-cidr=${FLANNEL_NETWORK}
Restart=on-failure
[Install]
WantedBy=multi-user.target
--cluster-cidr
也可以直接写集群的POD范围,一般也不会修改,是整个集群的pod范围, 不是当前节点。
[root@k8s-node1 k8s]# cat /var/run/flannel/subnet.env
FLANNEL_NETWORK=10.1.0.0/16
FLANNEL_SUBNET=10.1.44.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true
4、启动
[root@k8s-node1 k8s]# systemctl start kube-proxy
查看日志发现:
W1214 03:55:21.883814 30619 hostport_manager.go:68] The binary conntrack is not installed, this can cause failures in network connection cleanup.
直接yum安装conntrack就可以, 只是暂时还搞不懂具体的作用。
查看infor日志可以发现修改内核参数的信息:
warning日志:
Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg
W1214 03:56:04.673371 31011 server.go:208] WARNING: all flags other than --config, --write-config-to, and --cleanup are deprecated. Please begin using a config file ASAP.
W1214 03:56:04.751364 31011 proxier.go:420] IPVS scheduler not specified, use rr by default
ipvs默认rr调度,这个可以通过kube-proxy参数修改。
ipvs模块是否加载:
[root@k8s-node1 logs]# lsmod | grep ip_vs
ip_vs_sh 12688 0
ip_vs_wrr 12697 0
ip_vs_rr 12600 1
ip_vs 145497 7 ip_vs_rr,ip_vs_sh,ip_vs_wrr
nf_conntrack 137239 7 ip_vs,nf_nat,nf_nat_ipv4,xt_conntrack,nf_nat_masquerade_ipv4,nf_conntrack_netlink,nf_conntrack_ipv4
libcrc32c 12644 4 xfs,ip_vs,nf_nat,nf_conntrack
[root@k8s-node1 logs]#
查看有没有规则,集群有一个表示自己的service, 是service 网段的第一个ip。
[root@k8s-node1 logs]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.0.0.1:443 rr
-> 172.100.102.70:6443 Masq 1 0 0
[root@k8s-node1 logs]#
DaemonSet方式
下载的二进制安装包里面有除了kubelet以外的所有组件镜像文件。
自带的yaml文件
还有kube-proxy安装用的yaml文件。
kubernetes/cluster/addons/kube-proxy
[root@k8smaster1 kube-proxy]# ls
kube-proxy-ds.yaml kube-proxy-rbac.yaml OWNERS
其中rbac文件包含用到的serviceaccount的授权。另一个就是部署kube-proxy的daemonset了。
注意: 这个yaml文件里有nodeSelector
这个文件可能是用于salt管理工具批量安装的,这里把这些变量改吧改吧就能用。
上面的nodeselect看情况要不要删除。下面的日志路径也是看情况修改。
我这里改完以后是这个样子:
# Please keep kube-proxy configuration in-sync with:
# cluster/saltbase/salt/kube-proxy/kube-proxy.manifest
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
k8s-app: kube-proxy
addonmanager.kubernetes.io/mode: Reconcile
name: kube-proxy
namespace: kube-system
spec:
selector:
matchLabels:
k8s-app: kube-proxy
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 10%
template:
metadata:
labels:
k8s-app: kube-proxy
spec:
priorityClassName: system-node-critical
hostNetwork: true
tolerations:
- operator: "Exists"
effect: "NoExecute"
- operator: "Exists"
effect: "NoSchedule"
containers:
- name: kube-proxy
image: harbor.atest.pub/k8s/kube-proxy:v1.19.5
resources:
requests:
cpu: 500m
command:
- /bin/sh
- -c
- kube-proxy --cluster-cidr=10.1.0.0/16 --logtostderr=false --log-dir=/var/log --proxy-mode=ipvs 1>>/var/log/kube-proxy.log 2>&1
env:
- name: KUBERNETES_SERVICE_HOST
value: 192.168.1.221
- name: KUBERNETES_SERVICE_PORT
value: '6443'
securityContext:
privileged: true
volumeMounts:
- mountPath: /var/log
name: varlog
readOnly: false
- mountPath: /run/xtables.lock
name: xtables-lock
readOnly: false
- mountPath: /lib/modules
name: lib-modules
readOnly: true
volumes:
- name: varlog
hostPath:
path: /opt/kubernetes/log/kube-proxy
- name: xtables-lock
hostPath:
path: /run/xtables.lock
type: FileOrCreate
- name: lib-modules
hostPath:
path: /lib/modules
serviceAccountName: kube-proxy
上面的image
指定的是我这里的内网harbor。
应用yaml文件就是了:
kubectl apply -f kube-proxy-rbac.yaml
kubectl apply -f kube-proxy-ds.yaml
驱逐与抢占
驱逐
为了节点稳定性,在节点可用资源不多时,会驱逐一些pod。
资源限制的配置,也是看规模了。 为了避免资源紧缺被驱逐,最好把memory也加上。 并且添加limit与requests相等。 Guaranteed pod
。
如:
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 500m
memory: 512Mi
在get pod详情里可以看到这个字样。
[root@k8smaster1 kube-proxy]# kubectl get pods/kube-proxy-mwnnp -o yaml -n kube-system
......
qosClass: Guaranteed
......
抢占
抢占可能比驱逐只是多了一个抢,
因为资源紧缺,新的pod调度不进来,如果新的pod比节点已存在的pod优先级高,就会把低优先级的pod干掉。让高优先级的pod进来。
priorityClassName: system-node-critical
system-node-critical
是集群公共优先级类中优先级最高的。
详情:
https://kubernetes.io/zh/docs/concepts/configuration/pod-priority-preemption/
容忍设置
还要注意上面的tolerations
,容忍设置。这个必须要有。
因为有一种情况是:
节点因为kube-proxy没有部署导致是NoReady
状态, 只有添加容忍,kube-proxy才能部署过去,节点才能变为Ready
。
优化
1、conntrack表空间大小
sysctl -w net.netfilter.nf_conntrack_max=1000000
echo "net.netfilter.nf_conntrack_max=1000000" >> /etc/sysctl.conf