第六章 Kubernetes进阶之Service与外界连通

  1.Pod与Service的关系

  Pod出现故障以后Deployment会根据策略重启Pod,但是重启Pod会生成新的IP,需要引入Service概念保证访问正常

  Service

  • 防止Pod失联
  • 定义一组Pod访问策略
  • 支持ClusterIP,NodePort以及LoadBanlancer三种类型
  • Service的底层主要有Iptables和IPVS两种网络模式

  2.Service的定义

  Pod与Service的关系

  • 通过label-selector相关联
  • 通过Service实现Pod的负载均衡(TCP/UDP 4层)

  示例service.yaml

#版本
apiVersion: v1
#类型是service
kind: Service
metadata:
  name: my-service
  namespace: default
spec:
  #service默认clusterIP
  clusterIP: 10.10.10.123
  ports:
  - name: http
    #service端口
    port: 80
    protocol: TCP
    #后端容器端口
    targetPort: 80
  #标签选择器关联后端的一组Pod
  selector:
    run: nginx
      

   创建

kubectl apply -f service.yaml

   因为该service标签匹配一个nginx所以如果没有创建nginx的deployment需要创建一个

kubectl run nginx --replicas=3 --image=nginx --port=80

   创建以后可以查看有对应标签的pod

# kubectl get pod -l run=nginx
NAME                     READY   STATUS    RESTARTS   AGE
nginx-57867cc648-b4rct   1/1     Running   0          9m53s
nginx-57867cc648-qgbwl   1/1     Running   0          9m53s
nginx-57867cc648-qmbbw   1/1     Running   0          9m53s

  查看

# kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.10.10.1     <none>        443/TCP   6d23h
my-service   ClusterIP   10.10.10.123   <none>        80/TCP    6m25s

   其中name为kubernetes的service是k8s安装以后默认的一个service默认IP的service的第一个IP 10.10.10.1端口是443

  默认的svc的作用是负载均衡后端master的IP

  service需要动态感知后端ip变化可以通过以下命令查看,每个svc管理后端的一组容器

# kubectl get endpoints
NAME         ENDPOINTS                                      AGE
kubernetes   192.168.1.63:6443,192.168.1.64:6443            6d23h
my-service   172.17.41.2:80,172.17.55.2:80,172.17.55.4:80   9m59s

   在集群内部node例如192.168.1.65可以使用ClusterIP访问

curl 10.10.10.123

  PS:这里配置文件指定了clusterIP为10.10.10.123,默认不知道该clusterIP是随机的

apiVersion: v1
kind: Service
metadata:
  labels:
    run: nginx
  name: my-service
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: nginx

   不能直接应用生效

# kubectl apply -f service.yaml 
The Service "my-service" is invalid: spec.clusterIP: Invalid value: "": field is immutable

   需要删除原svc再应用生效

kubectl delete svc my-service

kubectl apply -f service.yaml 

   查看生成了随机的clusterIP

# kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.10.10.1     <none>        443/TCP   7d5h
my-service   ClusterIP   10.10.10.196   <none>        80/TCP    29s

 

  3.service类型

  service提供四层负载均衡把请求发送到后端的pod,默认规则是轮训

  • ClusterIP:默认,分配一个集群内部可以访问的虚拟IP
  • NodePort:在每个node上分配一个端口作为外部访问入口
  • LoadBanlancer:工作在特定的Cloud Provider上,例如Google,AWS,OpenStack
  ClusterIP

  分配一个内部集群IP地址,只能在集群内部访问(同Namespace内的Pod),默认ServiceType。 ClusterIP 模式的 Service 为你提供的,就是一个 Pod 的稳定的 IP 地址,即 VIP。

 

   NodePort

  分配一个内部集群IP地址,并在每个节点上启用一个端口来暴露服务,可以在集群外部访问。 访问地址:: node端口范围30000-32067
Client→NodeIP:NodePort→ClusterIP:ServicePort→PodIP:containerPort

 

   

#版本
apiVersion: v1
#类型是service
kind: Service
metadata:
  name: my-service
  namespace: default
spec:
  type: NodePort
  ports:
  - name: http
    #service端口
    port: 80
    protocol: TCP
    #后端容器端口
    targetPort: 80
  #标签选择器关联后端的一组Pod
  selector:
    run: nginx

   应用,service定义类型不支持自动更新,需要删除原有的配置再重新应用

kubectl delete -f service.yaml 
kubectl apply -f service.yaml 

   查看,类型变成NodePort了并且随机产生一个端口,本次随机端口是46194

# kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.10.10.1     <none>        443/TCP        7d3h
my-service   NodePort    10.10.10.238   <none>        80:46194/TCP   104s

   即使是使NodePort类型也会分配一个ClusterIP在集群内部可以访问,NodePort是供集群外部访问使用的

  使用NodePort会在多个node上可以访问,企业应用可以加一台负载均衡负载到一个或多个node

  LoadBalancer

  分配一个内部集群IP地址,并在每个节点上启用一个端口来暴露服务。 除此之外,Kubernetes会请求底层云平台上的负载均衡器,将每个Node([NodeIP]:[NodePort])作为后端添加进去

  4.Service代理模式

  底层流量转发与负载均衡实现

  • Iptables
  • IPVS

  service通过部署在node的应用kube-proxy实现

  可以通过kube-proxy配置文件查看模式

# cat /opt/kubernetes/cfg/kube-proxy
KUBE_PROXY_OPTS="--logtostderr=true \
--v=4 \
--hostname-override=192.168.31.65 \
--cluster-cidr=10.0.0.0/24 \
--proxy-mode=ipvs \
--masquerade-all=true \
--kubeconfig=/opt/kubernetes/cfg/kube-proxy.kubeconfig"

   查看Iptables的转发方式

  删除其中一台node192.168.1.66的ipvs配置

KUBE_PROXY_OPTS="--logtostderr=true \
--v=4 \
--hostname-override=192.168.31.66 \
--cluster-cidr=10.0.0.0/24 \
--kubeconfig=/opt/kubernetes/cfg/kube-proxy.kubeconfig"

   重启kube-proxy组件

 systemctl restart kube-proxy

   查看service对应的Iptables规则,过滤的IP为上面service的ip通过IP地址找到对应的规则

iptables-save|grep 10.10.10.238

   查看对应的规则

iptables-save|grep KUBE-SVC-I37Z43XJW6BD4TLV

 

 

   继续查看对应规则

iptables-save|grep KUBE-SEP-ETBSYW4QFKX7DP4Z

 

 

   Iptables的问题

  1,创建很多Iptables(更新,非增量式)

  2,Iptables规则是从上至下逐条匹配(规则多了,匹配延时大)

  无法大规模应用,救世主IPVS

  查看IPVS的工作方式

  LVS基于IPVS内核调度模块实现的负载均衡

  查看ipvs规则,需要kube-proxy设置ipvs工作模式才能查看到

ipvsadm -ln

   如果没有这个命令安装即可

yum -y install ipvsadm 

  

  会生成虚拟网卡kube-ipvs0,所有的ClusterIP会绑定在该网卡上

 

   默认使用rr轮训负载均衡策略,因为工作在内核态所以速度快

 

   对比

  Iptables

  • 灵活功能强大(可以在数据包不同阶段对包进行操作)
  • 规则遍历匹配和更新,呈线性时延

  IPVS

  • 工作在内核态,有更好的性能
  • 调度算法丰富:rr,wrr,lc,wlc,ip hash

  设置调度算法,一般使用默认即可无需配置

 

 

   Iptables和ipvs示意图

  5.DNS

  service创建以后在集群内部可以通过cluserIP访问,但是涉及迁移时IP会发生变化,需要部署内部DNS服务

  DNS服务监视Kubernetes API,为每一个Service创建DNS记录用于域名解析

  DNS配置文件官方下载地址https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/dns

 

   

   下载以后需要修改以下几处

 

   修改后

 

   修改镜像

 

   修改后

 

   修改资源限制

 

   修改后

 

   修改集群DNS地址

 

  修改后

 

 

   应用

 kubectl apply -f coredns.yaml

   排错:应用以后pod显示pending状态

kubectl get pod -n kube-system
kubectl describe pod  coredns-65589b968c-s7m28 -n kube-system

   错误信息为

nodes are available: 2 node(s) didn't match node selector

   标签不匹配

  查看系统标签

kubectl get node --show-labels
NAME           STATUS   ROLES    AGE   VERSION   LABELS
192.168.1.65   Ready    <none>   10d   v1.13.4   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=192.168.1.65
192.168.1.66   Ready    <none>   10d   v1.13.4   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=192.168.1.66

   查看配置文件发现确实不匹配实际beta.kubernetes.io/os=linux 配置文件为beta.kubernetes.io/os=linux

 

   修改或者注释这两行即可

   部署DNS以后测试

kubectl run -it --image=busybox:1.28.4 --rm --restart=Never sh

   PS:镜像需要使用1.28.4版本

  解析 nslookup加svc名

nslookup kubernetes

 

 

   默认的service是在默认的命名空间default下

# kubectl get svc -n default
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.10.10.1     <none>        443/TCP        9d
my-service   NodePort    10.10.10.196   <none>        80:37159/TCP   2d18h

   创建一个容器使用命名空间为kube-system

 kubectl run -it --image=busybox:1.28.4 --rm --restart=Never sh -n kube-system

   因为该容器的命名空间是kube-system所以无法解析默认命名空间default下的service需要在域名后加命名空间名称访问

# nslookup kubernetes
Server:    10.10.10.2
Address 1: 10.10.10.2 coredns.kube-system.svc.cluster.local

nslookup: can't resolve 'kubernetes'
/ # nslookup kubernetes.default
Server:    10.10.10.2
Address 1: 10.10.10.2 coredns.kube-system.svc.cluster.local

Name:      kubernetes.default
Address 1: 10.10.10.1 kubernetes.default.svc.cluster.local

   

  排错:nslookup可以正确解析外网DNS例如www.baidu.com但是无法解析内网DNS

  查看core日志

 kubectl logs  -n kube-system coredns-7777dd7b8c-7dv26

   

E0309 03:15:43.061842       1 reflector.go:205] github.com/coredns/coredns/plugin/kubernetes/controller.go:318: Failed to list *v1.Namespace: Get https://10.10.10.1:443/api/v1/namespaces?limit=500&resourceVersion=0: x509: certificate is valid for 10.0.0.1, 127.0.0.1, 192.168.1.60, 192.168.1.61, 192.168.1.62, 192.168.1.63, 192.168.1.64, 192.168.1.65, 192.168.1.66, not 10.10.10.1

   原因是因为在创建api证书的时候填写hosts信息错误

 

   修改IP地址以后重新创建证书重启api即可

posted @ 2020-03-06 11:36  minseo  阅读(2342)  评论(0编辑  收藏  举报