k8s之Service

写在前面

本文接k8s之DaemonSet

通过Deployment我们可以实现一直有指定个数的POD在运行,而通过DaemonSet可以实现在每个Node上都有一个POD在运行,不管是这两种方式中的哪一种,都是仅仅实现了有若干个POD在运行的效果,但是还无法正常的对外提供访问,并且要支持负载均衡,服务发现(因为POD可能经常会有老的退出,新的创建的情况,所以必须具备自动的服务发现机制,即发现退出的POD失效,新创建的POD加入到负载均衡中),为了实现这个目的,k8s提供了Service API对象,其定义如下:

ongyunqi@mongodaddy:~/k8s$ kubectl api-resources | egrep -w 'Service|KIND'

NAME                              SHORTNAMES   APIVERSION                             NAMESPACED   KIND
services                          svc          v1                                     true         Service

简称svc。这样,Deployment,DaemonSet负责保证有一定数量的POD在运行,Service负责让这些POD以负载均衡的方式对外提供访问,各司其职,以POD们为中心来运转。下面我们就详细看下Service API对象的使用。

1:定义yaml

我们知道API对象,如POD,Job,CronJob等都是通过kubectl create命令来创建yaml模板的,但是Service API对象就比较特殊,需要通过kubectl expose,这点要注意下(其实我认为这样搞特殊化挺不好的,徒增了学习和使用的复杂度,当然设计者可能想突出其expose的功能吧!),如下:

export out="--dry-run=client -o yaml"
kubectl expose deploy ngx-dep-name --port=80 --target-port=80 $out

简单说明:

deploy ngx-dep-name:指定使用名称为ngx-dep-name的Deployment管理的POD
--port=80 --target-port=80 暴露在Service端口号和POD内部服务端口号

以上说明可以参考下图:

在这里插入图片描述

注意图例,是以Deployment生成和管理POD为例,但其实POD到底是怎么来的Service是不关心的,它只是按照指定的app label来找到POD并用之对外提供服务,仅此而已,即Service API对象只和POD API对象有关系。

我们生成的yaml模板如下:

dongyunqi@mongodaddy:~/k8s$ kubectl get deploy
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
ngx-dep-name   3/3     3            3           9m37s
dongyunqi@mongodaddy:~/k8s$ export out="--dry-run=client -o yaml" && kubectl expose deploy ngx-dep-name --port=80 --target-port=80 $out
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: ngx-dep-app
  name: ngx-dep-name
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: ngx-dep-pod
status:
  loadBalancer: {}

app: ngx-dep-pod可看到自动为我们生成了deployment管理的名称为ngx-dep-pod的POD。修改后如下:

apiVersion: v1
kind: Service
metadata:
  name: ngx-svc
  
spec:
  selector:
    app: ngx-dep-pod
    
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP

这里我们通过label选择器selector选择app为ngx-dep-pod的POD,也就是我们在前面文章已经定义好的POD,基于这些POD来提供负载均衡,服务发现的服务。因为nginx默认返回的信息无法看出负载均衡的效果,所以我们需要来修改其默认的配置文件,这里我们通过ConfigMap 来实现,首先定义configmap如下:

apiVersion: v1
kind: ConfigMap
metadata:
  name: ngx-conf

data:
  default.conf: |
    server {
      listen 80;
      location / {
        default_type text/plain;
        return 200
          'srv : $server_addr:$server_port\nhost: $hostname\nuri : $request_method $host $request_uri\ndate: $time_iso8601\n';
      }
    }

特别说明这里的data结构转换为json后如下:

{
  "default.conf": "server {\n  listen 80;\n  location / {\n    default_type text/plain;\n    return 200\n      'srv : $server_addr:$server_port\\nhost: $hostname\\nuri : $request_method $host $request_uri\\ndate: $time_iso8601\\n';\n  }\n}\n"
}

接下来我们应用configmap,如下:

dongyunqi@mongodaddy:~/k8s$ kubectl apply -f configmap.yml 
configmap/ngx-conf created
dongyunqi@mongodaddy:~/k8s$ kubectl get configmap | egrep 'ngx-conf|NAME'
NAME               DATA   AGE
ngx-conf           1      49s

然后我们修改Deloyment API对象,以Volumes存储卷的方式加载到nginx容器中去,修改后如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: ngx-dep-app
  name: ngx-dep-name

spec:
  replicas: 3
  selector:
    matchLabels:
      app: ngx-dep-pod

  template:
    metadata:
      labels:
        app: ngx-dep-pod
    spec:
      volumes:
      - name: ngx-conf-vol
        configMap:
          name: ngx-conf

      containers:
      - image: nginx:alpine
        name: nginx
        ports:
        - containerPort: 80

        volumeMounts:
        - mountPath: /etc/nginx/conf.d
          name: ngx-conf-vol

然后我们apply让配置生效,如下:

dongyunqi@mongodaddy:~/k8s$ kubectl apply -f deploy.yml 
...

完成后可以进入POD的NGINX容器中查看文件是否挂载进去,如下:

dongyunqi@mongodaddy:~/k8s$ kubectl get pod
NAME                           READY   STATUS    RESTARTS        AGE
ngx-dep-name-dcc8b7bfd-7lbrq   1/1     Running   0               61m
ngx-dep-name-dcc8b7bfd-9m2rs   1/1     Running   0               61m
ngx-dep-name-dcc8b7bfd-wp4zt   1/1     Running   0               61m
redis-ds-5jf5x                 1/1     Running   1 (5h17m ago)   41h
redis-ds-n8p45                 1/1     Running   1 (5h17m ago)   41h
dongyunqi@mongodaddy:~/k8s$ kubectl exec -it ngx-dep-name-dcc8b7bfd-7lbrq -- sh
/ # ls
bin                   docker-entrypoint.sh  lib                   opt                   run                   sys                   var
dev                   etc                   media                 proc                  sbin                  tmp
/etc/nginx/conf.d # cat default.conf 
server {
  listen 80;
  location / {
    default_type text/plain;
    return 200
      'srv : $server_addr:$server_port\nhost: $hostname\nuri : $request_method $host $request_uri\ndate: $time_iso8601\n';
  }
}
/etc/nginx/conf.d # pwd
/etc/nginx/conf.d
/etc/nginx/conf.d # cat /etc/nginx/conf.d/default.conf 
server {
  listen 80;
  location / {
    default_type text/plain;
    return 200
      'srv : $server_addr:$server_port\nhost: $hostname\nuri : $request_method $host $request_uri\ndate: $time_iso8601\n';
  }
}

可以看到已经成功挂载进去了。接着我们就可以创建Service了。

2:apply

再贴下service的yaml:

apiVersion: v1
kind: Service
metadata:
  name: ngx-svc
  
spec:
  selector:
    app: ngx-dep-pod # 查找app label为ngx-dep-pod的POD
    
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP

apply:

dongyunqi@mongodaddy:~/k8s$ kubectl apply -f service.yml 
service/ngx-svc created
dongyunqi@mongodaddy:~/k8s$ kubectl get service
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   3d18h
ngx-svc      ClusterIP   10.105.114.19   <none>        80/TCP    7s

可以看到service的IP地址是10.105.114.19,这是一个虚拟的静态IP。通过kubectl describe可以查看service所使用的POD信息:

dongyunqi@mongodaddy:~/k8s$ kubectl describe svc ngx-svc
Name:              ngx-svc
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=ngx-dep-pod
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.105.114.19
IPs:               10.105.114.19
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.10.1.19:80,10.10.1.20:80,10.10.1.21:80
Session Affinity:  None
Events:            <none>

Endpoints: 10.10.1.19:80,10.10.1.20:80,10.10.1.21:80就是所使用的POD IP,如下验证:

dongyunqi@mongodaddy:~/k8s$ kubectl get pod -l 'app=ngx-dep-pod' -o wide
NAME                           READY   STATUS    RESTARTS   AGE   IP           NODE         NOMINATED NODE   READINESS GATES
ngx-dep-name-dcc8b7bfd-7lbrq   1/1     Running   0          80m   10.10.1.20   mongomummy   <none>           <none>
ngx-dep-name-dcc8b7bfd-9m2rs   1/1     Running   0          80m   10.10.1.21   mongomummy   <none>           <none>
ngx-dep-name-dcc8b7bfd-wp4zt   1/1     Running   0          80m   10.10.1.19   mongomummy   <none>           <none>

是对得上的。

3:负载均衡测试

现在我们已经知道Service API对象实例的IP地址是10.105.114.19,而且映射的端口号是80,那么我们就可以了来测试负载均衡效果了,如下:

dongyunqi@mongodaddy:~/k8s$ curl http://10.105.114.19:80
srv : 10.10.1.19:80
host: ngx-dep-name-dcc8b7bfd-wp4zt
uri : GET 10.105.114.19 /
date: 2023-01-12T08:29:23+00:00
dongyunqi@mongodaddy:~/k8s$ curl http://10.105.114.19:80
srv : 10.10.1.20:80
host: ngx-dep-name-dcc8b7bfd-7lbrq
uri : GET 10.105.114.19 /
date: 2023-01-12T08:29:24+00:00
dongyunqi@mongodaddy:~/k8s$ curl http://10.105.114.19:80
srv : 10.10.1.19:80
host: ngx-dep-name-dcc8b7bfd-wp4zt
uri : GET 10.105.114.19 /
date: 2023-01-12T08:29:25+00:00

service负载均衡使用的是简单的round robin轮询算法。英 [ˈrɒbɪn] 。

然后我们测试下服务发现,先来看下当前的POD:

dongyunqi@mongodaddy:~/k8s$ kubectl get pod -l 'app=ngx-dep-pod' -o wide | awk '{print $1}'
NAME
ngx-dep-name-dcc8b7bfd-7lbrq
ngx-dep-name-dcc8b7bfd-9m2rs
ngx-dep-name-dcc8b7bfd-wp4zt

接着我们将PODngx-dep-name-dcc8b7bfd-7lbrq删除,如下:

dongyunqi@mongodaddy:~/k8s$ kubectl delete pod ngx-dep-name-dcc8b7bfd-7lbrq
pod "ngx-dep-name-dcc8b7bfd-7lbrq" deleted

然后查看是否新建POD:

dongyunqi@mongodaddy:~/k8s$ kubectl get pod -l 'app=ngx-dep-pod' -o wide | awk '{print $1}'
NAME
ngx-dep-name-dcc8b7bfd-9m2rs
ngx-dep-name-dcc8b7bfd-pzddf
ngx-dep-name-dcc8b7bfd-wp4zt

可以看到新建了PODngx-dep-name-dcc8b7bfd-pzddf,再来看下负载均衡是否能使用到该POD:

dongyunqi@mongodaddy:~/k8s$ curl 10.105.114.19
srv : 10.10.1.22:80
host: ngx-dep-name-dcc8b7bfd-pzddf
uri : GET 10.105.114.19 /
date: 2023-01-12T08:56:49+00:00

3.1:通过域名的方式访问

在看如何通过域名访问之前需要先看下什么是命名空间namespace,是一个逻辑上的概念,用来对API对象实例进行分组,每个API对象都会归属于某个命名空间,如果不显式指定则就是默认的default命名空间,如下查看所有的命名空间:

dongyunqi@mongodaddy:~/k8s$ kubectl get namespace
NAME              STATUS   AGE
default           Active   3d19h
kube-flannel      Active   3d5h
kube-node-lease   Active   3d19h
kube-public       Active   3d19h
kube-system       Active   3d19h

截止到现在我们定义的所有API对象都是没有显式指定命名空间的,所以都在default命名空间中。kube-system命名空间,像api-server,ectd等核心组件的POD都在该命名空间下。如下查看我们定义的Service API对象所在的命名空间:

dongyunqi@mongodaddy:~/k8s$ kubectl get service -A | egrep 'NAMESP|ngx-svc'| awk '{print $1}'
NAMESPACE
default

看完了命名空间的概念后就可以来看域名了,service在启动后会生成默认的域名,规则是对象.名字空间.svc.cluster.local,但很多时候也可以省略后面的部分,直接写“对象.名字空间”甚至“对象名”就足够了,默认会使用对象所在的名字空间(比如这里就是 default),如下使用域名测试:

在这里插入图片描述

只有集群内的POD才能使用,k8s的node无法访问。

3.2:对外暴露服务

想要对外暴露服务的话需要配置Service API对象的type属性,该值默认是ClusterIP,通过静态IP方式负载均衡,只允许内部访问,当配置为NodePort时,service会在Node节点上映射一个访问端口号,因为是映射到Node上,所以外部就可以访问了,如下增加type:

apiVersion: v1
...
spec:
  ...
  type: NodePort

完整如下:

apiVersion: v1
kind: Service
metadata:
  name: ngx-svc
  
spec:
  selector:
    app: ngx-dep-pod
  type: NodePort
    
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP

然后重新apply,如下:

dongyunqi@mongodaddy:~/k8s$ kubectl apply -f service.yml 
service/ngx-svc configured

此时service就会在Node启用一个映射端口,如下查看:

dongyunqi@mongodaddy:~/k8s$ kubectl get services ngx-svc
NAME      TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
ngx-svc   NodePort   10.105.114.19   <none>        80:30825/TCP   3h56m

其中80:30825/TCP是将service的80端口映射到Node的30825,之后我们就可以直接通过访问Node的30825端口来访问POD了,NODE到Service,Service到POD的映射关系如下图:

在这里插入图片描述

访问测试如下:

在这里插入图片描述

在这里插入图片描述

可以看到能够正常访问,并且负载均衡也是生效的。

写在后面

小结

本文看了基于Service来实现服务的负载和自动发现,并看了如何以域名的方式访问,如何对外暴露服务。希望本文能够帮助到你。

多知道一点

Kubernetes也为每个Pod分配了域名,形式是“IP 地址. 名字空间.pod.cluster.local”,但需要把 IP 地址里的. 改成 - 。比如地址 10.10.1.87,它对应的域名就是 10-10-1-87.default.pod。

参考文章列表

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值