把H2數據庫從jar包部署到Kubernetes,並解決Ingress不支持TCP的問題

1 前言

歡迎訪問南瓜慢說 www.pkslow.com獲取更多精彩文章!

H2 Database是一個優秀的數據庫,又小又方便,支持內存和文件形式,經常會在測試POC(proof of concept)開發環境用到它。在Springboot的許多應用中,也是內置了H2數據庫,很常用。接下來我們來一步步把它推上k8s,讓它坐上一個不一樣的位置。

建議閱讀下面文章以幫助理解:

Kubernetes用Helm安裝Ingress並踩一下使用的坑

容器技術相關文章

2 本地jar包運行

2.1 下載和啟動

下載官網jar包如下:

$ curl //www.h2database.com/h2-2019-03-13.zip -o h2-2019-03-13.zip

解壓:

$ unzip h2-2019-03-13.zip

啟動H2數據庫

$ java -cp h2/bin/h2*.jar org.h2.tools.Server -ifNotExists
TCP server running at tcp://localhost:9092 (only local connections)
PG server running at pg://localhost:5435 (only local connections)
Web Console server running at //localhost:8082 (others can connect)

如果需要修改配置,如端口號、數據存儲目錄,可以在啟動時添加參數:

java -cp h2/bin/h2*.jar org.h2.tools.Server -ifNotExists \
 	-web -webAllowOthers -webPort 8082 \
 	-tcp -tcpAllowOthers -tcpPort 9092 \
 	-baseDir ${DATA_DIR} ${H2_OPTIONS}

2.2 配置連接

成功啟動後訪問//localhost:8082就能登陸控制台了。如下:

Driver Classorg.h2.Driver,驅動類;

JDBC URLjdbc:h2:mem:pkslow,使用內存數據庫,數據庫名為pkslow

賬號密碼設置為admin/123456

設置完成後,點擊連接即可創建數據庫。

如果我們把JDBC URL改為jdbc:h2:file:~/pkslow,就是以文件形式存在,這樣能把數據持久化,所以我們採取這種方式。這裡就會在~目錄,即${HOME}目錄生成文件pkslow.mv.db以保存數據。還有文件 ~/.h2.server.properties

更多URL的配置方法如下表:

Topic URL Format and Examples
Embedded (local) connection jdbc:h2:[file:][] jdbc:h2:~/test jdbc:h2:file:/data/sample jdbc:h2:file:C:/data/sample (Windows only)
In-memory (private) jdbc:h2:mem:
In-memory (named) jdbc:h2:mem: jdbc:h2:mem:test_mem
Server mode (remote connections) using TCP/IP jdbc:h2:tcp://[:]/[] jdbc:h2:tcp://localhost/~/test jdbc:h2:tcp://dbserv:8084/~/sample jdbc:h2:tcp://localhost/mem:test
Server mode (remote connections) using TLS jdbc:h2:ssl://[:]/[] jdbc:h2:ssl://localhost:8085/~/sample;
Using encrypted files jdbc:h2:;CIPHER=AES jdbc:h2:ssl://localhost/~/test;CIPHER=AES jdbc:h2:file:~/secure;CIPHER=AES
File locking methods jdbc:h2:;FILE_LOCK={FILE|SOCKET|NO} jdbc:h2:file:~/private;CIPHER=AES;FILE_LOCK=SOCKET
Only open if it already exists jdbc:h2:;IFEXISTS=TRUE jdbc:h2:file:~/sample;IFEXISTS=TRUE
Don’t close the database when the VM exits jdbc:h2:;DB_CLOSE_ON_EXIT=FALSE
Execute SQL on connection jdbc:h2:;INIT=RUNSCRIPT FROM ‘~/create.sql’ jdbc:h2:file:~/sample;INIT=RUNSCRIPT FROM ‘~/create.sql’;RUNSCRIPT FROM ‘~/populate.sql’
User name and/or password jdbc:h2:[;USER=][;PASSWORD=] jdbc:h2:file:~/sample;USER=sa;PASSWORD=123
Debug trace settings jdbc:h2:;TRACE_LEVEL_FILE=<level 0..3> jdbc:h2:file:~/sample;TRACE_LEVEL_FILE=3
Ignore unknown settings jdbc:h2:;IGNORE_UNKNOWN_SETTINGS=TRUE
Custom file access mode jdbc:h2:;ACCESS_MODE_DATA=rws
Database in a zip file jdbc:h2:zip:!/ jdbc:h2:zip:~/db.zip!/test
Compatibility mode jdbc:h2:;MODE= jdbc:h2:~/test;MODE=MYSQL;DATABASE_TO_LOWER=TRUE
Auto-reconnect jdbc:h2:;AUTO_RECONNECT=TRUE jdbc:h2:tcp://localhost/~/test;AUTO_RECONNECT=TRUE
Automatic mixed mode jdbc:h2:;AUTO_SERVER=TRUE jdbc:h2:~/test;AUTO_SERVER=TRUE
Page size jdbc:h2:;PAGE_SIZE=512
Changing other settings jdbc:h2:;=[;=…] jdbc:h2:file:~/sample;TRACE_LEVEL_SYSTEM_OUT=3

3 在Docker運行

3.1 創建鏡像並啟動

編寫Dockerfile文件:

FROM adoptopenjdk/openjdk8-openj9:latest
COPY h2/ h2/
ENV DATA_DIR /opt/h2-data
RUN mkdir -p ${DATA_DIR}
EXPOSE 8082 9092
ENTRYPOINT java -cp h2/bin/h2-1.4.199.jar org.h2.tools.Server -ifNotExists \
 	-web -webAllowOthers \
 	-tcp -tcpAllowOthers \
 	-baseDir ${DATA_DIR} ${H2_OPTIONS}

這裡把數據存儲文件放在/opt/h2-data目錄上,使用默認端口,所以只對外暴露8082/9092端口。

通過Dockerfile創建鏡像:

$ docker build -t h2:1.4.199 .

啟動Docker容器:

$ docker run -itd --name h2 -p 8082:8082 -p 9092:9092 h2:1.4.199

3.2 通過Web和TCP方式連接

3.2.1 Web界面連接

成功啟動後,訪問//localhost:8082配置連接如下:

進入容器,查看在/opt/h2-data目錄生成了存儲文件:

$ docker exec -it h2 /bin/bash
root@0121e369b933:/opt/h2-data# l
test.mv.db

3.2.2 TCP方式連接

通過IDEA配置連接H2時要注意路徑,通過TCP方式,不用加baseDir,配置為jdbc:h2:tcp://localhost:9092/test。如果要加,應該配置為jdbc:h2:tcp://localhost:9092//opt/h2-data/test

4 部署在Kubernetes上運行

4.1 部署上Kubernetes看看

4.1.1 創建PersistentVolumeClaim

PersistentVolumeClaim,簡稱PVC,是Kubernetes用於存儲的單元,為了可以使H2的數據持久化,在Pod死掉後重啟數據不丟失,我們來創建對應的PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: h2-db
  labels:
    app: h2-db
  annotations:
    volume.alpha.kubernetes.io/storage-class: default
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 0.05Gi

這裡空間只給0.05G,反正實驗為主,不作其它用途。

4.1.2 創建Deployment

這裡最關鍵的是要注意PVC的配置:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: h2-db
  labels:
    app: h2-db
spec:
  replicas: 1
  selector:
    matchLabels:
      app: h2-db
  template:
    metadata:
      labels:
        app: h2-db
    spec:
      containers:
      - image: h2:1.4.199
        name: h2-db
        ports:
          - containerPort: 8082
            name: h2-web
          - containerPort: 9092
            name: h2-tcp
        volumeMounts:
          - name: data
            mountPath: /opt/h2-data
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: h2-db

mountPath對應的是之前在製作Docker鏡像時指定的路徑。

4.1.3 創建Service和Ingress

ServiceIngress對應的yaml文件如下:

apiVersion: v1
kind: Service
metadata:
  name: h2-db
  labels:
    app: h2-db
spec:
  ports:
    - port: 8082
      name: web
    - port: 9092
      name: tcp
  selector:
    app: h2-db
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: h2-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
    - http:
        paths:
          - path: /
            backend:
              serviceName: h2-db
              servicePort: 8082
      host: h2-web.localhost
    - http:
        paths:
          - path: /
            backend:
              serviceName: h2-db
              servicePort: 9092
      host: h2-tcp.localhost

4.1.4 訪問

Web方式簡單,通過訪問//h2-web.localhost/配置連接即可。

TCP方式就麻煩了,無論如何配置,死活連不上。具體原因接下來繼續討論。

4.2 讓Ingress支持TCP

之前TCP連不上的原因是Ingress是不支持TCP路由轉發的,雖然Ingress是基於Nginx,而Nginx又可以轉發代理TCP/UDP。那就來探索一番吧。

4.2.1 修改nginx-ingress-controller

為了讓它支持TCP/UDP,我們要修改Ingress-Controller,在它的配置文件增加參數:

- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services

在下面內容中插入:

containers:
- args:
  - /nginx-ingress-controller
  - --default-backend-service=default/pki-nginx-ingress-default-backend
  - --election-id=ingress-controller-leader
  - --ingress-class=nginx
  - --configmap=default/pki-nginx-ingress-controller
  - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
  - --udp-services-configmap=$(POD_NAMESPACE)/udp-services

4.2.2 添加tcp-services config

上面的Controller指定了tcp-servicesConfigMap,那我們就添加上:

kind: ConfigMap
apiVersion: v1
metadata:
  name: tcp-services
  namespace: default
data:
  "9092": default/h2-db:9092

其中,"9092": default/h2-db:9092表示:<Nginx port>: <namespace/service name>:<service port>:[PROXY]:[PROXY],我們這樣配置相當於把Nginx9092端口,指向H29092端口。

4.2.3 修改Ingress Service的端口

在只有http/https的基礎上,增加H2配置:

spec:
  externalTrafficPolicy: Cluster
  ports:
  - name: http
    nodePort: 32231
    port: 80
    protocol: TCP
    targetPort: http
  - name: https
    nodePort: 30370
    port: 443
    protocol: TCP
    targetPort: https
  - name: h2-tcp
    nodePort: 30371
    port: 9092
    protocol: TCP
    targetPort: 9092

4.2.4 連接使用

完成以上步驟後,就可以連接了,如下:

配置後連接成功。

5 總結

至此,我們一步步從jar包到部署H2 DatabaseKubernetes,希望大家能從整個過程學到一些知識吧。我們解決了之前安裝Ingress不支持TCP的問題,但始終不是一個太好的方案。如果我們把連接數據庫的應用都部署在Kubernetes上,那就沒有必要把H2 TCP暴露出去了。


歡迎關注微信公眾號<南瓜慢說>,將持續為你更新…

多讀書,多分享;多寫作,多整理。

Tags: