0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何將多個(gè)容器暴露到一個(gè)端口上

dyquk4xk2p3d ? 來源:民工哥技術(shù)之路 ? 2023-11-29 14:30 ? 次閱讀

富 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è)端口了。72a7e9ee-8e7f-11ee-939d-92fbcf53809c.png

步驟一:創(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è)端口了。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 網(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)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    如何通過已占用的端口號(hào)找到占用端口容器?

    個(gè)已啟動(dòng)了N多個(gè)容器Linux操作系統(tǒng)的宿主機(jī)上,新啟動(dòng)個(gè)映射到宿主機(jī)
    的頭像 發(fā)表于 07-26 08:45 ?7060次閱讀
    如何通過已占用的<b class='flag-5'>端口</b>號(hào)找到占用<b class='flag-5'>端口</b>的<b class='flag-5'>容器</b>?

    ADXL345如何將端口INT1重置為原始低電平?

    我用ADXL345在INT1端口上配置了雙擊中斷,但是雙擊后觸發(fā)了。INT1端口的值直保持在高電平,沒有回到低電平。我想知道如何將端口 I
    發(fā)表于 12-27 07:44

    如何將Strut暴露給程序的其他部分?

    在頭文件(使用EXTEN)中聲明變量,在這種情況下,如何將Strut暴露給程序的其他部分?如果我想在整個(gè)程序中訪問個(gè)頭文件中的這個(gè)聲明,我不需要在同
    發(fā)表于 08-02 10:27

    如何將分區(qū)劃分為可讀分區(qū)?

    我們?cè)O(shè)計(jì)了基于USB SD3的自定義板。我們已經(jīng)移植的例子說明了使用FX3S固件API來實(shí)現(xiàn)大容量存儲(chǔ)類設(shè)備,它允許訪問連接到SD3的SD/MMC設(shè)備。應(yīng)用程序存儲(chǔ)端口上找到的存儲(chǔ)設(shè)備劃分為兩個(gè)
    發(fā)表于 09-27 14:22

    如何將多個(gè)LabVIEW生成的exe打包進(jìn)同一個(gè)安裝包??

    我用labview寫了個(gè)軟件,生成了多個(gè)版本的exe,如何將多個(gè)exe打包一個(gè)安裝包中。在安
    發(fā)表于 11-14 10:50

    如何將輸出重定向個(gè)不同的UART

    a)當(dāng)使用和聲時(shí),我可以Prtuf直接指向任意的UART,或者總是指向UART2?如果是,我如何將輸出重定向個(gè)不同的UART?B)和聲
    發(fā)表于 05-06 13:59

    如何將freemodbus移植stm32平臺(tái)

    modbus是個(gè)非常好的串口協(xié)議(當(dāng)然也能用在網(wǎng)口上),它簡(jiǎn)潔、規(guī)范、強(qiáng)大。可以滿足大部分的工業(yè)、嵌入式需求。這里詳細(xì)說下如何將freemodbus移植
    發(fā)表于 08-16 06:59

    如何將多個(gè)模塊的代碼合并到個(gè)工程里?

    如何將多個(gè)模塊的代碼合并到個(gè)工程里?
    發(fā)表于 11-18 07:39

    如何將CubeMX LSM303AH連接到I2C接口上呢?

    如何將CubeMX LSM303AH連接到I2C接口上呢?求大神告知
    發(fā)表于 12-16 06:44

    如何將按鈕回調(diào)從小容器傳播到個(gè)容器中的當(dāng)前視圖呢?

    組相同的小型自定義容器放入個(gè)容器中。然后我
    發(fā)表于 12-26 06:19

    如何將alpha值設(shè)置為模擬時(shí)鐘或容器

    我想在所有屏幕的背景上制作個(gè)透明時(shí)鐘。所以我認(rèn)為 Alpha 值是在兩個(gè)屏幕上實(shí)現(xiàn)透明的唯方法。模擬時(shí)鐘和容器在他們的庫中沒有 Alph
    發(fā)表于 02-07 07:01

    針對(duì)UART通信端口上射頻干擾的研究

    針對(duì)UART通信端口上射頻干擾的研究 有客戶報(bào)告其中心位于840MHz左右的RF干擾影響配置成UART的串行通信端口,該接口位于包含個(gè)AD6903(LeMansLCR+)數(shù)字
    發(fā)表于 04-20 16:54 ?1219次閱讀
    針對(duì)UART通信<b class='flag-5'>端口上</b>射頻干擾的研究

    如何將1個(gè)多個(gè)Arduino與樹莓派結(jié)合使用

    僅使用個(gè)Arduino您可以在關(guān)閉電源的情況下Arduino插入任何USB端口,然后它將正常工作。
    的頭像 發(fā)表于 11-19 11:12 ?4934次閱讀
    <b class='flag-5'>如何將</b>1<b class='flag-5'>個(gè)</b>或<b class='flag-5'>多個(gè)</b>Arduino與樹莓派結(jié)合使用

    如何將USB Type-C端口裝入墻上插座

    隨著USB Type-C成為電子設(shè)備的主流充電接口,設(shè)計(jì)工程師面臨著個(gè)挑戰(zhàn):如何將越來越高功率的USB Type-C端口裝入空間和散熱能力有限的墻上插座?這里分享
    的頭像 發(fā)表于 04-06 17:58 ?1.4w次閱讀

    如何將linux下多種類型的多個(gè)文件復(fù)制一個(gè)目錄

    即假如/haodao1目錄下存在test1.txt、test2.c、test3.java、test4.py、test5.sql這五種不同類型的不同文件,如何將.txt、.c、.java、.py這些文件類型的多個(gè)文件拷貝/hao
    發(fā)表于 06-09 15:44 ?971次閱讀