docker Desktop for windows 端口转发

在完成  在 kind 部署 MetalLB  之后,也就已经实现了标准 Kubernets 集群应用部署的输出了。但是对于  Docker Desktop 网络  限制,实际上整个 Kubernets 都是在一个 Linux 虚拟机中运行,从物理主机  linux  上不能直接访问这个输出地址,还需要做一个端口转发(port forwarding)来访问。

备注

在  X86 移动云 Kind(本地 docker 模拟 k8s 集群) ,采用直接在 Linux 物理主机上部署  kind(本地 docker 模拟 k8s 集群)  就没有这个麻烦,外部可以直接访问

备注

另一种方式是采用  Docker 环境运行 Squid  运行反向代理服务器来实现端口转发

构建  fedora-gw  镜像的 Dockerfile

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# USE DOCKER BUILD
# docker build --rm -t fedora-gw .
# USE DOCKER RUN
# docker run -itd --privileged=true -p 1122:22 --hostname fedora-gw --name fedora-gw fedora-gw

# USE nerdctl (containerd) BUILD
# nerdctl build -t fedora-gw .

# INTERACT RUN
# nerdctl run -it --privileged=true -p 1122:22 --hostname fedora-gw --name fedora-gw fedora-gw:latest

# BACKGROUND RUN
# nerdctl run -d --privileged=true -p 1122:22 --hostname fedora-gw --name fedora-gw fedora-gw:latest

FROM fedora:latest
MAINTAINER vincent huatai <vincent@huatai.me>

ENV container docker

# set china repo: mirros.163.com
RUN cp -R /etc/yum.repos.d /root/yum.repos.d
RUN rm /etc/yum.repos.d/fedora-cisco-openh264.repo
RUN sed -i 's/metalink=/#metalink=/g' /etc/yum.repos.d/*
RUN sed -i 's/#baseurl=/baseurl=/g' /etc/yum.repos.d/*
RUN sed -i 's/download.example\/pub\/fedora\/linux/mirrors.163.com\/fedora/g' /etc/yum.repos.d/*
RUN cp /root/yum.repos.d/fedora-cisco-openh264.repo /etc/yum.repos.d/

RUN dnf clean all
RUN dnf -y update

# Add Tini
ENV TINI_VERSION v0.19.0
# 标准方法是采用ADD方式向镜像添加tini,但是GFW阻碍,改为下载后本地复制
#ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
COPY tini /tini
RUN chmod +x /tini
ENTRYPOINT ["/tini", "--"]

# Copy tini entrypoint script
COPY entrypoint_ssh_cron_bash /entrypoint.sh
RUN chmod +x /entrypoint.sh

# not need systemd(initscripts)
RUN dnf -y install which sudo passwd openssh-clients openssh-server \
    iproute net-tools bind-utils bzip2 tmux sysstat nfs-utils lsof \
    procps tree file mlocate rsync cronie cronie-anacron \
    iptables-services

# add account "admin" and give sudo privilege
RUN groupadd -g 505 admin
RUN useradd -g 505 -u 505 -d /home/admin -m admin
RUN usermod -aG wheel admin
RUN echo "%wheel        ALL=(ALL)       NOPASSWD: ALL" >> /etc/sudoers

# set TIMEZONE to Shanghai
RUN unlink /etc/localtime && ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# Add ssh public key for login
RUN mkdir -p /home/admin/.ssh
COPY authorized_keys /home/admin/.ssh/authorized_keys
RUN chown -R admin:admin /home/admin/.ssh
RUN chmod 600 /home/admin/.ssh/authorized_keys
RUN chmod 700 /home/admin/.ssh

RUN ssh-keygen -A

# run service when container started - sshd
EXPOSE 22:122

# Run your program under Tini
# CMD ["/your/program", "-and", "-its", "arguments"]
CMD ["/entrypoint.sh"]

备注

镜像  从 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

配置  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 转发端口

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#!/usr/bin/env bash

# 需要在host主机(也就是Docker 虚拟机)内部执行以下这行命令激活内核IP转发
#echo 1 > /proc/sys/net/ipv4/ip_forward

iptables -F
iptables -t nat -F
iptables -X

dev_gw="172.22.0.12"

fedora_dev="172.22.255.201"
fedora_dev_ssh="10001"

iptables -t nat -A PREROUTING -p tcp --dport ${fedora_dev_ssh} -j DNAT --to-destination ${fedora_dev}:22
iptables -t nat -A POSTROUTING -p tcp -d ${fedora_dev} --dport 22 -j SNAT --to-source ${dev_gw}

对比一下,我执行的 image.png ![[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 虚拟机  内修改

通过 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.png ![[image-20240816133815007.png]]

注意需要执行 iptables_port_forwarding,必须在 dev-gw 执行一遍,才可以转发。 连接到 kind 中的 pod

image.png ![[image-20240816133840610.png]] kind 集群的样子如下图所示: image.png ![[image-20240816133907594.png]]

对应的服务为: image.png ![[image-20240816133958854.png]]

image.png ![[image-20240816134023261.png]]

对比上图,发现是 ssh 转发的端口,连接上 pod 的。

注意需要开启nfs的景象,需要给到privileged权限
1
2
3
     IPTABLES_DIR="/home/xfhuang/docs/github.com/cloud-atlas/source/kubernetes/kind/docker_macos_kind_port_forwarding"
        DOCS_DIR="/home/xfhuang/docs"
        docker run -itd --privileged  -p 122:22 -p 10000-10099:10000-10099 --network kind        --cap-add=NET_ADMIN --cap-add=NET_RAW        --mount type=bind,source="${IPTABLES_DIR}"/iptables_port_forwarding,target=/root/iptables_port_forwarding,readonly         -v  ${DOCS_DIR}:/docs         --hostname dev-gw --name dev-gw fedora-gw
Licensed under CC BY-NC-SA 4.0
最后更新于 Jan 06, 2025 05:52 UTC
comments powered by Disqus
Built with Hugo
主题 StackJimmy 设计
Caret Up