erlang的原理與linux系統很是像,有進程的概念,有進程調度等。今天要驗證的就是相似於DNS的功能:epmd。epmd是Erlang Port Mapper Daemon的縮寫,用於Erlang集羣中的節點互通。好比在ip1上面啓動了一個節點 nodeA@ip1,在ip2上面啓動了一個節點nodeB@ip2,若是nodeA要訪問nodeB,那麼首先會去connect nodeB節點上的epmd服務的端口:4369 端口,他會告訴nodeA,nodeB@ip2是在哪一個端口,而後nodeA直接connect該端口,與nodeB進行通訊。若是nodeB想要與nodeA通訊,因爲nodeA已經於nodeB創建了鏈路,那麼直接使用該鏈路進行通訊,不然也要像nodeA同樣,先訪問nodeA的4369端口,獲取nodeA的監聽端口,而後訪問該端口。關於epmd的原理和使用,有不少寫的很好的文章,好比[Erlang 0123] Erlang EPMD,Erlang epmd的角色以及使用,建議讀者能夠先看一下這篇文章:[Erlang 0123] Erlang EPMD,本文只是單純的驗證-kernel inet_dist_listen_min PortMin inet_dist_listen_max PortMax的正確性,而後講解一下遇到的防火牆配置問題,最後總結一下在生產環境應該如何開通訪問權限。由於生產環境遵循最小權限的原則,因此須要對端口權限控制的很是精準。在如rabbitmq、couchbase這樣的erlang應用中都會用到。html
咱們先說一下結論:
首先在192.168.3.142機器上面啓動一個節點'test142@192.168.3.142',而後在另一臺機器192.168.3.140上面啓動一個節點'test140@192.168.3.140',上面部署了一個使用erlang代碼編寫的web監控程序,須要監控節點'test142@192.168.3.142'的運行狀況。此時就須要這兩個節點之間可以連通。顯然局域網中是很容易實現的,沒有太多的端口限制。可是若是'test142@192.168.3.142'是部署在生產環境內的局域網,'test140@192.168.3.140'是部署在DMZ區,他們之間的訪問就涉及到端口權限的開通。首先須要140申請訪問142的epmd-4369端口,這樣才能查到test142節點的監聽端口。(爲保障生產環境的安全,除非必要,通常不會反向開通142到140的4369端口。)而後142的4369端口會告訴140,節點'test142@192.168.3.142'監聽的端口,一般這是一個隨機端口。這樣140還須要再申請到142的隨機端口的訪問,這顯然是不現實的。因此erlang提供了一個解決辦法:固定test142節點的監聽範圍,而不讓他變成隨機端口。node
erl -kernel inet_dist_listen_min 44000 inet_dist_listen_max 44002 -name test142@192.168.3.142 -setcookie test
在192.168.3.142機器上面執行該命令,設置該節點啓動以後,監聽的端口爲44000,若是44000被佔用,那麼監聽44001,若是依然被佔用,那麼監聽44002,若是還被佔用,那麼報錯。這樣140只須要開通到142上44000~44002的端口權限就能夠了。因此申請的端口列表是:linux
src:192.168.3.140 to:192.168.3.142 port:4369web
src:192.168.3.140 to:192.168.3.142 port:44000shell
src:192.168.3.140 to:192.168.3.142 port:44001centos
src:192.168.3.140 to:192.168.3.142 port:44002安全
那麼從'test140@192.168.3.140'訪問'test142@192.168.3.142'的鏈路是通的,可是從'test142@192.168.3.142'到'test140@192.168.3.140'的鏈路是否也通呢?若是你在142機器上面執行cookie
net_adm:ping('test140@192.168.3.140').
獲得的結果是"pang",也就是不通。難道必須開通反向的從142到140的端口嗎?其實不用,咱們先在140機器上面執行app
net_adm:ping('test142@192.168.3.142').
獲得的結果是"pong",這是正常的,由於咱們已經開通了從140到142的4369和44000的權限。此時再去142機器上執行net_adm:ping('test140@192.168.3.140'). 會發現獲得的結果是"pong",竟然通了!咱們不須要再開通反向的端口權限就解決了這個問題。這樣能最大限度的減小端口的開通。因此在生產環境中咱們只須要開通上面4個端口權限便可。 ssh
到這裏結論已經出來了,若是讀者願意繼續看,下面是個人驗證過程,涉及到防火牆的配置,若是沒興趣,到這裏就能夠結束了。
192.168.3.140和192.168.3.142都是個人Centos虛擬機。爲了將192.168.3.142模擬成生產環境,我將142機器上面的全部端口都屏蔽:
iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT DROP
關於iptables 防火牆的操做,你們能夠參考這個:linux IPtable防火牆 禁止和開放端口,講得很是詳細。若是iptables命令不可用,出現相似於這樣的錯誤
The service command supports only basic LSB actions (start, stop, restart, try-restart, reload, force-reload, status). For other actions, please try to use systemctl.
或者出現異常,能夠參考這個解決:關於centos 7 中service iptables save 指令使用失敗的結局方案 。若是讀者是在xshell這樣的ssh軟件裏面執行上面的操做,那麼執行到中途就會發現ssh鏈接斷開了,由於ssh的22號端口已經被防火牆屏蔽了,因此建議你們直接在虛擬機中執行上面三條命令。而後,爲了方便輸入,咱們能夠打開22號端口,輸入如下命令:
iptables -A INPUT -p tcp --dport 22 -j ACCEPT iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
第一條准入命令,表示容許其餘機器准入,協議是tcp,目的端口是22,注意這個是單向的,即只容許其餘機器向142的22端口發送數據,可是不容許22端口回覆數據,因此此時ssh其實仍是不可用,咱們還須要加上下面那一條,容許準出:容許本機從22端口發出tcp數據包。這樣咱們就可使用xshell這樣的軟件方便使用了。
iptables -A INPUT -p tcp -s 192.168.3.140 --dport 4369 -j ACCEPT iptables -A OUTPUT -p tcp -d 192.168.3.140 --sport 4369 -j ACCEPT
第一條是准入命令:容許源ip地址爲192.168.3.140的機器,向本機的4369端口發送tcp的數據包,一樣這也是單向的,因此必須加上第二條準出命令:容許本機的4369端口先目的ip地址爲192.168.3.140的機器發送tcp數據包,這樣才能保證順暢的訪問4369端口。此時在140機器上面telnet 142 的4369 端口是通的。
iptables -A INPUT -p tcp -s 192.168.3.140 --dport 44000 -j ACCEPT iptables -A OUTPUT -p tcp -d 192.168.3.140 --sport 44000 -j ACCEPT iptables -A INPUT -p tcp -s 192.168.3.140 --dport 44001 -j ACCEPT iptables -A OUTPUT -p tcp -d 192.168.3.140 --sport 44001 -j ACCEPT iptables -A INPUT -p tcp -s 192.168.3.140 --dport 44002 -j ACCEPT iptables -A OUTPUT -p tcp -d 192.168.3.140 --sport 44002 -j ACCEPT
erl -kernel inet_dist_listen_min 44000 inet_dist_listen_max 44002 -name test142@192.168.3.142 -setcookie test
你會驚訝的發現啓動不了,命令一直卡在那裏不動,什麼緣由呢?由於142機器上面的端口權限,只開通了上面幾個,其餘全部的端口都是禁止的,包括142訪問142本身的端口,也一樣是禁止的,沒法訪問!erlang在啓動的時候,須要訪問本地的端口的,因此應該容許142機器擁有訪問自己的權限:
iptables -A INPUT -s 127.0.0.1 -j ACCEPT iptables -A OUTPUT -d 127.0.0.1 -j ACCEPT
一樣,也是兩條命令,一條准入,一條準出,一條都不能少。按照理解,第一條准入命令與第二條準出命令是等價的,好像只有一條就能夠。可是我試過刪除第二條準出命令,只留下第一條准入命令,依然是卡在那裏不動,因此兩條命令一條都不能少。在142上面執行
iptables -L -n
查看一下當前的防火牆配置,能夠看到以下的防火牆規則:
執行以下命令查看本機當前的全部erlang節點所監聽的端口
epmd -names
能夠看到"name test142 at port 44000"的提示,說明test142節點已經監聽在了44000端口
在142機器的erl界面裏執行ping 命令用以測試是否與140節點連通,能夠看到結果爲"pang",是通不了的。
net_adm:ping('test140@192.168.3.140').
而後在140機器上面啓動一個erlang節點,
erl -name test140@192.168.3.140 -setcookie test
而後測試與142節點是否連通,能夠看到結果是"pong",是能夠通的
此時再在142機器的erl界面裏執行ping 命令用以測試是否與140節點連通,能夠看到結果爲"pong",已經連通,由於上一步test140節點已經建好了一條鏈路,因此能夠連通。
至此,在知足最小端口權限的原則下,已經打通了兩個節點之間的通訊鏈路。