上一篇讲到了扇贝的微服务实践,尤为是关于“人”的部分。html
本文将就“技术”方案部分作一个简单的分享。python
在扇贝,咱们维护了 “集成测试环境” 和 “生产环境” 两个 kubernetes
集群。mysql
咱们的 CI/CD 是基于 GitLab Pipeline 搭建的。git
架构组负责搭建和维护 runner(Pipeline 的执行环境),DevOps 小组负责 Pipeline 脚本的编写。redis
Gitlab pipeline
指 一组按照 stage
执行的job
(每一个 stage
包含若干个 job
),当一个 stage
的 job
都成功执行后,开始执行下一个 stage
的 job
。pipeline
定义在项目的 .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
: test
。test
中包含全部单元测试的 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-ci.yml
,接下来就要架构组构建可以执行这些 pipeline
的 runner 了。
Gitlab 提供了 GitLab Runner 来管理 runner
。 GitLab 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
的认证。咱们签发的流程就是:
在扇贝,几乎全部的平常运维工做都是基于 CI/CD 完成的