從celery rabbitmq with docker-compose 引出對容器、依賴注入、TDD的感悟


用docker配置項目管理系統taiga的時候,不是我一個人遇到這個問題。https://github.com/douglasmiranda/docker-taiga/issues/5

問題描述:

用docker-compose啟動celery_worker和rabbitmq,但是celery_worker 連不上 rabbitmq

celeryworker_1 | [2017-12-06 07:56:36,539: ERROR/MainProcess] consumer: Cannot connect to amqp://guest:**@rabbit1:5672//: [Errno -2] Name or service not known.
celeryworker_1 | Trying again in 4.00 seconds...

 

創建celery的地方用官網的

app = Celery(backend='amqp', broker='amqp://')

 

是不行的。

改成正式點的:

app = Celery(backend='amqp', broker='amqp://guest:guest@localhost:5672/')

 

也是不行的,不論用localhost。docker-compose 里 給 rabbitmq 設置的  hostname 都是不行的

 

成功嘗試一:rabbitmq在容器中,celery worker 和 發起異步任務在host

遇到問題1,首先縮小問題。分步嘗試,首先嘗試只用容器啟動rabbitmq。然后和傳統方式一樣,在host手工啟動celery worker。

成功。

問題縮小到celery_worker容器化的問題。

稍微靠譜點的解法是

1先手工創建1個docker bridge

2 用docker命令行分別啟動rabbitmq和celery worker 

3 手工把celery worker 和 rabbitmq 添加進bridge。

據說可行,但是我就是要用docker-compose的啊,這樣太丑陋了。

但至少說明有可能成功(不是celery本身bug之類)

 

 

 成功嘗試二、rabbitmq 和celeryworker都在容器中,celery用host的ip地址連接rabbitmq。

異步發起者可以在容器中,也可以在host中

 

docker中只運行rabbitmq,暴露5672 和15672端口,在本地host安裝celery 起celery worker 是沒問題的

但是如果想把celery worker也放進容器里,就出問題了。總是提示連不上amqp。

 用了各種方法,最終把rabbit5672暴露,然后把HOST主機IP灌進celery,搞定

 HOST_IP = '192.168.239.129' # ip of host(run docker-compose) 
app = Celery(backend = 'rpc://', broker = 'amqp://guest:guest@{0}:5672/'.format(HOST_IP))

額外的小技巧:

ubuntu查看 ip :

ip addr show

 

 成功嘗試三、rabbitmq 和celeryworker都在容器中,celery用docker-compose.yml中的service_name連接

異步發起者只能在容器中

20171207隔了一天,終於發現其實不需要HOST_IP,可以用名字連接的!

只不過名字被docker、rabbitmq給來回誤導了

先說答案:celery里要用docker-compose.yml里的這個名字,即啟動rabbitmq鏡像的那個service的名字(而不是他的hostname,我把它注釋掉了,太坑人):

這樣搞的話,比用HOST_IP不好的地方在於,沒法從host發起異步任務(返回不了結果)。只能從docker-compose啟動容器,在里面發起異步任務。

好處是5672端口不用暴露出來了。docker-compose內網和外部完全隔離,外面感覺不到rabbitmq存在(當然我保留了暴露15672監控端口,其實也可以不暴露)

 

 ——其實postgres的問題也是一樣,用Adminer連接的時候,Server處填的也是docker-composer.yml里的service名字。

http://www.cnblogs.com/xuanmanstein/p/7742647.html

 

 

結論

解決方案不細說了,放github上了

https://github.com/xuqinghan/celery-with-docker-compose#celery-with-docker-compose

 

心得:

1 遇到問題,要縮小、后退、分解。

 像鋸木頭鋸不動了,要往后撤,然后稍微換換方向,角度,再用巧力,不要用蠻力:

1從部署taiga的event模塊遇到celery_worker連接不上;

2退到用docker-compose運行celery官網的a+b小函數的demo 還是連不上;

3再繼續后退:只用docker-compose部署rabbitmq。手工啟動celery和發起異步任務,成功。

4在3成功的基礎上小步前進。而此時問題已經縮小、聚焦到足夠小,再嘗試幾種解決方案:localhost   127.0.0.1   hostname     bridge方式docker0網絡

5搞定、總結。成為自己的技能點,到處復用。

2 不要有潔癖,

不追求rabbitmq不暴露任何端口,只服務於docker-compose的網絡(不是docker0) ,在host里暴露端口不丟人;

在開發機上,只在調試當前工程時啟動當前的docker-compose。在生產環境還是1機1個組的。不追求多工程在一個機器上運行。

不追求一次就實現全都容器化,和寫代碼一樣,先寫好單次執行的邏輯,再套外層的for循環。

——注意到了這些點,問題半天不到就搞定了;死鑽牛角尖,可能N天都無解。

 

3 不能有0 or 100分這種想法。

不能急躁,也不能浮躁(想一次就得100分);

也不能因為想太多,把問題看成鐵板1塊,就畏懼困難(直接交白卷得0分)。

——做工程,都是1分、1分地得分,也是1分 1分地扣分的。 這和合同收付款、各種節點是完全不同的!不要被后者的干擾帶亂了自己的工作節奏。

做工程是類似持倉、空倉的長期過程,而不是啪啪啪不斷交易的各種精彩瞬間。(如果永遠處在趕工、保/搶節點的狀態,要么是自己工作能力不行,要么就是項目管理SB,沒有輕重緩急)

 

4做工程的人,在工程上做任何事每次出手,都要有章有法:有高度的目的論,且目的又和普通人不同:

1 貫徹目的和意圖導向的思考。在意從需求、系統用例、到組件名、類名、子過程名、直到變量名的命名,名不正則言不順,要強迫自己和別人(Не жалей ни себя, ни врагов.“不要吝惜自己和敵人”——《斯拉夫女人的告別》白俄版)思考目的性、價值和重要性排序。並且在每一天、每一句的開發中不斷加深學習、打磨、養成習慣;

2 能每時每刻聚焦特定問題,能暫時忽略其他問題和要求,有“置XX之敵於不顧”,“攻其一點,不及其余”的勇氣和能耐。這是建立在對能力的自信心(“打哪個,哪個就剩不下”,所以我有資格挑着打)基礎之上的純粹和純凈的心理狀態。

接觸新人、業余選手、非技術人員的最大感覺就是:

在1上,想的太簡單,做的太隨意(用我的話說,像個孩子);

在2上,一次想得太,想得太多(0分VS100分 來回地跳變,還是像個什么都想要的孩子)。

——包括之前的自己,也是這樣。還是因為功力不夠+心浮氣躁=棒槌。

因為和他們視角不同(甚至完全不同),所以自己首先不要生氣,配合別人的任務區時可以忍着點,盡力配合;

但只要進入自己的責任區,就是要火力全開。如果氣着對方也不要在意(負責這片的人是我,我也沒想故意氣誰,所以也無所謂)。

和戰斗機一樣,包線上各有優勢區,但進入大噴9(Spitfire LF IX)的優勢區,就不要怪Hispano 炮狠了。

 

技術方面的感受:容器和鏡像不是萬能的。不是什么都適合打包進鏡像。

celery和django都相繼不再在dockerhub發布官方鏡像。因為這倆在用的時候,大家都是定制、引用之后才用的。

並不是這倆和docker決裂了,只是不適合打包進dockerfile罷了。

對開發人員來說,什么適合塞進dockerfile呢?配環境的步驟+配出來的一致性,隔離的、純凈的運行環境。塞配置文件的位置。

其實dockerfile有點像測試框架。而源代碼和配置文件,類似mock。

所以,這符合我下意識的做法:我喜歡把源代碼、和各種配置文件,數據庫文件都放在外面, 用-v 或者volumns 在容器啟動時掛進去,而不是寫在dockerfile里(git clone 源代碼,具體配置參數),直接build成image。

 

這種套路,非常類似於依賴注入,把repository,service塞進component的過程。

此外,這樣好寫測試用例啊(不依賴實際連接web和數據庫)!

任何單元測試的運行,都不能依賴真實的web和數據庫訪問。

否則因為耗時間或者環境難配,不得不每次注釋掉一部分用例,現在想想,那還測試個屁啊!

 

寫程序的精髓在於識別和感受到  復雜性+變化性   VS  繁瑣+穩定    ,然后不斷分離,隔離,讓不同變化速率,膨脹系數的材料,高度地解耦。

——寫程序的門道無非那幾條,但是知道這些道理是一回事,理解認同這些道理是另一回事, 而實際工作中能在各種場合把這些招給用出來,用活了,又是另一回事了。

和武術、修行一樣,知易行難。“三歲小兒道得,八十老翁行不得”。

需要勤學苦練,不是蠻干(grasshopper里不寫代碼,一片一片地電池)

從各種角度、各種道路、多次實踐,去領悟相同的道理。

然后就容易全面開竅和到處突破了。

之前了解、學TDD半天,但是就是用不好;現在用了一段時間docker,反而容易找到依賴注入的感覺。

自己寫的程序,有哪些是框架性的,類似dockefile的;有哪些是頻繁改動的,類似源代碼、配置文件內容的,要層次分明,分離,然后各自獲得自由;

這個分離:就是意圖與實現、虛VS實;部隊 VS 分隊,測試用例VS外部接口的mock。

關注點分離了,就各自聚焦了,也自由了。分得開,責任邊界清晰,才聯合得起來。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM