今天是2019-5-11,那么我们来看一下kubernetes Service 资源配置清单的书写。
在安装配置的时候我们设置service处于哪个模式,那么services的工作就在哪个模式( iptables ipvs userspace )----三种代理模式。
Service:
工作模式: userspace , iptables , ipvs
Userspace: 1.1-
Iptables: 1.10-
Ipvs: 1.11+
那么下来我们看一下如何使用清单创建一个service资源:
和之前的类似 我们可以使用explian来查看service的定义,
[root@server1 ~]# kubectl explain svc
FIELDS:
apiVersion
APIVersion defines the versioned schema of this representation of an
object. Servers should convert recognized schemas to the latest internal
value, and may reject unrecognized values. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#resources
kind
Kind is a string value representing the REST resource this object
represents. Servers may infer this from the endpoint the client submits
requests to. Cannot be updated. In CamelCase. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
metadata
spec
status
可以看到类似于之前的配置清单的书写,一共也是五个字段(apiVersion , kind , metadata, spec ,status --系统的状态,无须定义)
下来我们看一下重要的spec中的字段:[root@server1 ~]# kubectl explain svc.spec
ports <[]Object> : 把哪个后端容器的端口建立成关联的关系
selector
clusterIP
type
那么这个type是service的类型:一共有四种: 默认是 ClusterIP ,先要接入外部的IP是 NodePort , LoadBalancer 表示把k8s部署在虚拟机上,而虚拟机在云盘上,而云盘支持一键调用,自动触发在集群的外部创建一个负载均衡器,
1. 我们先来说clusterIP这种资源的Service的创建 。
在 svc.spec.ports 的文档中 发现有三种类型的端口: nodePort
port
在spec中的slector中有什么样的字段 : selector
给出清单定义中的内容:
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: default
spec:
selector:
app: redis
role: logstor
clusterIP: 10.97.97.97
type: ClusterIP
ports:
- port: 6379
targetPort: 6379
[root@server1 ~]# kubectl apply -f redis-svc.yaml
service/redis created
[root@server1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1
redis ClusterIP 10.97.97.97
[root@server1 ~]# kubectl describe svc redis
Name: redis
Namespace: default
Labels:
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"redis","namespace":"default"},"spec":{"clusterIP":"10.97.97.97","ports":[{"por...
Selector: app=redis,role=logstor
Type: ClusterIP
IP: 10.97.97.97
Port:
TargetPort: 6379/TCP
Endpoints: 10.244.2.62:6379 这个后端的pod的地址
Session Affinity: None
Events:
那么service是不会直接到Pod的,service会直接到endpoints资源,那么endpoints就是地址+端口 ,然后再由endpoints关联到后端的pod,只不过我们再理解的时候就好像是service直接被pod关联了,那么我们可以手动的创建endpoints 。
资源记录: SVC_NS_NAME.DOMAIN.LTD. 集群默认的域名是 : svc.cluster.local 默认的格式:redis.default.svc.cluster.local
下来我们要创建一个NodePort类型的service资源,怎么创建? 思路: 我们只要在之前的资源配置中修改type就可以了:
下面是nodePort的资源的定义清单: 注: 注意:node'port的端口,这个端口不能是节点上已经存在的端口,否则会覆盖
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: default
spec:
selector:
app: myapp
clusterIP: 10.99.99.99
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30080
[root@server1 ~]# kubectl apply -f myapp-svc.yaml
service/myapp created
[root@server1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1
myapp NodePort 10.99.99.99
redis ClusterIP 10.97.97.97
[root@server1 ~]# kubectl describe svc myapp
Name: myapp
Namespace: default
Labels:
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"clusterIP":"10.99.99.99","ports":[{"nod...
Selector: app=myapp
Type: NodePort
IP: 10.99.99.99
Port:
TargetPort: 80/TCP
NodePort:
Endpoints: 10.244.1.66:80,10.244.1.67:80,10.244.1.69:80 + 2 more...
Session Affinity: None
External Traffic Policy: Cluster
Events:
下来我们在集群之外的节点上对我们的集群中的service对象的实例进行测试 :
[root@loaclhost kiosk]# while true; do curl http://172.25.254.1:30080/hostname.html ; sleep 1; done
myapp-deploy-69b47bc96d-gzlrk
myapp-deploy-69b47bc96d-92vkp
myapp-deploy-69b47bc96d-gzlrk
myapp-deploy-69b47bc96d-s4qlh
myapp-deploy-69b47bc96d-57vph
myapp-deploy-69b47bc96d-92vkp
myapp-deploy-69b47bc96d-x97jg
myapp-deploy-69b47bc96d-gzlrk
.....................
除此之外我们还可以对我们service中的pod做滚动更新;
下来我们说一下另一种类型的LoadBalancer : 下面我们简单的说一下它的原理 :
比如说: 你再阿里云上买了四个虚拟主机 ,在四个虚拟主机上部署了k8s集群,这个集群可以于底层的公有云交互,能够调度底层的iaaps,调度的时候能够请求外部的节点, 那么在其中的三个pod中会对外开放一个端口,这个三个节点的端口上提供相应的服务,他们会自动通过底层的iaas的负载均衡器的时候自动的去连接,那么客户通过外部的阿里云的客户端访问的时候,会先访问内部的负载均衡器,那么由负载均衡器调度到相应的node节点上 ,nodeport需要把请求转发给service,再由service由集群内部负载至pod对象上,这是一个两级的负载均衡。
第四种的资源类型 : ExternalName
作用: 用于在集群中实现搭建一个服务,这个service的服务的端点并不是本地的pod,那么将这个service关联到外部的客户端,那么在pod通过service访问外部的服务的时候,外部的服务先提交给nodeIP ,再由nodeIP转交给service,再由service转交给pod,那么pod就可以访问外部的服务了,这叫: 外部名称服务
externalName : 是一个name,而且很关键这个name必须被DNS解析 ,所以这个externalname 引用的时候,场景不太多 ,在其中的字段中也有支持的, 比如说是: 当k8s 内部的某个域名需要向根域名服务器解析的时候,可以使用这个方法来和外部的服务交互。
在service spec的字段中有个: SsssionAffinity 字段 ,默认情况下是基于源IP,是基于IPTABLES来进行调度的 ,如果我们要定义成ClientIP则表示我们要把来自同一个客户端的请求始终调度到同一个后端pod上去 。
那么我们下来演示一下效果,以path的方式对内部的资源进行添加 :
[root@server1 ~]# kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"ClientIP"}}'
service/myapp patched
[root@server1 ~]# kubectl describe svc myapp
Name: myapp
Namespace: default
Labels:
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"clusterIP":"10.99.99.99","ports":[{"nod...
Selector: app=myapp
Type: NodePort
IP: 10.99.99.99
Port:
TargetPort: 80/TCP
NodePort:
Endpoints: 10.244.1.66:80,10.244.1.67:80,10.244.1.69:80 + 2 more...
Session Affinity: ClientIP
External Traffic Policy: Cluster
Events:
在更改完成以后我们发现在来自同一个客户端的ip时候来自同一个后端的pod对象
[root@server1 ~]# while true ; do curl http://172.25.254.1:30080/hostname.html; sleep 1; done
myapp-deploy-69b47bc96d-x97jg
myapp-deploy-69b47bc96d-x97jg
myapp-deploy-69b47bc96d-x97jg
myapp-deploy-69b47bc96d-x97jg
myapp-deploy-69b47bc96d-x97jg
myapp-deploy-69b47bc96d-x97jg
那么除了ClientIP 我们更改成为 NONE
[root@server1 ~]# kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"None"}}'
service/myapp patched
那么None的效果就是在后端的任意的pod中随机的选择相应的pod资源进行访问。
那么service中还有一种类型成为 headlist : 无头
那么之前在service解析的时候,service_name : 其实就是Cluster IP 是自动生成的,那么除此之外我们还可以手动的指定,那么无头就意味着没有service_name 即不手动的指定,也不自动的生成,那么service就会向pod去解析,解析为pod 的IP ---pod IP ,直达后面的pod 。
我们来看一下这个参数的效果: [root@server1 ~]# vim myapp-headless.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-headless
namespace: default
spec:
selector:
app: myapp
clusterIP: None 将ClusterIP的地址直接指明为空,即表示 headless
ports:
- port: 80
targetPort: 80
nodePort: 30080
那么无头的解析的时候通常会有很多的,pod后端的地址,那么有头的解析的时候通常是固定的指定的地址 ,
我在使用dig 的时候系统报错了 : 如下: 如果dig 在正确的则可以看到相应的pod解析的地址
[root@server1 ~]# dig -t A myapp-svc.default.svc.cluster.local. @10.96.0.10
; <<>> DiG 9.9.4-RedHat-9.9.4-37.el7 <<>> -t A myapp-svc.default.svc.cluster.local. @10.96.0.1
;; global options: +cmd
;; connection timed out; no servers could be reached
上述的错误我们已经成功的解决了,如果有和我的情况相同的同仁们可以参考:
https://blog.csdn.net/qq_42339633/article/details/90112854
那么在解析后的service就是后端的地址的IP拉 : 我们来看一下
[root@server1 ~]# dig -t A myapp-svc.default.svc.cluster.local. @10.96.0.10
; <<>> DiG 9.9.4-RedHat-9.9.4-37.el7 <<>> -t A myapp-svc.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39381
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;myapp-svc.default.svc.cluster.local. IN A
;; ANSWER SECTION:
myapp-svc.default.svc.cluster.local. 5 IN A 10.244.1.70
myapp-svc.default.svc.cluster.local. 5 IN A 10.244.1.71
myapp-svc.default.svc.cluster.local. 5 IN A 10.244.1.73
myapp-svc.default.svc.cluster.local. 5 IN A 10.244.2.65
myapp-svc.default.svc.cluster.local. 5 IN A 10.244.2.66
;; Query time: 1 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Sat May 11 18:44:54 CST 2019
;; MSG SIZE rcvd: 319
那么我们还可以使用nslookup在pod内部对名称进行解析:
[root@server1 ~]# kubectl exec -it redis-5b5d6fbbbd-bfs6j -- /bin/sh
/data # nslookup redis.default.svc.cluster.local
nslookup: can't resolve '(null)': Name does not resolve
Name: redis.default.svc.cluster.local
Address 1: 10.97.97.97 redis.default.svc.cluster.local