在 Kubernetes 中 Pods 和 Services 的终极指南

Kubernetes 是一个强大的容器编排平台,但要充分利用其潜力,理解其核心组件是很重要的,其中 Pod 和服务扮演着基础性角色。在本文中,我们将深入探讨它们是什么,以及它们如何共同工作来公开和管理运行在 Kubernetes 集群中的应用程序。

什么是 Pod?

Pods 是您可以在 Kubernetes 中创建和管理的最小部署单位。

在我们创建一个 Pod 之前,让我们检查一下您的 Kubernetes 集群中可用的 API 资源;您可以使用 kubectl api-resources 命令。这个命令列出了 Kubernetes API 服务器支持的 API 资源,包括它们的简短名称、API 组,以及它们是否有命名空间。这对于了解您的集群的能力非常有用,特别是在处理自定义资源或探索新的 Kubernetes 功能时。kubectl explain 命令通过提供关于单个资源的详细信息来补充这一点。

让我们为运行简单 Nginx 容器的 Pod 创建一个基本的 Pod 配置文件。

创建一个名为 nginx-pod.yaml 的文件:

YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80

以下是使用到的术语的简要解释:

  • apiVersion: v1:指定 API 版本。
  • kind: Pod:表示这个配置是为一个 Pod。
  • metadata:name:Pod 的名称。
  • 元数据: 标签: 可用于组织和选择 pod 的键-值对。
  • 规范:容器: 将在 pod 中运行的容器列表。
  • 规范:容器:名称: 容器的名称。
  • 规范:容器:镜像: 要使用的容器镜像(在本例中为最新的 Nginx 镜像)。
  • 规范:容器:端口: 从容器中暴露的端口。

使用 kubectl 应用配置文件并创建 pod:

  • kubectl apply -f nginx-pod.yaml

检查 pod 的状态,确保已创建并正在运行:

  • kubectl get pods

您应该会看到类似于以下内容的输出:

Shell

 

NAME         READY   STATUS    RESTARTS    AGE
nginx-pod    1/1     Running   0           10s

接下来,删除 pod:

  • kubectl delete pod nginx-pod

输出应类似于以下内容:

Shell

 

kubectl get pod
No resources found in default namespace.

什么是服务?

为 Kubernetes 中的 Nginx pod 创建一个 服务 可以使 Nginx 应用程序在集群内或集群外可访问。以下是为 Nginx pod 创建服务的逐步指南。

确保您有一个正在运行的 Nginx pod,如果还没有,请创建一个名为 nginx-pod.yaml 的 YAML 文件:

YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80

应用 Pod 配置:

创建一个名为nginx-service.yaml的YAML文件来定义Service:

YAML

 

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
       targetPort: 80
  type: ClusterIP

以下是一些需要注意的事项:

  • selector:用于匹配Nginx pod的标签选择器。
  • app: nginx:这应该与Nginx pod中的标签匹配。
  • type: ClusterIP:Service的类型。ClusterIP使Service仅在集群内可访问。您也可以使用NodePort或LoadBalancer将Service暴露到外部。

使用kubectl应用Service配置:

  • kubectl apply -f nginx-service.yaml
  • kubectl get services
Shell

 

NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
nginx-service    ClusterIP   10.96.0.1        <none>        80/TCP    10s

由于Service的类型是ClusterIP,因此只能在集群内访问。要从集群外访问它,您可以将Service类型更改为NodePort或LoadBalancer。

使用NodePort在外部暴露Service,修改nginx-service.yaml文件:

YAML

 

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
       targetPort: 80
      nodePort: 30007  # Specify a node port in the range 30000-32767 (optional)
  type: NodePort

应用更新后的Service配置:

  • kubectl apply -f nginx-service.yaml

现在可以使用节点的IP地址和节点端口(例如,http://<node-ip>:30007)访问Nginx应用程序。

多容器Pods

每个 Pod 使用单个容器提供最大的细粒度和解耦。然而,在某些情况下,部署多个容器(有时称为复合容器)在单个 Pod 内是有益的。这些辅助容器可以执行各种角色:处理日志或增强主容器(边车概念),充当对外系统的代理(大使概念),或修改数据以适应外部格式(适配器概念)。这些辅助容器通过执行主容器无法处理的任务来补充主容器。

以下是一个 Kubernetes Pod 配置的示例,其中包括一个运行 Nginx 服务器的主容器和一个充当处理日志的边车的辅助容器。这个边车容器使用一个简单的日志容器如 BusyBox 来演示它如何追踪 Nginx 访问日志。

YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-with-logging-sidecar
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx
  - name: log-sidecar
    image: busybox:latest
    command: ["sh", "-c", "tail -f /var/log/nginx/access.log"]
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx
  volumes:
  - name: shared-logs
    emptyDir: {}

然后您需要执行以下操作:

  • 将 YAML 配置保存到一个文件中,例如 nginx-with-logging-sidecar.yaml。 
  • 使用 kubectl apply -f nginx-with-logging-sidecar.yaml 应用配置。 
  • 验证 Pod 是否正在运行: kubectl get pods。 
  • 检查边车容器的日志以查看 Nginx 访问日志: kubectl logs -f <pod-name> -c log-sidecar

通过以下步骤,您将删除现有的 Pod 并应用新配置,设置一个包含 Nginx 容器和用于记录日志的 sidecar 容器的 Pod。这将确保新配置在您的 Kubernetes 集群中处于活动状态并运行。

Kubernetes 中的多容器 Pod 提供了几个优势,可以实现更灵活和高效的应用部署和管理。

多容器 Pod 模式

Sidecar 模式

Sidecar 容器可以通过提供辅助功能(如记录日志、配置管理或代理)来增强主应用程序。这种模式有助于在不修改主容器的情况下扩展功能。Sidecar 容器可以通过收集和转发主应用程序容器的日志来处理记录日志。

Ambassador 模式

Ambassador 容器充当代理,管理主应用程序与外部服务之间的通信。这可以简化集成和配置。Ambassador 容器可能处理 SSL 终止或 API 网关功能。

Ambassador 模式涉及使用 sidecar 容器来管理主应用程序与外部服务之间的通信。这种模式可以处理代理、负载平衡或管理安全连接等任务,从而将复杂性抽象出来,使主应用程序容器免受影响。

  • 主应用程序容器:一个简单的 web 服务器,发出 HTTP 请求
  • Ambassador 容器:配置为管理对外部 API 的请求的 Envoy 代理
YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: app-with-ambassador
spec:
  containers:
  - name: web-app
    image: python:3.8-slim
    command: ["python", "-m", "http.server", "8000"]
    volumeMounts:
    - name: config-volume
      mountPath: /etc/envoy
  - name: envoy-proxy
    image: envoyproxy/envoy:v1.18.3
    args: ["-c", "/etc/envoy/envoy.yaml"]
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: config-volume
      mountPath: /etc/envoy
  volumes:
  - name: config-volume
    configMap:
      name: envoy-config

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: envoy-config
data:
  envoy.yaml: |
    static_resources:
      listeners:
      - name: listener_0
        address:
          socket_address:
            address: 0.0.0.0
            port_value: 8080
        filter_chains:
        - filters:
          - name: envoy.filters.network.http_connection_manager
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
              stat_prefix: ingress_http
              route_config:
                name: local_route
                virtual_hosts:
                - name: local_service
                  domains: ["*"]
                  routes:
                  - match:
                      prefix: "/"
                    route:
                      cluster: external_service
              http_filters:
              - name: envoy.filters.http.router
      clusters:
      - name: external_service
        connect_timeout: 0.25s
        type: LOGICAL_DNS
        lb_policy: ROUND_ROBIN
        load_assignment:
          cluster_name: external_service
          endpoints:
          - lb_endpoints:
            - endpoint:
                address:
                  socket_address:
                    address: api.example.com
                    port_value: 80

这个示例演示了Kubernetes中的Ambassador模式,其中Envoy代理充当中间件,管理主应用容器的外部通信。这种模式有助于抽象通信复杂性,增强模块化和可维护性。

适配器模式

适配器容器可以在主应用和外部系统之间修改或转换数据,确保兼容性和集成。例如,适配器容器可以重新格式化日志数据以满足外部日志服务的要求。

Kubernetes中的适配器模式涉及使用一个旁路容器在主应用容器和外部系统之间转换数据。当主应用需要特定格式的数据,而该格式与外部系统提供的或需要的格式不同时,这将非常有用。

假设您有一个主应用容器以自定义格式生成日志。您需要将这些日志发送到一个需要特定标准格式的外部日志服务。可以使用适配器容器将日志数据转换为所需格式,然后再发送到外部服务。

  • 主应用容器: 一个简单的应用程序,以自定义格式编写日志。
  • 适配器容器: 一个读取自定义日志,将其转换为JSON格式并发送到外部日志服务的容器。
YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: app-with-adapter
spec:
  containers:
  - name: log-writer
    image: busybox
    command: ["sh", "-c", "while true; do echo \"$(date) - Custom log entry\" >> /var/log/custom/app.log; sleep 5; done"]
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/custom
  - name: log-adapter
    image: busybox
    command: ["sh", "-c", "tail -f /var/log/custom/app.log | while read line; do echo \"$(echo $line | sed 's/ - / - {\"timestamp\": \"/;s/$/\"}/')\" >> /var/log/json/app.json; done"]
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/custom
    - name: json-logs
      mountPath: /var/log/json
  - name: log-sender
    image: busybox
    command: ["sh", "-c", "while true; do cat /var/log/json/app.json | grep -v '^$' | while read line; do echo \"Sending log to external service: $line\"; done; sleep 10; done"]
    volumeMounts:
    - name: json-logs
      mountPath: /var/log/json
  volumes:
  - name: shared-logs
    emptyDir: {}
  - name: json-logs
    emptyDir: {}

这个示例演示了 Kubernetes 中的适配器模式,其中适配器容器将主应用容器中的数据转换为所需的格式,然后将其发送到外部系统。这种模式通过在 sidecar 容器内处理数据格式转换来帮助将应用程序与外部服务集成。

摘要

总而言之,Pods:

  • 是 Kubernetes 中最小的可部署单元。
  • 代表正在运行的进程的单个实例。
  • 可以包含一个或多个容器。

Services:

  • 为访问 Pods 提供稳定的 IP 地址和 DNS 名称。
  • 在一组 Pods 中实现负载均衡。
  • 促进集群内的服务发现。

Source:
https://dzone.com/articles/the-ultimate-guide-to-kubernetes-pods-and-services