k8s入门系列之svc基础篇 – 21运维
通知: .-欢迎从事运维的朋友加QQ群:717973157

k8s入门系列之svc基础篇

K8S 21运维 44浏览

1,service介绍
Service(简称svc)定义了Pod的逻辑集合和访问该集合的策略,是真实服务的抽象。Service提供了一个统一的服务访问入口以及服务代理和发现机制,用户不需要了解后台Pod是如何运行。Service通过Label找到Pod组。因为Service是抽象的,所以在图表里通常看不到它们的存在,这也就让这一概念更难以理解。
svc在整个集群中负责网络服务(并不是底层容器网络实现),因为pod实际上是不可靠的,可能会被停止或者重启,一旦重启就会导致IP地址发生变化,SVC的功能就是使用kube-proxy进行网络的控制,pod的IP发生变化上层业务并不会中断,kube-proxy采用负载均衡等策略实现网络服务。
例如通过定义一个RC启动了4个pod,如何让外部能优雅的调用到这几个pod提供的服务?由于pod的IP地址可能随时发生变化(pod不健康或期间被重启或被重建等),在pod的外层使用nginx等进行负载也就不太方便了,而Service 就是解决这个问题而存在的:可以根据pod的标签将对应的所有pod纳入一个负载均衡组的形式,通过kube-proxy 进行数据转发,提供一个外部到pod的唯一入口而不用关心pod的变动,进而实现和外部的调用通信。

2,service网络服务模式
Service 创建网络服务一般分为集群内部访问(clusterIP )和集群外部访问(NodePort)模式:
clusterIP 的方式会创建一个虚拟IP地址,该地址没有基于某个实际网卡创建,所以在宿主机上是无法访问的,仅能在集群内部访问,也就是在容器内部访问;
NodePort 是通过映射端口到宿主机的方式,访问地址为宿主机IP地址加上端口的方式,和hostPort 类似,但是NodePort 会在kubernetes集群的所有node上监听,也就是说创建一个Service ,配置了一个NodePort 监听30000端口,那么集群内所有的node都会监听30000端口,不管访问该node上有没有对应的pod,随意访问任何一台node的30000端口都可以被转发到正确的后端pod中;
3,创建service
(1)集群内部访问。
基于以前的ng-rc.yml创建一个最简单的service,案例yml如下:

[[email protected] yaml]# cat  ng-rc-svc.yml 
apiVersion: v1  
kind: Service  
metadata:  
  name: ng-svc
  labels:  
    name: ng-svc 
spec: 
  ports:  
  - port: 88
    targetPort: 80  
    protocol: TCP
  selector:  
    app: ng-rc

kind: Service 指定创建一个Service
– port: 88 指的是监听88端口
targetPort: 80 是指定后端pod监听的端口
selector:
app: ng-rc 指定具有app标签,且值为ng-rc 的pod全部纳入本组Service
通过create 创建好后可以查看到clusterIP和端口等信息:

[[email protected] yaml]# kubectl  get  svc   ng-svc   -o wide
NAME      CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE       SELECTOR
ng-svc    10.254.99.239           88/TCP    1d        app=ng-rc

10.254.99.239 这个ip是虚拟的,也就是我们之前master 的apiserver里边定义的ip range。创建好以后进入这个pod可以访问到nginx的欢迎界面,但这个只能在集群内部访问,外部无法访问,没什么意义。只是作为了解即可。

(2)集群外部访问(nodeport模式)
通过这种模式,创建svc以后,集群里边的每一个node都会监听我们定义好的端口,并将该端口映射到pod,这样就实现了外部访问。案例yml如下:

[[email protected] yaml]# cat  ng-rc-svc-nodeport.yml 
piVersion: v1  
kind: Service  
metadata:  
  name: ng-svc-nodeport
  labels:  
    name: ng-svc-nodeport 
spec: 
  type: NodePort 
  ports:  
  - port: 30000
    targetPort: 80  
    protocol: TCP
    nodePort: 30000
  selector:  
    app: ng-rc

使用NodePort 模式,也就是外部能直接访问的模式需要定义type: NodePort
nodePort: 30000 是实际提供外部访问的端口,默认端口是30000-32767 范围,为了避免混淆,建议把除targetPort 外的端口都设置为相同。

查看Service 是否正确接管pod的网络服务可以使用命令:

[[email protected] yaml]# kubectl   get endpoints
NAME              ENDPOINTS                                               AGE
kubernetes        10.1.14.11:6443                                         1d
ng-svc            172.40.3.2:80,172.40.3.3:80,172.40.7.2:80 + 1 more...   1d
ng-svc-nodeport   172.40.3.2:80,172.40.3.3:80,172.40.7.2:80 + 1 more...   21h

可见新定义的service ng-svc-nodeport 下有4个pod,pod的内部ip以及容器内部端口。说明service是创建成功的。这个时候我们通过node1和node2节点查看,也都有30000这个端口监听,实际这个端口是kube-proxy监听,kube-proxy负责为Pod创建代理服务,Kubernetes Proxy会从Kubernetes API Server获取所有的Service信息,并根据Service的信息创建代理服务,实现Service到Pod的请求路由和转发,从而实现Kubernetes层级的虚拟转发网络。

理论上来讲我们可以通过访问node1或者node2的ip:30000就可以访问到nginx的欢迎界面了,机器其中pod跑到node1节点,访问node2的ip也是可以访问。
这里有一个问题,就是一开始会无法访问,需要解决一个问题:
docker 1.13 版本对iptables的规则进行了改动,默认FORWARD 链的规则为DROP ,整个影响就是规则DROP后,不同主机间就不能正常通信了(kubernetes的网络使用flannel情况),
临时解决办法,每个node执行如下命令(node机器重启就失效):

iptables -P FORWARD ACCEPT

根本解决办法:
修改Docker启动参数,在[Service] 区域末尾加上参数:

vim /usr/lib/systemd/system/docker.service
[Service]
............
ExecStartPost=/sbin/iptables -I FORWARD -s 0.0.0.0/0 -j ACCEPT

重启相关服务:

systemctl daemon-reload
systemctl restart docker

测试node节点机器重启或查看iptables -nvL 以后的转发通信都正常了。

参考文章:
svc 创建:https://www.cnyunwei.cc/archives/1595
service概念说明: https://blog.csdn.net/magerguo/article/details/72123278

转载请注明:21运维 » k8s入门系列之svc基础篇