K8s中的Service服务

红米1年前技术文章433


为何需要 Service

Kubernetes 中 Pod 是随时可以消亡的(节点故障、容器内应用程序错误等原因)。如果使用 Deployment 运行您的应用程序,Deployment 将会在 Pod 消亡后再创建一个新的 Pod 以维持所需要的副本数。每一个 Pod 有自己的 IP 地址,然而,对于 Deployment 而言,对应 Pod 集合是动态变化的。

这个现象导致了如下问题:

如果某些 Pod(假设是 'backends')为另外一些 Pod(假设是 'frontends')提供接口,在 'backends' 中的 Pod 集合不断变化(IP 地址也跟着变化)的情况下,'frontends' 中的 Pod 如何才能知道应该将请求发送到哪个 IP 地址?

Service 存在的意义,就是为了解决这个问题。

Kubernetes 通过引入 Service 的概念,将前端与后端解耦。

从 Kuboard 工作负载编辑器的视角来看,Service 与其他重要的 Kubernetes 对象之间的关系如下图所示:

20230504100434.jpg

创建service

如下:创建一个满足以下条件的service

1)名字为 my-service

2)目标端口为 TCP 9376

3)选取所有包含标签 app=MyApp 的 Pod

vi my-service.yaml
 
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

补充:

1Kubernetes 将为该 Service 分配一个 IP 地址(ClusterIP 或 集群内 IP),供 Service Proxy 使用。

2Kubernetes 将不断扫描符合该 selector 的 Pod,并将最新的结果更新到与 Service 同名 my-service 的 Endpoint 对象中。

虚拟 IP 和服务代理

Kubernetes 集群中的每个节点都运行了一个 kube-proxy,负责为 Service(ExternalName 类型的除外)提供虚拟 IP 访问。

Kubernetes 支持三种 proxy mode(代理模式)

 iptables proxy mode 模式

在 iptables proxy mode 下:

1kube-proxy 监听 kubernetes master 以获得添加和移除 Service / Endpoint 的事件

2kube-proxy 在其所在的节点(每个节点都有 kube-proxy)上为每一个 Service 安装 iptable 规则

3iptables 将发送到 Service 的 ClusterIP / Port 的请求重定向到 Service 的后端 Pod 上

a、对于 Service 中的每一个 Endpoint,kube-proxy 安装一个 iptable 规则

b、默认情况下,kube-proxy 随机选择一个 Service 的后端 Pod

20230504100656.jpg

IPVS 代理模式

需要着重了解下ipvs模式,在 IPVS proxy mode 下:

1kube-proxy 监听 kubernetes master 以获得添加和移除 Service / Endpoint 的事件

2kube-proxy 根据监听到的事件,调用 netlink 接口,创建 IPVS 规则;并且将 Service/Endpoint 的变化同步到 IPVS 规则中

3)当访问一个 Service 时,IPVS 将请求重定向到后端 Pod

20230421140129.jpg

IPVS 模式的优点:

IPVS proxy mode 基于 netfilter 的 hook 功能,与 iptables 代理模式相似,但是 IPVS 代理模式使用 hash table 作为底层的数据结构,并在 kernel space 运作。这就意味着

1IPVS 代理模式可以比 iptables 代理模式有更低的网络延迟,在同步代理规则时,也有更高的效率

2)与 user space 代理模式 / iptables 代理模式相比,IPVS 模式可以支持更大的网络流量

多端口的Service

Kubernetes 中,您可以在一个 Service 对象中定义多个端口,此时,您必须为每个端口定义一个名字。如下:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 9376
    - name: https
      protocol: TCP
      port: 443
      targetPort: 9377



服务发现

Kubernetes 支持两种主要的服务发现模式:

1)环境变量

如果要在 Pod 中使用基于环境变量的服务发现方式,必须先创建 Service,再创建调用 Service 的 Pod。否则,Pod 中不会有该 Service 对应的环境变量。

如果使用基于 DNS 的服务发现,您无需担心这个创建顺序的问题。

2DNS

首先确保集群中已安装了 DNS 服务,例如:Core DNS

CoreDNS 监听 Kubernetes API 上创建和删除 Service 的事件,并为每一个 Service 创建一条 DNS 记录。集群中所有的 Pod 都可以使用 DNS Name 解析到 Service 的 IP 地址。

发布Service

Kubernetes 中可以通过不同方式发布 Service,通过 ServiceType 字段指定,该字段的默认值是 ClusterIP,可选值有:

1ClusterIP:默认值。通过集群内部的一个 IP 地址暴露 Service,只在集群内部可以访问

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

a、在集群内部通过 $(ClusterIP): $(Port) 访问

b、在集群外部通过 $(NodeIP): $(NodePort) 访问

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

a、在集群内部通过 $(ClusterIP): $(Port) 访问

b、在集群外部通过 $(NodeIP): $(NodePort) 访问

c、在集群外部通过 $(LoadBalancerIP): $(Port) 访问

4ExternalName:将 Service 映射到 externalName 指定的地址(例如:foo.bar.example.com),返回值是一个 CNAME 记录。不使用任何代理机制。

补充:如使用 ExternalName 类型的 Service,CoreDNS 版本不能低于 1.7

Service/PodDNS

Kubernetes 集群中运行了一组 DNS Pod,配置了对应的 Service,并由 kubelete 将 DNS Service 的 IP 地址配置到节点上的容器中以便解析 DNS names。

集群中的每一个 Service(包括 DNS 服务本身)都将被分配一个 DNS name。

Service

1A记录

2SRV 记录

Pods

1Pod 的 hostname / subdomain

2Pod 的 DNS Policy

小实验-Service连接应用程序

在集群中部署pod

1、通过yaml文件创建pod

#创建文件 run-my-nginx.yaml

 

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

2执行以下命令,部署 Pod 并检查运行情况:

kubectl apply -f ./run-my-nginx.yaml
kubectl get pods -l run=my-nginx -o wide

查看podip

4、测试访问验证

在集群中的任意节点上,测试访问,可以获得 nginx 的响应。此时:

1)容器并没有使用节点上的 80 端口

2)没有使用 NAT 规则对容器端口进行映射

这意味着,您可以

1)在同一节点上使用 80 端口运行多个 nginx Pod

2)在集群的任意节点/Pod 上使用 nginx Pod 的 clusterIP 访问 nginx 的 80 端口

同 Docker 一样,Kubernets 中,仍然可以将 Pod 的端口映射到宿主节点的网络地址上(使用 nodePort),但是使用 Kubernetes 的网络模型时,这类需求已经大大减少了。

创建 Service

Service详情:

1)定义了集群中一组 Pod 的逻辑集合,该集合中的 Pod 提供了相同的功能

2)被创建后,获得一个唯一的 IP 地址(ClusterIP)。直到该 Service 被删除,此地址不会发生改变

3Pod 可以直接连接 Service IP 地址上的端口,且发送到该 IP 地址的网络请求被自动负载均衡分发到 Service 所选取的 Pod 集合中

执行命令:

kubectl expose deployment/my-nginx

可以为上面的两个 nginx Pod 创建 Service,执行结果如下:

以上命令等价于定义通过yaml文件创建service,如下:

#创建nginx-svc.yaml
vi nginx-svc.yaml
 
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
  selector:
    run: my-nginx
 
#执行yaml
kubectl apply -f nginx-svc.yaml


查看service ip信息

kubectl get svc my-nginx

结果如下:

Service 的后端 Pod 实际上通过 Endpoints 来暴露。Kubernetes 会持续检查 Service 的 label selector spec.selector,并将符合条件的 Pod 更新到与 Service 同名(my-nginx)的 Endpoints 对象。如果 Pod 终止了,该 Pod 将被自动从 Endpoints 中移除,新建的 Pod 将自动被添加到该 Endpoint。

从下图可以看到该serviceendpoints地址和上面podip地址相同。

访问 Service

Kubernetes 支持两种方式发现服务:

1)环境变量

2DNS

环境变量

针对每一个有效的 Service,kubelet 在创建 Pod 时,向 Pod 添加一组环境变量,但是要注意podservice顺序问题。

执行命令:

kubectl exec my-nginx-75897978cd-llgr7 -- printenv | grep SERVICE

输出结果如下:

此时命令删除pod,命令如下:

kubectl delete pods -l run=my-nginx

然后再执行命令查看重建的pod,命令如下:

kubectl get pods -l run=my-nginx -o wide

再次查看信息,命令如下:

kubectl exec my-nginx-75897978cd-f4hkg -- printenv | grep SERVICE

输出结果如下:

从下图可以看到Service 相关的环境变量已经被正确设置。

DNS

Kubernetes 提供了一个 DNS cluster addon,可自动为 Service 分配 DNS name。

可以通过如下命令确认集群中是否有安装对应组件,命令如下:

kubectl get services kube-dns --namespace=kube-system

输出结果如下:

证明该组件已经安装,基于该组件可以从集群中任何 Pod 中按 Service 的名称访问该 Service。

此时再创建一个pod,命令如下:

kubectl run curl --image=radial/busyboxplus:curl -i --tty

输出结果如下:

此时在该pod中测试解析server名称,可以正常解析。输出结果如下:

测试访问service对应服务,可以正常访问。输出结果如下:

保护 Service 的安全

上面测试都是在集群内部访问的,如果将service公布到互联网,必须保证是安全的,所以必须做如下措施:

1)准备 https 证书(购买,或者自签名)

2)将该 nginx 服务配置好,并使用该 https 证书

3)配置 Secret,以使得其他 Pod 可以使用该证书

可以如下步骤配置nginx自签证书

1)创建密钥对,命令如下:

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/nginx.key -out /tmp/nginx.crt -subj "/CN=my-nginx/O=my-nginx"

输出结果如下:

2)将密钥对转换为 base64 编码,命令如下:

cat /tmp/nginx.crt | base64

cat /tmp/nginx.key | base64

3)创建一个如下格式的 nginxsecrets.yaml 文件,使用前面命令输出的 base64 编码替换其中的内容(base64编码内容不能换行)(请使用前面两行命令生成的结果替换 nginx.crt 和 nginx.key 的内容,)

apiVersion: "v1"

kind: "Secret"

metadata:

  name: "nginxsecret"

  namespace: "default"

data:

  nginx.crt: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURIekNDQWdlZ0F3SUJBZ0lKQU9lQlVRWGN4eEllTUEwR0NTcUdTSWIzRFFFQkN3VUFNQ1l4RVRBUEJnTlYKQkFNTUNHMTVMVzVuYVc1NE1SRXdEd1lEVlFRS0RBaHRlUzF1WjJsdWVEQWVGdzB5TURFeU1UVXhORFU1TVRaYQpGdzB5TVRFeU1UVXhORFU1TVRaYU1DWXhFVEFQQmdOVkJBTU1DRzE1TFc1bmFXNTRNUkV3RHdZRFZRUUtEQWh0CmVTMXVaMmx1ZURDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTUdZNlU5T1V4dkEKTVhXWWd0VmJPKzYwaEtjVW16RlZBSFRYWEluRnZLQXBXT3hwd3A4S3AxRTRoLzE2bUFpV2k1ZUhDSDI5YmtyNwo3S1dnVVo0MUFjT1F2N2c2c1ZUaStZZXd3blVONjJtOGtNVk44ZURubnZFVm5DR3RwL1ZldjVJV3NCdU44Y3JMCjJxU1V6bGgyNWtiMlZIeXkwL1MrU3ZUU2YxMWpsdFBEanMzSTlxMUdwbUsxMkxvREtLS3FYSlVlUTNiYmU1Q3cKWDFPN0UreWxPU0kvd0g0TjFsTmZ0Wm5GbHZ5amtJL2J3VVRtYkRQc3hGOVRXTDUwZUtRQ1Z3amd3Unpkdnl6TwpWRkhIdWN1a1pXYk01dXNxNFNmdHhMck13U1dmNXhMcVdMT25LL2ovektVdHdhcCtlSFBqZGlkY25vWGdLTmNYCmw5ak1aelNpY3BjQ0F3RUFBYU5RTUU0d0hRWURWUjBPQkJZRUZNUSt4aUtBNkpOZ1p2dE03VWl0c1VBcmtRdCsKTUI4R0ExVWRJd1FZTUJhQUZNUSt4aUtBNkpOZ1p2dE03VWl0c1VBcmtRdCtNQXdHQTFVZEV3UUZNQU1CQWY4dwpEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBS0kweW15YzdCQjVOVFlJYzl0aGlQWjgwV3NIeUpqNTl5cFEraHMxCkR5VFgreE9JYUU4dEpHWlM4VkVFdFJ1QkVkRW9WczAxWWN3UkVaR2tlQVFxTWkwTk9QMXVRTGNabWVFOEIyVkgKZmZ1SSsrWHFRN2d2bzdkblZMSmx3eGRpVWRWUEhrSjA5MU1HUWQyU200aGdoWTJLUmlpMk1LU2ZGYnQ3cVJuZwoyN2g2L0hMUFRvY3E3cGZ0V0ZrNkJ0Y1d1cGlVQngyRFYra2JSMmRXN1RYZzUxVUtwN1J0aUprSk5wZlVnMDhBClNoaVV1YTZEbVN2TVdsU3hFZXF4dElKSzVWYTcyakFXTnE2bDg4QTBMb3FRWm4wUVB3MUFFWkRLR0pqazBCeDgKZGFXSm5yMkJJVHFRQ3R1NnJQeHhRTCtROSs2WVBncHp3YWd1RUp0NmtNU3dMZzg9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"

  nginx.key: "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRREJtT2xQVGxNYndERjEKbUlMVld6dnV0SVNuRkpzeFZRQjAxMXlKeGJ5Z0tWanNhY0tmQ3FkUk9JZjllcGdJbG91WGh3aDl2VzVLKyt5bApvRkdlTlFIRGtMKzRPckZVNHZtSHNNSjFEZXRwdkpERlRmSGc1NTd4Rlp3aHJhZjFYcitTRnJBYmpmSEt5OXFrCmxNNVlkdVpHOWxSOHN0UDB2a3IwMG45ZFk1YlR3NDdOeVBhdFJxWml0ZGk2QXlpaXFseVZIa04yMjN1UXNGOVQKdXhQc3BUa2lQOEIrRGRaVFg3V1p4WmI4bzVDUDI4RkU1bXd6N01SZlUxaStkSGlrQWxjSTRNRWMzYjhzemxSUgp4N25McEdWbXpPYnJLdUVuN2NTNnpNRWxuK2NTNmxpenB5djQvOHlsTGNHcWZuaHo0M1luWEo2RjRDalhGNWZZCnpHYzBvbktYQWdNQkFBRUNnZ0VBV0tabW43UWtCbDhaeHRtUmY1V0plaU1iWTA3aVNkSzhwTVJCVWExRVZLcmEKVjFlT2tUbFZxTEdVUkJReExpMlJ1azlSS2hMbVFGdmYzMi9zTDkvaDhPV0ZoUjBMT3UyOGljLzlHNURHTGVMMQpBQVJUTUVPZjJwR2tyeDlQKytIcEkwSlVYaW0vZ0xlY1pTVG00RWVCNXhqQlUyQ29BamhwSm5hRmNBUThlcmNUCjk1ZFlMTVJzWVMrbkFiMVdRNjdMUXRSa1k1UVRjdkhrNGhLM3J1N0pGVUNJN2c1N2VkQnJidTZNaGdtOVhDaVAKVmF5Zi9RZTV5VVpKdWg1TlF5ekxzdkJPcS9TZ3c1MU94MW5ienpFb3d1azhmWmpObWtFZGpHZ3pFUnllMlZSZAo5SkNVZEJFblc0M25JNkJEdExqcUw0cnRJdGI2QWMwT0Q4akx2MHlmQVFLQmdRRGdGcUkrQ3h4TXJBLzNkMk1BClBpekJHYXc2K2JiRnZ0NDlhNkpieWxySW42M1paVHJ2d1pGYmFrcm5WVDdWVWJjVU4yam5zdmh2YjBPbGlsbWMKZXgrMWdmN2xMOHZQdEZXelFiK1pXYU9ISmJBZk9TYzh5a1Ryc2J4NFZSOU9Wd2Q4UVFnNElNVklDSmNpNlFucApwMjFkVm40S0s1ZWR4M2VyNXZlQUNjazgxd0tCZ1FEZEtyR3ZWWkxXMHpEU3FVZFNQQU5Td1NSN0NWaTRhOVg5ClhMN3lURDFlNHI3MWowUWpiRzBsTHJxTXozTk9memJySXJicDRnMEhkSTVuUXZ0YWlPdkpCbnMwM05uZDdnbXQKb1lXNFF4UFN4WTZNT3hJenI2WUVjVTd2MUl4bk5OSXkyb2ptcXdVMUZadXl5ZzhpejdLV1lYeGpSUzJRQk9hKwpNbThzSUlZQVFRS0JnRlhLOUpTeVprUklmOWhyd2VCKzdWMkV1YmJla2daRlhBckI0YWdvNGZiN2czQyszQUNjCjZFektkaUQ1TnhRdXM5d3VscUJXbWR6NENUc2dxOHhJSzB5dmwyb2hrWE5WQkphYnJvSkVtbUlNb05CamJrMU0KMTNReFdRbnM5UTVtTFh4NTNXNjN4VEFkOGRjd3gxWElmd3VFS0w4MkQxY2QzZ2hYWmh5RUlxS0RBb0dCQUt5UgpZNU1yY2lldElhczk2aWlBS3hlbkhJL2oreFhyRGsxaTBKcStZaVJuU0JqU2NKZ3pRZmFCUDQ0ZlVCa3ZxZXBPCmErcVNOeGhhR2NMNHdLY2pydFpyK0RhSEhIZk9CRDgyaU4vOWRybys2N3IvWEhSMzJWSWVGem1LM3dLb2RGcTUKcVpoU1dQM1NubW9pdnl5cVl1NXpvbHJTMzNwQVdNcVBENitlc1BBQkFvR0FHSGpMQzZTWVJiM09BeHlyc2F5cgpubTVLZWd4Qm8xdXpreXVpdllwVHNjSUIyaTFxcnYyem5RWDNUUCtWYUdQaTJjUkNUM21MeGFXd3ZFY2VJelFyCk5Mc0hSMGNDbUdBVzFHOVJRanIvMVVwYllUMVhyRTc5YmdOejIwN2htNWVKN253L2V4SHlFM0tBV1BzOVY2RWMKbnR2ZTVPRzAza0YxWllPV1A3T1p4ZFk9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K"

4)使用该文件创建 Secrets

# 创建 Secrets
kubectl apply -f nginxsecrets.yaml
# 查看 Secrets
kubectl get secrets


输出结果如下:

5)修改 nginx 部署,使 nginx 使用 Secrets 中的 https 证书,修改 Service,使其暴露 80 端口和 443端口。nginx-secure-app.yaml 文件如下所示:

vi  nginx-secure-app.yaml
 
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
    name: http
  - port: 443
    protocol: TCP
    name: https
  selector:
    run: my-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 1
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      volumes:
      - name: secret-volume
        secret:
          secretName: nginxsecret
      containers:
      - name: nginxhttps
        image: bprashanth/nginxhttps:1.0
        ports:
        - containerPort: 443
        - containerPort: 80
        volumeMounts:
        - mountPath: /etc/nginx/ssl
          name: secret-volume


deployment以及service,命令如下:

kubectl delete deployments,svc my-nginx

kubectl create -f ./nginx-secure-app.yaml

然后执行创建命令,如下:

访问验证,测试可以从任何节点访问该 nginx server

补充:curl -k

1)在 curl 命令中指定 —k 参数,是因为我们在生成 https 证书时,并不知道 Pod 的 IP 地址,因此,在执行 curl 命令时必须忽略 CName 不匹配的错误。

2)通过创建 Service,我们将 https 证书的 CName 和 Service 的实际 DNS Name 联系起来,因此,我们可以尝试在另一个 Pod 中使用 https 证书的公钥访问 nginx Service。此时,curl 指令不在需要 -k 参数

创建 curlpod.yaml 文件,内容如下:、

apiVersion: apps/v1
kind: Deployment
metadata:
  name: curl-deployment
spec:
  selector:
    matchLabels:
      app: curlpod
  replicas: 1
  template:
    metadata:
      labels:
        app: curlpod
    spec:
      volumes:
      - name: secret-volume
        secret:
          secretName: nginxsecret
      containers:
      - name: curlpod
        command:
        - sh
        - -c
        - while true; do sleep 1; done
        image: radial/busyboxplus:curl
        volumeMounts:
        - mountPath: /etc/nginx/ssl
          name: secret-volume

 curlpod 的部

kubectl apply -f ./curlpod.yaml
kubectl get pods -l app=curlpod

输出结果如下:

测试访问:

kubectl exec curl-deployment-f8c5c685b-lw68q -- curl https://my-nginx --cacert /etc/nginx/ssl/nginx.crt

输出结果如下:

暴露 Service

在您的应用程序中,可能有一部分功能需要通过 Service 发布到一个外部的 IP 地址上。Kubernetes 支持如下两种方式:

1NodePort

2LoadBalancer 该方式需要云环境支持

在上面实验中我们创建的service就是NodePort类型,所以如果节点有公网地址,则 nginx HTTPS 部署已经可以接受来自于互联网的请求了。

 


相关文章

Kubernetes源码解读(三)-- Indexer和ThreadSafeStore源码分析

Kubernetes源码解读(三)-- Indexer和ThreadSafeStore源码分析

Indexer主要提供一个对象根据一定条件检索的能力,典型的实现是通过nameapce/name来构造key,通过ThreadSafeStore 来存储对象。换而言之,Indexer主要依赖于Thre...

某系统被入侵挖矿排查案例

某系统被入侵挖矿排查案例

1、当时的出现的情况是:执行 top、w、netstat命令的时候,会出现卡住的情况,无法正常使用2、我们上传新的top命令之后,只是看到CPU使用率比较高,但是看不到占用CPU的异常进程3、我们通过...

MySQL性能优化(七)优化or查询的另一个例子

MySQL性能优化(七)优化or查询的另一个例子

优化or查询的另外一个例子。一个例子SELECT msg.msg_id, msg.content , … FROM msg   ...

ES运维(四)扩容方式迁移

ES运维(四)扩容方式迁移

1 迁移概述本次模拟es在线迁移方式:集群扩容-->数据迁移-->老节点下线-->服务重启刷新配置。 中间master替换的时候会有短暂的不可用。 另外业务测需注意:老节点下线前...

PG安装部署

一、rpm包安装部署1、安装RPM包# yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_6...

数据湖技术之iceberg(十)Structured Streaming实时写入Iceberg

数据湖技术之iceberg(十)Structured Streaming实时写入Iceberg

目前Spark中Structured Streaming只支持实时向Iceberg中写入数据,不支持实时从Iceberg中读取数据,下面案例我们将使用Structured Streaming从Kafk...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。