筆者個人理解:gitlab-runner 安裝後就是一個監聽狀態的 runner,而透過 gitlab-runner register
註冊的“例項”其實只是預定義的配置節,當訊息抵達後,gitlab-runner 根據訊息內容選擇相應的配置節啟動執行執行緒。為了方便闡述和理解,本文也將每個配置節/執行執行緒
稱為 runner 例項
。
runner executor
runner 例項的執行環境,一般用的較多的是 shell
和 docker
,這兩者的區別無需贅述。
讓人困惑的是其它一些 executor
:比如 Docker-SSH
和 Docker-SSH+machine
(從 GitLab Runner 10.0 開始, Docker-SSH 和 Docker-SSH+machine executors 被廢棄了,並且將在後續某個版本中移除);還有 Docker machine
,這個概念原本是 Docker 提出的,但是後面被 Docker 棄用了,GitLab 為了向前相容保留了下來,也可以不用細究。
對於 docker executor 來說,runner 執行 job 的流程如下(摘自官網):
- The runner starts a Docker container using the defined entrypoint. The default from Dockerfile that may be overridden in the .gitlab-ci.yml file.
- The runner attaches itself to a running container.
- The runner prepares a script (the combination of before_script, script, and after_script).
- The runner sends the script to the container’s shell stdin and receives the output.
顯然,第 1 步要啟動容器,如果 runner 本身是以 docker 容器方式安裝執行的,那麼就涉及到 Docker-in-Docker
的概念了。
Docker-in-Docker
有些時候,我們需要在容器內部執行 docker 指令,一般有兩種方式:
- 掛載宿主機 docker 環境。啟動容器時掛載
/var/run/docker.sock
,這樣在容器內執行 docker 指令其實就等同於在容器外(宿主機中)執行 docker 指令。比如docker build
構建一個映象,該映象並不存在於容器內部,而是在宿主機中。所以該方法並不是嚴格意義上的docker in docker
。 - 容器內部有自己的一套 docker 環境。使用
docker:dind
映象,可以直接使用它作為主容器,或是作為其它容器的服務容器(其它容器與之通訊)。它在docker
映象(該映象只包含客戶端指令集)基礎上安裝了Docker Daemon
,因此可作為獨立的 docker 環境使用,是真正意義上的docker in docker
。然而,除非你真正需要在容器內巢狀容器,或者某些場景下無法使用第 1 種方式,否則還是建議避免使用該方式。
這兩種方式需要執行指令的容器處於 privileged mode
,有一定的安全風險(privileged=true
將使得容器內 root 擁有宿主 root 的許可權,否則只是宿主機上的普通使用者),因此市面上又出現了一種 Using Nestybox sysbox Docker runtime
的方法,感興趣的朋友請查閱參考資料,此處按過不表。
in gitlab-runner
如前所述,以 docker 方式安裝 runner,且 executor 採用 docker,那麼就要 Docker-in-Docker
。因為 runner 只是啟動新容器,不要求啟動的容器在 runner 容器內部,我們可以採用第 1 種方式,如下:
docker run -d --name gitlab-runner --restart always \
-v /srv/gitlab-runner/config:/etc/gitlab-runner \
-v /var/run/docker.sock:/var/run/docker.sock \ # 掛載 socket
gitlab/gitlab-runner:latest
另外,如果 docker executor 在 CI/CD job 中涉及到 docker 指令,那麼也要 Docker-in-Docker
。關鍵步驟如下:
- 註冊 runner 例項,並配置其啟動的容器為 privileged mode(注意配置的是每次
job
執行時啟動的容器,而 runner 所在的容器,且 runner 並不一定是 docker 形式)。
sudo gitlab-runner register -n \
--executor docker \
--docker-image "docker:20.10.16" \
--docker-privileged \ # privileged mode
--other arguments
- 接下來,可以選擇任一種方式實現 Docker-in-Docker:
- 在
config.toml
中增加捲對映volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"]
。 - 或者在
.gitlab-ci.yml
中指定docker:dind
如:
services: - docker:20.10.16-dind
- 在
TLS 配置
如果在第 2 步採用 docker:dind
方式,那麼由於涉及到容器間通訊,需要選擇是否啟用 TLS。
若是,則在註冊 runner 例項時,增加一個引數 --docker-volumes "/certs/client"
, 也可手動編輯 config.toml
,增加捲對映 volumes = ["/certs/client", "/cache"]
;然後在 .gitlab-ci.yml
中設定變數 DOCKER_TLS_CERTDIR: "/certs"
。
若否,則在 .gitlab-ci.yml
中設定變數 DOCKER_TLS_CERTDIR: ""
和 DOCKER_HOST: tcp://docker:2375
。
TLS 若未正確配置,會報 Cannot connect to the Docker daemon at tcp://docker:2375. Is the docker daemon running?
錯誤。