Despliegue automático de servicios con Drone CI

prefacio

Por lo general, escribo algunos servicios para mi propio uso. Antes de eso, se implementaba manualmente, es decir, se empaquetaba localmente, se cargaba en el servidor, se detenía el servicio original y se ejecutaba el nuevo servicio. Es muy complicado escribir la línea de comando manualmente cada vez Basado en el principio de que se puede automatizar, no es necesario hacerlo manualmente, por lo que decidí desarrollar un proceso de CI/CD para completar automáticamente el trabajo de empaquetado e implementación. Después de leer algunas plataformas de CI introducidas en Internet, combinadas con el rendimiento limitado de mi servidor y requisitos relativamente simples, finalmente elegí Drone .

Frameworks y herramientas implicadas en todo el proceso:

  • Nginx como servidor proxy;
  • SpringBoot;
  • Gradle como herramienta de construcción;

Instalar Dron

Drone se puede usar con múltiples plataformas Git, incluidas Github, GitLab, Gitea, Gogs, etc. Aquí se usa Github como ejemplo.

Crear una aplicación OAuth

Para usar Drone con Github, primero debe crear una aplicación Github OAuth y crear una nueva aplicación en Configuración de Github - Configuración del desarrollador - Aplicaciones OAuth. Preste atención al formato que Authorization callback URLdebe tener http(s)://域名/login, los ejemplos son los siguientes:

Crear aplicación OAuth

Una vez completada la creación, debe recordar ClientIdy ClientSecret, y debe usarlo más tarde;

Instalar Drone y Drone-Runner

Una vez completada la configuración, Drone se instala oficialmente. Drone debe instalarse usando Docker, use el siguiente comando:

# 拉取镜像
docker pull drone/drone:2
# 运行
docker run \
  --volume=/var/lib/drone:/data \
  --env=DRONE_USER_CREATE=username:${GITHUB_USERNAME},admin:true \
  --env=DRONE_GITHUB_CLIENT_ID=${CLIENT_ID} \
  --env=DRONE_GITHUB_CLIENT_SECRET=${CLIENT_SECRET} \
  --env=DRONE_SERVER_HOST=${URL} \
  --env=DRONE_SERVER_PROTO=http \
  --env=DRONE_RPC_SECRET=d1dcf4f192da23plpm25k126zh87otv0 \
  --publish=7000:80 \
  --restart=always \
  --detach=true \
  --name=drone \
  drone/drone:2
复制代码
  • DRONE_USER_CREATEEs el nombre de usuario del administrador, usernameseguido del nombre de usuario de Github.Si no está configurado, es imposible realizar configuraciones avanzadas en el almacén;
  • DRONE_GITHUB_CLIENT_IDes el ClientId después de crear la aplicación OAuth;
  • DRONE_GITHUB_CLIENT_SECRETes el ClientSecret después de crear la aplicación OAuth;
  • DRONE_SERVER_HOSTDebe ser el mismo que el nombre de dominio de la URL de devolución de llamada de autorización al crear la aplicación OAuth (sin /loginruta);
  • DRONE_SERVER_PROTO需要与创建OAuth Application时的Authorization callback URL的proto相同;
  • DRONE_RPC_SECRET将在后面配置Drone-Runner时使用,作为Drone与Drone-Runner通信的“凭证”,可以用openssl rand -hex 16生成一个;
  • --publish设置Docker的端口映射规则,这里将Drone的80端口映射到主机的7000端口;

接着安装Drone-Runner,命令如下:

# 拉取镜像
docker pull drone/drone-runner-docker:1
# 运行
docker run --detach \
  --volume=/var/run/docker.sock:/var/run/docker.sock \
  --env=DRONE_RPC_PROTO=http \
  --env=DRONE_RPC_HOST=drone \
  --env=DRONE_RPC_SECRET=d1dcf4f192da23plpm25k126zh87otv0 \
  --env=DRONE_RUNNER_CAPACITY=2 \
  --env=DRONE_RUNNER_NAME=drone-runner \
  --publish=7001:3000 \
  --restart=always \
  --name=runner \
  --link drone:drone \
  drone/drone-runner-docker:1
复制代码

需要注意DRONE_RPC_SECRET需要与运行Drone时的配置保持一致;此外还要注意这里的DRONE_RPC_PROTO, DRONE_RPC_HOST以及--link,由于我们这里的Drone与Drone-Runner在同一台主机上运行,需要它们之间可以相互通信,因此采用了--link选项,使得Runner的DRONE_RPC_HOST能够访问到Drone;

上面的Runner叫做Docker Runner,是Drone-Runner最常用的一种,主要为在无状态容器中编译及测试的代码提供了优化。除了Docker Runner以外,还有Kubernetes Runner, Exec Runner, SSH Runner等,由于与本文内容无关,不在此详细介绍

运行后,使用docker logs runner命令查看日志,如果有successfully pinged the remote server信息,代表Runner运行成功。

配置Nginx

Nginx的配置比较简单,只需要在Nginx的配置文件中添加以下内容,然后重启Nginx即可:

# /etc/nginx/nginx.conf
server {
    listen 80;
    # URL与Authorization callback URL保持一致,如drone.test.com
    server_name ${URL};

    location / {
        # 与Docker配置的端口号保持一致
        proxy_pass http://localhost:7000;
        proxy_set_header HOST $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        client_max_body_size 100m;
    }
}
复制代码

重启Nginx:

systemctl restart nginx
复制代码

对于比较新的Nginx版本,对于站点的配置可能在sites-enabled目录下,这时候在/etc/nginx/sites-enabled目录下创建drone.conf文件,然后将上面的配置复制到drone.conf文件中即可;

完成配置后,访问Drone URL,登录Github账号,针对仓库进行配置。

配置Repository

在Drone后台首页,可以看到Github账号下的所有仓库,点击我们想要启用CI的仓库,进入Settings Tab下,点击Activate Repository后,可以看到如下配置页面:

Configuración del repositorio

我们需要将Trusted开关打开,以保证后续pipeline中的命令可以正常执行。此外还有Timeout和Configuration等配置项,Timeout指定Pipeline脚本超时时间,而Configuration则对应了脚本名称。

如果Settings中没有这么多配置项,可能是运行Drone时没有设置Github用户名或者用户名不对

Settings Tab下还有Secrets等配置,可以在Sercets中新建secret,比如密码等,其值可以在后续的pipeline中获取到。

然后切换到Builds Tab下,点击右上角的NEW BUILD按钮,在弹出的对话框中输入目标分支名,然后点击Create。当目标分支有新的commit时,Drone会自动根据脚本运行Pipeline。

配置Pipeline

完成配置仓库后,我们需要手工编写Drone脚本,告诉Drone当有新提交时需要做什么。对于大部分服务,都需要 构建 - 部署 步骤。我们分开进行介绍。

构建任务

在需要开启CI的仓库的根目录下,创建.drone.yml文件,输入以下内容:

kind: pipeline
type: docker
name: MyService

steps:
  - name: build
    image: gradle:jdk11
    volumes:
      - name: service-root
        path: /app/build
      - name: gradle-cache
        path: /root/.gradle
    commands:
      - ./gradlew bootJar
      - cp /drone/src/app-api/build/libs/*.jar /app/build/my-service-latest.jar

volumes:
  - name: service-root
    host:
      path: /root/service
  - name: gradle-cache
    host:
      path: /root/.gradle
复制代码
  • kind 代表脚本的类型,这里指定为pipeline脚本,除了pipeline脚本还有secret和signature脚本;
  • type 定义pipeline的类型,与runner类型,除了Docker外,还有Kubernetes, Exec, SSH等;
  • name 为pipeline的名称;
  • steps 定义了pipeline的步骤,其由多个如上面形式的步骤组成:
    • name 为此步骤的命名;
    • image 指定了这次步骤所依赖的Docker镜像;
    • volumes 将Docker的路径与主机路径进行映射,以能在文件系统上相互访问;
    • commands 为此步骤需要运行的命令;
  • volumes 挂载了主机的卷,我们可以在stepsvolumes中直接使用这里定义的卷名称;

在上面的脚本中,我们进行了如下的操作:

  1. 定义pipeline名称为MyService
  2. 接着在steps中,定义了名为build的步骤,指定使用gradle:jdk11作为此步骤使用的镜像;
  3. 在volumes中,将主机的/root/service路径与Docker容器内的/app/build路径以及主机的/root/.gradle路径与Docker容器内的/root/.gradle路径做了映射,这样便可以直接访问主机指定目录下的文件系统;
  4. 在commands中,首先使用gradlew命令打包SpringBoot程序,然后将打包后的Jar文件复制到/app/build目录下,由于我们将/app/build路径与主机的/root/service做了映射,因此打包后的Jar文件会被直接复制到主机的/root/service目录下;

在复制命令中,cp的源目录是/drone/src/...,/drone/src是Drone的默认工作目录,代码会直接被clone到此目录下,可以在.drone.yml中通过workspace:path的方式进行配置

完成后,我们将.drone.yml进行提交并推送到Github上,打开Drone后台,可以看到Drone已经自动开始了pipeline任务:

Canalización de drones

Drone默认为pipeline增加clone步骤,并在自定义steps之前运行,特殊配置我们会在下文进行介绍

经过如上的操作,我们便完成了构建任务;

部署任务

由于Drone运行在Docker中,无法直接访问主机,因此部署任务需要SSH来“绕行”。

仍然是在.drone.yml文件中,在steps下增加以下内容:

steps:
  - name: build
    # ...
  
  - name: deploy
    image: appleboy/drone-ssh
    settings:
      host: 123.12.34.56
      username: root
      password:
        from_secret: ssh_password
      port: 22
      command_timeout: 5m
      script:
        - cd /root/service
        - mv my-service.jar my-service.backup.jar
        - mv my-service-latest.jar my-service.jar
        - chmod +x run.sh
        - ./run.sh
    when:
      event:
        - promote
复制代码
  • image 指定此步骤需要使用SSH镜像;
  • settings 针对SSH进行配置:
    • host 指定主机IP地址;
    • username SSH用户名;
    • password SSH密码,这里我们使用from_secret的方式从Secrets中取值(需要在仓库的Settings配置);
    • port SSH端口号;
    • command_timeout 远程操作命令超时时间;
    • script 是需要SSH运行的脚本,类比于steps的commands;
  • when 指定了此步骤运行的时机,event=promote指当构建任务完成后,手动在这次pipeline的后台点击右上角三个点 - Promote时运行;

script中,首先将当前目录切换至构建任务目标Jar包所在目录,然后执行一些重命名操作,并将运行脚本修改为execuable,最后运行脚本;

以运行Jar包为例,脚本内容如下:

#!/bin/sh
originalPid=$(ps x | grep "my-service" | grep -v grep | awk '{print $1}')
if [[ -n "$originalPid" ]]
then
    echo "Running my-service PID=$originalPid"
    echo "Stop Running my-service..."
    kill $originalPid
else
    echo "No Running my-service Found..."
fi
newPid=$(nohup java -jar my-service.jar >/dev/null 2>&1 &)
echo "Start my-service PID=$newPid"
复制代码

以上便是构建和部署任务的相关配置,下面我们介绍一些针对Pipeline的其他配置。

Clone配置

上文中讲到Drone会自动执行Clone步骤,如果我们需要某些自定义配置,也可以在脚本中进行声明:

kind: pipeline
type: docker
name: default

clone:
  depth: 50
  retries: 3
复制代码
  • depth 同Git的--depth tag;
  • retries 失败的重试次数,默认不会重试;

Drone默认clone不会fetch tag,如果需要可以通过以下配置:

steps:
- name: fetch
  image: alpine/git
  commands:
  - git fetch --tags
复制代码

同样,Drone也不会拉取submodules,如需要,则使用以下配置:

steps:
- name: submodules
  image: alpine/git
  commands:
  - git submodule update --init --recursive
复制代码

如果仍需要比较复杂的Git逻辑,可以直接禁用Drone的clone,自己定义Git逻辑:

clone:
  disable: true

steps:
- name: clone
  image: alpine/git
  commands:
  - git clone https://github.com/octocat/hello-world.git .
  - git checkout $DRONE_COMMIT
复制代码
  • DRONE_COMMIT 是触发此次pipeline的commit id;

Trigger配置

如果想要pipeline在某些特殊的情景下运行,可以通过Drone提供的trigger进行配置:

steps:
- name: build
  # ...

trigger:
  branch:
  - master
    include:
    - master
    - feature/*
    exclude:
    - alpha/*
  ref:
  - refs/heads/master
  - refs/heads/**
  - refs/pull/*/head
  event:
  - cron
  - custom
  - push
  - pull_request
  - tag
  - promote
  - rollback
复制代码
  • branch 当某个pull request以此分支作为目标分支时触发;
  • ref 基于Git引用有更新时触发;
  • event 当遇到某个事件时触发;

refevent都可以使用include与exclude

参考文档

Supongo que te gusta

Origin juejin.im/post/7150186954531799077
Recomendado
Clasificación