• 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 >
    
    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:       >
    Selector:          app2=nginx2
    Type:              ClusterIP
    IP Family Policy:  SingleStack
    IP Families:       IPv4
    IP:                10.98.95.134
    IPs:               10.98.95.134
    Port:              >  80/TCP
    TargetPort:        80/TCP
    Endpoints:         10.244.112.157:80,10.244.112.159:80
    Session Affinity:  None
    Events:            >
    
    [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   >           >
    nginx-75b9846bd7-m2pdq   1/1     Running   0          57m   10.244.112.159   k8scloude2   >           >
    

    把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:       >
    Selector:          app2=nginx2
    Type:              ClusterIP
    IP Family Policy:  SingleStack
    IP Families:       IPv4
    IP:                10.98.95.134
    IPs:               10.98.95.134
    Port:              >  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:            >
    

    把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:       >
    Selector:          app2=nginx2
    Type:              ClusterIP
    IP Family Policy:  SingleStack
    IP Families:       IPv4
    IP:                10.98.95.134
    IPs:               10.98.95.134
    Port:              >  80/TCP
    TargetPort:        80/TCP
    Endpoints:         10.244.112.157:80,10.244.251.248:80
    Session Affinity:  None
    Events:            >
    

    现在手动生成一个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:       >
    Selector:          app2=nginx2
    Type:              ClusterIP
    IP Family Policy:  SingleStack
    IP Families:       IPv4
    IP:                10.98.95.134
    IPs:               10.98.95.134
    Port:              >  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:            >
    

    删除手动创建的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>
    
  • 相关阅读:
    《低代码指南》——维格云锦囊简介
    Dubbo 3.x源码(10)—Dubbo初始化导出/引用模块配置源码
    终于更新了!时隔一年niushop多商户b2b2c的新补丁v5.0.2终于发布了,一起看看有啥新变化
    gradle-7.6.3-all 快速下载百度网盘下载
    前端面试基础面试题——10
    解码Transformer:自注意力机制与编解码器机制详述与代码实现
    0基础学习区块链技术——入门
    ASM字节码插桩:打印方法名、入参、返回值、方法耗时
    spring注解驱动系列--声明式事务
    CHAPTER 4: DESIGN A RATE LIMITER
  • 原文地址:https://www.cnblogs.com/renshengdezheli/p/17460981.html