六,k8s集群service资源

Service简介

service的基本说明:
Service 是作用于客户端可服务端(Pod)之间,作为一个固定的中间层
主要依赖于kubernetes中的DNS服务,1.11版本之前用的是kube-dns
而之后的版本使用的CoreDNS服务。

在kubernetes中有三种网络:

1. node network
2. pod network
3. cluster network (service network/virtual IP) 集群IP/虚拟IP,实质就是iptables中的规则

kube-proxy通过watch监视api service 有关Service的变动

kubernetes有三种代理模式:
1. userspace    1.1 之前(过于麻烦,需要经过iptables两次)
2. iptables     1.10 之前
3. ipvs         1.11 之后(如果ipvs没被激活,会降级至iptables)

ipvs模型示意图

Service 类型
ExternalName    # 关联集群外部的一个服务,用于集群内部有需求访问的资源通过Service去访问。
ClusterIP       # 默认,配置一个集群IP,仅用于集群内部使用
NodePort        # 集群外部,可与外部通信
LoadBalancer    # 把集群环境部署在云环境中,而云环境也支持LB
Headless Service  #无头service
ExternelName  #把集群外部的服务映射给集群内部使用, 是一个FQDN的名称,一个CNAME名称,这个CNAM指向公网的FQDN

ClusterIP

工作原理:提供一个集群内的虚拟IP以供pod使用

示意图:

ClusterIP 实测

[root@master manifests]# cat svc-redis.yaml 
apiVersion: v1
kind: Service       # 指定类型
metadata:
  name: redis
  namespace: default
spec:
  selector:         # 标签选择器
    app: redis
    role: logstor
  clusterIP: 10.97.97.97    # 这里的clusterIP 可以手动指定IP,如果不指定,则会自动获取一个IP
  type: ClusterIP
  ports:
  - port: 6379              # 这里的端口表示Service暴露的端口
    targetPort: 6379        # 这里表示匹配到的Pod 端口

创建

[root@master manifests]# kubectl apply -f svc-redis.yaml 
service/redis created
[root@master manifests]# kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE   SELECTOR
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP    15d   <none>
redis        ClusterIP   10.97.97.97   <none>        6379/TCP   5s    app=redis,role=logstor        # 这里可以看出已经匹配到了对应的Pod
[root@master manifests]# kubectl describe svc redis
Name:              redis
Namespace:         default
Labels:            <none>
Annotations:       kubectl.kubernetes.io/last-applied-configuration:
                     {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"redis","namespace":"default"},"spec":{"clusterIP":"10.97.97.97","...
Selector:          app=redis,role=logstor
Type:              ClusterIP
IP:                10.97.97.97
Port:              <unset>  6379/TCP
TargetPort:        6379/TCP
Endpoints:         10.244.1.24:6379 ##endpoints是存在于service和pod之间的
Session Affinity:  None
Events:            <none>
[root@master manifests]# kubectl get pods -o wide
NAME                           READY   STATUS    RESTARTS   AGE     IP            NODE                NOMINATED NODE   READINESS GATES
myapp-ds-8tvmc                 1/1     Running   0          5h34m   10.244.1.25   node03.kubernetes   <none>           <none>
myapp-ds-cs2hw                 1/1     Running   0          5h33m   10.244.3.27   node01.kubernetes   <none>           <none>
myapp-ds-f2pp8                 1/1     Running   0          5h34m   10.244.2.20   node02.kubernetes   <none>           <none>
redis-5c998b644f-wnzrd         1/1     Running   0          5h59m   10.244.1.24   node03.kubernetes   <none>           <none>       # 这里redis的Pod 和刚刚创建svc匹配的Pod的IP地址相同

资源记录:

SVC_NAME.NSNAME.DEMAIN.LTD.

svc.cluster.local. 集群默认后缀

手动测试集群内创建的DNS解析:

按照上面的记录,资源解析记录为: redis.default.svc.cluster.local.

进入到其中一台Pod中尝试解析:

[root@master manifests]# kubectl exec -it myapp-ds-8tvmc -- /bin/sh
/ # 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

Headless(无头service)

Headless Service也是一种Service,但不同的是会定义spec:clusterIP: None,也就是不需要Cluster IP的Service。

头Service区别是 ClusterIP 为空,而解析到的Service 直接是后端的Pod的IP地址

[root@master manifests]# cat myapp-svc-headless.yaml 
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
  namespace: default
spec:
  selector:
    app: myapp
    release: canary
  clusterIP: "None"     # 这里定义为None即可
  ports:
  - port: 80
    targetPort: 80
    NodePort: #节点端口,可以不指定,会自动分配
[root@master manifests]# kubectl apply -f myapp-svc-headless.yaml 
service/myapp-svc created
[root@master manifests]# kubectl get svc
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP        16d
myapp        NodePort    10.99.99.99   <none>        80:30080/TCP   17h
myapp-svc    ClusterIP   None          <none>        80/TCP         3s
redis        ClusterIP   10.97.97.97   <none>        6379/TCP       18h

下面手动解析测试:

[root@master manifests]# dig -t A myapp-svc.default.svc.cluster.local. @10.96.0.10

; <<>> DiG 9.9.4-RedHat-9.9.4-74.el7_6.1 <<>> -t A myapp-svc.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 52484
;; flags: qr aa rd; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; 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. 30 IN A    10.244.1.20
myapp-svc.default.svc.cluster.local. 30 IN A    10.244.3.23
myapp-svc.default.svc.cluster.local. 30 IN A    10.244.3.22     # 这里解析的是匹配到的后端的Pod地址
myapp-svc.default.svc.cluster.local. 30 IN A    10.244.2.16
myapp-svc.default.svc.cluster.local. 30 IN A    10.244.2.15

;; Query time: 1 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Fri Jul 26 10:04:24 CST 2019
;; MSG SIZE  rcvd: 319
[root@master manifests]# kubectl get pods -o wide -l app=myapp
NAME                           READY   STATUS    RESTARTS   AGE   IP            NODE                NOMINATED NODE   READINESS GATES
myapp-deploy-f4db5d79c-7hnfg   1/1     Running   0          46h   10.244.2.16   node02.kubernetes   <none>           <none>
myapp-deploy-f4db5d79c-85hpm   1/1     Running   0          46h   10.244.3.22   node01.kubernetes   <none>           <none>
myapp-deploy-f4db5d79c-b9h4s   1/1     Running   0          46h   10.244.2.15   node02.kubernetes   <none>           <none>
myapp-deploy-f4db5d79c-tm9mt   1/1     Running   0          46h   10.244.1.20   node03.kubernetes   <none>           <none>
myapp-deploy-f4db5d79c-xp8t6   1/1     Running   0          46h   10.244.3.23   node01.kubernetes   <none>           <none>

而解析有头的Service 则是Service自己的地址:

[root@master manifests]# dig -t A myapp.default.svc.cluster.local. @10.96.0.10

; <<>> DiG 9.9.4-RedHat-9.9.4-74.el7_6.1 <<>> -t A myapp.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14743
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;myapp.default.svc.cluster.local. IN    A

;; ANSWER SECTION:
myapp.default.svc.cluster.local. 30 IN  A   10.99.99.99

;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Fri Jul 26 10:05:33 CST 2019
;; MSG SIZE  rcvd: 107

NodePort

工作原理:用来对集群外暴露service, 你可以通过访问集群内的每个NodeIP:NodePort的方式访问到对应的service后端的Endpoint

示意图:

NodePod实测

 apiVersion: v1
 kind: Service
 metadata:
     name: myapp
     namespace: default
 spec:
     selector:
         app: myapp
         release: canary
     clusterIP: 10.99.99.99
     type: NodePort
     ports:
     - port: 80
       targetPort: 80
       #nodePort: 30080 nodePort可以自己指定, 如果没有指定, k8s会自动生成一个端口, 指定的好处是便于记忆, 坏处是容易冲突

kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"ClientIP"}}' #会话亲和性,同一个client的访问调度到同一个pod
kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"None"}}' #修改完会立即生效

posted @ 2019-09-26 17:55  戴红领巾的少年  阅读(555)  评论(0编辑  收藏  举报
感谢您的阅读,如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮。本文欢迎各位转载,但是转载文章之后必须在文章页面中给出作者和原文连接