一、为什么要有Service?

我们通过Deployment/StatefulSet/DaemonSet 创建的Pod的生命周期是短暂的,如果节点出现故障、容器内应用程序错误等原因,Pod随时会被销毁和重新创建,因为我们不能直接通过IP:PORT的方式来访问Pod。Pod类似于微服务,在SpringCloud微服务架构中,消费者并不是直接请求微服务,则是先请求注册中心来获取到可用的微服务列表,在k8s中的Service就类似于SpringCloud的注册中心,提供服务发现的功能。
k8s通过Service对一组Pod进行抽象,消费者只需要请求对应的Service即可访问到Pod,而不需要直接去访问Pod,此外Service起到了负载均衡的作用。

二、Service的简单使用

假设我们已经在k8s环境中创建了一个Deployment,该Deployment创建了2个Pod,具体配置如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

1. 定义一个Service

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

Service的kind配置为Service,selector配置的label需要匹配上Pod,见上面Deployment的label配置app=nginx,此外.spec.ports.port为Service对外暴露的端口,.spec.ports.targetPort为Pod的端口。

2. 创建Service

kubectl apply -f 文件名.yml

[root@k8s-master1 services]# kubectl apply -f 01-create-service.yml 
service/nginx-service created

注:修改和删除与Deployment、StatefulSet、DaemonSet类型,修改:kubectl replace -f 文件名.yml,删除:kubectl delete -f 文件名.yml

3. 查看Service

kubectl get service
或者 kubectl get svc

[root@k8s-master1 ~]# kubectl get service -owide
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE   SELECTOR
kubernetes      ClusterIP   10.96.0.1        <none>        443/TCP   8d    <none>
nginx-service   ClusterIP   10.100.208.173   <none>        80/TCP    21m   app=nginx
[root@k8s-master1 ~]# kubectl get svc -owide
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE   SELECTOR
kubernetes      ClusterIP   10.96.0.1        <none>        443/TCP   8d    <none>
nginx-service   ClusterIP   10.100.208.173   <none>        80/TCP    22m   app=nginx

查看配置文件:kubectl get service nginx-service -o yaml
或者 kubectl edit service nginx-service

[root@k8s-master1 ~]# kubectl get service nginx-service -o yaml
apiVersion: v1
kind: Service
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"nginx-service","namespace":"default"},"spec":{"ports":[{"port":80,"protocol":"TCP","targetPort":80}],"selector":{"app":"nginx"}}}
  creationTimestamp: "2022-12-22T03:09:09Z"
  name: nginx-service
  namespace: default
  resourceVersion: "361278"
  uid: 147678f2-f1df-47fb-b834-cd70a7b73ee5
spec:
  clusterIP: 10.100.208.173
  clusterIPs:
  - 10.100.208.173
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}
[root@k8s-master1 ~]# kubectl edit service nginx-service
Edit cancelled, no changes made.

查看Endpoints:kubectl get endpoints

[root@k8s-master1 ~]# kubectl get endpoints
NAME            ENDPOINTS                         AGE
kubernetes      192.168.253.110:6443              8d
nginx-service   172.16.36.65:80,172.16.36.70:80   26m

Endpoints定义了网络端点的列表,通常由Service引用,以定义可以将流量发送到哪些Pod。Endpoints的name与Service的name一致。

4. 简单测试

(1)可以通过Service的IP和端口进行访问Pod:curl http://10.100.208.173
(2)在Pod内部,可以直接通过Service的名称进行访问:curl http://nginx-service
(3)在Pod内部访问跨namespace的Service,需要指定namespace,格式为http://ServiceName.namespace,例如:
curl http://nginx-service.default

三、Service的类型

Service提供多种类型,可以通过.spec.type进行配置,默认情况下为ClusterIP,具体的类型有:

(1)ClusterIP
默认类型,通过集群内部的一个IP地址暴露Service,只能在集群内部进行访问。

(2)NodePort
通过每一个节点闪给的静态端口(NodePort)暴露Service,同时自动创建ClusterIP类型的访问方式。

  • 在集群内部通过ClusterIP:{ClusterIP}:{Port}访问
  • 在集群外部通过NodeIP:{NodeIP}:{NodePort}访问

image-1671693195461

比如我们按照了kubernetes dashboard,其Service就是采用NodePort的类型发布,我们可以在集群外部通过浏览器访问dashboard页面。

另外NodePort的端口范围是30000-32767,可以通过cat /usr/lib/systemd/system/kube-apiserver.service 进行查看。

[root@k8s-master1 ~]# cat /usr/lib/systemd/system/kube-apiserver.service 
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
After=network.target

[Service]
ExecStart=/usr/local/bin/kube-apiserver \
      --v=2  \
      --logtostderr=true  \
      --allow-privileged=true  \
      --bind-address=0.0.0.0  \
      --secure-port=6443  \
      --insecure-port=0  \
      --advertise-address=192.168.253.110 \
      --service-cluster-ip-range=10.96.0.0/12  \
      --service-node-port-range=30000-32767  \
      --etcd-servers=https://192.168.253.110:2379 \
      --etcd-cafile=/etc/etcd/ssl/etcd-ca.pem  \
      --etcd-certfile=/etc/etcd/ssl/etcd.pem  \
      --etcd-keyfile=/etc/etcd/ssl/etcd-key.pem  \
      --client-ca-file=/etc/kubernetes/pki/ca.pem  \
      --tls-cert-file=/etc/kubernetes/pki/apiserver.pem  \
      --tls-private-key-file=/etc/kubernetes/pki/apiserver-key.pem  \
      --kubelet-client-certificate=/etc/kubernetes/pki/apiserver.pem  \
      --kubelet-client-key=/etc/kubernetes/pki/apiserver-key.pem  \
      --service-account-key-file=/etc/kubernetes/pki/sa.pub  \
      --service-account-signing-key-file=/etc/kubernetes/pki/sa.key  \
      --service-account-issuer=https://kubernetes.default.svc.cluster.local \
      --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname  \
      --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota  \
      --authorization-mode=Node,RBAC  \
      --enable-bootstrap-token-auth=true  \
      --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.pem  \
      --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.pem  \
      --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client-key.pem  \
      --requestheader-allowed-names=aggregator  \
      --requestheader-group-headers=X-Remote-Group  \
      --requestheader-extra-headers-prefix=X-Remote-Extra-  \
      --requestheader-username-headers=X-Remote-User
      # --token-auth-file=/etc/kubernetes/token.csv

Restart=on-failure
RestartSec=10s
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target
[root@k8s-master1 ~]# 

(3)LoadBalancer
通过云服务供应商的负载均衡器在集群外部暴露Service,同时自动创建NodePort和ClusterIP类型的访问方式。

  • 在集群内部通过ClusterIP:{ClusterIP}:{Port}访问
  • 在集群外部通过NodeIP:{NodeIP}:{NodePort}访问
  • 在集群外部通过LoadBalancerIP:{LoadBalancerIP}:{Port}访问

(4)ExternalName:
将Service映射到externalName指定的地址,例如:www.baidu.com,返回值是一个CNAME记录。

四、使用Service代理k8s外部服务

当我们有一些应用系统没有在kubernetes环境部署,或者我们的平台正在分批次迁移到kubernetes,那么在kubernetes环境中的Pod如何访问到外部的服务呢?

(1)定义一个Service

apiVersion: v1
kind: Service
metadata:
  name: nginx-external-service
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

(2)定义一个Endpoints

apiVersion: v1
kind: Endpoints
metadata:
  name: nginx-external-service
subsets:
- addresses:
  - ip: 172.16.36.65
  - ip: 172.16.36.70
  ports:
  - port: 80
    protocol: TCP

注意:Endpoints的name必须与Service的name一致,这样kubernetes会自动把Endpoints绑定到Service中,另外subsets.ip列表配置的是外部服务的IP。

(3)测试

[root@k8s-master1 services]# kubectl get ep
NAME                     ENDPOINTS                         AGE
kubernetes               192.168.253.110:6443              8d
nginx-external-service   172.16.36.65:80,172.16.36.70:80   3s
nginx-service            172.16.36.65:80,172.16.36.70:80   3h56m
nginx-service-external   172.16.36.65:80,172.16.36.70:80   108s
[root@k8s-master1 services]# kubectl get service
NAME                     TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes               ClusterIP   10.96.0.1        <none>        443/TCP   8d
nginx-external-service   ClusterIP   10.99.156.71     <none>        80/TCP    12m
nginx-service            ClusterIP   10.100.208.173   <none>        80/TCP    3h56m
[root@k8s-master1 services]# 
[root@k8s-master1 services]# curl http://10.99.156.71
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<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>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@k8s-master1 services]# 

通过kubectl get service查看Service的ClusterIP为10.99.156.71 ,然后通过curl http://10.99.156.71可以访问到nginx

打赏
支付宝 微信
上一篇 下一篇