Kubernetes服务发布基础

        通过 k8s 的调度,我们可以成功的将服务部署到 Kubernetes,应用部署后,最重要的就是对用户开
放。
        在传统的架构中,用户访问公司内的服务可能通过了多层代理、网关、防火墙等。在 Kubernetes 中,访问 Kubernetes 中的的应用同样也会经过多层代理、网关、防火墙等。但是在传统架构中,可能是通过Nginx、Haproxy、LVS、公有云的 SLB、ELB 等实现的负载均衡和域名路由,虽然 Kubernetes 也是通过诸如此类的技术实现的域名路由或者负载均衡,只不过对应的名字叫法可能有所变化,不要把这些当做一个比较新颖的东西,其实内部的实现和之前并无区别。
        在传统架构配置多个相同服务的负载均衡可能使用的是Nginx的upstream,在 Kubernetes 中用Service 实现。在传统架构配置域名访问应用可能使用 Nginx 的 Server 配置,在 Kubernetes 中用Ingress 实现域名路由的配置。

一、Service的定义

        Service 用于为一组提供服务的 Pod 抽象一个稳定的网络访问地址,是 k8s 实现微服务的核心概念通过 service 的定义设置的访问地址是 DNS 域名格式的服务名称,对于客户端应用来说,网络访问方式并没有改变。Service 还提供了负载均衡器的功能,将客户端请求负载分发到后端提供具体服务的各个Pod 上。

        Service 主要用于提供网络服务,通过 Service 的定义,能够为客户端应用提供稳定的访问地址(域名或 IP 地址)和负载均衡功能,以及屏蔽后端 EndPoint 的变化,是 Kubernetes 实现微服务的核心资源。
        总之,service 是 kubernetes 中一个非常重要的概念,service 用于将外部请求代理到内部 pod上,提供4层负载均衡和服务发现的功能,使得我们可以构建高可用和可扩展的应用程序

二、service 的概念和原理

1.service基本介绍

        service 是 kubernetes 中的一种抽象,用于定义一组 pod 以及访问这一组 pod 的策略、service的作用是将一组 pod 封装为一个虚拟的服务,并提供一个统一的入口,供客户端访问。service 支持负载均衡、服务发现、服务暴露等功能。
        在 kubernetes 中,pod 的 IP地址是动态变化的,因此无法直接通过 pod的IP地址进行访问。service的出现正式为了解决找个问题的。service 会为一组 pod 创建一个虚拟的 IP 地址,通过这个 IP 地址可以访问这组 pod 中的任意一个 pod。当客户端请求这个虚拟 IP 地址时,请求会被负载均衡到一组 pod 中的某一个 pod 上,从而完成对 pod 的访问。

        service 的实现依赖于 kube-proxy 组件。kube-proxy 会在每个节点上监听 service 的变化,一旦有 service 发生变化,kube-proxy 会更新本地的 iptables 规则,从而实现流量的转发和负载均衡。

        另外,service 还与 CoreDNS 有关。coreDNS 是 kubernetes 集群中的 DNS 解析服务。在 kubernetes中 service 的虚拟 IP 地址还会注册到 CoreDNS 中,从而使得客户端还可以通过 service 名称访问service 的虚拟 IP 地址。在 service 的定义中,可以通过 spec.selector 字段指定哪些 pod 属于这个service,这样,就可以将请求负载均衡到这些 pod 中。
        总之,service 是 kubernetes 中一种非常重要的资源对象,它可以让 pod 对外提供服务,并提供负载均衡、服务发现等功能。service的实现依赖于kube-proxy和CoreDNS组件,他们共同协作,将service与 pod 连接起来,实现对 pod 的代理访问,如下图所示。

2.Service 的负载均衡机制

当一个 Service 对象在 Kubernetes 集群中被定义出来时,集群内的客户端应用就可以通过服务 IP访问到具体的 Pod 容器提供的服务了。从服务 IP 到后端 Pod 的负载均衡机制,则是由每个 node 上的kube-proxy 代理来负责实现的kubeproxy 的代理模式有:userspace、iptables、ipvs 和kernelspace。

(1)userspace

        起初,kube-proxy进程是一个真实的TCP/UDP代理,当某个pod以clusterIP方式访问某个service的时候,这个流量会被 pod 所在的本机的 iptables 转发到本机的 kube-proxy 进程,然后将请求转发到后端某个 pod 上。具体过程为:

  • kube-proxy 为每个 service 在 node 上打开一个随机端口作为代理端口
  • 建立 iptables 规则,将 clusterip 的请求重定向到代理端口(用户空间)
  • 到达代理端口的请求再由 kubeproxy 转发到后端

        clusterip重定向到kube-proxy服务的过程存在内核态到用户态的切换,开销很大,因此有了iptables模式,而userspace模式也被废弃了。

(2)iptabels

        kubernets从1.2版本开始将iptabels模式作为默认模式,这种模式下kube-proxy不再起到proxy
的作用。其核心功能:通过 API Server 的 Watch 接口实时跟踪 Service 和 Endpoint 的变更信息,并更新对应的 iptables 规则,client 的请求流量通过 iptables 的 NAT 机制“直接路由”到目标 Pod。

        不同于userspace,在 iptables 的模式中,kube-proxy 不再负责转发数据包,kube-proxy 主要完成对 iptables 策略的动态管理。数据包的走向完全由 iptables 规则决定,这样的过程不存在内核态到用户态的切换,效率明显会高很多。但是随着 service的增加,iptables 规则会不断增加,导致内核十分繁忙(等于在读一张很大的没建索引的表)。

(3)ipvs

        从 kubernetes 1.8版本开始引入第三代的 IPVS 模式,它也是基于 netfilter 实现的,但定位不同:iptables 是为防火墙设计的,IPVS 则专门用于高性能负载均衡,并使用高效的数据结构 Hash 表,允许几乎无限的规模扩张。

ipvs 为负载均衡提供了更多的算法:

  • rr:轮训
  • 1c:最小连接数
  • df:目标哈希
  • sh:源哈希
  • sed:预计延迟最短
  • nq:从不排队

        一句话说明:ipvs 使用 ipset 存储 iptables 规则,在査找时类似 hash 表査找,时间复杂度为 0(1)而 iptables 时间复杂度则为 0(n)。
        可以将 ipset 简单理解为 ip 集合,这个集合的内容可以是 IP 地址、IP 网段、端口等,iptabels可以直接添加规则对这个可变集合进行操作,这样做的好处可以大大减少 iptables 规则的数量,从而减少性能损耗。
        如果操作系统没有启用 IPVS 内核模块,kube-proxy 会自动运行为 iptables 模式,如果操作系统启用了 ipvs 模块,则 kube-proxy 会运行为 ipvs 模式。査看系统是否开启了 ipvs 模块,可以使用命令:lsmodgrep ip_vs

注释:
时间复杂度用字母0 表示

(4)kernelspace

Windows server 上的代理模式,此处不作介绍。

3.service的4种类型

kubernetes 支持4中 service 类型。

(1)clusterIP

        这是最常用的 Service 类型,它为 Pod 提供了一个虚拟的 IP 地址。当其他 Pod 需要访问该 Service时,它们只需要使用该虚拟 IP 地址即可。Kubernetes 会自动将请求路由到相应的 Pod 上。

(2)NodePort

        这种 Service 类型将 Pod 公开为集群中所有节点上的某个端口。当外部请求到达任何一个节点上的该端口时,Kubernetes 会将请求路由到相应的 Pod 上。

(3)LoadBalancer

        LoadBalancer Service:这种 Service 类型使用云提供商的负载均衡器将请求路由到后端 Pod。Kubernetes 会自动创建和配置负载均衡器,并将其绑定到 Service 上。

(4)externalName

        ExternalName Service: 这种 Service 类型允许你将 service 映射到集群外部的某个名称。当 Pod需要访问该 Service 时,它们将使用该名称来解析出相应的 IP 地址。

 三、生成用于测试service的Deployment

        编写 Deployment,用于各种 service 的验证。
        在应用 Service 概念之前,先创建一个提供 web 服务的 Pod 集合,有两个 Tomcat 容器副本组成,每个容器提供的服务端口都为 8080.

1.编写deployment

vim webapp-deployment.yaml 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
spec:
  replicas: 2    ##pod 的副本数
  selector:    ##目标 Pod 的标签选择器,
    matchLabels:    ##需要匹配的标签
      app: webapp    ##对应了目标 pod 的标签名称
  template:    ##自动创建新的 pod 副本的模板
    metadata:
      labels:    ##定义 pod 的标签
        app: webapp    ##标签值为 app:webapp
    spec:
      containers:
      - name: webapp
        image: kubeguide/tomcat-app:v1
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP

备注:
        selector(选择器)主要用于资源的匹配,只有符合条件的资源才会被调用或使用,可以使用该方式对集群中的各类资源进行分配。Kubernetes 和核心资源 Deployment、statefulset 管理的 Pod 是通过选择器字段决定的,通过 Service 访问这些后端 Pod 也是通过选择器字段决定的。
        label(标签)可以对 Kubernetes 的其他资源进行配置,当Kubernetes 对系统的任何 API 对象如Pod 进行分组时,会对其添加标签,用以精准的选择对应的API对象。

2.创建该 Deployment

[root@master ~]# ku create -f webapp-deployment.yaml 
deployment.apps/webapp created

3.查看pod创建情况

[root@master ~]# ku get pod
NAME                      READY   STATUS    RESTARTS   AGE
webapp-86b5d9fc88-cgmwx   1/1     Running   0          5s
webapp-86b5d9fc88-hppsp   1/1     Running   0          5s

4.查看各个pod的IP地址 

[root@master ~]# ku get pod -owide
NAME                      READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
webapp-86b5d9fc88-cgmwx   1/1     Running   0          15s   10.244.104.7     node2   <none>           <none>
webapp-86b5d9fc88-hppsp   1/1     Running   0          15s   10.244.166.135   node1   <none>           <none>

5.访问这两个地址

[root@master ~]#10.244.104.7
[root@master ~]#10.244.166.135

四、service的创建

1.1创建一个ClusterIP类型service

        描述:clusterIP 是默认的 Service 类型。它将创建一个虚拟的 clusterIP 地址,用于在集群内部访问 service。
        使用场景:适用于集群内部的服务通信,例如将前端服务和后端服务连接起来,供内部其他服务使用。

1.通过 expose 命令创建 clusterIp 类型的 Service

        为了让客户端应用能够访问到前面创建的两个 Tomcat Pod 实例,需要创建一个 Service 来提供服务。k8s 提供了一种快速地方法,即通过 kubectl expose 命令来创建 Service。

(1)执行expose 命令暴露端口
[root@master ~]# ku expose deployment webapp
service/webapp exposed
(2)查看创建的Service
[root@master ~]# ku get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP    3d23h
webapp       ClusterIP   10.101.177.31   <none>        8080/TCP   43s

        这里可以看到,系统为他分配了一个虚拟 IP 地址,Service 的端口号,从 pod 中复制而来。我们就可以通过这个虚拟 IP 地址,和端口号来访问这个 Service 了。

(3)访问测试
[root@k8s-master ~]# curl 10.101.177.31:8080

        客户端对 Service 的访问被自动负载分发到了后端的两个 pod 之一。Kubernetes 自动完成将客户端请求转发到后端多个 EndPoint 的负载分发的工作。通过负载均衡机制,Kubernetes 实现了一种分布式应用的统一入口,免去了客户端应用获知后端服务实例列表和变化的复杂度。

(4)删除此service
[root@k8s-master ~]# kubectl delete service webapp
service "webapp" deleted

2.使用yaml文件创建Service

        除了使用expose的命令创建Service,更便于管理的方式是yaml文件来创建Service。

(1)编辑service文件
vim webapp-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: webapp
spec:
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
  selector:
    app: webapp

注意:
        本案例中的 ports 定义的是 Service 本身的端口号8080(用于提供给外部用户访问的端口)targetPort 则用来指定后端 Pod 的容器端口号,selector 定义的是后端 Pod 所拥有的 labe1

(2)利用 yaml 创建此服务
[root@master ~]# ku create -f webapp-service.yaml 
service/webapp created
(3)查看创建的service,并访问测试
[root@master ~]# ku get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP    3d23h
webapp       ClusterIP   10.100.91.206   <none>        8080/TCP   7s
[root@master ~]# curl 10.100.91.206:8080
(4)查看 EndPoint 列表

        一个 Service 对应的后端由 Pod 的 IP 地址何容器的端口号组成,即一个完成的 IP:Port 访问地址。这在 k8s 中叫做 EndPoint。通过査看 Service 的详细信息,可以看到其后端的 EndPoint 列表

[root@master ~]# ku describe svc webapp
Name:              webapp
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=webapp
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.100.91.206
IPs:               10.100.91.206
Port:              <unset>  8080/TCP
TargetPort:        8080/TCP
Endpoints:         10.244.104.7:8080,10.244.166.135:8080
Session Affinity:  None
Events:            <none>
(5)查看 EndPoint 资源对象

实际上,k8s 自动创建了与 Service 关联的 EndPoint 资源对象,这可以通过 EndPoint 对象进行查看

[root@master ~]# ku get endpoints
NAME         ENDPOINTS                               AGE
kubernetes   192.168.10.101:6443                     3d23h
webapp       10.244.104.7:8080,10.244.166.135:8080   2m22s
(6)删除这个 Service
[root@k8s-master ~]# kubectl delete-f webapp-service.yaml
或
[root@k8s-master ~]# kubectl delete service webapp

1.2创建NodePort 类型的 service

        描述:NodePort 将在每个节点上公开一个端口,并将流量转发到 Service。它会创建一个ClusterIP,并将指定的端口映射到每个节点上的相同端口。
        使用场景:适用于需要从外部访问集群中的服务时,可以通过节点的 IP 地址和映射的端口进行访问。这对于开发和测试环境非常有用。

(1)创建 service 文件

设置 Service 类型为 NodePort,并设置具体的 nodePort 端口号为 30008

vim webapp-svc-nodeport.yaml 

apiVersion: v1
kind: Service
metadata:
  name: webapp
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 8080
    nodePort: 30008
  selector:
    app: webapp

备注:
nodePort 端口的范围在 1.23.6 的版本中为 30000-32767

(2)创建此service

继续使用刚才的 webapp 的 Deployment,为此 Deployment 创建一个 NodePort 类型的 service。

[root@master ~]# ku create -f webapp-svc-nodeport.yaml 
service/webapp created
(3)查看创建的 service
[root@master ~]# ku get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP          3d23h
webapp       NodePort    10.110.106.46   <none>        8080:30008/TCP   5s
(4)在windows 宿主机上用浏览器测试访问

http://192.168.10.101:30008

备注:
因为 NodePort 的方式可以在每个 Node 节点创建出这个端口,所以在任何一个节点使用 netstat -anptgrep 30008 命令查询,都可以看到此端口,在访问的时候,IP 地址可以使用任何一个主机的 IP 地址。

(5)删除该service
[root@master ~]# ku delete svc webapp
service "webapp" deleted

1.3创建LoadBalancer 类型的service

        通常在公有云的环境中会使用 LoadBalancer 的类型,可以将 Service 映射到公有云提供的某个负载均衡器的 IP 地址上,客户端通过负载均衡器的 IP 和 Service 的端口号就可以访问到具体的服务。
        描述:LoadBalancer 为 Service 创建一个外部负载均衡器,并分配一个外部 IP 地址。它通常由云提供商的负载均衡服务实现。
        使用场景:适用于需要将流量从外部负载均衡器分发到集群内部的服务,例如在生产环境中暴露 web应用程序。

(1)编写LoadBalancer 类型的 service 文件
vim webapp-svc-loadbalancer.yaml 

apiVersion: v1
kind: Service
metadata:
  name: webapp
  namespace: default
  labels:
    app: webapp
spec:
  type: LoadBalancer
  ports:
    - port: 8080
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app: webapp

备注:
这个 Service 创建好后,云服务商会在 Service 定义中补充 LoadBalancer 的 IP 地址,之后就可以在户端访问该 Service 了。
备注:
nodePort 的端口范围在 30000-32767 之间。

(2)创建此service
[root@master ~]# ku create -f webapp-svc-loadbalancer.yaml 
service/webapp created
(3)查看创建结果
[root@master ~]# ku get svc
NAME         TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP      10.96.0.1        <none>        443/TCP          3d23h
webapp       LoadBalancer   10.111.174.171   <pending>     8080:31380/TCP   30s
(4)在 windows 宿主机上访问

(5)删除此service
[root@k8s-master ~]# kubectl delete -f webapp-svc-loadbalancer.yaml

1.4创建 ExternalName 类型的 service

        描述:ExternalName 允许 Service 通过返回CNAME 记录来引用集群外部的服务。它没有ClusterIP,NodePort或LoadBalancer.
        使用场景:适用于需要将K8s内部的服务与集群外的现有服务进行关联,例如连接到外部的数据库或其他资源。
        ExternalName 类型是 Service 的特例,用于将集群外的服务定义为 Kubernetes 的集群 Service并通过 ExternalName 字段指定外部服务的地址,可以使用域名或 IP 格式。集群内客户端应用通过访问这个 Service 就能访问外部服务了。他没有选择器,没有定义任何端口和 EndPoint,他通过返回该外部服务的别名来提供服务。也可以用于两个不同的 namespace 之间的不同 pod 可以通过 name 的形式访问
注意:
        两个不同的命名空间中的 pod,可以直接使用他们的 IP 地址进行通信,但是 pod 的 IP 地址是随机分配的,重建 pod 后其 IP 地址就改变了,因此我们要用 pod 对应的 service名称进行通信。但是跨命名空间是不能解析其他命名空间中创建的 service 名称的。这个时候就可以使用 ExternalName 实现两个不同命名空间中的各个 pod 间的通信。

(1)创建案例所需的两个命名空间
[root@master ~]# ku create namespace test01
namespace/test01 created
[root@master ~]# ku create namespace test02
namespace/test02 created
(2)第一个 Pod
1)创建命名空间为 test01 的 Pod
vim myapp01.yaml 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp01
  namespace: test01
spec:
  replicas: 1
  selector: #标签选择器
    matchLabels: #匹配的标签为
      app: myapp01
      release: canary
  template:
    metadata:
      labels:
        app: myapp01 #和上面的myapp要匹配
        release: canary
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        ports:
        - name: http01
          containerPort: 80
[root@master ~]# ku create -f myapp01.yaml 
deployment.apps/myapp01 created
2)创建一个无头(headless)service
vim myapp-svc-headless01.yaml 

apiVersion: v1
kind: Service
metadata:
  name: myapp-svc01
  namespace: test01
spec:
  selector:
    app: myapp01 #挑选的pod还是myapp01。一个pod可以有多个service
    release: canary
  clusterIP: None #None表示是无头service
  ports:
  - port: 39320 #service ip中的端口
    targetPort: 80 #容器ip中的端口

备注:
(Headless Service)无头 Service:这种服务没有入口地址(没有clusterIP),kube-proxy 也不会为其创建负载转发的规则,服务名的解析机制取决于这个无头 Service 是否设置了标签选择器。
注意:
无头服务创建出来之后,对于其他外部的 pod 来讲,该 pod 对应的名字就确定了下来,其固定的格式是:无头服务名,命名空间.svc.cluster.local

[root@master ~]# ku create -f myapp-svc-headless01.yaml 
service/myapp-svc01 created
3)创建extername
vim myapp-svc-extername01.yaml 

kind: Service
apiVersion: v1
metadata:
  name: myapp-svcname02
  namespace: test01
spec:
  type: ExternalName
  externalName: myapp-svc02.test02.svc.cluster.local

备注:
name:myapp-svcname02        指的是外部的服务名称

myapp-svc02.test02.svc.cluster.local         对方无头服务的名字·对方命名空间的名字.svc.cluster.local

[root@master ~]# ku create -f myapp-svc-extername01.yaml 
service/myapp-svcname02 created
(3)创建第二个Pod
1)创建命名空间为test02 的 Pod
vim myapp02.yaml 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp02
  namespace: test02
spec:
  replicas: 1
  selector: #标签选择器
    matchLabels: #匹配的标签为
      app: myapp02
      release: canary
  template:
    metadata:
      labels:
        app: myapp02 #和上面的myapp要匹配
        release: canary
    spec:
      containers:
      - name: myapp02
        image: ikubernetes/myapp:v1
        ports:
        - name: http02
          containerPort: 80
[root@master ~]# ku create -f myapp02.yaml 
deployment.apps/myapp02 created
2)创建一个无头(headless)Service
 vim myapp-svc-headless02.yaml 

apiVersion: v1
kind: Service
metadata:
  name: myapp-svc02
  namespace: test02
spec:
  selector:
    app: myapp02 #挑选的pod还是myapp。一个pod可以有多个service
    release: canary
  clusterIP: None #None表示是无头service
  ports:
  - port: 39320 #service ip中的端口
    targetPort: 80 #容器ip中的端口
[root@master ~]# ku create -f myapp-svc-headless02.yaml 
service/myapp-svc02 created
3)创建extername
vim myapp-svc-extername02.yaml 

kind: Service
apiVersion: v1
metadata:
  name: myapp-svcname01
  namespace: test02
spec:
  type: ExternalName
  externalName: myapp-svc01.test01.svc.cluster.local

 备注:

name: myapp-svcname01 指的是外部的服务名称

[root@master ~]# ku create -f myapp-svc-extername02.yaml 
service/myapp-svcname01 created
(4)验证Pod间的通信

查看命名空间为test01的Pod

[root@master ~]# ku get pods -n test01
NAME                       READY   STATUS    RESTARTS   AGE
myapp01-696c886d6b-sgfhg   1/1     Running   0          21m
[root@master ~]# ku exec -it myapp01-696c886d6b-sgfhg -n test01 -- /bin/sh
/ # nslookup myapp-svcname02
nslookup: can't resolve '(null)': Name does not resolve

Name:      myapp-svcname02
Address 1: 10.244.166.136 10-244-166-136.myapp-svc02.test02.svc.cluster.local
/ # ping myapp-svcname02
PING myapp-svcname02 (10.244.166.136): 56 data bytes
64 bytes from 10.244.166.136: seq=0 ttl=62 time=1.121 ms
64 bytes from 10.244.166.136: seq=1 ttl=62 time=0.320 ms
64 bytes from 10.244.166.136: seq=2 ttl=62 time=2.746 ms
64 bytes from 10.244.166.136: seq=3 ttl=62 time=0.729 ms
^C
--- myapp-svcname02 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.320/1.229/2.746 ms
/ # 
[root@master ~]# ku get pods -n test02 -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
myapp02-55ffcd5f64-49cr9   1/1     Running   0          17m   10.244.166.136   node1   <none>           <none>
[root@master ~]# ku get pods -n test01 -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
myapp01-696c886d6b-sgfhg   1/1     Running   0          27m   10.244.104.8   node2   <none>           <none>

查看命名空间为test02的Pod

[root@master ~]# ku get pods -n test02 -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
myapp02-55ffcd5f64-49cr9   1/1     Running   0          17m   10.244.166.136   node1   <none>           <none>
[root@master ~]# ku get pods -n test01 -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
myapp01-696c886d6b-sgfhg   1/1     Running   0          27m   10.244.104.8   node2   <none>           <none>
[root@master ~]# ku get svc -n test02 -o wide
NAME              TYPE           CLUSTER-IP   EXTERNAL-IP                            PORT(S)     AGE     SELECTOR
myapp-svc02       ClusterIP      None         <none>                                 39320/TCP   15m     app=myapp02,release=canary
myapp-svcname01   ExternalName   <none>       myapp-svc01.test01.svc.cluster.local   <none>      8m44s   <none>
[root@master ~]# ku get pods -n test01 -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
myapp01-696c886d6b-sgfhg   1/1     Running   0          27m   10.244.104.8   node2   <none>           <none>
[root@master ~]# ku get svc -n test02 -o wide
NAME              TYPE           CLUSTER-IP   EXTERNAL-IP                            PORT(S)     AGE     SELECTOR
myapp-svc02       ClusterIP      None         <none>                                 39320/TCP   15m     app=myapp02,release=canary
myapp-svcname01   ExternalName   <none>       myapp-svc01.test01.svc.cluster.local   <none>      8m44s   <none>
[root@master ~]# ku get svc -n test01 -o wide
NAME              TYPE           CLUSTER-IP   EXTERNAL-IP                            PORT(S)     AGE   SELECTOR
myapp-svc01       ClusterIP      None         <none>                                 39320/TCP   25m   app=myapp01,release=canary
myapp-svcname02   ExternalName   <none>       myapp-svc02.test02.svc.cluster.local   <none>      21m   <none>

五、service的其他应用

1.Service的多端口设置

一个容器应用可以提供多个端口的服务,在 Service 的定义中也可以相应的设置多个端口号。

(1)创建 service 文件
vim service-multiple-ports.yaml 

apiVersion: v1
kind: Service
metadata:
  name: webapp
spec:
  ports:
  - port: 8080
    targetPort: 8080
    name: web
    protocol: TCP
  - port: 8005
    targetPort: 8005
    name: management
    protocol: TCP
  selector:
    app: webapp

注意:
selector 中的 app:webapp 的标签对应的是 webapp-deployment.yaml 中的 pod 的标签

(2)创建 service
[root@k8s-master ~]# kubectl create -f service-multiple-ports.yaml
(3)查看 EndPoint 列表
[root@k8s-master ~]# kubectl describe svc webapp
(4)查看创建的service
[root@k8s-master ~]#kubectl get svc webapp
(5)删除这个service
[root@k8s-master ~]# kubectl delete -f webapp-service.yaml

[root@k8s-master ~]# kubectl delete service webapp

2.Kubernetes服务发现

        服务发现机制是指客户端如何在一个 kubernetes 集群中获知后端服务的访问地址

        Kubernetes 的服务发现有两种方式:环境变量和DNS

(1)基于环境变量的服务发现

        当 Pod 部署到一个 node 节点后,该 node 节点上的 kubelet 会在该 pod 内部设置一组环境变量,这些环境变量是根据活跃的 Service 生成的,所以,要使用基于环境变量的服务发现,需要先创建对应的Service 后再创建所需的 Pod。在一个 Pod 运行起来的时候,系统会自动为其容器运行环境注入所有集群中有效 service 的信息,service 的相关信息包括服务 IP、服务端口号、各端口号相关的协议等。然后,客户端应用就能够根据 Service 相关环境变量的命名规则,从环境变量中获取需要访问的目标服务(Pod)的地址了。

先创建出之前用的 service

[root@k8s-master ~]# kubectl create -f service-multiple-ports.yaml
[root@k8s-master ~]# kubectl create -f webapp-deployment.yaml
[root@k8s-master ~]# kubectl get pod
NAME                      READY   STATUS    RESTARTS   AGE
webapp-86b5d9fc88-cgmwx   1/1     Running   0          97m
webapp-86b5d9fc88-hppsp   1/1     Running   0          97m

任意的Pod都会根据这些Service创建一组变量用于服务发现

[root@master ~]# ku exec -it webapp-86b5d9fc88-hppsp -- env
PATH=/usr/local/tomcat/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=webapp-86b5d9fc88-hppsp
TERM=xterm
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
LANG=C.UTF-8
JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64/jre
JAVA_VERSION=7u101
JAVA_DEBIAN_VERSION=7u101-2.6.6-1~deb8u1
CATALINA_HOME=/usr/local/tomcat
OPENSSL_VERSION=1.0.2h-1
TOMCAT_MAJOR=8
TOMCAT_VERSION=8.0.35
TOMCAT_TGZ_URL=https://www.apache.org/dist/tomcat/tomcat-8/v8.0.35/bin/apache-tomcat-8.0.35.tar.gz
HOME=/root
(2)基于 DNS 的服务发现

        Kubernetes 进行服务发现的另一种方式是基于 Kubernetes 内部的 DNS 记录,新版的 Kubernetes默认使用 CoreDNS 作为集群的内部 DNS,一般 coreDNs 的 Service 地址为 Service 网段的低 10 个地址比如 10.96.0.10,端口为 53,集群内的 Pod 可以通过该地址和端口进行 Kubernetes 内部的服务解析。DNS 服务器监听 Kubernetes 创建的 service,然后给每个 Service 添加一组 DNS 记录,集群中的 Pod就能通过 Kubernetes 内部的 DNS 解析到 Service 的 IP,也就是 Service 的 clusterIP。

例如:创建一个含有 nslookup 命令的容器,测试解析 kube-dns 的 Service。

[root@master ~]# ku run redis --image=redis:3.2.10-alpine
pod/redis created
[root@master ~]# ku exec -it redis -- nslookup redis
nslookup: can't resolve '(null)': Name does not resolve

Name:      redis
Address 1: 10.244.104.9 redis
[root@master ~]# ku exec -it redis -- nslookup kube-dns.kube-system
nslookup: can't resolve '(null)': Name does not resolve

Name:      kube-dns.kube-system
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

备注:
删除资源
kubectl delete -fmyappol.yaml
kubectl delete -fmyapp-svc-headless01.yaml
kubectl delete -fmyapp-svc-extername01.yaml
kubectl delete -fmyappo2.yaml
kubectl delete -fmyapp-svc-headless02.yaml
kubectl delete -fmyapp-svc-extername02.yaml

六、将Service 和 Deployment 整合的案例

1.案列一

vim nginx-service.yaml 

apiVersion: v1
kind: Service
metadata:
  name: mynginx
  namespace: default
  labels:
    app: mynginx
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app: mynginx

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mynginx-deployment
  namespace: default
  labels:
    app: mynginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: mynginx
  template:
    metadata:
      labels:
        app: mynginx
    spec:
      containers:
      - name: mynginx
        image: nginx:1.7.9
        ports:
          - name: http
            containerPort: 80
            protocol: TCP

主要:

红色部分的标签名称需要一致。

2.案列二

 vim tomcat-service.yaml 

apiVersion: v1
kind: Service
metadata:
  name: webapp
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 8080
    nodePort: 30008
  selector:
    app: webapp

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
      - name: webapp
        image: kubeguide/tomcat-app:v1
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值