背景:在 Spring Boot
中整合akka集群。现在需要将其部署在k8s中。
以下仅是一个节点的配置过程。若存在多个节点,则需要配置多次。
假设当前项目为3个akka节点。则在kubernetes中结构为:
management
和 bootstrap
自动发现代码
@configuration
)ActorSystem.create
创建 actorSystem
@Resource
注入; public void init(){
AkkaManagement.get(actorSystem).start();
ClusterBootstrap.get(actorSystem).start();
}
public class MyhealthCheck implements Supplier<CompletionStage<Boolean>> {
private final Cluster cluster;
public ClusterCheck(ActorSystem system) {
cluster = Cluster.get(system);
}
@Override
public CompletionStage<Boolean> get() {
return CompletableFuture.completedFuture(cluster.selfMember().status() == MemberStatus.up());
}
}
apiVersion: apps/v1 #必选,版本号,例如v1
kind: Deployment #必选,Pod
metadata: #必选,元数据
labels: #自定义标签
app: appka-test
name: appka-test
namespace: appka-1
spec: #必选,Pod中容器的详细定义
replicas: 1
selector:
matchLabels:
app: appka-test
template:
metadata: # 资源的元数据/属性
labels: # 设定资源的标签
app: appka-test
actorSystemName: appka-test
spec:
containers: #必选,Pod中容器列表
- name: appka-test # 容器的名字
image: appka-test-k8s:latest # 容器使用的镜像地址
readinessProbe: # Pod 准备服务健康检查设置
httpGet: # 通过httpget检查健康,返回200-399之间,则认为容器正常
path: "/ready"
port: management
periodSeconds: 10 # 检查间隔时间
failureThreshold: 3 # 失败门槛,连接失败5次,pod杀掉,重启一个新的pod
initialDelaySeconds: 10 # 表明第一次检测在容器启动后多长时间后开始
livenessProbe: # pod 内部健康检查的设置
httpGet:
path: "/alive"
port: management
periodSeconds: 10
failureThreshold: 5
initialDelaySeconds: 20
ports: #需要暴露的端口库号列表
# akka remoting
- name: remoting
containerPort: 2552 #容器需要监听的端口号
protocol: TCP #端口协议,支持TCP和UDP,默认TCP
# akka-management and bootstrap
- name: management
containerPort: 8558
protocol: TCP
- name: http
containerPort: 8080
protocol: TCP
env: #容器运行前需设置的环境变量列表
- name: NAMESPACE #环境变量名称
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: REQUIRED_CONTACT_POINT_NR
value: "2"
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: pod-reader
namespace: appka-1
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: read-pods
namespace: appka-1
subjects:
# serviceAccount是用于控制对Kubernetes API的访问的一种身份验证机制。
# 每个命名空间默认有一个名为default的服务账号,当你不指定服务账号时,Kubernetes会默认使用这个账号。
# 这种指定方式有助于明确哪些资源可以访问,从而提高系统的安全性。
# 在某些情况下,可能需要创建和使用自定义的服务账号,以便更好地控制资源的访问。
- kind: User
name: system:serviceaccount:appka-1:default
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
tips:
appka-test
需要适配自己的项目名appka-1
命名空间 namespace 需要自己适配containers.image
容器镜像:需要项目自定义部署subjects.name
: 服务账号;其中 appka-1 是命名空间。若需自定义,需要注意!kind: Role
角色配置次数选择官网默认。
conf
文件配置coordinated-shutdown.exit-jvm = on
CoordinatedShutdown
自动运行,将所有组件和资源关闭,包括终止JVM进程。allow-java-serialization
: 设置 允许使用Java序列化来序列化和反序列化Akka的消息 akka.actor.provider = "cluster"
设置akka集群模式shutdown-after-unsuccessful-join-seed-nodes
contact-point-discovery
节点 发现配置
kubernetes-api
akka {
loglevel = "DEBUG"
coordinated-shutdown.exit-jvm = on
actor {
allow-java-serialization = on
provider = "cluster"
}
cluster {
shutdown-after-unsuccessful-join-seed-nodes = 60s
downing-provider-class = "akka.cluster.sbr.SplitBrainResolverProvider"
}
}
akka.management {
cluster.bootstrap {
contact-point-discovery {
// ; k8s 服务发现的名称, 自定义
service-name = "%s"
discovery-method = kubernetes-api
required-contact-point-nr = 2
// ; akka组成集群最少节点数
required-contact-point-nr = ${?REQUIRED_CONTACT_POINT_NR}
}
}
}
akka.management {
health-checks {
readiness-checks {
// ; 健康探测的类
example-ready = "com.src.akka.check.MyhealthCheck"
}
}
}
Akka Management HTTP 的默认配置适合在 Kubernetes 中使用,它将绑定到 Pod 外部 IP 地址上的默认端口 8558。
配置完成后,需要对不同的节点打jar包,创建对应的docker镜像,进而部署至不同的pod中。
下面是后续需要考虑的问题。(皆来自官网)
配置后 akka-cluster在k8s还可能存在其他问题:
集群节点发现方式若两者其中有一个挂掉(如:a挂掉),a重新加入集群后,是否产生新的集群?
【脑裂】akka cluster split-brain-resolver(SBR)_lease-majority-CSDN博客
k8s 不同的pod ip不一样。若其中一个节点挂掉,重启pod会改变ip,但akka 集群会继续连接该ip
解决方式:配置相关策略
主要参考官网的部署步骤:
Deploying Akka Cluster to Kubernetes
学习文章:
Akka 集群如何部署到 k8s 中,实现自动发现管理节点 – 墨烟客 – 不只是代码,更是文学