Kubernetes中HostPort搭配dnsmasq的外部访问问题:如何配置dnsmasq Pod为外部可用DNS服务器
我正尝试通过Kubernetes部署一个dnsmasq Pod,对应的YAML配置文件如下:
apiVersion: apps/v1 kind: StatefulSet metadata: name: dnsmasq1 labels: name: dnsmasq1 spec: serviceName: "dnsmasq1" replicas: 1 selector: matchLabels: name: dnsmasq1 volumeClaimTemplates: - metadata: name: dnsmasqconf-pv1 spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: ceph-rbd-sc template: metadata: labels: name: dnsmasq1 spec: hostNetwork: false affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: name: dnsmasq1 topologyKey: "kubernetes.io/hostname" hostname: dnsmasq1 containers: - name: dnsmasq1 image: jpillora/dnsmasq ports: - containerPort: 8080 hostPort: 8082 imagePullPolicy: IfNotPresent env: - name: HTTP_USER value: "****" - name: HTTP_PASS value: "****" volumeMounts: - mountPath: /mnt/config name: dnsmasqconf-pv1 resources: requests: memory: 250Mi limits: memory: 250Mi nodeSelector: etiket: worker dnsPolicy: "None" dnsConfig: nameservers: - 8.8.8.8 volumes: - name: dnsmasqconf-pv1 persistentVolumeClaim: claimName: dnsmasqconf-pv1
当前该Pod部署正常,我可以通过节点IP访问到该Pod的8082端口(HTTP管理界面),但当我在测试机上将其作为DNS服务器使用时,无法解析DNS条目。我推测这是因为我使用的是节点IP而非Pod IP作为DNS服务器地址,而且我没有云服务提供商,无法使用LoadBalancer类型的Service。请问该如何配置才能让这个dnsmasq Pod可以被外部设备作为DNS服务器使用?
首先要指出你当前配置里的一个关键问题:你的dnsmasq容器只暴露了8080端口(HTTP管理界面),但dnsmasq提供DNS服务的默认端口是53(TCP+UDP),这是外部设备无法解析DNS的核心原因之一。先修正这个问题,再结合无LoadBalancer的场景,给你几个可行的方案:
方案1:使用NodePort类型的Service(最通用)
NodePort会在集群的每个节点上开放一个固定的端口,将流量转发到Pod的53端口。外部设备可以通过「节点IP:NodePort」作为DNS服务器地址。
步骤:
修改StatefulSet的容器端口配置,添加53端口的TCP和UDP暴露:
在containers[0].ports下添加:- containerPort: 53 protocol: TCP - containerPort: 53 protocol: UDP(不需要设置
hostPort,由Service来处理端口映射)创建NodePort类型的Service,指向dnsmasq Pod:
apiVersion: v1 kind: Service metadata: name: dnsmasq-service spec: type: NodePort selector: name: dnsmasq1 ports: - name: dns-tcp port: 53 targetPort: 53 protocol: TCP nodePort: 30053 # 可选,指定固定端口,范围30000-32767 - name: dns-udp port: 53 targetPort: 53 protocol: UDP nodePort: 30053 # TCP和UDP可以用同一个NodePort测试:在外部测试机上,将DNS服务器设置为
你的节点IP:30053,然后尝试解析域名。
方案2:使用HostNetwork模式(直接复用节点网络)
如果你的集群节点没有其他服务占用53端口,可以让Pod直接使用节点的网络栈,这样外部设备可以直接用节点IP作为DNS服务器地址(无需额外端口)。
步骤:
修改StatefulSet的Pod配置:
- 将
hostNetwork: false改为hostNetwork: true - 在
containers[0].ports添加53端口的映射(可以绑定到节点的53端口,或者其他端口):- containerPort: 53 hostPort: 53 protocol: TCP - containerPort: 53 hostPort: 53 protocol: UDP - 注意:如果节点上的53端口被
systemd-resolved或kube-dns占用,需要先停止这些服务,或者将dnsmasq绑定到其他端口(比如5353),测试机用节点IP:5353作为DNS地址。
- 将
验证Pod启动后,在节点上执行
ss -tulpn | grep 53,确认dnsmasq正在监听该端口。
方案3:使用带ExternalIPs的ClusterIP Service(适合有固定节点IP的场景)
如果你的节点有固定的局域网/公网IP,可以给ClusterIP Service添加externalIPs字段,外部设备直接用这个IP访问DNS服务,无需NodePort。
步骤:
- 先修正容器的53端口暴露(同方案1的第一步)
- 创建带ExternalIPs的ClusterIP Service:
apiVersion: v1 kind: Service metadata: name: dnsmasq-service spec: type: ClusterIP externalIPs: - 192.168.1.100 # 替换成你的节点固定IP selector: name: dnsmasq1 ports: - name: dns-tcp port: 53 targetPort: 53 protocol: TCP - name: dns-udp port: 53 targetPort: 53 protocol: UDP - 测试:外部测试机将DNS设置为
192.168.1.100即可。
额外注意事项
- 确保集群节点的防火墙允许对应的端口流量(比如NodePort的30053,或者53端口),否则外部设备无法连接。
- 如果你部署了多个dnsmasq副本,可以通过Service实现负载均衡,外部设备使用任意节点IP+NodePort都能访问。
内容的提问来源于stack exchange,提问作者Nyquillus

