返回博客

在Kubernetes集群中设置代理:DevOps工程师的完整指南

Kubernetes中代理设置的完整指南:环境变量配置、Docker、containerd、kubectl的设置,以及解决网络访问的常见问题。

📅2026年2月17日
```html

在企业环境或防火墙后部署Kubernetes时,通常需要配置代理服务器以访问外部资源。这对于下载容器镜像、更新软件包和与外部API交互至关重要。在本指南中,我们将讨论Kubernetes中代理的所有配置级别——从节点配置到单个Pods。

Kubernetes集群中为什么需要代理

企业环境中的Kubernetes集群通常在隔离的网络中运行,访问互联网的权限有限。代理服务器解决了几个关键问题:

  • 下载容器镜像 — Docker Hub、Google Container Registry、私有注册表需要外部访问
  • 更新软件包 — 在容器内通过apt、yum、pip安装依赖项
  • 访问外部API — 与云服务、监控、日志记录集成
  • 安全性 — 流量控制、域过滤、请求日志记录
  • 缓存 — 加速对相同资源的重复请求

如果没有正确配置代理,您可能会在尝试部署应用程序时遇到“image pull failed”、“connection timeout”或“network unreachable”等错误。这对于自动化CI/CD管道尤其关键,因为每一秒的停机都会造成经济损失。

重要: 对于企业集群,建议使用具有高带宽和连接稳定性的数据中心代理,因为它们关系到整个基础设施的可用性。

Kubernetes中代理的配置级别

Kubernetes具有多层架构,代理需要根据任务在每个级别进行配置:

级别 配置内容 用途
操作系统 系统环境变量 访问工具(curl、wget、apt)
Container Runtime (Docker/containerd) 守护进程配置 下载容器镜像
kubelet kubelet启动参数 与API服务器交互
Pods 清单中的环境变量 应用程序访问外部API
kubectl 客户端环境变量 通过代理管理集群

每个级别都需要单独配置,遗漏任何一个都可能导致问题。例如,如果只为Docker配置了代理,但没有为Pods配置,则镜像会被下载,但容器内的应用程序无法访问外部API。

为Docker和containerd配置代理

Container runtime是需要配置的第一个组件,因为它负责从外部注册表下载容器镜像。我们将讨论这两个流行的runtime的配置。

为Docker配置代理

对于Docker,需要创建systemd drop-in文件,将环境变量添加到Docker服务中:

# 创建配置目录
sudo mkdir -p /etc/systemd/system/docker.service.d

# 创建代理设置文件
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=http://proxy.company.com:8080"
Environment="HTTPS_PROXY=http://proxy.company.com:8080"
Environment="NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,.cluster.local,.svc"
EOF

# 重新加载systemd配置
sudo systemctl daemon-reload

# 重启Docker
sudo systemctl restart docker

# 检查设置是否生效
sudo systemctl show --property=Environment docker

之后,Docker将能够通过代理服务器下载镜像。可以使用以下命令检查其工作:

docker pull nginx:latest

为containerd配置代理

在现代Kubernetes集群中,containerd被用作主要的container runtime。为其配置代理稍有不同:

# 创建配置目录
sudo mkdir -p /etc/systemd/system/containerd.service.d

# 创建代理设置文件
sudo tee /etc/systemd/system/containerd.service.d/http-proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=http://proxy.company.com:8080"
Environment="HTTPS_PROXY=http://proxy.company.com:8080"
Environment="NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,.cluster.local,.svc"
EOF

# 重新加载配置
sudo systemctl daemon-reload
sudo systemctl restart containerd

# 检查状态
sudo systemctl status containerd

建议: 如果您使用私有容器注册表,请将其域名添加到NO_PROXY中,以避免不必要的延迟和SSL证书问题。

为kubelet配置代理

Kubelet是Kubernetes的代理,运行在集群的每个节点上。它也需要访问API服务器和外部资源。配置取决于Kubernetes的安装方式。

对于kubeadm集群

如果您使用kubeadm,请通过systemd配置代理:

# 创建kubelet配置目录
sudo mkdir -p /etc/systemd/system/kubelet.service.d

# 创建代理设置文件
sudo tee /etc/systemd/system/kubelet.service.d/http-proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=http://proxy.company.com:8080"
Environment="HTTPS_PROXY=http://proxy.company.com:8080"
Environment="NO_PROXY=localhost,127.0.0.1,10.96.0.0/12,10.244.0.0/16,.cluster.local,.svc"
EOF

# 重新加载kubelet
sudo systemctl daemon-reload
sudo systemctl restart kubelet

对于托管Kubernetes(EKS、GKE、AKS)

在托管的Kubernetes服务中,kubelet的配置通常通过节点启动参数或用户数据脚本进行。例如,对于AWS EKS:

#!/bin/bash
# EKS工作节点的用户数据脚本

# 为系统配置代理
cat <<EOF >> /etc/environment
HTTP_PROXY=http://proxy.company.com:8080
HTTPS_PROXY=http://proxy.company.com:8080
NO_PROXY=localhost,127.0.0.1,169.254.169.254,.ec2.internal,.cluster.local
EOF

# 为kubelet配置
mkdir -p /etc/systemd/system/kubelet.service.d
cat <<EOF > /etc/systemd/system/kubelet.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://proxy.company.com:8080"
Environment="HTTPS_PROXY=http://proxy.company.com:8080"
Environment="NO_PROXY=localhost,127.0.0.1,169.254.169.254,.ec2.internal,.cluster.local"
EOF

systemctl daemon-reload
systemctl restart kubelet

请注意将169.254.169.254添加到NO_PROXY中——这是AWS元数据服务的地址,应该在没有代理的情况下访问。

在Pods级别配置代理

即使您为Docker和kubelet配置了代理,Pods内部的应用程序也不会自动使用代理。需要在Kubernetes清单中明确指定环境变量。

通过Deployment清单配置

最简单的方法是将环境变量添加到容器的规格中:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: app
        image: my-company/my-app:latest
        env:
        - name: HTTP_PROXY
          value: "http://proxy.company.com:8080"
        - name: HTTPS_PROXY
          value: "http://proxy.company.com:8080"
        - name: NO_PROXY
          value: "localhost,127.0.0.1,.cluster.local,.svc,10.0.0.0/8"
        ports:
        - containerPort: 8080

使用ConfigMap进行集中配置

为了避免在每个Deployment中重复配置代理,请创建ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: proxy-config
  namespace: default
data:
  HTTP_PROXY: "http://proxy.company.com:8080"
  HTTPS_PROXY: "http://proxy.company.com:8080"
  NO_PROXY: "localhost,127.0.0.1,.cluster.local,.svc,10.0.0.0/8"

然后在Deployment中使用这个ConfigMap:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
      - name: app
        image: my-company/my-app:latest
        envFrom:
        - configMapRef:
            name: proxy-config

这种方法简化了管理:当代理地址更改时,只需更新ConfigMap,Pods重启后新设置将自动应用。

通过MutatingWebhook自动注入

为了自动将代理变量添加到所有Pods中,可以使用MutatingAdmissionWebhook。这是一种高级方法,需要开发自己的webhook服务,但它允许集中管理设置,而无需更改应用程序的清单。

正确配置NO_PROXY

NO_PROXY变量定义了哪些地址和域名应该绕过代理服务器。NO_PROXY配置不正确是Kubernetes集群中问题的最常见原因。

Kubernetes的必需排除项

以下地址和范围必须始终在NO_PROXY中:

地址/范围 用途
localhost, 127.0.0.1 本地连接
.cluster.local 集群内部DNS
.svc Kubernetes服务
10.0.0.0/8 Pod网络(取决于CNI)
10.96.0.0/12 服务网络(默认)
172.16.0.0/12 Docker私有网络
192.168.0.0/16 私有局域网

NO_PROXY的完整配置示例

NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,10.96.0.0/12,.cluster.local,.svc,.default.svc,.default.svc.cluster.local,kubernetes.default.svc,kubernetes.default.svc.cluster.local

注意: 一些应用程序不支持NO_PROXY中的CIDR表示法。在这种情况下,请使用通配符:10.*代替10.0.0.0/8

为kubectl配置代理

如果您通过位于代理后面的工作站管理集群,请为kubectl配置环境变量:

# 对于Linux/macOS - 添加到~/.bashrc或~/.zshrc
export HTTP_PROXY=http://proxy.company.com:8080
export HTTPS_PROXY=http://proxy.company.com:8080
export NO_PROXY=localhost,127.0.0.1,kubernetes.default.svc,.cluster.local

# 对于Windows PowerShell
$env:HTTP_PROXY="http://proxy.company.com:8080"
$env:HTTPS_PROXY="http://proxy.company.com:8080"
$env:NO_PROXY="localhost,127.0.0.1,kubernetes.default.svc,.cluster.local"

之后,kubectl将能够通过代理连接到集群的API服务器。检查其工作:

kubectl cluster-info
kubectl get nodes

带身份验证的代理配置

如果代理服务器需要身份验证,请将凭据添加到URL中:

export HTTP_PROXY=http://username:password@proxy.company.com:8080
export HTTPS_PROXY=http://username:password@proxy.company.com:8080

安全性: 不要在配置文件中以明文形式存储密码。使用环境变量或Kubernetes秘密来存储代理凭据。

诊断和解决常见问题

即使在正确配置的情况下,也可能会出现问题。让我们看看最常见的错误及其解决方法。

下载镜像时出现“ImagePullBackOff”错误

症状: Pods无法启动,事件中显示“Failed to pull image”或“connection timeout”错误。

诊断:

# 检查Pod事件
kubectl describe pod <pod-name>

# 检查Docker/containerd中的代理设置
sudo systemctl show --property=Environment docker
sudo systemctl show --property=Environment containerd

# 尝试在节点上手动下载镜像
sudo docker pull nginx:latest
sudo crictl pull nginx:latest

解决方案: 确保为container runtime配置了代理,并且镜像注册表的域名不在NO_PROXY中。

集群内部的DNS解析问题

症状: Pods无法通过DNS名称相互访问(例如,service-name.namespace.svc.cluster.local)。

诊断:

# 检查Pod中的DNS
kubectl run -it --rm debug --image=busybox --restart=Never -- nslookup kubernetes.default

# 检查Pod中的代理变量
kubectl exec -it <pod-name> -- env | grep PROXY

解决方案:.cluster.local.svc添加到NO_PROXY中。

访问外部API时的慢速或超时问题

症状: 应用程序运行缓慢或在请求外部服务时出现超时。

诊断:

# 检查Pod中的代理可用性
kubectl exec -it <pod-name> -- curl -v -x http://proxy.company.com:8080 https://www.google.com

# 测量响应时间
kubectl exec -it <pod-name> -- time curl -x http://proxy.company.com:8080 https://api.example.com

解决方案: 问题可能出在代理服务器的性能上。考虑使用地理位置接近的住宅代理以减少延迟。

通过代理时的SSL/TLS错误

症状: 出现“certificate verify failed”或“SSL handshake failed”等错误。

原因: 一些代理服务器执行SSL检查(解密HTTPS流量),这需要安装代理的根证书。

解决方案:

# 创建包含代理证书的ConfigMap
kubectl create configmap proxy-ca-cert --from-file=ca.crt=/path/to/proxy-ca.crt

# 将证书挂载到Pod并添加到系统存储中
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
      - name: app
        volumeMounts:
        - name: proxy-ca
          mountPath: /usr/local/share/ca-certificates/proxy-ca.crt
          subPath: ca.crt
      volumes:
      - name: proxy-ca
        configMap:
          name: proxy-ca-cert

生产环境中代理的最佳实践

根据在企业环境中运行Kubernetes集群的经验,以下是与代理可靠运行的建议:

1. 使用高可用的代理服务器

代理成为整个集群的单点故障。配置多个代理服务器通过负载均衡器:

HTTP_PROXY=http://proxy-lb.company.com:8080

其中proxy-lb.company.com是位于多个代理服务器前面的负载均衡器。

2. 集中管理配置

使用ConfigMap或Secret存储代理设置,而不是在每个清单中硬编码:

apiVersion: v1
kind: ConfigMap
metadata:
  name: cluster-proxy-config
  namespace: kube-system
data:
  HTTP_PROXY: "http://proxy-lb.company.com:8080"
  HTTPS_PROXY: "http://proxy-lb.company.com:8080"
  NO_PROXY: "localhost,127.0.0.1,.cluster.local,.svc,10.0.0.0/8"

3. 监控和警报

配置代理服务器的可用性监控和问题警报:

  • 代理的响应时间(应小于100ms对于本地代理)
  • 连接代理的错误数量
  • 集群中ImagePullBackOff事件的数量
  • 代理服务器的CPU和网络负载

4. 记录NO_PROXY的排除项

记录哪些域名和IP地址被添加到NO_PROXY中及其原因。这将有助于故障排除和安全审计。

5. 在开发环境中测试更改

在生产中更改代理设置之前,请始终在开发/暂存集群中进行测试:

# 测试Pod以检查代理
apiVersion: v1
kind: Pod
metadata:
  name: proxy-test
spec:
  containers:
  - name: test
    image: curlimages/curl:latest
    command: ["sleep", "3600"]
    env:
    - name: HTTP_PROXY
      value: "http://new-proxy.company.com:8080"
    - name: HTTPS_PROXY
      value: "http://new-proxy.company.com:8080"

# 检查外部资源的可用性
kubectl exec -it proxy-test -- curl -v https://registry.k8s.io
kubectl exec -it proxy-test -- curl -v https://docker.io

6. 针对不同任务使用不同类型的代理

对于关键组件(下载镜像、集群API),使用快速的数据中心代理,而对于需要地理多样性的IP的应用程序——使用住宅或移动代理。

7. 定期更新NO_PROXY列表

在添加新服务或更改网络拓扑时,更新NO_PROXY。通过Helm图表或Kustomize自动化此过程:

# Helm图表的values.yaml
proxy:
  enabled: true
  http: "http://proxy.company.com:8080"
  https: "http://proxy.company.com:8080"
  noProxy:
    - localhost
    - 127.0.0.1
    - .cluster.local
    - .svc
    - 10.0.0.0/8
    - internal-service.company.com

结论

在Kubernetes集群中配置代理是一项多层任务,需要在每个级别上关注细节:从操作系统和container runtime到单个Pods。正确的配置确保集群的持续运行、安全访问外部资源以及符合企业安全政策。

需要记住的关键点:

  • 在所有级别配置代理:操作系统、container runtime、kubelet、Pods
  • 正确配置NO_PROXY,包括集群的所有内部网络
  • 通过ConfigMap使用集中管理
  • 监控代理服务器的可用性和性能
  • 在生产中应用更改之前进行测试

对于关键的Kubernetes集群,建议使用可靠的数据中心代理,以确保高可用性和低延迟。这将确保基础设施的稳定运行,并最小化由于网络访问问题而导致的停机风险。

在出现问题时,使用系统的方法进行诊断:检查每个级别的设置,分析日志和事件,手动测试连接。大多数Kubernetes中与代理相关的问题都可以通过正确配置环境变量和NO_PROXY来解决。

```