Docker-基本操作-網路篇(中)
Linux 的防火牆由 Netfilter 和 Iptables 組成。使用者空間的 Iptables 制定防火牆規則,核心空間的 Netfilter 實現防火牆功能。Netfilter (核心空間)位於Linux核心中的包過濾防火牆功能體系,稱為 Linux 防火牆的“核心態”。 Iptables (使用者空間)位於 /sbin/iptables,是用來管理防火牆的命令的工具,為防火牆體系提供過濾規則/策略,決定如何過濾或處理到達防火牆主機的資料包,稱為 Linux 防火牆的“使用者態”。
白名單和黑名單
製作防火牆規則通常有兩種基本策略。 一是黑名單策略;二是白名單策略。
- 黑名單策略指沒有被拒絕的流量都可以通過,這種策略下管理員必須針對每一種新出現的攻擊,制定新的規則,因此不推薦。
- 白名單策略指沒有被允許的流量都要拒絕,這種策略比較保守,根據需要逐漸開放,目前一般都採用白名單策略,推薦。
四表五鏈
Iptables 有四表五鏈(其實有五表,是後來加進來的),四表分別是下圖的的 raw,mangle,nat,filter
表。五鏈分別是 PREROUTING,INPUT,OUTPUT,FORWARD,POSTROUTING
鏈。表決定了資料報文處理的方式,而鏈則決定了資料報文的流經哪些位置。
-
五鏈:
- PREROUTING:資料包進入路由表之前;
- INPUT:通過路由表後目的地為本機;
- FORWARD:通過路由表後,目的地不為本機;
- OUTPUT:由本機產生,向外轉發;
- POSTROUTIONG:傳送到網絡卡介面之前。
-
四表:
- filter 表:負責過濾功能,防火牆;核心模組:iptables_filter
- nat 表:network address translation,網路地址轉換功能;核心模組:iptable_nat
- mangle 表:拆解報文,做出修改,並重新封裝的功能;iptable_mangle
- raw 表:關閉 nat 表上啟用的連線追蹤機制;iptable_raw
處理流程
處理流程下圖所示,例如,制定一個filter表的規則,filter表決定是否放行資料包通過,那如果通過,則必須經由INPUT鏈流入資料包,INPUT鏈是處理入站資料的,如果沒問題,繼續放行到使用者空間,再經由OUTPUT鏈將資料包流出。而對於 NAT 表的規則,NAT 表主要實現轉發功能,資料包先經由PREROUTING鏈進行路由選擇,選擇好路線後再經由FORWARD鏈轉發資料,然後再進行一個路由選擇,最後由POSTROUTING鏈流出資料。
Iptables 語法
語法格式如下:
$ iptables [-t 表名] 選項 [鏈名] [條件] [-j 控制型別]
引數說明:
-P -P -F -L -I num -D num -s -d -i -o -p --dport num --sport num
SNAT、DNAT 與 MASQUERADE
- SNAT(source network address translation,源地址目標轉換)
區域網內的主機都配置了內網 IP,在訪問外部網路的時候,路由器將資料包的報頭中的源地址替換成路由器的 IP 。當外部網路的伺服器比如網站 Web 伺服器接到訪問請求的時候,他的日誌記錄下來的是路由器的 IP 地址,而不是 主機的內網 IP 。因為,伺服器收到的資料包的報頭的“源地址”部分已經被替換。
- DNAT(destination network address translation,目標網路地址轉換)
當 Web 伺服器放在內網,配置內網 IP ,前端有個防火牆,配置公網 IP,客戶端使用公網 IP 來訪問這個網站。當訪問的時候,客戶端發出一個數據包,這個資料包的報頭裡邊,目標地址寫的是防火牆的公網 IP 。防火牆會把這個資料包的報頭改寫一次,將目標地址改寫成 Web 伺服器的內網 IP ,然後再把這個資料包傳送到內網的Web 伺服器上這樣,資料包就可以穿透防火牆,並從公網 IP 變成了一個對內網地址的訪問。
- MASQUERADE(地址偽裝)
MASQUERADE 是 SNAT 的一個特例,因為它在 Iptables 中有著和 SNAT 相近的效果。SNAT 是指在資料包從網絡卡傳送出去的時候,把資料包中的源地址部分替換為指定的 IP,這樣,接收方就認為資料包的來源是被替換的那個 IP 的主機。MASQUERADE是用傳送資料的網絡卡上的IP來替換源IP,因此,對於那些IP不固定的場合,比如撥號網路或者通過 dhcp 分配 IP 的情況下,就得用 MASQUERADE。
容器訪問控制
容器訪問外部網路
容器要想訪問外部網路,需要本地系統的轉發支援。在 Linux 系統中,檢查轉發是否開啟,即 net.ipv4.ip_forward
是否等於 0。如果為 0,說明沒有開啟轉發,則需要手動開啟。
$sysctl net.ipv4.ip_forward net.ipv4.ip_forward = 1
也可以在啟動 Docker 服務的時候設定 --ip-forward=true
, Docker 就會自動設定系統的 ip_forward 引數為 1。
容器之間訪問
容器之間相互訪問,需要兩方面的支援:
- 容器的網路拓撲是否已經互聯。預設情況下,所有容器都會被連線到 docker0 網橋上。
- 本地系統的防火牆軟體 – iptables 是否允許通過。
在同一宿主機下,Docker 的容器是通過虛擬網橋來進行連線的。預設情況下,在同一宿主機中執行的不同容器之間是允許網路互通的。因為,當啟動 Docker 服務時候,預設會新增一條轉發策略到 iptables 的 FORWARD 鏈上。策略為通過(ACCEPT ) 還是禁止(DROP ) 取決於配置 --icc=true
還是 --icc=false
。因為預設值為 --icc=true
,所以預設是允許容器間互通的。
如果為了安全考慮,修改 vim /etc/default/docker
,在末尾新增配置 DOCKER_OPTS="--icc=false"
來禁止它。需要重啟 Docker 的服務 sudo service docker restart
。這樣就會拒絕所有容器間互聯。
另外,也可以允許特定容器間的連線。在 Docker 守護程序的啟動選項中設定 --icc=false
和 --iptables=true
,然後在容器啟動時使用 --link
選項來與特定容器進行連線。Docker 利用 iptables 中的機制,在 --icc=false
時,阻斷所有的 Docker 容器間的訪問,僅僅執行利用 link 選項配置的容器進行相互的訪問。
埠對映
預設情況下,容器可以主動訪問到外部網路的連線,但是外部網路無法訪問到容器。
容器訪問外部
容器所有到外部網路的連線,源地址都會被 NAT 成本地系統的 IP 地址。這是使用 iptables 的源地址偽裝操作實現的。 例如:
root@iZwz96uyro861qckgz89ljZ:~# iptables -t nat -nL ...... Chain POSTROUTING (policy ACCEPT) targetprot opt sourcedestination MASQUERADEall--172.17.0.0/160.0.0.0/0
上述規則將所有源地址在 172.17.0.0/16
網段,目標地址為其他網段(外部網路) 的流量動態偽裝為從系統網絡卡發出。如前一節所述,這裡使用的是 MASQUERADE(地址偽裝),MASQUERADE 跟傳統 SNAT 的好處是它能動態從網絡卡獲取地址。
外部訪問容器
容器允許外部訪問,可以在 docker run
時候通過 -p
或 -P
引數來啟用。但是,不管用那種辦法,其實也是在本地的 iptables 的 nat 表中新增相應的規則。例如:
root@iZwz96uyro861qckgz89ljZ:~# docker run -p 80:80 --name=web -d nginx bbe79958143a510ef5aca1b37770e5e19549d7f0a5fd441db092723fca6c1159 root@iZwz96uyro861qckgz89ljZ:~# iptables -t nat -nL ...... Chain POSTROUTING (policy ACCEPT) targetprot opt sourcedestination MASQUERADEall--172.17.0.0/160.0.0.0/0 MASQUERADEtcp--172.17.0.2172.17.0.2tcp dpt:80
網路配置命令
只有在 Docker 服務啟動的時候才能配置,而且不能馬上生效的命令:
-
-b BRIDGE
或--bridge=BRIDGE
:指定容器掛載的網橋; -
--bip=CIDR
:定製 docker0 的掩碼; -
-H SOCKET...
或--host=SOCKET...
:Docker 服務端接收命令的通道; -
--icc=true|false
:是否支援容器之間進行通訊; -
--ip-forward=true|false
:請看下文容器之間的通訊; -
--iptables=true|false
:是否允許 Docker 新增 iptables 規則; -
--mtu=BYTES
:容器網路中的 MTU。
示例:
# 編輯docker預設配置:DOCKER_OPTS="--icc=false --iptables=true " $ sudo vim /etc/default/docker # 重啟docker服務 $ sudo service docker restart
既可以在啟動服務時指定,也可以在啟動容器時指定的命令選項:
--dns=IP_ADDRESS... --dns-search=DOMAIN...
只能在容器啟動時使用的命令選項, docker run
命令與網路相關的選項:
-
-h HOSTNAME
或--hostname=HOSTNAME
:配置容器主機名; -
--link=CONTAINER_NAME:ALIAS
:新增到另一個容器的連線; -
--net=bridge|none|container:NAME_or_ID|host
:配置容器的橋接模式; -
-p SPEC 或 --publish=SPEC
:對映容器埠到宿主主機; -
-P or --publish-all=true|false
:對映容器所有埠到宿主主機 。