CI/CD 是持續集成、持續部署的意思,研發團隊的開發流程以代碼版本倉庫(VCS)爲中心,以不一樣的 branch
或 tag
進行代碼提交,以後 VCS 會觸發一系列的流水線做業,包括代碼檢查、單元測試、編譯、打包鏡像、發佈鏡像、觸發測試環境或生產環境的部署等,這一切都是自動的。研發成員只須要提交代碼到 VCS 就能夠了,免去了複雜的人力成本,提升了生產效率。html
上次咱們講了如何《經過 Docker 快速部署公司內部 GitLab》,此次來說講如何在 GitLab 的基礎上進行 CI/CD。GitLab 官方提供了 GitLab Runner 組件來與 GitLab 進行集成,他們能夠部署在同一集羣內不一樣機器上(內網進行通訊),當 GitLab 檢測到代碼提交事件,會自動觸發 Runner 執行流水線做業。mysql
咱們以上篇文章做爲本篇的上下文,進行安裝步驟和原理的講解。上一篇文章中,咱們說 GitLab 部署在了集羣內 IP 爲 192.168.31.43
的這臺機器上,那麼若是服務器資源充沛的話,最好將 Runner 部署在集羣內另一臺機器上,本文以部署在同一機器上爲例,如果與 GitLab 部署在不一樣機器,道理也是相同的,只要相互之間能夠通訊就行。git
咱們仍是經過 Docker 容器的方式來部署 Runner,所以部署 Runner 的這臺機器須要安裝有 Docker。咱們在部署 GitLab 機器的上部署 Runner,以前已經安裝了 Docker,如果部署在不一樣機器,請自行安裝。github
Docker 安裝後,執行如下命令,拉取 Runner 鏡像並啓動:golang
$ docker run -d --name gitlab-runner --restart always \ -v /path/to/gitlab-runner/config:/etc/gitlab-runner \ -v /var/run/docker.sock:/var/run/docker.sock \ gitlab/gitlab-runner:latest
咱們給運行 Runner 的這個容器起名爲 gitlab-runner
,並將 Runner 的配置目錄掛載到了宿主機,Runner 容器中的 docker.sock
與宿主機共享。Runner 在執行每一個流水線做業時都會啓動一個獨立而且隔離的 Docker 容器並在容器中執行用戶定義的腳本,經過共享 docker.sock
就可讓 Runner 經過宿主機的 Docker Engine 進行容器的拉取、啓動等操做。因 Runner 自己就運行在容器中,經過這種方式能夠避免 Docker in Docker 的問題。sql
這樣,Runner 就部署好了,Docker 容器爲咱們的應用部署帶來了極大的便利。下一步就是讓部署好的 Runner 與 GitLab 集成在一塊兒。docker
對於 GitLab 來說,Runner 有多種形式:共享 Runner、羣組 Runner、項目 Runner。共享 Runner 是 GitLab 上的全部的項目都可以使用的 Runner,羣組 Runner 是一個羣組內的項目都可以使用的 Runner。咱們這裏建議使用項目 Runner,也就是說,咱們部署的這個 Runner 只爲單獨一個 GitLab 項目服務。shell
瀏覽器打開 GitLab,進入一個項目,項目維護者(maintainer 身份) 能夠看到項目的設置選項,進入 設置 - CI/CD
:segmentfault
<img src="/img/bVbGr7y" width="50%" height="50%">數組
展開 runner 選項:
能夠看到 手動設置specific Runner
一項,而且展現了設置runner時須要輸入的gitlab url和token,經過這兩個參數去設置runner,便讓 runner 與 gitlab 創建了聯繫,同時 token 也指定了runner 只會爲這個項目服務,對於其餘項目,runner 將會不可見。接下來咱們去設置runner。
進入 runner 容器進行配置,讓其能夠與 gitlab 進行通訊,讓 gitlab 的事件能夠觸發 runner 執行任務。
docker exec -it gitlab-runner bash
進入容器後,執行命令 gitlab-runner register
進行交互式配置:
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com ) http://192.168.31.43:9080/ Please enter the gitlab-ci token for this runner xxx Please enter the gitlab-ci description for this runner [hostname] a runner just for the project: demo Please enter the gitlab-ci tags for this runner (comma separated): demo-project-runner Please enter the executor: ssh, docker+machine, docker-ssh+machine, kubernetes, docker, parallels, virtualbox, docker-ssh, shell: docker Please enter the Docker image (eg. ruby:2.6): alpine:latest
咱們逐一進行講解:
http://192.168.31.43:9080/
,runner 容器的網關是 docker0 接口,網段爲172.17.0.0/24
,屬於集羣網段192.168.31.0/24
的子網段,runner能夠向上訪問到父級網段的IP。bridge
)下,咱們能夠經過查看gitlab容器在bridge下的ip(docker inspect gitlab)來獲取到該網段的gitlab服務IP。又或者,能夠將gitlab容器和runner容器加入到同一network下,能夠直接經過容器名+端口號進行通訊,docker內部會作域名解析。原理詳見我以前的一篇文章。註冊完runner以後,再回到gitlab的項目設置頁面,查看runner,會發現此項目已激活的Runner
中有了一個剛剛註冊的runner。
至此,就完成了gitlab與runner的集成。之後,每次該項目檢測到有代碼提交以後,都會觸發runner執行流水線任務。你可能會問,runner怎麼才知道咱們須要什麼樣的流水線任務,怎麼知道本身要幹什麼?答案是不知道。咱們須要在咱們的項目根目錄中添加一個ci配置文件 .gitlab-ci.yml 來定義流水線任務的每一個階段作什麼事情執行什麼腳本,gitlab-ci 根據這個規定來讓runner作事,至於這個配置文件怎麼寫,這個放在後面來說。
可是須要注意的是,假如咱們的項目中不存在 .gitlab-ci.yml,gitlab-ci 會採用預約義的cicd配置執行流水線,因此咱們須要關閉它。
取消勾選 默認爲Auto DevOps流水線
,保存修改。
Runner
Executor
Pipline
Stage
Job
示例:
下面是一個 Go 項目的 ci 配置,流水線分爲 test 和 build 兩個階段, test job 使用 golang 鏡像做爲執行環境,build job 使用 dind 鏡像做爲執行環境來進行應用鏡像的構建和發佈。
咱們以這個配置爲例,來進行流水線構建優化工做的講解。
stages: - test - build test_job: stage: test image: golang:1.14.2 tags: - demo services: - name: mysql:8.0.17 alias: mysql command: ['--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci'] variables: MYSQL_HOST: mysql MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: test before_script: - go env -w GO111MODULE=on - go env -w GOPROXY=https://goproxy.cn,direct script: - go vet ./... - go test -v -race ./... build_job: stage: build image: docker:latest services: - docker:dind variables: DOCKER_DRIVER: overlay2 DOCKER_TLS_CERTDIR: '' script: - docker build -t goapp:latest . - docker login -u $DOCKER_REGISTRY_USERNAME -p $DOCKER_REGISTRY_PASSWORD $DOCKER_REGISTRY_ADDR - docker tag goapp:latest ${DOCKER_REGISTRY_ADDR}/xvrzhao/goapp:latest - docker push ${DOCKER_REGISTRY_ADDR}/xvrzhao/goapp:latest tags: - demo only: - master
[runners.docker]
欄中 privileged
爲 true。Runner 默認狀況下每執行一個job都會從新拉取一次所需鏡像,咱們能夠經過修改策略,鏡像不存在時纔會拉取。
編輯 config.toml 文件,在 [runners.docker]
一欄加入一行:
pull_policy = "if-not-present"
而後,重啓runner容器:
docker restart gitlab-runner
當 Runner 在每次流水線執行到 build job 時,都須要啓動一個全新的 dind 鏡像,在 dind 容器內部進行構建操做(docker build),因此構建過程當中所產生的中間鏡像緩存在下次構建時並使用不到,由於壓根就是兩個不一樣的 dind 容器。
因此咱們須要讓 runner 中的 docker.sock 掛載到每一個建立的容器中,這樣,在 dind 中每次執行 docker 命令時,實際上是在與外部的docker daemon進行通訊,也就是至關因而使用的 runner 中的docker,而 runner 又是掛載的宿主機的docker.sock,因此 dind 容器中的 docker 命令是在間接地使用宿主機的 docker daemon。這樣,就算不一樣的 dind 容器也能夠共享中間鏡像緩存了,由於中間鏡像是產生在宿主機的。
修改方式一樣是編輯 config.toml 文件,[runners.docker]
欄中 volumns 數組中添加一項 "/var/run/docker.sock:/var/run/docker.sock"
,並重啓 runner 容器生效。