写点什么

K8s 进阶之外部访问 Pod 的几种方式

  • 2025-05-19
    福建
  • 本文字数:4860 字

    阅读完需:约 16 分钟

概述


K8s 集群内部的 Pod 默认是不对外提供访问,只能在集群内部进行访问。这样做是为什么呢?


  • 安全性考虑

Kubernetes 设计时遵循最小权限原则,即组件仅获得完成其任务所需的最少权限。直接暴露 Pod 给外部网络可能会引入安全隐患,比如让攻击者更容易定位和攻击运行在 Pod 内的服务。通过限制 Pod 的直接访问,Kubernetes 鼓励使用更安全的服务暴露机制。


  • 可管理性和弹性

Kubernetes 设计鼓励使用 Service 来抽象 Pod 的访问。Service 为一组具有相同功能的 Pod 提供一个稳定的服务访问入口,并且可以实现负载均衡。即使 Pod 因为故障重建或扩展,Service 依然能够透明地路由流量到新的或现有的 Pod 实例,从而保证服务的高可用性和弹性。


外部要访问集群内部的 Pod 常用的有以下几种方式:

  • hostNetwork:直接使用宿主机网络的方式

  • HostPort:在 Pod 定义中直接将容器端口映射到宿主机端口,绕过 Service 层,外部可通过 节点 IP + HostPort 直接访问 Pod。

  • port-forward:用于在本地计算机和集群内运行的 Pod 之间建立临时的网络连接,实现端口转发。通常用于开发或者测试

  • service:通过 service 的 nodePort 来进行访问

  • ingress:通过 ingress 来进行访问,类似 nginx


HostNetwork 方式


这种方式通常用于开发、测试环境,不推荐生产环境使用。


直接使用宿主机网络的方式,使用方式如下:hostNetwork <boolean> 是否使用主机网络模式,默认为 false,如果设置为 true,表示使用宿主机网络


使用 hostNetwork 方式不要使用 deploy 部署的方式,这样会导致所有的 Pod 的端口都被占用


推荐使用 Pod 部署的方式示例:


# 定义deploy文件[root@master01 ~/deploy]# cat deploy-tomcat.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: deployment-tomcat  namespace: defaultspec:  # 定义更新策略  strategy:    type: RollingUpdate    rollingUpdate:      maxSurge: 1      maxUnavailable: 1  replicas: 10  selector:    matchLabels:      app: tomcat  template:    metadata:      name: pod-tomcat      labels:        app: tomcat    spec:      # 使用hostNetwork的方式暴漏端口访问方式      hostNetwork: true      containers:      - name: container-tomcat        image: tomcat:9.0      restartPolicy: Always # 创建[root@master01 ~/deploy]# kubectl apply -f deploy-tomcat.yamldeployment.apps/deployment-tomcat created
复制代码


查看 Pod 的启动状态


[root@master01 ~/deploy]# kubectl get po -o wide | grep deployment-tomcatdeployment-tomcat-577bcdbddc-5xvpl   0/1     CrashLoopBackOff   2 (27s ago)       56s     10.0.0.31         node01   <none>           <none>deployment-tomcat-577bcdbddc-c7mbs   0/1     CrashLoopBackOff   2 (21s ago)       56s     10.0.0.32         node02   <none>           <none>deployment-tomcat-577bcdbddc-dn7qb   0/1     CrashLoopBackOff   2 (21s ago)       56s     10.0.0.31         node01   <none>           <none>deployment-tomcat-577bcdbddc-ffp4f   0/1     CrashLoopBackOff   2 (21s ago)       56s     10.0.0.31         node01   <none>           <none>deployment-tomcat-577bcdbddc-fpsb5   1/1     Running            0                 56s     10.0.0.31         node01   <none>           <none>deployment-tomcat-577bcdbddc-gj9wg   1/1     Running            0                 56s     10.0.0.32         node02   <none>           <none>deployment-tomcat-577bcdbddc-jnvg5   0/1     CrashLoopBackOff   2 (27s ago)       56s     10.0.0.32         node02   <none>           <none>deployment-tomcat-577bcdbddc-qsxhj   0/1     CrashLoopBackOff   2 (21s ago)       56s     10.0.0.32         node02   <none>           <none>deployment-tomcat-577bcdbddc-swts5   0/1     CrashLoopBackOff   2 (21s ago)       56s     10.0.0.31         node01   <none>           <none>deployment-tomcat-577bcdbddc-x6lb2   0/1     CrashLoopBackOff   2 (21s ago)       56s     10.0.0.32         node02   <none>           <none>
复制代码


这里有很多 Pod 未启动成功,即使启动成功了也访问不了,为什么呢?查看一下日志,发现是对应的端口被占用了,我们上面提到过,hostNetwork 是使用宿主机的网络,也会使用宿主机的端口,所以当 Pod 调度过去之后端口被其它的 Pod 占用了


那么为什么启动的 Pod 也访问不了呢?因为 deploy 部署的时候所有的 Pod 都是同时创建的,都去争抢宿主机的端口,这就导致谁也抢不到需要绑定的端口


[root@master01 ~/deploy]# kubectl logs -f deployment-tomcat-577bcdbddc-qsxhj16-May-2025 15:46:31.134 SEVERE [main] org.apache.catalina.core.StandardServer.await Failed to create server shutdown socket on address [localhost] and port [8005] (base port [8005] and offset [0])        java.net.BindException: Address already in use                at java.base/sun.nio.ch.Net.bind0(Native Method)                at java.base/sun.nio.ch.Net.bind(Net.java:565)                at java.base/sun.nio.ch.Net.bind(Net.java:554)                at java.base/sun.nio.ch.NioSocketImpl.bind(NioSocketImpl.java:636)                at java.base/java.net.ServerSocket.bind(ServerSocket.java:391)                at java.base/java.net.ServerSocket.<init>(ServerSocket.java:278)                at org.apache.catalina.core.StandardServer.await(StandardServer.java:537)                at org.apache.catalina.startup.Catalina.await(Catalina.java:829)                at org.apache.catalina.startup.Catalina.start(Catalina.java:777)                at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)                at java.base/java.lang.reflect.Method.invoke(Method.java:580)                at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:345)                at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:476)
复制代码


使用 Pod 进行部署


[root@master01 ~/pod]# cat pod-tomcat.yamlapiVersion: v1kind: Podmetadata:  name: pod-tomcatspec:  hostNetwork: true  containers:  - name: container-tomcat    image: tomcat:latest    imagePullPolicy: Always[root@master01 ~/pod]# kubectl apply -f pod-tomcat.yamlpod/pod-tomcat created # 查看pod调度到哪个节点[root@master01 ~/pod]# kubectl get po -o wideNAME                                READY   STATUS             RESTARTS        AGE     IP                NODE     NOMINATED NODE   READINESS GATESpod-tomcat                          1/1     Running            0               7s      10.0.0.32         node02   <none>           <none>
复制代码


访问一下


查看 Pod 调度到哪个节点上,用节点 IP 进行访问,例如我使用 10.0.0.32 节点的 IP 进行访问


# 验证端口是否存在,tomcat端口为8080[root@node02 ~]# ss -lntup | grep 8080tcp   LISTEN 0      100                     *:8080             *:*    users:(("java",pid=2141262,fd=44)) # 在master节点进行curl访问[root@master01 ~/pod]# curl 10.0.0.32:8080<!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found</title>...
复制代码


HostPort


在 Pod 定义中直接将容器端口映射到宿主机端口,绕过 Service 层,外部可通过 节点 IP + HostPort 直接访问 Pod。


这种方式在 k8s v1.23.17+版本之后不会有端口监听,是采用 iptables 来进行转发规则。

示例:


# 定义资源文件[root@master01 ~/pod]# cat pod-tomcat.yamlapiVersion: v1kind: Podmetadata:  name: pod-tomcatspec:  containers:  - name: container-tomcat    image: tomcat:latest    imagePullPolicy: Always    ports:    - name: http      # 容器的端口      containerPort: 8080      # 映射到宿主机的端口      hostPort: 8080      # 指定端口协议      protocol: TCP# 创建Pod[root@master01 ~/pod]# kubectl apply -f pod-tomcat.yamlpod/pod-tomcat created
复制代码


访问测试


# 查看Pod调度到哪个节点[root@master01 ~/pod]# kubectl get po -o wideNAME                                READY   STATUS             RESTARTS          AGE     IP                NODE     NOMINATED NODE   READINESS GATESpod-tomcat                          1/1     Running            0                 28s     100.95.185.255    node02   <none>           <none> # 通过分配的IP进行访问[root@master01 ~/pod]# curl 100.95.185.255:8080<!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found</title>... # 通过宿主机IP进行访问[root@master01 ~/pod]# curl 10.0.0.32:8080<!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found</title>...
复制代码


port-forward 方式


kubectl port-forward是 Kubernetes 命令行工具 (kubectl) 提供的一个功能,用于在本地计算机和集群内运行的 Pod 之间建立临时的网络连接,实现端口转发。通常用于开发或者测试


基本语法


kubectl port-forward POD [LOCAL_PORT:]REMOTE_PORT [-n NAMESPACE] --address IP地址 --pod-running-timeout 300
复制代码


参数解析:

  • POD: 需要转发端口的 Pod 的名称或标签选择器。

  • LOCAL_PORT: 本地计算机上的端口号,可选。如果不指定,Kubernetes 会随机选择一个可用的本地端口。

  • REMOTE_PORT: Pod 中需要转发的端口号。

  • -n NAMESPACE: 指定 Pod 所在的命名空间,如果不在当前上下文中,则需要指定。

  • --address:指定外部访问的地址

  • --pod-running-timeout: 参数设置等待 Pod 运行的最长时间,超过这个时间命令会退出


示例


# 创建deploy[root@master01 ~/deploy]# cat deploy-tomcat.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: deployment-tomcat  namespace: defaultspec:  # 定义更新策略  strategy:    type: RollingUpdate    rollingUpdate:      maxSurge: 1      maxUnavailable: 1  replicas: 3  selector:    matchLabels:      app: tomcat  template:    metadata:      name: pod-tomcat      labels:        app: tomcat    spec:      containers:      - name: container-tomcat        image: tomcat:9.0      restartPolicy: Always[root@master01 ~/deploy]# kubectl apply -f deploy-tomcat.yamldeployment.apps/deployment-tomcat created
复制代码


进行 port-forward


[root@master01 ~/deploy]# kubectl port-forward deployment-tomcat-7ddf96c4d8-mgqzf 8080:8080 --address 0.0.0.0Forwarding from 0.0.0.0:8080 -> 8080
复制代码


访问测试


# curl访问[root@node01 ~]# curl 10.0.0.30:8080<!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found
复制代码


浏览器访问,这里 404 只是表示没有资源,但是访问成功了



service 的方式


service 有两种方式可以将 Pod 对外提供访问,分别是 NodePort 和 Loadbanlacer


ingress 的方式(生产环境推荐!!!)


Ingress 相当于一个 7 层的负载均衡器,是 kubernetes 对反向代理的一个抽象,它的工作原理类似于 Nginx,可以理解成在 Ingress 里建立诸多映射规则,Ingress Controller 通过监听这些配置规则并转化成 Nginx 的反向代理配置 , 然后对外部提供服务


文章转载自:huangSir-devops

原文链接:https://www.cnblogs.com/huangSir-devops/p/18880897

体验地址:http://www.jnpfsoft.com/?from=001YH

用户头像

还未添加个人签名 2025-04-01 加入

还未添加个人简介

评论

发布
暂无评论
K8s进阶之外部访问Pod的几种方式_容器_电子尖叫食人鱼_InfoQ写作社区