Cách tách DNS giữa Kubernetes và một sidecar OpenVPN
Pod sidecar cần hai thế giới tên. Hướng một resolver loopback tới cụm và đường hầm, và ngừng phụ thuộc vào resolv.conf đã chỉnh sửa.
Các pod chạy sidecar OpenVPN thất bại trong việc phân giải tên theo một mẫu dễ nhận ra: tên của cụm bị treo, tên từ xa vẫn trả lời cho đến khi pod khởi động lại, và tệp resolver bạn đã sửa quay trở lại. Không có gì trong chuỗi đó là lỗi của đường hầm. Một pod có một tệp resolver và hai thế giới tên, và tệp có thể liệt kê máy chủ theo thứ tự nhưng không thể diễn đạt vùng. Giải pháp bền vững là một resolver chạy bên trong pod và sở hữu việc phân tách, nhờ đó tệp vẫn đơn giản và không chính sách nào có lý do ghi đè nó.
Tại sao thay đổi bạn thực hiện cứ biến mất
Tệp thuộc về kubelet, không phải bạn. Dưới dnsPolicy: ClusterFirst kubelet tạo nó để trỏ tới DNS của cụm và tạo lại mỗi khi container khởi động. Mọi thứ bạn sửa qua kubectl exec sống trong lớp ghi của container, nên khởi động lại, trục xuất hay rollout sẽ vứt nó đi. Đặc tả pod vẫn mang chính sách cũ, đó là lý do tệp cũ quay lại.
Đặt dnsPolicy: None dừng việc tạo lại và cũng gỡ phân giải của cụm. Bạn được một tệp do mình kiểm soát và mất những tên mình cần. Sự đánh đổi đó là toàn bộ vấn đề: resolv.conf không biết khái niệm vùng, chỉ biết máy chủ thử theo thứ tự, nên không thể gửi cluster.local tới một địa chỉ và vùng riêng tới địa chỉ khác.
Chạy một resolver trong pod, trên loopback
Hướng pod tới một máy chủ tên duy nhất trên loopback, sau đó để container CoreDNS chia sẻ không gian tên mạng của pod trả lời trên cổng 53. Đặt chính sách thành None, cho pod địa chỉ duy nhất đó và thêm container DNS bên cạnh VPN và ứng dụng:
spec:
dnsPolicy: None
dnsConfig:
nameservers:
- 127.0.0.1
options:
- name: ndots
value: "5"
containers:
- name: dns
image: coredns/coredns
args: ["-conf", "/etc/coredns/Corefile"]
volumeMounts:
- {name: corefile, mountPath: /etc/coredns, readOnly: true}
- name: vpn
image: your-openvpn-client-image
- name: app
image: your-app-image
volumes:
- name: corefile
configMap:
name: split-dns-corefileCả ba container chia sẻ một không gian tên mạng, nên 127.0.0.1:53 từ container ứng dụng tới được CoreDNS mà không cần dịch vụ, không port-forward và không đi vòng qua mạng của cụm. Gắn Corefile từ ConfigMap giữ nó như đầu vào được đánh phiên bản thay vì tệp sửa tại chỗ. resolv.conf được sinh ra sau đó chứa một máy chủ tên và không gì khác, một trạng thái có thể suy luận.
Hai chi tiết cắn ở đây. Image chính thức ràng buộc cổng 53 với quyền root, và một số chính sách cụm yêu cầu bạn ghi rõ điều đó. Mọi container trong pod giờ phụ thuộc vào việc container duy nhất đó chạy, nên thêm readiness probe với một tên vô hại và để ứng dụng chịu đựng lỗi khởi động.
Cho mỗi vùng riêng upstream của riêng nó
Corefile là danh sách các vùng, mỗi vùng nêu máy chủ có thể trả lời nó. Một khối bao phủ vùng đường hầm, và khối bắt tất cả đến cuối và nhận mọi thứ không khối rõ ràng nào đòi. Khối bắt tất cả phải nhắm tới upstream thực, không bao giờ quay lại pod: .:53 { forward . 10.100.0.10 } dùng lại resolver của cụm vì nó đã chuyển tên công khai tới resolver của chính nút. Không gì khác trong pod cần biết một tên thuộc mạng nào.
.:53 {
errors
cache 30
forward . 10.100.0.10
}
svc.acme.internal:53 {
errors
cache 30
forward . 192.168.240.1
}Đọc địa chỉ của cụm từ dịch vụ kube-dns trong kube-system thay vì sao chép từ bài viết, vì CIDR của dịch vụ khác nhau. Địa chỉ đường hầm đến từ giá trị dhcp-option DNS mà máy chủ OpenVPN đẩy xuống, hoặc từ máy chủ có thẩm quyền của vùng đó. Nếu resolver của cụm không trả lời tên công khai, hãy đặt địa chỉ resolver của nút trong khối bắt tất cả, đọc trên nút và không phải trong pod.
Đừng hướng khối bắt tất cả tới /etc/resolv.conf, đó là dòng một lệnh hấp dẫn và là cạm bẫy trong đúng cấu hình này. Dưới dnsPolicy: None, tệp của chính pod chứa máy chủ tên duy nhất 127.0.0.1, nên mục tiêu đó là chính CoreDNS và mọi truy vấn không khớp sẽ lặp lại cho đến khi hết thời gian. Khối tên svc.acme.internal khớp với tên đó và mọi tên bên dưới, bao gồm db.svc.acme.internal và loại trừ svc.acme.internal.example.net. Dấu chấm cuối là hình thức, vì tên vùng được chuẩn hóa thành dạng đầy đủ; ranh giới hậu tố quyết định truy vấn rơi vào đâu.
Quyết định việc chuyển tiếp thuộc về resolver của cụm hay không
Nếu mọi khối lượng công việc trong không gian tên cần vùng đường hầm, một khối chuyển tiếp trong ConfigMap của CoreDNS dưới kube-system rẻ hơn sidecar cho mỗi pod. Thay đổi đó là cấp cụm: cần quyền quản trị và khởi động lại một triển khai mà mọi người phụ thuộc. Giới hạn nó trong đúng vùng đó, không bao giờ tới gốc. Địa chỉ đường hầm của một khối lượng công việc trở thành resolver của mọi pod cho vùng đó, và vào ngày đường hầm sụp, cả cụm mất tên đó.
Sidecar giữ bán kính ảnh hưởng trong một pod, đó là mặc định tốt hơn khi chỉ vài dịch vụ cần mạng từ xa. Dù chọn gì, hãy ghi lại resolver nào sở hữu vùng, vì người tiếp theo gỡ lỗi timeout sẽ hỏi.
Những tên vẫn phân giải được khi kết nối còn thất bại
Phân giải là một trong hai thứ đường hầm phải mang; thứ còn lại là đường về, và mạng của pod che giấu nó rất tốt. Nếu chính máy chủ OpenVPN chạy như một pod, các quy tắc bạn thêm vào container đó không kiểm soát lưu lượng đi ra qua nút. Lỗi đó hẹp: chỉ các pod trên nút cũng chạy máy chủ mới nhận được câu trả lời, còn lại đều hết thời gian.
Chạy máy chủ với hostNetwork: true đưa nó trở lại không gian tên của nút, nơi quy tắc FORWARD và dịch nguồn hoạt động. Dịch nhóm máy khách khi ra ngoài, nếu không không nút từ xa nào có tuyến quay về địa chỉ đường hầm như 10.8.0.6. Kiểm tra cả hai chiều trước khi chạm vào Corefile lần nữa. Một đường hầm mang truy vấn nhưng không mang câu trả lời tạo ra đúng thời gian chờ như một resolver chưa bao giờ nhận truy vấn.
Xác minh từ pod mới, không phải từ phiên bạn đã sửa
Hỏi cả hai vùng một cách rõ ràng, sau đó lặp lại truy vấn sau khi pod được thay. Cấu hình chỉ tồn tại trong một container đang chạy không phải là cấu hình:
kubectl exec -it deploy/app -- dig @127.0.0.1 kubernetes.default.svc.cluster.local +short
kubectl exec -it deploy/app -- dig @127.0.0.1 db.svc.acme.internal +short
kubectl delete pod -l app=your-app
kubectl wait --for=condition=Ready pod -l app=your-app --timeout=90s
kubectl exec -it deploy/app -- dig @127.0.0.1 db.svc.acme.internal +shortNếu cặp đầu trả lời và cặp sau khi thay không, Corefile đúng và đặc tả pod không. Nếu cả hai trả lời nhưng ứng dụng vẫn không kết nối, hãy dừng gỡ lỗi DNS và thử tuyến TCP với nc -vz db.svc.acme.internal 5432 từ bên trong container. Giữ đầu ra dig trong phiếu, vì đó là vật chứng tách vấn đề tên khỏi vấn đề định tuyến.