宇宙第一游 發表於 2025-5-17 20:38:00

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

<h2 id="概述">概述</h2>
<p>K8s集群内部的Pod默认是不对外提供访问,只能在集群内部进行访问。这样做是为什么呢?</p>
<ul>
<li>安全性考虑</li>
</ul>
<p>Kubernetes设计时遵循最小权限原则,即组件仅获得完成其任务所需的最少权限。直接暴露Pod给外部网络可能会引入安全隐患,比如让攻击者更容易定位和攻击运行在Pod内的服务。通过限制Pod的直接访问,Kubernetes鼓励使用更安全的服务暴露机制。</p>
<ul>
<li>可管理性和弹性</li>
</ul>
<p>Kubernetes设计鼓励使用Service来抽象Pod的访问。Service为一组具有相同功能的Pod提供一个稳定的服务访问入口,并且可以实现负载均衡。即使Pod因为故障重建或扩展,Service依然能够透明地路由流量到新的或现有的Pod实例,从而保证服务的高可用性和弹性。</p>
<p>外部要访问集群内部的Pod常用的有以下几种方式:</p>
<ul>
<li>hostNetwork:直接使用宿主机网络的方式</li>
<li>HostPort:在 Pod 定义中直接将容器端口映射到宿主机端口,绕过 Service 层,外部可通过 <code>节点 IP + HostPort</code> 直接访问 Pod。</li>
<li>port-forward:用于在本地计算机和集群内运行的Pod之间建立临时的网络连接,实现端口转发。通常用于开发或者测试</li>
<li>service:通过service的nodePort来进行访问</li>
<li>ingress:通过ingress来进行访问,类似nginx</li>
</ul>
<h2 id="hostnetwork方式">HostNetwork方式</h2>
<p>这种方式通常用于开发、测试环境,不推荐生产环境使用。</p>
<p>直接使用宿主机网络的方式,使用方式如下:<br>
<code>hostNetwork &lt;boolean&gt;</code> 是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络</p>
<p>使用hostNetwork方式不要使用deploy部署的方式,这样会导致所有的Pod的端口都被占用</p>
<p>推荐使用Pod部署的方式<br>
示例:</p>
<pre><code># 定义deploy文件
# cat deploy-tomcat.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-tomcat
namespace: default
spec:
# 定义更新策略
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

# 创建
# kubectl apply -f deploy-tomcat.yaml
deployment.apps/deployment-tomcat created
</code></pre>
<h4 id="查看pod的启动状态">查看Pod的启动状态</h4>
<pre><code># kubectl get po -o wide | grep deployment-tomcat
deployment-tomcat-577bcdbddc-5xvpl   0/1   CrashLoopBackOff   2 (27s ago)       56s   10.0.0.31         node01   &lt;none&gt;         &lt;none&gt;
deployment-tomcat-577bcdbddc-c7mbs   0/1   CrashLoopBackOff   2 (21s ago)       56s   10.0.0.32         node02   &lt;none&gt;         &lt;none&gt;
deployment-tomcat-577bcdbddc-dn7qb   0/1   CrashLoopBackOff   2 (21s ago)       56s   10.0.0.31         node01   &lt;none&gt;         &lt;none&gt;
deployment-tomcat-577bcdbddc-ffp4f   0/1   CrashLoopBackOff   2 (21s ago)       56s   10.0.0.31         node01   &lt;none&gt;         &lt;none&gt;
deployment-tomcat-577bcdbddc-fpsb5   1/1   Running            0               56s   10.0.0.31         node01   &lt;none&gt;         &lt;none&gt;
deployment-tomcat-577bcdbddc-gj9wg   1/1   Running            0               56s   10.0.0.32         node02   &lt;none&gt;         &lt;none&gt;
deployment-tomcat-577bcdbddc-jnvg5   0/1   CrashLoopBackOff   2 (27s ago)       56s   10.0.0.32         node02   &lt;none&gt;         &lt;none&gt;
deployment-tomcat-577bcdbddc-qsxhj   0/1   CrashLoopBackOff   2 (21s ago)       56s   10.0.0.32         node02   &lt;none&gt;         &lt;none&gt;
deployment-tomcat-577bcdbddc-swts5   0/1   CrashLoopBackOff   2 (21s ago)       56s   10.0.0.31         node01   &lt;none&gt;         &lt;none&gt;
deployment-tomcat-577bcdbddc-x6lb2   0/1   CrashLoopBackOff   2 (21s ago)       56s   10.0.0.32         node02   &lt;none&gt;         &lt;none&gt;
</code></pre>
<p>这里有很多Pod未启动成功,即使启动成功了也访问不了,为什么呢?<br>
查看一下日志,发现是对应的端口被占用了,我们上面提到过,hostNetwork是使用宿主机的网络,也会使用宿主机的端口,所以当Pod调度过去之后端口被其它的Pod占用了</p>
<p>那么为什么启动的Pod也访问不了呢?因为deploy部署的时候所有的Pod都是同时创建的,都去争抢宿主机的端口,这就导致谁也抢不到需要绑定的端口</p>
<pre><code># kubectl logs -f deployment-tomcat-577bcdbddc-qsxhj
16-May-2025 15:46:31.134 SEVERE org.apache.catalina.core.StandardServer.await Failed to create server shutdown socket on address and port (base port and offset )
      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.&lt;init&gt;(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)
</code></pre>
<h3 id="使用pod进行部署">使用Pod进行部署</h3>
<pre><code># cat pod-tomcat.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-tomcat
spec:
hostNetwork: true
containers:
- name: container-tomcat
    image: tomcat:latest
    imagePullPolicy: Always
# kubectl apply -f pod-tomcat.yaml
pod/pod-tomcat created

# 查看pod调度到哪个节点
# kubectl get po -o wide
NAME                              READY   STATUS             RESTARTS      AGE   IP                NODE   NOMINATED NODE   READINESS GATES
pod-tomcat                        1/1   Running            0               7s      10.0.0.32         node02   &lt;none&gt;         &lt;none&gt;

</code></pre>
<h3 id="访问一下">访问一下</h3>
<p>查看Pod调度到哪个节点上,用节点IP进行访问,例如我使用10.0.0.32节点的IP进行访问</p>
<pre><code># 验证端口是否存在,tomcat端口为8080
# ss -lntup | grep 8080
tcp   LISTEN 0      100                     *:8080             *:*    users:(("java",pid=2141262,fd=44))

# 在master节点进行curl访问
# curl 10.0.0.32:8080
&lt;!doctype html&gt;&lt;html lang="en"&gt;&lt;head&gt;&lt;title&gt;HTTP Status 404 – Not Found&lt;/title&gt;...
</code></pre>
<h2 id="hostport">HostPort</h2>
<p>在 Pod 定义中直接将容器端口映射到宿主机端口,绕过 Service 层,外部可通过 <code>节点 IP + HostPort</code> 直接访问 Pod。</p>
<p><strong>这种方式在k8s v1.23.17+版本之后不会有端口监听,是采用iptables来进行转发规则。</strong></p>
<p>示例:</p>
<pre><code># 定义资源文件
# cat pod-tomcat.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-tomcat
spec:
containers:
- name: container-tomcat
    image: tomcat:latest
    imagePullPolicy: Always
    ports:
    - name: http
      # 容器的端口
      containerPort: 8080
      # 映射到宿主机的端口
      hostPort: 8080
      # 指定端口协议
      protocol: TCP
# 创建Pod
# kubectl apply -f pod-tomcat.yaml
pod/pod-tomcat created
</code></pre>
<h3 id="访问测试">访问测试</h3>
<pre><code># 查看Pod调度到哪个节点
# kubectl get po -o wide
NAME                              READY   STATUS             RESTARTS          AGE   IP                NODE   NOMINATED NODE   READINESS GATES
pod-tomcat                        1/1   Running            0               28s   100.95.185.255    node02   &lt;none&gt;         &lt;none&gt;

# 通过分配的IP进行访问
# curl 100.95.185.255:8080
&lt;!doctype html&gt;&lt;html lang="en"&gt;&lt;head&gt;&lt;title&gt;HTTP Status 404 – Not Found&lt;/title&gt;...

# 通过宿主机IP进行访问
# curl 10.0.0.32:8080
&lt;!doctype html&gt;&lt;html lang="en"&gt;&lt;head&gt;&lt;title&gt;HTTP Status 404 – Not Found&lt;/title&gt;...
</code></pre>
<h2 id="port-forward方式">port-forward方式</h2>
<p><code>kubectl port-forward </code>是 Kubernetes 命令行工具 (kubectl) 提供的一个功能,用于在本地计算机和集群内运行的Pod之间建立临时的网络连接,实现端口转发。通常用于开发或者测试</p>
<h3 id="基本语法">基本语法</h3>
<pre><code>kubectl port-forward POD REMOTE_PORT [-n NAMESPACE] --address IP地址 --pod-running-timeout 300
</code></pre>
<p>参数解析:</p>
<ul>
<li>POD: 需要转发端口的Pod的名称或标签选择器。</li>
<li>LOCAL_PORT: 本地计算机上的端口号,可选。如果不指定,Kubernetes会随机选择一个可用的本地端口。</li>
<li>REMOTE_PORT: Pod中需要转发的端口号。</li>
<li>-n NAMESPACE: 指定Pod所在的命名空间,如果不在当前上下文中,则需要指定。</li>
<li>--address:指定外部访问的地址</li>
<li>--pod-running-timeout: 参数设置等待Pod运行的最长时间,超过这个时间命令会退出</li>
</ul>
<h3 id="示例">示例</h3>
<pre><code># 创建deploy
# cat deploy-tomcat.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-tomcat
namespace: default
spec:
# 定义更新策略
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
# kubectl apply -f deploy-tomcat.yaml
deployment.apps/deployment-tomcat created
</code></pre>
<p>进行port-forward</p>
<pre><code># kubectl port-forward deployment-tomcat-7ddf96c4d8-mgqzf 8080:8080 --address 0.0.0.0
Forwarding from 0.0.0.0:8080 -&gt; 8080
</code></pre>
<p>访问测试</p>
<pre><code># curl访问
# curl 10.0.0.30:8080
&lt;!doctype html&gt;&lt;html lang="en"&gt;&lt;head&gt;&lt;title&gt;HTTP Status 404 – Not Found
</code></pre>
<p>浏览器访问,这里404只是表示没有资源,但是访问成功了<br>
<img src="https://img2024.cnblogs.com/blog/3468887/202505/3468887-20250517003712174-1346932574.png" alt="image" loading="lazy"></p>
<h2 id="service的方式">service的方式</h2>
<p>service有两种方式可以将Pod对外提供访问,分别是NodePort和Loadbanlacer</p>
<p>NodePort可以看这篇文章:K8s新手系列之Service资源<br>
Loadbanlacer可以看这篇文章:K8s进阶之MetalLB实现LoadBalancer</p>
<h2 id="ingress的方式生产环境推荐">ingress的方式(生产环境推荐!!!)</h2>
<p>Ingress相当于一个7层的负载均衡器,是kubernetes对反向代理的一个抽象,它的工作原理类似于Nginx,可以理解成在Ingress里建立诸多映射规则,Ingress Controller通过监听这些配置规则并转化成Nginx的反向代理配置 , 然后对外部提供服务</p>
<p>可以参考这篇文章:K8s进阶之初识Ingress</p>


</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自博客园,作者:huangSir-devops,转载请注明原文链接:https://www.cnblogs.com/huangSir-devops/p/18880897,微信Vac6666666,欢迎交流</p><br><br>
来源:https://www.cnblogs.com/huangSir-devops/p/18880897
頁: [1]
查看完整版本: K8s进阶之外部访问Pod的几种方式