日志

Kubernetes学习笔记(四):服务

 来源    2020-05-23    1  

服务介绍

服务是一种为一组相同功能的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\n",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内部执行的命令
  • 创建一个多端口服务时,必须给每个端口指定名字。
  • 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、对外暴露、就绪探针,服务发现。
相关文章
kubernetes学习笔记之十四:helm入门
日志1.Helm的简介 Helm是Kubernetes的一个包管理工具,用来简化Kubernetes应用的部署和管理.可以把Helm比作CentOS的yum工具. Helm有如下几个基本概念: Chart ...
1
Netty学习笔记(四) 简单的聊天室功能之服务端开发
日志前面三个章节,我们使用了Netty实现了DISCARD丢弃服务和回复以及自定义编码解码,这篇博客,我们要用Netty实现简单的聊天室功能. Ps: 突然想起来大学里面有个课程实训,给予UDP还是TCP ...
1
kubernetes学习笔记(二)——部署服务
日志前面一篇文章部署好了minikube环境,这次学习下怎么部署app到kubernetes环境当中去.参考的是官网的教程,稍微做了一点改动,为了进一步熟悉go和docker,这里我把教程中的js换成了g ...
Apache Ignite 学习笔记(四): Ignite缓存冗余备份策略
日志Ignite的数据网格是围绕着基于内存的分布式key/value存储能力打造的.当初技术选型的时候,决定用Ignite也是因为虽然同样是key/value存储,它有着和其他key/value存储系统不 ...
2
C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻
日志前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...
1
Swoft2.x 小白学习笔记 (四) --- RPC
日志介绍 swoft 中 RPC使用:搭建访问服务端和客户端   RPC服务端: 一.配置,在文件 /app/bean.php中添加 return [ 'rpcServer' => [ 'class ...
1
SpringCloud学习笔记:服务注册与发现Eureka(2)
日志1. Eureka简介 Eureka是一个用于服务注册和发现的组件,分为Eureka Server和Eureka Client,Eureka Server为Eureka服务注册中心,Eureka Cl ...
nodejs学习笔记四(模块化、在npm上发布自己的模块)
日志模块化:      1.系统模块:  http.querystring.url      2.自定义模块      3.包管理器 [系统模块] Assert      断言:肯定确定会出现的情况使用断 ...
1
mysql的学习笔记(四)
日志---恢复内容开始--- 1.插入操作 INSERT (1)INSERT table_name(col_name,...) VALUES(...),(....) CREATE TABLE user( ...
1
CSS学习笔记四:下拉选择框以及其动画特效
日志以前学的只是了解了css的一些基本属性,在做项目的时候都是直接使用bootstrap响应式来写项目,这样子很方便,很快捷,但是在自己看来还是有一点缺陷的,毕竟,我很多时候不怎么清楚它里面的具体运作.所 ...
1
Mongodb学习笔记四(Mongodb聚合函数)
日志第四章 Mongodb聚合函数 插入 测试数据 for(var j=1;j<3;j++){ for(var i=1;i<3;i++){ var person={ Name:"ja ...
1
TDD学习笔记四 --- 如何隔离相依性 - 基本的可测试性
日志前言 相信许多读者都听过「可测试性」,甚至被它搞的要死要活的,还觉得根本是莫名其妙,徒劳无功.今天这篇文章,主要要讲的是对象的相依性,以及对象之间直接相依,会带来什么问题.为了避免发生因相依性而导致设 ...
Directx11学习笔记四 封装一个简单的Dx11DemoBase
日志原文:Directx11学习笔记[四] 封装一个简单的Dx11DemoBase根据前面两个笔记的内容,我们来封装一个简单的基类,方便以后的使用. 代码和前面类似,没有什么新的内容,直接看代码吧(由于代 ...
1
StackExchange.Redis学习笔记(四) 事务控制和Batch批量操作
日志原文:StackExchange.Redis学习笔记(四) 事务控制和Batch批量操作Redis事物 Redis命令实现事务 Redis的事物包含在multi和exec(执行)或者discard(回 ...
1
HTML5学习笔记四 HTML文本格式化
日志HTML 格式化标签 HTML 使用标签<b> 与<i> 对输出的文本进行格式, 如:粗体 or 斜体 这些HTML标签被称为格式化标签 通常标签 <strong> ...
1
MySql学习笔记四
日志MySql学习笔记四 5.3.数据类型 数值型 整型 小数 定点数 浮点数 字符型 较短的文本:char, varchar 较长的文本:text, blob(较长的二进制数据) 日期型 原则:所选择类 ...
原 Learning Spark (Python版) 学习笔记(四)----Spark Sreaming与MLlib机器学习
日志本来这篇是准备5.15更的,但是上周一直在忙签证和工作的事,没时间就推迟了,现在终于有时间来写写Learning Spark最后一部分内容了. 第10-11 章主要讲的是Spark Streaming ...
1
Angular JS 学习笔记(自定义服务:factory,Promise 模式异步请求查询:$http,过滤器用法filter,指令:directive)
日志刚学没多久,作了一个小项目APP,微信企业号开发与微信服务号的开发,使用的是AngularJS开发,目前项目1.0版本已经完结,但是项目纯粹为了赶工,并没有发挥AngularJS的最大作用,这几天项目 ...
1
Redis 学习笔记四 Mysql 与Redis的同步实践
日志一.测试环境在Ubuntu kylin 14.04 64bit 已经安装Mysql.Redis.php.lib_mysqludf_json.so.Gearman. 点击这里查看测试数据库及表参考 本文 ...
1
Git学习笔记四--远程仓库
日志Git远程仓库 Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上. 怎么分布呢?最早,肯定只有一台机器有一个原始版本库,此后,别的机器可以“克隆”这个原始版本库,而且每台机器的版本 ...