應用上K8S第三步:K8S整合Java應用

ITPUB社群發表於2023-01-03


預計閱讀時間4分鐘應用上K8S第三步:K8S整合Java應用

應用上K8S第三步:K8S整合Java應用

需求

當我們對Java應用完成Maven/Gradle打包並將映象推送至遠端倉庫後,剩下的工作就是應用上K8S了,涉及到的工作主要為:

  • 編寫Deployment/Service/Ingress部署應用;
  • 環境變數傳遞Xmx、應用名、環境名等個性化配置;
  • configmap傳遞統一標準規範的jvm引數;
  • 共享目錄統一管理配置檔案;

透過對Java應用執行依賴的JVM引數、執行目錄等內容的分析,需要分別透過K8S內建環境變數、Configmap、PV/PVC等功能進行不同程度的整合。

JVM引數管理

一套統一標準的JVM引數便於運維團隊對Java程式的統一管理,例如統一的記憶體引數、日誌目錄、gc日誌等等。我們將統一的JVM引數定義如下:

-server
-Xms2048m
-Xmx2048m
-XX:MaxPermSize:256m
-Dapp.name=test
-Denv=prod
-Djava.io.tmpdir=/tmp
# gc.log輸出到統一的日誌目錄
-Xloggc:/data/logs/gc.log
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCDateStamps
-XX:+PrintHeapAtGC
-XX:+PrintReferenceGC
-Dsun.jnu.encoding=UTF-8
-XX:+HeapDumpOnOutOfMemoryError
# dump檔案輸出到統一的日誌目錄
-XX:HeapDumpPath=/data/logs/HeapDumpOnOutOfMemoryError.dump

其中:

  • "-Xms2048m  -Xmx2048m"從JVM引數拆分,需要K8S環境變數單獨傳遞變數,以便應用記憶體個性化調整;
  • "-Denv=prod"從JVM引數拆分,需要K8S環境變數單獨傳遞變數,以便不同環境應用配置檔案訪問;
  • "-Dapp.name=test"在Dockerfile構建階段就透過程式碼內部的變數進行自動配置;
  • 剩餘的JVM引數因沒有個性化配置,統一透過configmap配置檔案進行統一管理;

1.Dockerfile 引數化傳遞

# vim Dockerfile
FROM harbor.xxx.com/public/centos-jdk8:1.0.0
MAINTAINER yunwei
#VOLUME /tmp
ARG JAR_FILE
ARG APP_NAME
ENV APP_NAME=${APP_NAME}
COPY ${JAR_FILE} ${APP_NAME}.jar
ENTRYPOINT ["/bin/sh","-c","java -Dapp.name=${APP_NAME} -Denv=${PROFILE} ${XM} -Xbootclasspath/a:/data/config/${APP_NAME} $JVM_OPTS -jar /${APP_NAME}.jar"]

其中:

  • "-Dapp.name"透過gradle打包映象傳遞;
  • "-Denv"和"XM"透過K8S環境變數傳遞;
  • "-Xbootclasspath"為配置檔案共享目錄;
  • "$JVM_OPTS"透過K8S的configmap傳遞;

2.K8S整合變數和配置

我們透過Deployment中的環境變數和configmap來進一步整合環境執行引數:

# vim configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
 name: jvmoptions
 namespace: test
data:
 JVM_OPTS: "-server -XX:MaxPermSize:256m -Djava.io.tmpdir=/tmp -Xloggc:/data/logs/gc.log -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -XX:+PrintReferenceGC -Dsun.jnu.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/logs/HeapDumpOnOutOfMemoryError.dump"

# vim Deployment.yaml
apiVersion: apps/v1
kind: Deployment
...省略...
   spec:
     containers:
       - name: sysmonitor
         env:
           - name: PROFILE
             value: "test"
           - name: XM
             value: "-Xms2048m -Xmx2048m"
           - name: JVM_OPTS
             valueFrom:
               configMapKeyRef:
                 name: jvmoptions
                 key: JVM_OPTS
...省略...

目錄管理

透過JVM引數可以發現,應用執行依賴的執行目錄主要有:

  • /data/logs,gc日誌目錄和執行日誌目錄;
  • /data/config/應用名,應用名的配置檔案目錄;

以上目錄我們一定要持久化,以便應用崩潰時能夠進行排查或後續日誌收集,K8S的解決方案是透過PV/PVC的方式實現持久卷的管理。

  • PV是叢集中的一塊儲存,可以由管理員事先製備(靜態製備), 或者使用儲存類(Storage Class)來動態製備
  • PVC是使用者對儲存的請求, Pod 透過 PVC 申領 PV 資源,實現對儲存的使用。

雖然靜態製備和動態製備都能實現我們對儲存資源的使用,但是從目前對目錄使用情況的分析,靜態製備是最適合我們的使用方案。而動態製備更適用於多目錄及不同等級儲存資源的需求及動態分配,對我們目前的使用量不太適用。對於儲存的適用,我們統一基於NFS的檔案儲存:

# vim static-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
 name: pv-static
 labels:
   type: pv-static
spec:
 storageClassName: nfs
 accessModes:
   - ReadWriteMany
 persistentVolumeReclaimPolicy: Recycle
 mountOptions:
   - vers=3
   - async
   - rsize=1048576
   - wsize=1048576
 nfs:
   path: /data
   server: 10.10.20.250
 capacity:
   storage: 10Gi

# vim static-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: pvc-static
 namespace: test
 labels:
   type: pvc-static
spec:
 storageClassName: nfs
 accessModes:
   - ReadWriteMany
 resources:
   requests:
     storage: 5Gi

# Deployment掛載
# vim deployment.yaml
apiVersion: apps/v1
kind: Deployment
...省略...
 template:
   spec:
     containers:
       - name: test
         env:
           - name: PROFILE
             value: "test"
           - name: XM
             value: "-Xms2048m -Xmx2048m"
           - name: JVM_OPTS
             valueFrom:
               configMapKeyRef:
                 name: jvmoptions
                 key: JVM_OPTS
...省略...
         ports:
           - containerPort: 8090
         volumeMounts:
           - name: data
             mountPath: /data
...省略...
     volumes:
       - name: data
         persistentVolumeClaim:
           claimName: pvc-static

我們在Nas上建立一個 data (10G)共享目錄,可方便對配置檔案進行統一管理:

  • 將Nas 共享目錄掛載到K8S 的一個master節點上,可在容器外進行管理;
  • /data/config目錄下的所有應用配置檔案,後續可在容器外手動git  pull更新;
  • 透過pv/pvc 將Nas 共享目錄 /data 掛載到應用pod容器內的 /data 目錄,多個pod共享檔案;
  • 其他logs或其他目錄均由應用自動生成;

Deployment/Service/Ingress

完整的一套應用上K8S的部署如下:

# vim helloworld.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
 name: helloworld
 namespace: test
spec:
 replicas: 1
 selector:
   matchLabels:
     app: helloworld
 template:
   metadata:
     name: helloworld
     labels:
       app: helloworld
   spec:
     containers:
       - name: helloworld
         env:
           - name: PROFILE
             value: "p2"
           - name: XM
             value: "-Xms2048m -Xmx2048m"
           - name: JVM_OPTS
             valueFrom:
               configMapKeyRef:
                 name: jvmoptions
                 key: JVM_OPTS
         image: harbor.xxx.com:8000/helloworld:1.1.21
         imagePullPolicy: IfNotPresent
         livenessProbe:
           httpGet:
             path: /app/health
             port: 8090
           initialDelaySeconds: 60
           timeoutSeconds: 5
         readinessProbe:
           httpGet:
             path: /app/health
             port: 8090
           initialDelaySeconds: 60
           timeoutSeconds: 5
         ports:
           - containerPort: 8090
         volumeMounts:
           - name: data
             mountPath: /data
     imagePullSecrets:
       - name: harbor-secret
     volumes:
       - name: data
         persistentVolumeClaim:
           claimName: pvc-static
       
---
apiVersion: v1
kind: Service
metadata:
 name: helloworld
 namespace: test
spec:
 type: NodePort
 selector:
   app: helloworld
 ports:
   - port: 8090
     targetPort: 8090

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
 name: helloworld
 namespace: test
spec:
 rules:
   - host: helloworld.xxx.net
     http:
       paths:
         - path: /
           pathType: Prefix
           backend:
             service:
               name: sysmonitor
               port:
                 number: 8090

總結

應用上K8S後並不意味著結束,相反我們仍還有其他需要工作要做:

  • Prometheus監控應用狀態;
  • 流水線實現應用的版本更新、快速交付;
  • 應用根據負載的彈性伸縮;
  • 應用的日誌收集;

其實本文應用的日誌最終寫在NFS共享儲存上,還是將其持久化到叢集node節點上。尤其是在上百已經級別的情況下,畢竟NFS的效能也是我們不得不面對的一個問題。其最終的解決方案,需要我們去從容選擇。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024420/viewspace-2930590/,如需轉載,請註明出處,否則將追究法律責任。

相關文章