Kubernetes 如何部署微服务?

文章导读
Previous Quiz Next 作为开发者,我们不断努力使我们的应用程序更具可扩展性、模块化和易于管理。微服务架构通过将大型单体应用程序分解为更小的、独立可部署的服务来帮助我们实现这一目标。而在管理这些服务和扩展它们时,Kubernetes 是首选平台。
📋 目录
  1. 什么是微服务?
  2. 前提条件
  3. 微服务演示应用
  4. 准备 Docker 镜像
  5. 创建 Backend Deployment
  6. 创建 Frontend Deployment
  7. 验证 Microservices
  8. 扩展 Services
  9. 监控和日志
  10. 可选:添加 Network Policies 或 Ingress
A A

Kubernetes - 部署微服务



Previous
Quiz
Next

作为开发者,我们不断努力使我们的应用程序更具可扩展性、模块化和易于管理。微服务架构通过将大型单体应用程序分解为更小的、独立可部署的服务来帮助我们实现这一目标。而在管理这些服务和扩展它们时,Kubernetes 是首选平台。

在本指南中,我们将逐步讲解如何在 Kubernetes 集群上部署一个基本的微服务应用程序。我们将涵盖设置、服务部署以及它们之间的通信方式。让我们开始吧!

什么是微服务?

在动手之前,让我们快速了解一下微服务是什么。与构建一个单一的大型应用程序(称为单体应用)不同,我们可以将它分解为小型、自包含的服务。每个服务只负责一件事——比如用户管理、支付或产品目录——并通过 API(通常是 REST 或 gRPC)与其他服务通信。

每个微服务:

  • 可以独立开发和部署
  • 拥有自己的数据库或存储
  • 可以独立扩展

这为我们提供了灵活性和故障隔离——如果一个服务失败,整个应用程序不会崩溃。

前提条件

在部署之前,我们需要以下内容:

  • 一个运行中的 Kubernetes 集群(Minikube、KIND 或基于云的如 GKE/EKS/AKS)
  • 已安装并配置的 kubectl
  • Docker(如果需要构建和推送 image)
  • YAML 和 Kubernetes 对象(Deployments、Services 等)的基本知识

如果您是 Minikube 或 KIND 的新手,请查看我们之前的章节来设置它们。

微服务演示应用

我们将部署一个简单的应用,包含两个微服务:

  • frontend-service:基于 Node.js 或 Python 的 Web 前端。
  • backend-service:返回数据的 API——比如产品列表。

我们将对它们进行容器化,在各自的 pod 中部署,并暴露它们,以便它们能在集群内通信。

准备 Docker 镜像

假设我们已经准备好了两个 Docker 镜像:

  • neviillle/backend:1.0
  • neviillle/frontend:1.0

您也可以查看我们之前的章节,了解如何设置 Docker 镜像。

构建并推送 Docker 镜像:

# 后端

$ cd backend/
$ docker build -t neviillle/backend:1.0 .

Output:
[+] Building 41.8s (10/10) FINISHED                                            docker:default
 => [internal] load build definition from Dockerfile                                     0.0s
 => => transferring dockerfile: 169B                                                     0.0s
 => [internal] load metadata for docker.io/library/python:3.9-slim                      30.7s
 => [internal] load .dockerignore                                                        0.0s
 => => transferring context: 2B                                                          0.0s
 => [1/5] FROM docker.io/library/python:3.9-slim@sha256:9aa5793609640ecea2f06451a0d6f37  4.9s
 => => resolve docker.io/library/python:3.9-slim@sha256:9aa5793609640ecea2f06451a0d6f37  0.0s

$ docker push neviillle/backend:1.0
Output:
970f7cb6a2b1: Pushed 
c79ef58278e8: Pushed 
2c39b83bbed7: Pushed 
e0d134baee1f: Pushed

# 前端

$ cd frontend/
$ docker build -t neviillle/frontend:1.0 .
Output:
 => [internal] load build context                                                                                                          0.0s
 => => transferring context: 959B                                                                                                          0.0s
 => [2/5] WORKDIR /app                                                                                                                     0.2s
 => [3/5] COPY package.json .                                                                                                              0.0s
 => [4/5] RUN npm install                                                                                                                  3.9s
 => [5/5] COPY . .                                                                                                                         0.0s
 => exporting to image                                                                                                                     0.4s
 => => exporting layers                                                                                                                    0.3s
 => => writing image sha256:ab1eeb42aab2e35ea90195c1e4ddc3dd9ff8175cfdcac0321991e59f3e78d5c4                                               0.0s
 => => naming to docker.io/neviillle/frontend:1.0

$ docker push neviillle/frontend:1.0
Output:
The push refers to repository [docker.io/neviillle/frontend]
defaaed6b602: Pushed 
cf9cae260d96: Pushed 
73e3f926c148: Pushed 
d9a57774634d: Pushed 
82140d9a70a7: Mounted from library/node 
f3b40b0cdb1c: Mounted from library/node 
0b1f26057bd0: Mounted from library/node 
08000c18d16d: Mounted from library/node 
1.0: digest: sha256:fb75803435f2ba2889733835326602a8cabd69766d0d77292fb2a5a797b142da size: 1989

创建 Backend Deployment

让我们从部署 backend API 开始。创建一个名为 backend-deployment.yaml 的 YAML 文件:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
spec:
  replicas: 2
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
      - name: backend
        image: neviillle/backend:1.0
        ports:
        - containerPort: 5000

应用它,

$ kubectl apply -f backend-deployment.yaml

输出

deployment.apps/backend created

现在创建一个 Service (backend-service.yaml),以便其他 pod 可以访问它:

apiVersion: v1
kind: Service
metadata:
  name: backend
spec:
  selector:
    app: backend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 5000

其作用:

  • name:backend → 创建一个名为 backend 的 service
  • selector:app: backend → 连接到带有 app: backend 标签的 pod
  • port:80 → 集群内部暴露的端口
  • targetPort:5000 → backend container 实际监听的端口

应用它,

$ kubectl apply -f backend-service.yaml

输出

service/backend created

创建 Frontend Deployment

frontend 将使用 service 名称 http://backend 调用 backend。

以下是 frontend-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
spec:
  replicas: 2
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: frontend
        image: neviillle/frontend:1.0
        env:
        - name: BACKEND_URL
          value: "http://backend"
        ports:
        - containerPort: 3000

应用它,

$ kubectl apply -f frontend-deployment.yaml

输出

deployment.apps/frontend created

现在我们来暴露它:

以下是 frontend-service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: frontend
spec:
  type: NodePort
  selector:
    app: frontend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000
      nodePort: 30036

其作用:

  • name: frontend → 将 service 命名为 frontend
  • type: NodePort → 允许通过 Node 的 IP 和 30036 端口从外部访问
  • selector: app: frontend → 针对带有 app: frontend 标签的 pod
  • port: 80 → 集群内部可访问的端口
  • targetPort: 3000 → container 实际监听的端口
  • nodePort: 30036 → 在主机机器的此端口上暴露

应用:

$ kubectl apply -f frontend-service.yaml

输出

service/frontend created

如果使用 Minikube:

$ minikube service frontend

验证 Microservices

检查一切是否正常运行:

$ kubectl get pods

输出

NAME                        READY   STATUS    RESTARTS   AGE
backend-799f58997c-dlb8j    1/1     Running   0          4m39s
backend-799f58997c-zrqjb    1/1     Running   0          4m39s
frontend-77b45bdbb7-fn6q5   1/1     Running   0          107s
frontend-77b45bdbb7-wh2lf   1/1     Running   0          107s

检查 services:

$ kubectl get svc

输出

NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
backend      ClusterIP   10.99.232.4      <none>        80/TCP         3m36s
frontend     NodePort    10.106.125.152   <none>        80:30036/TCP   70s
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        26m

扩展 Services

将 backend 扩展到 5 个副本:

$ kubectl scale deployment backend --replicas=5

输出

deployment.apps/backend scaled

缩减副本:

$ kubectl scale deployment backend --replicas=2

输出

deployment.apps/backend scaled

监控和日志

查看日志:

$ kubectl logs deployment/frontend

输出

> frontend@1.0.0 start
> node server.js
Frontend server is running on port 3000
Connected to backend at http://backend

排查问题:

$ kubectl describe pod <pod-name>

可选:添加 Network Policies 或 Ingress

如果您想控制流量或使用域名暴露服务,请查看以下内容:

  • Ingress controllers(例如 NGINX Ingress)
  • 用于控制服务间通信的 Network policies

这些功能非常适合生产环境部署。

结论

我们已成功在 Kubernetes 上部署了一个基本的微服务应用。每个微服务独立运行,Kubernetes 负责部署、扩展和内部网络管理。这种方法非常适合构建现代的云原生应用。

展望未来,我们可以探索添加数据库、保护 APIs、使用 Helm charts 以及设置 CI/CD 管道。