service暴露端口的方式和代理方式

service暴露端口的方式和代理方式

service 概念

SVC 通过 Label Selector 标签选择的方式,匹配一组 Pod,对外访问服务。每一个 SVC可以理解成为一个微服务。

service 能够提供负载均衡的能力,但是在使用上有以下限制:

只提供4层负载均衡能力(只有 RR 轮询算法),而没有7层功能,如果需要更多的匹配规则来转发请求,4层上的负载均衡是不支持的。

service 类型

Clusterip:默认类型,自动分配一个仅 Cluster 内部可以访问的 虚拟IP,一般用作集群内部负载均衡。

NodePort(service向外暴露):在ClusterIP 基础上为 Service 在每台机器上绑定一个映射端口,外网客户端可以通过 NodeIP,Nodeport访问。

LoadBalancer(service向外暴露):在 NodePort 基础上,借助 cloud provider 创建一个外部负载均衡器,并将请求转发到 NodeIP 和 NodePort

ExternalName:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,只有1.7之后版本的 kube-dns支持。

SVC 访问流程组件

首先 apiserver 监听 kube-proxy 去进行服务和端口的发现。

通过kube-proxy监控,kube-proxy监控所有 Pod 节点信息,标签、IP、port 等,并负责把它们写入到 iptables 规则当中。

client 访问 SVC,其实访问的是 iptables规则。再由 iptables 导向后端 Pod 节点。

ipvs,图片上没有,现在的ClusterIP,NodePort 都是采取 ipvs 调度算法对后端 Pod 节点进行调度访问。

ipvs 代理模式

ipvs (IP Virtual Server) 实现了传输层负载均衡,也就是我们常说的4层LAN交换,作为 Linux 内核的一部分。ipvs运行在主机上,在真实服务器集群前充当负载均衡器。ipvs可以将基于TCP和UDP的服务请求转发到真实服务器上,并使真实服务器的服务在单个 IP 地址上显示为虚拟服务。

ipvs 对比 iptables 我们知道kube-proxy支持 iptables 和 ipvs 两种模式, 在kubernetes v1.8 中引入了 ipvs 模式,在 v1.9 中处于 beta 阶段,在 v1.11 中已经正式可用了。iptables 模式在 v1.1 中就添加支持了,从 v1.2 版本开始 iptables 就是 kube-proxy 默认的操作模式,ipvs 和 iptables 都是基于netfilter的,那么 ipvs 模式和 iptables 模式之间有哪些差异呢?

  • ipvs 为大型集群提供了更好的可扩展性和性能
  • ipvs 支持比 iptables 更复杂的复制均衡算法(最小负载、最少连接、加权等等)
  • ipvs 支持服务器健康检查和连接重试等功能

ipvs为负载均衡提供算法:

  • rr:轮询带哦都
  • lc:最小连接数
  • dh:目标地址哈希
  • sh:源地址哈希
  • sed:最短期望延迟
  • nq:不排队调度

client Pod 访问 Server Pod

  • 首先,service IP 的 iptables代理变成了 ipvs 模块,实现负载均衡和流量导向。
  • client 访问到 IPvs 服务,将流量分发到不同的 Pod 上运行。

kubernetes暴露端口的方式

集群内部实现访问:Clusterip

Clusterip是集群内部的私有ip,在集群内部访问服务非常方便,也是kuberentes集群默认的方式,直接通过service的Clusterip访问,也可以直接通过ServiceName访问。集群外部则是无法访问的。

默认类型,自动分配一个仅Cluster内部能够访问的虚拟IP

[root@master ~]# cat cluster.yml 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: apache
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: apache
  template: 
    metadata:
      labels:
        app: apache 
    spec:
      containers:
      - image: bravealove1/apache:v1.0 
        imagePullPolicy: IfNotPresent
        name: apache

---
apiVersion: v1
kind: Service
metadata:
  name: apache
  namespace: default
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: apache
  type: ClusterIP  #指定网络模式

[root@master ~]# kubectl  apply -f cluster.yml 
deployment.apps/apache created
service/apache created


[root@master ~]# kubectl  get pods,svc
NAME                          READY   STATUS    RESTARTS   AGE
pod/apache-599bc546b8-xp5rg   1/1     Running   0          12s

NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
service/apache       ClusterIP   10.98.249.13   <none>        80/TCP    12s
service/kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   4d12h


[root@master ~]# curl 10.98.249.13
hello,this is a test page 1 

集群外部方式访问:NodePort

NodePort在kubenretes里是一个早期广泛应用的服务暴露方式。Kubernetes中的service默认情况下都是使用的ClusterIP这种类型,这样的service会产生一个ClusterIP,这个IP只能在集群内部访问,要想让外部能够直接访问service,需要将service type修改为 nodePort。将service监听端口映射到node节点。

nodePort的原理在于在node上开了一个端口,将向该端口的流量导入到kube-proxy,然后由 kube-proxy进一步到给对应的pod

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: apache
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: apache
  template: 
    metadata:
      labels:
        app: apache 
    spec:
      containers:
      - image: aimmi/apache:v1.0 
        imagePullPolicy: IfNotPresent
        name: apache

---
apiVersion: v1
kind: Service
metadata:
  name: apache
  namespace: default
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 30000   指定对外端口
  selector:
    app: apache
  type: NodePort   #指定网络模式


[root@master ~]# kubectl  apply -f nodeport.yml 
deployment.apps/apache created
service/apache created
[root@master ~]# kubectl get pods,svc
NAME                          READY   STATUS    RESTARTS   AGE
pod/apache-599bc546b8-w6xnd   1/1     Running   0          10s

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
service/apache       NodePort    10.96.90.92   <none>        80:30000/TCP   10s
service/kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP        4d12h
[root@master ~]# curl 192.168.145.188:30000
hello,this is a test page 1 

DNS解析

Service

  • 创建普通service 会以my-svc.my-namespace.svc.cluster.local 的形式指派一个 DNS A 记录,并解析到该service的Cluster IP。
  • 创建“Headless” Service(没有Cluster IP)也会以 my-svc.my-namespace.svc.cluster.local 的形式被指派一个 DNS A 记录,但是并不会解析到的Cluster IP,而是解析到一组被选中的- - pod 的IP,如果没有backend则不做处理。

Pod

  • 创建Pod 会以 pod-ip-address.my-namespace.pod.cluster.local 这种形式被指派一个 DNS A 记录。

案例

[root@master ~]# cat deploy.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
   matchLabels:
     app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80


参数--record可以记录当前版本的Deployment都执行过哪些命令
[root@master ~]# kubectl create -f deploy.yml  --record
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/nginx-deployment created


创建完成后立即执行get命令查看这个Deployment
[root@master ~]# kubectl get deployments
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           2m14s
[root@master ~]# kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-74d589986c-kxcvx   1/1     Running   0          2m11s
nginx-deployment-74d589986c-s277p   1/1     Running   0          2m11s
nginx-deployment-74d589986c-zlf8v   1/1     Running   0          2m11s

使用 nginx:1.9.1 的镜像来代替原来的 nginx的镜像
[root@master ~]# kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
deployment.apps/nginx-deployment image updated

查看更新进度
[root@master ~]# kubectl rollout status deployment/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out

查看镜像信息
[root@master ~]# kubectl describe deployment/nginx-deployment
Name:                   nginx-deployment
Namespace:              default
CreationTimestamp:      Fri, 24 Dec 2021 22:24:10 +0800
Labels:                 <none>
Annotations:            deployment.kubernetes.io/revision: 4
                        kubernetes.io/change-cause: kubectl create --filename=deploy.yml --record=true
Selector:               app=nginx
Replicas:               3 desired | 3 updated | 4 total | 3 available | 1 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=nginx
  Containers:
   nginx:
    Image:        nginx:1.9.1
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>


使用rollout history命令查看Deployment的版本(revision)
[root@master ~]# kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
1         kubectl create --filename=deploy.yml --record=true
2         kubectl create --filename=deploy.yml --record=true

使用rollout undo命令回滚到前一个revision
[root@master ~]# kubectl rollout undo deployment/nginx-deployment
deployment.apps/nginx-deployment rolled back


查看镜像信息
[root@master ~]# kubectl describe deployment/nginx-deployment
Name:                   nginx-deployment
Namespace:              default
CreationTimestamp:      Fri, 24 Dec 2021 22:24:10 +0800
Labels:                 <none>
Annotations:            deployment.kubernetes.io/revision: 3
                        kubernetes.io/change-cause: kubectl create --filename=deploy.yml --record=true
Selector:               app=nginx
Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=nginx
  Containers:
   nginx:
    Image:        nginx
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>

给一个应用扩容副本数为3
[root@master ~]# kubectl  apply -f cluster.yml 
deployment.apps/apache created

[root@master ~]# kubectl  get pods
NAME                          READY   STATUS    RESTARTS   AGE
pod/apache-599bc546b8-6tctl   1/1     Running   0          28s


[root@master ~]# kubectl scale  deployment apache --replicas 4
deployment.apps/apache scaled
[root@master ~]# kubectl  get pods
NAME                          READY   STATUS              RESTARTS   AGE
pod/apache-599bc546b8-6gx4p   0/1     ContainerCreating   0          2s
pod/apache-599bc546b8-6tctl   1/1     Running             0          2m3s
pod/apache-599bc546b8-8qzr4   0/1     ContainerCreating   0          2s
pod/apache-599bc546b8-j48v5   0/1     ContainerCreating   0          2s

创建一个pod,其中运行着nginx、redis、memcached 3个容器
[root@master ~]# vim pod.yml 
---
apiVersion: v1
kind: Pod
metadata:
  name: hellok8s
  namespace: default
  labels:
    app: myapp
spec:
  containers:
  - name: mynginx
    image: nginx 
    ports:
    - containerPort: 80
  - name: myredis
    image: redis
    ports:
    - containerPort: 6379
  - name: memcached
    image: memcached 

[root@master ~]# kubectl apply -f pod.yml 
pod/hellok8s created


[root@master ~]# kubectl  get pods
NAME       READY   STATUS    RESTARTS   AGE
hellok8s   3/3     Running   0          2m49s

给一个pod创建service,并可以通过ClusterlP/NodePort访问
[root@master ~]# vi nodeport.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: apache
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: apache
  template: 
    metadata:
      labels:
        app: apache 
    spec:
      containers:
      - image: bravealove1/apache:v1.0 
        imagePullPolicy: IfNotPresent
        name: apache

---
apiVersion: v1
kind: Service
metadata:
  name: apache
  namespace: default
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 30000   指定对外端口
  selector:
    app: apache
  type: NodePort   指定网络模式


[root@master ~]# kubectl  apply -f nodeport.yml 
deployment.apps/apache created
service/apache created
[root@master ~]# kubectl get pods,svc
NAME                          READY   STATUS    RESTARTS   AGE
pod/apache-599bc546b8-w6xnd   1/1     Running   0          10s

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
service/apache       NodePort    10.96.90.92   <none>        80:30000/TCP   10s
service/kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP        4d12h
[root@master ~]# curl 192.168.145.188:30000
hello,this is a test page 1 

创建deployment和service,使用busybox容器nslookup解析service
[root@master ~]# cat host.yml 
---
apiVersion: apps/v1 
kind: Deployment 
metadata: 
  name: myapp-deploy 
  namespace: default 
spec: 
  replicas: 1
  selector: 
    matchLabels: 
      app: myapp 
  template:
    metadata: 
      labels: 
        app: myapp 
    spec: 
      containers: 
      - name: myapp
        image: httpd
        imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata: 
  name: myapp-externalname
  namespace: default
spec: 
  type: ExternalName 
  externalName: web.test.example.com


部署
[root@master ~]# kubectl apply -f host.yml 
deployment.apps/myapp-deploy created
service/apache created
[root@master ~]# kubectl  get pods
NAME                           READY   STATUS    RESTARTS   AGE
myapp-deploy-55bd85c8b-9jgf2   1/1     Running   0          107s

查看pods,service状态
[root@master ~]# kubectl  get pods,svc
NAME                               READY   STATUS    RESTARTS   AGE
pod/myapp-deploy-55bd85c8b-9jgf2   1/1     Running   0          18m

NAME                         TYPE           CLUSTER-IP   EXTERNAL-IP            PORT(S)   AGE
service/kubernetes           ClusterIP      10.96.0.1    <none>                 443/TCP   4d14h
service/myapp-externalname   ExternalName   <none>       web.test.example.com   <none>    3m35s


[root@master ~]# vibusybox.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: busybox-pod
  name: test-busybox
spec:
  containers:
  - command:
    - sleep
    - "3600"
    image: busybox
    imagePullPolicy: Always
    name: test-busybox

部署
[root@master ~]# kubectl apply -f busybox.yaml 
pod/test-busybox created

查看pod状态
[root@master ~]# kubectl  get pods,svc
NAME                               READY   STATUS    RESTARTS   AGE
pod/myapp-deploy-55bd85c8b-9jgf2   1/1     Running   0          19m
pod/test-busybox                   1/1     Running   0          8m15s

NAME                         TYPE           CLUSTER-IP   EXTERNAL-IP            PORT(S)   AGE
service/kubernetes           ClusterIP      10.96.0.1    <none>                 443/TCP   4d14h
service/myapp-externalname   ExternalName   <none>       web.test.example.com   <none>    4m49s

使用exec -it 与busybox进行交互
[root@master ~]# kubectl exec -it test-busybox /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # nslookup myapp-externalname.default.svc.cluster.local
Server:         10.96.0.10
Address:        10.96.0.10:53

myapp-externalname.default.svc.cluster.local    canonical name = web.test.example.com
上一篇:2021-11-05


下一篇:《SQL必知必会》拾遗 原创 Django Java工程师成长日记