持續交付系列(一):使用Docker、Mesos實現持續交付

jopen 9年前發布 | 60K 次閱讀 Docker

本文主要講述如何為Node.js應用搭建持續集成環境。包括如何在開發機器上Docker化一個Node.js應用,如何部署Jenkins和 Docker registry以實現持續集成。推薦對使用Docker做CI方面的工作感興趣的同學閱讀,CI也是Docker的應用場景之一,本文是很好的教程。

你首先需要在你的Linux機器上安裝Docker和Fig。本文主要會介紹如何使用Docker和Mesos實現持續集成。

測試、搭建生產環境可用的Mesos集群以及其它的復雜工作不在本文討論范圍之內,我會在后續文章中詳細介紹。接下來,我們將在更多的云平臺上支持該解決方案,比如GCE、AWS,并逐漸集成更多的第三方組件,比如 FlockerWeaveConsul

本文所有的代碼都可以在 GitHub上找到。

整個解決方案中,我們使用到如下工具:

  • Node.js里的HelloWorld項目
  • Git
  • Jenkins
  • Docker
  • Docker Registry
  • Fig
  • Mesos
  • Mesosphere Marathon
  • Zookeeper

開發環境

讓我們先從一個簡單的HelloWorld先用開始吧,它使用Node.js編寫,并且運行在Docker容器中。

從下圖中,你可以看到開發人員在本地環境中使用容器運行構建、測試以及其它流程,如下圖淡藍色方塊所示。一旦測試通過,他們將會把代碼提交到中央Git倉庫,接下來會發布到生產環境。

 持續交付系列(一):使用Docker、Mesos實現持續交付

我假定閱讀這篇文章的讀者都能理解并且自己實現這一步。

首先是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/nodejs

WORKDIR /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實現持續交付

這里的配置沒有任何測試。并不是因為覺得不需要,而是為了簡化配置,將注意力放在Docker和Mesos/Marathon上。優秀的程序員都應該知道沒有測試的話,開發項目就不能直接上生產環境。

現在進入下一步。

持續集成/交付

 持續交付系列(一):使用Docker、Mesos實現持續交付

我們需要有一個版本控制系統和構建服務器,以在代碼提交后運行構建和測試。為此,我們使用了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_app

 Push 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。

 持續交付系列(一):使用Docker、Mesos實現持續交付

接下來添加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 jenkins

MAINTAINER 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/bash

if [ -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/bash

if [ -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}

 持續交付系列(一):使用Docker、Mesos實現持續交付

現在我們可以執行構建,可以看到新的鏡像部署到了Registry里。注意URL包含新的標簽。

 持續交付系列(一):使用Docker、Mesos實現持續交付

本文作為該系列的第一篇,講述了如何在開發機器上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

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!