1. 程式人生 > >Docker竟然還能這麼玩?商業級4G代理搭建實戰!

Docker竟然還能這麼玩?商業級4G代理搭建實戰!

時間過得真快,距離這個系列的上一篇文章《商業級4G代理搭建指南【準備篇】》釋出的時間已經過了兩個星期了,上個星期由於各種瑣事纏身,週二開始就沒空寫文章了,所以就咕咕咕了。

那麼在準備篇中,我們瞭解了一下搭建 4G 代理所需要的軟硬體,也知道了各種選擇的優劣勢。現在,我們就可以開始實際搭建了,相信大家也是期待已久了。


基本思路

從這篇文章的標題中我們可以看出,這一次的搭建方案主要用到的是 Docker,你可能會很好奇,Docker 跟搭建 4G 代理有什麼關係嗎?

嗯,關係很大,我們把整件事情梳理一下,先來看看搭建 4G 代理時的基本流程:

  1. 呼叫網絡卡撥號,撥號成功後會建立一個虛擬網絡卡。(正常情況下使用這個虛擬網絡卡就能上網了)

  2. 在多網絡卡的情況下,重複第一步,會得到多個虛擬網絡卡。

  3. 啟動代理伺服器,使其使用虛擬網絡卡作為出網網絡卡,並使用接入內網的實體網絡卡作為入網網絡卡。

但是呢,有個問題,根據我之前的測試結果來看,目前在 Linux 環境下還沒有一個 HTTP 代理伺服器是可以做到分別指定出網網絡卡和入網網絡卡的,嗯...這就很麻煩了,因為如果我們無法這麼做的話,就會出現類似於下面這樣的問題:

  1. 出網和入網都在虛擬網絡卡上,使用代理伺服器必須要走公網訪問。
  2. 入網為實體網絡卡,但出網被代理伺服器鎖定為了某一個,無法利用到多網絡卡。

嗯...那麼不用 HTTP 代理伺服器,用那些經常被用來做一些騷操作的 Socks5 代理伺服器呢?如果可以指定網絡卡的話,再用像 Privoxy 之類的工具把 Socks5 代理轉成 HTTP 代理就好了。(某知名扶牆軟體的 Windows 版本就是這麼轉的 HTTP 代理)

在經過一番嘗試後,我發現雖然有些 Socks5 代理伺服器的文件中是說可以指定網絡卡,但按照說明操作後,似乎並不能直接做到我想要的效果(要麼還是鎖定在某一個上面、要麼上不了網),所以還是存在一些問題的。可能是需要配合路由表設定來進行操作吧,不過我對網路工程的瞭解不怎麼深,搞了幾天也沒搞出來,於是乎還得想想別的辦法。

這時候,我想到了一個東西——Docker,它可以用來解決這個問題!

因為 Docker 容器被建立後,不管外界的網絡卡有多少個,容器內部的網絡卡都只會有一個Docker自己的虛擬網絡卡(容器間通訊用的)和一個本地環回介面(不用管它),而且我們在容器內進行撥號操作時,產生的那個新的虛擬網絡卡也不會影響到外界或其他容器,這樣的話,代理伺服器就不需要指定網絡卡了,直接啟動就能跑!

那麼現在整個流程就跑通了,進入實際操作環節看看吧!


系統方面

這個 Docker 版的搭建方式,系統方面的選擇很多,由於我使用的樣例裝置是樹莓派,所以這裡就選擇使用了 Raspbian(樹莓派專屬版 Debian)。如果你使用的是其他裝置的話,直接選擇一個自己常用的系統就好。

那麼準備好之後的第一步當然是先下載並安裝 Docker,這裡我直接使用 Docker 官方提供的一鍵安裝指令碼來進行安裝:

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# 出自官方文件:https://docs.docker.com/install/linux/docker-ce/debian/#install-using-the-convenience-script

這個一鍵安裝指令碼理論上來講所有 Linux 發行版都可以使用,畢竟已經出來很長時間了,如果不行的話請自行使用搜索引擎查詢相關資料。

裝好 Docker 之後,你有兩個選擇:

  1. 進入體驗模式,瞭解一下具體操作細節是怎麼樣的。
  2. 不看這一段,翻到本文最下方直接使用我寫好的輪子。

啟動容器

體驗的話,我們就直接這麼啟動一個 Docker 容器吧,執行以下命令:

sudo docker run -it --rm --privileged -p 3128:3128 ubuntu:18.04 bash

上面這條命令的意思是,啟動一個內部系統為 Ubuntu18.04 的容器,並進入容器內部的 Shell 執行 bash 命令,如果退出 bash 就自動銷燬容器;然後對映容器內的埠3128到外界,映射出來的外界埠也是3128;最後 privileged 引數是開啟特權模式,用於將網絡卡裝置對映進容器內。

如果下載映象很慢的話,可以搜一下“Docker 加速器”,也可以直接扶牆。

測試一下網絡卡是否正常

進入容器內部後,我們可以執行一下 ls /dev/ttyUSB* 看一下網絡卡有沒有正常被識別出來(在容器外也是一樣的,因為開了特權模式),如果是和我買的同一款 4G 網絡卡的話,在只插入一張網絡卡的情況下你會看到4個 ttyUSB 裝置。

不同 4G 網絡卡和硬體組合可能會有差異,請以實際情況為準。

如果你可以看到4✖4G網絡卡個數個 ttyUSB 裝置的話,就說明沒有問題,可以開始下一步了。

撥號上網

接下來要做的就是撥號了,撥號方面可以選擇使用 Wvdial 這種工具,也可以選擇使用像 Fanconn 這樣的商家提供的撥號指令碼(直接呼叫 PPPD),使用起來的效果會有一些區別。如果商家沒有提供撥號指令碼的話,就用 Wvdial 吧,它能自動生成配置,上手即用。

我這邊的話,由於 Fanconn 的技術人員直接提供了個撥號指令碼,那我就用這個指令碼了,Wvdial 的文件網上有很多很詳盡的,這裡就不再多提,需要的朋友自行搜尋即可。

如果你用的是 Fanconn 的這個撥號指令碼(怎麼弄進容器內就不用我說了吧?),那麼直接在 apt install ppp 安裝好撥號工具之後,用 chmod +x quectel-pppd.sh 給撥號指令碼加個執行許可權,然後 ./quectel-pppd.sh /dev/ttyUSB3 即可。

撥號時使用的 /dev/ttyUSB3 是指 4G 網絡卡的第四個通訊埠,文件中的解釋為:ttyUSB3→For PPP connections or AT command communication,翻譯一下就是用於 PPP 連線或 AT 命令通訊。

撥號之後用 ifconfig 之類的工具即可看到類似下圖中的狀態:

可以看到,如前文所述,現在有三個網絡卡,一個是 Docker 自己的、一個是本地環回介面(這個不用管)、一個是撥號產生的虛擬網絡卡。

如果不是在 Docker 容器內使用的話,還會有個 wwan0(或其他名字),那個是 4G 網絡卡本體。

測試是否能正常上網

現在如果你用 curl 的 --interface 引數指定虛擬網絡卡進行請求的話(如:curl --interface ppp0 https://ip.cn),是已經可以請求成功的了,IP 也會是你所使用的 SIM 卡對應的運營商分配的。

由於 Docker 的映象通常都是極度精簡的,所以 Ubuntu 映象裡並沒有預裝像 net-tools、iputils-ping、vim、curl 之類的這些包,需要自行安裝。所以如果你發現 ifconfig、ping、curl、vim 用不了,不要驚慌,這是正常現象,執行 apt install 包名 命令安裝即可。

如果你無法直接請求成功的話,就可能是 DNS 解析出問題了,可以嘗試 ping 一個公網 IP(如:ping 1.1.1.1)和一個域名(如:ping ip.cn),如果 IP 能 ping 通但域名會報 DNS 解析失敗的話,就可以確認是 DNS 設定問題了。

4G 撥號時如果出現 DNS 設定問題,通常是因為撥號工具沒有正常地將運營商返回的 DNS 伺服器設定寫入到配置中,我們可以手動配置一下(你要強制指定某一個 DNS 也可以):

# 以下為阿里雲的公共DNS
echo 'nameserver 223.5.5.5' >> /etc/resolv.conf
echo 'nameserver 223.6.6.6' >> /etc/resolv.conf

在 Docker 容器中,這個 /etc/resolv.conf 檔案可能還會有兩條內容,是容器本身所需要的,建議不要刪除/覆蓋,否則會出現容器間無法使用容器名互相通訊的情況。

啟動代理伺服器

那麼在測試撥號後確實可以通過 4G 網絡卡上網了之後,我們就可以把代理伺服器啟動了,這裡我使用的是 TinyProxy。

測試發現,Squid 對資源的佔用更大一些,不利於多網絡卡情況下的使用,會影響到 4G 網絡卡的數量上限。

apt install tinyproxy 一波,然後 vim /etc/tinyproxy/tinyproxy.conf 修改一下配置。

要修改的配置主要有:

  • Port 配置項改為3128,因為我們前面映射出來的埠是3128。
  • Listen 配置項改為0.0.0.0,因為我們需要在其他裝置上使用這個代理伺服器。
  • Allow 配置項註釋掉或改為0.0.0.0/0,預設的127.0.0.1會導致其他裝置無法訪問。

改完之後儲存一波,然後就可以直接執行 tinyproxy 啟動了...嗎?

等等,還有一個操作要做!那就是將預設路由指向到虛擬網絡卡上,很簡單,執行以下命令即可:

route del -net 0.0.0.0 eth0
route add -net 0.0.0.0 ppp0

這兩條命令的意思是:先將預設的、指向 eth0 這個網絡卡的上網路由刪除,然後新增一個同樣的、指向 ppp0 這個網絡卡的路由。

改完預設路由後的效果就是,即使你不使用 curl 的 --interface 引數,也能直接使用 4G 網絡卡上網了。

如果沒有改預設路由的話,在不指定網絡卡的情況下,4G 網絡卡並不會被使用到,因為預設路由指向的是 Docker 自身的虛擬網絡卡,那個網絡卡通向你原本的內網環境。也就是說,IP 不會變!

那麼現在,你可以執行 tinyproxy 啟動代理伺服器了。

測試代理伺服器

好了,代理伺服器應該已經正常啟動了,現在我們可以在另一個裝置上嘗試連線那個容器中的代理伺服器,看看是否能正常通過它使用 4G 網絡卡上網。

例如我這裡樹莓派分配到的IP是:192.168.137.66,那麼我就可以用這樣的 curl 命令或 Python 程式碼進行測試:

curl:

curl "https://ip.cn"
curl -x "192.168.137.66:3128" "https://ip.cn"

Python:

import requests
resp = requests.get("https://ip.cn", proxies={"https": "http://192.168.137.66:3128"})
no_proxy_resp = requests.get("https://ip.cn")
print(resp.text)
print(no_proxy_resp.text)

測試出來的結果應該與前面在容器內部測試時的一致,在使用代理後 IP 就變成了運營商分配的基站 IP。

更換 IP

那麼最核心的問題來了,怎麼更換 IP 呢?

其實和使用那些撥號 VPS 架設代理伺服器一樣,我們只需要重新撥個號就能換 IP 了,直接 kill 掉 pppd 程序就可以讓它斷開撥號,斷開後重新執行一遍撥號指令碼就是重新撥號了。

斷開撥號方面 Fanconn 的技術人員也提供了一個指令碼,同樣在 chmod +x quectel-ppp-kill 賦予執行許可權之後,執行 ./quectel-ppp-kill 就可以了。

但需要注意的是,蜂窩網路的撥號在斷開後,IP 仍然會保留一段時間(具體多久不清楚,可能跟連線的基站也有關係),所以我們需要強制性地讓網絡卡重新搜網。

冷門小知識:手機上開啟關閉飛航模式的效果就是重新搜網,通常只是關閉“移動資料”的話,效果是與斷開撥號一致的。

怎麼做呢?很簡單,就兩行命令:

AT+CFUN=0
AT+CFUN=1

但注意哦,這是 AT 命令,不是 Linux 下的 Shell 命令,AT 命令是一種調變解調器命令語言,我們如果需要將它執行起來,需要這麼做:

echo "AT+CFUN=0" > /dev/ttyUSB2
# 中間間隔1秒左右
echo "AT+CFUN=1" > /dev/ttyUSB2

這裡使用的 /dev/ttyUSB2 是指 4G 網絡卡的第三個通訊埠,文件中的解釋為:ttyUSB2→For AT command communication,與第四個通訊埠類似,只是它不能用於 PPP 連線、只能用於 AT 命令通訊而已。

不同樣使用第四個通訊埠的原因是那個埠有被佔用的可能性,直接區分開最穩妥,本來網絡卡也就是提供了兩個 AT 命令通訊渠道的。

在使網絡卡重新搜網後的幾秒至十幾/幾十秒內的時間裡,你無法正常撥號,需要等待它初始化完成後才可以撥號成功,具體等待時間以訊號強度為準,我測試的時候通常5秒以內就可以了。

所以如果你在斷開後一直撥號失敗,不妨過一會兒再試。


總結

那麼現在操作流程也跑通了,我們也瞭解到了整個的內部細節,最後要做的就是把每個網絡卡都分別分配一個容器,這樣我們就能實現文章開頭所提到的——“使用虛擬網絡卡作為出網網絡卡,並使用接入內網的實體網絡卡作為入網網絡卡”的效果了。

實際操作起來的話,就是把指定網絡卡的部分給配置化,然後在啟動容器的時候傳入就好了,使用 Docker 的容器環境變數相關設定可以很輕鬆地實現這個功能。

最後,我們可以以這個思路,構建一個 docker-compose 模板,模板的核心內容一是做個簡易的4G網絡卡容器叢集,二是啟動個 Squid,用來聚合代理伺服器,這樣我們使用的時候只需要指定一個代理伺服器就能隨機更換了,操作起來更加方便。


好了,上面就是 Docker 版搭建方式的思路和整個的搭建流程,如果你懶得看的話,直接用我寫好的輪子也是可以的,只需要傳送訊息【Docker版4G代理】到公眾號【NightTeam】即可。

評價

最後的最後,我給這個搭建方式打個評價吧。

這個搭建方式並不完美,因為變數太多,而且很多地方肯定不如系統級原生支援的那麼穩定,長期使用可能會出現各種奇奇怪怪的問題。

然後 Docker 的資源佔用其實挺高的,會浪費相當多的記憶體在啟動容器上,如果只是兩三個網絡卡還好,如果數量大一點的話,像樹莓派2B 這種小記憶體的裝置根本就扛不住。

另外代理伺服器本身對資源的消耗也是比較高的,高頻呼叫下對樹莓派2B 的小 CPU 壓力還是蠻大的,即使我對它的 CPU 進行了超頻,在併發測試時也還是會出現輕鬆打滿 CPU 的情況。

但是!截止目前,我還有兩種基於路由器系統的搭建方案沒寫出來!所以...敬請期待後續的其他搭建方案(斜眼笑)。


文章作者:「夜幕團隊 NightTeam」 - Loco

夜幕團隊成立於 2019 年,團隊包括崔慶才、周子淇、陳祥安、唐軼飛、馮威、蔡晉、戴煌金、張冶青和韋世東。

涉獵的程式語言包括但不限於 Python、Rust、C++、Go,領域涵蓋爬蟲、深度學習、服務研發、物件儲存等。團隊非正亦非邪,只做認為對的事情,請大家小心。