經過 GitLab Runner 實現 CI/CD 工做流

介紹

CI/CD 是持續集成、持續部署的意思,研發團隊的開發流程以代碼版本倉庫(VCS)爲中心,以不一樣的 branchtag 進行代碼提交,以後 VCS 會觸發一系列的流水線做業,包括代碼檢查、單元測試、編譯、打包鏡像、發佈鏡像、觸發測試環境或生產環境的部署等,這一切都是自動的。研發成員只須要提交代碼到 VCS 就能夠了,免去了複雜的人力成本,提升了生產效率。html

上次咱們講了如何《經過 Docker 快速部署公司內部 GitLab》,此次來說講如何在 GitLab 的基礎上進行 CI/CD。GitLab 官方提供了 GitLab Runner 組件來與 GitLab 進行集成,他們能夠部署在同一集羣內不一樣機器上(內網進行通訊),當 GitLab 檢測到代碼提交事件,會自動觸發 Runner 執行流水線做業。mysql

部署 Gitlab Runner

咱們以上篇文章做爲本篇的上下文,進行安裝步驟和原理的講解。上一篇文章中,咱們說 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

配置 Runner

對於 GitLab 來說,Runner 有多種形式:共享 Runner、羣組 Runner、項目 Runner。共享 Runner 是 GitLab 上的全部的項目都可以使用的 Runner,羣組 Runner 是一個羣組內的項目都可以使用的 Runner。咱們這裏建議使用項目 Runner,也就是說,咱們部署的這個 Runner 只爲單獨一個 GitLab 項目服務。shell

瀏覽器打開 GitLab,進入一個項目,項目維護者(maintainer 身份) 能夠看到項目的設置選項,進入 設置 - CI/CDsegmentfault

image.png

<img src="/img/bVbGr7y" width="50%" height="50%">數組

展開 runner 選項:

image.png

能夠看到 手動設置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

咱們逐一進行講解:

  1. 輸入gitlab的http服務地址,進行註冊。
    對於將gitlab和runner部署在不一樣機器的狀況來說,這個ip應該是集羣內可訪問gitlab的地址,好比 http://192.168.31.43:9080/,runner 容器的網關是 docker0 接口,網段爲172.17.0.0/24,屬於集羣網段192.168.31.0/24的子網段,runner能夠向上訪問到父級網段的IP。
    但對於部署在同一臺機器上的狀況來說,經過集羣IP訪問本機上的服務就有些繞了,但runner又不能夠經過localhost:9080來訪問,由於localhost:9080服務是對於宿主機而言的,runner容器內9080端口沒有服務。咱們在docker上啓動容器時,若不指定network,默認網關都是宿主機的docker0接口,都是在同一網段(bridge)下,咱們能夠經過查看gitlab容器在bridge下的ip(docker inspect gitlab)來獲取到該網段的gitlab服務IP。又或者,能夠將gitlab容器和runner容器加入到同一network下,能夠直接經過容器名+端口號進行通訊,docker內部會作域名解析。原理詳見我以前的一篇文章。
  2. 輸入項目token來與項目進行綁定。
  3. 輸入這個runner的描述文字。
  4. 輸入這個runner的標籤,多個標籤用英文逗號分隔,這個標籤會在之後寫ci文件時用到,用來指定一個job讓哪一個runner來執行。
  5. 選擇執行器,咱們這裏選擇docker。也就是說對於每一個job(你可能還不清楚什麼是job,咱們會在下一節進行講解,這裏你先理解成runner執行任務時的每一個階段)runner 都會分配一個獨立並隔離的docker容器環境進行job的執行。固然,你也能夠選擇使用其餘的執行器,好比shell,一樣的道理,每一個job都會分配一個獨立的shell環境來執行。
  6. 輸入docker默認鏡像。當ci文件中沒有指定一個job所使用的容器鏡像(也就是上面提到的job執行環境)時,就會使用這個默認的鏡像做爲執行環境。

註冊完runner以後,再回到gitlab的項目設置頁面,查看runner,會發現此項目已激活的Runner中有了一個剛剛註冊的runner。

至此,就完成了gitlab與runner的集成。之後,每次該項目檢測到有代碼提交以後,都會觸發runner執行流水線任務。你可能會問,runner怎麼才知道咱們須要什麼樣的流水線任務,怎麼知道本身要幹什麼?答案是不知道。咱們須要在咱們的項目根目錄中添加一個ci配置文件 .gitlab-ci.yml 來定義流水線任務的每一個階段作什麼事情執行什麼腳本,gitlab-ci 根據這個規定來讓runner作事,至於這個配置文件怎麼寫,這個放在後面來說。

可是須要注意的是,假如咱們的項目中不存在 .gitlab-ci.yml,gitlab-ci 會採用預約義的cicd配置執行流水線,因此咱們須要關閉它。

關閉默認流水線

image.png

取消勾選 默認爲Auto DevOps流水線,保存修改。

GitLab-CI 中的基本概念

  • Runner

    • 配合 gitlab 執行 ci 任務,是實際執行 ci 任務的進程,並將執行結果返回給 gitlab。通常一個項目分配一個 Runner,但也能夠多個項目共享一個 Runner。
  • Executor

    • 執行器,有多種選擇,如:docker、shell等,決定 Runner 以什麼環境執行做業,一個 Runner 對應一個 Executor。
  • Pipline

    • 流水線,流水線表明項目 cicd 的整個流程,分爲多個階段 stages(在 .gitlab-ci.yml 中本身規定)。
  • Stage

    • 階段,一個 Pipline 對應多個階段。
  • Job

    • cicd 中最小的執行單元,一個 stage 對應多個 jobs。

示例:

image.png

優化工做

下面是一個 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

使用 dind 注意事項

  1. 若要使用 docker:dind 鏡像執行job,則須要 Runner 開啓特權模式,不然可能會報錯。進入到掛載到宿主機的runner配置目錄,編輯 config.toml 文件,修改 [runners.docker]欄中 privileged 爲 true。
  2. 注意使用dind鏡像做爲job執行環境時配置文件的寫法,image使用docker:latest, services 使用 docker:dind,而且要聲明兩個變量 DOCKER_DRIVER: overlay2 和 DOCKER_TLS_CERTDIR: '',不然會出現問題(待驗證,以後只聲明瞭image: docker:latest,並無聲明 services 和 variables,貌似也經過了)。

修改鏡像拉取策略

Runner 默認狀況下每執行一個job都會從新拉取一次所需鏡像,咱們能夠經過修改策略,鏡像不存在時纔會拉取。
編輯 config.toml 文件,在 [runners.docker] 一欄加入一行:

pull_policy = "if-not-present"

而後,重啓runner容器:

docker restart gitlab-runner

掛載 job 容器的 docker.sock

當 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 容器也能夠共享中間鏡像緩存了,由於中間鏡像是產生在宿主機的。

WX20200426-093758@2x.png

修改方式一樣是編輯 config.toml 文件,[runners.docker] 欄中 volumns 數組中添加一項 "/var/run/docker.sock:/var/run/docker.sock",並重啓 runner 容器生效。

參考連接

相關文章
相關標籤/搜索