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 完成的

相关文章
相关标签/搜索