本身工作偏開發,為何要了解Docker?
最近Micro service火紅,大型服務被切成一個一個小模組,減少彼此耦合,個別跑在各自container上,方便重複部署,且彼此互相用Rest API或socket溝通。這樣帶來的好處在於可以在開發上減少後續迭代的困難,減少維運的難度,增加系統穩定性。
但要獲得這些好處,軟體在最初開始設計架構的階段就要拆分服務,一開始設計不好之後就算有docker工具那也只是把所有服務丟到同一個Container上,沒有辦法發揮docker切割服務的優勢。
所以想成為架構師,當然不能不了解這個工具。而從程式開發上來看,能夠把CI Keep in mind,有新Commit Push到develop branch,CI Server就自動執行下面步驟
打包新的Image
產生Container
執行Service
Run Test Code…
能夠協助開發者確保最終程式碼在Production環境是可以正常運行,有問題可以立即發現與處理。
Docker對比傳統VM優點在於所消耗資源很小,啟動速度很快,並且兼具傳統VM打包成Image擋可以Anywhere都快速建立起一樣的Service等優點。
這篇文章主要就以上面幾點依序從包含如何製作Image,產生Container,利用Container啟動我們要的Service,最後如何匯出部署到另一台機器等一系列記錄下來。
Dockerfile與Base Image
要導入的Service是由三個部分組成
Node.js專案,用Express作為Route Framework,為業務邏輯層負責API JSON的輸出
Node.js專案,用Express作為Route Framework,使用Bootstrap來包含View的後台操作介面
MySQL Instance
之前做法是把Node.js專案都放在同台Server,但因爲HA需要,所以也有一台Hot standby的實體機並排在HAProxy下。這裡帶來第一個問題是當要重新build環境時靠Install Guide手動安裝很不方便,解決方法便是用Dockerfile
,把Install Guide所需的環境與步驟打包成一個Image。
1&2專案相同部分是Node.js專案,用Express作為Route Framework
,所以可以Build一個Base Image來當基底環境,之後只要分別把/var/www
置換成對應的專案檔即可。
1
2
3
4
5
6
7
8
FROM centos:7 // 指定CentOS
MAINTAINER daan.shih@gmail.com
RUN yum install -y epel-release // -y避免互動輸入
RUN yum install -y nodejs
RUN yum install -y npm
RUN npm install pm2 -g
RUN mkdir /var/www/
WORKDIR /var/www/
有了Dockerfile後就可以Build Image了
1
docker build -f /path/to/dockerfile ./
之後會得到一個Image ID,因為是只安裝npm基底就取名為npm-ready
1
docker tag [Image ID] npm-ready
現在打docker images
應該可以看到類似npm-ready latest 43c671f848fd 22 hours ago 405.6 MB
的資訊
以Base Image為底,加入express專案檔
這時候我們已經有一個Image檔,包含npm與必須的tools,只缺express專案檔。所以接下來就以FROM
指令,指定以npm-ready:latest
為底,用COPY
指令把我們需要的專案檔複製到Image中。
這裡要注意第三行的PSControlCenter/
這個目錄必須與Dockerfile同一個目錄(docker build
後面會加上的path我們是打./),不然會出現找不到此目錄。
1
2
3
FROM npm-ready:latest
MAINTAINER daan.shih@gmail.com
COPY ControlCenter/ /var/www/
得到新Image ID後幫它補上名字方便識別
1
docker tag [Image ID] control-center
Image to Container
至此我們已經有一個包含全部所需要檔案的Image檔control-center
了。現在只需要利用Image去產生一個Container,並且執行這個Container就行了。
本來產生create
與執行start
是兩個指令,這裡可以用run
來代表連續執行上面兩個指令。類似git裡面pull
是連續執行fetch
和merge
。
1
docker run -t -i -p 9453:3000 [Image ID] /bin/bash
這裡要注意的是-p
,每個運行中的container的網路環境與host是完全分離的,所以我們要從外部去訪問container,就要用這個指令來指定port的相依關係。
這個例子裡我們在host輸入127.0.0.1:9453就會訪問到container的3000 port。
建立完container後,這時可以透過下面指令拿到Container ID
1
docker ps -a // -a會列出所有container(包含停止)
運行container後,想再得到運行狀態中的container的bash shell可執行
1
docker exec -it [container-id] bash
exec指令就是對該運行中的container下達指令。
Run Service
到這裡我們已經利用Image去產生Container,並起啟動了Container,指定了Port的映射關係,最後取得該Container的Shell。這時環境已經建立起來,我們就可利用PM2把service給run起來:
1
pm2 start ./bin/www --watch --name "www"
然後在Host瀏覽器訪問127.0.0.9453,就可以看到服務啟動了。
部署在另一台機器上
把control-center這個Image用save
指令匯出成.tar檔
1
docker save control-center > ./control-center.tar
接著在另一台的Dokcer instance上用load
指令,指定tar檔路徑匯入成image
1
docker load < /path/to/control-center.tar
再來用docker images
來確認是否有成功匯入Imagecontrol-center
。
之後我們便可以把該Imagecontrol-center
打包匯出到其他機器,短短的兩行幾秒內就把服務給建立起來,非常輕鬆寫意的部屬方式。
1
2
docker run -t -i -p 9453:3000 [Image ID] /bin/bash
pm2 start ./bin/www --watch --name "www"
Next
下次介紹另一個Docker的重要概念:Volume。Container與Image有個很重要原則是裡面不要存Data,也就是不要把MySQL的資料給存在Image裡,所以在資料庫相關的Container裡有關Data的部分會採用另外掛載的方式。
參考FYI