由于我们公司之前就有自己的gitlab仓库和harbor仓库,都是通过docker-compose管理的,在我接手后先是把gitlab也搬到了K8s集群里面,而harbor仓库由于实在比较大,平时用着也比较稳定,所以就一直维持了之前的样子。
目前搭建的CI和CD是分离的,实际上Drone也可以直接在K8s集群中更新我们的服务,具体为什么要分开来后续会做说明。
CI
一开始我使用过jenkins来做CICD,一开始也用的还不错,除了一开始配置麻烦一点,但只要配置好了一个,后面就都是模板化操作了。但是由于一次意外导致数据损坏,所有的配置以及脚本全都付之一炬了,当时也没有把配置过程记录下来,所以就懒得再做一次了。然后就发现了DroneCI这个工具,它分为Server和Runner。Server负责和git仓交互,并且提供API和界面。Runner负责和Server交互,获取到Server的构建任务进行实际的构建工作。
配置server
Server我是直接跑在Kubernetes里面,需要先在gitlab的admin-area里面添加一个application,添加drone-server的回调地址,并且给与权限,从而获取到clientid和clientsecret。
然后把上一步中获取的id和secret填入drone的环境变量中,其中DRONE_ADMIN定义drone的管理员用户,需要同时也是gitlab的用户。
apiVersion: apps/v1
kind: Deployment
metadata:
name: drone
namespace: tools
labels:
app: drone
spec:
replicas: 1
selector:
matchLabels:
app: drone
template:
metadata:
labels:
app: drone
spec:
volumes:
- name: data
persistentVolumeClaim:
claimName: drone-server-data
containers:
- name: drone
image: drone/drone:latest
env:
- name: DRONE_ADMIN
value: xxxx
- name: DRONE_GITLAB_CLIENT_ID
value: fa92ebce8b11bf3a940eb6fac3b23753ea99ccb6ce0bede07666bd2a800fcfa7
- name: DRONE_GITLAB_CLIENT_SECRET
value: 9d9231e10ac6179c05b8a1a6bfc66eea55d2ced4cc503fbcba5e6e4a1ab3ef65
- name: DRONE_GITLAB_SERVER
value: http://gitlab.sz
- name: DRONE_GIT_ALWAYS_AUTH
value: 'true'
- name: DRONE_RPC_SECRET
value: drone
- name: DRONE_SERVER_HOST
value: drone.tools.k
- name: DRONE_SERVER_PROTO
value: http
- name: DRONE_USER_CREATE
value: username:xxxx,admin:true
- name: DRONE_WEBHOOK_SKIP_VERIFY
value: 'true'
resources: {}
volumeMounts:
- name: data
mountPath: /data
imagePullPolicy: IfNotPresent
restartPolicy: Always
把drone通过上面定义好的域名暴露出来,然后就可以访问drone-server了。
点击continue就会跳转到gitlab要求账号密码登录,登录成功回跳回drone-server就完成了
然后通过sync进行项目的同步,选择需要CI的项目active即可。
由于我在构建的时候用到了服务器本地的存储,所以需要勾选trusted。这样Drone-Server的配置就完成了,接下来配置Runner。
我是单独拿了一台服务器来做构建工作的,Runner是直接通过docker-compose启动的,这里给出docker-compose.yml文件,其中DRONE_RPC_SECRET要与server的DRONE_RPC_SECRET相同。
version: '3'
services:
drone-runner:
image: drone/drone-runner-docker:latest
container_name: drone-runner
restart: always
privileged: true
environment:
- DRONE_RPC_PROTO=http
- DRONE_RPC_HOST=drone.tools.k
- DRONE_RPC_SECRET=drone
- DRONE_RUNNER_CAPACITY=2
- DRONE_RUNNER_NAME=drone-runner
- DRONE_REGISTRY_PLUGIN_SKIP_VERIFY=true
ports:
- 3000:3000
volumes:
- /var/run/docker.sock:/var/run/docker.sock
Runner配置完成之后只需要在项目中添加.drone.yml文件就可以进行自动构建了。
这里给出一个实例的构建文件,tag事件会触发项目的CI动作,drone会先从gitlab中拉取项目,然后挂载到nodejs中去进行build,build完成之后挂载到docker-plugin中去构建镜像并推送到镜像仓,最后通过slack进行通知。其中构建镜像的时候还需要用到Dockerfile文件。
# .drone.yml
kind: pipeline
type: docker
name: default
steps:
- name: package
image: nodejs
commands:
- npm install
- npm run build:prod
- name: build and publish image
image: library/docker-plugin:latest
volumes:
- name: run
path: /var/run/docker.sock
settings:
username: XXX
password: XXX
insecure: true
registry: harbor.test
repo: harbor.test/library/front
tags: ${DRONE_TAG}
- name: build notify
image: library/slack:latest
settings:
webhook: http://XXXX
channel: cicd
when:
status: [ success, failure ]
trigger:
event:
- tag
volumes:
- name: run
host:
path: /var/run/docker.sock
# Dockerfile
FROM nginx:latest
COPY ./dist /usr/share/nginx/html
CD
CD我选用的是ArgoCD,它可以跟gitlab集成,从gitlab里面获取yml文件并同步到K8s集群中。
K8s没有提供一个可以管理yml文件的地方,所以要管理这些部署文件也是一个头疼的事情,而git则可以完美的解决这个问题,既可以做权限管理,又可以管理文件的提交记录,这就是目前流行的gitops。
ArgoCD可以直接通过helm进行安装,安装步骤就详细说明了,这里只说一下如何跟gitlab集成和通知。
登陆ArgoCD之后在Settings/Repositories里面添加gitlab的项目地址,如果你的gitlab仓是https的可以通过用户名和密码来验证权限,如果是通过ssh连接的就需要ssh密钥了。在gitlab的个人用户设置,SSH Keys里面添加上公钥,然后在ArgoCD中添加一个Connect repo using SSH,把对应的私钥和项目地址填上去,当然首先你的账号需要有对应项目的读取权限。
然后就可以通过这个Repositories来读取这个项目下面的yml文件了,argocd会自动识别yml以及chart包,简单一点的话可以在一个项目里面创建所有的需要部署的服务的文件夹,然后把对应服务的yml文件放到对应的目录中,argocd创建application的时候可以支持从项目的指定目录中读取数据。
后续当需要更新服务版本的时候,只需要在gitlab里面改一下yml文件里面的版本号就可以了,这样就实现了gitlab、argocd、k8s的集成了。
argocd默认是每3分钟从gitlab中同步一次数据,你可以通过在gitlab中添加webhook来主动通知argocd进行数据的同步。具体可以参考https://argo-cd.readthedocs.io/en/stable/operator-manual/webhook/ 。
argocd支持多种的通知方式,包括邮件,slack等,我使用的是mattermost的通知,我把所有的消息通知、监控的告警都集成到了公司的mattermost上。
只需要在argocd-notifications-cm中添加通知模版、通知地址、通知触发条件,在argocd-notifications-secret添加mattermost的token即可。
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
service.mattermost: |
apiURL: mattermost
token: $mattermost-token
insecureSkipVerify: true
template.app-sync-status: |
message: |
Application {{.app.metadata.name}} sync is {{.app.status.sync.status}}.
Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.
mattermost:
attachments: |
[{
"title": "{{.app.metadata.name}}",
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#18be52",
"fields": [{
"title": "Sync Status",
"value": "{{.app.status.sync.status}}",
"short": true
}, {
"title": "Repository",
"value": "{{.app.spec.source.repoURL}}",
"short": true
}]
}]
trigger.sync-operation-change: >
- when: app.status.operationState.phase in ['Succeeded'] and
app.status.health.status == 'Healthy'
oncePer: app.status.sync.revision
send: [app-sync-status]
- when: app.status.operationState.phase in ['Error', 'Failed']
send: [app-sync-status]
apiVersion: v1
kind: Secret
metadata:
name: argocd-notifications-secret
namespace: argocd
data:
mattermost-token: token
type: Opaque
最后在需要通知的Application资源上添加annotation就可以了,具体可参考https://argo-cd.readthedocs.io/en/stable/operator-manual/notifications/services/mattermost/
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
notifications.argoproj.io/subscribe.sync-operation-change.mattermost: <channel-id>
总结
至此CICD就搭建好了,基于gitlab,把开发人员和运维人员分割开来,开发人员只需要通过gitlab就能进行代码的提交、构建以及发布工作,并且所有记录都通过gitlab进行管理。当然上面还缺了很多东西,只是一个最基本的CICD,缺了包括集成测试等重要工作。