# 與Docker使用的網絡瓶頸
Docker 是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的容器中,然后發布到任何流行的 Linux 機器上,也可以實現虛擬化。容器是完全使用沙箱機制,相互之間不會有任何接口(類似 iPhone 的 app)。幾乎沒有性能開銷,可以很容易地在機器和數據中心中運行。最重要的是,他們不依賴于任何語言、框架包括系統。
Docker自2013年以來非常火熱,無論是從 github 上的代碼活躍度,還是Redhat在RHEL6.5中集成對Docker的支持, 就連 Google 的 Compute Engine 也支持 docker 在其之上運行。
在360企業版安全中,我們使用Docker的原因和目的,可能與其他公司不太一樣。我們一直存在比較特殊的"分發"需求,Docker主要是用來屏蔽企業用戶平臺的不一致性。我們的企業用戶使用的系統比較雜,僅僅主流系統就有Ubuntu, Centos,RedHat,AIX,還有一些定制裁減系統等,百花齊放。
雖然OpenResty具有良好的跨平臺特性,無奈我們的安全項目比較重,組件比較多,是不可能逐一適配不同平臺的,工作量、穩定性等,難度和后期維護復雜度是難以想象的。如果您的應用和我們一樣需要二次分發,非常建議考慮使用docker。這個年代是云的時代,二次分發其實成本很高,后期維護成本也很高,所以盡量做到云端。
說說Docker與OpenResty之間的"坑"吧,你們肯定對這個更感興趣。
我們剛開始使用的時候,是這樣啟動的:
~~~
docker run -d -p 80:80 openresty
~~~
首次壓測過程中發現Docker進程CPU占用率100%,單機接口4-5萬的QPS就上不去了。經過我們多方探討交流,終于明白原來是網絡瓶頸所致(OpenResty太彪悍,Docker默認的虛擬網卡受不了了 ^_^)。
最終我們繞過這個默認的橋接網卡,使用`--net`參數即可完成。
~~~
docker run -d -p --net=host 80:80 openresty
~~~
多么簡單,就這么一個參數,居然困擾了我們好幾天。一度懷疑我們是否要忍受引入docker帶來的低效率網絡。所以有時候多出來交流、學習,真的可以讓我們學到好多。雖然這個點是我們自己挖出來的,但是在交流過程中還學到了很多好東西。
> Docker Network settings,引自:[http://www.lupaworld.com/article-250439-1.html](http://www.lupaworld.com/article-250439-1.html)
~~~
默認情況下,所有的容器都開啟了網絡接口,同時可以接受任何外部的數據請求。
--dns=[] : Set custom dns servers for the container
--net="bridge" : Set the Network mode for the container
'bridge': creates a new network stack for the container on the docker bridge
'none': no networking for this container
'container:<name|id>': reuses another container network stack
'host': use the host network stack inside the container
--add-host="" : Add a line to /etc/hosts (host:IP)
--mac-address="" : Sets the container's Ethernet device's MAC address
~~~
你可以通過`docker run --net none`來關閉網絡接口,此時將關閉所有網絡數據的輸入輸出,你只能通過STDIN、STDOUT或者files來完成I/O操作。默認情況下,容器使用主機的DNS設置,你也可以通過`--dns`來覆蓋容器內的DNS設置。同時Docker為容器默認生成一個MAC地址,你可以通過`--mac-address 12:34:56:78:9a:bc`來設置你自己的MAC地址。
Docker支持的網絡模式有:
- none。關閉容器內的網絡連接
- bridge。通過veth接口來連接容器,默認配置。
- host。允許容器使用host的網絡堆棧信息。 注意:這種方式將允許容器訪問host中類似D-BUS之類的系統服務,所以認為是不安全的。
- container。使用另外一個容器的網絡堆棧信息。
#### None模式
將網絡模式設置為none時,這個容器將不允許訪問任何外部router。這個容器內部只會有一個loopback接口,而且不存在任何可以訪問外部網絡的router。
#### Bridge模式
Docker默認會將容器設置為bridge模式。此時在主機上面將會存在一個docker0的網絡接口,同時會針對容器創建一對veth接口。其中一個veth接口是在主機充當網卡橋接作用,另外一個veth接口存在于容器的命名空間中,并且指向容器的loopback。Docker會自動給這個容器分配一個IP,并且將容器內的數據通過橋接轉發到外部。
#### Host模式
當網絡模式設置為host時,這個容器將完全共享host的網絡堆棧。host所有的網絡接口將完全對容器開放。容器的主機名也會存在于主機的hostname中。這時,容器所有對外暴露的端口和對其它容器的連接,將完全失效。
#### Container模式
當網絡模式設置為Container時,這個容器將完全復用另外一個容器的網絡堆棧。同時使用時這個容器的名稱必須要符合下面的格式:--net container:.
比如當前有一個綁定了本地地址localhost的Redis容器。如果另外一個容器需要復用這個網絡堆棧,則需要如下操作:
~~~
$ sudo docker run -d --name redis example/redis --bind 127.0.0.1
$ # use the redis container's network stack to access localhost
$ sudo docker run --rm -ti --net container:redis example/redis-cli -h 127.0.0.1
~~~
- 序
- Lua簡介
- Lua環境搭建
- 基礎數據類型
- 表達式
- 控制結構
- if/else
- while
- repeat
- 控制結構for的使用
- break,return
- Lua函數
- 函數的定義
- 函數的參數
- 函數的返回值
- 函數回調
- 模塊
- String庫
- Table庫
- 日期時間函數
- 數學庫函數
- 文件操作
- 元表
- 面向對象編程
- FFI
- LuaRestyRedisLibrary
- select+set_keepalive組合操作引起的數據讀寫錯誤
- redis接口的二次封裝(簡化建連、拆連等細節)
- redis接口的二次封裝(發布訂閱)
- pipeline壓縮請求數量
- script壓縮復雜請求
- LuaCjsonLibrary
- json解析的異常捕獲
- 稀疏數組
- 空table編碼為array還是object
- 跨平臺的庫選擇
- PostgresNginxModule
- 調用方式簡介
- 不支持事務
- 超時
- 健康監測
- SQL注入
- LuaNginxModule
- 執行階段概念
- 正確的記錄日志
- 熱裝載代碼
- 阻塞操作
- 緩存
- sleep
- 定時任務
- 禁止某些終端訪問
- 請求返回后繼續執行
- 調試
- 調用其他C函數動態庫
- 我的lua代碼需要調優么
- 變量的共享范圍
- 動態限速
- shared.dict 非隊列性質
- 如何添加自己的lua api
- 正確使用長鏈接
- 如何引用第三方resty庫
- 使用動態DNS來完成HTTP請求
- 緩存失效風暴
- Lua
- 下標從1開始
- 局部變量
- 判斷數組大小
- 非空判斷
- 正則表達式
- 不用標準庫
- 虛變量
- 函數在調用代碼前定義
- 抵制使用module()函數來定義Lua模塊
- 點號與冒號操作符的區別
- 測試
- 單元測試
- API測試
- 性能測試
- 持續集成
- 灰度發布
- web服務
- API的設計
- 數據合法性檢測
- 協議無痛升級
- 代碼規范
- 連接池
- c10k編程
- TIME_WAIT問題
- 與Docker使用的網絡瓶頸
- 火焰圖
- 什么時候使用
- 顯示的是什么
- 如何安裝火焰圖生成工具
- 如何定位問題