• Kubernetes学习笔记(四):服务


    服务介绍

    服务是一种为一组相同功能的pod提供单一不变接入点的资源。当服务存在时,他的IP和端口不会改变。客户端通过IP和端口建立连接,这些连接会被路由到任何一个pod上。如此,客户端不需要知道每个单独提供服务的pod地址,这些pod也可以随时被创建、删除。

    服务通过标签选择器决定选择哪些pod。

    准备镜像

    首先要准备一个能够提供web服务的镜像,作者将镜像存储到了阿里云的镜像仓库。

    web.go

    监听8000端口,接到请求输出当前hostname

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    	"os"
    )
    
    func main()  {
    	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    		hostname,_ := os.Hostname();
    		fmt.Fprintf(w,"this is %v
    ",hostname)
    	})
    	log.Fatal(http.ListenAndServe(":8000",nil))
    }
    

    Dockerfile

    多步骤构建,有关与此以及Dockerfile的文章请见:Docker学习笔记(三):Dockerfile及多步骤构建镜像

    FROM golang:1.14-alpine
    COPY goweb.go /src/
    RUN CGO_ENABLED=0 GOOS=linux go build -o /bin/goweb /src/goweb.go
    
    FROM alpine
    COPY --from=0 /bin/goweb /usr/local/bin/
    RUN apk add --no-cache curl
    EXPOSE 8000
    CMD ["/usr/local/bin/goweb"]
    

    构建、测试、推送

    构建完成

    -> [feifei@ffmac.local] [~/work/service] docker build -t registry.cn-hangzhou.aliyuncs.com/orzi/goweb .
    Sending build context to Docker daemon  3.072kB
    ......
    Successfully built 3db4b643ba0a
    Successfully tagged registry.cn-hangzhou.aliyuncs.com/orzi/goweb:latest
    

    运行镜像,本地8001映射到容器的8000

    -> [feifei@ffmac.local] [~] docker run --rm -d -p 8001:8000 registry.cn-hangzhou.aliyuncs.com/orzi/goweb
    6241a412caeacfe5f025d20af154b2eba98555fcb2b2f55742154a9e6fa46817
    

    请求本地的8001端口

    -> [feifei@ffmac.local] [~] curl http://localhost:8001
    this is 6241a412caea
    

    没有问题,推送

    -> [feifei@ffmac.local] [~] docker push registry.cn-hangzhou.aliyuncs.com/orzi/goweb
    The push refers to repository [registry.cn-hangzhou.aliyuncs.com/orzi/goweb]
    8c5325633e9a: Pushed
    3e207b409db3: Pushed
    latest: digest: sha256:2704d806836060237169ea59cfda238c50fc5e5881e15cb1230200b5c8b2f5a0 size: 739
    

    创建服务

    goweb-rs.yaml

    apiVersion: apps/v1
    kind: ReplicaSet
    metadata:
      name: goweb-rs
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: goweb
      template:
        metadata:
          labels:
            app: goweb
        spec:
          containers:
            - name: goweb
              image: registry.cn-hangzhou.aliyuncs.com/orzi/goweb
              ports:
                - containerPort: 8000
    

    goweb-svc.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: goweb-svc
    spec:
      ports:
        - port: 80		# 服务的端口
          targetPort: 8000	# 服务将连接转发到容器的端口
      selector:		# 匹配此选择器的都属于这个服务
        app: goweb
    

    创建一个名为goweb-svc的服务,它将在80端口接收请求并将连接路由到具有标签app=goweb的pod的8000端口上。

    创建

    -> [root@kube0.vm] [~] k create -f goweb-svc.yaml
    service/goweb-svc created
    
    -> [root@kube0.vm] [~] k create -f goweb-rs.yaml
    replicaset.apps/goweb-rs created
    
    -> [root@kube0.vm] [~] k get all
    NAME                 READY   STATUS    RESTARTS   AGE
    pod/goweb-rs-6n6fw   1/1     Running   0          14m
    pod/goweb-rs-vkwqb   1/1     Running   0          14m
    
    NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
    service/goweb-svc    ClusterIP   10.104.46.76   <none>        80/TCP    9s
    service/kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   40h
    
    NAME                       DESIRED   CURRENT   READY   AGE
    replicaset.apps/goweb-rs   2         2         2       14m
    

    kubectl exec

    访问服务可以在集群节点上直接访问,如:

    -> [root@kube0.vm] [~] curl http://10.104.46.76
    this is goweb-rs-vkwqb
    -> [root@kube0.vm] [~] curl http://10.104.46.76
    this is goweb-rs-6n6fw
    

    或者通过kubectl exec命令在已存在的pod上执行curl

    -> [root@kube0.vm] [~] k exec goweb-rs-vkwqb -- curl -s http://10.104.46.76
    this is goweb-rs-vkwqb
    -> [root@kube0.vm] [~] k exec goweb-rs-vkwqb -- curl -s http://10.104.46.76
    this is goweb-rs-6n6fw
    

    双横杠表示kubectl命令项的结束,在此之后的是指要在pod内部执行的命令。这是为了避免异常和歧义,如果需要执行的指令中没有横杠,那么可以不用双横杠。

    sessionAffinity

    使用svc.spec.sessionAffinity设置会话亲和性,默认是None。指定为ClientIP会使来自同一个Client IP的请求转发到同一个Pod上。
    Kubernetes只支持这两种亲和性设置,不支持cookie,因为Kubernetes不在HTTP层面工作。服务处理TCP和UDP包,不关心其中的内容。

    一个服务暴露多个端口

    创建一个多端口服务时,必须给每个端口指定名字。

    为服务指定多个端口

    apiVersion: v1
    kind: Service
    metadata:
      name: goweb-svc
    spec:
      ports:
        - name: http
          port: 80
          targetPort: 8000
        - name: https
          port: 443
          targetPort: 8443
      selector:
        app: goweb
    

    使用命名的端口

    使用方法是:在Pod(或其他资源的Pod模板)的spec.containers.ports.name配置中指定端口名称,然后Service中的spec.ports.targetPort引用。

    使用命名端口的好处在于,当Pod更改端口号时,不会影响到Service,因为Service引用的是端口名。

    Pod中指定端口名:

    spec:
      containers:
        - name: goweb
          ports:
            - name: http	# 命名8000端口为http
              containerPort: 8000
            - name: https	# 命名8443端口为https
              containerPort: 8443
    

    Service中引用:

    apiVersion: v1
    kind: Service
    metadata:
      name: goweb-svc
    spec:
      ports:
        - name: http	# 将80端口映射到容器中名为http的端口
          port: 80
          targetPort: http
        - name: https	# 将443端口映射到容器中名为https的端口
          port: 443
          targetPort: https
      selector:
        app: goweb
    

    服务发现

    通过环境变量发现服务

    在容器中执行env,列出一部分结果。
    服务名称中的横线被转换为下划线,并且全部转为大写

    -> [root@kube0.vm] [~] k exec goweb-rs-hztlt env
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    HOSTNAME=goweb-rs-hztlt
    KUBERNETES_SERVICE_HOST=10.96.0.1
    KUBERNETES_SERVICE_PORT=443
    GOWEB_SVC_SERVICE_HOST=10.98.92.202
    GOWEB_SVC_SERVICE_PORT=80
    .........
    

    通过DNS发现服务

    Kubernetes集群运行了一个名为kube-dns的服务,提供DNS解析。

    -> [root@kube0.vm] [~] k get svc -n kube-system
    NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
    kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   2d17h
    

    查看容器内的/etc/resolv.conf文件

    -> [root@kube0.vm] [~] k exec goweb-rs-hztlt cat /etc/resolv.conf
    nameserver 10.96.0.10
    search default.svc.cluster.local svc.cluster.local cluster.local lan vm
    options ndots:5
    

    没有错,nameserver指定的IP就是kube-dns服务的地址!

    通过FQDN连接服务

    FQDN(Fully Qualified Domain Name):全限定域名
    比如:goweb-svc.default.svc.cluster.local,goweb-svc是Service名称,default是命名空间,svc表示资源类型,cluster.local表示本地集群后缀。

    根据情况,可以省略命名空间(请求方与Service在相同命名空间下)和 svc.cluster.local,也就是说下列情况都是可以的:

    -> [root@kube0.vm] [~] k exec goweb-rs-dknjv -- curl -s http://goweb-svc
    this is goweb-rs-dknjv
    -> [root@kube0.vm] [~] k exec goweb-rs-dknjv -- curl -s http://goweb-svc.default
    -> [root@kube0.vm] [~] k exec goweb-rs-dknjv -- curl -s http://goweb-svc.default.svc.cluster.local
    

    无法ping通服务IP的原因

    因为服务的集群IP是一个虚拟IP,并且只有在与服务端口结合时才有意义。

    Endpoint

    Service与Pod不是直接相连的,有一种资源介于两者之间,他就是Endpoint。

    Endpoint暴露一个服务的IP和端口列表。

    查看Service

    -> [root@kube0.vm] [~] k describe svc goweb-svc
    Name:              goweb-svc
    Namespace:         default
    .......
    Endpoints:         10.244.1.58:8000,10.244.2.61:8000
    .......
    

    查看Endpoint资源

    -> [root@kube0.vm] [~] k get ep
    NAME         ENDPOINTS                           AGE
    goweb-svc    10.244.1.58:8000,10.244.2.61:8000   7h58m
    kubernetes   192.168.199.117:6443                8h
    

    手动配置服务的Endpoint

    如果创建了不包含Pod选择器的服务,Kubernetes将不会创建Endpoint资源。

    创建没有Pod选择器的Service

    external-service.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: external-svc
    spec:
      ports:
        - port: 80
    

    查看external-svc

    -> [root@kube0.vm] [~] k describe svc external-svc
    Name:              external-svc
    Namespace:         default
    Labels:            <none>
    Annotations:       <none>
    Selector:          <none>
    Type:              ClusterIP
    IP:                10.108.251.192
    Port:              <unset>  80/TCP
    TargetPort:        80/TCP
    Endpoints:         <none>
    Session Affinity:  None
    Events:            <none>
    

    为没有选择器的服务创建Endpoint

    Endpoint对象需要与服务具有相同的名字,并包含该服务的目标IP和端口列表

    Service和Endpoint都提交到服务器后,Service就又可以像具有Pod选择器那样了。

    external-service-endpoint.yaml

    apiVersion: v1
    kind: Endpoints
    metadata:
      name: external-svc	# 名字必须与相应服务的名字相同
    subsets:
      - addresses:		# IP、端口列表
        - ip: 11.11.11.11
        - ip: 22.22.22.22
        ports:
          - port: 80
    

    创建Endpoint

    -> [root@kube0.vm] [~] k create -f external-svc-endpoint.yaml
    endpoints/external-svc created
    

    查看external-svc服务

    -> [root@kube0.vm] [~] k describe svc external-svc
    Name:              external-svc
    Namespace:         default
    Labels:            <none>
    Annotations:       <none>
    Selector:          <none>
    Type:              ClusterIP
    IP:                10.108.251.192
    Port:              <unset>  80/TCP
    TargetPort:        80/TCP
    Endpoints:         11.11.11.11:80,22.22.22.22:80
    Session Affinity:  None
    Events:            <none>
    

    为外部服务创建别名

    创建一个具有别名的外部服务时,需要指定service.spec.type的值为ExternalName;并且指定service.spec. externalName的值为外部服务的完整域名。因此连接到服务的客户端将直接连接到外部服务,完全绕过服务代理。出于这个原因,这些类型的服务也就没有集群IP

    external-svc-externalname.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: external-svc-externalname
    spec:
      type: ExternalName		# 服务类型
      externalName: www.baidu.com	# 外部服务的完整域名
      ports:
      - port: 80
    

    创建、查看别名外部服务,可以看到external-svc-externalname确实没有集群IP

    -> [root@kube0.vm] [~] k create -f external-svc-externalname.yaml
    service/external-svc-externalname created
    
    -> [root@kube0.vm] [~] k get svc
    NAME                        TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)   AGE
    external-svc                ClusterIP      10.108.251.192   <none>          80/TCP    57m
    external-svc-externalname   ExternalName   <none>           www.baidu.com   80/TCP    18s
    kubernetes                  ClusterIP      10.96.0.1        <none>          443/TCP   9h
    

    通过external-svc-externalname.default.svc.cluster.local甚至是external-svc-externalname可以访问服务。

    NodePort与LoadBalancer

    以下几种方式可在外部访问服务:

    • 将服务的类型设置成NodePort:
      每个集群节点都会打开一个相同的端口,并将该端口的流量重定向到服务。
    • 将服务的类型设置成LoadBalancer:
      LoadBalancer是NodePort的一种扩展,这种类型需要云基础设施提供专用的负载均衡器,负载均衡器将流量转发到集群的节点端口。
      如果不支持LoadBalancer,那么它会变得和NodePort一样。
    • 创建一个Ingress资源:
      通过一个IP地址公开多个服务,它运行在第七层。

    NodePort

    goweb-nodeport.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: goweb-nodeport
    spec:
      type: NodePort	# Service类型
      ports:
        - port: 80		# Service的端口
          targetPort: 8000	# Pod的端口
          nodePort: 31234	# 通过任意Node的此端口访问服务
      selector:
        app: goweb
    

    创建、查看这个类型为NodePort的服务

    -> [root@kube0.vm] [~] k create -f goweb-nodeport.yaml
    service/goweb-nodeport created
    
    -> [root@kube0.vm] [~] k get svc goweb-nodeport
    NAME             TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
    goweb-nodeport   NodePort   10.105.234.226   <none>        80:31234/TCP   10s
    

    查看节点IP

    -> [root@kube0.vm] [~] k get node -o wide
    NAME       STATUS   ROLES    AGE    VERSION   INTERNAL-IP       EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION               CONTAINER-RUNTIME
    kube0.vm   Ready    master   3d5h   v1.17.3   192.168.199.117   <none>        CentOS Linux 7 (Core)   5.6.14-1.el7.elrepo.x86_64   docker://19.3.6
    kube1.vm   Ready    <none>   3d5h   v1.17.3   192.168.199.231   <none>        CentOS Linux 7 (Core)   5.6.14-1.el7.elrepo.x86_64   docker://19.3.6
    kube2.vm   Ready    <none>   3d5h   v1.17.3   192.168.199.212   <none>        CentOS Linux 7 (Core)   5.6.14-1.el7.elrepo.x86_64   docker://19.3.6
    

    使用不同节点IP访问服务

    -> [root@kube0.vm] [~] curl http://192.168.199.231:31234
    this is goweb-rs-pbxvx
    -> [root@kube0.vm] [~] curl http://192.168.199.212:31234
    this is goweb-rs-6wc2f
    

    搞个图

    LoadBalancer

    goweb-loadbalancer.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: goweb-loadbalancer
    spec:
      type: LoadBalancer	# 更改了类型
      ports:		# 去掉了nodePort、随机分配
        - port: 80
          targetPort: 8000
      selector:
        app: goweb
    

    创建、查看这个类型为LoadBalancer的服务

    -> [root@kube0.vm] [~] k create -f goweb-loadbalancer.yaml
    service/goweb-loadbalancer created
    
    -> [root@kube0.vm] [~] k get svc goweb-loadbalancer
    NAME                 TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
    goweb-loadbalancer   LoadBalancer   10.106.251.246   <pending>     80:31141/TCP   21m
    

    EXTERNAL-IP字段一直是<pending>,是作者的环境不支持LoadBalancer。退而求其次,将其作为NodePort使用:

    -> [root@kube0.vm] [~] curl http://192.168.199.212:31141
    this is goweb-rs-pbxvx
    -> [root@kube0.vm] [~] curl http://192.168.199.231:31141
    this is goweb-rs-6wc2f
    

    搞个图

    外部连接的特性

    externalTrafficPolicy

    sservice.spec.externalTrafficPolicy设置为local,则服务代理会选择运行本地的Pod。如果本地Node没有Pod,则连接将挂起。

    客户端IP是不记录的

    节点端口接收到连接是,会对包的源地址进行转换(SNAT),因此数据包的源IP将发生改变。

    但是externalTrafficPolicy为local的不会进行SNAT

    Ingress

    因为每个LoadBalancer服务都需要自己的负载均衡器,以及独有的共有IP地址。而Ingress只需要一个地址就可以为多个服务提供访问。当客户端向Ingress发送Http请求时,Ingress会根据请求的主机名和路径决定请求转发到那个服务。

    部署Ingress控制器

    只有Ingress控制器在集群中运行,Ingress资源才能正常工作。所以我们要先部署Ingress控制器,需要做的工作非常简单:
    进入ingress-nginx官网,复制粘贴以下内容,然后执行就可以了。

    kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-0.32.0/deploy/static/provider/baremetal/deploy.yaml
    

    这时候查看Namespace,会发现多出一个ingress-nginx,具体内容就不细述了。

    -> [root@kube0.vm] [~] k get ns
    NAME              STATUS   AGE
    default           Active   3d15h
    ingress-nginx     Active   15m
    kube-node-lease   Active   3d15h
    kube-public       Active   3d15h
    kube-system       Active   3d15h
    

    除此之外还要做个小改动,执行k edit -n ingress-nginx service/ingress-nginx-controller,在spec下添加工作节点的IP。出处请见官网

      externalIPs:
      - 192.168.199.231
      - 192.168.199.212
    

    然后删除其管理的Pod,使其重建。

    -> [root@kube0.vm] [~] k delete -n ingress-nginx pod/ingress-nginx-controller-f8d756996-8prk2
    pod "ingress-nginx-controller-f8d756996-8prk2" deleted
    

    goweb-ingress.yaml

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: goweb-ingress
    spec:
      rules:
      - host: www.goweb.com
        http:
          paths:
          - path: /
            backend:
              serviceName: goweb-svc
              servicePort: 80
    

    创建、查看goweb-ingress

    -> [root@kube0.vm] [~] k create -f goweb-ingress.yaml
    ingress.extensions/goweb-ingress created
    
    -> [root@kube0.vm] [~] k get ing
    NAME            HOSTS           ADDRESS           PORTS   AGE
    goweb-ingress   www.goweb.com   192.168.199.212   80      61s
    

    在host文件中添加 192.168.199.212 www.goweb.com。然后访问

    -> [root@kube0.vm] [~] curl http://www.goweb.com
    this is goweb-rs-mhvj4
    -> [root@kube0.vm] [~] curl http://www.goweb.com
    this is goweb-rs-88k9t
    

    暴露多个服务

    需要暴露多个服务,参照goweb-ingress.yaml:

    • 将多个服务映射到同一个域名只要在pahts下再配置一个path即可。
    • 将多个服务映射到不同域名则配置多个host即可。

    Ingress工作原理

    从表面上看请求的流程是:client->ingress->service->pod,但实际上是client->ingress->pod。
    在Ingress收到客户端的请求后,会根据域名和路径来确定服务,通过与该服务关联的Endpoint对象查看Pod IP,并将客户端的请求转发给其中一个pod。也就是说,请求不会转发给服务,服务只是被用来选择pod。

    处理TLS传输

    占个位置,以后补上。

    就绪探针

    就绪探针(readinessProbe)的类型与存活探针(livenessProbe)一样,请见此文它与存活探针的不同在于:如果容器未通过检查,则不会被终止或重新启动,但Pod会被从服务的Endpoint中移除,它确保了客户端只与正常的Pod交互。

    在众多的微服务中存在很多依赖关系,被依赖服务只有在准备就绪后,才能接收请求。所以就绪探针务必要定义。

    goweb-readiness.yaml

    apiVersion: apps/v1
    kind: ReplicaSet
    metadata:
      name: goweb-readiness
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: goweb
      template:
        metadata:
          labels:
            app: goweb
        spec:
          containers:
            - name: goweb
              image: registry.cn-hangzhou.aliyuncs.com/orzi/goweb
              ports:
                - name: http
                  containerPort: 8000
              readinessProbe:
                exec:
                  command: ["ls","/var/ready"]
    

    运行查看goweb-readiness

    创建之后等了一段时间,可以看到两个Pod都处于为就绪状态,goweb-svc的Endpoints也是空的。

    -> [root@kube0.vm] [~] k create -f goweb-readiness.yaml
    replicaset.apps/goweb-rs created
    
    -> [root@kube0.vm] [~] k get po
    NAME                    READY   STATUS    RESTARTS   AGE
    goweb-readiness-9k9kv   0/1     Running   0          11s
    goweb-readiness-x2gfb   0/1     Running   0          11s
    
    -> [root@kube0.vm] [~] k describe svc goweb-svc
    Port:              http  80/TCP
    TargetPort:        http/TCP
    Endpoints:
    Session Affinity:  None
    Events:            <none>
    

    让我们来给 goweb-readiness-9k9kv 创建一个/var/ready文件,使其准备就绪。

    -> [root@kube0.vm] [~] k exec goweb-readiness-9k9kv touch /var/ready
    

    再来查看、可以看到已经有一个Pod就绪了,Endpoints也有内容了。

    -> [root@kube0.vm] [~] k get po
    NAME                    READY   STATUS    RESTARTS   AGE
    goweb-readiness-9k9kv   1/1     Running   0          89s
    goweb-readiness-x2gfb   0/1     Running   0          89s
    
    -> [root@kube0.vm] [~] k describe svc goweb-svc
    Endpoints:         10.244.2.74:8000
    

    headless

    将服务的spec.clusterIP设置为None会使服务成为headless服务。它不会被分配集群IP,DNS对其解析时就会返回Pod IP。

    默认情况下,DNS对headless服务名解析只会返回已经就绪的Pod的IP。

    goweb-headless.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: goweb-headless
    spec:
      clusterIP: None
      ports:
        - name: http
          port: 80
          targetPort: 8000
      selector:
        app: goweb
    

    创建、查看

    ReplicaSet是使用前面的goweb-readiness.yaml创建的。

    -> [root@kube0.vm] [~] k create -f goweb-headless.yaml
    service/goweb-headless created
    
    -> [root@kube0.vm] [~] k get all -o wide
    NAME                        READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
    pod/goweb-readiness-2jj49   0/1     Running   0          10m   10.244.2.4   kube2.vm   <none>           <none>
    pod/goweb-readiness-5h5sg   0/1     Running   0          10m   10.244.1.5   kube1.vm   <none>           <none>
    
    NAME                     TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE     SELECTOR
    service/goweb-headless   ClusterIP   None         <none>        80/TCP    9m54s   app=goweb
    service/kubernetes       ClusterIP   10.96.0.1    <none>        443/TCP   79m     <none>
    
    NAME                              DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES                                         SELECTOR
    replicaset.apps/goweb-readiness   2         2         1       10m   goweb        registry.cn-hangzhou.aliyuncs.com/orzi/goweb   app=goweb
    

    使用nslookup解析goweb-headless,没有返回任何Pod的IP,这是因为两个Pod都未就绪。

    -> [root@kube0.vm] [~] k exec goweb-readiness-2jj49 nslookup goweb-headless
    Server:		10.96.0.10
    Address:	10.96.0.10:53
    
    ** server can't find goweb-headless.default.svc.cluster.local: NXDOMAIN
    ** server can't find goweb-headless.svc.cluster.local: NXDOMAIN
    ........
    

    为goweb-readiness-2jj49创建/var/ready使其满足就绪条件

    k exec goweb-readiness-2jj49 touch /var/ready
    

    再使用nslookup查看,可以看到返回了goweb-readiness-2jj49 的 IP

    -> [root@kube0.vm] [~] k exec goweb-readiness-2jj49 nslookup goweb-headless
    Server:		10.96.0.10
    Address:	10.96.0.10:53
    ......
    Name:	goweb-headless.default.svc.cluster.local
    Address: 10.244.2.4
    ......
    

    如法炮制,使另一个Pod生效,就能看到两个Pod的IP了

    publishNotReadyAddresses

    service.spec.publishNotReadyAddresses设置为true,允许DNS解析headless服务是发现未就绪的Pod。

    将goweb-readiness的Pod副本变成3个

    -> [root@kube0.vm] [~] k scale --replicas=3 rs goweb-readiness
    replicaset.apps/goweb-readiness scaled
    
    -> [root@kube0.vm] [~] k get po -o wide
    NAME                    READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
    goweb-readiness-2jj49   1/1     Running   0          24m   10.244.2.4   kube2.vm   <none>           <none>
    goweb-readiness-5h5sg   1/1     Running   0          24m   10.244.1.5   kube1.vm   <none>           <none>
    goweb-readiness-jb74c   0/1     Running   0          31s   10.244.1.6   kube1.vm   <none>           <none>
    

    然后编辑goweb-headless,写入publishNotReadyAddresses: true

    -> [root@kube0.vm] [~] k edit svc goweb-headless
    service/goweb-headless edited
    

    nslookup查看,虽然有未就绪的,但IP还是全都返回了。

    -> [root@kube0.vm] [~] k exec goweb-readiness-2jj49 nslookup goweb-headless
    Server:		10.96.0.10
    Address:	10.96.0.10:53
    
    Name:	goweb-headless.default.svc.cluster.local
    Address: 10.244.2.4
    Name:	goweb-headless.default.svc.cluster.local
    Address: 10.244.1.5
    Name:	goweb-headless.default.svc.cluster.local
    Address: 10.244.1.6
    

    注意事项

    • 双横杠表示kubectl命令项的结束,在此之后的是指要在pod内部执行的命令
    • 创建一个多端口服务时,必须给每个端口指定名字。
    • 服务的IP无法ping通:因为服务的集群IP是一个虚拟IP,并且只有在与服务端口结合时才有意义。
    • sservice.spec.sessionAffinity设置会话亲和性,默认为None,可以设置为ClientIP
    • 创建ExternalService需要将spec.type设置为ExternalName,此类服务只在DNS级别实施(为服务创建了CNAME DNS),也因此不会获得集群IP。
    • service.spec.externalTrafficPolicy设置为local,则服务代理会选择运行本地的Pod。如果本地Node没有Pod,则连接将挂起。
    • service.spec.publishNotReadyAddresses设置为true,允许DNS解析headless服务是发现未就绪的Pod。

    小结

    • 服务是一种为一组相同功能的pod提供单一不变接入点的资源
    • 创建了不包含Pod选择器的服务,Kubernetes将不会创建Endpoints资源。
    • 服务对外暴露的方法:NodePort、LoadBalancer、Ingress
    • Ingress的的工作原理是:client->ingress->pod,而不是client->ingress->service->pod。
    • 就绪探针与存活探针:
      • 就绪探针:作用确保客户端只与正常的Pod交互。如果检查未通过,不会终止或重启容器,但Pod会被从服务的Endpoint中移除。
      • 存活探针:作用是让集群知道Pod是否正常运行。如果检查未通过,则终止异常容器并重新启动。
    • 一些概念:Service、Endpoint、对外暴露、就绪探针,服务发现。
  • 相关阅读:
    2015年秋季个人阅读计划
    Task 6.4 冲刺Two之站立会议10
    《需求工程——软件建模与分析》阅读笔记之三
    《需求工程——软件建模与分析》阅读笔记之二
    《需求工程——软件建模与分析》阅读笔记之一
    专业实训题目需求分析
    2015年秋季个人阅读计划
    《大道至简——软件工程实践者的思想》读书笔记之三
    《大道至简——软件工程实践者的思想》读书笔记之二
    《大道至简——软件工程实践者的思想》读书笔记之一
  • 原文地址:https://www.cnblogs.com/flhs/p/12934652.html
Copyright © 2020-2023  润新知