目录一.系统环境二.前言三.Kubernetes service简介四.使用hostPort向外界暴露应用程序4.1 创建deploy4.2 使用hostPort向外界暴露pod的端口五.使用service服务向外界暴露应用程序5.1 使用service服务向外界暴露pod5.1.1 创建service服务5.1.2 测试svc的负载均衡六.service服务的发现6.1 使用clusterIP的方式进行服务发现6.2 使用环境变量的方式进行服务发现6.3 使用DNS的方式进行服务发现(推荐)七.service服务的发布7.1 使用nodeport进行服务的发布7.1.1 使用kubectl edit修改服务类型为NodePort7.1.2 使用type指定服务类型为NodePort7.2 使用LoadBalancer的方式进行服务的发布7.2.1 安装METALLB7.2.2 配置地址池7.2.3 使用LoadBalancer的方式进行服务发布一.系统环境

本文主要基于Kubernetes1.21.9和Linux操作系统CentOS7.4。

服务器版本docker软件版本Kubernetes(k8s)集群版本CPU架构
CentOS Linux release 7.4.1708 (Core)Docker version 20.10.12v1.21.9x86_64

Kubernetes集群架构:k8scloude1作为master节点,k8scloude2,k8scloude3作为worker节点。


(资料图片)

服务器操作系统版本CPU架构进程功能描述
k8scloude1/192.168.110.130CentOS Linux release 7.4.1708 (Core)x86_64docker,kube-apiserver,etcd,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calicok8s master节点
k8scloude2/192.168.110.129CentOS Linux release 7.4.1708 (Core)x86_64docker,kubelet,kube-proxy,calicok8s worker节点
k8scloude3/192.168.110.128CentOS Linux release 7.4.1708 (Core)x86_64docker,kubelet,kube-proxy,calicok8s worker节点
二.前言

Kubernetes 是一个强大的容器编排平台,它可以帮助开发者快速、可靠地部署和管理容器化应用程序。其中一个重要的概念就是 service(服务)。在 Kubernetes 中,service 是一组 Pod 的抽象,用于提供稳定的网络端点以便其他应用程序访问。本文将介绍 Kubernetes service 的相关知识,包括服务的发现和服务的发布。

使用service服务的前提是已经有一套可以正常运行的Kubernetes集群,关于Kubernetes(k8s)集群的安装部署,可以查看博客《Centos7 安装部署Kubernetes(k8s)集群》https://www.cnblogs.com/renshengdezheli/p/16686769.html。

三.Kubernetes service简介

Kubernetes 中的 service 是一种可以提供内部负载均衡的抽象,用于将应用程序暴露为一个稳定的网络端点。Kubernetes service 可以通过一个虚拟 IP 地址或者 DNS 来暴露一个应用程序。当需要访问这个应用程序时,只需要使用这个虚拟 IP 地址或者 DNS 就可以了,而不需要知道实际运行这个应用程序的节点的 IP 地址。这种方式可以帮助我们解耦应用程序和底层网络架构,从而使应用程序能够更加灵活地运行在不同的环境中。

Kubernetes 中的 service 还有一些重要的特性,包括:

内部负载均衡:Kubernetes service 提供了内部负载均衡的功能,可以将请求均匀地分配给后端 Pod,从而提高应用程序的可用性和响应速度。服务发现:Kubernetes service 允许我们使用标准的 DNS 解析或者环境变量来查找其他服务。这种方式可以使得不同的服务之间能够更加方便地进行通信。在线升级:Kubernetes service 支持在线升级,可以在不影响现有的服务的情况下进行版本升级。四.使用hostPort向外界暴露应用程序

service简写为svc。创建svc存放yaml文件的目录。

[root@k8scloude1 ~]# mkdir svc[root@k8scloude1 ~]# cd svc/[root@k8scloude1 svc]# pwd/root/svc

创建svc的namespace

[root@k8scloude1 svc]# kubectl create ns svcnamespace/svc created

切换命名空间到svc

[root@k8scloude1 svc]# kubens svcContext "kubernetes-admin@kubernetes" modified.Active namespace is "svc".[root@k8scloude1 svc]# kubectl get podNo resources found in svc namespace.
4.1 创建deploy

deploy控制器能更好的控制pod,我们先创建deploy。关于deploy控制器的详细内容请查看博客《Kubernetes(k8s)控制器(一):deployment》。

生成创建deploy的yaml文件。

[root@k8scloude1 svc]# kubectl create deploy nginx --image=nginx --dry-run=client -o yaml >nginxdeploy.yaml[root@k8scloude1 svc]# cat nginxdeploy.yaml apiVersion: apps/v1kind: Deploymentmetadata:  creationTimestamp: null  labels:    app: nginx  name: nginxspec:  replicas: 1  selector:    matchLabels:      app: nginx  strategy: {}  template:    metadata:      creationTimestamp: null      labels:        app: nginx    spec:      containers:      - image: nginx        name: nginx        resources: {}status: {}

修改yaml文件,表示创建一个名为nginx的deploy,pod副本数为1。

[root@k8scloude1 svc]# vim nginxdeploy.yaml [root@k8scloude1 svc]# cat nginxdeploy.yaml apiVersion: apps/v1kind: Deploymentmetadata:  creationTimestamp: null  labels:    app: nginx  name: nginxspec:  #replicas: 1表示pod副本数为1  replicas: 1  selector:    matchLabels:      app: nginx  strategy: {}  template:    metadata:      creationTimestamp: null      labels:        app: nginx    spec:      #terminationGracePeriodSeconds: 0 表示当Pod被终止时,不需要等待额外的时间。      terminationGracePeriodSeconds: 0      containers:      - image: nginx        imagePullPolicy: IfNotPresent        name: nginx        resources: {}status: {}

创建deploy,可以看到1个pod。

[root@k8scloude1 svc]# kubectl apply -f nginxdeploy.yaml deployment.apps/nginx created[root@k8scloude1 svc]# kubectl get pod -o wideNAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATESnginx-6cf858f6cf-5wh5s   1/1     Running   0          7s    10.244.112.155   k8scloude2              [root@k8scloude1 svc]# kubectl get deploy -o wideNAME    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES   SELECTORnginx   1/1     1            1           23s   nginx        nginx    app=nginx

pod的地址为10.244.112.155,对于pod的地址,在kubernetes集群的任何节点都可以访问,但是外界访问不了。

[root@k8scloude1 svc]# ping 10.244.112.155PING 10.244.112.155 (10.244.112.155) 56(84) bytes of data.64 bytes from 10.244.112.155: icmp_seq=1 ttl=63 time=0.430 ms64 bytes from 10.244.112.155: icmp_seq=2 ttl=63 time=0.516 ms64 bytes from 10.244.112.155: icmp_seq=3 ttl=63 time=0.595 ms^C--- 10.244.112.155 ping statistics ---3 packets transmitted, 3 received, 0% packet loss, time 2001msrtt min/avg/max/mdev = 0.430/0.513/0.595/0.072 ms
4.2 使用hostPort向外界暴露pod的端口

为了让kubernetes集群以外的机器可以访问pod,可以使用hostPort字段把容器的端口映射到物理机的端口,这样外界就可以访问pod了,类似于docker容器端口映射,关于docker容器端口映射可以查看博客《一文搞懂docker容器基础:docker镜像管理,docker容器管理》。

查看hostPort字段的解释

[root@k8scloude1 svc]# kubectl explain pod.spec.containers.ports.hostPortKIND:     PodVERSION:  v1FIELD:    hostPort DESCRIPTION:     Number of port to expose on the host. If specified, this must be a valid     port number, 0 < x < 65536. If HostNetwork is specified, this must match     ContainerPort. Most containers do not need this.

修改deploy的yaml文件,添加hostPort参数,把容器80端口映射到物理机的6554端口。

[root@k8scloude1 svc]# vim nginxdeploy.yaml [root@k8scloude1 svc]# cat nginxdeploy.yaml apiVersion: apps/v1kind: Deploymentmetadata:  creationTimestamp: null  labels:    app: nginx  name: nginxspec:  replicas: 1  selector:    matchLabels:      app: nginx  strategy: {}  template:    metadata:      creationTimestamp: null      labels:        app: nginx    spec:      #terminationGracePeriodSeconds: 0 表示Pod终止时不需要等待额外时间。      terminationGracePeriodSeconds: 0      containers:      - image: nginx        imagePullPolicy: IfNotPresent        #把容器80端口映射到物理机的6554端口        ports:        - name: http          containerPort: 80          hostPort: 6554        name: nginx        resources: {}status: {}

删除旧的deploy并创建新的deploy

[root@k8scloude1 svc]# kubectl delete deploy nginx deployment.apps "nginx" deleted[root@k8scloude1 svc]# kubectl apply -f nginxdeploy.yaml deployment.apps/nginx created[root@k8scloude1 svc]# kubectl get deployNAME    READY   UP-TO-DATE   AVAILABLE   AGEnginx   1/1     1            1           8s

查看pod,发现pod运行在k8scloude2上,访问k8scloude2的6554端口即可访问pod。

[root@k8scloude1 svc]# kubectl get pod -o wideNAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATESnginx-6f64cc5884-kkqmf   1/1     Running   0          15s   10.244.112.158   k8scloude2              [root@k8scloude1 svc]# kubectl get deploy -o wideNAME    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES   SELECTORnginx   1/1     1            1           25s   nginx        nginx    app=nginx

nginx-6f64cc5884-kkqmf 这个pod运行在k8scloude2上,访问k8scloude2地址加端口,即可访问pod的nginx服务。

[root@k8scloude1 svc]# curl http://192.168.110.129:6554......

Welcome to nginx!

If you see this page, the nginx web server is successfully installed andworking. Further configuration is required.

......

Thank you for using nginx.

把deploy的副本数变为2

[root@k8scloude1 svc]# kubectl scale deploy nginx --replicas=2deployment.apps/nginx scaled[root@k8scloude1 svc]# kubectl get deployNAME    READY   UP-TO-DATE   AVAILABLE   AGEnginx   2/2     2            2           6m23s

现在有2个pod了,pod分别运行在两个worker上

[root@k8scloude1 svc]# kubectl get pod -o wideNAME                     READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATESnginx-6f64cc5884-h78tv   1/1     Running   0          17s     10.244.251.252   k8scloude3              nginx-6f64cc5884-kkqmf   1/1     Running   0          6m30s   10.244.112.158   k8scloude2              

此时k8scloude3也可以访问成功

[root@k8scloude1 svc]# curl 192.168.110.128:6554......

Welcome to nginx!

If you see this page, the nginx web server is successfully installed andworking. Further configuration is required.

......

Thank you for using nginx.

把deploy的副本数变为3

[root@k8scloude1 svc]# kubectl scale deploy nginx --replicas=3deployment.apps/nginx scaled[root@k8scloude1 svc]# kubectl get deployNAME    READY   UP-TO-DATE   AVAILABLE   AGEnginx   2/3     3            2           8m29s

这时候问题就来了!可以发现通过hostPort把容器端口映射到物理机端口这种方法不太好,因为如果一个worker上有两个pod,每个pod都要映射物理机端口,就会造成端口冲突,pod创建失败

[root@k8scloude1 svc]# kubectl get pod -o wideNAME                     READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATESnginx-6f64cc5884-h78tv   1/1     Running   0          2m23s   10.244.251.252   k8scloude3              nginx-6f64cc5884-kkqmf   1/1     Running   0          8m36s   10.244.112.158   k8scloude2              nginx-6f64cc5884-msdqx   0/1     Pending   0          14s                                  [root@k8scloude1 svc]# kubectl get deploy -o wideNAME    READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES   SELECTORnginx   2/3     3            2           8m43s   nginx        nginx    app=nginx

删除deploy

[root@k8scloude1 svc]# kubectl delete deploy nginx deployment.apps "nginx" deleted[root@k8scloude1 svc]# kubectl get podNo resources found in svc namespace.[root@k8scloude1 svc]# kubectl get deployNo resources found in svc namespace.
五.使用service服务向外界暴露应用程序

修改deploy的yaml文件,给pod指定多个标签,但是deploy只匹配其中一个标签matchLabels:app1: nginx1。

[root@k8scloude1 svc]# vim nginxdeploy.yaml [root@k8scloude1 svc]# cat nginxdeploy.yaml apiVersion: apps/v1kind: Deploymentmetadata:  creationTimestamp: null  labels:    app: nginx  name: nginxspec:  #pod副本数为2个  replicas: 2  #deploy只匹配其中一个标签  selector:    matchLabels:      app1: nginx1  strategy: {}  template:    metadata:      creationTimestamp: null      #pod有3个标签      labels:        app1: nginx1        app2: nginx2        app3: nginx3    spec:      ##当需要关闭容器时,立即杀死容器而不等待默认的30秒优雅停机时长。      terminationGracePeriodSeconds: 0      containers:      - image: nginx        ##imagePullPolicy: IfNotPresent:表示如果本地已经存在该镜像,则不重新下载;否则从远程 Docker Hub 下载该镜像        imagePullPolicy: IfNotPresent        name: nginx        resources: {}status: {}

创建deploy

[root@k8scloude1 svc]# kubectl apply -f nginxdeploy.yaml deployment.apps/nginx created

deploy根据标签进行匹配

[root@k8scloude1 svc]# kubectl get deploy -o wideNAME    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES   SELECTORnginx   2/2     2            2           7s    nginx        nginx    app1=nginx1[root@k8scloude1 svc]# kubectl get pod -o wideNAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATESnginx-75b9846bd7-22btx   1/1     Running   0          12s   10.244.112.157   k8scloude2              nginx-75b9846bd7-m2pdq   1/1     Running   0          12s   10.244.112.159   k8scloude2              

可以看到pod有三个标签

[root@k8scloude1 svc]# kubectl get pod -o wide --show-labelsNAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES   LABELSnginx-75b9846bd7-22btx   1/1     Running   0          30s   10.244.112.157   k8scloude2                          app1=nginx1,app2=nginx2,app3=nginx3,pod-template-hash=75b9846bd7nginx-75b9846bd7-m2pdq   1/1     Running   0          30s   10.244.112.159   k8scloude2                          app1=nginx1,app2=nginx2,app3=nginx3,pod-template-hash=75b9846bd7
5.1 使用service服务向外界暴露pod5.1.1 创建service服务

查看service,服务service简写为svc

[root@k8scloude1 svc]# kubectl get svcNo resources found in svc namespace.[root@k8scloude1 svc]# kubectl get serviceNo resources found in svc namespace.

创建service服务建议使用命令行,而不是使用yaml文件。

svc创建语法如下:

kubectl expose --name=名字 资源类型/名字 --port=xxx --target-port=yyykubectl expose --name=名字 deploy/web1 --port=xxx --target-port=yyykubectl expose --name=名字 deploy web1 --port=xxx --target-port=yyykubectl expose --name=名字 pod/web1 --port=xxx --target-port=yyykubectl expose --name=名字 pod web1 --port=xxx --target-port=yyy

svc具有一个负载均衡器的作用,svc本身的端口(--port=xxx)可以随意定义,svc转发到pod的端口(--target-port=yyy)不可以随意定义,需要根据容器的实际情况来定义,svc通过标签选择后端的pod。

为deploy创建一个service服务

[root@k8scloude1 svc]# kubectl get deployNAME    READY   UP-TO-DATE   AVAILABLE   AGEnginx   2/2     2            2           46m[root@k8scloude1 svc]# kubectl expose --name=nginxsvc deploy nginx --port=80 service/nginxsvc exposed[root@k8scloude1 svc]# kubectl get svc -o wideNAME       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTORnginxsvc   ClusterIP   10.98.213.102           80/TCP    15s   app1=nginx1

如果svc没有指定使用哪个标签定位pod时,使用的标签和deploy一样

[root@k8scloude1 svc]# kubectl get svc -o wide --show-labelsNAME       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR      LABELSnginxsvc   ClusterIP   10.98.213.102           80/TCP    44s   app1=nginx1   app=nginx[root@k8scloude1 svc]# kubectl get pod -o wide --show-labelsNAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES   LABELSnginx-75b9846bd7-22btx   1/1     Running   0          48m   10.244.112.157   k8scloude2                          app1=nginx1,app2=nginx2,app3=nginx3,pod-template-hash=75b9846bd7nginx-75b9846bd7-m2pdq   1/1     Running   0          48m   10.244.112.159   k8scloude2                          app1=nginx1,app2=nginx2,app3=nginx3,pod-template-hash=75b9846bd7

删除svc

[root@k8scloude1 svc]# kubectl delete svc nginxsvc service "nginxsvc" deleted

可以手动指定svc选择的标签

[root@k8scloude1 svc]# kubectl expose --name=nginxsvc deploy nginx --port=80 --selector=app2=nginx2service/nginxsvc exposed[root@k8scloude1 svc]# kubectl get svc nginxsvc -o wideNAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE   SELECTORnginxsvc   ClusterIP   10.98.95.134           80/TCP    23s   app2=nginx2

查看svc的描述信息,Endpoints表示svc后端定位的pod。

[root@k8scloude1 svc]# kubectl describe svc nginxsvc Name:              nginxsvcNamespace:         svcLabels:            app=nginxAnnotations:       Selector:          app2=nginx2Type:              ClusterIPIP Family Policy:  SingleStackIP Families:       IPv4IP:                10.98.95.134IPs:               10.98.95.134Port:                80/TCPTargetPort:        80/TCPEndpoints:         10.244.112.157:80,10.244.112.159:80Session Affinity:  NoneEvents:            [root@k8scloude1 svc]# kubectl get pod -o wideNAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATESnginx-75b9846bd7-22btx   1/1     Running   0          57m   10.244.112.157   k8scloude2              nginx-75b9846bd7-m2pdq   1/1     Running   0          57m   10.244.112.159   k8scloude2              

把deploy的副本数变为4

[root@k8scloude1 svc]# kubectl scale deploy nginx --replicas=4deployment.apps/nginx scaled[root@k8scloude1 svc]# kubectl get pod -o wideNAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATESnginx-75b9846bd7-22btx   1/1     Running   0          58m   10.244.112.157   k8scloude2              nginx-75b9846bd7-bswx2   1/1     Running   0          10s   10.244.251.248   k8scloude3              nginx-75b9846bd7-kzx7h   1/1     Running   0          10s   10.244.251.249   k8scloude3              nginx-75b9846bd7-m2pdq   1/1     Running   0          58m   10.244.112.159   k8scloude2              

Endpoints定位的pod自动变为4个

[root@k8scloude1 svc]# kubectl describe svc nginxsvc Name:              nginxsvcNamespace:         svcLabels:            app=nginxAnnotations:       Selector:          app2=nginx2Type:              ClusterIPIP Family Policy:  SingleStackIP Families:       IPv4IP:                10.98.95.134IPs:               10.98.95.134Port:                80/TCPTargetPort:        80/TCPEndpoints:         10.244.112.157:80,10.244.112.159:80,10.244.251.248:80 + 1 more...Session Affinity:  NoneEvents:            

把deploy的副本数再次变为2

[root@k8scloude1 svc]# kubectl scale deploy nginx --replicas=2deployment.apps/nginx scaled

Endpoints定位的pod自动变为2个

[root@k8scloude1 svc]# kubectl describe svc nginxsvc Name:              nginxsvcNamespace:         svcLabels:            app=nginxAnnotations:       Selector:          app2=nginx2Type:              ClusterIPIP Family Policy:  SingleStackIP Families:       IPv4IP:                10.98.95.134IPs:               10.98.95.134Port:                80/TCPTargetPort:        80/TCPEndpoints:         10.244.112.157:80,10.244.251.248:80Session Affinity:  NoneEvents:            

现在手动生成一个pod,pod的标签为app2=nginx2,svc也能自动选择此pod。

[root@k8scloude1 svc]# kubectl run pod1 --image=nginx --image-pull-policy=IfNotPresent --labels="app2=nginx2"pod/pod1 created[root@k8scloude1 svc]# kubectl get pod -o wideNAME                     READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATESnginx-75b9846bd7-22btx   1/1     Running   0          64m     10.244.112.157   k8scloude2              nginx-75b9846bd7-bswx2   1/1     Running   0          5m58s   10.244.251.248   k8scloude3              pod1                     1/1     Running   0          7s      10.244.112.161   k8scloude2              

svc的Endpoints自动定位到该pod1

[root@k8scloude1 svc]# kubectl describe svc nginxsvc Name:              nginxsvcNamespace:         svcLabels:            app=nginxAnnotations:       Selector:          app2=nginx2Type:              ClusterIPIP Family Policy:  SingleStackIP Families:       IPv4IP:                10.98.95.134IPs:               10.98.95.134Port:                80/TCPTargetPort:        80/TCPEndpoints:         10.244.112.157:80,10.244.112.161:80,10.244.251.248:80Session Affinity:  NoneEvents:            

删除手动创建的pod1

[root@k8scloude1 svc]# kubectl delete pod pod1 --forcewarning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.pod "pod1" force deleted

把deploy的副本数变为3

[root@k8scloude1 svc]# kubectl scale deploy nginx --replicas=3deployment.apps/nginx scaled[root@k8scloude1 svc]# kubectl get pod -o wideNAME                     READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATESnginx-75b9846bd7-22btx   1/1     Running   0          66m     10.244.112.157   k8scloude2              nginx-75b9846bd7-7q7qm   1/1     Running   0          27s     10.244.112.166   k8scloude2              nginx-75b9846bd7-bswx2   1/1     Running   0          8m24s   10.244.251.248   k8scloude3              
5.1.2 测试svc的负载均衡

现在测试svc的负载均衡功能,看看svc能不能把流量均匀的分配给后端pod。

修改3个pod里的Nginx首页文件index.html,这样能辨别出每一个pod。

[root@k8scloude1 svc]# kubectl exec -it nginx-75b9846bd7-22btx -- sh -c "echo 111 >/usr/share/nginx/html/index.html"[root@k8scloude1 svc]# kubectl exec -it nginx-75b9846bd7-7q7qm -- sh -c "echo 222 >/usr/share/nginx/html/index.html"[root@k8scloude1 svc]# kubectl exec -it nginx-75b9846bd7-bswx2 -- sh -c "echo 333 >/usr/share/nginx/html/index.html"

svc的地址在集群内部可以访问,访问svc,可以看到svc具有负载均衡的作用,分别转发给了后端三个pod

[root@k8scloude1 svc]# while true ;do curl -s 10.98.95.134:80;sleep 1;done222111111222333333222

值得注意的是:ping不通svc的地址,但是可以telnet svc地址和80端口,因为svc只开放了端口80。

kube-proxy模式默认是iptables,如果kube-proxy模式为iptables时,在集群内部,ping不通svc的地址,但是如果kube-proxy模式为ipvs时,则能ping通svc的地址

#ping不通svc的地址[root@k8scloude1 svc]# ping 10.98.95.134PING 10.98.95.134 (10.98.95.134) 56(84) bytes of data.^C--- 10.98.95.134 ping statistics ---18 packets transmitted, 0 received, 100% packet loss, time 17001ms#可以telnet svc的地址[root@k8scloude1 svc]# telnet 10.98.95.134 80Trying 10.98.95.134...Connected to 10.98.95.134.Escape character is "^]".^CConnection closed by foreign host.

删除deploy

[root@k8scloude1 svc]# lsnginxdeploy.yaml[root@k8scloude1 svc]# kubectl delete -f nginxdeploy.yaml deployment.apps "nginx" deleted[root@k8scloude1 svc]# kubectl get podNo resources found in svc namespace.
六.service服务的发现

什么是服务的发现?创建了一个svc之后,pod怎么发现服务svc,这就是服务的发现。

服务的发现有三种方式:1.clusterIP 2.变量的方式 3.DNS。

下面进行逐一讲述。

6.1 使用clusterIP的方式进行服务发现

我们之前所创建的应用都比较单一,现在创建多级应用,使用wordpress镜像和mysql镜像搭建博客。以往还介绍了使用docker搭建博客的案例,详情请查看博客《使用docker 5分钟搭建一个博客(mysql+WordPress)》。

先在kubernetes集群的worker节点拉取mysql镜像和WordPress镜像。

[root@k8scloude2 ~]# docker pull hub.c.163.com/library/wordpress:latest[root@k8scloude2 ~]# docker pull hub.c.163.com/library/mysql:latest[root@k8scloude3 ~]# docker pull hub.c.163.com/library/wordpress:latest[root@k8scloude3 ~]# docker pull hub.c.163.com/library/mysql:latest

生成创建pod的yaml文件,使用hub.c.163.com/library/mysql:latest镜像创建pod。

[root@k8scloude1 svc]# kubectl run mysqlpod --image=hub.c.163.com/library/mysql:latest --image-pull-policy=IfNotPresent --dry-run=client -o yaml > mysqlpod.yaml

修改yaml文件,设置mysql的环境变量(root密码,MySQL用户,MySQL用户密码,要使用的MySQL数据库名)。

[root@k8scloude1 svc]# vim mysqlpod.yaml [root@k8scloude1 svc]# cat mysqlpod.yaml apiVersion: v1kind: Podmetadata:  creationTimestamp: null  labels:    run: mysqlpod  name: mysqlpodspec:  #当需要关闭容器时,立即杀死容器而不等待默认的30秒优雅停机时长。  terminationGracePeriodSeconds: 0  containers:  - image: hub.c.163.com/library/mysql:latest    #imagePullPolicy: IfNotPresent:表示如果本地已经存在该镜像,则不重新下载;否则从远程 Docker Hub 下载该镜像    imagePullPolicy: IfNotPresent    name: mysqlpod    resources: {}    env:    #root密码    - name: MYSQL_ROOT_PASSWORD      value: rootmima    #MySQL用户    - name: MYSQL_USER      value: lisi    #MySQL用户密码    - name: MYSQL_PASSWORD      value: lisimim    #要使用的MySQL数据库名    - name: MYSQL_DATABASE      value: wordpress  #dnsPolicy: ClusterFirst 表示Pod使用集群的DNS解析服务来解析域名。      dnsPolicy: ClusterFirst  #restartPolicy: Always 表示容器退出后总是重新启动。  restartPolicy: Alwaysstatus: {}

创建pod

[root@k8scloude1 svc]# kubectl apply -f mysqlpod.yaml pod/mysqlpod created[root@k8scloude1 svc]# kubectl get pod -o wideNAME       READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATESmysqlpod   1/1     Running   0          8s    10.244.112.163   k8scloude2              

pod创建好之后,创建pod的svc,--port=3306指定svc端口,--target-port=3306指定mysql容器端口。

[root@k8scloude1 svc]# kubectl expose --name=mysqlsvc pod mysqlpod --port=3306 --target-port=3306service/mysqlsvc exposed

查看svc

[root@k8scloude1 svc]# kubectl get svc -o wideNAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE   SELECTORmysqlsvc   ClusterIP   10.104.58.98           3306/TCP   13s   run=mysqlpodnginxsvc   ClusterIP   10.98.95.134           80/TCP     8h    app2=nginx2

接下来创建wordpress。yaml配置文件功能为:创建名为wordpresspod的pod,使用hub.c.163.com/library/wordpress:latest镜像,设置wordpress的环境变量,用于连接 MySQL 数据库,分别指定了MySQL数据库地址、MySQL数据库用户名、MySQL数据库密码和数据库名称。

WORDPRESS_DB_HOST数据库地址这里填mysql svc的ClusterIP,这是通过clusterIP进行服务发现

[root@k8scloude1 svc]# vim wordpresspod.yaml [root@k8scloude1 svc]# cat wordpresspod.yaml apiVersion: v1kind: Podmetadata:  creationTimestamp: null  labels:    run: wordpresspod  name: wordpresspodspec:  #当需要关闭容器时,立即杀死容器而不等待默认的30秒优雅停机时长。  terminationGracePeriodSeconds: 0  containers:  - image: hub.c.163.com/library/wordpress:latest    #imagePullPolicy: IfNotPresent:表示如果本地已经存在该镜像,则不重新下载;否则从远程 Docker Hub 下载该镜像    imagePullPolicy: IfNotPresent    name: wordpresspod    resources: {}    #设置wordpress的变量    env:    #MySQL数据库地址,WORDPRESS_DB_HOST数据库地址这里填mysql svc的ClusterIP    - name: WORDPRESS_DB_HOST      value: 10.104.58.98    #MySQL数据库用户名      - name: WORDPRESS_DB_USER      value: lisi    #MySQL数据库密码      - name: WORDPRESS_DB_PASSWORD      value: lisimim    #数据库名称      - name: WORDPRESS_DB_NAME      value: wordpress  dnsPolicy: ClusterFirst  restartPolicy: Alwaysstatus: {}

创建wordpresspod

[root@k8scloude1 svc]# kubectl apply -f wordpresspod.yaml pod/wordpresspod created[root@k8scloude1 svc]# kubectl get pod -o wideNAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATESmysqlpod       1/1     Running   0          13m   10.244.112.163   k8scloude2              wordpresspod   1/1     Running   0          9s    10.244.251.255   k8scloude3              

给wordpresspod创建一个svc用于外界访问wordpress,--type=NodePort用于服务发布,这样外界就可以访问此svc服务。

[root@k8scloude1 svc]# kubectl expose --name=wordpresssvc pod wordpresspod --port=80 --type=NodePortservice/wordpresssvc exposed

查看svc,80:31860/TCP 把pod的80 端口映射到物理机的31860端口,访问物理机的31860端口就可访问wordpress,如下所示:

[root@k8scloude1 svc]# kubectl get svc -o wideNAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTORmysqlsvc       ClusterIP   10.104.58.98            3306/TCP       14m   run=mysqlpodnginxsvc       ClusterIP   10.98.95.134            80/TCP         8h    app2=nginx2wordpresssvc   NodePort    10.107.76.238           80:31860/TCP   8s    run=wordpresspod

浏览器访问kubernetes集群任意节点IP+端口31860,就可访问wordpress页面,访问http://192.168.110.128:31860,语言选择简体中文,点击继续。

设置站点标题,用户名,密码,email,安装WordPress。

WordPress安装成功之后,点击登录。

根据你设置的账号进行登录。

此时个人博客就搭建完毕了。

6.2 使用环境变量的方式进行服务发现

上面是通过clusterIP进行服务发现,下面使用环境变量的方式进行服务发现。

现在有两个pod

[root@k8scloude1 ~]# kubectl get pod -o wideNAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATESmysqlpod       1/1     Running   0          63m   10.244.112.163   k8scloude2              wordpresspod   1/1     Running   0          50m   10.244.251.255   k8scloude3              

进入wordpresspod里,使用env查看pod里的环境变量,可以看到里面有很多环境变量。

[root@k8scloude1 ~]# kubectl exec -it wordpresspod -- bash #使用env查看pod里的环境变量root@wordpresspod:/var/www/html# envNGINXSVC_PORT_80_TCP_PROTO=tcp......PWD=/var/www/htmlMYSQLSVC_PORT_3306_TCP_PORT=3306MYSQLSVC_PORT=tcp://10.104.58.98:3306NGINXSVC_PORT_80_TCP_ADDR=10.98.95.134NGINXSVC_SERVICE_PORT=80MYSQLSVC_PORT_3306_TCP_ADDR=10.104.58.98MYSQLSVC_PORT_3306_TCP_PROTO=tcpNGINXSVC_PORT_80_TCP=tcp://10.98.95.134:80NGINXSVC_PORT=tcp://10.98.95.134:80WORDPRESS_DB_USER=lisi......root@wordpresspod:/var/www/html# exitexit

pod会以环境变量的方式去记录服务svc的信息,格式为:大写服务名_SERVICE_HOST=服务的IP ; 大写服务名_SERVICE_PORT=服务的端口,wordpress连接的mysql svc为mysqlsvc。MYSQLSVC_SERVICE_HOST为mysql svc的IP地址。

注意:pod创建之后会自动记录之前的存在的svc信息,在pod之后创建的svc信息不自动记录。

[root@k8scloude1 ~]# kubectl exec -it wordpresspod -- bashroot@wordpresspod:/var/www/html# env | grep -i mysqlsvcMYSQLSVC_SERVICE_HOST=10.104.58.98MYSQLSVC_PORT_3306_TCP_PORT=3306MYSQLSVC_PORT=tcp://10.104.58.98:3306MYSQLSVC_PORT_3306_TCP_ADDR=10.104.58.98MYSQLSVC_PORT_3306_TCP_PROTO=tcpMYSQLSVC_SERVICE_PORT=3306MYSQLSVC_PORT_3306_TCP=tcp://10.104.58.98:3306root@wordpresspod:/var/www/html# exitexit

现在一个mysql的pod和svc,一个wordpress的pod和svc

[root@k8scloude1 ~]# kubectl get svc -o wideNAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTORmysqlsvc       ClusterIP   10.104.58.98            3306/TCP       71m   run=mysqlpodnginxsvc       ClusterIP   10.98.95.134            80/TCP         9h    app2=nginx2wordpresssvc   NodePort    10.107.76.238           80:31860/TCP   57m   run=wordpresspod[root@k8scloude1 ~]# kubectl get pod -o wideNAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATESmysqlpod       1/1     Running   0          74m   10.244.112.163   k8scloude2              wordpresspod   1/1     Running   0          61m   10.244.251.255   k8scloude3              

删除wordpresspod

[root@k8scloude1 ~]# kubectl delete pod wordpresspod --forcewarning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.pod "wordpresspod" force deleted[root@k8scloude1 ~]# kubectl get pod -o wideNAME       READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATESmysqlpod   1/1     Running   0          75m   10.244.112.163   k8scloude2              

修改wordpresspod的yaml文件,设置wordpress的环境变量,用于连接 MySQL 数据库,分别指定了MySQL数据库地址、MySQL数据库用户名、MySQL数据库密码和数据库名称。

WORDPRESS_DB_HOST数据库地址这里填mysql svc的环境变量WORDPRESS_DB_HOST,这是通过环境变量进行服务发现

[root@k8scloude1 ~]# cd svc/[root@k8scloude1 svc]# pwd/root/svc[root@k8scloude1 svc]# vim wordpresspod.yaml [root@k8scloude1 svc]# cat wordpresspod.yaml apiVersion: v1kind: Podmetadata:  creationTimestamp: null  labels:    run: wordpresspod  name: wordpresspodspec:  #当需要关闭容器时,立即杀死容器而不等待默认的30秒优雅停机时长。  terminationGracePeriodSeconds: 0  containers:  - image: hub.c.163.com/library/wordpress:latest    #imagePullPolicy: IfNotPresent:表示如果本地已经存在该镜像,则不重新下载;否则从远程 Docker Hub 下载该镜像    imagePullPolicy: IfNotPresent    name: wordpresspod    resources: {}    env:    #MySQL数据库地址,WORDPRESS_DB_HOST数据库地址这里填mysql svc的环境变量    - name: WORDPRESS_DB_HOST      #使用变量的方式      value: $(MYSQLSVC_SERVICE_HOST)    #MySQL数据库用户名        - name: WORDPRESS_DB_USER      value: lisi    #MySQL数据库密码        - name: WORDPRESS_DB_PASSWORD      value: lisimim    #数据库名称        - name: WORDPRESS_DB_NAME      value: wordpress  dnsPolicy: ClusterFirst  restartPolicy: Alwaysstatus: {}

创建wordpresspod,这时候一切又正常了,搭建的博客又可以正常工作了。

此时浏览器访问http://192.168.110.128:31860/,即可访问wordpress。

[root@k8scloude1 svc]# kubectl apply -f wordpresspod.yaml pod/wordpresspod created[root@k8scloude1 svc]# kubectl get pod -o wideNAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATESmysqlpod       1/1     Running   0          79m   10.244.112.163   k8scloude2              wordpresspod   1/1     Running   0          6s    10.244.112.162   k8scloude2              [root@k8scloude1 svc]# kubectl get svc -o wideNAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTORmysqlsvc       ClusterIP   10.104.58.98            3306/TCP       76m   run=mysqlpodnginxsvc       ClusterIP   10.98.95.134            80/TCP         9h    app2=nginx2wordpresssvc   NodePort    10.107.76.238           80:31860/TCP   62m   run=wordpresspod

通过环境变量的方式进行服务发现,存在缺陷如下:

只能获取相同namespace里的变量;变量的获取有先后顺序,引用的变量必须要先创建。6.3 使用DNS的方式进行服务发现(推荐)

Kubernetes 中的 DNS 服务是一个专门的服务,用于为 Pod 提供服务发现功能。当我们创建一个 service 时,Kubernetes 会自动为该 service 创建一个 DNS 记录。这个 DNS 记录中包含了该 service 的名称、IP 地址以及端口信息。当一个 Pod 需要访问该 service 时,它可以通过该 service 的名称来查找该 DNS 记录,并将该名称解析为一个 IP 地址。这样,该 Pod 就可以直接通过该 IP 地址来访问该 service。

kube-dns记录了集群的DNS信息,svc创建好之后会向kube-dns进行注册,等以后pod想通过服务名直接访问svc时,会向kube-dns查询svc的IP地址,kube-dns把查到的svc地址返回给pod,pod就可访问svc。

[root@k8scloude1 svc]# kubectl get svc -n kube-systemNAME             TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                  AGEkube-dns         ClusterIP   10.96.0.10            53/UDP,53/TCP,9153/TCP   32dmetrics-server   ClusterIP   10.97.8.134           443/TCP                  31d

如何查询到kube-dns这个svc对应的pod?使用标签查找。

先查看svc选择的标签为k8s-app=kube-dns。

[root@k8scloude1 svc]# kubectl get svc -n kube-system -o wideNAME             TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                  AGE   SELECTORkube-dns         ClusterIP   10.96.0.10            53/UDP,53/TCP,9153/TCP   32d   k8s-app=kube-dnsmetrics-server   ClusterIP   10.97.8.134           443/TCP                  31d   k8s-app=metrics-server

通过标签k8s-app=kube-dns定位到pod

[root@k8scloude1 svc]# kubectl get pod -A -o wide -l k8s-app=kube-dnsNAMESPACE     NAME                       READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATESkube-system   coredns-545d6fc579-7wm95   1/1     Running   21         32d   10.244.158.109   k8scloude1              kube-system   coredns-545d6fc579-87q8j   1/1     Running   21         32d   10.244.158.110   k8scloude1              

删除svc,重新给wordpress创建svc

[root@k8scloude1 svc]# kubectl get svc -o wideNAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE    SELECTORmysqlsvc       ClusterIP   10.104.58.98            3306/TCP       164m   run=mysqlpodnginxsvc       ClusterIP   10.98.95.134            80/TCP         11h    app2=nginx2wordpresssvc   NodePort    10.107.76.238           80:31860/TCP   151m   run=wordpresspod[root@k8scloude1 svc]# kubectl delete svc wordpresssvc service "wordpresssvc" deleted[root@k8scloude1 ~]# kubectl get svc -o wideNAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE   SELECTORmysqlsvc   ClusterIP   10.104.58.98           3306/TCP   15h   run=mysqlpodnginxsvc   ClusterIP   10.98.95.134           80/TCP     24h   app2=nginx2[root@k8scloude1 ~]# kubectl expose --name=wordpresssvc pod wordpresspod --port=80 --type=NodePortservice/wordpresssvc exposed[root@k8scloude1 ~]# kubectl get svc -o wideNAME           TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE   SELECTORmysqlsvc       ClusterIP   10.104.58.98           3306/TCP       15h   run=mysqlpodnginxsvc       ClusterIP   10.98.95.134           80/TCP         24h   app2=nginx2wordpresssvc   NodePort    10.100.99.82           80:32729/TCP   9s    run=wordpresspod

使用Nginx镜像创建一个nginx pod。

[root@k8scloude1 svc]# cat pod.yaml apiVersion: v1kind: Podmetadata:  labels:    test: podtest  name: podtestspec:  #当需要关闭容器时,立即杀死容器而不等待默认的30秒优雅停机时长。  terminationGracePeriodSeconds: 0  containers:  - name: nginx    image: nginx    imagePullPolicy: IfNotPresent[root@k8scloude1 svc]# kubectl apply -f pod.yaml pod/podtest created

查看pod

[root@k8scloude1 svc]# kubectl get pod -o wideNAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATESmysqlpod       1/1     Running   1          15h   10.244.112.168   k8scloude2              podtest        1/1     Running   0          9s    10.244.251.195   k8scloude3              wordpresspod   1/1     Running   1          14h   10.244.112.164   k8scloude2              

修改pod里的index.html文件,把index.html内容修改为111。

[root@k8scloude1 svc]# kubectl exec -it podtest -- sh -c "echo 111 > /usr/share/nginx/html/index.html"

给podtest创建svc服务

[root@k8scloude1 svc]# kubectl expose --name=podtestsvc pod podtest --port=80 service/podtestsvc exposed[root@k8scloude1 svc]# kubectl get svc -o wideNAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE     SELECTORmysqlsvc       ClusterIP   10.104.58.98             3306/TCP       15h     run=mysqlpodnginxsvc       ClusterIP   10.98.95.134             80/TCP         24h     app2=nginx2podtestsvc     ClusterIP   10.108.102.183           80/TCP         7s      test=podtestwordpresssvc   NodePort    10.100.99.82             80:32729/TCP   8m23s   run=wordpresspod

--rm表示创建一个临时pod,退出pod就会自动删除pod。

创建名为clientpod的临时pod作为客户端,去访问其他svc,首先访问podtestsvc。

[root@k8scloude1 svc]# kubectl run clientpod --image=nginx --image-pull-policy=IfNotPresent -it --rm -- bashIf you don"t see a command prompt, try pressing enter.#直接访问svc就可访问服务root@clientpod:/# curl podtestsvc111root@clientpod:/# exitexitSession ended, resume using "kubectl attach clientpod -c clientpod -i -t" command when the pod is runningpod "clientpod" deleted

-n default:表示进入pod后,自动切换为default命名空间,继续访问podtestsvc。

[root@k8scloude1 svc]# kubectl run clientpod --image=nginx --image-pull-policy=IfNotPresent -it --rm -n default -- bashIf you don"t see a command prompt, try pressing enter.#因为是在default命名空间里访问svc命名空间里的服务,所以访问失败root@clientpod:/# curl podtestsvccurl: (6) Could not resolve host: podtestsvc#需要指定svc命名空间root@clientpod:/# curl podtestsvc.svc111#查看pod里DNS信息:nameserver 10.96.0.10对应的就是kube-dns的IProot@clientpod:/# cat /etc/resolv.conf nameserver 10.96.0.10search default.svc.cluster.local svc.cluster.local cluster.localoptions ndots:5root@clientpod:/# exitexitSession ended, resume using "kubectl attach clientpod -c clientpod -i -t" command when the pod is runningpod "clientpod" deleted

删除wordpresspod,重新创建。

[root@k8scloude1 svc]# kubectl delete pod wordpresspod --forcewarning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.pod "wordpresspod" force deleted[root@k8scloude1 svc]# kubectl get pod -o wideNAME       READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATESmysqlpod   1/1     Running   1          16h   10.244.112.168   k8scloude2              podtest    1/1     Running   0          10m   10.244.251.195   k8scloude3              

修改wordpresspod的yaml文件,设置wordpress的环境变量,用于连接 MySQL 数据库,分别指定了MySQL数据库地址、MySQL数据库用户名、MySQL数据库密码和数据库名称。

WORDPRESS_DB_HOST数据库地址这里直接填mysql svc的名称mysqlsvc,这是通过DNS进行服务发现

[root@k8scloude1 svc]# vim wordpresspod.yaml [root@k8scloude1 svc]# cat wordpresspod.yaml apiVersion: v1kind: Podmetadata:  creationTimestamp: null  labels:    run: wordpresspod  name: wordpresspodspec:  #当需要关闭容器时,立即杀死容器而不等待默认的30秒优雅停机时长。  terminationGracePeriodSeconds: 0  containers:  - image: hub.c.163.com/library/wordpress:latest    #imagePullPolicy: IfNotPresent:表示如果本地已经存在该镜像,则不重新下载;否则从远程 Docker Hub 下载该镜像    imagePullPolicy: IfNotPresent    name: wordpresspod    resources: {}    #设置wordpress的变量    env:    #MySQL数据库地址,WORDPRESS_DB_HOST数据库地址这里直接填mysql svc的名称mysqlsvc    - name: WORDPRESS_DB_HOST      #使用DNS的方式      value: mysqlsvc    #MySQL数据库用户名        - name: WORDPRESS_DB_USER      value: lisi    #MySQL数据库密码        - name: WORDPRESS_DB_PASSWORD      value: lisimim    #数据库名称        - name: WORDPRESS_DB_NAME      value: wordpress  dnsPolicy: ClusterFirst  restartPolicy: Alwaysstatus: {}

创建wordpresspod,这时候一切又正常了,搭建的博客又可以正常工作了。

此时浏览器访问http://192.168.110.128:32632/,即可访问wordpress。

[root@k8scloude1 svc]# kubectl apply -f wordpresspod.yaml pod/wordpresspod created[root@k8scloude1 svc]# kubectl get pod -o wideNAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATESmysqlpod       1/1     Running   1          16h   10.244.112.168   k8scloude2              wordpresspod   1/1     Running   0          10s   10.244.251.198   k8scloude3              [root@k8scloude1 svc]# kubectl get svc -o wideNAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE     SELECTORmysqlsvc       ClusterIP   10.104.58.98            3306/TCP       16h     run=mysqlpodnginxsvc       ClusterIP   10.98.95.134            80/TCP         24h     app2=nginx2wordpresssvc   NodePort    10.109.31.167           80:32632/TCP   4m42s   run=wordpresspod

删除pod和svc

[root@k8scloude1 svc]# kubectl delete pod mysqlpod wordpresspod --forcewarning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.pod "mysqlpod" force deletedpod "wordpresspod" force deleted[root@k8scloude1 svc]# kubectl delete svc mysqlsvc nginxsvc wordpresssvcservice "mysqlsvc" deletedservice "nginxsvc" deletedservice "wordpresssvc" deleted[root@k8scloude1 svc]# kubectl get pod -o wideNo resources found in svc namespace.[root@k8scloude1 svc]# kubectl get svc -o wideNo resources found in svc namespace.
七.service服务的发布

在Kubernetes中,服务发布是指将应用程序或服务对外部公开,以便其他应用程序或用户可以访问它们。简而言之服务发布就是使外界能访问svc。

Kubernetes集群中的服务可以使用三种不同的类型进行发布和暴露:ClusterIP,NodePort以及LoadBalancer:

ClusterIP:ClusterIP是最常见的服务发布类型,它将Pod暴露给集群内部,并通过集群内部的DNS进行发现。这意味着只有在同一Kubernetes集群内的其他Pod才能访问该服务,而外部客户端无法访问。ClusterIP类型的服务通常用于基于微服务架构的应用程序内部通信。

NodePort:使用NodePort类型的服务可以公开一个Pod,以便从集群外部访问。当您创建一个NodePort类型的服务时,Kubernetes会在每个节点上公开一个随机端口。通过此端口,来自集群外部的客户端可以访问此服务。NodePort类型的服务通常用于测试、开发和小型生产环境。

LoadBalancer:LoadBalancer类型的服务可以公开一个Pod,以便从外部负载平衡器访问。当您创建一个LoadBalancer类型的服务时,Kubernetes会为其分配一个外部IP地址,并配置外部负载平衡器以将流量路由到该地址。LoadBalancer类型的服务通常用于生产环境中需要大规模处理流量的应用程序。

除了这三种类型之外,还有一种称为ExternalName的特殊类型。使用ExternalName类型的服务可以将一个Kubernetes服务映射到集群外部的DNS名称。这种类型的服务通常用于需要访问集群外部资源的应用程序,例如外部数据库或Web服务。

注意:service在哪个节点上运行这种说法是错误的,service是抽象的,不存在在哪个节点上运行。

7.1 使用nodeport进行服务的发布

先弄清楚几个参数:NodePort是svc映射到物理机的端口,port是svc的端口,target-port是pod容器里的端口,hostport是pod映射到物理机的端口

7.1.1 使用kubectl edit修改服务类型为NodePort

使用Nginx镜像创建一个pod。

[root@k8scloude1 svc]# cat pod.yaml apiVersion: v1kind: Podmetadata:  labels:    test: podtest  name: podtestspec:  #当需要关闭容器时,立即杀死容器而不等待默认的30秒优雅停机时长。  terminationGracePeriodSeconds: 0  containers:  - name: nginx    image: nginx    #imagePullPolicy: IfNotPresent:表示如果本地已经存在该镜像,则不重新下载;否则从远程 Docker Hub 下载该镜像    imagePullPolicy: IfNotPresent#创建一个nginx pod[root@k8scloude1 svc]# kubectl apply -f pod.yaml pod/podtest created

给pod创建svc

[root@k8scloude1 svc]# kubectl get pod -o wideNAME      READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATESpodtest   1/1     Running   0          26s   10.244.112.169   k8scloude2              [root@k8scloude1 svc]# kubectl expose --name=podtestsvc pod podtest --port=80service/podtestsvc exposed[root@k8scloude1 svc]# kubectl get svc -o wideNAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTORpodtestsvc   ClusterIP   10.100.92.123           80/TCP    6s    test=podtest

直接编辑svc:把type: ClusterIP改为type: NodePort。

[root@k8scloude1 svc]# kubectl edit svc podtestsvc service/podtestsvc edited

把type: ClusterIP改为type: NodePort之后,svc类型就变了,此时svc的发布类型已经改变,在浏览器访问物理机IP:30908,即可访问svc服务。

[root@k8scloude1 svc]# kubectl get svc -o wideNAME         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE     SELECTORpodtestsvc   NodePort   10.100.92.123           80:30908/TCP   3m39s   test=podtest

浏览器访问192.168.110.129:30908,即可成功访问Nginx。

要恢复svc的发布类型,直接把type: NodePort 改为type: ClusterIP即可。

[root@k8scloude1 svc]# kubectl edit svc podtestsvc service/podtestsvc edited

此时svc发布类型又变为ClusterIP了。

[root@k8scloude1 svc]# kubectl get svc -o wideNAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE     SELECTORpodtestsvc   ClusterIP   10.100.92.123           80/TCP    7m28s   test=podtest

删除svc

[root@k8scloude1 svc]# kubectl delete svc podtestsvc service "podtestsvc" deleted
7.1.2 使用type指定服务类型为NodePort

也可以使用命令行的方式指定svc的发布类型为NodePort。

[root@k8scloude1 svc]# kubectl expose --name=podtestsvc pod podtest --port=80 --type=NodePortservice/podtestsvc exposed

现在svc类型为NodePort

[root@k8scloude1 svc]# kubectl get svc -o wideNAME         TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE   SELECTORpodtestsvc   NodePort   10.97.91.78           80:31596/TCP   2s    test=podtest

删除svc

[root@k8scloude1 svc]# kubectl delete svc podtestsvc service "podtestsvc" deleted

注意:NodePort的svc发布类型存在一定问题:

NodePort映射的端口越多,漏洞越大NodePort端口太多维护困难。7.2 使用LoadBalancer的方式进行服务的发布7.2.1 安装METALLB

使用LoadBalancer的方式进行服务发布,需要借助第三方的工具(METALLB)。

每个svc都有一个私有地址,只能在集群内部访问,如果我们把svc的类型设置为LoadBalancer,则svc会获取到一个外部IP,这个外部IP来自地址池,本文使用METALLB配置地址池。

METALLB的官网如下:https://metallb.universe.tf/

查看MetalLB的安装方式,Installation MetalLB By Manifest。

创建metallb的namespace

[root@k8scloude1 svc]# kubectl create ns metallb-systemnamespace/metallb-system created

下载metallb的安装文件

[root@k8scloude1 svc]# wget https://raw.githubusercontent.com/metallb/metallb/v0.11.0/manifests/metallb.yaml[root@k8scloude1 svc]# wget https://raw.githubusercontent.com/metallb/metallb/v0.11.0/manifests/namespace.yaml[root@k8scloude1 svc]# lsmetallb.yaml  namespace.yaml  

查看metallb需要的镜像

[root@k8scloude1 svc]# grep image metallb.yaml         image: quay.io/metallb/speaker:v0.11.0        image: quay.io/metallb/controller:v0.11.0

修改metallb.yaml 文件,修改metallb.yaml里的镜像下载策略为IfNotPresent,表示如果本地已经存在该镜像,则不重新下载;否则从远程仓库下载该镜像。

[root@k8scloude1 svc]# vim metallb.yaml [root@k8scloude1 svc]# cat metallb.yaml | grep image        image: quay.io/metallb/speaker:v0.11.0        imagePullPolicy: IfNotPresent        image: quay.io/metallb/controller:v0.11.0        imagePullPolicy: IfNotPresent

在worker节点提前下载speaker和controller镜像。

[root@k8scloude2 ~]# docker pull quay.io/metallb/speaker:v0.11.0[root@k8scloude2 ~]# docker pull quay.io/metallb/controller:v0.11.0[root@k8scloude2 ~]# docker images | grep metallbquay.io/metallb/speaker                              v0.11.0   896b796b12bb   3 months ago    50.2MBquay.io/metallb/controller                           v0.11.0   85a7890eec45   3 months ago    46.5MB[root@k8scloude3 ~]# docker pull quay.io/metallb/speaker:v0.11.0[root@k8scloude3 ~]# docker pull quay.io/metallb/controller:v0.11.0[root@k8scloude3 ~]# docker images | grep metallbquay.io/metallb/speaker                              v0.11.0   896b796b12bb   3 months ago    50.2MBquay.io/metallb/controller                           v0.11.0   85a7890eec45   3 months ago    46.5MB

应用命名空间文件,安装metallb。

[root@k8scloude1 svc]# kubectl apply -f namespace.yaml Warning: resource namespaces/metallb-system is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.namespace/metallb-system configured[root@k8scloude1 svc]# kubectl apply -f metallb.yaml Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+podsecuritypolicy.policy/controller createdpodsecuritypolicy.policy/speaker created......rolebinding.rbac.authorization.k8s.io/config-watcher createdrolebinding.rbac.authorization.k8s.io/pod-lister createdrolebinding.rbac.authorization.k8s.io/controller createddaemonset.apps/speaker createddeployment.apps/controller created

查看pod,可以看到metallb安装成功。

[root@k8scloude1 svc]# kubectl get pod -n metallb-system -o wideNAME                          READY   STATUS    RESTARTS   AGE     IP                NODE         NOMINATED NODE   READINESS GATEScontroller-7dcc8764f4-qdwl2   1/1     Running   0          2m41s   10.244.112.160    k8scloude2              speaker-892pm                 1/1     Running   0          2m41s   192.168.110.128   k8scloude3              speaker-jfccb                 1/1     Running   0          2m41s   192.168.110.130   k8scloude1              speaker-nkrgk                 1/1     Running   0          2m41s   192.168.110.129   k8scloude2              
7.2.2 配置地址池

查看配置地址池的yaml文件。

接下来配置地址池,地址池的IP范围为:192.168.110.188-192.168.110.250

[root@k8scloude1 svc]# vim ipaddrpool.yaml[root@k8scloude1 svc]# cat ipaddrpool.yaml apiVersion: v1kind: ConfigMapmetadata:  namespace: metallb-system  name: configdata:  config: |    address-pools:    - name: default      protocol: layer2     #地址池的IP范围      addresses:      - 192.168.110.188-192.168.110.250

创建地址池

[root@k8scloude1 svc]# kubectl apply -f ipaddrpool.yaml configmap/config created[root@k8scloude1 svc]# kubectl get configmap -o wideNAME               DATA   AGEkube-root-ca.crt   1      35h
7.2.3 使用LoadBalancer的方式进行服务发布

现在podtest没有svc,给podtest创建svc,类型为LoadBalancer。

[root@k8scloude1 svc]# kubectl get pod -o wideNAME      READY   STATUS    RESTARTS   AGE    IP               NODE         NOMINATED NODE   READINESS GATESpodtest   1/1     Running   0          148m   10.244.112.169   k8scloude2              [root@k8scloude1 svc]# kubectl get svc -o wideNo resources found in svc namespace.[root@k8scloude1 svc]# kubectl expose --name=podtestsvc pod podtest --port=80 --type=LoadBalancerservice/podtestsvc exposed

查看svc,EXTERNAL-IP地址是从地址池里分配的。

[root@k8scloude1 svc]# kubectl get svc -o wideNAME         TYPE           CLUSTER-IP     EXTERNAL-IP       PORT(S)        AGE   SELECTORpodtestsvc   LoadBalancer   10.97.238.10   192.168.110.188   80:30725/TCP   3s    test=podtest

浏览器直接访问外部IP即可访问svc服务:http://192.168.110.188/ 。

再给podtest创建一个svc,类型还是LoadBalancer。

[root@k8scloude1 svc]# kubectl expose --name=podtestsvc2 pod podtest --port=80 --type=LoadBalancerservice/podtestsvc2 exposed[root@k8scloude1 svc]# kubectl get svc -o wideNAME          TYPE           CLUSTER-IP     EXTERNAL-IP       PORT(S)        AGE    SELECTORpodtestsvc    LoadBalancer   10.97.238.10   192.168.110.188   80:30725/TCP   5m3s   test=podtestpodtestsvc2   LoadBalancer   10.96.128.89   192.168.110.189   80:32644/TCP   5s     test=podtest

浏览器直接访问外部IP即可访问svc服务:http://192.168.110.189/。

删除svc。

[root@k8scloude1 svc]# kubectl delete svc podtestsvc podtestsvc2service "podtestsvc" deletedservice "podtestsvc2" deleted[root@k8scloude1 svc]# kubectl get svc -o wideNo resources found in svc namespace.[root@k8scloude1 svc]# kubectl get pod -o wideNAME      READY   STATUS    RESTARTS   AGE    IP               NODE         NOMINATED NODE   READINESS GATESpodtest   1/1     Running   0          159m   10.244.112.169   k8scloude2              

推荐内容