74·云原生进阶

Kubernetes 部署

kubernetesdeploymentserviceconfigmap

第74课:Go 应用 Kubernetes 部署

学习目标

  1. 理解 Kubernetes 部署的核心概念(Deployment, Service, ConfigMap)
  2. 学会为 Go Web 应用编写基本的 Deployment 和 Service YAML 文件
  3. 掌握使用 ConfigMap 管理应用配置的方法
  4. 能够使用 kubectl 命令完成应用的部署、更新和访问
  5. 了解 Kubernetes 部署的基本流程和最佳实践

核心概念

想象一下,你开发了一个非常棒的 Go Web 服务。现在,你想让它稳定地运行在成千上万的用户面前。直接在一台服务器上运行 go run main.go 是不可靠的,服务器可能会宕机,用户量增长也需要扩展。Kubernetes (K8s) 就是这样一个容器编排平台,它能帮你自动化地管理、扩展和修复你的应用。

在 K8s 中部署一个应用,我们主要和以下几个“角色”打交道:

  1. Deployment(部署):这是你的“应用管理员”。你告诉 Deployment 你希望同时运行多少个应用副本(比如 3 个),它负责保证始终有 3 个健康的实例在运行。如果某个实例挂了,它会自动拉起一个新的。你还可以用它来滚动更新你的应用版本,实现零停机升级。

  2. Service(服务):这是你的应用的“门卫”和“负载均衡器”。Pod(由 Deployment 创建的运行实例)的 IP 地址是动态变化的,不固定。Service 为你的应用提供一个稳定的访问入口(例如,一个固定的域名或 IP)。它将用户的流量均匀地分发到后端健康的 Pod 上。

  3. ConfigMap(配置图):这是应用的“外部配置中心”。通常我们把数据库连接串、API 密钥等配置信息从代码中分离出来。ConfigMap 可以以文件或环境变量的形式挂载到 Pod 中,这样修改配置就无需重新构建镜像。

简单流程:你编写 YAML 文件 -> kubectl 提交给 K8s API Server -> K8s 根据 YAML 创建 Deployment -> Deployment 创建和管理 Pod -> Service 为这些 Pod 创建统一入口

代码示例

我们假设有一个简单的 Go Web 应用,它从环境变量读取一个欢迎语。

1. Go 应用代码 (main.go)

package main

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

func main() {
	// 从环境变量获取欢迎语,如果没有则使用默认值
	greeting := os.Getenv("GREETING")
	if greeting == "" {
		greeting = "Hello from my Go app!"
	}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, greeting)
	})

	log.Println("Server starting on port 8080...")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

2. 构建 Docker 镜像 (Dockerfile)

# 构建阶段
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o main .

# 运行阶段
FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]

构建并推送镜像到镜像仓库(如Docker Hub):

docker build -t your-dockerhub-user/go-greeting-app:v1 .
docker push your-dockerhub-user/go-greeting-app:v1

3. Kubernetes 配置文件

  • configmap.yaml - 定义应用的配置

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: go-app-config # ConfigMap 的名字
    data:
      # 键值对,键名将成为环境变量名
      GREETING: "Welcome to the cloud-native Go world!"
    
  • deployment.yaml - 定义如何运行应用

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: go-greeting-deployment # Deployment 的名字
      labels:
        app: go-greeting # 用于关联 Service 的标签
    spec:
      replicas: 3 # 我们希望同时运行 3 个副本
      selector:
        matchLabels:
          app: go-greeting # 选择器,用于找到它管理的 Pod
      template: # 这是 Pod 的模板
        metadata:
          labels:
            app: go-greeting # Pod 的标签,必须与 selector 匹配
        spec:
          containers:
          - name: go-greeting-container
            image: your-dockerhub-user/go-greeting-app:v1 # 使用我们构建的镜像
            ports:
            - containerPort: 8080 # 容器暴露的端口
            env:
            - name: GREETING # 从 ConfigMap 设置环境变量
              valueFrom:
                configMapKeyRef:
                  name: go-app-config # 引用哪个 ConfigMap
                  key: GREETING # 引用 ConfigMap 中的哪个键
    
  • service.yaml - 定义如何访问应用

    apiVersion: v1
    kind: Service
    metadata:
      name: go-greeting-service # Service 的名字
    spec:
      type: LoadBalancer # 在云环境中通常会提供外部负载均衡器
      selector:
        app: go-greeting # 必须与 Deployment 中 Pod 的标签匹配!
      ports:
      - protocol: TCP
        port: 80 # Service 在集群内部暴露的端口
        targetPort: 8080 # 流量转发到 Pod 的哪个端口
    

4. 部署应用

# 1. 创建 ConfigMap
kubectl apply -f configmap.yaml

# 2. 创建 Deployment
kubectl apply -f deployment.yaml

# 3. 创建 Service
kubectl apply -f service.yaml

# 4. 查看状态
kubectl get deployments # 查看 Deployment 状态
kubectl get pods -l app=go-greeting # 通过标签查看关联的 Pod
kubectl get services # 查看 Service,获取外部 IP (EXTERNAL-IP)

# 5. 访问应用 (替换 EXTERNAL-IP)
# 在浏览器或使用 curl 访问 http://<EXTERNAL-IP>
# 你应该会看到:”Welcome to the cloud-native Go world!”

实践练习

  1. 基础部署:使用上面的 YAML 模板,修改镜像名为你自己的镜像仓库地址,将你的 Go 应用部署到 Kubernetes 集群(如 Minikube、Kind 或云厂商的 K8s 服务)。验证 kubectl get pods 显示 3 个运行中的 Pod。

    • 预期输出:3 个状态为 Running 的 Pod。
  2. 配置热更新:在不重新构建和部署镜像的情况下,更新 ConfigMap 中的 GREETING 值,然后重启 Pod 以使新配置生效。最后验证应用输出已改变。

    • 提示:使用 kubectl edit configmap go-app-config 或重新 kubectl apply -f configmap.yaml(需提前修改文件),然后用 kubectl rollout restart deployment/go-greeting-deployment 重启 Pod。
    • 预期输出:访问应用后看到新的欢迎语。
  3. 滚动更新:修改 Go 应用代码(例如,在欢迎语后添加一个版本号如 v2),构建新镜像 v2 并推送。然后更新 deployment.yaml 中的镜像标签为 v2 并执行 kubectl apply -f deployment.yaml。观察 Pod 的更新过程。

    • 预期输出kubectl get pods -w 会显示旧 Pod 逐渐终止,新 Pod 逐渐启动,整个过程应用服务不中断。

常见错误

  1. 标签选择器不匹配:这是最常见的错误!Deployment.spec.selector.matchLabelsPod.template.metadata.labelsService.spec.selector 三者必须使用完全相同的标签键值对。如果不匹配,Service 将无法找到 Pod,Deployment 也无法正确管理 Pod。
  2. 端口混淆:需要区分三种端口:
    • containerPort:容器内部监听的端口(代码中 ListenAndServe 的端口)。
    • port:Service 在集群内部暴露的端口。
    • targetPort:Service 将流量转发到 Pod 的哪个端口(通常等于 containerPort)。
  3. ConfigMap 未先创建:如果 Deployment 引用了一个还不存在的 ConfigMap,Pod 会启动失败。务必确保 kubectl apply 的顺序,或使用 --dry-run=client 检查。
  4. 镜像拉取失败:确保镜像名正确无误,并且 K8s 集群的节点能够访问到你的镜像仓库(如果是私有仓库,需要配置 imagePullSecrets)。

小结

本节课,我们学习了使用 Kubernetes 部署 Go 应用的三大核心组件:

  • Deployment:负责维护应用的副本数量,并管理 Pod 的生命周期,是实现高可用和滚动更新的基石。
  • Service:为动态的 Pod 集合提供一个稳定的网络访问入口,并实现负载均衡。
  • ConfigMap:将应用的配置信息与容器镜像解耦,便于管理和更新配置。

掌握这三个组件的 YAML 编写和 kubectl 的基本操作,你就具备了将 Go 应用部署到生产级 Kubernetes 环境的基础能力。记住,Kubernetes 的强大之处在于其声明式 API:你只需告诉它“你想要什么状态”,它就会自动努力达成并维持这个状态。接下来,你可以进一步探索 Ingress(管理外部 HTTP 访问)、Secret(管理敏感信息)和 PersistentVolume(管理存储)等更高级的概念。

练习编辑器

go
Loading...

继续学习

完成本课后,建议继续学习下一课「CLI 工具:Cobra」 以巩固所学知识。