具有主备集群POD的Kubernetes服务

8

很抱歉我不能简短地描述问题,因为这样做会让我错过一些重要的细节。

我有一个传统的Java应用程序,它在集群环境中以活动/备用模式工作,通过预定义端口公开某些RESTful Web服务。

如果我的应用程序集群中有两个节点,那么任何时候只有一个节点处于活动模式,另一个节点处于被动模式,并且请求总是由处于活动模式下运行应用程序的节点提供。'活动'和'被动'只是角色,应用程序本身将在两个节点上运行。活动实例和备用实例之间通过相同的预定端口进行通信。

假设我有一个具有两个节点的集群,每个节点上都运行着我的应用程序的一个实例,那么一个实例最初将是活动状态,而另一个实例则是备用状态。如果由于某种原因活动节点崩溃了,另一个节点中的应用程序实例使用某种心跳机制识别出此情况,接管控制并成为新的活动实例。当旧的活动实例重新启动时,它会检测到另一个实例已经拥有新的活动角色,因此会进入被动模式。

该应用程序通过使用集群IP,在无论哪个节点下运行应用程序处于“活动”模式时,都能够在相同的端点IP上提供RESTful Web服务。

我正在尝试将此应用程序容器化并在Kubernetes集群中运行以实现规模和部署的便利性。我能够容器化并将其部署为Kubernetes集群中的一个POD。

为了在这里引入活动/备用角色,我运行了两个此POD的实例,每个实例钉住不同的K8S节点,并使用我的应用程序的集群机制将它们聚集在一起,其中只有一个是活动状态,另一个是备用状态。

我使用K8S服务语义将REST服务外部公开,通过在主节点上使用NodePort公开REST Web服务。

以下是我的YAML文件内容:

apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  labels:
    app: myapp-service
spec:
  type: NodePort
  ports:
    - port: 8443
      nodePort: 30403
  selector:
    app: myapp

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: active
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: myapp
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: nodetype
                operator: In
                values:
                - active
      volumes:
        - name: task-pv-storage
          persistentVolumeClaim:
           claimName: active-pv-claim
      containers:
      - name: active
        image: myapp:latest
        imagePullPolicy: Never
        securityContext:
           privileged: true
        ports:
         - containerPort: 8443
        volumeMounts:
        - mountPath: "/myapptmp"
          name: task-pv-storage

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: passive
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: myapp
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: nodetype
                operator: In
                values:
                - passive
      volumes:
        - name: task-pv-storage
          persistentVolumeClaim:
           claimName: active-pv-claim
      containers:
      - name: passive
        image: myapp:latest
        imagePullPolicy: Never
        securityContext:
           privileged: true
        ports:
         - containerPort: 8443
        volumeMounts:
        - mountPath: "/myapptmp"
          name: task-pv-storage

除了两个POD都通过同一端口公开Web服务之外,一切似乎都正常工作。K8S服务以随机方式将传入请求路由到这些POD中的一个。由于我的REST WebService端点仅在活动节点上工作,因此当请求被路由到处于活动角色的POD时,服务请求才通过K8S服务资源工作。如果K8S服务在任何时候将传入请求路由到处于被动角色的应用程序的POD,则该服务将无法访问/未提供。

我该如何使其以这样的方式工作,即K8S服务始终将请求路由到处于活动角色的POD?这在Kubernetes中可行吗,还是我要求过高?

感谢您的时间!

3个回答

5

您可以使用就绪探针与选举容器一起使用。选举将始终从选举池中选出一个主节点,如果您确保只有该Pod被标记为ready...那么只有该Pod将接收流量。


太好了!非常感谢@Radek 'Goblin' Pieczonka的回答。你让我的一天变得美好 :-) - msbl3004
1
我认为这并不像预期的那样工作,因为就算指定的端点上没有运行 readiness 探针,它也不会一直运行下去。 - halfwarp
这个选举容器是什么? - Abhishek D K

1

有些晚了。 您可以使用两个不同服务的相同应用程序部署,并带有不同的IP(或端口),然后还可以使用自定义配置部署负载平衡器以将流量发送到一个应用程序,第二个作为备份。 所有流量首先经过您的负载平衡器。 您还可以检查是否有任何Kubernetes Ingress控制器支持备份选项。


1

1
问题在于,我无法永久地将一个特定的 POD 标记为“Active”,因为如果该 POD 中的应用程序由于某种原因而关闭,则角色可能会变为被动状态,在这种情况下,另一个 POD 中的应用程序可能会承担“Active”的角色。实际上,这取决于集群 IP。任何具有集群 IP(我的应用程序的集群 IP,而不是 K8S 服务集群 IP)激活的 POD 都应被视为“Active”,并且入口流量应路由到该 POD。 - msbl3004
1
另一个选择是像Radek所提到的那样,您可以使用存活探针https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#define-a-liveness-http-request - sfgroups
感谢 @sfgroups,正如Radek建议的那样,我添加了一个Readiness探针,仅在该POD是Active时将其标记为Ready,这解决了问题! - msbl3004
2
@msbl3004 你可以分享一下你的代码来检查POD的活动状态吗? - ImranRazaKhan
无法理解,如果活动 Pod 关闭,k8s 服务的请求路由如何切换到被动 Pod? - Rahul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接