Kubernetes-Service实现

Service 类型

对于Kubernetes 可以实现内部服务的自由通信,也可以将平台内部的服务发布到外部环境 Service主要有四种类型,实现不同的网络通信功能,参考文档

复制代码
https://kubernetes.io/docs/concepts/services-networking/service/#publishingservices-service-types
类型 解析
ClusterIP 此为Service的默认类型,为集群内部的客户端访问,包括节点和Pod等,外部网络无法访问,In client --> clusterIP: ServicePort (Service) --> PodIP: PodPort
NodePort 本质上在ClusterIP模式基础上,再多加了一层端口映射的封装,相当于增强版的 ClusterIP 通过NodeIP:NodePort对外部网络提供服务,默认随机端口范围 30000~32767, 可指定为固定端口,NodePort是一个随机的端口,以防止端口冲突,在所有安装kube-proxy的节点上都会打开此相同的端口,可通过访问ClusterIP实现集群内部访问,也可以通过NodeIP:NortPort的方式实 现从集群外部至内部的访问 Ex Client --> NodeIP:NodePort (Service) --> PodIP:PodPort
LoadBalancer 基于NodePort基础之上,使用集群外部的运营商负载均衡器方式实现对外提供 服务,增强版的NodePort 基于云运营商IaaS云创建一个Kubernetes云,云平台也支持LBaaS(Load Balance as a Service)产品服务 Master 借助cloud-manager向LBaaS的API请求动态创建软件LB,即支持和Kubernetes API Server 进行交互 如果没有云服务,将无法获取EXTERNAL-IP,显示Pending状态,则降级为 NodePort类型 Ex Client --> LB_IP:LB_PORT --> NodeIP:NodePort(Service)--> PodIP:PodPort
ExternalName 当Kubernetes集群需要访问集群外部服务时,需要通过externalName将外部 主机引入到集群内部 外部主机名以 DNS方式解析为一个 CNAME记录给Kubernetes集群的其他主机 来使用 这种Service既没有ClusterIP,也没有NodePort.而且依赖于内部的CoreDNS功能In client -->Cluster ServiceName --> CName --> External Service Name 本方式的service没有selector,所以也不会创建同名的Endpoints资源对象 示例: Service名称:MySQL服务内部域名 mysql.default.svc.cluster.local MySQL服务外部域名:mysql.example.org In Client --> mysql.default.svc.cluster.local --> mysql.example.org --> 集群外的 MYSQL IP

1.ClusterIP Service 实现

1.1.查看集群内默认 Service

复制代码
#在集群内kubeapi对应的SVC默认占用Service 网络的第一个IP
root@master01:~# kubectl get svc kubernetes 
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   3d16h
​
#DNS对应的SVc,默认占用Service网络的第10个IP
root@master01:~# 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   3d17h

1.2.创建Deployment

复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myweb
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myweb
  template:
    metadata:
      labels:
        app: myweb
    spec:
      containers:
      - name: nginx
        image: harbor.apotos.com/nginx/nginx-podip:latest
        ports:
        - containerPort: 80
复制代码
root@master01:~/kubernetes-cni# kubectl get nodes
NAME       STATUS   ROLES           AGE     VERSION
master01   Ready    control-plane   3d18h   v1.32.12
node01     Ready    <none>          3d18h   v1.32.12
node02     Ready    <none>          3d18h   v1.32.12
root@master01:~/kubernetes-cni# 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   3d18h
root@master01:~/kubernetes-cni# kubectl apply -f myweb-deploy.yaml 
deployment.apps/myweb created
root@master01:~/kubernetes-cni# kubectl get pod -l app=myweb
NAME                     READY   STATUS    RESTARTS   AGE
myweb-7d756bcd87-chbsv   1/1     Running   0          29s
myweb-7d756bcd87-kcbz7   1/1     Running   0          29s
myweb-7d756bcd87-pn27p   1/1     Running   0          29s

1.3.创建service-ClusterIP

复制代码
kind: Service
apiVersion: v1
metadata:
  name: myweb
spec:
  # type: ClusterIP  # 默认即为ClusterIP,此行可省略
  # clusterIP: 192.168.64.100  # 可以手动指定IP,但一般都是系统自动指定而无需添加此行
  selector:
    app: myweb  # 引用上面deployment的名称,同时也是Pod的Label中app的值,实现service代理指定Pod的功能
    # version: v1.0  # 可以添加多个label与关系,即只过滤出有此处label匹配的pod,而非deployment的名称
  ports:
    - name: http
      protocol: TCP
      port: 80  # Service的端口
      targetPort: 80  # 后端Pod对应的端口
复制代码
root@master01:~/kubernetes-cni# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP   3d18h
myweb        ClusterIP   10.111.115.235   <none>        80/TCP    3m38s

service会自动创建同名的endpoint

复制代码
root@master01:~/kubernetes-cni# kubectl get endpoints
NAME         ENDPOINTS                                              AGE
kubernetes   192.168.48.100:6443                                    3d18h
myweb        172.16.140.85:80,172.16.196.149:80,172.16.196.150:80   6m1s

ENDPOINTS对应了deployment的三个pod。

复制代码
root@master01:~/kubernetes-cni# kubectl get pod -l app=myweb -o wide 
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE     NOMINATED NODE   READINESS GATES
myweb-7d756bcd87-chbsv   1/1     Running   0          25m   172.16.196.149   node01   <none>           <none>
myweb-7d756bcd87-kcbz7   1/1     Running   0          25m   172.16.140.85    node02   <none>           <none>
myweb-7d756bcd87-pn27p   1/1     Running   0          25m   172.16.196.150   node01   <none>           <none>

1.4.访问service

宿主机上使用ClusterIP访问

复制代码
root@master01:~/kubernetes-cni# curl 10.111.115.235
pod ip: 172.16.196.149
root@master01:~/kubernetes-cni# curl 10.111.115.235
pod ip: 172.16.140.85
root@master01:~/kubernetes-cni# curl 10.111.115.235
pod ip: 172.16.196.150

宿主机上使用PodIP访问

复制代码
root@master01:~/kubernetes-cni# curl 172.16.196.149
pod ip: 172.16.196.149
root@master01:~/kubernetes-cni# curl 172.16.140.85
pod ip: 172.16.140.85
root@master01:~/kubernetes-cni# curl 172.16.196.150
pod ip: 172.16.196.150

宿主机上使用svc的域名访问

复制代码
root@master01:~/kubernetes-cni# curl http://myweb.default.svc.cluster.local
curl: (6) Could not resolve host: myweb.default.svc.cluster.local

集群内的Pod使用svc的域名访问

创建用于测试的pod:

复制代码
root@master01:~/kubernetes-cni# cat network-tools-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: network-tools
  labels:
    app: network-tools
spec:
  containers:
  - name: tools
    image: harbor.apotos.com/network-tools/network-tools:latest
    imagePullPolicy: IfNotPresent  # 镜像拉取策略:如果本地不存在则拉取
    command: ["/bin/sh", "-c"]
    args: ["tail -f /dev/null"]  # 保持容器运行
  restartPolicy: Always

集群内的Pod使用svc的域名访问

复制代码
root@master01:~/kubernetes-cni# kubectl exec -it network-tools -- curl myweb.default.svc.cluster.local
pod ip: 172.16.196.150
root@master01:~/kubernetes-cni# kubectl exec -it network-tools -- curl myweb.default.svc.cluster.local
pod ip: 172.16.196.149
root@master01:~/kubernetes-cni# kubectl exec -it network-tools -- curl myweb.default.svc.cluster.local
pod ip: 172.16.140.85

发现宿主机上使用svc的域名访问报错:Could not resolve host: myweb.default.svc.cluster.local

因为是在节点宿主机(master01)上直接 curl,宿主机默认不走 K8s 的集群 DNS(CoreDNS),而是走我们自己配置的DNS服务器,比如谷歌,阿里的dns服务器,所以curl myweb宿主机 DNS 解析不到 myweb(这是 Pod 内才默认能解析的短域名)

在宿主机上访问 ClusterIP 用这个就行:

复制代码
curl -I http://10.111.115.235
curl http://10.111.115.235

在集群内(Pod 里)按服务名访问用这个域名:

复制代码
curl http://myweb.default.svc.cluster.local

1.5.查看ipvs规则

复制代码
root@master01:~/kubernetes-cni# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn        
TCP  10.111.115.235:80 rr
  -> 172.16.140.85:80             Masq    1      0          0         
  -> 172.16.196.149:80            Masq    1      0          0         
  -> 172.16.196.150:80            Masq    1      0          0   

可以看到ipvs的规则表中都有相关的负载均衡规则,访问10.111.115.235:80会按轮询(rr)的负载均衡策略转发到后端的172.16.140.85:80,172.16.196.149:80,172.16.196.150:80。

2.NodePort Service 实现

NodePort会在所有节点主机上,向外暴露一个指定或者随机的端口,供集群外部的应用能够访问 Kubernetes集群内部的Pod资源。 注意:nodePort 属性范围为 30000-32767,且type 类型只支持 NodePort或LoadBalancer 注意: 此方式有安全风险,端口为非标端口,而且性能一般,生产一般较少使用 生产中建议使用Ingress方式向外暴露集群内的服务

为了方便识别,将web改为web-clusterip,web-nodeport......

2.1.创建service-NodePort

复制代码
apiVersion: v1
kind: Service
metadata:
  name: myweb-nodeport
spec:
  type: NodePort
  selector:
    app: myweb
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30066

2.2.查看service

复制代码
root@master01:~/kubernetes-cni# kubectl get svc
NAME              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes        ClusterIP   10.96.0.1       <none>        443/TCP        3d20h
myweb-clusterip   ClusterIP   10.96.250.54    <none>        80/TCP         56s
myweb-nodeport    NodePort    10.103.29.129   <none>        80:30066/TCP   6s

2.3.访问service

复制代码
#宿主机上使用nodeip:nodeport访问
root@master01:~/kubernetes-cni# curl 192.168.48.100:30066
pod ip: 172.16.140.85
root@master01:~/kubernetes-cni# curl 192.168.48.101:30066
pod ip: 172.16.196.150
root@master01:~/kubernetes-cni# curl 192.168.48.102:30066
pod ip: 172.16.196.149

其他的Clusterip可行的访问方式,nodeport类型的service也可以访问

复制代码
root@master01:~/kubernetes-cni# curl 10.111.115.235
pod ip: 172.16.196.149
root@master01:~/kubernetes-cni#  curl 172.16.196.149
pod ip: 172.16.196.149
root@master01:~/kubernetes-cni# kubectl exec -it network-tools -- curl myweb-clusterip.default.svc.cluster.local
pod ip: 172.16.196.150
root@master01:~/kubernetes-cni# kubectl exec -it network-tools -- curl myweb-nodeport.default.svc.cluster.local
pod ip: 172.16.196.150

2.4.查看ipvs规则

复制代码
root@master01:~/kubernetes-cni# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.241.64:30066 rr
  -> 172.16.140.85:80             Masq    1      0          0         
  -> 172.16.196.149:80            Masq    1      0          0         
  -> 172.16.196.150:80            Masq    1      0          0  

3.LoadBalancer Service 实现

只有Kubernetes集群是部署在一个LBaaS平台上且指供有一个集群外部的LB才适合使用LoadBalancer 一般的公有云都提供了此功能,但可能会有费用产生 如果在一个非公用云的普通的Kubernetes集群上,创建了一个LoadBalancer类型的Service,一般情况 默认环境中是没有LBaaS的,所以会导致由于找不到指定的服务,状态会一直处于 Pending 状态 如果在私有云环境中使用 LoadBalancer Service,可以使用云原生的开源项目实现负载均衡器,比如 OpenELB, MetalLB 实现 Loadbalancer 可以获取用户访问的Service对应的Pod在哪个节点上,因此支持externaltrafficpolicy为 Local模式的流量转发

这里使用MetalLB

安装说明

复制代码
https://metallb.universe.tf/installation/
https://metallb.io/installation/

如果 kube-proxy工作于ipvs模式,必须使用严格ARP(StrictARP)模式,因此若有必要,先运行如下 命令,配置kube-proxy。

复制代码
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl apply -f - -n kube-system

部署MetalLB至Kubernetes集群

复制代码
METALLB_VERSION='v0.15.2'
kubectl apply -f 
https://raw.githubusercontent.com/metallb/metallb/${METALLB_VERSION}/config/manifests/metallb-native.yaml

创建地址池:

注意: IPAddressPool 必须使用Kuberetes集群节点的IP地址段

复制代码
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: localip-pool
  namespace: metallb-system
spec:
  addresses:
    - 192.168.48.20-192.168.48.30
  autoAssign: true
  avoidBuggyIPs: true

创建二层公告机制:

复制代码
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: localip-pool-l2a
  namespace: metallb-system
spec:
  ipAddressPools:
    - localip-pool
  interfaces:
    - ens33  # 用于发送免费ARP公告

3.1.创建 Service

复制代码
apiVersion: v1
kind: Service
metadata:
  name: myweb-loadbalancer
spec:
  type: LoadBalancer
  selector:
    app: myweb
  ports:
  - name: http
    port: 80
    targetPort: 80

3.2.查看Service

复制代码
root@master01:~/kubernetes-cni# kubectl get svc
NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
kubernetes           ClusterIP      10.96.0.1       <none>          443/TCP        4d
myweb-clusterip      ClusterIP      10.96.250.54    <none>          80/TCP         4h17m
myweb-loadbalancer   LoadBalancer   10.106.36.213   192.168.48.20   80:32264/TCP   4h8m
myweb-nodeport       NodePort       10.103.29.129   <none>          80:30066/TCP   4h16m

3.3.访问service

复制代码
root@master01:~/kubernetes-cni# curl 192.168.48.20
pod ip: 172.16.196.149
root@master01:~/kubernetes-cni# curl 192.168.48.20
pod ip: 172.16.140.85
root@master01:~/kubernetes-cni# curl 192.168.48.20
pod ip: 172.16.196.150

查看ipvs规则

复制代码
root@master01:~/kubernetes-cni# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn       
TCP  192.168.48.20:80 rr
  -> 172.16.140.85:80             Masq    1      0          0         
  -> 172.16.196.149:80            Masq    1      0          0         
  -> 172.16.196.150:80            Masq    1      0          0  

4.ExternalName Service 实现

Service 不仅可以实现Kubernetes集群内Pod应用之间的相互访问以及从集群外部访问集群中的Pod ExternalName Service 可以支持做为外部服务的代理实现集群中Pod访问集群外的服务或者另一个集群内的Service,因此也可以称为其它服务的"别名"服务 。

复制代码
pod-->serviceName-->externalname-->外部dns-->外部服务ip

Service代理Kubernetes外部应用的使用场景:

  • 在生产环境中Pod 希望使用某个固定的名称而非IP地址进行访问集群外部的服务

  • 使用Service指向另一个Namespace中或其它Kubernetes集群中的服务

  • 某个项目正在迁移至Kubernetes集群,但是一部分服务仍然在集群外部,此时可以使用service代 理至k8s集群外部的服务

4.1创建service

复制代码
apiVersion: v1
kind: Service
metadata:
  name: baidu
spec:
  type: ExternalName
  externalName: www.baidu.com

4.2.查看service

复制代码
root@master01:~/kubernetes-cni# kubectl get svc
NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
baidu                ExternalName   <none>          www.baidu.com   <none>         2m44s
kubernetes           ClusterIP      10.96.0.1       <none>          443/TCP        4d1h
myweb-clusterip      ClusterIP      10.96.250.54    <none>          80/TCP         4h57m
myweb-loadbalancer   LoadBalancer   10.106.36.213   192.168.48.20   80:32264/TCP   4h49m
myweb-nodeport       NodePort       10.103.29.129   <none>          80:30066/TCP   4h57m

查看endpoint

复制代码
root@master01:~/kubernetes-cni# kubectl get ep
NAME                 ENDPOINTS                                              AGE
kubernetes           192.168.48.100:6443                                    4d1h
myweb-clusterip      172.16.140.85:80,172.16.196.149:80,172.16.196.150:80   5h6m
myweb-loadbalancer   172.16.140.85:80,172.16.196.149:80,172.16.196.150:80   4h57m
myweb-nodeport       172.16.140.85:80,172.16.196.149:80,172.16.196.150:80   5h5m

没有创建和service同名的endpoint资源对象。也没有CLUSTER-IP。

In client -->Cluster ServiceName --> CName --> External Service Name

复制代码
root@master01:~/kubernetes-cni# kubectl exec -it network-tools -- nslookup baidu
;; Got recursion not available from 10.96.0.10
Server:     10.96.0.10
Address:    10.96.0.10#53
​
baidu.default.svc.cluster.local canonical name = www.baidu.com.
Name:   www.baidu.com
Address: 198.18.0.4

4.3.访问service

复制代码
root@master01:~/kubernetes-cni# kubectl exec -it network-tools -- ping baidu
PING www.baidu.com (198.18.0.4) 56(84) bytes of data.
64 bytes from 198.18.0.4 (198.18.0.4): icmp_seq=1 ttl=127 time=0.261 ms
64 bytes from 198.18.0.4 (198.18.0.4): icmp_seq=2 ttl=127 time=0.762 ms
^C
--- www.baidu.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1029ms
rtt min/avg/max/mdev = 0.261/0.511/0.762/0.250 ms
相关推荐
小二·2 小时前
Go 语言系统编程与云原生开发实战(第19篇)
开发语言·云原生·golang
A-刘晨阳2 小时前
K8S部署kube-state-metrics + CAdvisor 并使用 Prometheus 监控 Kubernetes 指标
运维·云原生·kubernetes·云计算·prometheus·cadvisor·state-metrics
江畔何人初2 小时前
MySQL 服务器进程的三层结构
linux·运维·服务器·云原生·mysal
陈桴浮海2 小时前
MySQL 主从复制与 GTID 环形复制
linux·mysql·云原生
码农老J2 小时前
【十六】容器化技术:Docker与Kubernetes实战
docker·容器·kubernetes
sryyd_022 小时前
云原生-高可用集群keepalived
服务器·网络·云原生
切糕师学AI2 小时前
Kubernetes DaemonSet 详细介绍
kubernetes·daemonset
王码码203513 小时前
Flutter for OpenHarmony:Flutter 三方库 bluez 玩转 Linux 风格的蓝牙操作(蓝牙底层互操作)
linux·运维·服务器·前端·flutter·云原生·harmonyos
努力搬砖的咸鱼13 小时前
一个域名搞定前后端:用 Ingress 配置 / 和 /api 路由
微服务·云原生·容器·架构·kubernetes