golang Kubernetes微服务最佳实践演示插件podinfo的使用

Golang Kubernetes微服务最佳实践演示插件podinfo的使用

Podinfo简介

Podinfo是一个用Go编写的小型Web应用程序,展示了在Kubernetes中运行微服务的最佳实践。它被CNCF项目如Flux和Flagger用于端到端测试和研讨会。

podinfo-ui

主要特性

  • 健康检查(就绪和存活)
  • 中断信号上的优雅关闭
  • 用于秘密和配置映射的文件观察器
  • 使用Prometheus和Open Telemetry进行仪器化
  • 使用zap的结构化日志记录
  • 使用viper的12-factor应用
  • 故障注入(随机错误和延迟)
  • Swagger文档
  • Timoni、Helm和Kustomize安装程序
  • 使用Kubernetes Kind和Helm进行端到端测试
  • 使用Docker buildx和GitHub Actions的多架构容器镜像
  • 使用Sigstore cosign进行容器镜像签名
  • 嵌入容器镜像中的SBOM和SLSA Provenance
  • 使用govulncheck进行CVE扫描

Web API

  • GET / 打印运行时信息
  • GET /version 打印podinfo版本和git提交哈希
  • GET /metrics 返回HTTP请求持续时间和Go运行时指标
  • GET /healthz 由Kubernetes存活探针使用
  • GET /readyz 由Kubernetes就绪探针使用
  • POST /readyz/enable 向Kubernetes LB发出信号,表示此实例已准备好接收流量
  • POST /readyz/disable 向Kubernetes LB发出信号,停止向此实例发送请求
  • GET /status/{code} 返回状态代码
  • GET /panic 以退出代码255崩溃进程
  • POST /echo 将调用转发到后端服务并回显发布的内容
  • GET /env 将环境变量作为JSON数组返回
  • GET /headers 返回带有请求HTTP头的JSON
  • GET /delay/{seconds} 等待指定的时间段
  • POST /token 发行有效期为一分钟的JWT令牌
  • GET /token/validate 验证JWT令牌
  • GET /configs 返回带有安装在config卷中的配置映射和/或秘密的JSON
  • POST/PUT /cache/{key} 将发布的内容保存到Redis
  • GET /cache/{key} 如果键存在,则从Redis返回内容
  • DELETE /cache/{key} 如果存在,则从Redis删除键
  • POST /store 将发布的内容写入磁盘上的/data/hash并返回内容的SHA1哈希
  • GET /store/{hash} 如果存在,则返回文件/data/hash的内容
  • GET /ws/echo 通过websockets回显内容
  • GET /chunked/{seconds} 使用transfer-encoding类型chunked给出部分响应,然后等待指定的时间段
  • GET /swagger.json 返回API Swagger文档,用于Linkerd服务分析和Gloo路由发现

安装

要在Kubernetes上安装Podinfo,最低要求的版本是Kubernetes v1.23

Timoni安装

timoni -n default apply podinfo oci://ghcr.io/stefanprodan/modules/podinfo

Helm安装

从github.io安装:

helm repo add podinfo https://stefanprodan.github.io/podinfo

helm upgrade --install --wait frontend \
--namespace test \
--set replicaCount=2 \
--set backend=http://backend-podinfo:9898/echo \
podinfo/podinfo

helm test frontend --namespace test

helm upgrade --install --wait backend \
--namespace test \
--set redis.enabled=true \
podinfo/podinfo

从ghcr.io安装:

helm upgrade --install --wait podinfo --namespace default \
oci://ghcr.io/stefanprodan/charts/podinfo

Kustomize安装

kubectl apply -k github.com/stefanprodan/podinfo//kustomize

Docker安装

docker run -dp 9898:9898 stefanprodan/podinfo

持续交付

要在Kubernetes集群上安装podinfo并自动保持最新版本,您可以使用Flux。

在MacOS和Linux上使用Homebrew安装Flux CLI:

brew install fluxcd/tap/flux

安装Helm操作所需的Flux控制器:

flux install \
--namespace=flux-system \
--network-policy=false \
--components=source-controller,helm-controller

将podinfo的Helm存储库添加到您的集群,并配置Flux每十分钟检查一次新图表版本:

flux create source helm podinfo \
--namespace=default \
--url=https://stefanprodan.github.io/podinfo \
--interval=10m

创建一个podinfo-values.yaml文件:

cat > podinfo-values.yaml <<EOL
replicaCount: 2
resources:
  limits:
    memory: 256Mi
  requests:
    cpu: 100m
    memory: 64Mi
EOL

为在默认命名空间中部署podinfo创建一个Helm release:

flux create helmrelease podinfo \
--namespace=default \
--source=HelmRepository/podinfo \
--release-name=podinfo \
--chart=podinfo \
--chart-version=">5.0.0" \
--values=podinfo-values.yaml

要检查当前部署的版本:

flux get helmreleases -n default

要从集群中删除podinfo的Helm存储库和release:

flux -n default delete source helm podinfo
flux -n default delete helmrelease podinfo

更多关于golang Kubernetes微服务最佳实践演示插件podinfo的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang Kubernetes微服务最佳实践演示插件podinfo的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Kubernetes微服务最佳实践:Podinfo演示插件使用指南

Podinfo是一个轻量级的Go微服务示例,专门设计用于演示Kubernetes最佳实践。下面我将详细介绍如何使用Podinfo以及相关的Golang代码示例。

1. Podinfo概述

Podinfo提供以下功能:

  • HTTP和gRPC API端点
  • 指标导出(Prometheus格式)
  • 就绪/存活探针
  • 混沌测试注入
  • 配置管理
  • 结构化日志记录

2. 部署Podinfo

基本部署YAML

apiVersion: apps/v1
kind: Deployment
metadata:
  name: podinfo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: podinfo
  template:
    metadata:
      labels:
        app: podinfo
      annotations:
        prometheus.io/scrape: "true"
    spec:
      containers:
      - name: podinfo
        image: ghcr.io/stefanprodan/podinfo:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9898
        env:
        - name: PODINFO_UI_COLOR
          value: "#34577c"
        resources:
          limits:
            cpu: 2000m
            memory: 512Mi
          requests:
            cpu: 100m
            memory: 64Mi
        livenessProbe:
          httpGet:
            path: /healthz
            port: 9898
          initialDelaySeconds: 5
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /readyz
            port: 9898
          initialDelaySeconds: 5
          periodSeconds: 10

3. Golang客户端示例代码

HTTP客户端示例

package main

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"time"
)

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, "GET", "http://podinfo:9898", nil)
	if err != nil {
		panic(err)
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Response: %s\n", body)
}

gRPC客户端示例

package main

import (
	"context"
	"log"
	"time"

	pb "github.com/stefanprodan/podinfo/pkg/api/grpc"
	"google.golang.org/grpc"
)

func main() {
	conn, err := grpc.Dial("podinfo:9999", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()

	c := pb.NewPodinfoClient(conn)

	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	r, err := c.Status(ctx, &pb.StatusRequest{})
	if err != nil {
		log.Fatalf("could not get status: %v", err)
	}
	log.Printf("Status: %v", r)
}

4. 配置管理

Podinfo支持通过ConfigMap和环境变量配置:

package main

import (
	"log"
	"net/http"
	"os"
)

type Config struct {
	Color       string
	Message     string
	ServiceName string
}

func main() {
	cfg := Config{
		Color:       getEnv("PODINFO_UI_COLOR", "#34577c"),
		Message:     getEnv("PODINFO_UI_MESSAGE", "Welcome to Podinfo"),
		ServiceName: getEnv("PODINFO_SERVICE_NAME", "podinfo"),
	}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(cfg.Message))
	})

	log.Fatal(http.ListenAndServe(":9898", nil))
}

func getEnv(key, fallback string) string {
	if value, ok := os.LookupEnv(key); ok {
		return value
	}
	return fallback
}

5. 健康检查实现

Podinfo的健康检查实现示例:

package main

import (
	"net/http"
	"sync/atomic"
)

var readiness int32

func main() {
	http.HandleFunc("/healthz", healthz)
	http.HandleFunc("/readyz", readyz)
	http.ListenAndServe(":9898", nil)
}

func healthz(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	w.Write([]byte("OK"))
}

func readyz(w http.ResponseWriter, r *http.Request) {
	if atomic.LoadInt32(&readiness) == 1 {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("OK"))
	} else {
		w.WriteHeader(http.StatusServiceUnavailable)
	}
}

// 在应用初始化完成后调用
func setReady() {
	atomic.StoreInt32(&readiness, 1)
}

6. 指标监控

使用Prometheus客户端库暴露指标:

package main

import (
	"net/http"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

var (
	requestsTotal = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "http_requests_total",
			Help: "Total number of HTTP requests",
		},
		[]string{"method", "path", "status"},
	)
)

func init() {
	prometheus.MustRegister(requestsTotal)
}

func main() {
	http.Handle("/metrics", promhttp.Handler())
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		requestsTotal.WithLabelValues(r.Method, r.URL.Path, "200").Inc()
		w.Write([]byte("Hello World"))
	})
	http.ListenAndServe(":9898", nil)
}

7. 最佳实践总结

  1. 资源限制:始终为容器设置资源请求和限制
  2. 健康检查:实现存活和就绪探针
  3. 配置分离:使用ConfigMap和Secret管理配置
  4. 监控:暴露Prometheus格式的指标
  5. 优雅终止:处理SIGTERM信号实现优雅关闭
  6. 安全:使用非root用户运行容器
  7. 日志:输出结构化日志
  8. 滚动更新:配置适当的更新策略

Podinfo是一个优秀的Kubernetes微服务示例,展示了这些最佳实践的实际应用。通过研究其源代码和部署方式,可以学习到如何在Golang中构建生产就绪的Kubernetes微服务。

回到顶部