把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 http://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 http://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 配置连接
成功启动后访问http://localhost:8082就能登陆控制台了。如下:

Driver Class:org.h2.Driver,驱动类;
JDBC URL:jdbc: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界面连接
成功启动后,访问http://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
Service和Ingress对应的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方式简单,通过访问http://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-services的ConfigMap,那我们就添加上:
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],我们这样配置相当于把Nginx的9092端口,指向H2的9092端口。
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 Database上Kubernetes,希望大家能从整个过程学到一些知识吧。我们解决了之前安装Ingress不支持TCP的问题,但始终不是一个太好的方案。如果我们把连接数据库的应用都部署在Kubernetes上,那就没有必要把H2 TCP暴露出去了。
欢迎关注微信公众号<南瓜慢说>,将持续为你更新...

多读书,多分享;多写作,多整理。
把H2数据库从jar包部署到Kubernetes,并解决Ingress不支持TCP的问题的更多相关文章
- springboot之jar包部署步骤
eclipse中: 1.单击整个项目 run as - maven clean - maven install 2.找到项目所在的路径 找到所有的jar包 3.把jar包放到linux对应的文件夹 l ...
- windows环境jar包部署到linux服务器,一键操作
背景: windows系统下生成的jar包通过FTP上传到linux服务器,然后通过XShell进行jar包的发布,这样反复了几个月后,开发阶段需要频繁更新包的部署.个人觉得很繁琐,想一键式把这个工作 ...
- springboot的jar包部署
由于springboot常用war包部署,改为cloud开发模式多端口情况下,部署反而不习惯 毕竟,war包要不要项目名访问都必须放在tomcat的root目录下 而此目录限制只能放置一个项目,并且登 ...
- Springboot中如何引入本地jar包,并通过maven把项目成功打包成jar包部署
最近尝试引入阿里云的短信验证码,阿里云的core sdk是maven就有的,但是短信相关的jar包却不是放在maven的,所以得引入本地的下载回来的jar包.本地开发直接引入,idea是可以直接跑调用 ...
- 自己挖的坑自己填-- maven打jar包部署服务器报错
1.今天 mvn install 后把 jar 包部署到服务器上,执行 java -jar xx.jar 报 "no main manifest attribute,in xx.jar&qu ...
- maven依赖jar包时版本冲突的解决
https://blog.csdn.net/sinat_39789638/article/details/78005945 共有四种解决方式: 1.第一声明优先原则: 在pom.xml配置文件中,如果 ...
- External Libraries中没有Maven的jar包的原因(已解决)
**深坑!** ## External Libraries中没有Maven的jar包的原因(已解决) 2021年3月1日 --- 搭建一个新项目 IDEA 从 Git 上拉 拉去Maven项目然后 m ...
- SpringBoot+Maven多模块项目(创建、依赖、打包可执行jar包部署测试)完整流程
一,创建Maven多模块项目先建立外层父工程 File →new →project 选择Spring Initializr Next下一步到以下页面 工程结构如下 ...
- 如何发布本地maven项目jar包部署到nexus私服?
首先在我们的pom里面描述我们要部署的地址: <distributionManagement> <repository> <id>release</id> ...
随机推荐
- NPOI Excel设置样式
在表格导出时,会碰到样式修改的问题,作如下简单归纳: //创建行样式ICellStyle style = workbook.CreateCellStyle();//前景色 ...
- C++ 优先队列priority_queue用法
头文件:#include<queue> 操作: top 访问队头 empty 队列是否为空 size 返回队列元素个数 push 插入元素到队尾 pop 弹出队头 swap 交换内容 定义 ...
- 写给程序员的机器学习入门 (八) - 卷积神经网络 (CNN) - 图片分类和验证码识别
这一篇将会介绍卷积神经网络 (CNN),CNN 模型非常适合用来进行图片相关的学习,例如图片分类和验证码识别,也可以配合其他模型实现 OCR. 使用 Python 处理图片 在具体介绍 CNN 之前, ...
- P1852 跳跳棋 [LCA思想+二分答案]
题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有\(3\)颗棋子,分别在\(a,b,c\)这三个位置.我们要通过最少的跳动 ...
- 详解 awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}每个字段的意思
用这个列子说好了如果NF代表字段 那最后应该是7 才对啊 还有最后怎么都是1呢?END前面的是查看并发吧 后面是查看 tcp连接数 是这样吗? awk下标采用字符串来表示可能你在其它语言见 ...
- sed 指定行范围匹配
sed -n '5,10{/pattern/p}' file sed是一个非交互性性文本编辑器,它编辑文件或标准输入 导出的文件拷贝.标准输入可能是来自键盘.文件重定向.字符串或变量,或者是一个管道文 ...
- Python之数据结构:列表、元组、字典、set
列表 列表里可以存储任意的数据类型.可修改的结构,用[ ]括起来表示或用函数list()构建. eg: y = [1,1.5,'hello',True] 列表还可以嵌套列表 eg: y = [1,1. ...
- jmeter变量的声明和使用
@@@@@@@@@@@@@@@ 据说好多人早上看时间不是为了起床,而是看还能睡多久 jmeter中变量的使用还是很广泛的,有语言基础的都知道变量是什么意思.在jmeter中变量的声明和调用也都有自己的 ...
- 递归-N皇后问题
// // #include <stdio.h> /*可以用回溯,但是我已经不太熟悉回溯了!!!!!!!!呜呜呜 * */ #include <iostream> #inclu ...
- 在Windows上安装MySQL(转整)
MySQL安装 在Windows上安装MySQL.首先登录MySQL的官网下载安装包. 选择MySQL installer 这里选择第二个安装包下载即可. 下载完成之后就选择安装那个下载到的文件,基本 ...