首先啟動(dòng)一個(gè)gitlab runner服務(wù)蘑险,并注冊(cè)一個(gè)docker executor滴肿,這是比較簡(jiǎn)單的,此處暫不贅述
本文主要講述使用docker executor佃迄,如何處理緩存泼差,工件,構(gòu)建docker鏡像的問(wèn)題呵俏,如何盡可能在保證安全的前提下加速編譯過(guò)程堆缘。
以java項(xiàng)目為例,配置ci/cd文件
stages:
- package
- build
variables:
MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
mvn:package:
stage: package
tags:
- gr1
image: maven:3.6.3-jdk-8
#緩存mvn庫(kù)
cache:
key: mvn_repo
paths:
- .m2/repository
artifacts:
paths:
- target/multi-renter.jar
script:
- mvn package
緩存:
cache:
key:mvn_repo
paths:
- .m2/repository
這是指定一個(gè)緩存普碎,在當(dāng)前的gr1這個(gè)runner中的任何job中有效吼肥,緩存會(huì)保存在主機(jī)的另一個(gè)docker container(dockers ps -a 可以看到 gitlab runner helper),并最終掛在到主機(jī)的一個(gè)位置麻车。為什么不直接掛載到主機(jī)上呢缀皱,那樣效率不是更高嗎?當(dāng)然动猬,直接掛載到主機(jī)上啤斗,效率更高,但是卻讓當(dāng)前的job和主機(jī)的某個(gè)目錄耦合赁咙,試想钮莲,如果其他人的job也往主機(jī)掛載,并且恰好掛載到和你一樣的目錄了呢彼水?另外崔拥,不同的主機(jī)類(lèi)型,比如windows和linux猿涨,目錄格式不一樣握童,因此你的配置要根據(jù)主機(jī)os類(lèi)型而變化。而且你還要關(guān)注gitlab-runner服務(wù)可讀寫(xiě)的目錄權(quán)限問(wèn)題叛赚。wow澡绩,真是太復(fù)雜了。但是掛載到另一個(gè)容器俺附,gitlab-runner幫你解決了所有的問(wèn)題肥卡。只是犧牲了一點(diǎn)點(diǎn)效率。無(wú)非就是增加了壓縮和解壓緩存的時(shí)間事镣。緩存在所屬的gitlab-runner(上述例子中所屬為:gr1)后續(xù)的所有pipeline可見(jiàn)步鉴。
工件:
artifacts:
paths:
- target/multi-renter.jar
工件和緩存類(lèi)似,只不過(guò)其往往在一個(gè)pipeline中生存工件的后續(xù)job中可見(jiàn)。在web ui中也可見(jiàn)氛琢,但是在另一個(gè)pipeline中不可見(jiàn)喊递。比如,我在mvn:package:這個(gè)job中編譯了一個(gè)jar文件阳似,在編譯的下一個(gè)stage中想把這個(gè)jar復(fù)制到docker鏡像骚勘,就應(yīng)該用工件去傳遞這個(gè)jar,而不是使用緩存撮奏。
構(gòu)建docker image
構(gòu)建docker鏡像俏讹,官方給了幾種方式
對(duì)于docker executor,每次都是啟動(dòng)一個(gè)新的container構(gòu)建畜吊,新的container是一個(gè)非常clear的環(huán)境泽疆,因此上次構(gòu)建使用到的base image和構(gòu)建的緩存都無(wú)法使用,所以閱讀下述方式時(shí)玲献,重點(diǎn)關(guān)注如何加速構(gòu)建速度殉疼,解決方式是否復(fù)雜以及帶來(lái)的問(wèn)題。
kaniko
kaniko可以在不使用docker特權(quán)模式下構(gòu)建docker鏡像青自,并且可以利用container registry加速構(gòu)建株依。主要過(guò)程如下
- kaniko在--cache-dir目錄下查找base image緩存(即docker file中的from命令)這里需要注意,如果這里沒(méi)有命中延窜,kaniko會(huì)去download image,但是不會(huì)寫(xiě)入緩存抹锄,因此逆瑞,即使你通過(guò)卷持久化了這個(gè)目錄,下次執(zhí)行依然不會(huì)命中伙单。因此我們需要提前將鏡像緩存到--cache-dir获高,kanico關(guān)于cache base image的講解。我使用了一下warmer吻育,發(fā)現(xiàn)按照官網(wǎng)提供的命令念秧,不加-f,如果緩存沒(méi)命中布疼,shell返回0摊趾,但實(shí)際報(bào)錯(cuò)了,加上-v debug可以看到游两,如果緩存命中了砾层,什么都不發(fā)生。加上-f贱案,則每次都會(huì)強(qiáng)制pull鏡像覆蓋cache肛炮,消耗一定時(shí)間。這可能是一個(gè)bug。我們要做的就是侨糟,先使用warmer下載base image碍扔,然后把緩存的目錄掛載到kanico容器中使用(配置/srv/gitlab-runner/config/config.toml文件)。我只是想編譯而已秕重,為何要我解決如此麻煩的緩存問(wèn)題不同?另外注意一下,kanico的executor和warmer都有相同名稱(chēng)的參數(shù)悲幅,所以這里需要自己體會(huì)下其含義套鹅,不要搞混了。
- kaniko對(duì)run命令進(jìn)行緩存汰具,因此執(zhí)行run命令前卓鹿,會(huì)到指定的遠(yuǎn)程registry查看有沒(méi)有已經(jīng)緩存的層,命中的話(huà)就使用緩存
- kaniko將構(gòu)建好的image提交到registry
這是個(gè)好東西留荔,我簡(jiǎn)單試用了一下吟孙,官方給的示例多是k8s中用,如果不在k8s中用聚蝶,如何緩存base image是一個(gè)問(wèn)題杰妓,我暫時(shí)還沒(méi)有在官方找到一個(gè)比較好的方式。
kaniko拉取base image方式和docker pull不一樣碘勉,測(cè)試使用warmer緩存java:8和使用docker pull java:8一個(gè)耗時(shí)不到一分鐘巷挥,一個(gè)約3分鐘。
docker:build:
stage: build
tags:
- gr1
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
script:
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG --insecure
docker in docker
這種方式需要以特權(quán)方式執(zhí)行docker验靡,帶來(lái)不安全的因素倍宾。同時(shí),構(gòu)建也是非常慢的胜嗓。因此也需要使用緩存去加速構(gòu)建高职。原理是:docker先從registry拉取上次構(gòu)建的鏡像。然后構(gòu)建的時(shí)候指定--cache-from=<last-image>辞州,也就是說(shuō)以上次的鏡像作為緩存構(gòu)建怔锌。構(gòu)建完畢后,上次鏡像变过,作為下次的構(gòu)建緩存使用埃元。但是需要注意的是,仍需要花費(fèi)一部分時(shí)間在download image上牵啦。如果registry在內(nèi)網(wǎng)亚情,其實(shí)下載和上傳都是蠻快的,可以接受哈雏。
docker:build:
stage: build
tags:
- gr1
image: docker:19.03.1
services:
- name: docker:19.03.1-dind
command: ['--insecure-registry=your.registry.com:port']
variables:
# Use TLS https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#tls-enabled
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ""
#DOCKER_TLS_CERTDIR: "/certs"
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker pull $CI_REGISTRY_IMAGE:latest || true
- docker build --cache-from $CI_REGISTRY_IMAGE:latest --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --tag $CI_REGISTRY_IMAGE:latest --build-arg JAR_FILE=target/*.jar .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker push $CI_REGISTRY_IMAGE:latest
DOCKER_HOST的配置參見(jiàn)docker dockerhub楞件,主要注意一下證書(shū)如果配置了衫生,端口號(hào)會(huì)是2376,否則是2375土浸。
如果使用了不安全的registry罪针,那么需要指定command: ['--insecure-registry=your.registry.com:port']
docker socket binding
由于此方式最終實(shí)際上是使用的host的docker daemon,因此黄伊,鏡像和構(gòu)建的緩存都是直接使用host中的緩存泪酱。當(dāng)然,有利就有弊还最,此種方式的缺點(diǎn)有:
- 由于共享了主機(jī)的docker socket墓阀,所以docker命令都是向主機(jī)發(fā)出的命令,比如docker rm -f $(docker ps -a -q)會(huì)把主機(jī)上的所有docker容器刪除了拓轻,包括gitlab-runner容器斯撮。
- 并發(fā)工作可能無(wú)法正常執(zhí)行;創(chuàng)建具有特定名稱(chēng)的容器扶叉,則它們可能會(huì)相互沖突勿锅。
- 將源倉(cāng)庫(kù)中的文件和目錄共享到容器中可能無(wú)法正常工作,因?yàn)榫戆惭b是在主機(jī)而不是構(gòu)建容器的上下文中完成的枣氧。
你必須時(shí)刻注意溢十,你的docker命令是在主機(jī)執(zhí)行的,而不是容器內(nèi)部达吞。 - 需要修改gitlab-runner的配置张弛,掛載主機(jī)的docker socket,但是不同的host system的sock文件路徑不同酪劫,這目前只能在host上配置乌庶。
- 在k8s中迹恐,docker binding脫離了k8s的控制丹喻,是非常危險(xiǎn)的行為犀盟。有的k8s集群通過(guò)名稱(chēng)空間做環(huán)境隔離,想想一下搪桂,開(kāi)發(fā)環(huán)境的docker命令刪除了線(xiàn)上環(huán)境的容器。
如何綁定docker.sock?
修改gitlab-runner服務(wù)的配置文件 /srv/gitlab-runner/config/config.toml
volumes = ["/cache","/var/run/docker.sock:/var/run/docker.sock"]
[[runners]]
name = "gr1"
url = "http://gitlab.lbl.com"
token = "mJJWevdY42sJQ84syyN9"
executor = "docker"
[runners.custom_build_dir]
[runners.docker]
tls_verify = false
image = "ruby:2.6"
privileged = true
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/cache","/var/run/docker.sock:/var/run/docker.sock"]
shm_size = 0
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
ci/cd文件配置
docker:build:
stage: build
tags:
- gr1
image:
name: docker:19.03.1
# before_script:
#登錄到gitlab集成的注冊(cè)表
# - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --tag $CI_REGISTRY_IMAGE:latest --build-arg JAR_FILE=target/*.jar .
#推送到gitlab集成的注冊(cè)表
# - docker push $CI_REGISTRY_IMAGE:latest
接下來(lái)盯滚,讓我們看看踢械,如果使用k8s執(zhí)行器。