Khi triển khai Kubernetes trong môi trường doanh nghiệp hoặc sau tường lửa, thường có nhu cầu cài đặt máy chủ proxy để truy cập các tài nguyên bên ngoài. Điều này rất quan trọng để tải hình ảnh container, cập nhật gói và tương tác với các API bên ngoài. Trong hướng dẫn này, chúng ta sẽ xem xét tất cả các cấp độ cài đặt proxy trong Kubernetes - từ cấu hình nút đến từng pod.
Tại sao cần proxy trong các cụm Kubernetes
Các cụm Kubernetes trong môi trường doanh nghiệp thường hoạt động trong các mạng bị cô lập với quyền truy cập Internet hạn chế. Máy chủ proxy giải quyết một số nhiệm vụ quan trọng:
- Tải hình ảnh container — Docker Hub, Google Container Registry, các registry riêng yêu cầu quyền truy cập bên ngoài
- Cập nhật gói — cài đặt các phụ thuộc thông qua apt, yum, pip bên trong các container
- Truy cập các API bên ngoài — tích hợp với các dịch vụ đám mây, giám sát, ghi log
- Bảo mật — kiểm soát lưu lượng, lọc miền, ghi log các yêu cầu
- Bộ nhớ đệm — tăng tốc độ các yêu cầu lặp lại đến cùng một tài nguyên
Nếu không có cấu hình proxy chính xác, bạn sẽ gặp phải các lỗi như "image pull failed", "connection timeout" hoặc "network unreachable" khi cố gắng triển khai ứng dụng. Điều này đặc biệt quan trọng đối với các pipeline CI/CD tự động, nơi mỗi giây ngừng hoạt động đều tốn kém.
Quan trọng: Đối với các cụm doanh nghiệp, nên sử dụng proxy trung tâm dữ liệu với băng thông cao và độ ổn định của kết nối, vì chúng ảnh hưởng đến khả năng hoạt động của toàn bộ hạ tầng.
Các cấp độ cài đặt proxy trong Kubernetes
Kubernetes có kiến trúc đa cấp, và proxy cần được cấu hình ở mỗi cấp tùy thuộc vào các nhiệm vụ:
| Cấp độ | Cái gì được cấu hình | Để làm gì |
|---|---|---|
| Hệ điều hành | Các biến môi trường hệ thống | Truy cập các tiện ích (curl, wget, apt) |
| Container Runtime (Docker/containerd) | Cấu hình daemon | Tải hình ảnh container |
| kubelet | Tham số khởi động kubelet | Tương tác với API server |
| Pods | Các biến môi trường trong các manifest | Truy cập ứng dụng đến các API bên ngoài |
| kubectl | Các biến môi trường của client | Quản lý cụm thông qua proxy |
Mỗi cấp độ yêu cầu cấu hình riêng biệt, và việc bỏ qua bất kỳ cấp nào có thể dẫn đến vấn đề. Ví dụ, nếu chỉ cấu hình proxy cho Docker nhưng không cho các pod, thì hình ảnh sẽ được tải, nhưng các ứng dụng bên trong container sẽ không thể truy cập các API bên ngoài.
Cài đặt proxy cho Docker và containerd
Container runtime là thành phần đầu tiên cần được cấu hình, vì nó chịu trách nhiệm tải hình ảnh container từ các registry bên ngoài. Hãy xem xét cấu hình cho cả hai runtime phổ biến.
Cài đặt proxy cho Docker
Đối với Docker, bạn cần tạo một file drop-in systemd, sẽ thêm các biến môi trường vào dịch vụ Docker:
# Tạo thư mục cho cấu hình
sudo mkdir -p /etc/systemd/system/docker.service.d
# Tạo file với cấu hình proxy
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
# Tải lại cấu hình systemd
sudo systemctl daemon-reload
# Khởi động lại Docker
sudo systemctl restart docker
# Kiểm tra xem cấu hình đã được áp dụng
sudo systemctl show --property=Environment docker
Sau đó, Docker sẽ có thể tải hình ảnh thông qua máy chủ proxy. Bạn có thể kiểm tra hoạt động bằng lệnh:
docker pull nginx:latest
Cài đặt proxy cho containerd
Containerd được sử dụng trong các cụm Kubernetes hiện đại như là container runtime chính. Cài đặt proxy cho nó hơi khác một chút:
# Tạo thư mục cho cấu hình
sudo mkdir -p /etc/systemd/system/containerd.service.d
# Tạo file với cấu hình proxy
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
# Tải lại cấu hình
sudo systemctl daemon-reload
sudo systemctl restart containerd
# Kiểm tra trạng thái
sudo systemctl status containerd
Mẹo: Nếu bạn sử dụng registry container riêng, hãy thêm miền của nó vào NO_PROXY để tránh độ trễ không cần thiết và các vấn đề với chứng chỉ SSL.
Cấu hình proxy cho kubelet
Kubelet là tác nhân của Kubernetes, chạy trên mỗi nút của cụm. Nó cũng cần truy cập vào API server và các tài nguyên bên ngoài. Cấu hình phụ thuộc vào cách cài đặt Kubernetes.
Đối với các cụm kubeadm
Nếu bạn sử dụng kubeadm, hãy cấu hình proxy thông qua systemd:
# Tạo thư mục cho cấu hình kubelet
sudo mkdir -p /etc/systemd/system/kubelet.service.d
# Tạo file với cấu hình proxy
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
# Tải lại kubelet
sudo systemctl daemon-reload
sudo systemctl restart kubelet
Đối với các dịch vụ Kubernetes được quản lý (EKS, GKE, AKS)
Trong các dịch vụ Kubernetes được quản lý, cấu hình kubelet thường được thực hiện thông qua các tham số khởi động của nút hoặc các script user data. Ví dụ, cho AWS EKS:
#!/bin/bash
# Script user data cho các nút worker EKS
# Cấu hình proxy cho hệ thống
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
# Cấu hình cho 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
Lưu ý rằng bạn đã thêm 169.254.169.254 vào NO_PROXY — đây là địa chỉ của dịch vụ metadata AWS, cần phải truy cập mà không cần proxy.
Cài đặt proxy ở cấp độ pod
Ngay cả khi bạn đã cấu hình proxy cho Docker và kubelet, các ứng dụng bên trong các pod sẽ không tự động sử dụng proxy. Bạn cần chỉ định rõ các biến môi trường trong các manifest Kubernetes.
Cài đặt thông qua manifest Deployment
Cách đơn giản nhất là thêm các biến môi trường vào thông số của container:
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
Sử dụng ConfigMap để cấu hình tập trung
Để không phải lặp lại cấu hình proxy trong mỗi Deployment, hãy tạo một 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"
Sau đó, sử dụng ConfigMap này trong Deployment:
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
Cách tiếp cận này giúp quản lý dễ dàng hơn: khi thay đổi địa chỉ proxy, chỉ cần cập nhật ConfigMap, và sau khi khởi động lại các pod, các cấu hình mới sẽ tự động được áp dụng.
Tiêm tự động thông qua MutatingWebhook
Để tự động thêm các biến proxy vào tất cả các pod, bạn có thể sử dụng MutatingAdmissionWebhook. Đây là một phương pháp nâng cao, yêu cầu phát triển dịch vụ webhook riêng, nhưng cho phép quản lý cấu hình một cách tập trung mà không cần thay đổi các manifest của ứng dụng.
Cấu hình NO_PROXY chính xác
Biến NO_PROXY xác định các địa chỉ và miền nào cần bỏ qua máy chủ proxy. Cấu hình NO_PROXY không chính xác là nguyên nhân phổ biến nhất gây ra vấn đề trong các cụm Kubernetes.
Các ngoại lệ bắt buộc cho Kubernetes
Các địa chỉ và dải sau đây LUÔN LUÔN phải có trong NO_PROXY:
| Địa chỉ/Dải | Mục đích |
|---|---|
localhost, 127.0.0.1 |
Kết nối cục bộ |
.cluster.local |
DNS nội bộ của cụm |
.svc |
Các dịch vụ Kubernetes |
10.0.0.0/8 |
Mạng Pod (tùy thuộc vào CNI) |
10.96.0.0/12 |
Mạng dịch vụ (mặc định) |
172.16.0.0/12 |
Mạng riêng tư của Docker |
192.168.0.0/16 |
Mạng cục bộ riêng tư |
Ví dụ về cấu hình NO_PROXY đầy đủ
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
Cảnh báo: Một số ứng dụng không hỗ trợ định dạng CIDR trong NO_PROXY. Trong những trường hợp đó, hãy sử dụng wildcard: 10.* thay vì 10.0.0.0/8.
Cài đặt kubectl để làm việc qua proxy
Nếu bạn quản lý cụm từ một trạm làm việc nằm sau proxy, hãy cấu hình các biến môi trường cho kubectl:
# Đối với Linux/macOS - thêm vào ~/.bashrc hoặc ~/.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
# Đối với 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"
Sau đó, kubectl sẽ có thể kết nối với API server của cụm thông qua proxy. Kiểm tra hoạt động:
kubectl cluster-info
kubectl get nodes
Cài đặt proxy với xác thực
Nếu máy chủ proxy yêu cầu xác thực, hãy thêm thông tin đăng nhập vào URL:
export HTTP_PROXY=http://username:password@proxy.company.com:8080
export HTTPS_PROXY=http://username:password@proxy.company.com:8080
Bảo mật: Không lưu trữ mật khẩu dưới dạng văn bản rõ trong các file cấu hình. Sử dụng các biến môi trường hoặc bí mật Kubernetes để lưu trữ thông tin đăng nhập proxy.
Chẩn đoán và giải quyết các vấn đề thường gặp
Ngay cả khi cấu hình đúng, vẫn có thể xảy ra vấn đề. Hãy xem xét các lỗi thường gặp nhất và cách giải quyết chúng.
Lỗi "ImagePullBackOff" khi tải hình ảnh
Triệu chứng: Các pod không khởi động, trong sự kiện hiển thị lỗi "Failed to pull image" hoặc "connection timeout".
Chẩn đoán:
# Kiểm tra sự kiện của pod
kubectl describe pod <pod-name>
# Kiểm tra cấu hình proxy trong Docker/containerd
sudo systemctl show --property=Environment docker
sudo systemctl show --property=Environment containerd
# Thử tải hình ảnh thủ công trên nút
sudo docker pull nginx:latest
sudo crictl pull nginx:latest
Giải pháp: Đảm bảo rằng proxy đã được cấu hình cho container runtime và miền của registry hình ảnh không nằm trong NO_PROXY.
Vấn đề với phân giải DNS bên trong cụm
Triệu chứng: Các pod không thể truy cập lẫn nhau qua tên DNS (ví dụ, service-name.namespace.svc.cluster.local).
Chẩn đoán:
# Kiểm tra DNS từ pod
kubectl run -it --rm debug --image=busybox --restart=Never -- nslookup kubernetes.default
# Kiểm tra các biến proxy trong pod
kubectl exec -it <pod-name> -- env | grep PROXY
Giải pháp: Thêm .cluster.local và .svc vào NO_PROXY.
Hoạt động chậm hoặc timeout khi truy cập các API bên ngoài
Triệu chứng: Các ứng dụng hoạt động chậm hoặc nhận timeout khi yêu cầu đến các dịch vụ bên ngoài.
Chẩn đoán:
# Kiểm tra khả năng truy cập proxy từ pod
kubectl exec -it <pod-name> -- curl -v -x http://proxy.company.com:8080 https://www.google.com
# Đo thời gian phản hồi
kubectl exec -it <pod-name> -- time curl -x http://proxy.company.com:8080 https://api.example.com
Giải pháp: Vấn đề có thể nằm ở hiệu suất của máy chủ proxy. Hãy xem xét việc sử dụng proxy cư trú với vị trí địa lý gần để giảm độ trễ.
Lỗi SSL/TLS khi làm việc qua proxy
Triệu chứng: Các lỗi như "certificate verify failed" hoặc "SSL handshake failed".
Nguyên nhân: Một số máy chủ proxy thực hiện kiểm tra SSL (giải mã lưu lượng HTTPS), điều này yêu cầu cài đặt chứng chỉ gốc của proxy.
Giải pháp:
# Tạo ConfigMap với chứng chỉ của proxy
kubectl create configmap proxy-ca-cert --from-file=ca.crt=/path/to/proxy-ca.crt
# Gắn chứng chỉ vào pod và thêm vào kho lưu trữ hệ thống
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
Các phương pháp tốt nhất cho proxy trong sản xuất
Dựa trên kinh nghiệm vận hành các cụm Kubernetes trong môi trường doanh nghiệp, đây là những khuyến nghị để làm việc với proxy một cách đáng tin cậy:
1. Sử dụng máy chủ proxy có độ khả dụng cao
Proxy trở thành điểm thất bại duy nhất cho toàn bộ cụm. Cấu hình nhiều máy chủ proxy sau bộ cân bằng tải:
HTTP_PROXY=http://proxy-lb.company.com:8080
Trong đó proxy-lb.company.com là bộ cân bằng tải trước nhiều máy chủ proxy.
2. Quản lý cấu hình tập trung
Sử dụng ConfigMap hoặc Secret để lưu trữ các thiết lập proxy thay vì mã cứng trong mỗi manifest:
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. Giám sát và cảnh báo
Cấu hình giám sát khả năng truy cập của các máy chủ proxy và cảnh báo khi có vấn đề:
- Thời gian phản hồi của proxy (nên < 100ms cho các proxy cục bộ)
- Số lượng lỗi kết nối đến proxy
- Số lượng sự kiện ImagePullBackOff trong cụm
- Tải CPU và mạng trên các máy chủ proxy
4. Tài liệu hóa các ngoại lệ NO_PROXY
Giữ tài liệu về các miền và địa chỉ IP đã được thêm vào NO_PROXY và lý do tại sao. Điều này sẽ hữu ích trong việc khắc phục sự cố và kiểm toán bảo mật.
5. Kiểm tra các thay đổi trong môi trường dev
Trước khi thay đổi cấu hình proxy trong sản xuất, hãy luôn kiểm tra trong cụm dev/staging:
# Pod thử nghiệm để kiểm tra proxy
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"
# Kiểm tra khả năng truy cập các tài nguyên bên ngoài
kubectl exec -it proxy-test -- curl -v https://registry.k8s.io
kubectl exec -it proxy-test -- curl -v https://docker.io
6. Sử dụng các loại proxy khác nhau cho các nhiệm vụ khác nhau
Đối với các thành phần quan trọng (tải hình ảnh, API của cụm), hãy sử dụng các proxy trung tâm dữ liệu nhanh, trong khi cho các ứng dụng yêu cầu sự đa dạng địa lý của IP — hãy sử dụng proxy cư trú hoặc di động.
7. Cập nhật danh sách NO_PROXY thường xuyên
Khi thêm các dịch vụ mới hoặc thay đổi cấu trúc mạng, hãy cập nhật NO_PROXY. Tự động hóa điều này thông qua Helm charts hoặc Kustomize:
# values.yaml cho Helm chart
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
Kết luận
Cài đặt proxy trong các cụm Kubernetes là một nhiệm vụ đa cấp, yêu cầu sự chú ý đến từng chi tiết ở mỗi cấp: từ hệ điều hành và container runtime đến từng pod. Cấu hình chính xác đảm bảo hoạt động liên tục của cụm, truy cập an toàn đến các tài nguyên bên ngoài và tuân thủ các chính sách bảo mật của doanh nghiệp.
Những điểm chính cần nhớ:
- Cấu hình proxy ở tất cả các cấp: OS, container runtime, kubelet, pod
- Cấu hình NO_PROXY chính xác, bao gồm tất cả các mạng nội bộ của cụm
- Sử dụng quản lý tập trung thông qua ConfigMap
- Giám sát khả năng truy cập và hiệu suất của các máy chủ proxy
- Kiểm tra các thay đổi trước khi áp dụng trong sản xuất
Đối với các cụm Kubernetes quan trọng, chúng tôi khuyên bạn nên sử dụng các proxy trung tâm dữ liệu đáng tin cậy với độ khả dụng cao và độ trễ thấp. Điều này sẽ đảm bảo hoạt động ổn định của hạ tầng và giảm thiểu rủi ro ngừng hoạt động do các vấn đề về truy cập mạng.
Khi gặp vấn đề, hãy sử dụng phương pháp có hệ thống để chẩn đoán: kiểm tra cấu hình ở mỗi cấp, phân tích log và sự kiện, kiểm tra kết nối thủ công. Hầu hết các vấn đề với proxy trong Kubernetes có thể được giải quyết bằng cách cấu hình chính xác các biến môi trường và NO_PROXY.