運(yùn)行Jenkins有多種方法,有l(wèi)inux/windows安裝包项玛,有war包自行發(fā)布到Servlet容器(例如Tomcat)貌笨,最簡單干凈的就是在容器中運(yùn)行,運(yùn)行結(jié)束jenkins直接刪除容器襟沮,不留垃圾锥惋。本文記錄一次體驗(yàn):通過容器運(yùn)行Jenkins昌腰,并在其中啟動容器節(jié)點(diǎn)完成構(gòu)建步驟。其中一些踩坑經(jīng)歷膀跌,相信值得借鑒遭商。本文實(shí)驗(yàn)基于Ubuntu 16.04 LTS , Docker 17.06.0-ce捅伤,docker-compose 1.8
讓容器運(yùn)行起來
編寫docker-compose.yml劫流,內(nèi)容如下
version: '2'
services:
web:
image: 'jenkins:alpine'
restart: unless-stopped
environment:
TZ: 'Asia/Shanghai'
ports:
- '8080:8080'
- '50000:50000'
volumes:
- './jks_home:/var/jenkins_home'
用sudo docker-compose up -d
運(yùn)行,結(jié)果如下
用
sudo docker-compose logs
查看啟動log丛忆,發(fā)現(xiàn)錯誤提示沒有權(quán)限寫祠汇,如下原因是,在docker-compose.yml中熄诡,做了數(shù)據(jù)卷綁定
- './jks_home:/var/jenkins_home'
可很,我們用sudo運(yùn)行容器,運(yùn)行時(shí)會自動創(chuàng)建jks_home凰浮,因?yàn)槭莝udo我抠,所有者和組都是root,而jenkins容器內(nèi)部運(yùn)行用戶是jenkins(uid:1000,gid:1000,參考Jekins Alpine Dockfile定義),因此當(dāng)然沒有權(quán)限往jks_home里寫了导坟。趕緊的
sudo chown simon:simon jks_home/
繼續(xù)觀察log屿良,終于看到
為什么把jks_home的所有者和組改成simon:simon就可以了呢?上面我們提到j(luò)enkins容器內(nèi)的運(yùn)行用戶jenkins的uid和gid是1000惫周,而simon的uid和gid也是1000尘惧,因此容器運(yùn)行時(shí),從主機(jī)看就是以simon在運(yùn)行递递,容器不過就是主機(jī)的一個進(jìn)程而已與其他在主機(jī)啟動進(jìn)程并無區(qū)別喷橙,只是為了實(shí)現(xiàn)隔離(名稱和資源),運(yùn)行了很多服務(wù)進(jìn)程登舞,對在Docker空間運(yùn)行進(jìn)程實(shí)施控制贰逾,不是很多介紹文章簡單認(rèn)為是輕量級虛擬機(jī)。
ps -aux | grep jenkins
瀏覽器打開http://192.168.1.101:8080/
按照畫面提示找到密碼,因?yàn)槲覀兪侨萜鬟\(yùn)行菠秒,所以
sudo docker-compose exec web cat /var/jenkins_home/secrets/initialAdminPassword
copy密碼疙剑,貼到瀏覽器里藐窄,繼續(xù)竟趾,后續(xù)按照畫面提示安裝插件(筆者按照suggested的安裝),創(chuàng)建用戶等步驟导而,就不一一貼畫面了禁灼。
最終管挟,創(chuàng)建了一個名為pydocker的pipeline project,如下圖
沒有其他配置弄捕,只是添加了測試啟動Docker Slave的pipeline script
pipeline{
agent {
docker {
image 'ubuntu'
}
}
stages {
stage('Build') {
steps {
sh 'uname -a'
echo 'Building..'
}
}
stage('Test') {
steps {
echo 'Testing..'
}
}
stage('Deploy') {
steps {
echo 'Deploying....'
}
}
}
}
要運(yùn)行Docker命令僻孝,還需要在jenkins所在容器安裝docker客戶端导帝,否則構(gòu)建會出現(xiàn) docker: not found
錯誤。另外docker客戶端與服務(wù)器通訊支持2種協(xié)議穿铆,tcp和unix domain socket您单,后者只限于服務(wù)器在本地的情況,客戶端和服務(wù)器通過共同訪問一個本地socket文件來通訊悴务,如docker用的socket文件默認(rèn)位置就是/var/run/docker.sock
睹限。好了譬猫,接下來我們就利用docker的volume mount來直接利用主機(jī)上的docker客戶端和sock文件讯檐,示意圖如下
更新后的docker-compose.yml如下
version: '2'
services:
web:
image: 'jenkins:alpine'
restart: unless-stopped
environment:
TZ: 'Asia/Shanghai'
ports:
- '8080:8080'
- '50000:50000'
volumes:
- './jks_home:/var/jenkins_home'
- '/var/run/docker.sock:/var/run/docker.sock'
- '/usr/bin/docker:/usr/bin/docker'
這里又有一個坑,如果你是通過apt安裝的docker的話染服,依然提示
docker: not found
錯誤,原因是apt安裝的docker采用的是動態(tài)鏈接編譯的别洪,還依賴其他的so文件,而你沒有mount到容器柳刮,所以找不到相應(yīng)文件挖垛,這里有討論。解決辦法是安裝靜態(tài)編譯的docker秉颗。
好了痢毒,接著重啟容器sudo docker-compose down && sudo docker-compose up -d
,再次在jenkins畫面點(diǎn)擊立即構(gòu)建蚕甥,咦哪替,還是出錯
怎么回事呢,原來jenkins容器里的docker客戶端通信要訪問docker.sock文件卻沒有權(quán)限
當(dāng)前用戶是jenkins,不在ping組(gid:999)里菇怀,所有的坑都是因?yàn)閖enkins容器的運(yùn)行用戶時(shí)jenkins(uid:1000)造成的凭舶,而其他容器化應(yīng)用,基本都是以root運(yùn)行的爱沟。
因?yàn)閖enkins可以安裝插件帅霜,猜測作者是擔(dān)心插件不安全,所以用普通用戶吧
這篇文章做法是新生成容器鏡像呼伸,授予jenkins超級用戶權(quán)限身冀,不知道這同直接用root用戶運(yùn)行jenkins有何區(qū)別,反正都不安全括享,測試么搂根,粗糙的編寫下面的Dockerfile
FROM jenkins:alpine
USER root
生成鏡像sudo docker build --rm -t jks .
改用jks鏡像,docker-compose.yml如下
version: '2'
services:
web:
image: 'jks'
restart: unless-stopped
environment:
TZ: 'Asia/Shanghai'
ports:
- '8080:8080'
- '50000:50000'
volumes:
- './jks_home:/var/jenkins_home'
- '/var/run/docker.sock:/var/run/docker.sock'
- '/usr/bin/docker:/usr/bin/docker'
重啟jenkins容器sudo docker-compose down && sudo docker-compose up -d
,再次在jenkins畫面點(diǎn)擊立即構(gòu)建奶浦,
Finished: SUCCESS
兄墅,啊,終于跑起來了澳叉。
總結(jié)
用容器運(yùn)行jenkins隙咸,方便快捷沐悦,但是因?yàn)殓R像用戶是jenkins,造成了很多不便五督,但是精細(xì)化控制和易用性總是需要平衡的藏否,目前似乎還沒有優(yōu)雅方案在容器中運(yùn)行容器。另外充包,在Docker Cloud服務(wù)越來越流行背景之下副签,jenkins調(diào)用容器命令,把鏡像發(fā)布到docker cloud中運(yùn)行基矮,方便實(shí)現(xiàn)Continuous Delivery淆储。
參考
Running Docker in Jenkins (in Docker)
uid=1000. gid=1000. why 1000?
Continuous Delivery with Docker on Mesos in less than a minute