在Kubernetes容器中运行Golang测试的最佳实践
在Kubernetes容器中运行Golang测试的最佳实践 我大量使用 Kubernetes,并且有一些测试依赖于投射服务账户令牌卷。这意味着我必须在 Kubernetes Pod 内部运行我的集成测试。
我使用 Skaffold 来部署 Pod,但 Skaffold 希望 Pod 永远运行,因此当 Pod 退出时,它会报错并退出。
我想我会把它转换成一个 Job,但我想知道是否有更好的方法来解决这个问题。有没有人遇到过投射服务账户令牌卷的类似问题,并找到了好的解决方案?
1 回复
更多关于在Kubernetes容器中运行Golang测试的最佳实践的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在 Kubernetes Pod 中运行 Go 测试时,使用 Job 确实是标准做法。以下是具体实现方案:
1. 创建测试专用的 Job 配置
# test-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: go-integration-test
spec:
ttlSecondsAfterFinished: 3600 # 完成后1小时自动清理
backoffLimit: 0 # 失败不重试
template:
spec:
serviceAccountName: test-service-account # 使用有权限的SA
automountServiceAccountToken: true # 自动挂载令牌
containers:
- name: test-runner
image: golang:1.21-alpine
command: ["go", "test", "./...", "-v", "-count=1"]
volumeMounts:
- name: serviceaccount
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
readOnly: true
env:
- name: KUBERNETES_SERVICE_HOST
value: "kubernetes.default.svc"
- name: KUBERNETES_SERVICE_PORT
value: "443"
workingDir: /app
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
restartPolicy: Never
volumes:
- name: serviceaccount
projected:
sources:
- serviceAccountToken:
path: token
expirationSeconds: 3600
audience: api
2. Go 测试代码示例
// integration_test.go
package main
import (
"fmt"
"io/ioutil"
"os"
"testing"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
func TestKubernetesIntegration(t *testing.T) {
// 使用 Pod 内的服务账户令牌
tokenPath := "/var/run/secrets/kubernetes.io/serviceaccount/token"
// 读取服务账户令牌
token, err := ioutil.ReadFile(tokenPath)
if err != nil {
t.Fatalf("Failed to read service account token: %v", err)
}
// 创建 Kubernetes 客户端配置
config, err := rest.InClusterConfig()
if err != nil {
t.Fatalf("Failed to create in-cluster config: %v", err)
}
// 创建客户端
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
t.Fatalf("Failed to create kubernetes client: %v", err)
}
// 测试 Kubernetes API 访问
_, err = clientset.CoreV1().Namespaces().List(context.Background(), metav1.ListOptions{})
if err != nil {
t.Fatalf("Failed to list namespaces: %v", err)
}
t.Log("Successfully authenticated with Kubernetes API")
}
func TestWithServiceAccount(t *testing.T) {
// 验证令牌文件存在
if _, err := os.Stat("/var/run/secrets/kubernetes.io/serviceaccount/token"); os.IsNotExist(err) {
t.Fatal("Service account token not found")
}
// 验证 CA 证书存在
if _, err := os.Stat("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"); os.IsNotExist(err) {
t.Fatal("CA certificate not found")
}
// 验证命名空间文件存在
namespace, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
if err != nil {
t.Fatalf("Failed to read namespace: %v", err)
}
t.Logf("Running in namespace: %s", string(namespace))
}
3. 使用 Skaffold 运行测试 Job
# skaffold.yaml
apiVersion: skaffold/v4beta1
kind: Config
profiles:
- name: test
test:
- image: go-test-image
context: .
custom:
- command: kubectl apply -f test-job.yaml
- command: kubectl wait --for=condition=complete job/go-integration-test --timeout=300s
- command: kubectl logs job/go-integration-test --tail=-1
- command: kubectl delete -f test-job.yaml
4. 使用 Makefile 简化流程
.PHONY: test-integration
test-integration:
kubectl apply -f test-job.yaml
kubectl wait --for=condition=complete job/go-integration-test --timeout=300s
kubectl logs job/go-integration-test --tail=-1
kubectl delete -f test-job.yaml
.PHONY: test-debug
test-debug:
kubectl run go-test-debug \
--image=golang:1.21-alpine \
--serviceaccount=test-service-account \
--restart=Never \
--command -- sh -c "apk add git && git clone https://github.com/your/repo.git /app && cd /app && go test ./... -v"
kubectl logs -f go-test-debug
5. 使用测试容器镜像
# Dockerfile.test
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go test -c -o /test-runner ./cmd/test
FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder /test-runner /test-runner
COPY --from=builder /var/run/secrets/kubernetes.io/serviceaccount /var/run/secrets/kubernetes.io/serviceaccount
ENTRYPOINT ["/test-runner"]
这种方案确保了测试在真实的 Kubernetes 环境中运行,能够正确访问投射的服务账户令牌卷,同时通过 Job 的完成状态明确测试结果。

