夜猫的小站

自建服务的cicd

Published on
阅读时间:9分钟1646

本文最近一次更新于 503 个天前,其中的内容很可能已经有所发展或是发生改变。

前言

记录下我的自建服务中的 cicd 实现。 我希望我的应用部署是自动化的,不用我每次手动打包,手动登录服务器部署代码。之前的大部分服务都是基于 docker 以及 docker-compose 部署的。但是每次都是手动打包加上登录服务器手动更新,有点麻烦。在双 11 有了性能主机作为打包编译的服务器以后,我就考虑用下牛刀杀鸡了,用一下热门了很多年的 k8s 生态部署应用。

整体实现

这一次我用的是 woodpecker 作为 ci 工具,从自建的 gitea 仓库拉取代码自动编译,再推送到 docker register 自建私有镜像中心。等待推送完镜像以后,在通过工作流程中的调用 argocd的接口通知 argocd拉取最新的更新,自动部署到 k3s 容器中。内部网络基于 k3s 的 ingress 绑定,外网环境使用 headscale 连接内部以及腾讯云服务器,通过 nginx 代理需要外网访问的服务。

应用 cicd 具体实现

以这个博客为例,我把 woodpeckerargocd以及博客打包用 dockerfile 都集成的博客项目内,这样就方便我统一管理博客从开发、编译、部署的流程。 image.png

woodpecker 配置

Woodpecker 是基于 droneci 的开源 fork 版本,语法使用上和我之前使用 drone 差别没那么大。

添加项目

开始阶段需要在 woodpecker 后台中添加 gitea 中的项目 image.png

配置项目

进入项目设置,运行流水线前先进行项目配置,在基本设置中需要先勾选受信任,方便在执行构建时挂载目录。

没有受信任的选项,请现将当前用户登记为 woodpeacker 管理员

image.png image.png

when 的语法

when:
  - event: push
    branch: dev
    path:
      exclude: ['*.md', 'docs/**', '.workflow', 'config']

这部分的逻辑是基于 dev 分支 push 实践触发工作流,'*.md', 'docs/**', '.workflow', 'config' 这些文件的更新不会触发。

pipeline 的基本写法

pipeline 的标准写法就是 steps 后面带上任务名称,以及镜像名称,执行方式等操作。

demo.yml
steps:
  build-image-xxx:
    image: docker:20.10.3
    volumes: 
      - /data:/var/
    commands: 
      - echo 'hello world'

比如下面的写法其实就是我用 docker 镜像通过博客的 Dockerfile 打包了博客的镜像并推送到我的私有镜像服务中,这种是 docker in docker 的方式,因为 woodpecker 本身也是通过 docker-compose 部署在 docker 中。

由于是个人的家庭网络中使用,所以也不考虑使用 harbor 搭建,直接使用了官方 docker register 搭建。如果是镜像仓库有账号密码的鉴权的逻辑,在推送到镜像仓库前,还需要先进行登录。

docker-compose.yml
steps:
  build-blog-image:
    image: docker:20.10.3
    volumes: 
      - /var/run/docker.sock:/var/run/docker.sock
    environment: 
      IMAGE: 192.168.50.214:5134/remix-blog
    commands: 
      - export DRONE_TAG=$(cat .tags) ${CI_COMMIT_TAG}
      - docker build -f ./Dockerfile -t $IMAGE:$DRONE_TAG ./
      - docker tag $IMAGE:$DRONE_TAG $IMAGE:latest
      - docker push $IMAGE:$DRONE_TAG
      - docker push $IMAGE:latest

推送到镜像仓库后,就是部署以及持续集成了。我的博客是部署在 k3s 中,所以考虑后使用本身就是云原生的 argocd 来进行持续集成。pipeline 在打包完镜像以后就需要通知 argocd 拉取最新镜像,更新 pod。

之前手动部署 k3s 应用的时候都是 kubectl apply -f app.yml,有了 argocd 部署方便了很多。

完整的 woodpecker 配置如下:

.woodpecker.yml
when:
  - event: push
    branch: dev
    path:
      exclude: ['*.md', 'docs/**', '.workflow', 'config']
steps:
  build:
    image: docker:20.10.3
    volumes: 
      - /var/run/docker.sock:/var/run/docker.sock
    environment: 
      IMAGE: 192.168.50.214:5134/remix-blog
    commands: 
      - export DRONE_TAG=$(cat .tags) ${CI_COMMIT_TAG}
      - docker build -f ./Dockerfile -t $IMAGE:$DRONE_TAG ./
      - docker tag $IMAGE:$DRONE_TAG $IMAGE:latest
      - docker push $IMAGE:$DRONE_TAG
      - docker push $IMAGE:latest
  deploy:
    image: 192.168.50.214:5134/argocd:latest
    environment: 
      ARGOCD_SERVER: '192.168.50.17:32460'
      ARGOCD_USERNAME: 'admin'
      ARGOCD_PASSWORD: $ARGOCD_PASSWORD
      APP_NAME: 'blog'
      BRANCH: 'dev'
    commands:
      - echo 'start deploy'
      - echo $ARGOCD_PASSWORD
      - argocd login $ARGOCD_SERVER --insecure --username=$ARGOCD_USERNAME --password=$ARGOCD_PASSWORD
      - argocd app sync $APP_NAME --revision $BRANCH
      - argocd app wait $APP_NAME
    secrets: [ argocd_password ]

argocd 镜像的 Dockerfile

官方没有合适的镜像命令行通知,所以就基于 argocd 官方镜像在生成可以执行命令行的镜像。我是部署在我的私有仓库中,所以在 deploy 的操作中是拉取 192.168.50.214:5134/argocd:latest 镜像。

FROM argoproj/argocd:v2.6.15 as builder

FROM ubuntu:18.04 as app

COPY --from=builder /usr/local/bin/argocd /usr/local/bin/argocd

ENTRYPOINT [ "argocd" ]

生成这个镜像也是用的 woodpecker

生成 argocd:latest 镜像的 woopecker 配置如下:

.woodpecker.yml
steps:
  build:
    image: docker:20.10.3
    volumes: 
      - /var/run/docker.sock:/var/run/docker.sock
    environment: 
      IMAGE: 192.168.50.214:5134/argocd
    commands: 
      - export VERSION_TAG=$(cat .tags)
      - docker build -f ./Dockerfile -t $IMAGE:$VERSION_TAG ./
      - docker tag $IMAGE:$VERSION_TAG $IMAGE:latest
      - docker push $IMAGE:$VERSION_TAG
      - docker push $IMAGE:latest

argocd 应用配置

设置应用

先登录到 argocd 后台中,添加应用。登录后在 Applications 页,点击 NEW APP 创建项目。 image.png 按照官方文档创建项目,设置项目的 git 仓库 image.png

image.png

博客中的 argocd 配置

这个其实就是配置对应仓库目录的 k8sdeploymentSVC。例如在 argocd 中的路径设置的是 .worflow/argocd 那么在我的博客中的对应目录, deploymentSVC 的文件就放在目录中。

deploymentSVC 的概念需要先学习下 k8s 相关的概念

image.png

blog-deployment.yml 以及 blog-svc.yml 的配置如下

blog-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: blog-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: blog-app
  template:
    metadata:
      labels:
        app: blog-app
    spec:
      terminationGracePeriodSeconds: 30
      containers:
      - name: blog-app
        image: 192.168.50.214:5134/remix-blog:latest
        imagePullPolicy: "Always"
        ports:
          - containerPort: 3002
        env:
          - name: "REMOTE"
            value: "git"
          - name: "REDIS_URL"
            value: "redis://default:nas1234%3F@192.168.50.120:6379"
        resources:
            limits:
              cpu: "2"
              memory: "2Gi"
            requests:
              cpu: "1"
              memory: "512Mi"
blog-svc.yml

apiVersion: v1
kind: Service
metadata:
  name: blog-app
spec:
  type: NodePort
  ports:
  - port: 3002
    nodePort: 32428
  selector:
    app: blog-app

woodpeacker 推送到 argocd

argocd 会自动根据 git 仓库的更新情况重新下来镜像进行更新,但是仓库一般是优先于镜像的更新,所以就需要在镜像打包完成以后主动通知 argocd 镜像已经更新。 这里就用到 woodpeacker 的 deploy 中配置,通过 argocd 命令行调用同步的命令。

deploy:
    image: 192.168.50.214:5134/argocd:latest
    environment: 
      ARGOCD_SERVER: '192.168.50.17:32460'
      ARGOCD_USERNAME: 'admin'
      ARGOCD_PASSWORD: $ARGOCD_PASSWORD
      APP_NAME: 'blog'
      BRANCH: 'dev'
    commands:
      - echo 'start deploy'
      - echo $ARGOCD_PASSWORD
      - argocd login $ARGOCD_SERVER --insecure --username=$ARGOCD_USERNAME --password=$ARGOCD_PASSWORD
      - argocd app sync $APP_NAME --revision $BRANCH
      - argocd app wait $APP_NAME
    secrets: [ argocd_password ]

设置环境变量

在 woodpecker 中的密钥栏,添加用于 argocd 登录的密钥,比如用户名和密码。设置密钥的时候,使用的小写字母,在使用的时候会转换为大写。 image.png

总结

整体编译的流程对于一个小的项目其实复杂了很多,使用这一套流程目的也是学习了解云原生的 cicd 过程。整体实践下来,相对 jenkins 还是方便很多,不需要去操作对应部署的服务器。