使用Ruby on Rails開啟Docker微服務之旅

我們談論關于架構的話題所意,總離不開微服務淮逊,而微服務又會引向容器和Docker。它們都是能簡化龐大而復雜應用的構建過程扁眯。本周希云和大家分享壮莹,如何在Giant Swarm上運行Docker化的Ruby on Rails應用。

對于微服務姻檀,沒有一個像apt-get這樣的工具命满,不禁讓人問:“我怎樣安裝這個新東西?” 答案是:“你安裝不了微服務绣版〗禾ǎ” 更具體來說是,“你不可能一下子就用上它杂抽≌┗#”

“一個系統(tǒng)的架構是最難改變的”,“微服務”這個新事物也不是一顆銀彈缩麸,即使在今天也沒有人能輕易就重構一個復雜的系統(tǒng)铸磅,尤其是對于像用了Rails框架構造出來的龐大系統(tǒng)。

Docker承諾的一個特性是:“減少開發(fā)杭朱、測試和生產環(huán)境之間的差異” 阅仔,然而,在生產環(huán)境運行Docker并不簡單弧械,所以我們將研究Giant Swarm這樣的工具是如何簡化這個部署過程的八酒。

剛開始,我會把一個簡單的應用Docker化刃唐,這個應用是一個NoSQL數(shù)據(jù)庫ArangoDb的ODM羞迷。你能在Github上找到這個應用,如果你要自己嘗試這個例子画饥,你的機器上需要裝好Docker衔瓮,Ruby 2版本以上,還有一個用于部署的Giant Swarm賬號抖甘,不需要單獨安裝數(shù)據(jù)庫热鞍,將會在本地使用一個容器作為數(shù)據(jù)庫。

?各個擊破

在我們制作Docker容器之前,先看一下這個應用的本身碍现,以及我們將如何實現(xiàn)Docker化,我們手頭上的應用是一個普通的Web工程:

一個前端

通過OAuth2使用GitHub登錄

調用外部接口(GitHub)

后臺長期運行的任務

主數(shù)據(jù)庫

任務隊列

可以把這些功能都放到一個容器中米奸,但是這樣會得不償失昼接。例如,會失去應用和數(shù)據(jù)庫分離帶來的可擴展性悴晰。遵循在每個容器只運行一個進程的原則慢睡,把應用分成5個容器:

Nginx會作為前端代理服務器,在我們的例子中它會提供靜態(tài)資源铡溪,在更復雜的應用中漂辐,它可能會作為訪問控制或者為后端服務提供負載均衡。

第二層是Rails應用棕硫,它會運行在一個簡單的web服務中髓涯,這里用的是Puma。

Sidekiq也會運行在一個獨立的容器中哈扮,如果你有一個以上的隊列纬纪,需要為每一個隊列創(chuàng)建一個容器。

一個安裝了Redis作為任務隊列的容器滑肉。

一個安裝了ArangoDB作為主數(shù)據(jù)庫的容器包各。

以下這幅圖幫助我們去理解這個架構,以及組件之間的通訊:

把Sidekiq放到一個單獨的容器運行和微服務架構還相差很遠靶庙,但這已經(jīng)使這個應用有不錯的隔離性问畅,使每個服務都在各自的工作進程中。

??各個組件

我們已經(jīng)指定了各個容器的功能六荒,現(xiàn)在就要動手創(chuàng)建它們了护姆。Docker容器是基于Dockerfile構建的,這個文件描述了每一個構建步驟恬吕。前面說到我們需要五個容器签则,對應地需要五個Dockerfile。

不過幸運的是铐料,這些容器可以共享同一個鏡像渐裂。我們不需要額外的定制鏡像就可以直接用了,你能找到各種應用的鏡像钠惩,當然種類最多的還是數(shù)據(jù)庫柒凉。

??數(shù)據(jù)庫

我們將使用官方的Redis和ArangoDB鏡像,通過以下命令運行:

# 會運行Redis并把端口暴露到宿主機

$ docker run --name redis-dredis

# 會運行ArangoDB并把端口暴露到宿主機

$ docker run --name arangodb-darangodb/arangodb

這兩個命令會從官方的鏡像庫獲取到鏡像篓跛,以后臺方式(-d)啟動膝捞,并且分配了一個名稱(—name),它們都會分配到一個卷還有默認的端口愧沟。對于ArangoDB蔬咬,至少應該為生產環(huán)境配置權限認證的設置鲤遥。

??Nginx 前端代理

記住,Docker容器應該是被看作不可變的林艘,改變應該發(fā)生在構建時而不是運行時盖奈,這個要在每次更改時重新構建鏡像。對于Nginx前端狐援,需要這樣一個更改:指定一個配置文件來代理Rails應用钢坦。因為Docker鏡像每次構建時都使用一個已經(jīng)存在的鏡像,我們使用了官方的Nginx鏡像作為基礎鏡像:

FROM nginx

RUN rm -rf /usr/share/nginx/html

COPY public /usr/share/nginx/html

COPY config/deploy/nginx.conf /etc/nginx/conf.d/default.conf

Dockerfile的開頭總是FROM語句啥酱,它告訴Docker要繼承于哪個基礎鏡像爹凹。另外我們只需要COPY這個public目錄和配置到鏡像中,正如我前邊所說镶殷,容器應該被看作不可變的禾酱,每當需要改變這些資源時,應該創(chuàng)建一個新的鏡像批钠。Nginx的配置如下:

server { ? ?listen80; ? ?server_name ?localhost; ? ?location / { ? ? ? ?root ? ? ?/usr/share/nginx/html; ? ? ? ?index ? ? index.html index.htm; ? ? ? ?try_files$uri/index.html$uri.html$uri@upstream; ? ?} ? ?location @upstream { ? ? ? ?proxy_pass http://rails-app:8080; ? ?}}

還有一件事應該提一下:這個rails-app主機名從哪里來的呢宇植?Docker將提供兩種方法去連接容器(我們會解釋這點),一串環(huán)境變量和/etc/hosts文件。在這個例子中埋心,我們使用了/etc/hosts指郁。

? Rails應用和Sidekiq Worker

現(xiàn)在添加Nginx代理的后端服務:Rails應用。官方有個Rails Dockerfile拷呆,但不會用它闲坎,因為它會安裝一些我們不需要的組件,更糟的是它安裝bundle的時候沒用—deployment參數(shù)茬斧。盡管如此腰懂,還是用它作為指引:

FROM ruby:2.1.5

# 如果Gemfile被修改過則拋出錯誤

RUN bundle config --global frozen1

RUN mkdir -p /usr/src/appWORKDIR /usr/src/appCOPY Gemfile /usr/src/app/COPY Gemfile.lock /usr/src/app/RUN bundle install --deploymentCOPY . /usr/src/app/ENV RAILS_ENV productionEXPOSE8080CMD ["/usr/src/app/bin/rails","server","-p","8080"]

不用Docker我們可以部署類似Capistrano之類的應用,而現(xiàn)在项秉,需要在遠程服務器上操作的步驟绣溜,我們可以在構建Docker鏡像時就完成了。諸如安裝gem包和復制代碼到服務器娄蔼,通過這樣怖喻,有了一個在任何地方任何時間都能啟動的容器,而且它的狀態(tài)和我們最初構建它的時候一模一樣岁诉。

Sidekiq Worker的Dockerfile基本和上邊的一樣锚沸,比直接復制這個Dockerfile更好的方式是,定義一個公用的基礎鏡像涕癣,用于構建Rails應用和Sidekiq Worker哗蜈。

??構建容器

Docker期待的是一個Dockerfile而例子中已經(jīng)有三個了,把每個Dockerfile加上了一個有意義的后綴,但是使用Docker命令時會重命名這些文件距潘。如果有一個工具可以用來實現(xiàn)這個炼列,那就是Rake:

namespace :dockerdotask :build => ['docker:build:web','docker:build:app','docker:build:worker','assets:clobber'] ?namespace :builddotask :web => ['assets:precompile','assets:clean']dosh'ln -snf Dockerfile.web Dockerfile'sh'sudo docker build -t "registry.giantswarm.io/yoshida/gh-recommender-web" .'sh'rm -f Dockerfile'end ? ?task :app => ['assets:precompile','assets:clean']dosh'ln -snf Dockerfile.app Dockerfile'sh'sudo docker build -t "registry.giantswarm.io/yoshida/gh-recommender-app" .'sh'rm -f Dockerfile'end ? ?task :workerdosh'ln -snf Dockerfile.worker Dockerfile'sh'sudo docker build -t "registry.giantswarm.io/yoshida/gh-recommender-worker" .'sh'rm -f Dockerfile'end ?endend

web和app的構建都需要使用RAILS_ENV=production,因為要這些文件都是給生產環(huán)境而不是開發(fā)環(huán)境生成的音比。-t參數(shù)會指定目標鏡像的倉庫名稱唯鸭,這對下一步把鏡像推到云上是必須的。

??轉移到云上

目前為止我們已經(jīng)有了一個完整的本地環(huán)境硅确,這很好,但是如果想真正要的是對外的環(huán)境明肮,至少還要幾步菱农。

任何人都可以配置服務器來運行基于Docker的應用。但是這樣的話就要面對各種挑戰(zhàn):把容器鏈接在一起柿估,擴展容器循未,管理跨節(jié)點的容器,還有更多秫舌。幸運的是的妖,你可以直接使用Giant Swarm,這些它都幫你考慮了足陨。首先你需要獲取一個邀請碼嫂粟,你注冊之后就可以使用swarm命令行工具去配置你本地的機器了。第一件要做的事是創(chuàng)建一個swarm.json:

{ ?"name":"github_recommender", ?"components":{ ? ?"arangodb":{ ? ? ?"image":"arangodb/arangodb", ? ? ?"ports":["8529/tcp"], ? ? ?"volumes":[ ? ? ? ?{ ? ? ? ? ?"path":"/data", ? ? ? ? ?"size":"5 GB"} ? ? ?]}, ? ?"nginx":{ ? ? ?"image":"registry.giantswarm.io/yoshida/gh-recommender-web", ? ? ?"ports":["80/tcp"], ? ? ?"domains":{ ? ? ? ?"80/tcp":["gh-recommender.gigantic.io"]}, ? ? ?"links":[ ? ? ? ?{ ? ? ? ? ?"component":"rails-app", ? ? ? ? ?"target_port":"8080/tcp"} ? ? ?]}, ? ?"rails-app":{ ? ? ?"image":"registry.giantswarm.io/yoshida/gh-recommender-app", ? ? ?"ports":["8080/tcp"], ? ? ?"env":["RAILS_ENV=production","SECRET_KEY_BASE=$secret_key_base","REDIS_URL=redis://redis:6379","GITHUB_KEY=$github_key","GITHUB_SECRET=$github_secret"], ? ? ?"links":[ ? ? ? ?{ ? ? ? ? ?"component":"arangodb", ? ? ? ? ?"target_port":"8529/tcp"}, ? ? ? ?{ ? ? ? ? ?"component":"redis", ? ? ? ? ?"target_port":"6379/tcp"} ? ? ?]}, ? ?"redis":{ ? ? ?"image":"redis", ? ? ?"ports":["6379/tcp"]}, ? ?"sidekiq-worker":{ ? ? ?"image":"registry.giantswarm.io/yoshida/gh-recommender-worker", ? ? ?"env":["RAILS_ENV=production","SECRET_KEY_BASE=$secret_key_base","REDIS_URL=redis://redis:6379"], ? ? ?"links":[ ? ? ? ?{ ? ? ? ? ?"component":"arangodb", ? ? ? ? ?"target_port":"8529/tcp"}, ? ? ? ?{ ? ? ? ? ?"component":"redis", ? ? ? ? ?"target_port":"6379/tcp"} ? ? ?]}}}

這里定義了整個應用和組件之間的關聯(lián)關系墨缘,回想一下Nginx的配置星虹,我們使用了http://rails-app:8080作為后端地址,這就是我們定義的地方镊讼。rails-app組件會被鏈接到Nginx組件宽涌,同樣,REDIS_URL也被關聯(lián)到了redis組件蝶棋。

如果不想在swarm.json中放置敏感信息(例如Github OAuth2的token)卸亮,可以單獨在一個swarmvars.json文件中定義這些變量:

{"GIANT_SWARM_USER/dev": {"github_key":"GITHUB_KEY","github_secret":"GITHUB_SECRET","secret_key_base":"SECRET_KEY_BASE"}}

可以使用例如$github_key關聯(lián)這些變量到swarm.json,當應用在Giant Swarm上運行時玩裙,各個容器會使用適當?shù)摹猯ink和—env選項兼贸。為了使所有服務都能從外部訪問,我們需要指定域名到至少一個組件献酗,Nginx是我們的入口寝受,所以把域名指定到它上。

在啟動應用之前罕偎,首先需要上傳鏡像到Giant Swarm的鏡像庫上(當然你也可以推到Docker Hub上很澄,但可能你不想你的鏡像能被公開訪問):

$ docker push registry.giantswarm.io/yoshida/gh-recommender-web

$ docker push registry.giantswarm.io/yoshida/gh-recommender-app

$ docker push registry.giantswarm.io/yoshida/gh-recommender-worker

網(wǎng)絡狀況會直接影響這個上傳過程,一旦上傳完成,就可以用這個命令啟動所有容器:

$ swarm up

這個命令會從倉庫中獲取所有需要用到的鏡像甩苛,然后以適合的參數(shù)啟動各個容器蹂楣,收集所有容器的日志,并且在http://gh-recommender.gigantic.io下部署好了應用讯蒲。整個過程異常簡潔痊土。

如果已經(jīng)到了這步,恭喜你墨林!

??擴容

現(xiàn)在我們?yōu)槊總€組件都使用了一個容器赁酝,當你的應用吸引了更多的用戶,或者突然發(fā)生了不可預見的事件需要更加多的資源旭等。傳統(tǒng)的做法是添加更多的服務器酌呆,需要一系列的人工操作:啟動機器,搭建好環(huán)境并且添加節(jié)點到負載均衡中搔耕。使用Giant Swarm的話隙袁,添加一個實例非常簡單:

$ swarm scaleup github_recommender/gh-recommender/rails-app

這樣減輕了很多技術負擔,但是它并不能使你的應用魔法般地就支持水平擴展弃榨,當它在數(shù)據(jù)庫應用上就更加復雜了菩收,你還需要研究怎樣使應用支持擴展。但是這樣至少你可以專注于這塊鲸睛,而不需要擔心基礎設施的細節(jié)了娜饵。

??結論

文中談及的就是這些,在這主題下官辈,還有更多的東西可以討論和學習划咐。分享的目的是希望起碼可以帶大家入門,如果想走得更遠钧萍,這里有幾點建議主題褐缠,是文中沒有提及但密切關聯(lián)的:

容器能在本地開發(fā)環(huán)境使用,但本文并沒有涉及如何實現(xiàn)风瘦。

無論在本地或者生產環(huán)境下队魏,調試容器都是一個比較大的問題。正如它的其它方面万搔,這個也沒有銀彈胡桨,可能也永遠不會有。這也是需要注意的地方瞬雹。

在Docker世界中昧谊,安全也是一個大問題,使用Giant Swarm會有所幫助酗捌,我們需要熟悉容器和Docker可能帶來的安全性問題呢诬。這里說的不是安全漏洞涌哲,而是與傳統(tǒng)部署方式之間的不同,例如像安裝或管理虛擬機那樣尚镰。

此外阀圾,希云強烈建議大家自己打包鏡像,不要依賴于公共鏡像庫狗唉。否則最終你會需要很多不同的鏡像初烘。例如,例子中的五個容器就需要三個不同的Linux分發(fā)版分俯。

嘗試在每個容器中只啟動一個進程肾筐,雖然這是Docker官方的建議,但無疑這是有爭議的缸剪,是否必須要這樣做局齿,應該具體問題具體分析,根據(jù)實際情況做出決定橄登。

如了解更多Docker相關知識,請觀看培訓視頻:https://csphere.cn/training讥此!

如需要Docker相關產品拢锹,請訪問希云官網(wǎng)首頁:https://csphere.cn!

cSphere1.0版本已發(fā)布萄喳,正式商用卒稳!歡迎咨詢 400-686-1560

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市他巨,隨后出現(xiàn)的幾起案子充坑,更是在濱河造成了極大的恐慌,老刑警劉巖染突,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捻爷,死亡現(xiàn)場離奇詭異,居然都是意外死亡份企,警方通過查閱死者的電腦和手機也榄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來司志,“玉大人甜紫,你說我怎么就攤上這事÷钤叮” “怎么了囚霸?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長激才。 經(jīng)常有香客問我拓型,道長额嘿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任吨述,我火速辦了婚禮岩睁,結果婚禮上,老公的妹妹穿的比我還像新娘揣云。我一直安慰自己捕儒,他們只是感情好,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布邓夕。 她就那樣靜靜地躺著刘莹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪焚刚。 梳的紋絲不亂的頭發(fā)上点弯,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天,我揣著相機與錄音矿咕,去河邊找鬼抢肛。 笑死,一個胖子當著我的面吹牛碳柱,可吹牛的內容都是我干的捡絮。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼莲镣,長吁一口氣:“原來是場噩夢啊……” “哼福稳!你這毒婦竟也來了?” 一聲冷哼從身側響起瑞侮,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤的圆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后半火,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體越妈,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年钮糖,在試婚紗的時候發(fā)現(xiàn)自己被綠了叮称。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡藐鹤,死狀恐怖瓤檐,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情娱节,我是刑警寧澤挠蛉,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站肄满,受9級特大地震影響谴古,放射性物質發(fā)生泄漏质涛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一掰担、第九天 我趴在偏房一處隱蔽的房頂上張望汇陆。 院中可真熱鬧,春花似錦带饱、人聲如沸毡代。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽教寂。三九已至,卻和暖如春执庐,著一層夾襖步出監(jiān)牢的瞬間酪耕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工轨淌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留迂烁,地道東北人。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓递鹉,卻偏偏與公主長得像盟步,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子梳虽,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內容