Drone with Gitea 首先是配置一个环境,这里我的Gitea以及Drone都将使用Docker进行部署。
Delpoy Gitea with Docker 先考虑部署Gitea,官方文档可见:
Installation with Docker - Docs (gitea.io)
在部署前安装Docker
以及Docker-compose
这两个软件。官方给出的基础docker-compose.yml
文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 version: "3" networks: gitea: external: false services: server: image: gitea/gitea:1.14.2 container_name: gitea environment: - USER_UID=1000 - USER_GID=1000 restart: always networks: - gitea volumes: - ./gitea:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: - "3000:3000" - "222:22"
其中volumes
的挂载卷除第一个可修改外,其余不可修改,另外,本人选取的docker image tag
为latest
,建议参考官方给出的版本号tag
,其余设置按需修改端口号即可。
本人配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 version: "3" networks: gitea: external: false services: server: image: gitea/gitea:latest container_name: gitea environment: - USER_UID=1000 - USER_GID=1000 restart: always networks: - gitea volumes: - ./data:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: - "10081:3000" - "9022:9022"
修改完docker-compose.yml
文件后使用docker-compose
进行部署:
1 2 3 4 mkdir /app/giteacd /app/giteasudo docker-compose up -d sudo docker ps -a
如无意外应看到gitea
的container
运行起来了:
1 2 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7045e8aece99 gitea/gitea:latest "/usr/bin/entrypoint…" 2 days ago Up 2 hours 0.0.0.0:9022->9022/tcp, :::9022->9022/tcp, 0.0.0.0:10081->3000/tcp, :::10081->3000/tcp gitea
本人的Gitea已经部署很久了
接下来访问Gitea
,系统将要求你进行安装配置,输入配置完成安装后可进入Gitea
。
可以使用Sqlite3,当然也可以使用更好的MySQL以及Postgresql,本人在主机上安装了Postgresql并配置Gitea使用Postgresql
至此,Gitea
部署完成,如出现容器不断重启,请查看日志,并修改配置文件。
配置文件位于:
1 /app/gitea/data/gitea/conf/app.ini
你可以按照官方文档修改该配置文件直至容器可正常启动。
Deploy Drone With Docker Drone 先看官方文档:
Gitea | Drone
在Gitea
中登录管理员账号,然后创建一个OAuth2
程序。官方说的很清楚,你的回调URL应该为:
1 http[s]://domain[:port]/login
其中domain
可以为一个IP地址。完成后请保存secret
,它将在接下来的Drone部署
应用到。
按照官方给出的文档,使用docker可以直接部署一个基础的Drone
,命令如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 docker run \ --volume=/var/lib/drone:/data \ --env =DRONE_GITEA_SERVER={{DRONE_GITEA_SERVER}} \ --env =DRONE_GITEA_CLIENT_ID={{DRONE_GITEA_CLIENT_ID}} \ --env =DRONE_GITEA_CLIENT_SECRET={{DRONE_GITEA_CLIENT_SECRET}} \ --env =DRONE_RPC_SECRET={{DRONE_RPC_SECRET}} \ --env =DRONE_SERVER_HOST={{DRONE_SERVER_HOST}} \ --env =DRONE_SERVER_PROTO={{DRONE_SERVER_PROTO}} \ --publish=80:80 \ --publish=443:443 \ --restart=always \ --detach=true \ --name=drone \ drone/drone:1
但遗憾的是,官方未给出使用docker-compose
的yml
文件,因此我考虑先阅读完整个过程再自行编写docker-compose.yml
文件,根据上述的命令,可以写出以下的docker-compose.yml
文件:
注意:在该部署中,你需要完整的提供所有信息,包括域名等有效信息,暂时未发现可以直接修改配置文件等方式修改部署配置,因此如果信息有误,你必须删除该容器后重新启动容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 version: '3' services: drone: container_name: drone-server image: drone/drone:1 ports: - 10082 :80 volumes: - ./data:/data restart: always environment: - DRONE_GITEA_SERVER={{DRONE_GITEA_SERVER}} - DRONE_GITEA_CLIENT_ID={{DRONE_GITEA_CLIENT_ID}} - DRONE_GITEA_CLIENT_SECRET={{DRONE_GITEA_CLIENT_SECRET}} - DRONE_RPC_SECRET={{DRONE_RPC_SECRET}} - DRONE_SERVER_HOST={{DRONE_SERVER_HOST}} - DRONE_SERVER_PROTO={{DRONE_SERVER_PROTO}}
说明如下:
DRONE_GITEA_SERVER: 填写你的Gitea地址
,包含http(s),例如https://mygitea.com
DRONE_GITEA_CLIENT_ID: 方才在Gitea创建的OAuth2
程序中的客户端ID
DRONE_GITEA_CLIENT_SECRET: 方才在Gitea创建的OAuth2
程序中的客户端密钥
DRONE_RPC_SECRET: 你可以使用openssl生成一个和Runner
通信的密钥,命令为openssl rand -hex 16
,该密钥请同样留存
DRONE_SERVER_HOST: Drone的域名
,请不要书写协议,例如mydrone.com
DRONE_SERVER_PROTO: 服务协议,可选http
和https
,根据自己实际情况而定
在以上基础上,本人引入了Postgresql
作为Drone的数据库系统,因此还加入了部分配置,亦新建了Drone的管理员,整体配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 version: '3' services: drone: container_name: drone-server image: drone/drone:1 ports: - 10082 :80 volumes: - ./data:/data restart: always environment: - DRONE_GITEA_SERVER={{DRONE_GITEA_SERVER}} - DRONE_GITEA_CLIENT_ID={{DRONE_GITEA_CLIENT_ID}} - DRONE_GITEA_CLIENT_SECRET={{DRONE_GITEA_CLIENT_SECRET}} - DRONE_RPC_SECRET={{DRONE_RPC_SECRET}} - DRONE_SERVER_HOST={{DRONE_SERVER_HOST}} - DRONE_SERVER_PROTO={{DRONE_SERVER_PROTO}} - DRONE_DATABASE_DRIVER=postgres - DRONE_DATABASE_DATASOURCE=postgres://root:password@1.2.3.4:5432/postgres?sslmode=disable - DRONE_USER_CREATE=username:{{DRONE_ADMIN}},admin:true
说明的只有一个:
DRONE_ADMIN: Drone的管理员用户名
至于数据库配置请参照配置中的链接。
完成后,我们来进行Runner
的部署。
Drone Runner 我这里选用的是Docker Runner
,这对我而言更加易于使用。
官方文档:
Runner Overview | Drone
同样的,官方未给出docker-compose.yml
,因此还是照着命令书写,官方命令如下:
1 2 3 4 5 6 7 8 9 10 11 docker run -d \ -v /var/run/docker.sock:/var/run/docker.sock \ -e DRONE_RPC_PROTO=https \ -e DRONE_RPC_HOST=drone.company.com \ -e DRONE_RPC_SECRET=super-duper-secret \ -e DRONE_RUNNER_CAPACITY=2 \ -e DRONE_RUNNER_NAME=${HOSTNAME} \ -p 3000:3000 \ --restart always \ --name runner \ drone/drone-runner-docker:1
对应的docker-compose.yml
文件则为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 drone-docker-runner: container_name: drone-docker-runner image: drone/drone-runner-docker:1 ports: - 10011 :3000 restart: always depends_on: - drone volumes: - /var/run/docker.sock:/var/run/docker.sock environment: - DRONE_RPC_PROTO={{DRONE_SERVER_PROTO}} - DRONE_RPC_HOST={{DRONE_SERVER_HOST}} - DRONE_RPC_SECRET={{DRONE_RPC_SECRET}} - DRONE_RUNNER_CAPACITY=2 - DRONE_RUNNER_NAME=docker-runner
!此内容为节选,不是完整的文件内容
然后组合一下,完整的文件内容为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 version: '3' services: drone: container_name: drone-server image: drone/drone:1 ports: - 10082 :80 volumes: - ./data:/data restart: always environment: - DRONE_GITEA_SERVER={{DRONE_GITEA_SERVER}} - DRONE_GITEA_CLIENT_ID={{DRONE_GITEA_CLIENT_ID}} - DRONE_GITEA_CLIENT_SECRET={{DRONE_GITEA_CLIENT_SECRET}} - DRONE_RPC_SECRET={{DRONE_RPC_SECRET}} - DRONE_SERVER_HOST={{DRONE_SERVER_HOST}} - DRONE_SERVER_PROTO={{DRONE_SERVER_PROTO}} - DRONE_DATABASE_DRIVER=postgres - DRONE_DATABASE_DATASOURCE=postgres://root:password@1.2.3.4:5432/postgres?sslmode=disable - DRONE_USER_CREATE=username:{{DRONE_ADMIN}},admin:true drone-docker-runner: container_name: drone-docker-runner image: drone/drone-runner-docker:1 ports: - 10011 :3000 restart: always depends_on: - drone volumes: - /var/run/docker.sock:/var/run/docker.sock environment: - DRONE_RPC_PROTO={{DRONE_SERVER_PROTO}} - DRONE_RPC_HOST={{DRONE_SERVER_HOST}} - DRONE_RPC_SECRET={{DRONE_RPC_SECRET}} - DRONE_RUNNER_CAPACITY=2 - DRONE_RUNNER_NAME=docker-runner
随后,使用docker-compose
启动该容器。
1 2 3 4 mkdir /app/dronecd /app/dronesudo docker-compose up -d sudo docker ps -a
如无意外,你将看到两个容器正常启动;
1 2 3 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f14db02cd116 drone/drone-runner-docker:1 "/bin/drone-runner-d…" About an hour ago Up About an hour 0.0.0.0:10011->3000/tcp, :::10011->3000/tcp drone-docker-runner 247fe706b523 drone/drone:1 "/bin/drone-server" About an hour ago Up About an hour 443/tcp, 0.0.0.0:10082->80/tcp, :::10082->80/tcp drone-server
但是runner
不一定能正常启动,请使用日志判断是否正常:
1 sudo docker logs drone-docker-runner
当存在一下类似日志时,即表明正常:
1 time="2021-05-19T07:14:18Z" level=info msg="successfully pinged the remote server"
至此,Drone with Gitea部署
完成。
Drone CI/CD Example with hexo blog
说明:这个例子是为了解决一些未使用过Drone已经刚接触Drone不太熟悉Drone的人准备的,里面包含的问题大部分新手都可能遇到。
开始前,我们了解一下官方对pipeline
的解释:
Pipelines help you automate steps in your software delivery process, such as initiating code builds, running automated tests, and deploying to a staging or production environment.
Pipeline execution is triggered by a source code repository. A change in code triggers a webhook to Drone which runs the corresponding pipeline. Other common triggers include automatically scheduled or user-initiated workflows.
Pipelines are configured by placing a .drone.yml
file in the root of your git repository. The yaml syntax is designed to be easy to read and expressive so that anyone viewing the repository can understand the workflow.
翻译一下,大致意思就是流水线自动构建、测试以及部署你的服务,这一切依赖于文件.drone.yml
实现,来看一下一个pipeline
的例子:
1 2 3 4 5 6 7 8 9 10 kind: pipeline type: docker name: default steps: - name: greeting image: alpine commands: - echo hello - echo world
接下来对上面的一些字段解释:
kind 一般而言都是定义为流水线,即pipeline
,也可以定义为secret
和signature
,具体见文档Secrets | Drone 和Signatures | Drone
type 流水线类型,具体参考Drone的各类型Pipeline
name 为此次CI/CD指定名字
steps 在steps下指定若干个step执行流水线作业,其中一个流水线作业失败,整个流水线作业都将终止
然后来看看具体的单个step
应该怎么做:
定义单个step
非常简单,只需要指定它的name
和它的image
即可,这就是一个最简单的step
,但是该step
将什么都不做,如果需要进行操作,你需要配置commands
或者根据相应的插件配置对应的字段值
。
接下来我们将以一个Hexo Blog Build and Delploy
的例子来看看一个CI/CD
具体应该如何书写。
Step 1 - Clone 该代码仓库为Gitea
的Private Repo
,对于私有仓库,我们应该自主clone
,而不应该使用Drone
的Clone
过程,所以第一步我们禁用Drone Clone
,第二步使用git
的容器进行克隆。
则书写为下面的配置文件:
该文件内容来自于我真实的博客CI/CD
配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 kind: pipeline type: docker name: blog-pipeline clone: disable: true steps: - name: clone image: alpine/git environment: SSH_KEY: from_secret: SSH_KEY commands: - mkdir -p /root/.ssh/ - echo "$SSH_KEY" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - ssh-keyscan -p $SSH_PORT -t rsa $SSH_HOST >> ~/.ssh/known_hosts - git clone "ssh://git@$SSH_HOST:$SSH_PORT/evalexp/PentestBlog.git" .
不需要在普通命令中使用secret的变量,上面的除了SSH_KEY变量以外,请将SSH_PORT以及SSH_HOST修改为准确值。
在第一个clone
的step
中,我们使用了alpine/git
这个镜像来进行克隆。由于是私有仓库的克隆,因此,我们需要导入SSH 密钥
来进行克隆,这里的SSH 密钥
建议使用Gitea 部署密钥
,具体密钥生成方法参照Github以及Gitlab的Deploy Key
。
你应该注意到了,environment
实际上就是暴露给容器的环境变量,而from_secret
则是Drone
配置,你需要在Drone
中添加Secret
,这样才可以使用from_secret
获取这些变量的值,添加页面如下:
这样第一个克隆步骤就可以完成了。
Step 2 - Build 第二个步骤,构建这个博客。
这个step
相对简单,我们使用node
镜像利用npm install
等即可完成,此处不再赘述,配置如下:
完成后将生成的文件打包一下,以便传输
1 2 3 4 5 6 7 8 - name: generate image: node:16-alpine commands: - npm install hexo -g - npm install - node fix-image.js - hexo g - tar -czvf publish.tar.gz -C public .
Step 3 - Upload 这个步骤实际上用于将打包的文件上传到你的服务器上,我们使用Drone
的插件SCP
来完成这件事,插件用法可以去插件首页查看。
文件内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - name: scp file image: appleboy/drone-scp settings: host: from_secret: SSH_HOST username: from_secret: SSH_USER password: from_secret: SSH_PASSWORD port: from_secret: SSH_PORT target: /tmp source: - publish.tar.gz - deploy.sh
此处拷贝了发布文件的压缩包,以及部署脚本,部署脚本将在服务器上运行
Step 4 - Deploy 关于部署,自动化由脚本完成,Drone
的使命至此完成,在执行deploy.sh
后,整个CI/CD
便完成了,但是最关键的部署往往是最复杂的,请注意部署脚本的书写。
这是我的部署脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #!/bin/bash DEPLOY_DIR=/app/blog BACKUP_DIR=/home/evalexp/backups/blog USER_AND_GROUP=evalexp:evalexp if [ ! -d $DEPLOY_DIR ]; then mkdir -p $DEPLOY_DIR chown -R $USER_AND_GROUP $DEPLOY_DIR fi if [ ! -d $BACKUP_DIR ]; then mkdir -p $BACKUP_DIR chown -R $USER_AND_GROUP $BACKUP_DIR fi time=$(date +%Y-%m-%d-%H:%M) tar -czvf "$BACKUP_DIR /blog.$time .tar.gz" $DEPLOY_DIR rm -rf "$DEPLOY_DIR /*" tar -zxvf /tmp/publish.tar.gz -C $DEPLOY_DIR
使用该脚本部署将自动备份旧版本博客,并将发布包释放到部署目录,仅用于静态网站部署。
Web服务部署实际也差不多一致,在项目中书写好Dockerfile
,将jar
或者其余格式的文件挂载到宿主机,使用docker
停止容器,更换后继续启动容器即可。
由于在宿主机中执行脚本等,使用Drone
的SSH
插件来完成此次工作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 - name: deploy image: appleboy/drone-ssh settings: host: from_secret: SSH_HOST username: from_secret: SSH_USER password: from_secret: SSH_PASSWORD port: from_secret: SSH_PORT script: - bash /tmp/deploy.sh
这样就配置好了一个CI/CD
流水线作业,现在推送,让服务器自动构建,并部署到我们的服务器上。
如果你愿意配置,使用Docker hub
的镜像以及官方插件,你有无限的可能。