4.1.5 setupConnection
下面我们继续深入了解Client是如何将这个request发送给Tiller的。我们先回过头来看一个问题,在install命令行时,Helm还执行了一个操作,使用kubectl port-forward临时在本地宿主机打通一个与Tiller Pod沟通的通道,首先看一下代码。
...... cmd := &cobra.Command{ Use: "install [CHART]", Short: "Install a Chart archive", Long: installDesc, PreRunE: func(_ *cobra.Command, _ []string) error { return setupConnection() }, RunE: func(cmd *cobra.Command, args []string) error { ......
需要注意的是,PreRunE函数是在RunE函数之前执行的。也就是说其实在执行install的那些命令之前,setupConnection函数使用kubectl port-forward功能在宿主机与Tiller Pod之间建立了一个通道,下面看看具体实现。
func setupConnection() error { if settings.TillerHost == "" { config, client, err := getKubeClient(settings.KubeContext, settings.KubeConfig) if err != nil { return err } TillerTunnel, err = portforwarder.New(settings.TillerNamespace, client, config) if err != nil { return err } settings.TillerHost = fmt.Sprintf("127.0.0.1:%d", TillerTunnel.Local) debug("Created tunnel using local port: '%d'\n", TillerTunnel.Local) } // 设置gRPC config debug("SERVER: %q\n", settings.TillerHost) // 支持插件 return nil }
由此可见,根据默认的kubeConfig获取Kubernetes client命令行实例后,portforwarder.New(settings.TillerNamespace,client,config)调用了kubectl port-forward命令。
举个例子,kubectl port-forward pod/Tiller 8888:5000这个命令就是建立一个连接,首先监听本地8888端口,然后远程连接Tiller这个Pod的5000端口。也就是说,向本地8888端口发送的数据都会直接被转发到远程的Tiller Pod 5000端口上,这样就建立了一个本地和远程容器之间的通道。而且这个通道是通过ApiServer连接的,不需要Pod向外暴露任何端口,非常安全。
这里调用本地宿主机的端口是随机的,任何一个端口都可以被调用,然后被调用的端口会被指向远程的Tiller Pod,函数settings.TillerHost=fmt.Sprintf("127.0.0.1:%d",TillerTunnel.Local)就是将随机选择的本地端口指定到setting结构体中。这样在执行其他函数之前,我们的本地其实已经默默建好了与远程Tiller之间的通信链路。