在介紹.gitlab-ci.yml以前,咱們先看幾個概念:node
通常來講,構建任務都會佔用不少的系統資源 (譬如編譯代碼),而 GitLab CI
又是 GitLab
的一部分,若是由 GitLab CI
來運行構建任務的話,在執行構建任務的時候,GitLab
的性能會大幅降低。git
GitLab CI
最大的做用是管理各個項目的構建狀態,所以,運行構建任務這種浪費資源的事情就交給 GitLab Runner
來作啦。由於 GitLab Runner
能夠安裝到不一樣的機器上,因此在構建任務運行期間並不會影響到 GitLab
的性能。web
GitLab Runner
的安裝特別簡單,官網有各平臺的安裝方法或安裝包,此處再也不贅述。正則表達式
GitLab
中的項目頁面,在項目設置中找到 runners
runner
運行的機器上,用命令行註冊,好比:gitlab-runner register --name="XX" --url="https://git.xx.com/" --token="XXX" --executor="shell"redis
按照提示一步一步安裝就能夠了。其中,executor
能夠是多種類型,簡單的話能夠選shell
。有熟悉docker
的可使用docker
。docker
配置文件在/etc/gitlab-runner/config.toml
shell
配置項相似下面,可能須要手動添加builds_dir
和cache_dir
這兩個變量,再重啓服務npm
[[runners]] name = "216XX" url = "https://git.XX.com/" token = "XX" executor = "shell" builds_dir = "/home/gitlab-runner/builds" cache_dir = "/home/gitlab-runner/cache" [runners.cache]
sudo gitlab-runner list 查看各個 Runner 的狀態 sudo gitlab-runner stop 中止服務 sudo gitlab-runner start 啓動服務 sudo gitlab-runner restart 重啓服務
Stages
表示構建階段,說白了就是上面提到的流程。默認有3個stages
:build
, test
, deploy
。咱們能夠在一次 Pipeline
中定義多個 Stages
,這些 Stages
會有如下特色:windows
Stages
會按照順序運行,即當一個 Stage
完成後,下一個 Stage
纔會開始Stages
完成後,該構建任務 (Pipeline) 纔會成功Stage
失敗,那麼後面的 Stages
不會執行,該構建任務 (Pipeline) 失敗Jobs
表示構建工做,表示某個 Stage
裏面執行的工做。咱們能夠在 Stages
裏面定義多個 Jobs
,這些 Jobs 會有如下特色:緩存
一、相同 Stage
中的 Jobs
會並行執行
二、相同 Stage
中的 Jobs
都執行成功時,該 Stage
纔會成功
三、若是任何一個 Job
失敗,那麼該 Stage
失敗,即該構建任務 (Pipeline) 失敗
.gitlab-ci.yml
用來配置 CI
用你的項目中作哪些操做,這個文件位於倉庫的根目錄。
當有新內容push
到倉庫,或者有代碼合併後,GitLab
會查找是否有.gitlab-ci.yml
文件,若是文件存在,Runners
將會根據該文件的內容開始build
本次commit
。
.gitlab-ci.yml
使用YAML
語法, 你須要格外注意縮進格式,要用空格來縮進,不能用tabs
來縮進。
任務中必須得有script
部分。
# 定義 stages(階段)。任務將按此順序執行。 stages: - build - test - deploy # 定義 job(任務) job1: stage: test tags: - XX #只有標籤爲XX的runner纔會執行這個任務 only: - dev #只有dev分支提交代碼纔會執行這個任務。也能夠是分支名稱或觸發器名稱 - /^future-.*$/ #正則表達式,只有future-開頭的分支纔會執行 script: - echo "I am job1" - echo "I am in test stage" # 定義 job job2: stage: test #若是此處沒有定義stage,其默認也是test only: - master #只有master分支提交代碼纔會執行這個任務 script: - echo "I am job2" - echo "I am in test stage" allow_failure: true #容許失敗,即不影響下步構建 # 定義 job job3: stage: build except: - dev #除了dev分支,其它分支提交代碼都會執行這個任務 script: - echo "I am job3" - echo "I am in build stage" when: always #無論前面幾步成功與否,永遠會執行這一步。它有幾個值:on_success (默認值)\on_failure\always\manual(手動執行) # 定義 job .job4: #對於臨時不想執行的job,能夠選擇在前面加個".",這樣就會跳過此步任務,不然你除了要註釋掉這個jobj外,還須要註釋上面爲deploy的stage stage: deploy script: - echo "I am job4" # 模板,至關於公用函數,有重複任務時頗有用 .job_template: &job_definition # 建立一個錨,'job_definition' image: ruby:2.1 services: - postgres - redis test1: <<: *job_definition # 利用錨'job_definition'來合併 script: - test1 project test2: <<: *job_definition # 利用錨'job_definition'來合併 script: - test2 project #下面幾個都至關於全局變量,均可以添加到具體job中,這時會被子job的覆蓋 before_script: - echo "每一個job以前都會執行" after_script: - echo "每一個job以後都會執行" variables: #變量 DATABASE_URL: "postgres://postgres@postgres/my_database" #在job中能夠用${DATABASE_URL}來使用這個變量。經常使用的預約義變量有CI_COMMIT_REF_NAME(項目所在的分支或標籤名稱),CI_JOB_NAME(任務名稱),CI_JOB_STAGE(任務階段) GIT_STRATEGY: "none" #GIT策略,定義拉取代碼的方式,有3種:clone/fetch/none,默認爲clone,速度最慢,每步job都會從新clone一次代碼。咱們通常將它設置爲none,在具體任務裏設置爲fetch就能夠知足需求,畢竟不是每步都須要新代碼,那也不符合咱們測試的流程 cache: #緩存 #由於緩存爲不一樣管道和任務間共享,可能會覆蓋,因此有時須要設置key key: ${CI_COMMIT_REF_NAME} # 啓用每分支緩存。 #key: "$CI_JOB_NAME/$CI_COMMIT_REF_NAME" # 啓用每一個任務和每一個分支緩存。須要注意的是,若是是在windows中運行這個腳本,須要把$換成% untracked: true #緩存全部Git未跟蹤的文件 paths: #如下2個文件夾會被緩存起來,下次構建會解壓出來 - node_modules/ - dist/
https://git.xx.com/ci/lint
若是你的commit
信息包涵[ci skip]
或者[skip ci]
,不論大小寫,這個commit
將會被建立,可是job
會被跳過
使用shell
腳本時,每步job
一開始總有不短的等待時間,對於咱們而言是沒必要要的,除去後臺jenkins_build
這步外,仍要最快20
分鐘。
以前,我曾在release
分支時,暫時將各步整合到一個job
裏,時間縮短爲5
分鐘。固然,這是不符合語義的。
最近,發現docker
沒有這個問題。因此,建議使用docker
。
如下是咱們項目中使用的.gitlab-ci.yml
文件:
image: xx:1.0 stages: - jenkins_build - install - test - build - e2e - zip - copy - end cache: policy: pull key: "$CI_COMMIT_REF_NAME" paths: - node_modules/ - .eslintcache variables: DOCKER_DRIVER: overlay2 GIT_STRATEGY: "fetch" .template: &templateDef # 建立一個錨,'template' only: - master - release - dev install: stage: install <<: *templateDef # 利用錨'templateDef'來合併 cache: key: "$CI_COMMIT_REF_NAME" paths: - node_modules script: - cnpm i eslint: stage: test <<: *templateDef script: - npm run eslint unit: stage: test <<: *templateDef script: - npm run unit build: stage: build <<: *templateDef only: - release script: - npm run clear_dist - npm run build .e2e_ci: stage: e2e <<: *templateDef script: - npm run e2e_ci zip: stage: zip <<: *templateDef only: - release script: - npm run zip ## Jenkins 複製 jenkins_copyweb: stage: copy <<: *templateDef only: - release script: - ssh $JENKINS_SERVER_IP /jenkins/XX_copyweb.sh ## Jenkins 提交 jenkins_commit: stage: end <<: *templateDef only: - release script: - ssh $JENKINS_SERVER_IP /jenkins/XX_svn_commit.sh ## Jenkins 構建 jenkins_build: stage: jenkins_build <<: *templateDef only: - master script: - ssh $JENKINS_SERVER_IP /jenkins/build.sh
其中,XX:1.0
是咱們本身建立的docker
鏡像,它主要安裝了nodejs
、cnpm
、jdk
、sshpass
,其中sshpass
不是必須的,它是使用密碼登錄宿主機時的一種方案。
如今,咱們使用ssh
來與宿主機交互,須要將容器內生成的ssh
的key
(ssh-keygen -t rsa
),即/root/.ssh/id_rsa.pub
中內容,複製到宿主機的/root/.ssh/authorized_keys
文件中。
配置文件/etc/gitlab-runner/config.toml
修改成
[[runners]] name = "216xx" url = "https://git.xx.com/" token = "xx" executor = "docker" [runners.docker] tls_verify = false image = "xx:1.0" privileged = false disable_cache = false pull_policy = "if-not-present" volumes = ["/cache","/tmp:/tmp:rw"] shm_size = 0 [runners.cache]
其中,pull_policy
是下載docker
鏡像image
的策略,默認會先從網上找,沒有就報錯,咱們改成先從本地找;volumes
是將docker
中的數據卷掛載到宿主機上。