持續交付系列(一):使用Docker、Mesos實現持續交付
本文主要講述如何為Node.js應用搭建持續集成環境。包括如何在開發機器上Docker化一個Node.js應用,如何部署Jenkins和 Docker registry以實現持續集成。推薦對使用Docker做CI方面的工作感興趣的同學閱讀,CI也是Docker的應用場景之一,本文是很好的教程。
你首先需要在你的Linux機器上安裝Docker和Fig。本文主要會介紹如何使用Docker和Mesos實現持續集成。
測試、搭建生產環境可用的Mesos集群以及其它的復雜工作不在本文討論范圍之內,我會在后續文章中詳細介紹。接下來,我們將在更多的云平臺上支持該解決方案,比如GCE、AWS,并逐漸集成更多的第三方組件,比如 Flocker、 Weave和 Consul。
本文所有的代碼都可以在 GitHub上找到。
整個解決方案中,我們使用到如下工具:
- Node.js里的HelloWorld項目
- Git
- Jenkins
- Docker
- Docker Registry
- Fig
- Mesos
- Mesosphere Marathon
- Zookeeper
開發環境
讓我們先從一個簡單的HelloWorld先用開始吧,它使用Node.js編寫,并且運行在Docker容器中。從下圖中,你可以看到開發人員在本地環境中使用容器運行構建、測試以及其它流程,如下圖淡藍色方塊所示。一旦測試通過,他們將會把代碼提交到中央Git倉庫,接下來會發布到生產環境。
我假定閱讀這篇文章的讀者都能理解并且自己實現這一步。
首先是Node.js應用app.js:
// Load the http module to create an http server. var http = require('http');// Configure our HTTP server to respond with Hello World to all requests. var server = http.createServer(function (request, response) { response.writeHead(200, {"Content-Type": "text/plain"}); response.end("Hello World\n"); });
// Listen on port 8000, IP defaults to "0.0.0.0" server.listen(8000);
// Put a friendly message on the terminal console.log("Server running at 對應的配置文件package.json:
{ "name": "hello-world", "description": "hello world", "version": "0.0.1", "private": true, "dependencies": { "express": "3.x" }, "scripts": {"start": "node app.js"} }
上面兩步完成之后,可以使用 Google的Node.js鏡像來Docker化該應用,并且添加如下Dockerfile:
FROM google/nodejsWORKDIR /app ADD package.json /app/ RUN npm install ADD . /app
EXPOSE 8000 CMD [] ENTRYPOINT ["/nodejs/bin/npm", "start"]</pre>
開發環境準備好了。現在我們可以構建容器,并確認鏡像是否可以正常運行。$ docker build -t my_nodejs_image . $ docker run -p 8000:8000 my_nodejs_image
現在可以訪問http://127.0.0.1:8000/,看看是否可以看到“Hello World”!
你可以修改app.js以讓它顯示其它的字符串。只需要重新構建鏡像,然后啟動一個新的容器,刷新瀏覽器,就能夠看到這個新的字符串。
這里的配置沒有任何測試。并不是因為覺得不需要,而是為了簡化配置,將注意力放在Docker和Mesos/Marathon上。優秀的程序員都應該知道沒有測試的話,開發項目就不能直接上生產環境。
現在進入下一步。
持續集成/交付
我們需要有一個版本控制系統和構建服務器,以在代碼提交后運行構建和測試。為此,我們使用了Jenkins,并將構建結果(artefact)發布到倉 庫。因為我們使用Docker部署,所最終的artefact就是一個Docker鏡像,push也是push到本地Docker Registry上。
為了簡化復雜度,我并沒有使用Git倉庫管理工具,比如GitLab或者GitHub。將Jenkins連接到Git服務器很簡單,這里不再贅述。如果想要在Docker上部署Git服務器,可以使用這個 鏡像。
現在,讓我們開始編寫fig.yml吧。Fig是一個編排工具,我們使用一個命令就可以將所有中心化的服務部署好。 Fig只是個開發工具,如果想要在生產環境使用,需要用更復雜的自動化工具替代它。
幾天之前,Docker發布了Docker Compose的第一個版本,它可以代替Fig。我還沒有測試它,不過應該不需要什么改變,Docker Compose就可以代替Fig了。
如下是搭建本地Docker Registry的fig.yml:
registry: image: registry environment: - STORAGE_PATH=/registry volumes: - registry-stuff:/registry ports: - "5000:5000"
這里使用的是標準的Docker Registry鏡像,并且將容器外的一個持久存儲的卷掛載到上面,因為我們需要重啟容器后還能保留構建出的鏡像。
接下來運行:
$ fig up
Docker Registry運行在http://localhost:5000。
下一步是構建鏡像并將其push到Registry上。
# Build an image $ docker build -t localhost:5000/containersol/nodejs_appPush it to the registry
$ docker push localhost:5000/containersol/nodejs_app</pre>
這時Docker Daemon會報如下錯誤:Forbidden. If this private registry supports only HTTP or HTTPS with an unknown CA certificate, please add –insecure-registry 10.0.0.26:5000 to the daemon’s arguments.
解決這個問題的方法見 StackOverflow
最快最簡單的方法是將如下行添加到/etc/default/docker,然后重啟Docker Daemon:
DOCKER_OPTS="--insecure-registry localhost:5000"
解決問題之后,將鏡像push到repo上,并訪問該 URL,檢查鏡像是否已經被成功push。
接下來添加Jenkins的配置到fig.yml文件里,重啟系統:
jenkins: image: containersol/jenkins_with_docker volumes: - jenkins-stuff:/var/jenkins_home - .:/var/jenkins_data - /var/run/docker.sock:/var/run/docker.sock - /usr/bin/docker:/usr/bin/docker ports: - "8081:8080" registry: image: registry environment: - STORAGE_PATH=/registry volumes: - registry-stuff:/registry ports: - "5000:5000"
這里詳細解釋下Jenkins配置。首先,我們在Jenkins容器里掛載了Docker二進制文件(譯者注:如上的/usr/bin/docker)和 docker daemon使用的socket。這是因為需要從容器里允許Jenkins在主機上運行Docker命令。問題是,只有Docker組里的用戶才有權這么 做,而Jenkins容器是Jenkins用戶,而不是root用戶。因此,我們使用如下Dockerfile構建我們自己的Jenkins鏡像:
FROM jenkinsMAINTAINER ContainerSolutions
USER root
TODO the group ID for docker group on my Ubuntu is 125, therefore I can only run docker commands if I have same group id inside.
Otherwise the socket file is not accessible.
RUN groupadd -g 125 docker && usermod -a -G docker jenkins USER jenkins</pre>
在Dockerfile的文件夾里運行如下命令構建鏡像:$ docker build -t containersol/jenkins_with_docker .
這并不是很巧妙的解決方案,如果你有更好的方法,一定在本文后留言告訴我。
Fig會為Jenkins容器創建持久化的存儲,并將當前目錄掛載到容器里。這在之后運行build,push并且deploy腳本時就有用了。
要想完成文本介紹的持續集成,還需要添加一些腳本來構建和push Docker鏡像,配置Jenkins來運行它們。
build.sh包含額外的鏡像版本信息。每個Jenkins build會為Docker鏡像創建新的標簽。需要注意,我并不是說這是版本化的正確方式。這個領域很復雜,可能會在以后專門寫文章討論,但是現在就跳過吧。
#!/bin/bashif [ -z "${1}" ]; then version="latest" else version="${1}" fi
cd nodejs_app docker build -t localhost:5000/containersol/nodejs_app:${version} . cd ..</pre>
注意構建出的鏡像的名字。它首先包含Registry的URL,然后是鏡像全名,然后是標簽。
還需要注意的是Jenkins在容器里運行,會使用腳本構建鏡像,但是在Jenkins容器里執行的docker命令實際上會運行在主機上,因為之前我們掛載了Docker所使用的socket。
push.sh會push之前步驟構建出的鏡像。使用和之前腳本一樣的版本。#!/bin/bashif [ -z "${1}" ]; then version="latest" else version="${1}" fi
docker push localhost:5000/containersol/nodejs_app:"${version}"</pre>
最后一步是用Fig重啟整個系統,并且配置Jenkins job運行build.sh和push.sh。Jenkins在URLhttp://localhost:8081上運行。
這是一個標準的構建job,執行兩個shell命令,build的版本是其輸入參數:./build.sh ${BUILD_ID} ./push.sh ${BUILD_ID}
現在我們可以執行構建,可以看到新的鏡像部署到了Registry里。注意URL包含新的標簽。
本文作為該系列的第一篇,講述了如何在開發機器上Docker化一個Node.js應用,并且如何為了Node.js應用部署Jenkins和Docker Registry。
第二部分會接著介紹Mesos和Marathon的搭建,以及如何完成持續集成工作流。
原文鏈接:Continuous Delivery with Docker on Mesos in less than a minute – Part 1(翻譯:崔婧雯 校對:郭蕾)
===========================
譯者介紹
崔婧雯,現就職于VMware,高級軟件工程師,負責桌面虛擬化產品的質量保證工作。曾在IBM WebSphere業務流程管理軟件擔任多年系統測試工作。對虛擬化,中間件技術有濃厚的興趣。
來自:http://dockerone.com/article/239