用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。
關注點分離了,就各自聚焦了,也自由了。分得開,責任邊界清晰,才聯合得起來。