Gitlab CI 與 DevOps

上一篇講到了扇貝的微服務實踐,尤爲是關於「人」的部分。html

本文將就「技術」方案部分作一個簡單的分享。python

區分不一樣的環境

在扇貝,咱們維護了 「集成測試環境」 和 「生產環境」 兩個 kubernetes 集羣。mysql

  • 集成測試環境負責:單元測試,構建鏡像,集成測試部署
  • 生產環境負責:預發佈,正式發佈

CI/CD 的搭建

咱們的 CI/CD 是基於 GitLab Pipeline 搭建的。git

架構組負責搭建和維護 runner(Pipeline 的執行環境),DevOps 小組負責 Pipeline 腳本的編寫。redis

Gitlab Pipeline

Gitlab pipeline 指 一組按照 stage 執行的job(每一個 stage 包含若干個 job),當一個 stagejob 都成功執行後,開始執行下一個 stagejobpipeline 定義在項目的 .gitlab-ci.yml裏。關於 .gitlab-ci.yml 的詳細參考文檔,請見:Configuration of your jobs with .gitlab-ci.ymlsql

.gitlab-ci.yml 的編寫和維護

在扇貝,每一個 DevOps 小組負責編寫和維護本身負責項目的 .gitlab-ci.yml,定義本身的 pipeline。固然,架構組會提供一個 .gitlab-ci.yml 模版。這個模版 包含 test, build-image, deploy-integration, deploy-staging, deploy-production 5個 stage。基於這樣的 pipeline 能夠實現這樣的 CI/CD 工做流:docker

組員新建分支,開發功能,建立一個 Merge Request,這時候觸發第一個 stage: testtest 中包含全部單元測試的 job。當 test 經過後,組長 Review Merge Request,這其中可能還會提一些修改意見,組員進行對應的修改,再次觸發 test。當且僅當組長 Review 經過後,執行 Merge,這時候開始觸發第二個 stage: build-image(也就是構建 Docker Image)。構建成功後進入到 deploy-integration。集成測試沒有問題,再依次deploy-staging-> 預發佈驗證 -> deploy-production。至此整個 CI/CD 工做流就完成了。api

一個大概的 .gitlab-ci.yml 模版以下:bash

stages:
 - test
 - build
 - deploy_integration
 - deploy_staging
 - deploy_production

variables:
 MYSQL_DATABASE: test
 MYSQL_ALLOW_EMPTY_PASSWORD: yes
 SEA_ENV: testing
 DOCKER_HOST: tcp://dockerd:2375
 IMAGE: registry.mydocker.com/devops/${CI_PROJECT_NAMESPACE}-${CI_PROJECT_NAME}

before_script:
 - IMAGE_TAG=${IMAGE}:${CI_COMMIT_SHA:0:8}

#========================================= Unit Testing ================================================
test_all:
 image: python:3.7
 stage: test
 services:
 - name: mysql:5.6
 alias: mysql
 - name: redis:4
 alias: redis
 before_script:
 - pip install -U -r requirements.txt
 script:
 - flake8 app jobs
 - sea test

#========================================== Build Image =================================================
build_image:
 stage: build
 only:
 - master
 tags:
 - build
 script:
 - docker build -t ${IMAGE_TAG} -f Dockerfile .
 - docker push ${IMAGE_TAG}


deploy_rpc_integration:
 stage: deploy_integration
 only:
 - master
 tags:
 - deploy-integration
 script:
 - kubectl -n xyz set image deploy/examples-rpc "app=${IMAGE_TAG}" --record

deploy_staging:
 stage: deploy_staging
 only:
 - master
 tags:
 - deploy-production
 when: manual
 script:
 - kubectl -n xyz-staging set image deploy/examples-celery "app=${IMAGE_TAG}" --record
 - kubectl -n xyz-staging set image deploy/examples-rpc "app=${IMAGE_TAG}" --record

deploy_production:
 stage: deploy_production
 only:
 - master
 tags:
 - deploy-production
 when: manual
 script:
 - kubectl -n xyz set image deploy/examples-celery "app=${IMAGE_TAG}" --record
 - kubectl -n xyz set image deploy/examples-rpc "app=${IMAGE_TAG}" --record
複製代碼

下圖是一個執行的例子,圖中能夠看到 stage 執行到哪一步,結果分別是什麼。架構

GitLab Runner

除了各個小組可以維護本身的 .gitlab-ci.yml,接下來就要架構組構建可以執行這些 pipelinerunner 了。

Gitlab 提供了 GitLab Runner 來管理 runnerGitLab Runner 負責註冊,運行和反註冊 runner

咱們能夠利用 k8s 來很方便地運行 GitLab Runner,而且選擇 k8s 做爲executor 來運行 job。一個示例配置以下:

apiVersion: v1
metadata:
 labels:
 app: gitlab-builder
 name: gitlab-builder-cm
 namespace: cicd
data:
 REGISTER_NON_INTERACTIVE: "true"
 REGISTER_LOCKED: "false"
 CI_SERVER_URL: "https://gitlab.com/ci"
 RUNNER_CONCURRENT_BUILDS: "4"
 RUNNER_REQUEST_CONCURRENCY: "4"
 RUNNER_TAG_LIST: "build"
 RUNNER_EXECUTOR: "kubernetes"
 KUBERNETES_NAMESPACE: "cicd"
 KUBERNETES_IMAGE: "docker:17.11"
 KUBERNETES_SERVICE_ACCOUNT: "builder"
kind: ConfigMap
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
 name: builder
 namespace: cicd
 labels:
 app: builder
spec:
 replicas: 1
 selector:
 matchLabels:
 app: builder
 template:
 metadata:
 labels:
 app: builder
 spec:
 containers:
 - name: ci-builder
 image: gitlab/gitlab-runner:v10.6.0
 command:
 - /usr/bin/gitlab-ci-multi-runner
 - run
 imagePullPolicy: IfNotPresent
 envFrom:
 - configMapRef:
 name: gitlab-builder-cm
 volumeMounts:
 - mountPath: /etc/gitlab-runner/
 name: config-volume
 lifecycle:
 preStop:
 exec:
 command:
 - /bin/bash
 - -c
 - "/usr/bin/gitlab-ci-multi-runner unregister -t xxxxxx -n builder"
 initContainers:
 - name: register-runner
 image: gitlab/gitlab-runner:v10.6.0
 command: ["sh", "-c", "/usr/bin/gitlab-ci-multi-runner unregister -t xxxxxx -n builder; /usr/bin/gitlab-ci-multi-runner register -r xxxxxx;"]
 volumeMounts:
 - mountPath: /etc/gitlab-runner/
 name: config-volume
 envFrom:
 - configMapRef:
 name: gitlab-builder-cm
 volumes:
 - name: config-volume
 emptyDir: {}
 restartPolicy: Always
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
 namespace: cicd
 name: builder
rules:
 - apiGroups: [""]
 resources: ["pods", "pods/exec"]
 verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
 namespace: cicd
 name: builder
subjects:
- kind: ServiceAccount
 name: builder
 namespace: cicd
roleRef:
 kind: Role
 name: builder
 apiGroup: rbac.authorization.k8s.io
複製代碼

這樣咱們就能夠獲得一個可以build docker image 的runner。在 .gitlab-ci.yml 中指定 tag 爲 build 就可使用。

最小化運維

咱們堅持「最小化運維」的理念,除了平常的 DevOps,咱們儘量地利用 git + pipeline 的方式完成平常工做。咱們堅信這樣的工做方式可以最大化下降手動運維帶來的風險和不肯定性。

例如咱們 k8s 的證書籤發就是基於 git + pipeline 來作的。你們知道,要可以使用 kubectl,每一個人得有通過 k8s 的簽發的 crt 才能夠經過 k8s 的認證。咱們簽發的流程就是:

  1. 有一個存放你們csr的 git repo
  2. 新人生成本身的csr,添加到 git repo,提交 merge request
  3. ci 開始 validate csr合法性(例如name的格式,是否包含什麼信息,不包含什麼信息等等)
  4. 集羣管理員 validate csr name 和申請人是否相符,若是相符,則合併該 merge request
  5. ci 開始簽發 integration, production 兩個集羣的 crt

在扇貝,幾乎全部的平常運維工做都是基於 CI/CD 完成的

相關文章
相關標籤/搜索