Kubernetes(k8s)服务service:service的发现和service的发布

一.系统环境

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

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

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

服务器 操作系统版本 CPU架构 进程 功能描述
k8scloude1/192.168.110.130 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kube-apiserver,etcd,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calico k8s master节点
k8scloude2/192.168.110.129 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kubelet,kube-proxy,calico k8s worker节点
k8scloude3/192.168.110.128 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kubelet,kube-proxy,calico k8s 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 svc
namespace/svc created

切换命名空间到svc

[root@k8scloude1 svc]# kubens svc
Context "kubernetes-admin@kubernetes" modified.
Active namespace is "svc".

[root@k8scloude1 svc]# kubectl get pod
No 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/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  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/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  #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 wide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
nginx-6cf858f6cf-5wh5s   1/1     Running   0          7s    10.244.112.155   k8scloude2   <none>           <none>

[root@k8scloude1 svc]# kubectl get deploy -o wide
NAME    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES   SELECTOR
nginx   1/1     1            1           23s   nginx        nginx    app=nginx

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

[root@k8scloude1 svc]# ping 10.244.112.155
PING 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 ms
64 bytes from 10.244.112.155: icmp_seq=2 ttl=63 time=0.516 ms
64 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 2001ms
rtt 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.hostPort
KIND:     Pod
VERSION:  v1

FIELD:    hostPort <integer>

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/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  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 deploy
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           8s

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

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
nginx-6f64cc5884-kkqmf   1/1     Running   0          15s   10.244.112.158   k8scloude2   <none>           <none>

[root@k8scloude1 svc]# kubectl get deploy -o wide
NAME    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES   SELECTOR
nginx   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
<!DOCTYPE html>
......
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
......
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

把deploy的副本数变为2

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

[root@k8scloude1 svc]# kubectl get deploy
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   2/2     2            2           6m23s

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

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

此时k8scloude3也可以访问成功

[root@k8scloude1 svc]# curl 192.168.110.128:6554
<!DOCTYPE html>
<html>
......
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
......
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

把deploy的副本数变为3

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

[root@k8scloude1 svc]# kubectl get deploy
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   2/3     3            2           8m29s

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

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATES
nginx-6f64cc5884-h78tv   1/1     Running   0          2m23s   10.244.251.252   k8scloude3   <none>           <none>
nginx-6f64cc5884-kkqmf   1/1     Running   0          8m36s   10.244.112.158   k8scloude2   <none>           <none>
nginx-6f64cc5884-msdqx   0/1     Pending   0          14s     <none>           <none>       <none>           <none>

[root@k8scloude1 svc]# kubectl get deploy -o wide
NAME    READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES   SELECTOR
nginx   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 pod
No resources found in svc namespace.

[root@k8scloude1 svc]# kubectl get deploy
No 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/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  #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 wide
NAME    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES   SELECTOR
nginx   2/2     2            2           7s    nginx        nginx    app1=nginx1

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
nginx-75b9846bd7-22btx   1/1     Running   0          12s   10.244.112.157   k8scloude2   <none>           <none>
nginx-75b9846bd7-m2pdq   1/1     Running   0          12s   10.244.112.159   k8scloude2   <none>           <none>

可以看到pod有三个标签

[root@k8scloude1 svc]# kubectl get pod -o wide --show-labels
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES   LABELS
nginx-75b9846bd7-22btx   1/1     Running   0          30s   10.244.112.157   k8scloude2   <none>           <none>            app1=nginx1,app2=nginx2,app3=nginx3,pod-template-hash=75b9846bd7
nginx-75b9846bd7-m2pdq   1/1     Running   0          30s   10.244.112.159   k8scloude2   <none>           <none>            app1=nginx1,app2=nginx2,app3=nginx3,pod-template-hash=75b9846bd7

5.1 使用service服务向外界暴露pod

5.1.1 创建service服务

查看service,服务service简写为svc

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

[root@k8scloude1 svc]# kubectl get service
No resources found in svc namespace.

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

svc创建语法如下:

  • kubectl expose --name=名字 资源类型/名字 --port=xxx --target-port=yyy
  • kubectl expose --name=名字 deploy/web1 --port=xxx --target-port=yyy
  • kubectl expose --name=名字 deploy web1 --port=xxx --target-port=yyy
  • kubectl expose --name=名字 pod/web1 --port=xxx --target-port=yyy
  • kubectl 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 deploy
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   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 wide
NAME       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR
nginxsvc   ClusterIP   10.98.213.102   <none>        80/TCP    15s   app1=nginx1

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

[root@k8scloude1 svc]# kubectl get svc -o wide --show-labels
NAME       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR      LABELS
nginxsvc   ClusterIP   10.98.213.102   <none>        80/TCP    44s   app1=nginx1   app=nginx

[root@k8scloude1 svc]# kubectl get pod -o wide --show-labels
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES   LABELS
nginx-75b9846bd7-22btx   1/1     Running   0          48m   10.244.112.157   k8scloude2   <none>           <none>            app1=nginx1,app2=nginx2,app3=nginx3,pod-template-hash=75b9846bd7
nginx-75b9846bd7-m2pdq   1/1     Running   0          48m   10.244.112.159   k8scloude2   <none>           <none>            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=nginx2
service/nginxsvc exposed

[root@k8scloude1 svc]# kubectl get svc nginxsvc -o wide
NAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE   SELECTOR
nginxsvc   ClusterIP   10.98.95.134   <none>        80/TCP    23s   app2=nginx2

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

[root@k8scloude1 svc]# kubectl describe svc nginxsvc 
Name:              nginxsvc
Namespace:         svc
Labels:            app=nginx
Annotations:       <none>
Selector:          app2=nginx2
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.98.95.134
IPs:               10.98.95.134
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.112.157:80,10.244.112.159:80
Session Affinity:  None
Events:            <none>

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
nginx-75b9846bd7-22btx   1/1     Running   0          57m   10.244.112.157   k8scloude2   <none>           <none>
nginx-75b9846bd7-m2pdq   1/1     Running   0          57m   10.244.112.159   k8scloude2   <none>           <none>

把deploy的副本数变为4

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

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
nginx-75b9846bd7-22btx   1/1     Running   0          58m   10.244.112.157   k8scloude2   <none>           <none>
nginx-75b9846bd7-bswx2   1/1     Running   0          10s   10.244.251.248   k8scloude3   <none>           <none>
nginx-75b9846bd7-kzx7h   1/1     Running   0          10s   10.244.251.249   k8scloude3   <none>           <none>
nginx-75b9846bd7-m2pdq   1/1     Running   0          58m   10.244.112.159   k8scloude2   <none>           <none>

Endpoints定位的pod自动变为4个

[root@k8scloude1 svc]# kubectl describe svc nginxsvc 
Name:              nginxsvc
Namespace:         svc
Labels:            app=nginx
Annotations:       <none>
Selector:          app2=nginx2
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.98.95.134
IPs:               10.98.95.134
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.112.157:80,10.244.112.159:80,10.244.251.248:80 + 1 more...
Session Affinity:  None
Events:            <none>

把deploy的副本数再次变为2

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

Endpoints定位的pod自动变为2个

[root@k8scloude1 svc]# kubectl describe svc nginxsvc 
Name:              nginxsvc
Namespace:         svc
Labels:            app=nginx
Annotations:       <none>
Selector:          app2=nginx2
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.98.95.134
IPs:               10.98.95.134
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.112.157:80,10.244.251.248:80
Session Affinity:  None
Events:            <none>

现在手动生成一个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 wide
NAME                     READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATES
nginx-75b9846bd7-22btx   1/1     Running   0          64m     10.244.112.157   k8scloude2   <none>           <none>
nginx-75b9846bd7-bswx2   1/1     Running   0          5m58s   10.244.251.248   k8scloude3   <none>           <none>
pod1                     1/1     Running   0          7s      10.244.112.161   k8scloude2   <none>           <none>

svc的Endpoints自动定位到该pod1

[root@k8scloude1 svc]# kubectl describe svc nginxsvc 
Name:              nginxsvc
Namespace:         svc
Labels:            app=nginx
Annotations:       <none>
Selector:          app2=nginx2
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.98.95.134
IPs:               10.98.95.134
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.112.157:80,10.244.112.161:80,10.244.251.248:80
Session Affinity:  None
Events:            <none>

删除手动创建的pod1

[root@k8scloude1 svc]# kubectl delete pod pod1 --force
warning: 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=3
deployment.apps/nginx scaled

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATES
nginx-75b9846bd7-22btx   1/1     Running   0          66m     10.244.112.157   k8scloude2   <none>           <none>
nginx-75b9846bd7-7q7qm   1/1     Running   0          27s     10.244.112.166   k8scloude2   <none>           <none>
nginx-75b9846bd7-bswx2   1/1     Running   0          8m24s   10.244.251.248   k8scloude3   <none>           <none>

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;done
222
111
111
222
333
333
222

值得注意的是: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.134
PING 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 80
Trying 10.98.95.134...
Connected to 10.98.95.134.
Escape character is '^]'.

^CConnection closed by foreign host.

删除deploy

[root@k8scloude1 svc]# ls
nginxdeploy.yaml

[root@k8scloude1 svc]# kubectl delete -f nginxdeploy.yaml 
deployment.apps "nginx" deleted

[root@k8scloude1 svc]# kubectl get pod
No 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: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: mysqlpod
  name: mysqlpod
spec:
  #当需要关闭容器时,立即杀死容器而不等待默认的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: Always
status: {}

创建pod

[root@k8scloude1 svc]# kubectl apply -f mysqlpod.yaml 
pod/mysqlpod created

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME       READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod   1/1     Running   0          8s    10.244.112.163   k8scloude2   <none>           <none>

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

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

查看svc

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE   SELECTOR
mysqlsvc   ClusterIP   10.104.58.98   <none>        3306/TCP   13s   run=mysqlpod
nginxsvc   ClusterIP   10.98.95.134   <none>        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: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: wordpresspod
  name: wordpresspod
spec:
  #当需要关闭容器时,立即杀死容器而不等待默认的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: Always
status: {}

创建wordpresspod

[root@k8scloude1 svc]# kubectl apply -f wordpresspod.yaml 
pod/wordpresspod created

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod       1/1     Running   0          13m   10.244.112.163   k8scloude2   <none>           <none>
wordpresspod   1/1     Running   0          9s    10.244.251.255   k8scloude3   <none>           <none>

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

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

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

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTOR
mysqlsvc       ClusterIP   10.104.58.98    <none>        3306/TCP       14m   run=mysqlpod
nginxsvc       ClusterIP   10.98.95.134    <none>        80/TCP         8h    app2=nginx2
wordpresssvc   NodePort    10.107.76.238   <none>        80:31860/TCP   8s    run=wordpresspod

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

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

image-20230605160616369

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

image-20230605160644735

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

image-20230605160717044

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

image-20230605160757200

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

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

现在有两个pod

[root@k8scloude1 ~]# kubectl get pod -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod       1/1     Running   0          63m   10.244.112.163   k8scloude2   <none>           <none>
wordpresspod   1/1     Running   0          50m   10.244.251.255   k8scloude3   <none>           <none>

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

[root@k8scloude1 ~]# kubectl exec -it wordpresspod -- bash 

#使用env查看pod里的环境变量
root@wordpresspod:/var/www/html# env
NGINXSVC_PORT_80_TCP_PROTO=tcp
......
PWD=/var/www/html
MYSQLSVC_PORT_3306_TCP_PORT=3306
MYSQLSVC_PORT=tcp://10.104.58.98:3306
NGINXSVC_PORT_80_TCP_ADDR=10.98.95.134
NGINXSVC_SERVICE_PORT=80
MYSQLSVC_PORT_3306_TCP_ADDR=10.104.58.98
MYSQLSVC_PORT_3306_TCP_PROTO=tcp
NGINXSVC_PORT_80_TCP=tcp://10.98.95.134:80
NGINXSVC_PORT=tcp://10.98.95.134:80
WORDPRESS_DB_USER=lisi
......

root@wordpresspod:/var/www/html# exit
exit

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 -- bash

root@wordpresspod:/var/www/html# env | grep -i mysqlsvc
MYSQLSVC_SERVICE_HOST=10.104.58.98
MYSQLSVC_PORT_3306_TCP_PORT=3306
MYSQLSVC_PORT=tcp://10.104.58.98:3306
MYSQLSVC_PORT_3306_TCP_ADDR=10.104.58.98
MYSQLSVC_PORT_3306_TCP_PROTO=tcp
MYSQLSVC_SERVICE_PORT=3306
MYSQLSVC_PORT_3306_TCP=tcp://10.104.58.98:3306

root@wordpresspod:/var/www/html# exit
exit

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

[root@k8scloude1 ~]# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTOR
mysqlsvc       ClusterIP   10.104.58.98    <none>        3306/TCP       71m   run=mysqlpod
nginxsvc       ClusterIP   10.98.95.134    <none>        80/TCP         9h    app2=nginx2
wordpresssvc   NodePort    10.107.76.238   <none>        80:31860/TCP   57m   run=wordpresspod

[root@k8scloude1 ~]# kubectl get pod -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod       1/1     Running   0          74m   10.244.112.163   k8scloude2   <none>           <none>
wordpresspod   1/1     Running   0          61m   10.244.251.255   k8scloude3   <none>           <none>

删除wordpresspod

[root@k8scloude1 ~]# kubectl delete pod wordpresspod --force
warning: 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 wide
NAME       READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod   1/1     Running   0          75m   10.244.112.163   k8scloude2   <none>           <none>

修改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: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: wordpresspod
  name: wordpresspod
spec:
  #当需要关闭容器时,立即杀死容器而不等待默认的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: Always
status: {}

创建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 wide
NAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod       1/1     Running   0          79m   10.244.112.163   k8scloude2   <none>           <none>
wordpresspod   1/1     Running   0          6s    10.244.112.162   k8scloude2   <none>           <none>

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTOR
mysqlsvc       ClusterIP   10.104.58.98    <none>        3306/TCP       76m   run=mysqlpod
nginxsvc       ClusterIP   10.98.95.134    <none>        80/TCP         9h    app2=nginx2
wordpresssvc   NodePort    10.107.76.238   <none>        80:31860/TCP   62m   run=wordpresspod

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

  1. 只能获取相同namespace里的变量;
  2. 变量的获取有先后顺序,引用的变量必须要先创建。

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-system
NAME             TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                  AGE
kube-dns         ClusterIP   10.96.0.10    <none>        53/UDP,53/TCP,9153/TCP   32d
metrics-server   ClusterIP   10.97.8.134   <none>        443/TCP                  31d

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

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

[root@k8scloude1 svc]# kubectl get svc -n kube-system -o wide
NAME             TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                  AGE   SELECTOR
kube-dns         ClusterIP   10.96.0.10    <none>        53/UDP,53/TCP,9153/TCP   32d   k8s-app=kube-dns
metrics-server   ClusterIP   10.97.8.134   <none>        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-dns
NAMESPACE     NAME                       READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
kube-system   coredns-545d6fc579-7wm95   1/1     Running   21         32d   10.244.158.109   k8scloude1   <none>           <none>
kube-system   coredns-545d6fc579-87q8j   1/1     Running   21         32d   10.244.158.110   k8scloude1   <none>           <none>

删除svc,重新给wordpress创建svc

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE    SELECTOR
mysqlsvc       ClusterIP   10.104.58.98    <none>        3306/TCP       164m   run=mysqlpod
nginxsvc       ClusterIP   10.98.95.134    <none>        80/TCP         11h    app2=nginx2
wordpresssvc   NodePort    10.107.76.238   <none>        80:31860/TCP   151m   run=wordpresspod

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

[root@k8scloude1 ~]# kubectl get svc -o wide
NAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE   SELECTOR
mysqlsvc   ClusterIP   10.104.58.98   <none>        3306/TCP   15h   run=mysqlpod
nginxsvc   ClusterIP   10.98.95.134   <none>        80/TCP     24h   app2=nginx2

[root@k8scloude1 ~]# kubectl expose --name=wordpresssvc pod wordpresspod --port=80 --type=NodePort
service/wordpresssvc exposed

[root@k8scloude1 ~]# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE   SELECTOR
mysqlsvc       ClusterIP   10.104.58.98   <none>        3306/TCP       15h   run=mysqlpod
nginxsvc       ClusterIP   10.98.95.134   <none>        80/TCP         24h   app2=nginx2
wordpresssvc   NodePort    10.100.99.82   <none>        80:32729/TCP   9s    run=wordpresspod

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

[root@k8scloude1 svc]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: podtest
  name: podtest
spec:
  #当需要关闭容器时,立即杀死容器而不等待默认的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 wide
NAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod       1/1     Running   1          15h   10.244.112.168   k8scloude2   <none>           <none>
podtest        1/1     Running   0          9s    10.244.251.195   k8scloude3   <none>           <none>
wordpresspod   1/1     Running   1          14h   10.244.112.164   k8scloude2   <none>           <none>

修改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 wide
NAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE     SELECTOR
mysqlsvc       ClusterIP   10.104.58.98     <none>        3306/TCP       15h     run=mysqlpod
nginxsvc       ClusterIP   10.98.95.134     <none>        80/TCP         24h     app2=nginx2
podtestsvc     ClusterIP   10.108.102.183   <none>        80/TCP         7s      test=podtest
wordpresssvc   NodePort    10.100.99.82     <none>        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 -- bash
If you don't see a command prompt, try pressing enter.

#直接访问svc就可访问服务
root@clientpod:/# curl podtestsvc
111
root@clientpod:/# exit
exit
Session ended, resume using 'kubectl attach clientpod -c clientpod -i -t' command when the pod is running
pod "clientpod" deleted

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

[root@k8scloude1 svc]# kubectl run clientpod --image=nginx --image-pull-policy=IfNotPresent -it --rm -n default -- bash
If you don't see a command prompt, try pressing enter.

#因为是在default命名空间里访问svc命名空间里的服务,所以访问失败
root@clientpod:/# curl podtestsvc
curl: (6) Could not resolve host: podtestsvc

#需要指定svc命名空间
root@clientpod:/# curl podtestsvc.svc
111

#查看pod里DNS信息:nameserver 10.96.0.10对应的就是kube-dns的IP
root@clientpod:/# cat /etc/resolv.conf 
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

root@clientpod:/# exit
exit
Session ended, resume using 'kubectl attach clientpod -c clientpod -i -t' command when the pod is running
pod "clientpod" deleted

删除wordpresspod,重新创建。

[root@k8scloude1 svc]# kubectl delete pod wordpresspod --force
warning: 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 wide
NAME       READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod   1/1     Running   1          16h   10.244.112.168   k8scloude2   <none>           <none>
podtest    1/1     Running   0          10m   10.244.251.195   k8scloude3   <none>           <none>

修改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: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: wordpresspod
  name: wordpresspod
spec:
  #当需要关闭容器时,立即杀死容器而不等待默认的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: Always
status: {}

创建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 wide
NAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod       1/1     Running   1          16h   10.244.112.168   k8scloude2   <none>           <none>
wordpresspod   1/1     Running   0          10s   10.244.251.198   k8scloude3   <none>           <none>

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE     SELECTOR
mysqlsvc       ClusterIP   10.104.58.98    <none>        3306/TCP       16h     run=mysqlpod
nginxsvc       ClusterIP   10.98.95.134    <none>        80/TCP         24h     app2=nginx2
wordpresssvc   NodePort    10.109.31.167   <none>        80:32632/TCP   4m42s   run=wordpresspod

删除pod和svc

[root@k8scloude1 svc]# kubectl delete pod mysqlpod wordpresspod --force
warning: 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 deleted
pod "wordpresspod" force deleted

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

[root@k8scloude1 svc]# kubectl get pod -o wide
No resources found in svc namespace.

[root@k8scloude1 svc]# kubectl get svc -o wide
No 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是抽象的,不存在在哪个节点上运行。

除了使用NodePort,LoadBalancer进行服务的发布以外,还有一种更灵活,功能更多的发布方式,就是使用Ingress来发布Kubernetes服务,详情请查看博客《Kubernetes(k8s)使用ingress发布服务》。

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: v1
kind: Pod
metadata:
  labels:
    test: podtest
  name: podtest
spec:
  #当需要关闭容器时,立即杀死容器而不等待默认的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 wide
NAME      READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
podtest   1/1     Running   0          26s   10.244.112.169   k8scloude2   <none>           <none>

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

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR
podtestsvc   ClusterIP   10.100.92.123   <none>        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 wide
NAME         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE     SELECTOR
podtestsvc   NodePort   10.100.92.123   <none>        80:30908/TCP   3m39s   test=podtest

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

image-20230606115711553

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

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

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

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE     SELECTOR
podtestsvc   ClusterIP   10.100.92.123   <none>        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=NodePort
service/podtestsvc exposed

现在svc类型为NodePort

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME         TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE   SELECTOR
podtestsvc   NodePort   10.97.91.78   <none>        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/

image-20230606155144155

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

image-20230606155236641

创建metallb的namespace

[root@k8scloude1 svc]# kubectl create ns metallb-system
namespace/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]# ls
metallb.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 metallb
quay.io/metallb/speaker                              v0.11.0   896b796b12bb   3 months ago    50.2MB
quay.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 metallb
quay.io/metallb/speaker                              v0.11.0   896b796b12bb   3 months ago    50.2MB
quay.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 created
podsecuritypolicy.policy/speaker created
......
rolebinding.rbac.authorization.k8s.io/config-watcher created
rolebinding.rbac.authorization.k8s.io/pod-lister created
rolebinding.rbac.authorization.k8s.io/controller created
daemonset.apps/speaker created
deployment.apps/controller created

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


[root@k8scloude1 svc]# kubectl get pod -n metallb-system -o wide
NAME                          READY   STATUS    RESTARTS   AGE     IP                NODE         NOMINATED NODE   READINESS GATES
controller-7dcc8764f4-qdwl2   1/1     Running   0          2m41s   10.244.112.160    k8scloude2   <none>           <none>
speaker-892pm                 1/1     Running   0          2m41s   192.168.110.128   k8scloude3   <none>           <none>
speaker-jfccb                 1/1     Running   0          2m41s   192.168.110.130   k8scloude1   <none>           <none>
speaker-nkrgk                 1/1     Running   0          2m41s   192.168.110.129   k8scloude2   <none>           <none>

7.2.2 配置地址池

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

image-20230606155409311

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

[root@k8scloude1 svc]# vim ipaddrpool.yaml

[root@k8scloude1 svc]# cat ipaddrpool.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  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 wide
NAME               DATA   AGE
kube-root-ca.crt   1      35h

7.2.3 使用LoadBalancer的方式进行服务发布

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

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE    IP               NODE         NOMINATED NODE   READINESS GATES
podtest   1/1     Running   0          148m   10.244.112.169   k8scloude2   <none>           <none>

[root@k8scloude1 svc]# kubectl get svc -o wide
No resources found in svc namespace.

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

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

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

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

image-20230606155531665

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

[root@k8scloude1 svc]# kubectl expose --name=podtestsvc2 pod podtest --port=80 --type=LoadBalancer
service/podtestsvc2 exposed

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME          TYPE           CLUSTER-IP     EXTERNAL-IP       PORT(S)        AGE    SELECTOR
podtestsvc    LoadBalancer   10.97.238.10   192.168.110.188   80:30725/TCP   5m3s   test=podtest
podtestsvc2   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 podtestsvc2
service "podtestsvc" deleted
service "podtestsvc2" deleted

[root@k8scloude1 svc]# kubectl get svc -o wide
No resources found in svc namespace.

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE    IP               NODE         NOMINATED NODE   READINESS GATES
podtest   1/1     Running   0          159m   10.244.112.169   k8scloude2   <none>           <none>
posted @ 2023-06-06 16:38  人生的哲理  阅读(1350)  评论(1编辑  收藏  举报