在完成 在 kind 部署 MetalLB 之后,也就已经实现了标准 Kubernets 集群应用部署的输出了。但是对于 Docker Desktop 网络 限制,实际上整个 Kubernets 都是在一个 Linux 虚拟机中运行,从物理主机 linux 上不能直接访问这个输出地址,还需要做一个端口转发(port forwarding)来访问。
备注
在 X86 移动云 Kind(本地 docker 模拟 k8s 集群) ,采用直接在 Linux 物理主机上部署 kind(本地 docker 模拟 k8s 集群) 就没有这个麻烦,外部可以直接访问
解决方案¶
- 在 Docker Desktop 中运行一个连接
kind
bridge 的容器dev-gw
( Gateway,为了精简系统采用 Fedora 镜像(采用 tini 替代 systemd) 的dev-ssh
基础镜像 ) - 在
dev-gw
运行时使用-p
参数将所有需要从外部访问的端口都映射到这个dev-gw
容器上 - 在
dev-gw
内部运行 iptables 实现端口转发,转发到 在 kind 部署 MetalLB 输出的 LoadBalancer 的EXTERNAL-IP
的端口,实现访问 kind(本地 docker 模拟 k8s 集群) 部署的应用
备注
另一种方式是采用 Docker 环境运行 Squid 运行反向代理服务器来实现端口转发
部署¶
- 基于 Fedora 镜像(采用 tini 替代 systemd) 的
fedora-ssh-tini
做一些改进定制构建一个fedora-gw
镜像:
构建 fedora-gw
镜像的 Dockerfile¶
|
|
备注
镜像 从 Dockerfile 构建 Docker 镜像 添加了 iptables
工具( iptables-services
)以及必要的运维工具
- 构建
fedora-gw
镜像:
构建 fedora-gw
镜像¶
docker build –rm -t fedora-gw .
- 基于
fedora-gw
镜像运行dev-gw
容器 :
基于 fedora-gw
镜像运行 dev-gw
容器,将 host 主机的 10000-10099 端口全部映射到这个网关容器¶
docker run -itd -p 122:22 -p 10000-10099:10000-10099 –network kind
–cap-add=NET_ADMIN –cap-add=NET_RAW
–hostname dev-gw –name dev-gw fedora-gw
备注
Docker 支持端口范围的 Port Mapping,不需要一个个映射可以方便这个 fedora-gw
容器内部自行进行端口转发。但是,我发现端口映射会拖慢 Docker 容器启动的速度(例如我尝试映射 999 个端口),所以我最终改为只映射 99 个端口(小型开发测试环境足够了)
备注
在容器内部使用 iptables
需要在运行容器时添加参数 --cap-add=NET_ADMIN
和 --cap-add=NET_RAW
(从 Docker 1.2 开始支持)
检查和验证¶
- 检查运行起来的
dev-gw
可以看到运行的容器实现了10000-10099
的端口范围映射,并且ssh -p 122
从 host 主机能够登陆到dev-gw
容器中 :
检查 dev-gw
容器¶
% docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 78131fbac6e8 fedora-gw “/tini – /entrypoin…” 2 hours ago Up 2 hours 122/tcp, 0.0.0.0:10000-10099->10000-10099/tcp, 0.0.0.0:122->22/tcp dev-gw % ssh -p 122 admin@127.0.0.1 Last login: Tue Jan 31 18:59:02 2023 from 172.22.0.1 [admin@dev-gw ~]$ [admin@dev-gw ~]$ df -h Filesystem Size Used Avail Use% Mounted on overlay 59G 25G 31G 45% / tmpfs 64M 0 64M 0% /dev shm 64M 0 64M 0% /dev/shm /dev/vda1 59G 25G 31G 45% /etc/hosts tmpfs 3.9G 0 3.9G 0% /sys/firmware
- 在 在 kind 部署 MetalLB 配置了负载均衡流量转发到后端 Kubeernetes 服务(services)
fedora-dev-service
,可以看到对外服务的EXTERNAL-IP
是172.22.255.201
配置 fedora-dev-tini
设置 LoadBalancer 服务类型后 kubectl get services
显示服务具备了 EXTERNAL-IP
¶
% kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE fedora-dev-service LoadBalancer 10.96.175.32 172.22.255.201 22:32440/TCP,80:31218/TCP,443:32049/TCP 4d1h
端口转发¶
- 在
dev-gw
内部执行iptables
进行端口转发:
dev-gw
容器内执行 iptables 转发端口¶
|
|
对比一下,我执行的 ![[image-20240816134334368.png]]
备注
这里我遇到一个错误,在容器内部无法修改 /proc/sys/net/ipv4/ip_forward
,提示报错:
iptables_port_forwarding: line 3: /proc/sys/net/ipv4/ip_forward: Read-only file system
Docker 虚拟机内核参数必须在 host 主机,也就是 Docker Desktop on Mac 虚拟机 内修改
- 使用 Docker Desktop on Mac 虚拟机 中方法进入 Docker 虚拟机中:
通过 nsenter 进入运行容器的控制台¶
docker run -it –privileged –pid=host debian nsenter -t 1 -m -u -n -i sh
在 Docker VM 内部执行以下命令开启内核 IP 转发:
echo 1 > /proc/sys/net/ipv4/ip_forward
此时就完成了所有端口转发的配置,从 Host 主机访问本机(所有网络接口)的端口 10001
都会被 Docker Desktop 映射到 dev-gw
虚拟机,然后又被 dev-gw
端口转发给目标 在 kind 部署 MetalLB 对外提供的 fedora-dev
虚拟机的 fedora-dev-service
服务上(对外提供了多个服务端口)。整个过程虽然繁复,但是能够真正实现访问 kind(本地 docker 模拟 k8s 集群) 集群提供的 Kubernetes 服务,和生产环境没有差别。
改进¶
- 为了方便快捷完成端口转发,修订运行
dev-gw
容器的命令,将iptables_port_forwarding
脚本直接bind
到容器内部,这样随时可以在物理主机上修改好脚本,只要重新创建一次容器就可以运行了:
dev-gw
容器运行时 bind mount 进端口转发脚本,方便自动执行¶
docker run -itd -p 122:22 -p 10000-10099:10000-10099 –network kind
–cap-add=NET_ADMIN –cap-add=NET_RAW
–mount type=bind,source="$(pwd)"/iptables_port_forwarding,target=/root/iptables_port_forwarding,readonly \ –hostname dev-gw –name dev-gw fedora-gw
![[image-20240816133815007.png]]
注意需要执行 iptables_port_forwarding,必须在 dev-gw 执行一遍,才可以转发。 连接到 kind 中的 pod
![[image-20240816133840610.png]] kind 集群的样子如下图所示: ![[image-20240816133907594.png]]
对应的服务为: ![[image-20240816133958854.png]]
![[image-20240816134023261.png]]
对比上图,发现是 ssh 转发的端口,连接上 pod 的。
注意需要开启nfs的景象,需要给到privileged权限
|
|