在k8s上部署嵌入式模式的hazelcast
将带有嵌入式Hazelcast的应用程序部署到Kubernetes集群中。
来自每个应用程序副本的Hazelcast实例都将自动发现它们自己,并形成一个一致的Hazelcast集群。得益于 Hazelcast Kubernetes自动发现插件,不需要静态地写死配置。
准备
- Docker (Docker for Desktop is good enough)
- Kubernetes cluster (Docker for Desktop or Minikube is good enough)
- Git
- JDK 1.8+
- Apache Maven 3.2+
示例
我们可以将 Hazelcast 嵌入到任何基于jvm的应用程序中,并使用任何您想要的web框架。 作为本教程的一个示例,我们使用 Spring Boot 入门教程中的应用程序。我执行以下命令来下载:
git clone https://github.com/hazelcast-guides/hazelcast-embedded-springboot.git
配置
Hazelcast提供了专用的Hazelcast Kubernetes插件,允许在Kubernetes环境中自动形成Hazelcast集群。我们使用以下Hazelcast配置来启动这个功能。
hazelcast:
network:
join:
multicast:
enabled: false # 反使能多播模式
kubernetes:
enabled: true # 使能kubernetes模式
要将此文件包含在Spring Boot项目中,将其复制到hazelcast-embedded-springboot/src/resources/中。
cp hazelcast.yaml hazelcast-embedded-springboot/src/main/resources/
现在,我们可以使用以下命令构建项目。
mvn package -f hazelcast-embedded-springboot/pom.xml
作为输出,我们的应用程序的JAR文件应该在hazelcast-embedded-springboot/target/*. JAR中创建。
将应用程序容器化
要将应用程序容器化,需要安装Docker,我们可以使用以下Dockerfile
FROM openjdk:8-jre-alpine
COPY hazelcast-embedded-springboot/target/*.jar app.jar
ENTRYPOINT ["java","-jar","app.jar"]
编译成镜像
docker build -t hazelcastguides/hazelcast-embedded-kubernetes .
推送到远程
docker push hazelcastguides/hazelcast-embedded-kubernetes
配置Configure RBAC
Hazelcast Kubernetes发现插件通过调用Kubernetes API来提供自动成员发现。因此,它需要授予特定的ClusterRole规则。我们可以使用以下命令应用最小的RBAC配置(对于默认名称空间中的默认服务帐户)。
kubectl apply -f https://raw.githubusercontent.com/hazelcast/hazelcast/master/kubernetes-rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: hazelcast-cluster-role
rules:
- apiGroups:
- ""
# Access to apps API is only required to support automatic cluster state management
# when persistence (hot-restart) is enabled.
- apps
resources:
- endpoints
- pods
- nodes
- services
# Access to statefulsets resource is only required to support automatic cluster state management
# when persistence (hot-restart) is enabled.
- statefulsets
verbs:
- get
- list
# Watching resources is only required to support automatic cluster state management
# when persistence (hot-restart) is enabled.
- watch
- apiGroups:
- "discovery.k8s.io"
resources:
- endpointslices
verbs:
- get
- list
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: hazelcast-cluster-role-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: hazelcast-cluster-role
subjects:
- kind: ServiceAccount
name: default
namespace: default
如果您使用非默认的服务帐户或非默认的命名空间,则需要修改 https://raw.githubusercontent.com/hazelcast/hazelcast/master/kubernetes-rbac.yaml 如果您的Kubernetes集群不使用RBAC,则可以跳过整个“配置RBAC”步骤
将应用程序部署到Kubernetes
可以直接 apply 以下的部署的yaml文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: hazelcast-test
spec:
replicas: 2
selector:
matchLabels:
app: hazelcast-test
template:
metadata:
labels:
app: hazelcast-test
app.hazelcast/name: iidp
spec:
containers:
- name: hazelcast-test
image: lizhanbin/hazelcast-test
imagePullPolicy: Always
resources:
requests:
memory: 100Mi
---
apiVersion: v1
kind: Service
metadata:
name: my-app-svc
labels:
app: my-app-svc
spec:
type: ClusterIP
ports:
- port: 8080
selector:
app: my-app
然后我们直接查看组网情况
$ kubectl logs pod/my-app-86df8b785f-4x9pj
...
Members {size:2, ver:2} [
Member [10.24.1.10]:5701 - a7eb36b6-6d86-4d26-8eb6-47986e46d055 this
Member [10.24.2.6]:5701 - 9994d6c6-d271-4ddd-9aa9-1ac4767c1a73
]
测试应用程序
直接执行命令请求服务
$ curl --data "key=key1&value=hazelcast" "localhost:8080/put"
{"value":"hazelcast"}
$ curl "localhost:8080/get?key=key1"
{"value":"hazelcast"}
停止集群
kubectl delete deployment/my-app service/my-app
kubectl delete -f https://raw.githubusercontent.com/hazelcast/hazelcast/master/kubernetes-rbac.yaml
sidecar形式部署
hazelcast支持以sidecar形式进行部署,从而可以跨语言来进行通信,而不仅仅是在java中使用,我们以golang为例,来实现一个集群,且与java版的hazelcast集群正常通信和组网。
我们编写 main.go
package main
import (
"context"
"fmt"
"github.com/gin-gonic/gin"
"github.com/hazelcast/hazelcast-go-client"
)
var (
hz *hazelcast.Client
mp *hazelcast.Map
)
func main() {
r := gin.New()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
"code": 200,
})
})
r.POST("/set", func(c *gin.Context) {
// get kv
// get from hazelcast
err := mp.Set(c, "foo", "bar")
if err != nil {
c.JSON(500, gin.H{
"message": "get error",
"code": 500,
})
return
}
c.JSON(200, gin.H{
"message": "ok",
"code": 200,
})
})
r.GET("/get", func(c *gin.Context) {
// get kv
// get from hazelcast
resp, err := mp.Get(c, "foo")
if err != nil {
c.JSON(500, gin.H{
"message": "get error",
"code": 500,
})
return
}
c.JSON(200, gin.H{
"message": "ok",
"code": 200,
})
})
r.GET("/get", func(c *gin.Context) {
// get kv
// get from hazelcast
resp, err := mp.Get(c, "foo")
if err != nil {
c.JSON(500, gin.H{
"message": "get error",
"code": 500,
})
return
}
c.JSON(200, gin.H{
"message": resp,
"code": 200,
})
})
r.Run(":8888")
}
func init() {
ctx := context.TODO()
cfg := hazelcast.Config{}
cfg.Cluster.Name = "hazelcast-benchmark"
// cfg.Cluster.Network.Addresses = []string{"192.168.168.176:5701"}
var err error
hz, err = hazelcast.StartNewClientWithConfig(ctx, cfg)
if err != nil {
panic(fmt.Errorf("starting the client with config: %w", err))
}
mp, err = hz.GetMap(ctx, "my-distributed-map")
if err != nil {
panic(fmt.Errorf("trying to get a map: %w", err))
}
}
同样地,我们编写yaml文件来部署这个golang程序,并携带上sidecar,如下所示。得益于k8s容器机制,如果是在同一个pod下的容器,则天然是共享同一个网络的,那么就可以直接基于localhost来进行通信。
apiVersion: apps/v1
kind: Deployment
metadata:
name: sidecar-test
spec:
replicas: 3
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
containers:
- name: test
image: lizhanbin/sidecar-test
imagePullPolicy: Always
ports:
- containerPort: 8888
- name: hazelcast
image: hazelcast/hazelcast:5.3.6
lifecycle:
type: Sidecar
env:
- name: HZ_CLUSTERNAME
value: hazelcast-benchmark
ports:
- name: hazelcast
containerPort: 5701
- name: mc
image: hazelcast/management-center:latest-snapshot
ports:
- name: mc
containerPort: 8080