Kubernetes服务篇

前言

上文介绍了Kubernetes副本机制,正是因为副本机制你的部署能自动保待运行,并且保持健康,无须任何手动干预;本文继续介绍kubernetes的另一个强大的功能服务,在客户端和pod之间提供一个服务层,提供了单一的接入点,更加方便客户端使用pod。

服务

Kubernetes服务是一种为一组功能相同的pod提供单一不变的接入点的资源;当服务存在时,它的IP地址和端口不会改变,客户端通过IP地址和端口号建立连接,这些连接会被路由到提供该服务的任意一个pod上;

1.创建服务

服务的连接对所有的后端pod是负载均衡的,至于哪些pod被属于哪个服务,通过在定义服务的时候设置标签选择器;

1[d:\k8s]$ kubectl create -f kubia-rc.yaml 2replicationcontroller/kubia created 3 4[d:\k8s]$ kubectl get pod 5NAME READY STATUS RESTARTS AGE 6kubia-6dxn7 0/1 ContainerCreating 0 4s 7kubia-fhxht 0/1 ContainerCreating 0 4s 8kubia-fpvc7 0/1 ContainerCreating 0 4s

使用之前的yaml文件创建pod,模版中设置的标签为app: kubia,所以创建服务的yaml(还有之前介绍的kubectl expose方式也可以创建服务)中也需要指定相同的标签:

1apiVersion: v1 2kind: Service 3metadata: 4 name: kubia 5spec: 6 ports: 7 - port: 80 8 targetPort: 8080 9 selector: 10 app: kubia

首先指定的资源类型为Service,然后指定了两个端口分别:port服务提供的端口,targetPort指定pod中进程监听的端口,最后指定标签选择器,相同标签的pod被当前服务管理;

1[d:\k8s]$ kubectl create -f kubia-svc.yaml 2service/kubia created 3 4[d:\k8s]$ kubectl get svc 5NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 6kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d15h 7kubia ClusterIP 10.96.191.193 <none> 80/TCP 4s 8 9[d:\k8s]$ kubectl exec kubia-6dxn7 -- curl -s http://10.96.191.193 10You've hit kubia-fhxht 11 12[d:\k8s]$ kubectl exec kubia-6dxn7 -- curl -s http://10.96.191.193 13You've hit kubia-fpvc7

创建完服务之后,可以发现给kubia分配了CLUSTER-IP,这是一个内部ip;至于如何测试可以使用kubectl exec命令远程地在一个已经存在的pod容器上执行任何命令;pod名称可以随意指定三个中的任何一个,接收到crul命令的pod,会转发给Service,由Service来决定将请求交给哪个pod处理,所以可以看到多次执行,发现每次处理的pod都不一样;如果希望特定客户端产生的所有请求每次都指向同一个pod, 可以设置服务的sessionAffinity属性为ClientIP;

1.1配置会话黏性

1apiVersion: v1 2kind: Service 3metadata: 4 name: kubia 5spec: 6 sessionAffinity: ClientIP 7 ports: 8 - port: 80 9 targetPort: 8080 10 selector: 11 app: kubia

除了添加了sessionAffinity: ClientIP,其他都一样

1[d:\k8s]$ kubectl delete svc kubia 2service "kubia" deleted 3 4[d:\k8s]$ kubectl create -f kubia-svc-client-ip-session-affinity.yaml 5service/kubia created 6 7[d:\k8s]$ kubectl get svc 8NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 9kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d15h 10kubia ClusterIP 10.96.51.99 <none> 80/TCP 25s 11 12[d:\k8s]$ kubectl exec kubia-6dxn7 -- curl -s http://10.96.51.99 13You've hit kubia-fhxht 14 15[d:\k8s]$ kubectl exec kubia-6dxn7 -- curl -s http://10.96.51.99 16You've hit kubia-fhxht

1.2 同一个服务暴露多个端口

如果pod监听了两个或者多个端口,那么服务同样可以暴露多个端口:

1apiVersion: v1 2kind: Service 3metadata: 4 name: kubia 5spec: 6 ports: 7 - name: http 8 port: 80 9 targetPort: 8080 10 - name: https 11 port: 443 12 targetPort: 8080 13 selector: 14 app: kubia

因为Node.js只监听了8080一个端口,所以这里在Service里面配置两个端口都指向同一个目标端口,看是否都能访问:

1[d:\k8s]$ kubectl create -f kubia-svc-named-ports.yaml 2service/kubia created 3 4[d:\k8s]$ kubectl get svc 5NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 6kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d18h 7kubia ClusterIP 10.96.13.178 <none> 80/TCP,443/TCP 7s 8 9[d:\k8s]$ kubectl exec kubia-6dxn7 -- curl -s http://10.96.13.178 10You've hit kubia-fpvc7 11 12[d:\k8s]$ kubectl exec kubia-6dxn7 -- curl -s http://10.96.13.178:443 13You've hit kubia-fpvc7

可以发现使用两个端口都可以访问;

1.3 使用命名的端口

在Service中指定了端口为8080,如果目标端口变了这里也需要改变,可以在定义pod的模版中给端口命名,在Service中可以直接指定名称:

1apiVersion: v1 2kind: ReplicationController 3metadata: 4 name: kubia 5spec: 6 replicas: 3 7 selector: 8 app: kubia 9 template: 10 metadata: 11 labels: 12 app: kubia 13 spec: 14 containers: 15 - name: kubia 16 image: ksfzhaohui/kubia 17 ports: 18 - name: http 19 containerPort: 8080

在之前的ReplicationController中稍作修改,在port是中指定了名称,Service的yaml文件同样做修改,直接使用名称:

1apiVersion: v1 2kind: Service 3metadata: 4 name: kubia 5spec: 6 ports: 7 - port: 80 8 targetPort: http 9 selector: 10 app: kubia

targetPort直接使用了名称http:

1[d:\k8s]$ kubectl create -f kubia-rc2.yaml 2replicationcontroller/kubia created 3 4[d:\k8s]$ kubectl get pod 5NAME READY STATUS RESTARTS AGE 6kubia-4m9nv 1/1 Running 0 66s 7kubia-bm6rx 1/1 Running 0 66s 8kubia-dh87r 1/1 Running 0 66s 9 10[d:\k8s]$ kubectl create -f kubia-svc2.yaml 11service/kubia created 12 13[d:\k8s]$ kubectl get svc 14NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 15kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 7d 16kubia ClusterIP 10.96.106.37 <none> 80/TCP 10s 17 18[d:\k8s]$ kubectl exec kubia-4m9nv -- curl -s http://10.96.106.37 19You've hit kubia-dh87r

2.服务发现

服务给我们提供了一个单一不变的ip去访问pod,那是否每次都要先创建服务,然后找到服务的CLUSTER-IP,再给其他pod去使用;这样就太麻烦了,Kubernets还提供了其他方式去访问服务;

2.1 通过环境变量发现服务

在pod开始运行的时候,Kubernets会初始化一系列的环境变量指向现在存在的服务;如果创建的服务早于客户端pod的创建,pod上的进程可以根据环境变量获得服务的IP地址和端口号;

1[d:\k8s]$ kubectl get svc 2NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 3kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 7d14h 4kubia ClusterIP 10.96.106.37 <none> 80/TCP 14h 5 6[d:\k8s]$ kubectl get pod 7NAME READY STATUS RESTARTS AGE 8kubia-4m9nv 1/1 Running 0 14h 9kubia-bm6rx 1/1 Running 0 14h 10kubia-dh87r 1/1 Running 0 14h 11 12[d:\k8s]$ kubectl exec kubia-4m9nv env 13PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 14HOSTNAME=kubia-4m9nv 15KUBERNETES_SERVICE_PORT_HTTPS=443 16KUBERNETES_PORT=tcp://10.96.0.1:443 17KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443 18KUBERNETES_PORT_443_TCP_PROTO=tcp 19KUBERNETES_PORT_443_TCP_PORT=443 20KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1 21KUBERNETES_SERVICE_HOST=10.96.0.1 22KUBERNETES_SERVICE_PORT=443 23NPM_CONFIG_LOGLEVEL=info 24NODE_VERSION=7.10.1 25YARN_VERSION=0.24.4 26HOME=/root

因为这里的pod早于服务的创建,所有没有相关服务的相关信息:

1[d:\k8s]$ kubectl delete po --all 2pod "kubia-4m9nv" deleted 3pod "kubia-bm6rx" deleted 4pod "kubia-dh87r" deleted 5 6[d:\k8s]$ kubectl get pod 7NAME READY STATUS RESTARTS AGE 8kubia-599v9 1/1 Running 0 48s 9kubia-8s8j4 1/1 Running 0 48s 10kubia-dm6kr 1/1 Running 0 48s 11 12[d:\k8s]$ kubectl exec kubia-599v9 env 13PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 14HOSTNAME=kubia-599v9 15... 16KUBIA_SERVICE_HOST=10.96.106.37 17KUBIA_SERVICE_PORT=80 18...

如果删除pod重新创建新的pod,这样服务就在创建pod之前了,再次获取环境变量可以发现有KUBIA_SERVICE_HOST和KUBIA_SERVICE_PORT,分别代表了kubia服务的IP地址和端口号;这样就可以通过环境变量去获取IP和端口了;

2.2 通过DNS发现服务

命名空间kube-system下有一个默认的服务kube-dns,其后端是一个coredns的pod:

1[d:\k8s]$ kubectl get svc --namespace kube-system 2NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 3kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 9d 4 5[d:\k8s]$ kubectl get po -o wide --namespace kube-system 6NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES 7coredns-7f9c544f75-h2cwn 1/1 Running 0 9d 172.17.0.3 minikube <none> <none> 8coredns-7f9c544f75-x2ttk 1/1 Running 0 9d 172.17.0.2 minikube <none> <none>

运行在pod上的进程DNS查询都会被Kubernets自身的DNS服务器响应,该服务器知道系统中运行的所有服务;客户端的pod在知道服务名称的情况下可以通过全限定域名(FQDN)来访问

1[d:\k8s]$ kubectl exec kubia-599v9 -- curl -s http://kubia.default.svc.cluster.local 2You've hit kubia-8s8j4

kubia对应服务名称,default为服务所在的命名空间,svc.cluster.local是在所有集群本地服务名称中使用的可配置集群域后缀;如果两个pod在同一个命名空间下,可以省略svc.cluster.local和default,使用服务名即可:

1[d:\k8s]$ kubectl exec kubia-599v9 -- curl -s http://kubia.default 2You've hit kubia-dm6kr 3 4[d:\k8s]$ kubectl exec kubia-599v9 -- curl -s http://kubia 5You've hit kubia-dm6kr

2.3 在pod中运行shell

1d:\k8s>winpty kubectl exec -it kubia-599v9 -- sh 2# curl -s http://kubia 3You've hit kubia-dm6kr 4# exit

通过kubectl exec命令在一个pod容器上运行bash,这样就无须为每个要运行的命令执行kubectl exec命令;因为在windows环境下使用了winpty工具;

连接集群外部的服务

以上介绍的后端是集群中运行的一个或多个pod的服务;但也存在希望通过Kubernetes服务特性暴露外部服务的情况,可以通过Endpoint方式和外部服务别名的方式;

1.Endpoint

服务并不是和pod直接相连的;有一种资源介于两者之间:它就是Endpoint资源

1[d:\k8s]$ kubectl describe svc kubia 2Name: kubia 3Namespace: default 4Labels: <none> 5Annotations: <none> 6Selector: app=kubia 7Type: ClusterIP 8IP: 10.96.106.37 9Port: <unset> 80/TCP 10TargetPort: http/TCP 11Endpoints: 172.17.0.10:8080,172.17.0.11:8080,172.17.0.9:8080 12Session Affinity: None 13Events: <none> 14 15[d:\k8s]$ kubectl get pod -o wide 16NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES 17kubia-599v9 1/1 Running 0 3h51m 172.17.0.10 minikube <none> <none> 18kubia-8s8j4 1/1 Running 0 3h51m 172.17.0.11 minikube <none> <none> 19kubia-dm6kr 1/1 Running 0 3h51m 172.17.0.9 minikube <none> <none>

可以看到Endpoints对应其实就是pod的IP和端口;当客户端连接到服务时,服务代理选择这些IP和端口对中的一个,并将传入连接重定向到在该位置监听的服务器;

2.手动配置服务的endpoint(内部)

如果创建了不包含pod选择器的服务,Kubernetes将不会创建Endpoint资源;这样就需要创建Endpoint资源来指定该服务的Endpoint列表;

1apiVersion: v1 2kind: Service 3metadata: 4 name: external-service 5spec: 6 ports: 7 - port: 80

如上定义没有指定selector选择器:

1[d:\k8s]$ kubectl create -f external-service.yaml 2service/external-service created 3 4[d:\k8s]$ kubectl get svc external-service 5NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 6external-service ClusterIP 10.96.241.116 <none> 80/TCP 74s 7 8[d:\k8s]$ kubectl describe svc external-service 9Name: external-service 10Namespace: default 11Labels: <none> 12Annotations: <none> 13Selector: <none> 14Type: ClusterIP 15IP: 10.96.241.116 16Port: <unset> 80/TCP 17TargetPort: 80/TCP 18Endpoints: <none> 19Session Affinity: None 20Events: <none>

可以发现因为没有指定selector选择器,external-service的Endpoints为none,这种情况可以手动配置服务的Endpoint;

1apiVersion: v1 2kind: Endpoints 3metadata: 4 name: external-service 5subsets: 6 - addresses: 7 - ip: 172.17.0.9 8 - ip: 172.17.0.10 9 ports: 10 - port: 8080

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

1[d:\k8s]$ kubectl create -f external-service-endpoints.yaml 2endpoints/external-service created 3 4[d:\k8s]$ kubectl describe svc external-service 5Name: external-service 6Namespace: default 7Labels: <none> 8Annotations: <none> 9Selector: <none> 10Type: ClusterIP 11IP: 10.96.241.116 12Port: <unset> 80/TCP 13TargetPort: 80/TCP 14Endpoints: 172.17.0.10:8080,172.17.0.9:8080 15Session Affinity: None 16Events: <none> 17 18[d:\k8s]$ kubectl exec kubia-599v9 -- curl -s http://external-service 19You've hit kubia-dm6kr

可以发现再创建完Endpoints之后,服务external-service的Endpoints中多了pod的ip地址和端口,同样也可以通过kubectl exec执行请求;

3.手动配置服务的endpoint(外部)

以上在endpoint配置的是kubernetes内部的ip端口,同样也可以配置外部的ip端口,在kubernetes外部启动一个服务:

1apiVersion: v1 2kind: Endpoints 3metadata: 4 name: external-service 5subsets: 6 - addresses: 7 - ip: 10.13.82.21 8 ports: 9 - port: 8080

以上配置的10.13.82.21:8080就是一个普通的tomcat服务,在本机启动即可

1[d:\k8s]$ kubectl create -f external-service-endpoints2.yaml 2endpoints/external-service created 3 4[d:\k8s]$ kubectl create -f external-service.yaml 5service/external-service created 6 7[d:\k8s]$ kubectl exec kubia-599v9 -- curl -s http://external-service 8ok

经测试可以返回外部服务的响应

4.创建外部服务别名

除了手动配置服务的Endpoint来代替公开外部服务方法,还可以通过给外部服务指定一个别名,比如给10.13.82.21指定一个域名:api.ksfzhaohui.com

1apiVersion: v1 2kind: Service 3metadata: 4 name: external-service 5spec: 6 type: ExternalName 7 externalName: api.ksfzhaohui.com 8 ports: 9 - port: 80

要创建一个具有别名的外部服务的服务时,要将创建服务资源的一个type字段设置为ExternalName;在externalName中指定外服服务的域名:

1[d:\k8s]$ kubectl create -f external-service-externalname.yaml 2service/external-service created 3 4[d:\k8s]$ kubectl exec kubia-599v9 -- curl -s http://external-service:8080 5ok

经测试可以返回外部服务的响应

将服务暴露给外部客户端

向外部公开某些服务,kubernetes提供了三种方式:NodePort服务,LoadBalance服务以及Ingress资源方式,下面分别介绍及实战;

1.NodePort类型的服务

创建一个服务并将其类型设置为NodePort,通过创建NodePort服务,可以让kubernetes在其所有节点上保留一个端口(所有节点上都使用相同的端口号),然后将传入的连接转发给pod;

1apiVersion: v1 2kind: Service 3metadata: 4 name: kubia-nodeport 5spec: 6 type: NodePort 7 ports: 8 - port: 80 9 targetPort: 8080 10 nodePort: 30123 11 selector: 12 app: kubia

指定服务类型为NodePort,节点端口为30123;

1d:\k8s]$ kubectl create -f kubia-svc-nodeport.yaml 2service/kubia-nodeport created 3 4[d:\k8s]$ kubectl get svc 5NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 6kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 31d 7kubia-nodeport NodePort 10.96.59.16 <none> 80:30123/TCP 3s 8 9[d:\k8s]$ kubectl exec kubia-7fs6m -- curl -s http://10.96.59.16 10You've hit kubia-m487j

要外部可以访问内部pod服务,需要知道节点的IP,我们这里使用的节点为minikube,因为这里的minikube是安装在本地windows系统下,可以直接使用minikube的内部ip进行访问

1d:\k8s]$ kubectl get nodes -o wide 2NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME 3minikube Ready master 34d v1.17.0 192.168.99.108 <none> Buildroot 2019.02.7 4.19.81 docker://19.3.5

2.LoadBalance类型服务

相比NodePort方式可以通过任何节点的30312端口访问内部的pod,LoadBalance方式拥有自己独一无二的可公开访问的IP地址;LoadBalance其实是NodePort的一种扩展,使得服务可以通过一个专用的负载均衡器来访问;

1apiVersion: v1 2kind: Service 3metadata: 4 name: kubia-loadbalancer 5spec: 6 type: LoadBalancer 7 ports: 8 - port: 80 9 targetPort: 8080 10 selector: 11 app: kubia

指定服务类型为LoadBalancer,无需指定节点端口;

1d:\k8s]$ kubectl create -f kubia-svc-loadbalancer.yaml 2service/kubia-loadbalancer created 3 4[d:\k8s]$ kubectl get svc 5NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 6kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 31d 7kubia-loadbalancer LoadBalancer 10.96.207.113 <pending> 80:30038/TCP 7s 8kubia-nodeport NodePort 10.96.59.16 <none> 80:30123/TCP 32m

可以看到虽然我们没有指定节点端口,但是创建完之后自动启动了30038节点端口

所以可以发现同样能通过使用NodePort的方式来访问服务(节点IP+节点端口);同时也可以通过EXTERNAL-IP来访问,但是使用Minikube,就不会有外部IP地址,外部IP地址将会一直是pending状态;

3.了解并防止不必要的网络跳数

当外部客户端通过节点端口连接到服务时,随机选择的pod并不一定在接收连接的同一节点上运行;可以通过将服务配置为仅将外部通信重定向到接收连接的节点上运行的pod来阻止此额外跳数;

1apiVersion: v1 2kind: Service 3metadata: 4 name: kubia-nodeport-onlylocal 5spec: 6 type: NodePort 7 externalTrafficPolicy: Local 8 ports: 9 - port: 80 10 targetPort: 8080 11 nodePort: 30124 12 selector: 13 app: kubia

通过在服务的spec部分中设置externalTrafficPolicy字段来完成;

4.Ingress类型服务

每个LoadBalancer服务都需要自己的负载均衡器,以及独有的公有IP地址;而Ingress 只需要一个公网IP就能为许多服务提供访问;当客户端向Ingress发送HTTP请求时,Ingress会根据请求的主机名和路径转发到对应的服务;

4.1 Ingress控制器

只有Ingress控制器在集群中运行,Ingress资源才能正常工作;不同的Kubernetes环境使用不同的控制器实现,但有些并不提供默认控制器;我这里使用的Minikube需要启用附加组件才可以使用控制器;

1[d:\Program Files\Kubernetes\Minikube]$ minikube addons list 2- addon-manager: enabled 3- dashboard: enabled 4- default-storageclass: enabled 5- efk: disabled 6- freshpod: disabled 7- gvisor: disabled 8- helm-tiller: disabled 9- ingress: disabled 10- ingress-dns: disabled 11- logviewer: disabled 12- metrics-server: disabled 13- nvidia-driver-installer: disabled 14- nvidia-gpu-device-plugin: disabled 15- registry: disabled 16- registry-creds: disabled 17- storage-provisioner: enabled 18- storage-provisioner-gluster: disabled

列出所有的附件组件,可以看到ingress是不可用的,所以需要开启

1[d:\Program Files\Kubernetes\Minikube]$ minikube addons enable ingress 2* ingress was successfully enabled

启动之后可以查看kube-system命名空间下的pod

1[d:\k8s]$ kubectl get pods -n kube-system 2NAME READY STATUS RESTARTS AGE 3coredns-7f9c544f75-h2cwn 1/1 Running 0 55d 4coredns-7f9c544f75-x2ttk 1/1 Running 0 55d 5etcd-minikube 1/1 Running 0 55d 6kube-addon-manager-minikube 1/1 Running 0 55d 7kube-apiserver-minikube 1/1 Running 0 55d 8kube-controller-manager-minikube 1/1 Running 2 55d 9kube-proxy-xtbc4 1/1 Running 0 55d 10kube-scheduler-minikube 1/1 Running 2 55d 11nginx-ingress-controller-6fc5bcc8c9-nvcb5 0/1 ContainerCreating 0 8s 12storage-provisioner 1/1 Running 0 55d

可以发现正在创建一个名称为nginx-ingress-controller的pod,会一直停留在拉取镜像状态,并显示如下错误:

Failed to pull image "quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.26.1": rpc error: code = Unknown desc = context canceled

这是因为国内无法下载quay.io下面的镜像,可以使用阿里云镜像:

image: registry.aliyuncs.com/google_containers/nginx-ingress-controller:0.26.1

可以从ingress-nginx下的deploy/static/mandatory.yaml文件修改其中的镜像为阿里云镜像,然后重新创建即可:

1[d:\k8s]$ kubectl create -f mandatory.yaml 2namespace/ingress-nginx created 3configmap/nginx-configuration created 4configmap/tcp-services created 5configmap/udp-services created 6serviceaccount/nginx-ingress-serviceaccount created 7clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created 8role.rbac.authorization.k8s.io/nginx-ingress-role created 9rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created 10clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created 11deployment.apps/nginx-ingress-controller created

再次查看kube-system命名空间下的pod

1[d:\k8s]$ kubectl get pods -n kube-system 2NAME READY STATUS RESTARTS AGE 3coredns-7f9c544f75-h2cwn 1/1 Running 0 56d 4coredns-7f9c544f75-x2ttk 1/1 Running 0 56d 5etcd-minikube 1/1 Running 0 56d 6kube-addon-manager-minikube 1/1 Running 0 56d 7kube-apiserver-minikube 1/1 Running 0 56d 8kube-controller-manager-minikube 1/1 Running 2 56d 9kube-proxy-xtbc4 1/1 Running 0 56d 10kube-scheduler-minikube 1/1 Running 2 56d 11nginx-ingress-controller-6fc5bcc8c9-nvcb5 1/1 Running 0 10m 12storage-provisioner 1/1 Running 0 56d

nginx-ingress-controller已经为Running状态,下面就可以使用Ingress资源了;

4.2 Ingress资源

Ingress控制器启动之后,就可以创建Ingress资源了

1apiVersion: extensions/v1beta1 2kind: Ingress 3metadata: 4 name: kubia 5spec: 6 rules: 7 - host: kubia.example.com 8 http: 9 paths: 10 - path: / 11 backend: 12 serviceName: kubia-nodeport 13 servicePort: 80

指定资源类型为Ingress,定一个单一规则,所有发送kubia.example.com的请求都会被转发给端口为80的kubia-nodeport服务上;

1[d:\k8s]$ kubectl get svc 2NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 3kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 53d 4kubia-nodeport NodePort 10.96.204.104 <none> 80:30123/TCP 21h 5 6[d:\k8s]$ kubectl create -f kubia-ingress.yaml 7ingress.extensions/kubia created 8 9[d:\k8s]$ kubectl get ingress 10NAME HOSTS ADDRESS PORTS AGE 11kubia kubia.example.com 192.168.99.108 80 6m4s

需要把域名映射到ADDRESS:192.168.99.108,修改hosts文件即可,下面就可以直接用域名访问了,最终请求会被转发到kubia-nodeport服务

大致请求流程如下:浏览器中请求域名首先会查询域名服务器,然后DNS返回了控制器的IP地址;客户端向控制器发送请求并在头部指定了kubia.example.com;然后控制器根据头部信息确定客户端需要访问哪个服务;然后通过服务关联的Endpoint对象查看pod IP,并将请求转发给其中一个;

4.3 Ingress暴露多个服务

rules和paths是数组,可以配置多个

1apiVersion: extensions/v1beta1 2kind: Ingress 3metadata: 4 name: kubia2 5spec: 6 rules: 7 - host: kubia.example.com 8 http: 9 paths: 10 - path: /v1 11 backend: 12 serviceName: kubia-nodeport 13 servicePort: 80 14 - path: /v2 15 backend: 16 serviceName: kubia-nodeport 17 servicePort: 80 18 - host: kubia2.example.com 19 http: 20 paths: 21 - path: / 22 backend: 23 serviceName: kubia-nodeport 24 servicePort: 80

配置了多个host和path,这里为了方便映射了同样服务;

1[d:\k8s]$ kubectl create -f kubia-ingress2.yaml 2ingress.extensions/kubia2 created 3 4[d:\k8s]$ kubectl get ingress 5NAME HOSTS ADDRESS PORTS AGE 6kubia kubia.example.com 192.168.99.108 80 41m 7kubia2 kubia.example.com,kubia2.example.com 192.168.99.108 80 15m

同样需要配置host文件,测试如下:

4.4 配置Ingress处理TLS传输

以上介绍的消息都是基于Http协议,Https协议需要配置相关证书;客户端创建到Ingress控制器的TLS连接时,控制器将终止TLS连接;客户端与Ingress控制器之间是加密的,而Ingress控制器和pod之间没有加密;要使控制器可以这样,需要将证书和私钥附加到Ingress中;

1[root@localhost batck-job]# openssl genrsa -out tls.key 2048 2Generating RSA private key, 2048 bit long modulus 3..................................................................+++ 4........................+++ 5e is 65537 (0x10001) 6[root@localhost batck-job]# openssl req -new -x509 -key tls.key -out tls.cert -days 360 -subj /CN=kubia.example.com 7 8[root@localhost batck-job]# ll 9-rw-r--r--. 1 root root 1115 Feb 11 01:20 tls.cert 10-rw-r--r--. 1 root root 1679 Feb 11 01:20 tls.key

生成的两个文件创建secret

1[d:\k8s]$ kubectl create secret tls tls-secret --cert=tls.cert --key=tls.key 2secret/tls-secret created

现在可以更新Ingress对象,以便它也接收kubia.example.com的HTTPS请求;

1apiVersion: extensions/v1beta1 2kind: Ingress 3metadata: 4 name: kubia 5spec: 6 tls: 7 - hosts: 8 - kubia.example.com 9 secretName: tls-secret 10 rules: 11 - host: kubia.example.com 12 http: 13 paths: 14 - path: / 15 backend: 16 serviceName: kubia-nodeport 17 servicePort: 80

tls中指定相关证书

1[d:\k8s]$ kubectl apply -f kubia-ingress-tls.yaml 2Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply 3ingress.extensions/kubia configured

通过浏览器访问https协议,如下图所示

Pod就绪信号

只要pod的标签和服务的pod选择器想匹配,pod就可以作为服务的后端,但是如果pod没有准备好,是不能处理请求的,这时候就需要就绪探针了,用来检查pod是否已经准备好了,如果检查成功就可以作为服务的后端处理消息了;

1.就绪探针类型

就绪探针有三种类型分别:

  • Exec探针:执行进程的地方,容器的状态由进程的退出状态代码确认;
  • Http get探针:向容器发送HTTP GET请求,通过响应的HTTP状态代码判断容器是否准备好;
  • Tcp socket探针:它打开一个TCP连接到容器的指定端口,如果连接己建立,则认为容器己准备就绪。

kubernetes会周期性地调用探针,并根据就绪探针的结果采取行动。如果某个pod报告它尚未准备就绪,则会从该服务中删除该pod。如果pod再次准备就绪,则重新添加pod;

2.向pod添加就行探针

编辑ReplicationController,修改pod模版添加就绪探针

1[d:\k8s]$ kubectl edit rc kubia 2libpng warning: iCCP: known incorrect sRGB profile 3replicationcontroller/kubia edited 4 5[d:\k8s]$ kubectl get pods 6NAME READY STATUS RESTARTS AGE 7kubia-7fs6m 1/1 Running 0 22d 8kubia-m487j 1/1 Running 0 22d 9kubia-q6z5w 1/1 Running 0 22d

编辑ReplicationController如下所示,添加readinessProbe

1apiVersion: v1 2kind: ReplicationController 3metadata: 4 name: kubia 5spec: 6 replicas: 3 7 selector: 8 app: kubia 9 template: 10 metadata: 11 labels: 12 app: kubia 13 spec: 14 containers: 15 - name: kubia 16 image: ksfzhaohui/kubia 17 ports: 18 - containerPort: 8080 19 readinessProbe: 20 exec: 21 command: 22 - ls 23 - /var/ready

就绪探针将定期在容器内执行ls/var/ready命令。如果文件存在,则ls命令返回退出码 0, 否则返回非零的退出码;如果文件存在,则就绪探针将成功,否则失败;
我们编辑完ReplicationController还没有产生新的pod所以可以发现以上pod的READY都为1,表示已经准备好可以处理消息;

1[d:\k8s]$ kubectl delete pod kubia-m487j 2pod "kubia-m487j" deleted 3 4[d:\k8s]$ kubectl get pods 5NAME READY STATUS RESTARTS AGE 6kubia-7fs6m 1/1 Running 0 22d 7kubia-cxz5v 0/1 Running 0 114s 8kubia-q6z5w 1/1 Running 0 22d

删除一个pod,马上会创建一个带有就绪探针的pod,可以发现长时间READY为0;

总结

本文首先介绍了服务的基本知识,如何创建服务发现服务;然后介绍了服务和pod直接的关联器endpoint;最后重点介绍了将服务暴露给外部客户端的三种方式。

参考

Kubernetes in Action

博客地址

Github

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )