基于K8s技术构建通用的区块链方案

译文 精选
开发 区块链
一文展示如何使用Kubernetes和微服务架构,来构建一个具有复杂功能的加密支付应用的示例。

译者 | 陈峻

审校 | 云昭

本文简要展示了如何使用Kubernetes和微服务架构,来构建一个具有复杂功能的加密支付应用的示例。  Kubernetes已在当前各类Web应用中得到了广泛使用。那么,开发者想过它是否可以被应用到加密支付类型的应用开发之中呢?下面,我将向开发者展示如何使用Kubernetes技术,构建通用的区块链应用解决方案的过程。通过调整,该方案也可以被用于其他行业的应用场景中。

涉及到的技术

该项目在初期虽然预算有限,但是在被客户认可后,为了定期向投资人演示新功能的开发进展,我们进行了持续迭代。下面便是我们使用到的技术:

  • Node JS(NestJS框架)
  • PostgreSQL数据库
  • Kafka JS
  • Kubernetes(K8s)+ Helm charts
  • Flutter
  • React

开发过程

在第一阶段,我们的主要目的是将待开发的应用,拆分并创建为如下六个微服务:1.管理微服务2.核心微服务3.支付微服务4.邮件和通知服务5.Cron任务服务6.Webhooks微服务

值得一提的是,这六个微服务是专为本区块链应用示例而创建的。如果开发者的应用在本质上不尽相同,则可以使用相同的技术,按需设计出不同的微服务。

接着,让我们来看看如何在NestJS上构建这些微服务。由于我们需要针对Kafka消息的代理,来配置相关的选项,因此我们为所有微服务的公共模块和配置,创建了一个共享的资源文件夹。

1.微服务的配置选项

import { ClientProviderOptions, Transport } from '@nestjs/microservices';
import CONFIG from '@application-config';
import { ConsumerGroups, ProjectMicroservices } from './microservices.enum';
const { BROKER_HOST, BROKER_PORT } = CONFIG.KAFKA;
export const PRODUCER_CONFIG = (name: ProjectMicroservices): ClientProviderOptions => ({
name,
transport: Transport.KAFKA,
options: {
client: {
brokers: [`${BROKER_HOST}:${BROKER_PORT}`],
},
}
});
export const CONSUMER_CONFIG = (groupId: ConsumerGroups) => ({
transport: Transport.KAFKA,
options: {
client: {
brokers: [`${BROKER_HOST}:${BROKER_PORT}`],
},
consumer: {
groupId
}
}
});

左右滑动查看完整代码

让我们通过consumer模式,将管理面板的微服务连接到Kafka上。它将允许我们去捕捉和处理来自各个主题的事件。

然后,我们通过如下代码,使应用程序能够在微服务的模式下消费(使用)事件:

app.connectMicroservice(CONSUMER_CONFIG(ConsumerGroups.ADMIN)); await app.startAllMicroservices();

开发者可能已注意到,consumer的配置中包含了groupId。它会允许来自同一组的consumer从主题中获取事件,并将它们分发给彼此,以更快地对其进行处理。假设我们的微服务能够接收到事件的速度,快于它处理事件的速度,那么我们便可以通过自动扩展以生成额外的pod的方式,来共享它们之间的负载,并且让该过程的速度翻倍。为此,consumer应该被置于组中,并将由扩展生成的pod也放在同一组中。在此基础上,它们将能够共享加载,而不必处理来自不同Kafka分区的相同主题事件。下面,让我们来看看如何在NestJS中捕捉和处理Kafka事件:

2.用户控制器

import { Controller } from '@nestjs/common';
import { Ctx, KafkaContext, MessagePattern, EventPattern, Payload } from '@nestjs/microservices';
@Controller('consumer')
export class ConsumerController {
@MessagePattern('hero')
readMessage(@Payload() message: any, @Ctx() context: KafkaContext) {
return message;
}
@EventPattern('event-hero')
sendNotif(data) {
console.log(data);
}
}

左右滑动查看完整代码

通常,consumer可以在两种模式下工作:

  • EventPattern decorator--接收并处理各种事件,但不返回任何响应
  • MessagePattern decorator--在处理事件后,将响应返回给producer

由于EventPattern不需要额外地包含任何源代码层,便可提供请求/响应功能,因此如果可能的话,它应该被作为首选项。

配置Producer

为了连接Producer,我们需要为负责发送事件的模块,提供Producer的相关配置。

1.Producer连接

import { Module } from '@nestjs/common';
import DatabaseModule from '@shared/database/database.module';
import { ClientsModule } from '@nestjs/microservices';
import { ProducerController } from './producer.controller';
import { PRODUCER_CONFIG } from '@shared/microservices/microservices.config';
import { ProjectMicroservices } from '@shared/microservices/microservices.enum';
@Module({
imports: [
DatabaseModule,
ClientsModule.register([PRODUCER_CONFIG(ProjectMicroservices.ADMIN)]),
],
controllers: [ProducerController],
providers: [],
})
export class ProducerModule {}

左右滑动查看完整代码

2.基于事件的Producer

import { Controller, Get, Inject } from '@nestjs/common';
import { ClientKafka } from '@nestjs/microservices';
import { ProjectMicroservices } from '@shared/microservices/microservices.enum';
@Controller('producer')
export class ProducerController {
constructor(
@Inject(ProjectMicroservices.ADMIN)
private readonly client: ClientKafka,
) {}
@Get()
async getHello() {
this.client.emit('event-hero', { msg: 'Event Based'});
}
}

左右滑动查看完整代码

3.基于请求/响应的Producer

import { Controller, Get, Inject } from '@nestjs/common';
import { ClientKafka } from '@nestjs/microservices';
import { ProjectMicroservices } from '@shared/microservices/microservices.enum';
@Controller('producer')
export class ProducerController {
constructor(
@Inject(ProjectMicroservices.ADMIN)
private readonly client: ClientKafka,
) {}
async onModuleInit() {
// Need to subscribe to a topic
// to make the response receiving from Kafka microservice possible
this.client.subscribeToResponseOf('hero');
await this.client.connect();
}
@Get()
async getHello() {
const responseBased = this.client.send('hero', { msg: 'Response Based' });
return responseBased;
}
}

左右滑动查看完整代码

每个微服务既可以工作在Producer或Consumer模式下,也可以同时工作在两种混合模式中。通常,微服务使用混合模式来实现负载平衡,为主题生成事件,并均匀地使用它们,以及共享各种负载。

下图是针对每个微服务的实现,而进行的基于Helm图表模板的Kubernetes配置。

图片

用Helm图表表示的admin-API微服务的组件及其结构

该模板由如下配置文件所组成:

  • 部署
  • 水平pod自动扩展(hpa)
  • 入口控制器
  • 服务

下面,让我们来看看每个配置文件(并不涉及到Helm模板)。

4.Admin-API部署

apiVersion: apps/v1
kind: Deployment
metadata:
name: admin-api
spec:
replicas: 1
selector:
matchLabels:
app: admin-api
template:
metadata:
labels:
app: admin-api
spec:
containers:
- name: admin-api
image: xxx208926xxx.dkr.ecr.us-east-1.amazonaws.com/project-name/stage/admin-api
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: 250m
memory: 512Mi
ports:
- containerPort: 80
env:
- name: NODE_ENV
value: production
- name: APP_PORT
value: "80"

左右滑动查看完整代码

在真实的项目部署中,我们可能还需要包含诸如:资源限制、运行状况检查配置、更新策略等更多细节配置。在此,我们仅提供了一个基本的配置示例。开发者可以根据手头项目的实际情况,按需进行扩展。

5.Admin-API服务

---
apiVersion: v1
kind: Service
metadata:
name: admin-api
spec:
selector:
app: admin-api
ports:
- name: admin-api-port
port: 80
targetPort: 80
protocol: TCP
type: NodePort

左右滑动查看完整代码

显然,我们需要对外公开其服务,才能使用它。让我们通过一个负载平衡器,来公开该应用程序,并提供SSL的相关配置,以方便使用安全的HTTPS连接。在此,我们选用时下最流行的解决方案:AWS负载平衡控制器,并安装到集群上。

接着,我们需要使用以下配置,来创建入口控制器:

6.Admin-API入口控制器

apiVersion: networking.K8s.io/v1
kind: Ingress
metadata:
namespace: default
name: admin-api-ingress
annotations:
alb.ingress.kubernetes.io/load-balancer-name: admin-api-alb
alb.ingress.kubernetes.io/ip-address-type: ipv4
alb.ingress.kubernetes.io/tags: Environment=production,Kind=application
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-east-2:xxxxxxxx:certificate/xxxxxxxxxx
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
alb.ingress.kubernetes.io/healthcheck-protocol: HTTPS
alb.ingress.kubernetes.io/healthcheck-path: /healthcheck
alb.ingress.kubernetes.io/healthcheck-interval-seconds: '15'
alb.ingress.kubernetes.io/ssl-redirect: '443'
alb.ingress.kubernetes.io/group.name: admin-api
spec:
ingressClassName: alb
rules:
- host: example.com
http:
paths:
- path: /*
pathType: ImplementationSpecific
backend:
service:
name: admin-api
port:
number: 80

左右滑动查看完整代码

在应用了上述配置以后,我们将能够创建一个新的ALB负载平衡器。同时,我们需要使用在'host'参数中提供的名称,来创建一个域,进而将流量从该host,路由到负载平衡器上。

7.Admin-API自动扩展配置

apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: admin-api-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: admin-api
minReplicas: 1
maxReplicas: 2
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 90

左右滑动查看完整代码

有关Helm

在我们需要降低K8s基础设施的复杂性时,Helm是一个非常实用的工具。没有它,我们则需要在集群运行之前,编写多个yml文件。此外,Helm也能够协助我们记住应用程序、标签、以及名称等之间的关系。它的工作原理与包管理器比较类似,允许我们创建应用程序的模板,并可使用简单的命令来准备和运行它。下面,让我们来使用helm制作自己的模板:

1.Admin-API的部署(Helm charts)

apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.appName }}
spec:
replicas: {{ .Values.replicas }}
selector:
matchLabels:
app: {{ .Values.appName }}
template:
metadata:
labels:
app: {{ .Values.appName }}
spec:
containers:
- name: {{ .Values.appName }}
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.internalPort }}
{{- with .Values.env }}
env: {{ tpl (. | toYaml) $ | nindent 12 }}
{{- end }}

左右滑动查看完整代码

2.Admin-API的服务(Helm charts)

apiVersion: v1
kind: Service
metadata:
name: {{ .Values.global.appName }}
spec:
selector:
app: {{ .Values.global.appName }}
ports:
- name: {{ .Values.global.appName }}-port
port: {{ .Values.externalPort }}
targetPort: {{ .Values.internalPort }}
protocol: TCP
type: NodePort

左右滑动查看完整代码

3.Admin-API的入口(Helm charts)

apiVersion: networking.K8s.io/v1
kind: Ingress
metadata:
namespace: default
name: ingress
annotations:
alb.ingress.kubernetes.io/load-balancer-name: {{ .Values.ingress.loadBalancerName }}
alb.ingress.kubernetes.io/ip-address-type: ipv4
alb.ingress.kubernetes.io/tags: {{ .Values.ingress.tags }}
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/certificate-arn: {{ .Values.ingress.certificateArn }}
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
alb.ingress.kubernetes.io/healthcheck-protocol: HTTPS
alb.ingress.kubernetes.io/healthcheck-path: {{ .Values.ingress.healthcheckPath }}
alb.ingress.kubernetes.io/healthcheck-interval-seconds: {{ .Values.ingress.healthcheckIntervalSeconds }}
alb.ingress.kubernetes.io/ssl-redirect: '443'
alb.ingress.kubernetes.io/group.name: {{ .Values.ingress.loadBalancerGroup }}
spec:
ingressClassName: alb
rules:
- host: {{ .Values.adminApi.domain }}
http:
paths:
- path: {{ .Values.adminApi.path }}
pathType: ImplementationSpecific
backend:
service:
name: {{ .Values.adminApi.appName }}
port:
number: {{ .Values.adminApi.externalPort }}

4.Admin-API的自动扩展配置(Helm charts)

{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "ks.fullname" . }}
labels:
{{- include "ks.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "ks.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end }}

左右滑动查看完整代码

不同模板的值分别位于“Values.yml”、“Values-dev.yml”和“Values stage.yml”文件中。具体它们中的哪一个将被使用到,则完全取决于真实的应用环境。下面,让我们来查看针对dev env(开发环境)的一些示例值。

5.Admin-API Helm的Values-Stage.yml文件

env: stage
appName: admin-api
domain: admin-api.xxxx.com
path: /*
internalPort: '80'
externalPort: '80'
replicas: 1
image:
repository: xxxxxxxxx.dkr.ecr.us-east-2.amazonaws.com/admin-api
pullPolicy: Always
tag: latest
ingress:
loadBalancerName: project-microservices-alb
tags: Environment=stage,Kind=application
certificateArn: arn:aws:acm:us-east-2:xxxxxxxxx:certificate/xxxxxx
healthcheckPath: /healthcheck
healthcheckIntervalSeconds: '15'
loadBalancerGroup: project-microservices
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
env:
- name: NODE_ENV
value: stage
- name: ADMIN_PORT
value: "80"

左右滑动查看完整代码

为了在集群上应用相关的配置,我们需要升级charts,并重新启动部署。

下面,让我们在来看看负责此项操作的GitHub的相关操作步骤。

6.在GitHub的各项操作中应用Helm配置

env: stage
appName: admin-api
domain: admin-api.xxxx.com
path: /*
internalPort: '80'
externalPort: '80'
replicas: 1
image:
repository: xxxxxxxxx.dkr.ecr.us-east-2.amazonaws.com/admin-api
pullPolicy: Always
tag: latest
ingress:
loadBalancerName: project-microservices-alb
tags: Environment=stage,Kind=application
certificateArn: arn:aws:acm:us-east-2:xxxxxxxxx:certificate/xxxxxx
healthcheckPath: /healthcheck
healthcheckIntervalSeconds: '15'
loadBalancerGroup: project-microservices
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
env:
- name: NODE_ENV
value: stage
- name: ADMIN_PORT
value: "80"

小结

综上所述,我们深入研究了如何在一个特定的加密支付的案例中,使用Kubernetes来构建微服务,并最终将代码示例转换为一个成熟的区块链应用的过程。虽然我们跳过了一些其它步骤和组件,但是前面的源代码足以向开发者展示和诠释Kubernetes微服务是如何构建的。

原文链接:https://dzone.com/articles/blockchain-case-using-kubernetes

译者介绍

陈峻 (Julian Chen),51CTO社区编辑,具有十多年的IT项目实施经验,善于对内外部资源与风险实施管控,专注传播网络与信息安全知识与经验。

责任编辑:薛彦泽 来源: 51CTO
相关推荐

2017-04-18 09:36:36

OpenStackK8SEasyStack

2021-11-04 07:49:58

K8SStatefulSetMySQL

2020-08-27 14:59:08

K8sDevOps平台

2024-02-01 09:48:17

2022-04-22 13:32:01

K8s容器引擎架构

2023-11-06 07:16:22

WasmK8s模块

2023-01-26 14:05:05

2022-05-06 14:03:18

区块链NFT加密货币

2023-12-25 07:35:40

数据集成FlinkK8s

2022-04-07 10:17:18

云原生服务器优化

2022-07-04 11:28:14

RancherK8s集群云计算

2019-01-18 05:22:39

区块链智能合约网络安全

2021-09-16 11:15:21

区块链环境技术

2023-09-06 08:12:04

k8s云原生

2021-09-12 22:23:14

区块链比特币技术

2018-03-27 09:52:30

区块链数字货币比特币

2021-12-17 14:15:44

区块链游戏技术

2020-12-17 08:00:00

区块链数据以太坊

2023-02-06 07:47:23

2023-11-02 08:01:22

点赞
收藏

51CTO技术栈公众号