019-K8S-kubectl端口转发

一、概述

在 Kubernetes 集群中,所有资源都运行在私有网络空间(通常使用 CNI 插件构建 overlay 网络),这带来了以下调试难题:

  • Pod 使用动态 IP 地址(生命周期短暂)
  • Service 的 ClusterIP 仅在集群内部可达
  • 生产环境通常禁用 NodePort 等暴露方式

针对上述的几种情况,我们就可以使用 kubectl port-forward来满足需求。

1. port-forward 介绍

kubectl port-forward 是 Kubernetes 命令行工具 kubectl 提供的一个功能,用于在本地主机和 Kubernetes 集群中的 Pod 之间建立端口转发。

当你运行 kubectl port-forward 命令时,它会将本地主机上的一个端口与 Kubernetes 集群中的一个 Pod 的端口进行绑定。这样,在本地主机上监听的端口上收到的流量将被转发到 Pod 的端口上,反之亦然。

这个功能在开发和调试应用程序时非常有用。以下是一些 kubectl port-forward的常见用途和好处:

  • 访问远程 Pod 的本地服务: 你可以将 Pod 的端口转发到本地主机,从而能够直接访问 Pod 上运行的服务。例如,你可以将一个运行在 Kubernetes 集群中的数据库 Pod 的端口转发到本地,以便在本地开发环境中连接和测试数据库。
  • 调试和日志记录: 通过将 Pod 的端口转发到本地,你可以使用本地工具来调试和监视在 Kubernetes 中运行的应用程序。你可以使用本地的调试器、日志记录工具或其他开发工具来检查应用程序的状态、调试问题或查看日志。
  • 绕过 Kubernetes 服务和负载均衡器: 有时候,你可能想直接访问运行在 Kubernetes 中的应用程序,而不经过 Kubernetes 的服务发现和负载均衡机制。通过将 Pod 的端口转发到本地,你可以绕过这些机制,直接连接到应用程序。

端口转发优势

特性 kubectl port-forward NodePort Ingress
无需修改资源配置
临时性访问
支持TCP/UDP TCP HTTP/HTTPS only
网络策略穿透

注意:kubectl port-forward 目前仅支持 TCP 端口的转发,对 UDP 协议的支持正在 GitHubIssue Port-forward for UDP 中进行跟踪。

2. 安装 socat

kubectl port-forward 命令依赖 socat 来处理本地端口与 Kubernetes Pod 之间的 TCP 连接转发。如果 socat 未安装,命令会无法执行转发操作,导致连接丢失(”lost connection to pod”)。

Pod 运行的每个节点都需要安装

# Linux(例如 Ubuntu/Debian):
sudo apt update
sudo apt install socat

# Linux(例如 CentOS/RHEL/Fedora)
sudo yum install socat

# dnf 系统
sudo dnf install socat

# macOS(使用 Homebrew)
brew install socat

二、kubectl port-forward 命令概述

1. 基本语法

kubectl port-forward <pod-name> [local-port:]pod-port [-n namespace]
  
kubectl port-forward deployment/<deployment-name> [local-port:]pod-port [-n namespace]

kubectl port-forward replicaset/<replicaset-name> [local-port:]pod-port [-n namespace]

kubectl port-forward service/<service-name> [local-port:]pod-port [-n namespace]

核心参数说明

-n, --namespace string       		指定命名空间(默认default)
--address stringArray        		绑定地址(默认为127.0.0.1), 0.0.0.0 表示所有ip都能连接访问
--pod-running-timeout duration 		等待Pod运行的最长时间

2. 多资源类型支持

# Pod 转发(直接访问指定Pod)
kubectl port-forward pod/nginx 8080:80
 
# Deployment 转发(自动选择最新Pod)
kubectl port-forward deployment/nginx 8080:80
 
# Service 转发(自动选择后端Pod)
kubectl port-forward svc/mysql 3306:3306
 
# StatefulSet 转发(指定序号Pod)
kubectl port-forward pod/redis-1 6379:6379

3. 高级转发模式

3.1 多端口转发

kubectl port-forward pod/nginx 8080:80 8443:443

3.2 后台运行

# 使用 nohup 防止终端关闭后进程终止
nohup kubectl port-forward pod/nginx 8080:80 > portforward.log 2>&1 < /dev/null &

命令解析

这个命令用于在后台运行 Kubernetes 的 kubectl port-forward 操作,将本地端口(8080)上的流量转发到 Kubernetes 中名为 nginx 的 Pod 的端口(80)。它通过 nohup 确保进程在终端关闭后继续运行,将输出重定向到日志文件,并将进程与终端分离。

  • **nohup**:作用:nohup(no hang-up,意为“无挂起”)是一个 Unix 工具,用于让进程在用户退出终端或关闭会话后继续运行。通常,当终端会话关闭时,进程会收到 SIGHUP(挂起信号)而终止,而 nohup 可以防止进程因收到此信号而停止。

  • **> portforward.log**:作用:将命令的标准输出(stdout)重定向到文件 portforward.log 中。

    • kubectl port-forward 的输出(例如连接信息或日志)会被写入到当前目录下的 portforward.log 文件,而不是显示在终端上。
    • 如果 portforward.log 文件已存在,> 会覆盖原有内容(若想追加而不是覆盖,可以用 >>)。
  • **2>&1**:作用:将标准错误(stderr)重定向到标准输出(stdout)。

    在 Unix/Linux 中,进程有三个标准文件描述符

    • 0:标准输入(stdin)
    • 1:标准输出(stdout)
    • 2:标准错误(stderr)

    2>&1 表示将标准错误(2)重定向到标准输出(1)的同一个目标。结合前面的 > portforward.log,这意味着标准错误和标准输出都会被写入到 portforward.log 文件中。

  • < /dev/null :将标准输入(stdin)重定向到 /dev/null。

    • /dev/null 是一个特殊的 Unix 文件,任何写入其中的数据都会被丢弃,读取时则返回空。
    • < /dev/null 表示将命令的标准输入设置为 /dev/null,意味着命令不会从终端读取任何输入。
  • & :将命令放入后台运行

    • & 使整个命令在后台执行,终端会立即返回提示符,允许用户继续执行其他命令。

    • 结合 nohup,这确保进程不仅在后台运行,而且在终端关闭后也不会终止。

关闭后台进程

# 查找进程
ps aux | grep kubectl
输出示例:user     12345  0.1  0.2 123456 7890 ?  S    04:00   0:00 kubectl port-forward pod/nginx 8080:80

# 杀死进程
kill -9 <PID>

三、案例实操

1. 创建 Pod

# 创建一个nginx deployment
$ kubectl create deployment nginx-deployment --image=nginx:1.29.0 --replicas=3

# 查看Deployment
$ kubectl get deployment -o wide
NAME               READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES         SELECTOR
nginx-deployment   2/3     3            2           14s   nginx        nginx:1.29.0   app=nginx-deployment

# 查看Pod
$ kubectl get pods -o wide
NAME                               READY   STATUS         RESTARTS   AGE    IP               NODE         NOMINATED NODE   READINESS GATES
nginx-deployment-95cff5589-5jldt   1/1     Running        0          108s   171.20.58.206    k8s-node02   <none>           <none>
nginx-deployment-95cff5589-b7klr   1/1     Running        0          108s   171.20.85.206    k8s-node01   <none>           <none>
nginx-deployment-95cff5589-jctfz   0/1     ErrImagePull   0          108s   171.20.135.129   k8s-node03   <none>           <none>

2. 本地访问pod

# 本地访问 Pod 正常
$ curl http://171.20.58.206:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<h1>Welcome to nginx!</h1>
</body>
</html>

3. 使用端口转发

仅本地访问

# 前台运行端口转发,此时转发的地址默认是 127.0.0.1,仅本地可以访问
$ kubectl port-forward deployment/nginx-deployment 30080:80 -n default
Forwarding from 127.0.0.1:30080 -> 80
Forwarding from [::1]:30080 -> 80


# 新开终端,通过转发的端口 30080 访问 pod
$ curl 127.0.0.1:30080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<h1>Welcome to nginx!</h1>
</body>
</html>

不限制访问IP

# 前台运行端口转发,所有IP可以访问
$ kubectl port-forward deployment/nginx-deployment 30080:80 -n default --address=0.0.0.0
Forwarding from 0.0.0.0:30080 -> 80

浏览器,通过转发端口访问 nginx

浏览器通过转发端口访问

四、故障排查与最佳实践

1. 常见错误解决方案

错误现象 可能原因 解决方案
unable to do port forwarding: pod not found Pod未启动 检查Pod状态:kubectl describe pod/[name]
error: listen tcp 127.0.0.1:8080: bind: address already in use 端口冲突 更换端口或杀死占用进程:lsof -i :8080
error: timed out waiting for the condition Pod启动超时 增加超时参数:--pod-running-timeout=5m

2. 性能优化技巧

批量转发:同时转发多个相关端口

kubectl port-forward deployment/nginx-deployment 80:80 443:443

保持连接:使用工具自动重连

while true; do kubectl port-forward svc/redis 6379:6379; done

网络诊断:开启详细日志

kubectl port-forward -v=9 pod/nginx 8080:80

参考链接

https://blog.csdn.net/J56793/article/details/145400712

https://feisky.gitbooks.io/kubernetes/content/practice/portforward.html

https://www.cnblogs.com/waldron/p/17927449.html

https://chanjarster.github.io/post/k8s/kubectl-port-forward/


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 george_95@126.com