Gitea

简介

使用过git的开发者都知道,这是一个很好用的代码管理工具。

网上已有很多在线的git管理平台,如github、gitee等,但有一些限制,如:

  • 有成员人数限制。github免费的私有库最多3人,gitee为5人;
  • github网速慢;
  • 代码曝露在公网上(虽然可以设置私有库)

有时我们需要一款开源的、可搭在本地的可视化git产品。这里比较有名的就是Gitlab了,是面向企业的,但是其占用的资源也很大。

本文介绍的就是另一款轻量级产品:Gitea。

下文演示环境为虚拟机Centos 7.9,CPU架构为AMD(x86_64)(可用arch命令查看)。

阅读本文需要有Linux、Docker基础

安装

Gitea有多种安装方式,最简单的就是在官网https://dl.gitea.io/gitea下载源文件,然后在服务器端直接运行:

wget -O gitea https://dl.gitea.io/gitea/1.18/gitea-1.18-linux-amd64
chmod +x gitea
./gitea web

通过http://hostname:3000即可访问。

Gitea可选自带的SQLite3数据库,也可以选装其他性能好的,包括MySQL、PostgreSQL、MSSQL或 TiDB (MySQL协议) 等。
若用别的数据库,采用上述方式安装后,需要再额外安装数据库。

为了与Drone统一安装方式,更好地管理安装的产品,下文将展示通过Docker安装的方法。

安装项较多,整合了一个Gitea、Drone的安装脚本,参考最后一个章节快速安装。接下来的2个章节为该脚本的拆解。

Docker

经过多次的发展及命名变更,现在的docker分为社区版Community Edition (CE) 和 企业版Enterprise Edition (EE)。

我们这里使用开源的社区版。本节命令使用root用户执行,参考自官方网站Docker安装

卸载

如果系统里已安装旧版docker,想要升级的,先执行命令卸载:

echo ">>>>>>>>>>>>>>>>>>>>1.1 Stopping docker service"
systemctl stop docker.socket
systemctl stop docker.service
echo ">>>>>>>>>>>>>>>>>>>>1.2 Removing docker files"
rm -rf /etc/docker
rm -rf /run/docker
rm -rf /var/lib/dockershim
rm -rf /var/lib/docker

echo ">>>>>>>>>>>>>>>>>>>>1.3 Uninstalling docker rpms"
yum remove -y docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine \
docker-ce \
docker-ce-cli \
docker-ce-rootless-extras \
docker-scan-plugin \
container-selinux \
containerd.io \
docker-compose-plugin

安装

执行命令(社区版的docker包后缀为-ce):

echo ">>>>>>>>>>>>>>>>>>>>2.1 Installing docker"
yum -y install yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 验证安装
docker -v

启动

echo ">>>>>>>>>>>>>>>>>>>>3.1 Starting docker"
systemctl enable docker.service #开机自启
systemctl start docker.service

Gitea

Gitea不能以root用户运行,使用root用户执行本节命令,参考自官方网站Gitea安装

创建用户

useradd -g docker gitea

这里指定了用户组为docker(安装docker时自动创建的),这样用户gitea就可以直接使用docker相关命令

拉取镜像

后续使用mysql数据库,本处拉取2个镜像:

docker pull gitea/gitea
docker pull mysql
#查看所有镜像文件
docker images

创建容器目录

我们将所有容器映射到宿主机的目录放在一起,方便管理,大致目录结构:

image-20221222182435412

本小节开始,使用gitea用户执行后续命令。

mkdir -p ~/workspace/containers/gitea
mkdir -p ~/workspace/containers/mysql

创建配置文件

我们使用docker compose插件,通过配置文件来启停服务。

配置文件gitea-compose.yml放在~/workspace/containers下(文件名可自定义),内容:

version: "3"

networks:
  gitea:

services:
  server:
    image: gitea/gitea:latest
    container_name: gitea
    extra_hosts:
      <HOST_NAME>: <HOST_IP>
    environment:
      - USER_UID=<USER_UID>
      - USER_GID=<USER_GID>
      - GITEA__database__DB_TYPE=mysql
      - GITEA__database__HOST=db:3306
      - GITEA__database__NAME=gitea
      - GITEA__database__USER=gitea
      - GITEA__database__PASSWD=gitea
    restart: always
    networks:
      - gitea
    volumes:
      - ./gitea:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "13000:3000"
      - "13022:22"

    depends_on:
      - db

  db:
    image: mysql:latest
    container_name: mysql
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=gitea
      - MYSQL_USER=gitea
      - MYSQL_PASSWORD=gitea
      - MYSQL_DATABASE=gitea
    networks:
      - gitea
    volumes:
      - ./mysql:/var/lib/mysql

<HOST_NAME>、<HOST_IP>替换为宿主机域名、IP;

另有2处需要替换:<USER_UID>和<USER_GID>,值为gitea用户的ID及其用户组ID,可通过下述命令分别获取:

id -u gitea
id -g gitea

其他的密码、端口等设置,可自视情况调整。

启动服务

gitea用户下执行:

cd ~/workspace/containers
docker compose -f gitea-compose.yml up -d

至此,Gitea即可登录使用了!登录网址:http://hostname:13000

不使用-f参数指定文件时,docker compose命令会查找docker-compose.yml文件

使用

首次登录

首次打开登录页,会弹出初始配置。

第一部分是数据库,根据gitea-compose.yml中的设置已自动填入:

image-20221223170238120

下划页面可以看到一般设置:

image-20221223180848970

划到最后的可选设置,我们创建一个管理员账号:

image-20221223175243288

最后点击立即安装即可,过几秒会自动跳转至首页(如果未跳转或页面报错,刷新下页面):

image-20221223181048386

使用设置

个人设置

点击页面右上角的个人链接:

image-20221223181549542

可以设置个人的一些相关信息:
image-20221223181720744

创建组织

可以创建一个组织,将某个项目上的代码仓库、开发人员归入该组织进行管理。

点击左上角的用户名,选择创建组织:

image-20221224161856437

输入组织名,并根据需要选择组织可见性:

image-20221224161953427

点击创建组织后,首页变更为当前组织:

image-20221224162212658

点击右上角的访问按钮,弹出组织的相关信息:

image-20221224162244944

可以看到,当前还没有仓库,组织成员、组织团队都仅1个,即创建者。

Owners团队是组织的管理者,可以设置组织团队、组织下的仓库。

可以由各开发员登录Gitea时自己注册账户,也可以由管理员在"管理后台"的"帐户管理"页签创建。

分支保护

创建了仓库后,点击仓库名可以进入仓库界面,点击右侧的设置,选择分支:

image-20221224163542917

勾选"启用分支保护"即可,该分支的代码则只支持合并:

image-20221224163626702

持续发布

现有的持续发布/持续集成产品有很多,这里贴上部分流行的CICD工具对比图:

image-20221224171826137

下文中,我们将演示使用Drone完成持续发布。

安装Drone

参考官方文档Drone Server安装

拉取镜像

执行docker命令拉取drone及其docker类型runner的镜像:

docker pull drone/drone
docker pull drone/drone-runner-docker

配置

OAuth2

OAuth2的用处:登录某网站时,不用该网站账号,而是第三方账号,例如有些网站可以直接微信登录。

在Gitea上创建OAuth2应用,使Drone可以直接使用Gitea账户登录。

在个人设置的"应用"页签,填写应用名称及重定向URI(URI为Drone的登录地址,端口在后续设置中会引用到):

image-20221224173218879

暂存生成的客户端ID及其秘钥:

image-20221224173334670
通信秘钥

在Drone服务端和运行端之间的通信秘钥,执行命令:

openssl rand -hex 16

暂存该命令生成的16位随机码

配置文件

在服务器gitea用户的~/workspace/containers目录下创建配置文件drone-compose.yml:

version: "3"

services:
  drone-server:
    image: drone/drone:latest
    container_name: drone-server
    restart: always
    ports:
      - "13080:80"
    extra_hosts:
      <HOST_NAME>: <HOST_IP>
    volumes:
      - ./drone:/data
    environment:
      - DRONE_GITEA_SERVER=http://<HOST_NAME>:13000
      - DRONE_GITEA_CLIENT_ID=<CLIENT_ID>
      - DRONE_GITEA_CLIENT_SECRET=<CLIENT_SECRET>
      - DRONE_RPC_SECRET=<RPC_SECRET>
      - DRONE_SERVER_HOST=<HOST_NAME>:13080
      - DRONE_SERVER_PROTO=http
      - DRONE_GIT_ALWAYS_AUTH=true
      - DRONE_USER_CREATE=username:<GITEA_USERNAME>,admin:true

  drone-runner:
    image: drone/drone-runner-docker:latest
    container_name: drone-runner
    restart: always
    ports:
      - "13010:3000"
    extra_hosts:
      <HOST_NAME>: <HOST_IP>
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - TZ="Asia/Shanghai"
      - DRONE_RPC_HOST=<HOST_NAME>:13080
      - DRONE_RPC_PROTO=http
      - DRONE_RPC_SECRET=<RPC_SECRET>
      - DRONE_RUNNER_NAME=drone-runner
      - DRONE_RUNNER_CAPACITY=2

替换该配置文件中的:

  • <HOST_NAME>:运行Drone的宿主机域名
  • <HOST_IP>:运行Drone的宿主机IP
  • <CLIENT_ID>、<CLIENT_SECRET>:Gitea上生成的OAuth2 ID
  • <RPC_SECRET>:上一步生成的通信秘钥
  • <GITEA_USERNAME>:Gitea帐户名
启动

修改完配置文件后,在同目录下创建子目录drone,然后启动Drone服务:

docker compose -f drone-compose.yml up -d

进入登录页http://hostname:13080/

image-20221225103110268

点击CONTINUE按钮,会跳转Gitea认证页面:
image-20221225103219769

点击应用授权后,自动跳转回Drone注册页:

image-20221225145539112

输入Gitea帐户的邮箱、用户名即可,点击SUBMIT,会跳转至Drone首页:

image-20221225145647685

首页列出了Gitea账户下的仓库,点击仓库名,跳转其设置页面:

image-20221225145735029

启用Trusted,然后保存即可:
image-20221225152354182

同时,可以在Gitea的该仓库设置中,看到Web钩子中多了一项:

image-20221225152816098

使用

简单例子

在仓库根目录创建文件".drone.yml",内容:

kind: pipeline
type: docker
name: Test

clone:
  disable: true

steps:
  - name: test
    pull: if-not-exists
    image: alpine
    commands:
      - whoami
      - pwd

保存后,会自动触发一次构建,但是会失败。在Web钩子的设置界面:

image-20221225155307831

划到最后,可以看到构建记录:

image-20221225155349541

图里的报错是因为未将Drone服务器加进Gitea的Web钩子白名单。

添加白名单

编辑Gitea容器的设置文件app.ini(<Gitea容器映射在宿主机的目录>/gitea/conf/app.ini,本文即为~/workspace/containers/gitea/gitea/conf/app.ini),添加:

[webhook]
ALLOWED_HOST_LIST = <宿主机Host>

重启Gitea容器:

docker compose -f gitea-compose.yml down
docker compose -f gitea-compose.yml up -d

点击上图测试按钮下的刷新图标,重新触发,可以看到构建成功:

image-20221225161835475

在Drone页面也可以看到成功记录:

image-20221225161919549

点击仓库名后:

image-20221225162006688

点开第二次构建:

image-20221225162124988

可以看到左侧是我们定义的构建名(Test)和步骤名(test),右侧是执行的命令及对应结果。

因为是第一次触发构建,本地没有alpine镜像,日志中显示了其下载记录。

EBS

概述

前面演示的简单案例中,用的是Docker类型通道完成构建,也就是每个步骤都会引用一个镜像来执行对应步骤。
各步骤之间共享一个虚拟目录/drone/src,在构建结束后,该目录会删除。

为了将增量代码发布到多个环境中去,找了很多镜像,没有找到比较合适的,要么会导致.drone.yml文件变得臃肿,要么不支持ssh到目标环境调用脚本时传参。
翻阅官方资料后,最终决定改用EXEC类型的通道,直接在宿主机端执行自定义脚本来完成构建。

下述自动部署的实现效果及主体逻辑:

  • 获取增量代码
    • 在宿主机执行git diff命令获取增量代码
  • 发布到指定环境
    • 在.drone.yml中配置,每个环境配置一个步骤
    • 在步骤中执行同样的脚本,将增量代码发送到目标环境,并在目标环境调用指定脚本。
      这里使用sshpass命令,可以免交互的调用scp、ssh等命令
      当然,要是运行Drone的宿主机,添加到了目标环境的authorized_keys中,可以不安装sshpass命令。
  • 更新配置文件
    • 前面步骤成功后,将触发本次构建的git提交ID更新入配置文件,以供下次获取增量代码使用

按照上述逻辑,需要安装:

  • EXEC类型的Runner
  • git命令
  • sshpass命令

本方法有个弊端,就是要自开发大量的脚本,对开发者来说是个不小的挑战。

安装

EXEC Runner

参考官方文档Exec Runner安装,目前尚未发布正式版:

image-20221231163224472

root用户执行:

wget https://github.com/drone-runners/drone-runner-exec/releases/download/v1.0.0-beta.10/drone_runner_exec_linux_amd64.tar.gz
tar -xzvf drone_runner_exec_linux_amd64.tar.gz
install -t /usr/local/bin drone-runner-exec
mkdir /etc/drone-runner-exec
mkdir /var/log/drone-runner-exec

在/etc/drone-runner-exec下创建配置文件config:

DRONE_RPC_PROTO=http
DRONE_RPC_HOST=<HOST_NAME>:13080
DRONE_RPC_SECRET=<RPC_SECRET>
DRONE_LOG_FILE=/var/log/drone-runner-exec/log.txt
DRONE_LOG_FILE_MAX_SIZE=10
DRONE_LOG_FILE_MAX_AGE=30
DRONE_UI_USERNAME=drone
DRONE_UI_PASSWORD=drone

替换<HOST_NAME>、<RPC_SECRET>,与drone-compose.yml中一致。
本配置文件设定了Drone Server信息、日志路径、日志单个文件大小(单位:M)、日志保留天数、可视化界面的登录用户及密码。

然后启动:

drone-runner-exec service install
drone-runner-exec service start
#查看日志
tail -10 /var/log/drone-runner-exec/log.txt

可以从日志中看到成功连接到Server:

image-20221225170520325

服务器命令

安装git、sshpass

yum -y install git
yum -y install sshpass
简单案例

修改.drone.yml为:

kind: pipeline
type: exec
name: Test

clone:
  disable: true

steps:
  - name: test
    commands:
      - whoami
      - pwd

提交后,可以看到Drone中成功构建:

image-20221225170918753

EBS自动部署

配置ssh

gitea用户下执行(替换自己的邮箱):

ssh-keygen -t rsa -C "xx@qq.com"
cat /home/gitea/.ssh/id_rsa.pub

将id_rsa.pub的内容复制到Gitea的账户设置下:

image-20221225172745557

点击验证:

image-20221225172821210

按提示执行命令(注意将命令最后的路径替换为ssh key的路径,默认为~/.ssh):

image-20221225172848861

操作要快一点,防止超时。

演示环境的ssh命令版本较低,不支持上图中的-Y参数。如果升级ssh,步骤繁琐,而且影响很大,可以切到gitea容器内执行。

cp ~/.ssh/id_rsa* ~/workspace/containers/gitea/gitea #将ssh秘钥复制到容器目录下
docker exec -it gitea bash #进入容器
cd /data/gitea #进入复制有ssh秘钥的gitea目录
echo -n 'xxxx' | ssh-keygen -Y sign -n gitea -f id_rsa #执行上图中的签名命令
rm id_rsa* #删除秘钥

gitea帐户执行:

git clone <ssh url>

主要是为了建立host认证,后续自动部署时不失败:

image-20221225235441293

克隆后,可以删除仓库目录。

部署目录

下载docker/workspace/deploy目录(点此下载),上传到gitea用户的~/workspace下

image-20221231215952490
.drone.yml
kind: pipeline
type: exec
name: Test For EBS Deploy

clone:
  disable: true

steps:
  - name: Generate Incremental Codes
    commands:
      - su - gitea -c "bash ~/workspace/deploy/scripts/01_GenIncrementalCodes.sh $DRONE_GIT_SSH_URL $DRONE_REPO_NAME $DRONE_BRANCH $DRONE_COMMIT"

  - name: Deploy Codes In DEV
    environment:
      TARGET_HOST: 172.16.135.143
      TARGET_USER: strive
      TARGET_PSWD: xxxxxx
      TARGET_PORT: 22
      APPS_PSWD: APPS
      CUX_PSWD: CUX
    commands:
      - su - gitea -c "bash ~/workspace/deploy/scripts/02_SendAndInstall.sh $TARGET_HOST $TARGET_USER $TARGET_PSWD $TARGET_PORT $APPS_PSWD $CUX_PSWD $DRONE_COMMIT"

  - name: Deploy Codes In SIT
    environment:
      TARGET_HOST: 172.16.135.141
      TARGET_USER: strive
      TARGET_PSWD:
        from_secret: SIT_STRIVE_PSWD
      TARGET_PORT: 22
      APPS_PSWD: APPS
      CUX_PSWD: CUX
    commands:
      - su - gitea -c "bash ~/workspace/deploy/scripts/02_SendAndInstall.sh $TARGET_HOST $TARGET_USER $TARGET_PSWD $TARGET_PORT $APPS_PSWD $CUX_PSWD $DRONE_COMMIT"

  - name: Reset Config
    commands:
      - su - gitea -c "bash ~/workspace/deploy/scripts/03_ResetConfig.sh $DRONE_COMMIT"

上面的.drone.yml中,设置了四个步骤:

获取增量代码
su - gitea -c "bash ~/workspace/deploy/scripts/01_GenIncrementalCodes.sh $DRONE_GIT_SSH_URL $DRONE_REPO_NAME $DRONE_BRANCH $DRONE_COMMIT"

这里切换到gitea用户,并调用脚本01_GenIncrementalCodes.sh,传入参数:GIT仓库克隆路径、仓库名、分支名、提交ID。
DRONE开头的这些变量是Drone自带的,全部变量可在任意步骤下调用env命令,然后在构建日志中查看。

获取增量代码的脚本01_GenIncrementalCodes.sh:

set -e
echo "------------------1. Setting parameters value------------------"
DRONE_GIT_SSH_URL=$1
DRONE_REPO_NAME=$2
DRONE_BRANCH=$3
DRONE_COMMIT=$4

echo "------------------2. Sychronizing repository------------------"
cd ~/workspace/deploy/repository
if [ -e $DRONE_REPO_NAME ]; then
    echo ">>>>>>>>>>>>>>>>Pulling Repository"
    cd $DRONE_REPO_NAME
    git pull --progress -v --no-rebase origin
else
    echo ">>>>>>>>>>>>>>>>Clonning Repository"
    git clone $DRONE_GIT_SSH_URL
    cd ./$DRONE_REPO_NAME
fi

echo "------------------3. Checkouting trigger branch------------------"
git checkout -B $DRONE_BRANCH origin/$DRONE_BRANCH
git branch

echo "------------------4. Getting last commit ID------------------"
source ~/workspace/deploy/config/deploy.cfg
if [ -z "$LAST_COMMIT_ID" ]; then
    echo "Getting First Commit ID"
    LAST_COMMIT_ID=$(git log --oneline --format='%h' | tail -1)
fi
echo "LAST_COMMIT_ID=$LAST_COMMIT_ID"
echo ""

echo "------------------5. Generating incremental codes------------------"
CURRENT_TIME=$(date "+%Y%m%d%H%M")
echo "Adding new directory: $CURRENT_TIME"
mkdir ~/workspace/deploy/codes/$CURRENT_TIME
git archive --format=zip -o ~/workspace/deploy/codes/$CURRENT_TIME/IncrementalCodes.zip HEAD $(git diff $LAST_COMMIT_ID..$DRONE_COMMIT --name-only)
cp ~/workspace/deploy/scripts/install* ~/workspace/deploy/codes/$CURRENT_TIME
sed -i "s/\(INSTALLING_DIR=\)\(.*\)/\1$CURRENT_TIME/" ~/workspace/deploy/config/deploy.cfg

这里的逻辑大致为:

  1. 接收调用时传入的参数值;

  2. 判断~/workspace/deploy/repository下有无触发构建的仓库名目录,无则克隆仓库,有则拉取最新代码;

  3. 切换到触发构建的分支

  4. ~/workspace/deploy/config/deploy.cfg中存储的是键值对:

image-20221231165822250 通过source命令,将上次构建的最新提交ID读至变量LAST_COMMIT_ID; 若为空,则通过命令"git log --oneline --format='%h' | tail -1"获取第一次提交ID
  1. 获取增量代码
  • 获取当前时间(格式为"年月日时分"),存入变量CURRENT_TIME,并创建目录~/workspace/deploy/codes/$CURRENT_TIME;

  • 根据上次提交ID及本次提交ID,通过命令git diff导出增量代码,放到上步的目录中;

  • 将EBS代码安装脚本install.pl、install.cfg一起复制到~/workspace/deploy/codes/$CURRENT_TIME

  • 将配置文件中INSTALLING_DIR对应的值置为变量CURRENT_TIME的值

部署至DEV环境
  1. 首先是设置了几个环境变量:
    environment:
      TARGET_HOST: 172.16.135.143
      TARGET_USER: strive
      TARGET_PSWD: xxxxxx
      TARGET_PORT: 22
      APPS_PSWD: APPS
      CUX_PSWD: CUX

这里列出了要部署到的环境信息,包括IP、用户、密码、数据库用户密码(APPS、CUX)。
注意不能有空值,测试时发现给空时,构建会卡住无反应,日志也无报错。

  1. 然后是在目标环境安装增量代码:
su - gitea -c "bash ~/workspace/deploy/scripts/02_SendAndInstall.sh $TARGET_HOST $TARGET_USER $TARGET_PSWD $TARGET_PORT $APPS_PSWD $CUX_PSWD $DRONE_COMMIT"

脚本02_SendAndInstall.sh:

set -e
echo "------------------1. Setting parameters value------------------"
# 接收脚本参数
TARGET_HOST=$1
TARGET_USER=$2
TARGET_PSWD=$3
TARGET_PORT=$4
APPS_PSWD=$5
CUX_PSWD=$6
DRONE_COMMIT_ID=$7
source ~/workspace/deploy/config/deploy.cfg

# Shell变量名中不可出现".",替换TARGET_HOST中的"."为"_"
REPLACED_HOST="H${TARGET_HOST//./_}"
echo "Replaced HOST: $REPLACED_HOST, Current commit ID: ${!REPLACED_HOST}, Drone commit ID: $DRONE_COMMIT_ID"

# 当前TARGET_HOST的提交ID与触发部署的提交ID不一致时
if [ ! "${!REPLACED_HOST}" == $DRONE_COMMIT_ID ]; then
    echo "------------------2. Sending codes to $TARGET_USER@$TARGET_HOST------------------"
    sshpass -p $TARGET_PSWD ssh -o StrictHostKeyChecking=no -p $TARGET_PORT $TARGET_USER@$TARGET_HOST "[ ! -e ~/workspace ] && mkdir ~/workspace"
    sshpass -p $TARGET_PSWD scp -P $TARGET_PORT -r ~/workspace/deploy/codes/$INSTALLING_DIR $TARGET_USER@$TARGET_HOST:~/workspace

    echo "------------------3. Calling remote install script------------------"
    sshpass -p $TARGET_PSWD ssh -p $TARGET_PORT $TARGET_USER@$TARGET_HOST "cd ~/workspace/$INSTALLING_DIR/; bash install.sh $APPS_PSWD $CUX_PSWD"

    echo "------------------4. Setting new commit ID------------------"
    # 远程机HOST不存在于配置文件中时,加一行
    if [ ! "${!REPLACED_HOST}" ]; then
        echo "$REPLACED_HOST=$DRONE_COMMIT_ID" >> ~/workspace/deploy/config/deploy.cfg

    # 存在时,替换
    else  
        sed -i "s/\($REPLACED_HOST=\)\(.*\)/\1$DRONE_COMMIT_ID/" ~/workspace/deploy/config/deploy.cfg
    fi

# 当前TARGET_HOST的提交ID与触发部署的提交ID一致时,跳过处理
else
    echo ">>>>>>>>>>>>>Already deployed successfully, skip left steps."
fi

这里的逻辑大致为:

  1. 初始化:
  • 接收调用时传入的参数值;
  • 调用source命令,将部署配置文件(~/workspace/deploy/config/deploy.cfg)中的值赋到对应环境变量;
    此配置中存放了各环境的已部署的提交ID,各目标环境键值为H+IP:
    image-20221231171356161
  • 因为环境变量名不能以数字开头,也不能包含点,所以用H拼在开头,IP中的"."也替换成"_"

若已部署的提交ID与此次触发构建的提交ID一致,则跳过剩余步骤,否则继续:

  1. 发送代码:
    • 调用ssh命令,在远程环境用户的主目录下创建workspace目录;
      给定参数-o StrictHostKeyChecking=no,自动添加目标环境host至本机的~/.ssh/known_hosts中;
    • 调用scp命令将增量代码及其安装脚本,发送到目标环境用户的~/workspace下
  2. 调用ssh命令,调用目标环境的install.sh命令,完成代码安装;
  3. 因为前面调用了set -e,安装失败时会直接中断构建;
    若安装成功,则更新此环境部署的提交ID至部署配置文件(~/workspace/deploy/config/deploy.cfg)

install.sh:

前面通过ssh命令在目标环境运行了安装脚本,该脚本内容为:

# 1. 获取配置信息
GetConfig(){
	# 任意一行代码出错则退出
	set -e
	echo "  >>>>>>>>>>>>>>>>>>>>>>>>3.1 Setting parameters value>>>>>>>>>>>>>>>>>>>>>>>>"

	# 初始化上下文
	#source ~/.bash_profile

	# 接收参数传入的APPS/CUX密码
	APPS_PSWD=$1
	CUX_PSWD=$2

	# 设置文件变量
	CURRENT_DIR=$(cd `dirname $0`; pwd)
	CFG_FILE=$CURRENT_DIR/install.cfg
	LOG_FILE=$CURRENT_DIR/install.log
	ERR_FILE=$CURRENT_DIR/install.err
	echo "" > $LOG_FILE
	
	# 解压代码文件
	mkdir code
	unzip -q -d ./code IncrementalCodes.zip
}

# 2. 批量安装(若代码结构不是标准的objectlist,可修改此处)
BatchInstall(){
	echo "  >>>>>>>>>>>>>>>>>>>>>>>>3.2 Installing>>>>>>>>>>>>>>>>>>>>>>>>"
	for loop_num in 1
	do
		sleep 1
		#perl install.pl installpath=$CURRENT_DIR cfgfile=$CFG_FILE appsusr=APPS appspwd=$APPS_PSWD dbschemapwd=$CUX_PSWD logfile=$LOG_FILE
	done
}

# 3. 导出报错内容
ExpErrorMsg(){
	echo "  >>>>>>>>>>>>>>>>>>>>>>>>3.3 Exporting error file>>>>>>>>>>>>>>>>>>>>>>>>"
	STEP_NAME=""
	STEP_FLAG=true
	ERROR_FLAG=false
	ERROR_MSG=""

	# 遍历行读取日志文件install.log
	while read ROW_CONTENT
	do
		# 读到每个大类(表、包头、Form等)开始安装的日志时,写入上个脚本执行结果、初始化错误标志、记录当前大类
		if [[ "$ROW_CONTENT" =~ ^"# install step".* ]]; then
			WriteErrorMsg
			STEP_NAME=$ROW_CONTENT
			STEP_FLAG=false
		
		# SQL类脚本,若有非ORA-00955(同名创建)错误或SP2开头错误,标记出错
		elif [[ ("$ROW_CONTENT" =~ ^ORA-.* && ! "$ROW_CONTENT" =~ ^ORA-00955.*) || "$ROW_CONTENT" =~ ^SP2-.* ]]; then
			ERROR_FLAG=true

		# 程序包编译失败,标记出错
		elif [[ "$ROW_CONTENT" =~ ^"created with compilation errors".* ]]; then
			ERROR_FLAG=true
		
		# Form编译失败,标记出错
		elif [[ "$ROW_CONTENT" =~ ^"Form not created".* ]]; then
			ERROR_FLAG=true
		
		# SQL类脚本开始执行,写入上个脚本执行结果,并初始化错误标志
		elif [[ "$ROW_CONTENT" =~ ^run.* ]]; then
			WriteErrorMsg
		
		# Form开始编译,写入上个脚本执行结果,并初始化错误标志
		elif [[ "$ROW_CONTENT" =~ ^frmcmp_batch.* ]]; then
			WriteErrorMsg
		fi
		
		# 拼接单个脚本的执行日志
		ERROR_MSG="$ERROR_MSG$ROW_CONTENT\n"
	done < $LOG_FILE
	
	# 最后一个脚本执行结果处理
	WriteErrorMsg

	# 如果错误日志大小不为0,则有错误,返回错误码
	if [ -s "$ERR_FILE" ] ; then
		echo "Installation failed:"
		cat $ERR_FILE
		exit 1
	fi
}

# 3.1-错误信息写入文件
WriteErrorMsg(){
	# 若由错误
	if [ $ERROR_FLAG = true ]; then
		# 若大类未写入错误文件,则先写入
		if [ $STEP_FLAG != true ]; then
			echo "$STEP_NAME" >> $ERR_FILE
			STEP_FLAG=true
		fi
		
		# echo -e,转义后文本,即有换行
		# 将脚本及报错内容写入错误文件
		echo -e "$ERROR_MSG" | while read TMP_MSG
		do
			echo "$TMP_MSG" >> $ERR_FILE
		done
		echo "------------------------------------------" >> $ERR_FILE
	fi
	
	# 重置错误标记
	ERROR_FLAG=false
	ERROR_MSG=""
}

GetConfig $1 $2 # 1. 获取配置信息
BatchInstall # 2. 批量安装
ExpErrorMsg # 3. 导出报错内容

大致逻辑就是:

  • 读取被调用时传入的参数值;
  • 调用perl install.pl 执行EBS代码安装;
  • 读取安装日志install.log,判断有无数据库对象(表、视图、包等)编译错误、Form编译失败,有则返回错误状态1

这里为了模拟测试通过,注释掉了source ~/.bash_profile和perl install.pl命令,实际使用时需放开。

部署至SIT环境

与部署至DEV环境一致,为了测试多个环境而添加的步骤。

类似的,若项目上有多个环境,复制一份此步内容,修改对应环境信息即可。

设置配置文件

最后一步,将本次触发构建的提交ID更新回设置文件

# 全部环境部署成功后,更新配置文件中的提交ID
set -e
DRONE_COMMIT=$1
sed -i "s/\(LAST_COMMIT_ID=\)\(.*\)/\1$DRONE_COMMIT/" ~/workspace/deploy/config/deploy.cfg
优化设置
密码设置

在前面演示的.drone.yml中,部署至SIT环境的步骤里使用了from_secret:

  - name: Deploy Codes In SIT
    environment:
      ...
      TARGET_PSWD:
        from_secret: SIT_STRIVE_PSWD

这里是将密码设置在了Drone中:

image-20221231174951573

同样的,使用到密码的地方都推荐使用此种方式,防止明文配置密码,导致泄露。

触发条件

搭建好的Web钩子默认是全分支、全事件触发的,项目上实际使用时,不用这么频繁,设置为特定分支变动时触发即可。

打开Web钩子设置:

image-20221226101823971

下划到事件设置:

image-20221226101924348

只保留"推送"事件,指定特定分支。
点击最下方的"更新钩子"按钮保存修改。

分支保护

启用触发构建分支的保护,并设置审批白名单。

在前面介绍过的分支保护设置中,下划到审批白名单:

image-20221226102346628

"所需的批准"为必要的审批人数;
批准的用户或团队里,可以单独设置审批人,或专门建立一个审批团队:组织的团队里再新建一个团队,然后加入到协作者:

image-20221226102617037

审批路径:

image-20221226103130716
操作人员

包括项目管理者在内,不设置在组织的Owners团队中,因为有超级权限,可以越过审批直接合并。
为防止误操作,管理员账户非必要不使用,每个人单独创建自己的账号。

至此,可以模拟项目开发场景:

  • 每个开发员创建各自开发分支,推送到远程仓库;
  • 每个开发员发起合并到指定分支;
  • 管理者从指定分支发起合并到触发构建的分支,因为加了审批人,需要额外一步审批操作,防止误点;
  • 审批后,点击合并,自动触发构建
构建样例

测试时的构建日志,增量代码生成:

image-20221226103809312

已部署过,不再处理:
image-20221226103925697

未部署过,触发部署:

image-20221226103942823

最后更新配置文件:

image-20221226104000460

若某步出错,则会中断构建:

image-20221226104037910

修正后,可以点击右上角的Restart来重新构建:

image-20221226104237814

快速安装

为了简化Gitea安装、Drone安装、自动部署设置,此处提供了快速安装脚本。
脚本内容为前2个章节中可自动化安装步骤的合并。

下载自动部署包及目录,点此进入下载

因为一个脚本包含了多项安装步骤,提高了问题出现概率,若某步出现问题,可在解决后,手动复制剩余命令执行。

在线安装

若是服务器可以访问外网,将下载好的目录直接上传至服务器/tmp下,然后以root用户运行安装:

bash /tmp/install-online.sh

离线安装

有些项目的服务器不允许曝露至外网的,就需要将安装包提前打好后再安装。

这里还是要依赖一台同配置可访问外网的服务器。

下载依赖包

依赖包的处理很麻烦,还是通过yum命令自动处理。运行下述命令,仅下载安装包及其依赖:

mkdir /tmp/rpms
yum -y install yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install --downloadonly --downloaddir=/tmp/rpms docker-ce docker-ce-cli containerd.io docker-compose-plugin
wget -P /tmp/rpms https://github.com/drone-runners/drone-runner-exec/releases/download/v1.0.0-beta.10/drone_runner_exec_linux_amd64.tar.gz

若wget速度较慢,可使用网盘中的版本,或尝试进入github页面手动下载。
将/tmp/rpms下的文件放到从网盘下载到本地的docker/rpms下:

image-20221231221512941

导出镜像

在装有Docker的服务器上,导出镜像文件:

docker pull gitea/gitea
docker pull mysql
docker pull drone/drone
docker pull drone/drone-runner-docker

docker save gitea/gitea:latest | gzip > gitea.tar.gz
docker save mysql:latest | gzip > mysql.tar.gz
docker save drone/drone:latest | gzip > drone_server.tar.gz
docker save drone/drone-runner-docker:latest | gzip > drone_runner.tar.gz

将导出的四个镜像文件放到从网盘下载到本地的docker/rpms下:

image-20221231221947469

或者使用网盘中的版本,为截止2022-12-25的官方最新版本

安装

上传完整的docker目录及安装脚本install-offline.sh至服务器/tmp下,然后root用户运行:

bash /tmp/install-offline.sh

后续设置

前面的安装脚本执行完后,即可登录Gitea,然后进行配置:

关于Drone:

然后在Gitea仓库中添加.drone.yml即可。

posted @ 2022-12-29 22:13  水木夏  阅读(1718)  评论(3编辑  收藏  举报