背景
在Mac本地安装完Kind集群后,由于这个K8s集群所有的服务都跑在了一个docker容器中。由于从本地既无法ping通Kind docker的IP,也无法Ping通集群中Pod的IP。因此从本地访问集群中的服务成为了一个问题。
那么有没有办法来解决呢?
对于自己不能解决的问题,其他人肯定也遇到过,Google是个好东西。
https://github.com/wenjunxiao/mac-docker-connector/blob/master/README.md
打通本地网络与Docker网络
首先分析为什么本地无法访问Docker网络?
对于一个简单的docker的服务,如nginx,如果要访问这个服务,需要把它的端口expose出来。
docker run -p 8000:80 nginx
此时就可以正常的访问主机端口
curl localhost:8000 # ok
为什么要expose?
对于在docker中运行的一个服务,本质上它是一个进程,该进程会绑定该docker的namespace的网络层(IP)及传输层(端口)。进程通常绑定的IP为127.0.0.1
、0.0.0.0
或是这个这个进程宿主机的IP,如果这个进程是跑在容器中的,它也有可能是绑定这个容器的IP。
通常docker run <image>
跑起来的容器,它的网络使用default bridge模式。它是一个独立的网络,在这个桥中的容器,网络可以互通。
➜ ~ docker inspect `docker ps | grep nginx | awk '{print $1}'` | less -i
"Networks": {
"bridge": {
"IPAddress": "172.17.0.2",
"Gateway": "172.17.0.1",
可以看到是bridge网络,且是172.17段
➜ ~ docker network ls
NETWORK ID NAME DRIVER SCOPE
cec614647447 bridge bridge local
可以通过 docker network inspect cec614647447
查看该network详细信息。
docker网络分为三种:host、bridge、none。
无法直接访问通该docker ip的原因就是因为没有连接到host网络。使用expose,本质上就是把容器ns上的port映射到了host网络的port上。
那么问题来了:对于kind
这个docker,默认安装时,只expose出了一个apiserver
的port,那现在要访问服务中的Port
,要如何做呢?
通过上面的文章,我们可以默认打通mac本地到所有bridge中的网络。
$ brew tap wenjunxiao/brew
$ brew install docker-connector
$ docker network ls --filter driver=bridge --format "" | xargs docker network inspect --format "route " >> /usr/local/etc/docker-connector.conf
$ sudo brew services start docker-connector
$ docker pull wenjunxiao/mac-docker-connector
$ docker run -it -d --restart always --net host --cap-add NET_ADMIN --name connector wenjunxiao/mac-docker-connector
这几步完成后,已经可以ping所有bridge网络中的IP
➜ ~ docker inspect `docker ps | grep kind | awk '{print $1}'` | grep IPAddress
"IPAddress": "172.20.0.2",
➜ ~ ping 172.20.0.2
PING 172.20.0.2 (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: icmp_seq=0 ttl=63 time=1.472 ms
现在已经可以访问kind容器的IP了,那么如何访问kind 集群中的服务呢?
访问kind集群中的服务
集群内部的网络与kind容器的网络是两个不同的网络。
就好比是在虚机上搭建的一个k8s集群,容器的网络其实跟宿主机的网络,本质上不是同一个网络。
在虚机中能Ping通Pod IP,因此可以直接访问Pod中的服务。虚机Host网络与集群中的网络,不过是通过cni插件额外做了一些工作,将它们打通。
但是Kind集群的网络与Kind容器所在的网络并没有打通。其实对于k8s集群而言,也有类似于docker expose的概念,即将这个服务改成NodePort,这样就可以使流量从外部进入到集群。
本质上也是两上不通的Namespace,通过NodePort TargetPort做了下映射。
因此此时,只需要将该服务改成NodePort即可访问成功。
➜ zackzhangkai.github.io git:(master) ✗ k -n kubesphere-system get svc ks-console
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ks-console NodePort 10.99.226.191 <none> 80:30880/TCP 21h
➜ zackzhangkai.github.io git:(master) ✗ docker ps | grep kind
c46d6ca06e9f kindest/node:v1.19.1 "/usr/local/bin/entr…" 28 hours ago Up 28 hours 127.0.0.1:53079->6443/tcp kind-control-plane
➜ zackzhangkai.github.io git:(master) ✗ docker inspect c46d6ca06e9f | grep -i ipadd
"SecondaryIPAddresses": null,
"IPAddress": "",
"IPAddress": "172.20.0.2",
➜ zackzhangkai.github.io git:(master) ✗ curl -I 172.20.0.2:30880
HTTP/1.1 302 Found
Vary: Accept-Encoding
Location: /login
Content-Type: text/html; charset=utf-8
Content-Length: 43
Date: Fri, 19 Mar 2021 07:56:34 GMT
Connection: keep-alive
Keep-Alive: timeout=5
使用配置文件来暴露端口
其实在创建集群的时候,可以直接在配置文件中定义好要暴露的端口
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
# WARNING: It is _strongly_ recommended that you keep this the default
# (127.0.0.1) for security reasons. However it is possible to change this.
apiServerAddress: "127.0.0.1"
# By default the API server listens on a random open port.
# You may choose a specific port but probably don't need to in most cases.
# Using a random port makes it easier to spin up multiple clusters.
apiServerPort: 6443