我有一个在端口 4840 上运行 OPC 服务器的容器。我正在尝试配置我的 microk8s 以允许我的 OPC 客户端连接到端口 4840。以下是我的部署和服务的示例:
(这里没有定义命名空间,但它们是通过 Azure 管道部署的,并且命名空间就是在这里定义的,部署和服务的命名空间是“jawcrusher”)
部署.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: jawcrusher
spec:
replicas: 1
selector:
matchLabels:
app: jawcrusher
strategy: {}
template:
metadata:
labels:
app: jawcrusher
spec:
volumes:
- name: jawcrusher-config
configMap:
name: jawcrusher-config
containers:
- image: XXXmicrok8scontainerregistry.azurecr.io/jawcrusher:#{Version}#
name: jawcrusher
ports:
- containerPort: 4840
volumeMounts:
- name: jawcrusher-config
mountPath: "/jawcrusher/config/config.yml"
subPath: "config.yml"
imagePullSecrets:
- name: acrsecret
服务.yml
apiVersion: v1
kind: Service
metadata:
name: jawcrusher-service
spec:
ports:
- name: 4840-4840
port: 4840
protocol: TCP
targetPort: 4840
selector:
app: jawcrusher
type: ClusterIP
status:
loadBalancer: {}
所以现在我想告诉 microk8s 从端口 4840“外部”为我的 OPC 服务器提供服务。例如,如果我的服务器 DNS 是 microk8s.xxxx.internal,我想将我的 OPC 客户端连接到 microk8s.xxxx.internal:4840。
我遵循了这个例子:https://microk8s.io/docs/addon-ingress(向下滚动一点查看 tcp 部分)
它说要更新入口的 tcp 配置,这是我更新后的样子:
nginx-ingress-tcp-microk8s-conf:
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-ingress-tcp-microk8s-conf
namespace: ingress
......
data:
'4840': jawcrusher/jawcrusher-service:4840
binaryData: {}
它还表示要在入口控制器中公开端口。添加新端口后,它看起来如下:
nginx-ingress-microk8s-控制器:
spec:
containers:
- name: nginx-ingress-microk8s
image: registry.k8s.io/ingress-nginx/controller:v1.2.0
args:
- /nginx-ingress-controller
- '--configmap=$(POD_NAMESPACE)/nginx-load-balancer-microk8s-conf'
- >-
--tcp-services-configmap=$(POD_NAMESPACE)/nginx-ingress-tcp-microk8s-conf
- >-
--udp-services-configmap=$(POD_NAMESPACE)/nginx-ingress-udp-microk8s-conf
- '--ingress-class=public'
- ' '
- '--publish-status-address=127.0.0.1'
ports:
- name: http
hostPort: 80
containerPort: 80
protocol: TCP
- name: https
hostPort: 443
containerPort: 443
protocol: TCP
- name: health
hostPort: 10254
containerPort: 10254
protocol: TCP
####THIS IS WHAT I ADDED####
- name: jawcrusher
hostPort: 4840
containerPort: 4840
protocol: TCP
更新守护进程集后,它会重新启动所有 pod。端口似乎已打开,如果我运行此脚本,则输出:
Test-NetConnection -ComputerName microk8s.xxxx.internal -Port 4840
ComputerName : microk8s.xxxx.internal
RemoteAddress : 10.161.64.124
RemotePort : 4840
InterfaceAlias : Ethernet 2
SourceAddress : 10.53.226.55
TcpTestSucceeded : True
在我进行更改之前,它显示 TcpTestSucceeded:False。
但 OPC-Client 无法连接。它只是说:无法连接到服务器:BadCommunicationError。
当我尝试使用 OPC-Client 连接到服务器时,我在 ingress-daemonset-pod 日志中看到一条错误消息:
2023/02/15 09:57:32 [错误] 999#999:*63002 connect() 连接到上游时失败(111:连接被拒绝),客户端:10.53.225.232,服务器:0.0.0.0:4840,上游:“10.1.98.125:4840”,来自/到客户端的字节数:0/0,来自/到上游的字节数:0/0
10.53.225.232 是客户端机器的 IP 地址(运行 OPC 客户端的位置),10.1.98.125 是运行 OPC 服务器的 pod 的 IP 号码。
因此,它似乎已经理解外部端口 4840 应该代理/转发到我的服务,而我的服务又指向 OPC-server-pod。但为什么我会收到错误...
我不想使用端口转发解决方案,但我尝试了一下,只是想看看它是否有效。
kubectl port-forward service/jawcrusher-service 5000:4840 -n jawcrusher --address='0.0.0.0'
这使我能够使用 OPC 客户端通过端口 5000 连接到服务器。但我不想使用端口转发,我想要一个更永久的解决方案。
有人看到我是否在某个地方犯了错误或者知道如何在 microk8s 中做到这一点吗?
更新 1:这是 netstat 的输出:
root@jawcrusher-7787464c5-8w5ww:/jawcrusher# netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:4840 0.0.0.0:* LISTEN 1/python
tcp6 0 0 ::1:4840 :::* LISTEN 1/python
答案1
几乎在任何情况下,Ingress
或Service
设置不起作用但运行kubectl port-forward
起作用,几乎总是容器在 127.0.0.1 上监听,而所有 Pod 都必须监听 0.0.0.0。kubectl port-forward
始终有效的原因是它实际上使用与 Pod 的沙盒容器相同的网络 cgroup 中生成的副本socat
,因此其连接性并不代表集群的连接性到 Pod
一个快速测试可以kubectl exec
进入集群中的任何其他 Pod(或者也可以通过 ssh/ssm 进入节点),并向 Pod 的 IP 地址发出 curl(或 wget),看看是否可以从集群中的其他地方访问它。由于 Kubernetes 设计要求所有 Pod 都可以相互连接(模数网络策略),因此这是一个低成本的测试,可以找出任何人可以到达该容器,而不仅仅是Ingress
或Service
配置