skip to Main Content

Kubernetes에서 Wildfly 가용성(High-Availability) 구성

몇 년 전부터 기술 스택과 환경이 극적으로 변화하면서 Monolithic Architecture 보다 MicroService Architecture 가 주목 받고 있지만 여전히 많은 웹 애플리케이션 서버(WAS) 와 JEE 애플리케이션이 프로덕션 환경에서 실행되고 있습니다. 

대표적인 웹 애플리케이션 서버인 Wildfly를 예로 들어 Kubernetes 에서 여러 WAS 컨테이너를 관리하고 운영할 수 있는 방법에 대해 알아보겠습니다.

💬 Wildfly High-Availability

WildFly는 배포된 Java EE 애플리케이션의 가용성을 보장하는 기능을 제공합니다.

장애 조치 :  노드 장애가 있는 경우에도 클라이언트가 해당 애플리케이션에 중단 없이 액세스 가능합니다.
로드밸런싱 : 대량의 요청이 있는 경우에도 적시에 애플리케이션은 응답 할 수 있습니다.

🧰 Wildfly Kube-ping

Wildfly HA 구성은 TCP/UDP 프로토콜을 통해서 가능합니다. 반면 Kubernetes에서는 CNI 에 따라 UDP Multicast를 지원하지 않기 때문에 그런 경우에는 TCP를 사용해야합니다.

하지만 TCP 구성은 인스턴스 IP를 고정해야하기 때문에 Pod AutoScale을 할 수 없고 Pod IP를 고정해야하는 문제점을 가지고 있습니다. 이러한 문제점을 해결할 수 있도록 Kubernetes 환경에서 Wildfly 는 KUBE_PING  프로토콜을 지원하고 있습니다.

KUBE_PING 은 Kubernetes에서 클러스터 노드 검색 프로토콜입니다.

이번 글에서는 kube-ping을 사용하여 Kubernetes 에서 Wildfly HA 구성을 할 수 있는 방법에 대해 알아보도록 하겠습니다.

예제 파일은 아래 링크에서 확인해보실 수 있습니다.

🔗 https://github.com/mantech-accordion/wildfly-kubeping

사전환경

🔧 Kubernetes 1.18.12

🔧 Wildfly 23.0.1 Final

👨‍💻 Wildfly Image 작성

먼저, wildfly 베이스 이미지에 kube-ping 기능을 설정하는 embedded server 스크립트(config-wildfly.cli)을 포함하도록 Dockerfile을 작성합니다.

wildfly 버전에 따라 kube-ping 모듈을 별도 설치해야 할 수도 있습니다.

📄 Dockerfile

FROM jboss/wildfly:23.0.1.Final
LABEL MAINTAINER bskim <bskim@mantech.co.kr>

ADD config-wildfly.cli /opt/jboss/
ADD cluster.war /opt/jboss/wildfly/standalone/deployments/

RUN /opt/jboss/wildfly/bin/add-user.sh admin accordion --silent \
    && /opt/jboss/wildfly/bin/jboss-cli.sh --file=config-wildfly.cli \
    && rm -Rf /opt/jboss/wildfly/standalone/configuration/standalone_xml_history/*

EXPOSE 8080 9990 7600 8888

📄 standalone-ha.xml

스크립트가 실행되면 설정은 파일은 아래와 같이 수정됩니다.

      <subsystem xmlns="urn:jboss:domain:jgroups:8.0">
            <channels default="ee">
                <channel name="ee" stack="tcp" cluster="kubernetes"/>
            </channels>
                <stack name="tcp">
                    <transport type="TCP" socket-binding="jgroups-tcp"/>
                    <protocol type="kubernetes.KUBE_PING">
                        <property name="namespace">${env.KUBERNETES_NAMESPACE}</property>
                        <property name="labels">${env.KUBERNETES_LABELS}</property>
                        <property name="port_range">0</property>
                        <property name="masterHost">kubernetes.default.svc</property>
                        <property name="masterPort">443</property>
                    </protocol>
                    <protocol type="MERGE3"/>
                    <socket-protocol type="FD_SOCK" socket-binding="jgroups-tcp-fd"/>
                    <protocol type="FD_ALL"/>
                    <protocol type="VERIFY_SUSPECT"/>
                    <protocol type="pbcast.NAKACK2"/>
                    <protocol type="UNICAST3"/>
                    <protocol type="pbcast.STABLE"/>
                    <protocol type="pbcast.GMS"/>
                    <protocol type="MFC"/>
                    <protocol type="FRAG3"/>
                </stack>

...

    <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
        <socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
        <socket-binding name="http" port="${jboss.http.port:8080}"/>
        <socket-binding name="https" port="${jboss.https.port:8443}"/>
        <socket-binding name="jgroups-mping" interface="private" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45700"/>
        <socket-binding name="jgroups-tcp" interface="kubernetes" port="7600"/>
        <socket-binding name="jgroups-tcp-fd" interface="kubernetes" port="57600"/>

👨‍💻 ServiceAccount, ClusterRole, ClusterRoleBinding 생성

kubernetes 에서 kube-ping을 사용하기 위해 클러스터 리소스에 접근 권한이 필요합니다. Kubneretes의 ClusterRole, ClusterRoleBinding 생성하여 kube-ping에 필요한 클러스터 리소스 권한을 얻을 수 있습니다.

$ export TARGET_NAMESPACE=shop
$ kubectl apply -f https://raw.githubusercontent.com/mantech-accordion/wildfly-kubeping/main/wildfly-sa-role.yaml -n $TARGET_NAMESPACE

📄 yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: jgroups-kubeping-service-account
  namespace: $TARGET_NAMESPACE
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: jgroups-kubeping-pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: jgroups-kubeping-api-access
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: jgroups-kubeping-pod-reader
subjects:
- kind: ServiceAccount
  name: jgroups-kubeping-service-account
  namespace: $TARGET_NAMESPACE

👨‍💻 Wildfly Deployment, Service 생성

마지막으로 kube-ping이 설치된 wildfly 이미지를 배포할 차례입니다. Deployment, Service 를 생성합니다.

$ kubectl apply -f https://raw.githubusercontent.com/mantech-accordion/wildfly-kubeping/main/wildfly-deploy.yaml -n $TARGET_NAMESPACE

Deployment yaml 에 serviceAccountName: jgroups-kubeping-service-account 를 명시해야 Wildfly cluster member를 찾을 수 있습니다.

env에 명시된 POD_IP, KUBERNETES_NAMESPACE, KUBERNETES_LABELS를 통해 wildfly cluster를 namespace, labels로 분리할 수 있습니다.

📄 yaml

spec:
 serviceAccountName: jgroups-kubeping-service-account
...
env:
  - name: POD_IP
    valueFrom:
      fieldRef:
        apiVersion: v1
        fieldPath: status.podIP
  - name: KUBERNETES_NAMESPACE
    valueFrom:
      fieldRef:
        apiVersion: v1
        fieldPath: metadata.namespace
  - name: KUBERNETES_LABELS 
    value: app=wildfly
...

👨‍💻 Test Cluster

생성된 Wildfly Pod 로그에서 deployment replicas 만큼 cluster member가 같은지 확인할 수 있습니다.

 [org.infinispan.CLUSTER] (thread-4,null,wildfly-6bf8b74bd8-fflmc) ISPN000094: Received new cluster view for channel kubernetes: [wildfly-6bf8b74bd8-fflmc|1] (2) [wildfly-6bf8b74bd8-fflmc, wildfly-6bf8b74bd8-24cg                                                                                              

웹브라우저에서 배포된 테스트 애플리케이션을 통해 session 테스트 할 수 있습니다.

nodeid에 pod 이름이 보이고 pod 가 종료되었을때 sessionid 가 변경되지 않고 유지되는 것을 확인할 수 있습니다.

Kubernetes 환경에서도 자동확장이 가능한 Wildfly HA 구성 방법에 대해 알아보았습니다. 👍

🔗 Related Links

https://github.com/jgroups-extras/jgroups-kubernetes

Back To Top