背景
kubernetes中的集群发现有两种方式,一种是环境变量
,还有一种就是dns
服务。对于环境变量,在使用上有一些限制,它依赖于svc和rc的启动顺序: 如果rc先于svc启动,那么pod里面就没有相关svc的环境变量,这种方式违背了kubernetes的理念,即资源之间是解耦的。推荐的方式是使用dns的服务,这篇文章主要关于部署skydns的过程以及其中遇到的问题和采用的方式。
部署
关于skydns如何部署在已有的kubernetes集群中,网上有不少资料可以参考,这里贴上一篇文章: kubernetes入门之skydns。想要部署一个toy版本可以参考一下。
问题 & 方案
在实际应用的过程中,我需要改变一些配置,其中遇到的坑就记录在此。
http vs https
网络上所有关于skydns的配置,全都是基于http的。比如下面这一条:
1 | command: |
kube-apiserver监听了两个端口,一个是对外的https,一个是对内的http,两者提供的服务是一样的。
默认的http端口是监听在127.0.0.1:8080上的,对于这个问题,有几个可行的方案:
- 修改apiserver的配置,让它监听在某个内网ip上,skydns通过内网ip去访问apiserver
- 通过外网ip访问,建立iptables路由规则,将外网的流量转发到127.0.0.1:8080
这个方案需要注意添加ip白名单,防止外网恶意流量的入侵,由于事先并不知道调度器会把dns服务送往哪台机器,需要预先对所有集群机器的ip加白名单。 - 将dns服务通过label绑定在apiserver所在的机器上,直接访问本地外网ip
(备注,不确定本地docker里面访问external_ip:8080
可不可以被转发到127.0.0.1:8080
,需要试试。如果不行的话,这条方案直接枪毙。)
但我所遇到的情况更苛刻,kubernetes集群中的机器分布于不同的idc机房,运营商也不全是同一个。这个时候除了自己搭建vpn内网,就没有办法使用内网ip了。由于自己维护vpn内网的成本太大,因此这里就不考虑方案一了。
对于方案二,需要预先加很多白名单。之后如果集群有新机器进来,又要加一遍,维护成本也很大,暂时放弃。
对于方案三,即使可行,但我也不想把dns服务绑死在某一台机器上,集群调度本身就应该有足够的自由度。
想了又想,要不试试使用https的端口吧。但让我失望的是,google到处搜,也没有搜到skydns用https的方案。最后还是在kube2sky的github主页找到了某个可能可用的配置选项:
1 | --kube-master-url: URL of kubernetes master. Required if --kubecfg_file is not set. |
在skydns-rc.yaml中去掉--kube_master_url
,然后使用--kubecfg_file
,指向kubeconfig文件,这里我偷个懒使用的是kubelet的配置文件(kubelet.kubeconfig):
1 | apiVersion: v1 |
目录挂载
在上一部中指定了--kubecfg_file=/etc/kubernetes/kubelet.kubeconfig
还是不够的,启动的时候会报错,说找不到配置文件。原因是这个路径只是作为一个字符串传进了pod中,pod中并没有这个路径对应的文件,我们还需要做目录的挂载:
1 | # 省略很多配置 |
1 | # 省略很多配置 |
在我以为大功告成的时候,结果还是给了我最后一个坑。这个时候kube2sky报了一个错,说无法解析node-1-master。
因为集群中所有机器都是以这种短名字命名的,它们对应的ip都配在所有机器的/etc/hosts
里。而pod中的/etc/hosts
并不是继承于宿主机的,所以自然就无法解析这些短名字了。最后解决的方法也跟上面一样,把/etc/hosts
这个文件挂载到skydns的pod中就可以了。
总结
我的方案可能并不是best practice,也非常感谢广大读者可以提出更好的做法,我也会即使更新在博客中,在此谢过了。