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
的文件:
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
您应该会看到类似于以下内容的输出:
NAME READY STATUS RESTARTS AGE
nginx-pod 1/1 Running 0 10s
接下来,删除 pod:
kubectl delete pod nginx-pod
输出应类似于以下内容:
kubectl get pod
No resources found in default namespace.
什么是服务?
为 Kubernetes 中的 Nginx pod 创建一个 服务 可以使 Nginx 应用程序在集群内或集群外可访问。以下是为 Nginx pod 创建服务的逐步指南。
确保您有一个正在运行的 Nginx 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
应用 Pod 配置:
创建一个名为nginx-service.yaml
的YAML文件来定义Service:
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
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
文件:
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 访问日志。
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 代理
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格式并发送到外部日志服务的容器。
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