草庐IT

使用Kubernetes的区块链案例

李睿 2023-03-29 原文

译者 | 李睿

审校 | 孙淑娟

为了说明如何使用Kubernetes,建议考虑本文介绍的区块链案例,并探讨为加密货币市场开发的应用程序。这个应用程序使用的技术是实用的,也可以用于其他项目。换句话说,技术任务是一个非常通用的解决方案,主要针对Kubernetes进行了专门调整,也可以用于其他行业。

使用的技术

该项目是一个启动项目,预算有限。而开发人员将定期为投资者提供演示,并定期展示开发新功能的进展情况。因此决定使用以下技术:

  • Node JS(NestJS 框架)
  • Postgre SQL数据库
  • Kafka JS
  • Kubernetes(k8s)+Helm图表
  • Flutter
  • React

开发过程

对于第一阶段,开发人员的主要目的是将其应用程序拆分为微服务。在这一案例中,决定创建6个微服务。

(1)管理微服务

(2)核心微服务

(3)支付微服务

(4)邮件和通知服务

(5)Cron任务服务

(6)Webhooks微服务

值得一提的是,虽然技术堆栈是实用的,并且可以在各种情况下使用而无需更改,但上述微服务却不是,它们是专门为这一项目中所需的功能而创建的。因此可以使用相同的技术,但必须根据需要设计新的微服务。

以下了解如何在NestJS上制作这些微服务。需要为Kafka消息代理进行配置选项。因此,为所有微服务的常用模块和配置创建了一个共享资源文件夹。

微服务配置选项

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

}

}

});

以消费者模式将管理面板微服务连接到Kafka。它将允许捕获和处理来自主题的事件。

使应用程序在微服务模式下工作,以便能够使用事件:

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

可以注意到消费者配置包含groupId。这是一个重要的选项,它将允许来自同一组的消费者从主题中获取事件,并将它们分发给彼此以更快地处理它们。

例如,假设微服务接收事件的速度快于处理它们的速度。在这种情况下,可以进行自动扩展以生成额外的pod以在它们之间共享负载,并使该过程加快两倍。

为了实现这一点,消费者应该在组中,并且在扩展之后,生成的pod也将在同一个组中。因此,他们将能够共享加载,而不是处理来自不同Kafka分区的相同主题事件。

以下了解一个如何在NestJS中捕获和处理Kafka事件的示例:

消费者控制器

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);

}

}

消费者可以在两种模式下工作。它接收事件并处理它们而不返回任何响应(EventPattern decorator),或者在处理事件后将响应返回给生产者(MessagePattern decorator)。EventPattern更好,如果可能的话应该是首选,因为它不包含任何额外的源代码层来提供请求/响应功能。

生产者呢?

对于连接生产者,需要为负责发送事件的模块提供生产者配置。

生产者连接

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 {}

基于事件的生产者

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'});

}

}

基于请求/响应的生产者

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;

}

}

每个微服务可以同时在两种模式(生产者/消费者)或两种模式(混合)下工作。通常情况下,微服务使用混合模式来达到负载平衡的目的,为主题生成事件并均匀地使用它们,共享负载。

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

Helm图表描述的Admin API微服务组件及其结构

该模板由几个配置文件组成:

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

以下来看每个配置文件(没有Helm模板)

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"

部署可以包含更多的精简配置,如资源限制、健康检查配置、更新策略等。但是提供了一个基本配置示例,可以根据任何其他项目的需要进行扩展。

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负载均衡器控制器。

然后,需要使用以下配置创建入口:

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”参数中提供的名称创建一个域,并将流量从该主机路由到负载均衡器。

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来制作模板:

Admin-API 部署(Helm图表)

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

Admin-API 服务(Helm图表)

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 }}

Admin-API自动扩展配置(Helm图表)

{{- 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的一些值的示例。

Admin-API Helm Values-Stage.yml File

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"

要在集群上应用配置,需要升级图表并重新启动部署。

以下检查负责此操作的GitHub Actions步骤。

在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微服务是如何构建的。

原文标题:Blockchain Case Using Kubernetes,作者:Tetiana Stoyk

有关使用Kubernetes的区块链案例的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  10. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

随机推荐