惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

豆逗子的小黑屋

GEMINI-CLI settings 参数详情 使用 sing-box Tun 模式实现 V2rayU 的透明代理 浅析 Claude Code 的执行与提示词 多模态模型是如何处理和理解图片的? 从配料表出发:便秘的猫应该怎么选主食 盘点开源的 DeepResearch 实现方案 浅谈 DeepSeek-R1 和 Kimi k1.5 论文中的思维链 + 强化学习 使用 TiDB Vector 构建 LightRAG 知识库 从论文到源码:详解 RAG 算法 云南之行——游在大理食在昆明 浅入浅出 Rerank 模型 一年同行:我的TiDB社区之旅 读书笔记《大语言模型》 TiDB Vector + Dify 快速构建 AI Agent 基于 LLM 推动游戏叙事 HTTP/2 和 CONTINUATION Flood 混合专家模型 (MoE) 笔记 报告分享: IMF第四次磋商报告 和 美联储研究笔记 使用 Coze 搭建 TiDB 助手 2023年总结 读书笔记《大规模语言模型:从理论到实践》 TiDB知识点梳理 (PCTA 笔记) 向量相似性检索方法 Java & Go 线程模式对比 Hugo + umami 博客统计面板 资产配置 101 探究 Spring-Boot 内置Server 为什么Spring可以“自己注入自己” Go语言指针性能 从固定走向浮动 ——《时运变迁》读书笔记 Netty 源码分析及内存溢出思路 博客搭建简述 推荐 笔记 看得见的手——《置身事内》读书笔记 2022年初读书回顾 荐书:《走出唯一真理观》 nintendo switch 关于 邮箱
搭建Go版本Kubernetes微服务示例
2023-07-20 · via 豆逗子的小黑屋

前言 #

此项目示例主要是参考Java版Kubernetes微服务示例,在业务需求相同的情况下,搭建一个Golang版本的Kubernetes项目

项目代码:Go微服务架构 Kubernetes

架构图 #

本项目和Java版本的示例类似架构,也是采用的DDD领域驱动设计,故架构图如下:

Untitled

模块 #

本项目分别采用了字节的kitex和hertz框架构建的微服务,具体的内容包括:

  • 框架方面,domain领域模块(account/payment/warehouse)采用的Kitex框架;gateway网关采用的**Hertz框架**,网关目前只做了简单的转发验签
  • 配置方面,使用https://github.com/spf13/viper读取 toml 文件,同时兼容了environment环境变量
  • 通信和序列化协议方面,account领域提供了RPC+Thrift协议进行内部服务间调用;payment和warehouse模块提供了RPC+Protobuf协议进行内部服务间调用;gateway模块提供了RESTful接口供外部前端模块使用

Kitex框架中序列化的代码生成,具体参考代码生成工具

技术组件 #

采用基于Kubernetes的微服务架构,其中的技术组件包括

  • 配置中心:采用的 Kubernetes 的 ConfigMap 来管理配置文件。在Kubernetes的 Deployment 中,将 ConfigMap 中的配置文件映射到Pod容器内,使用 viper 读取容器中配置文件并实现动态更新。
  • 服务发现:采用 Kubernetes 的Service 来管理,通过 Kubernetes 的 NameSpace 名称空间,使用 Service name 自动将 RPC 访问中的服务路由到对应容器。
  • 服务网关:仅用hertz框架搭建了一个简易的网关,只是进行简单的 restful 到 RPC 的请求转发,并使用Oauth中间键做权限校验。
  • 认证授权:采用Google OAuth2

镜像构建 #

DockerFile 中的镜像生成,将镜像构建和镜像运行分为了两步:

  • 使用golang:1.20镜像作为builder,编译构建微服务,产出二进制文件
  • 使用alpine镜像运行 builder 中产生的二进制文件

以gateway模块为例,具体的操作如下:

FROM golang:1.20 as builder

RUN mkdir /app
WORKDIR /app

ENV GO111MODULE=on \
    GOPROXY=https://goproxy.cn,direct \
    PORT=8888

COPY *.go ./
COPY go.mod go.sum ./
RUN go mod tidy
RUN CGO_ENABLED=0 go build -o bookstore-platform-gateway *.go

###################################################################
## Run container
FROM alpine:latest

RUN apk --no-cache add ca-certificates

RUN mkdir /app
WORKDIR /app
COPY conf/*.toml conf/
COPY --from=builder /app/bookstore-platform-gateway .

EXPOSE $PORT

## Run
CMD [ "./bookstore-platform-gateway" ]

运行程序 #

相比于《凤凰架构》中的原工程,这里仅支持 Skaffold 的方式运行。

Skaffold 是根据skaffold.yml中的配置来进行的,开发时 skaffold 通过dev指令来执行这些配置。

拓展 #

Kitex Protobuf 中使用 google.timestamp 的序列化问题 #

kitex 框架中 fastpb 部分对于 google.timestamp 的序列化暂无支持,具体 issue 可以追溯到 https://github.com/cloudwego/kitex/issues/835,这里通过 string 类型兼容了这一处理,具体操作如下:

import "google/protobuf/timestamp.proto";

message Payment {
  google.protobuf.Timestamp createTime = 1;
  string payId = 2;
  double totalPrice = 3;
  int64 expires = 4;
  string paymentLink = 5;
}
type Payment struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	CreateTime  *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=createTime,proto3" json:"createTime,omitempty"`
	PayId       string                 `protobuf:"bytes,2,opt,name=payId,proto3" json:"payId,omitempty"`
	TotalPrice  float64                `protobuf:"fixed64,3,opt,name=totalPrice,proto3" json:"totalPrice,omitempty"`
	Expires     int64                  `protobuf:"varint,4,opt,name=expires,proto3" json:"expires,omitempty"`
	PaymentLink string                 `protobuf:"bytes,5,opt,name=paymentLink,proto3" json:"paymentLink,omitempty"`
}

func (x *Payment) fastReadField1(buf []byte, _type int8) (offset int, err error) {
	value, offset, err := fastpb.ReadString(buf, _type)
	if err != nil {
		return offset, err
	}
	timestamp, _ := time.Parse(time.RFC3339Nano, value)
	x.CreateTime = &timestamppb.Timestamp{Seconds: timestamp.Unix(), Nanos: int32(timestamp.Nanosecond())}
	return offset, nil
}

func (x *Payment) fastWriteField1(buf []byte) (offset int) {
	if x.CreateTime == nil {
		return offset
	}
	timestamp := x.GetCreateTime().AsTime()
	offset += fastpb.WriteString(buf[offset:], 1, timestamp.Format(time.RFC3339Nano))
	return offset
}

func (x *Payment) sizeField1() (n int) {
	if x.CreateTime == nil {
		return n
	}
	timestamp := x.GetCreateTime().AsTime()
	n += fastpb.SizeString(1, timestamp.Format(time.RFC3339Nano))
	return n
}

Viper 读取 ConfigMap 配置 #

采用 Kubernetes ConfigMap 定义config.toml 配置文件,在使用 Kubernetes Deployment 构建过程中,将 ConfigMap 映射到 volumes ,并在 volumes 映射到 container 对应的配置文件目录。具体的操作示例如下:

## ConfigMap 定义配置配置文件config.toml
kind: ConfigMap
apiVersion: v1
metadata:
  name: gateway
  namespace: bookstore-microservices
data:
  config.toml: |-
    [account.client]
    connnum = 1
    hostport = ["account:8810"]

    [payment.client]
    connnum = 1
    hostport = ["payment:8812"]

    [warehouse.client]
    connnum = 1
    hostport = ["warehouse:8811"]

---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: bookstore-platform-gateway
  namespace: bookstore-microservices
  labels:
    app: gateway
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gateway
  template:
    metadata:
      labels:
        app: gateway
    spec:
      serviceAccountName: book-admin
      containers:
        - name: gateway
          image: icyfenix/bookstore-platform-gateway
          ports:
            - name: http-server
              containerPort: 8888
          env:
            - name: CONFIG_PATH
              value: /app/conf/config.toml
          ## volumes 映射到 container 中的配置文件目录
          volumeMounts:
            - name: config-volume
              mountPath: /app/conf
      ## 映射 configmap 到 volumes
      volumes:
        - name: config-volume
          configMap:
            name: gateway

微服务层面,使用 viper 读取对应的配置文件,具体操作如下:

func NewConfig() (v *viper.Viper) {
	v = viper.New()
	v.SetDefault(configPathKey, defaultConfigPath)
	defaultClientConfig(v)
	v.AutomaticEnv()
	// 通过ENV获取
	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
	v.SetTypeByDefaultValue(true)
	v.SetConfigFile(v.GetString(configPathKey))
	err := v.ReadInConfig()
	if err != nil {
		klog.CtxErrorf(context.Background(), err.Error())
	}
	v.WatchConfig()
	v.OnConfigChange(func(in fsnotify.Event) {
		klog.CtxErrorf(context.Background(), "Config file changed: %s", in.Name)
	})
	return
}

框架 #

参考 #

项目 #

文档 #

《凤凰架构》——基于Kubernetes的微服务架构

kitex 文档

hertz 文档

viper 读取 ConfigMap 配置

Kubernetes Deployment 添加 ConfigMap 和 Secret 配置映射