前言
公司早期的K8S集群是基于flannel分配網(wǎng)段后,并沒有在kubelet中啟動(dòng)cni插件功能,而是利用docker本身的網(wǎng)絡(luò)管理功能,如下所示dockerd的啟動(dòng)命令為:
./dockerd --bip=10.236.51.1/25 ...
這利用了docker的自身的網(wǎng)絡(luò)管理能力,我們知道docker本身是具備端口映射的功能,可以把容器中的服務(wù)通過端口映射的方式,如下所示,我們啟動(dòng)一個(gè)容器,把容器中的80端口映射到宿主機(jī)的8000端口上:
docker run -p 8000:80 -it ubuntu /bin/bash
有些老業(yè)務(wù)為了讓容器與外部系統(tǒng)互通,把容器的端口映射到了宿主機(jī)的端口上,通過對(duì)宿主機(jī)的端口進(jìn)行管理,來防止容器調(diào)度的沖突,這種方式一定層度上解決了業(yè)務(wù)上的問題。
近期,我們對(duì)K8S的網(wǎng)絡(luò)模型進(jìn)行了升級(jí),通過自定義的網(wǎng)絡(luò)CNI插件,實(shí)現(xiàn)三層網(wǎng)絡(luò)模型,可以讓容器網(wǎng)絡(luò)與主機(jī)網(wǎng)絡(luò)系統(tǒng)打通,為了統(tǒng)一K8S集群方便管理,我們需要把一些老的業(yè)務(wù)遷移到新的K8S集群中來。
我們又不希望管理多個(gè)K8S集群,但是新集群中的CNI插件本身,不具備這種端口映射的能力,所以碰到了舊的業(yè)務(wù)無法遷移的難題。
額外話題:
從這個(gè)問題本身來看,其實(shí)業(yè)務(wù)方并沒有使用端口映射功能的必要性,既然業(yè)務(wù)自己管理分配的主機(jī)節(jié)點(diǎn)和端口號(hào),那么我們完全可以基于Host網(wǎng)絡(luò)部署Pod來達(dá)到相同的目的。
這里我們先不考慮方案替代性上來說,端口映射功能也是一個(gè)比較有意思的點(diǎn),剖析一下如何在我們新的K8S集群中來支撐這種端口映射功能。
K8S中的端口映射
K8S在框架層面是支撐了端口映射的功能,我們可以看看下面這個(gè)Pod的定義:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
hostPort: 8080
這個(gè)Pod要求把容器中80端口映射到宿主機(jī)的8080端口中,雖然我們能夠這樣申明,但是究竟能不能做到,就跟我們指定的網(wǎng)絡(luò)模式有很大關(guān)系了。
如果按照我們老集群中,采用None的模式,讓docker進(jìn)程去管理網(wǎng)絡(luò),那么docker自身具備這種端口映射的能力,所以他就能夠支持,而在我們新集群中應(yīng)用的時(shí)候,發(fā)現(xiàn)不能達(dá)到目的,映射根本沒有完成。
應(yīng)用CNI portmap插件實(shí)現(xiàn)對(duì)端口映射的支持
我們首先來看看我們自定義的插件配置:
root@herrypc:/etc/cni/net.d# cat 11-flannel.conf
{
"cniVersion": "0.3.0",
"name": "mynet",
"type": "flannel",
"ipMasq": false,
"delegate": {
"type": "bridge",
"forceAddress": false,
"ipMasq": false,
"hairpinMode": true,
"isDefaultGateway": true
}
}
基礎(chǔ)插件自身是不具備端口映射的能力的,所以基于上述配置無法實(shí)現(xiàn)端口映射,但是CNI本身支持級(jí)聯(lián)插件的功能,可以在配置中指定portmap作為級(jí)聯(lián)插件來支持端口映射能力。
為了支持級(jí)聯(lián)插件,我們配置不能采用前面的配置格式,而是基于conflist的配置,文件名改為:11-flannel.conflist,內(nèi)容如下:
root@herrypc:/etc/cni/net.d# cat 11-flannel.conflist
{
"cniVersion": "0.3.0",
"name": "mynet",
"plugins": [
{
"type": "flannel",
"ipMasq": false,
"delegate": {
"type": "bridge",
"forceAddress": false,
"ipMasq": false,
"hairpinMode": true,
"isDefaultGateway": true
}
},
{
"type": "portmap",
"capabilities": {"portMappings": true},
"snat": true
},
}
}