Drone 是一款基于Docker的CI工具,不仅运行环境是容器化的,甚至于 CI 流中的每一个插件也是 docker 容器。基于容器的 Drone 插件一大特色就是允许我们使用任何语言去开发插件,Python, PHP, Nodejs, bash… 这些都是可以的。每个开发者都可以使用自己熟悉的语言去开发自己想要的插件。Drone 的官方插件市场罗列了很多插件,并且在文档提供了 Golang 和 Bash 版本的插件开发文档,并开源了一个插件脚手架。
官方插件里有一个 drone-telegram 插件,不过插件目前是不支持自定义 telegrame 请求地址的,对于我这种机器部署在国内需要使用反代的方式访问 telegram 的用户来说不是很方便。搜索到 node-telegram-api 这个模块可以配置,下面我就简单说说基于 Nodejs 写一个 telegram 消息通知的插件。
原理
Docker 容器在启动的时候可以设置一个启动命令,这样我们就可以做到实例化插件容器的时候就执行插件脚本。另外 Drone 运行插件的时候会将本次 CI 构建相关的信息以及插件配置信息以环境变量的形式注入到插件容器实例中。所有的语言都是可以去读取系统环境变量的,这也让其支持所有语言成为了可能。
- 插件配置会以
PLUGIN_xxx
的形式注入,例如PLUGIN_TOKEN
。 - 构建相关的信息会以
CI_xxx
或者DRONE_xxx
的形式注入,例如DRONE_COMMIT
,CI_COMMIT_AUTHOR_NAME
。
编写插件
编写插件很简单,只需要注意需要获取的配置使用 PLUGIN_
获取即可,例如 telegram 需要使用的 PLUGIN_TOKEN
等。下面是具体的插件代码:
const render = require('drone-render');
const TelegramBot = require('node-telegram-bot-api');
const {
PLUGIN_TOKEN,
PLUGIN_TO,
TELEGRAM_TOKEN,
TELEGRAM_TO,
PLUGIN_LANG,
PLUGIN_MESSAGE,
PLUGIN_BASE_API_URL
} = process.env;
const TOKEN = PLUGIN_TOKEN || TELEGRAM_TOKEN;
const TO = PLUGIN_TO || TELEGRAM_TO;
if(PLUGIN_LANG) {
render.locale(PLUGIN_LANG);
}
const bot = new TelegramBot(TOKEN, {
baseApiUrl: PLUGIN_BASE_API_URL
});
bot.sendMessage(TO, render(PLUGIN_MESSAGE));
可以看到其实代码非常的简单。
Dockerfile
插件写好之后就需要创建 Dockerfile 文件制作镜像了。由于 Dockerfile 的每一个指令都会为容器创建一个layer,所以这里有个小技巧是将 npm install
依赖安装这种不怎么会变化的操作提前,频繁变化的插件脚本的拷贝置后。这样在多次打包发布的时候会占优势,仅仅只会传后面变化的部分,减小传输体积。
FROM mhart/alpine-node:8.9.3
WORKDIR /telegram-node
COPY package.json /telegram-node/package.json
RUN npm install
COPY index.js /telegram-node/index.js
ENTRYPOINT [ "node", "/telegram-node/index.js" ]
最后就是编译并发布我们的 docker 容器以供其它人方便使用:
docker build lizheming/drone-telegram-node .
docker push lizheming/drone-telegram-node
测试
本地使用如下命令启动镜像即可测试插件是否工作
docker run --rm \
-e PLUGIN_TOKEN=xxxxxxx \
-e PLUGIN_TO=xxxxxxx \
-e PLUGIN_MESSAGE=test \
-e PLUGIN_BASE_API_URL=xxxx \
lizheming/drone-telegram-node
问题
secrets 参数获取
经常有些密钥之类的参数不想写在 .drone.yml
配置文件中暴露给所有项目可见的用户,这时候我们就会使用 drone secrets 添加变量,具体可参考我之前写的文章《如何使用Drone》。这里需要注意的是 secrets 定义的变量名即最后 drone 注入进入的环境变量名称,所以不能随意使用。例如你的配置是:
pipline:
telegram:
image: lizheming/drone-telegram-node
secrets: [ telegram_token, telegram_to ]
message: hello
最后你在插件内部就能使用 process.env.TELEGTAM_TOKEN
来获取对应的密钥变量。
插件不生效
在编写插件的时候我碰到的一个问题是我最开始的 Dockerfile 是如下这样的:
FROM mhart/alpine-node:8.9.3
WORKDIR /telegram-node
COPY package.json /telegram-node/package.json
RUN npm install
COPY index.js /telegram-node/index.js
ENTRYPOINT [ "node", "index.js" ]
由于我设置了 WORKDIR
工作目录,正常的 docker run
是可以找到我的入口文件为 ${WORKDIR}/index.js
的。但是 drone 在执行插件的时候由于需要访问项目代码,所以会通过命令覆盖掉镜像的 WORKDIR
配置。导致了我的插件正常运行没问题,但是上到 drone 怎么也执行不了。最后查了才发现是因为复现了工作目录配置后入口文件找不到压根就没执行我的插件的问题。
后记
插件的所有代码已经发布在 Github:https://github.com/lizheming/drone-telegram-node,镜像也已发布到 docker 平台上。本插件相对于官方的插件的优势是能够设置 telegram API 接口的地址,对于国内服务使用反代的方式来说比较适合。如果想要在国内服务器上使用 drone telegram 消息通知的可以使用。不知道如何设置 telegram API 反代的也可以参考我的文章《反代访问Telegram》。
非常好的分享,赞赞。