kubernetes 服务访问

简介

kubernetes 使用service和ingress共同构建了,外部访问k8s内部容器的通道。

Service

概念

Service是定义一系列Pod以及访问这些Pod的策略的一层抽象

Pods是短暂的,那么重启时IP地址可能会改变,为了能从前端容器正确可靠地指向后台容器

Service通过Label找到Pod组。因为Service是抽象的,所以在图表里通常看不到它们的存在,这也就让这一概念更难以理解。

现在,假定有2个后台Pod,并且定义后台Service的名称为‘backend-service’,lable选择器为(tier=backend, app=myapp)。backend-service 的Service会完成如下两件重要的事情:

  • 会为Service创建一个本地集群的DNS入口,因此前端Pod只需要DNS查找主机名为 ‘backend-service’,就能够解析出前端应用程序可用的IP地址。
  • 现在前端已经得到了后台服务的IP地址,但是它应该访问2个后台Pod的哪一个呢?Service在这2个后台Pod之间提供透明的负载均衡,会将请求分发给其中的任意一个(如下面的动画所示)。通过每个Node上运行的代理(kube-proxy)完成。

下述动画展示了Service的功能。注意该图作了很多简化。如果不进入网络配置,那么达到透明的负载均衡目标所涉及的底层网络和路由相对先进。


k8s-service.gif

在实际生产环境中,对Service的访问可能会有两种来源:Kubernetes集群内部的程序(Pod)和Kubernetes集群外部,为了满足上述的场景,Kubernetes service有以下三种类型:

  • ClusterIP:提供一个集群内部的虚拟IP以供Pod访问。
  • NodePort:在每个Node上打开一个端口以供外部访问。
  • LoadBalancer:通过外部的负载均衡器来访问。

ClusterIP

此模式会提供一个集群内部的虚拟IP(与Pod不在同一网段),以供集群内部的pod之间通信使用。
ClusterIP也是Kubernetes service的默认类型。

clusterip.png

为了实现图上的功能主要需要以下几个组件的协同工作

  • apiserver
    用户通过kubectl命令向apiserver发送创建service的命令,apiserver接收到请求以后将数据存储到etcd中。
  • kube-proxy
    kubernetes的每个节点中都有一个叫做kube-proxy的进程,这个进程负责感知service,pod的变化,并将变化的信息写入本地的
    iptables中。
  • iptables
    使用NAT等技术将virtualIP的流量转至endpoint中。
    下面我们实际发布一个Service,能够更清晰的了解到Service是如何工作的。

发布一个rc,并指定replices count为3.

yancey@ yancey-macbook kubernetes-1$kubectl create -f rc_nginx.yaml
yancey@ yancey-macbook kubernetes-1$kubectl get pods
NAME                     READY     STATUS    RESTARTS   AGE
k8s-master-core-v2-01    4/4       Running   0          8m
k8s-proxy-core-v2-01     1/1       Running   0          8m
nginx-controller-6bovu   1/1       Running   0          4m
nginx-controller-iowux   1/1       Running   0          4m
nginx-controller-o7m6u   1/1       Running   0          4m
yancey@ yancey-macbook kubernetes-1$kubectl describe pod nginx-controller-6bovu
Name:       nginx-controller-6bovu
Namespace:  default
Node:       core-v2-01/172.17.8.101
Start Time: Fri, 17 Jun 2016 15:22:20 +0800
Labels:     app=nginx
Status:     Running
IP:     10.1.13.3
Controllers:    ReplicationController/nginx-controller

发布一个service,并指定步骤1中的label

yancey@ yancey-macbook kubernetes-1$kubectl create -f service_nginx.yaml
yancey@ yancey-macbook kubernetes-1$kubectl get svc
NAME            CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
kubernetes      10.0.0.1     <none>        443/TCP    9m
nginx-service   10.0.0.252   <none>        8000/TCP   4m

kubernetes为nginx-server这个service创建了一个10.0.0.252这个ClusterIP,也可以称为VirtualIP.

yancey@ yancey-macbook kubernetes-1$kubectl get ep
NAME            ENDPOINTS                                AGE
kubernetes      172.17.8.101:6443                        9m
nginx-service   10.1.13.2:80,10.1.13.3:80,10.1.13.4:80   4m

查看endpoint信息,发现nginx-service一共有三个endpoint地址,分别对应nginx的三个pod。

查看iptables,观察其NAT表中的信息(只截取了部分和这个service有关的信息)
查看iptables中NAT表的命令: iptables -L -v -n -t nat

Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
   37  2766 KUBE-SERVICES  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
   33  2112 DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

在PREROUTING链中会先匹配到KUBE-SERVICES这个Chain。

Chain KUBE-SERVICES (2 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 KUBE-SVC-GKN7Y2BSGW4NJTYL  tcp  --  *      *       0.0.0.0/0            10.0.0.252           /* default/nginx-service: cluster IP */ tcp dpt:8000
   18  1080 KUBE-NODEPORTS  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL

所有destinationIP为10.0.0.252的包都转到KUBE-SVC-GKN7Y2BSGW4NJTYL这个Chain

Chain KUBE-SVC-GKN7Y2BSGW4NJTYL (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 KUBE-SEP-7ROBBXFV7SD4AIRW  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/nginx-service: */ statistic mode random probability 0.33332999982
    0     0 KUBE-SEP-XY3F6VJIZ7ELIF4Z  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/nginx-service: */ statistic mode random probability 0.50000000000
    0     0 KUBE-SEP-JIDZHFC4A3T535AK  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/nginx-service: */

这里能看到请求会平均执行KUBE-SEP-7ROBBXFV7SD4AIRW,KUBE-SEP-XY3F6VJIZ7ELIF4Z,KUBE-SEP-XY3F6VJIZ7ELIF4Z这三个Chain.最后我们看下KUBE-SEP-7ROBBXFV7SD4AIRW这个Chain做了什么

Chain KUBE-SEP-7ROBBXFV7SD4AIRW (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 KUBE-MARK-MASQ  all  --  *      *       10.1.13.2            0.0.0.0/0            /* default/nginx-service: */
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/nginx-service: */ tcp to:10.1.13.2:80

这个Chain使用了DNAT规则将流量转发到10.1.13.2:80这个地址。至此从Pod发出来的流量通过本地的iptables将流量转至了service背后的pod上。

NodePort

Kubernetes将会在每个Node上打开一个端口并且每个Node的端口都是一样的,通过<NodeIP>:NodePort的方式Kubernetes集群外部的程序可以访问Service。

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: NodePort
  ports:
  - port: 8000
    targetPort: 80
    protocol: TCP
  # just like the selector in the replication controller,
  # but this time it identifies the set of pods to load balance
  # traffic to.
  selector:
    app: nginx

发布这个service,可以看到已经随机分配了一个NodePort端口。

yancey@ yancey-macbook kubernetes-1$kubectl get svc nginx-service -o yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: 2016-06-18T03:29:42Z
  name: nginx-service
  namespace: default
  resourceVersion: "1405"
  selfLink: /api/v1/namespaces/default/services/nginx-service
  uid: e50ba23a-3504-11e6-a94f-080027a75e9e
spec:
  clusterIP: 10.0.0.229
  ports:
  - nodePort: 30802
    port: 8000
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  sessionAffinity: None
  type: NodePort
status:
  loadBalancer: {}

观察Iptables中的变化,KUBE-NODEPORTS这个Chain中增加了如下内容

Chain KUBE-NODEPORTS (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 KUBE-MARK-MASQ  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/nginx-service: */ tcp dpt:30802
    0     0 KUBE-SVC-GKN7Y2BSGW4NJTYL  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/nginx-service: */ tcp dpt:30802

可以看到流量会转至KUBE-SVC-GKN7Y2BSGW4NJTYL这个Chain中处理一次,也就是ClusterIP中提到的通过负载均衡将流量平均分配到3个endpoint上。

LoadBalancer

Ingress

概念

通常情况下,service和pod仅可在集群内部网络中通过IP地址访问。所有到达边界路由器的流量或被丢弃或被转发到其他地方。从概念上讲,可能像下面这样:

    internet
        |
  ------------
  [ Services ]

Ingress是授权入站连接到达集群服务的规则集合。

    internet
        |
   [ Ingress ]
   --|-----|--
   [ Services ]

你可以给Ingress配置提供外部可访问的URL、负载均衡、SSL、基于名称的虚拟主机等。用户通过POST Ingress资源到API server的方式来请求ingress。 Ingress controller负责实现Ingress,通常使用负载平衡器,它还可以配置边界路由和其他前端,这有助于以HA方式处理流量。

你需要一个Ingress Controller来实现Ingress,单纯的创建一个Ingress没有任何意义。

GCE/GKE会在master节点上部署一个ingress controller。你可以在一个pod中部署任意个自定义的ingress controller。你必须正确地annotate每个ingress,比如 运行多个ingress controller 和 关闭glbc

为了使Ingress正常工作,集群中必须运行Ingress controller。 这与其他类型的控制器不同,其他类型的控制器通常作为kube-controller-manager二进制文件的一部分运行,在集群启动时自动启动。 你需要选择最适合自己集群的Ingress controller或者自己实现一个。

实践

单Service Ingress

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
spec:
  backend:
    serviceName: testsvc
    servicePort: 80

使用kubectl create -f命令创建,然后查看ingress:

$ kubectl get ing
NAME                RULE          BACKEND        ADDRESS
test-ingress        -             testsvc:80     107.178.254.228

107.178.254.228就是Ingress controller为了实现Ingress而分配的IP地址。RULE列表示所有发送给该IP的流量都被转发到了BACKEND所列的Kubernetes service上。

简单展开

如前面描述的那样,kubernete pod中的IP只在集群网络内部可见,我们需要在边界设置一个东西,让它能够接收ingress的流量并将它们转发到正确的端点上。这个东西一般是高可用的loadbalancer。使用Ingress能够允许你将loadbalancer的个数降低到最少,例如,嫁入你想要创建这样的一个设置:

foo.bar.com -> 178.91.123.132 -> / foo    s1:80
                                 / bar    s2:80

你需要一个这样的ingress:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /foo
        backend:
          serviceName: s1
          servicePort: 80
      - path: /bar
        backend:
          serviceName: s2
          servicePort: 80

使用kubectl create -f创建完ingress后:

$ kubectl get ing
NAME      RULE          BACKEND   ADDRESS
test      -
          foo.bar.com
          /foo          s1:80
          /bar          s2:80

只要服务(s1,s2)存在,Ingress controller就会将提供一个满足该Ingress的特定loadbalancer实现。 这一步完成后,您将在Ingress的最后一列看到loadbalancer的地址。

基于名称的虚拟主机

Name-based的虚拟主机在同一个IP地址下拥有多个主机名。

foo.bar.com --|                 |-> foo.bar.com s1:80
              | 178.91.123.132  |
bar.foo.com --|                 |-> bar.foo.com s2:80

下面这个ingress说明基于 Host header的后端loadbalancer的路由请求:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - backend:
          serviceName: s1
          servicePort: 80
  - host: bar.foo.com
    http:
      paths:
      - backend:
          serviceName: s2
          servicePort: 80

默认backend:一个没有rule的ingress,如前面章节中所示,所有流量都将发送到一个默认backend。你可以用该技巧通知loadbalancer如何找到你网站的404页面,通过制定一些列rule和一个默认backend的方式。如果请求header中的host不能跟ingress中的host匹配,并且/或请求的URL不能与任何一个path匹配,则流量将路由到你的默认backend。

TLS

你可以通过指定包含TLS私钥和证书的 secret 来加密Ingress。 目前,Ingress仅支持单个TLS端口443,并假定TLS termination。 如果Ingress中的TLS配置部分指定了不同的主机,则它们将根据通过SNI TLS扩展指定的主机名(假如Ingress controller支持SNI)在多个相同端口上进行复用。 TLS secret中必须包含名为tls.crttls.key的密钥,这里面包含了用于TLS的证书和私钥,例如:

apiVersion: v1
data:
  tls.crt: base64 encoded cert
  tls.key: base64 encoded key
kind: Secret
metadata:
  name: testsecret
  namespace: default
type: Opaque

在Ingress中引用这个secret将通知Ingress controller使用TLS加密从将客户端到loadbalancer的channel:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: no-rules-map
spec:
  tls:
    - secretName: testsecret
  backend:
    serviceName: s1
    servicePort: 80

各种Ingress controller支持的TLS功能之间存在差距。 请参阅有关
nginx,gce 或任何其他平台特定Ingress controller的文档,以了解TLS在你的环境中的工作原理。

Ingress controller启动时附带一些适用于所有Ingress的负载平衡策略设置,例如负载均衡算法,后端权重方案等。更高级的负载平衡概念(例如持久会话,动态权重)尚未在Ingress中公开。 你仍然可以通过 service loadbalancer获取这些功能。 随着时间的推移,我们计划将适用于跨平台的负载平衡模式加入到Ingress资源中。

还值得注意的是,尽管健康检查不直接通过Ingress公开,但Kubernetes中存在并行概念,例如准备探查,可以使你达成相同的最终结果。 请查看特定控制器的文档,以了解他们如何处理健康检查。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Kubernetes是Google开源的容器集群管理系统,其提供应用部署、维护、 扩展机制等功能,利用Kubern...
    devabel阅读 6,296评论 0 13
  • 1、基础架构 1.1 Master Master节点上面主要由四个模块组成:APIServer、scheduler...
    阿斯蒂芬2阅读 10,845评论 0 44
  • 一、 K8s 是什么? Kubernetes(k8s)是自动化容器操作的开源平台,这些操作包括部署,调度和节点集群...
    loveroot阅读 6,636评论 1 21
  • kubernetes 简介 一个迅速过一遍kubernetes 非常不错的资源:基于Kubernetes构建Doc...
    bradyjoestar阅读 15,277评论 2 7
  • 端午节注定是寻虐的日子,还记得去年的端午在沙漠中度过的,一个月前约定了跟天津翱翔户外俱乐部来大五,直到出发前一个小...
    Vivian_wh阅读 510评论 1 0