富 Web 時(shí)代,應(yīng)用變得越來越強(qiáng)大,與此同時(shí)也越來越復(fù)雜。集群部署、隔離環(huán)境、灰度發(fā)布以及動(dòng)態(tài)擴(kuò)容缺一不可,而容器化則成為中間的必要橋梁。
IT 軟件中所說的 “Docker” ,是指容器化技術(shù),用于支持創(chuàng)建和使用 Linux 容器。而 Docker 技術(shù)就是這樣一種神奇的存在:懂,萬物皆可容器化;不懂,則重復(fù)“搬磚”,繁忙而不自知。
我們的容器需要對(duì)外提供訪問的話,就是必須使用端口暴露。
Docker 容器暴露端口的形式有四種:
-p #將指定的容器端口映射到宿主機(jī)所有地址的一個(gè)隨機(jī)端口 -p: #將容器端口映射到指定的主機(jī)端口 -p:: #將容器端口映射到主機(jī)指定ip的隨機(jī)端口 -p:: #將容器端口映射到指定主機(jī)ip的指定端口
在日常工作環(huán)境中,我們會(huì)部署多個(gè)相同的服務(wù)來對(duì)外提供服務(wù),這樣可以有效保證集群的高可用性,從而使用戶得到很好的體驗(yàn)。
那么,如果多個(gè)容器提供一個(gè)服務(wù),對(duì)外只暴露一個(gè)端口,怎么做呢?
通常有以下三種主流方法。
反向代理
當(dāng)請(qǐng)求達(dá)到后,通過反向代理比如nginx、haproxy等,負(fù)載均衡的方式將流量轉(zhuǎn)發(fā)到后端不同的容器里面。對(duì)外就可以暴露一個(gè)端口了。
步驟一:創(chuàng)建一個(gè)網(wǎng)絡(luò)
首先,我們需要?jiǎng)?chuàng)建一個(gè)網(wǎng)絡(luò),使得多個(gè)容器能夠相互通信。我們可以使用Docker命令docker network create來創(chuàng)建網(wǎng)絡(luò)。下面是創(chuàng)建一個(gè)名為my-network的網(wǎng)絡(luò)的代碼示例:
dockernetworkcreatemy-network
這將創(chuàng)建一個(gè)名為my-network的網(wǎng)絡(luò),供后續(xù)的容器使用。
啟動(dòng)多個(gè)容器
接下來,我們需要啟動(dòng)多個(gè)容器,并將它們連接到之前創(chuàng)建的網(wǎng)絡(luò)上。同時(shí),我們需要將容器的端口映射到宿主機(jī)的端口上,以便外部可以訪問。以下是啟動(dòng)三個(gè)容器并進(jìn)行端口映射的代碼示例:
dockerrun-d--networkmy-network--namecontainer1-p8080:80image1 dockerrun-d--networkmy-network--namecontainer2-p8080:80image2 dockerrun-d--networkmy-network--namecontainer3-p8080:80image3
上述代碼中,我們使用docker run命令分別啟動(dòng)了三個(gè)容器,并指定了容器的網(wǎng)絡(luò)為my-network。--name參數(shù)用于指定容器的名稱,-p參數(shù)用于進(jìn)行端口映射,將容器的80端口映射到宿主機(jī)的8080端口上。
步驟三:配置負(fù)載均衡
最后,我們需要配置一個(gè)負(fù)載均衡容器,將外部對(duì)于宿主機(jī)的訪問請(qǐng)求分發(fā)到多個(gè)容器上。在本示例中,我們使用了Nginx作為負(fù)載均衡容器。以下是配置負(fù)載均衡容器的代碼示例:
dockerrun-d--networkmy-network-p8080:80--nameload-balancernginx
上述代碼中,我們使用docker run命令啟動(dòng)了一個(gè)Nginx容器,并將容器的網(wǎng)絡(luò)設(shè)置為my-network。-p參數(shù)用于進(jìn)行端口映射,將容器的80端口映射到宿主機(jī)的8080端口上。
DNAT
熟悉k8s Nodeport 實(shí)現(xiàn)的話就會(huì)發(fā)現(xiàn),k8s里面service iptables 實(shí)現(xiàn)就是基于DNAT。關(guān)于k8s Nodeport的實(shí)現(xiàn)參見之前k8s的文章。我們可以先通過docker 命令啟動(dòng)兩個(gè)容器:
$CONT_PORT=9090 $dockerrun-d--rm --namehttp_server_foo -eINSTANCE=foo -ePORT=$CONT_PORT http_server $dockerrun-d--rm --namehttp_server_bar -eINSTANCE=bar -ePORT=$CONT_PORT http_server
獲取這個(gè)兩個(gè)容器的IP
$CONT_FOO_IP=$(dockerinspect-f'{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}'http_server_foo) $echo$CONT_FOO_IP 172.17.0.2 $CONT_BAR_IP=$(dockerinspect-f'{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}'http_server_bar) $echo$CONT_BAR_IP 172.17.0.3
然后創(chuàng)建 DNAT 規(guī)則
$FRONT_PORT=80 #Notsecure!UseglobalACCEPTonlyfortests. $sudoiptables-IFORWARD1-jACCEPT #DNAT本地流量,宿主機(jī)訪問 $sudoiptables-tnat-IOUTPUT1-ptcp--dport$FRONT_PORT -mstatistic--moderandom--probability1.0 -jDNAT--to-destination$CONT_FOO_IP:$CONT_PORT $sudoiptables-tnat-IOUTPUT1-ptcp--dport$FRONT_PORT -mstatistic--moderandom--probability0.5 -jDNAT--to-destination$CONT_BAR_IP:$CONT_PORT #DNAT外部流量,其他機(jī)器訪問 $sudoiptables-tnat-IPREROUTING1-ptcp--dport$FRONT_PORT -mstatistic--moderandom--probability1.0 -jDNAT--to-destination$CONT_FOO_IP:$CONT_PORT $sudoiptables-tnat-IPREROUTING1-ptcp--dport$FRONT_PORT -mstatistic--moderandom--probability0.5 -jDNAT--to-destination$CONT_BAR_IP:$CONT_PORT
通過上面模仿k8s Nodeport的實(shí)現(xiàn),就是可以輕松實(shí)現(xiàn)一個(gè)端口對(duì)應(yīng)多個(gè)容器了。
多服務(wù)監(jiān)聽
這個(gè)方法稍微hack 一點(diǎn),其實(shí) socket 在listen 的時(shí)候,支持 SO_REUSEPORT ,它的效果是運(yùn)行多個(gè)程序監(jiān)聽同一個(gè)端口。
funcmain(){ lc:=net.ListenConfig{ Control:func(network,addressstring,connsyscall.RawConn)error{ varoperrerror iferr:=conn.Control(func(fduintptr){ operr=syscall.SetsockoptInt( int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1, ) });err!=nil{ returnerr } returnoperr }, } ln,err:=lc.Listen( context.Background(), "tcp", os.Getenv("HOST")+":"+os.Getenv("PORT"), ) iferr!=nil{ panic(err) } http.HandleFunc("/",func(whttp.ResponseWriter,_req*http.Request){ w.Write([]byte(fmt.Sprintf("Hellofrom%s ",os.Getenv("INSTANCE")))) }) iferr:=http.Serve(ln,nil);err!=nil{ panic(err) } }
這個(gè)我們就啟動(dòng)多個(gè)容器,共享 network namespace,同時(shí)監(jiān)聽這個(gè)端口了。
審核編輯:湯梓紅
-
網(wǎng)絡(luò)
+關(guān)注
關(guān)注
14文章
7486瀏覽量
88544 -
主機(jī)
+關(guān)注
關(guān)注
0文章
983瀏覽量
35011 -
端口
+關(guān)注
關(guān)注
4文章
948瀏覽量
31986 -
容器
+關(guān)注
關(guān)注
0文章
492瀏覽量
22028 -
Docker
+關(guān)注
關(guān)注
0文章
453瀏覽量
11792
原文標(biāo)題:面試官:如何將多個(gè)容器暴露到一個(gè)端口上?問倒一大片。。。
文章出處:【微信號(hào):良許Linux,微信公眾號(hào):良許Linux】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論