gitlab runner运行完相关的测试或打包后,我们总想让它把结果实时主动的告知我们,这时候便需要一个钉钉机器人了。报着试试看的想法在docker hub上搜索,虽然找到了几个关键字相同的,但很遗憾这些作者都很懒,没有任何的使用说明。索性就自己来一个吧。
前言
如果你并不想知道我是如何从0到1完成的构建过程,而仅仅是需要一个可以在itlab runner下发送钉钉消息话,请移步docker官方仓库来快速满足当前需求。
选择语言
钉钉开放文档上给出了两种代码的推送示例,分别是JAVA及PHP。由于PHP是个不需要的脚本语言,所以这里我们使用PHP。
<?php
function request_by_curl($remote_server, $post_string) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $remote_server);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_HTTPHEADER, array ('Content-Type: application/json;charset=utf-8'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// 线下环境不用开启curl证书验证, 未调通情况可尝试添加该代码
// curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
// curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
$webhook = "https://oapi.dingtalk.com/robot/send?access_token=xxxxxx";
$message="我就是我, 是不一样的烟火";
$data = array ('msgtype' => 'text','text' => array ('content' => $message));
$data_string = json_encode($data);
$result = request_by_curl($webhook, $data_string);
echo $result;
?>
虽然在bash也可以使用最原始的curl命令来达到这一效果,但从开发的效率来讲,这并不是最佳的选择。
image
语言确定使用php后,我选择比较常用的php:5.6版本,同时我们在此仅需要使用php的脚本功能,所以使用php:5.6-cli版本便可以。但本地启动docker服务后,执行:docker run php:5.6-cli /bin/bash
,稍微等待一些时候,一个php:5.6-cli环境就搭建好了。
panjie@panjies-iMac yunzhiclub % docker run -it php:5.6-cli /bin/bash
root@d46c5475b769:/# php -v
PHP 5.6.40 (cli) (built: Jan 23 2019 00:04:26)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
docker run -it php:5.6-cli /bin/bash
表示构造相应的容器后,进该容器.
最后我们使用exit
命令退出容器,此时容器自动终止。
本地调试
接下来,我们在基于php:5.6-cli
镜像上打造的contanier容器进行调试,步骤如下:
- 本地创建一个ding.php文件
- 复制官方的示例代码到ding.php文件中。
- 替换token为自己钉钉机器人token
- 将ding.php复制到contanier容器上
- 在容器上执行
php ding.php
查看效果
过程如下:
本地创建一个ding.php文件,然后我们复制官方的代码,并将access_token=xxx的部分进行替换:
<?php
function request_by_curl($remote_server, $post_string) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $remote_server);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_HTTPHEADER, array ('Content-Type: application/json;charset=utf-8'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// 线下环境不用开启curl证书验证, 未调通情况可尝试添加该代码
// curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
// curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
$webhook = "https://oapi.dingtalk.com/robot/send?access_token=这里替换为你自己的自定义钉钉机器人token";
$message="我就是我, 是不一样的烟火";
$data = array ('msgtype' => 'text','text' => array ('content' => $message));
$data_string = json_encode($data);
$result = request_by_curl($webhook, $data_string);
echo $result;
?>
注意: 机器人类型一定是自定义机器
保存文件后使用docker run -t -d --name=php php:5.6-cli
命令启动容器,然后继续执行docker cp ./ding.php php:/root/ding.php
将本地的ding.php复制到容器中.
最后我们进行到容器中进行测试:
$ docker exec -it php /bin/bash
root@80adb7e221c3:/# cd /root
root@80adb7e221c3:~# php ding.php
root@80adb7e221c3:~# exit
然后就可以在钉钉中发现测试的机器人推送的消息了:
mardown
但仅仅推送文本消息还是不够的,我们希望的是其推送带有PR地址的消息,这样当构造成功时,我们直接在钉钉中点击链接就可以直接打开PR的地址来完成合并操作了。
接下来,我们停止原容器,然后启动一个新容器,并使用挂载的方式将当前目录挂载到容器中,这样以来我们便可以在本地进行代码变更,然后在容器中来执行脚本进行测试了.
$ docker stop php
$ docker container rm php
$ docker run -it -v /Users/panjie/gitlab/yunzhiclub/process-evaluation/ding:/root --name=php php:5.6-cli /bin/bash
root@488cfb9ae30a:/# cd /root
root@488cfb9ae30a:~# root@ddff97414a5c:~# ls
ding.php
注意: 上面的参数中少了-d
参数,增加了-t
参数及结尾的/bin/bash
,作用是容器创建完成后便进入该容器。
其中:/Users/panjie/gitlab/yunzhiclub/process-evaluation/ding
为ding.php所在的本地目录,必须是绝对路径,/root
为容器目录。
修改ding.php
按钉钉官方文档,我们将推送机器人消息格式改成markdown。
<?php
function request_by_curl($remote_server, $post_string) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $remote_server);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_HTTPHEADER, array ('Content-Type: application/json;charset=utf-8'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
// curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
$webhook = "https://oapi.dingtalk.com/robot/send?access_token=你自定义机器人的token";
$message = ["title" => "这是标题", "text" => "## 执行成功 \n 我就是我,不一样的烟火[这里是地址](https://www.baidu.com)"];
$data = array ('msgtype' => 'markdown','markdown' => $message);
$data_string = json_encode($data);
$result = request_by_curl($webhook, $data_string);
echo $result;
echo PHP_EOL;
?>
在容器中执行php /root/ding.php
测试:
环境变量
在gitlab runner中的脚本中执行env
便可以查看环境变量,然后我们找出需要的几项:
CI_MERGE_REQUEST_PROJECT_URL=https://xxx.xxx.com:xxx/yunzhiclub/process-evaluation
CI_MERGE_REQUEST_TITLE=用户管理 重置密码 和 编辑
CI_MERGE_REQUEST_IID=32
GITLAB_USER_LOGIN=weiweiyi189
用以拼接 [PR标题](PR地址)构建成功,运行者:weiweiyi189
这条markdown信息。
PHP获取环境变量
为了使用PHP与gitlab runner中的环境变量相结合,我们对ding.php进行以下改造.
<?php
$projectUrl = getenv("CI_MERGE_REQUEST_PROJECT_URL");
$prId = getenv("CI_MERGE_REQUEST_IID");
if (!$prId) {
echo "当前脚本仅适用于PR" . PHP_EOL;
exit(1);
}
$prUrl = $projectUrl . "/-/merge_requests/" . $prId;
$title = getenv("CI_MERGE_REQUEST_TITLE");
$author = getenv("GITLAB_USER_LOGIN");
$text = "## 😀 😃 😄 😁 😆 \n [$title]($prUrl)运行成功,提交者: $author";
function request_by_curl($remote_server, $post_string) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $remote_server);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_HTTPHEADER, array ('Content-Type: application/json;charset=utf-8'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
// curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
$webhook = "https://oapi.dingtalk.com/robot/send?access_token=你自定义机器的token";
$markdown = ["title" => "这是标题", "text" => $text];
$data = array ('msgtype' => 'markdown','markdown' => $markdown);
$data_string = json_encode($data);
$result = request_by_curl($webhook, $data_string);
echo $result;
echo PHP_EOL;
?>
然后在容器中设计几个环境变量:
$ export CI_MERGE_REQUEST_PROJECT_URL=https://xxx.xxx.com:xxx/yunzhiclub/process-evaluation
$ export CI_MERGE_REQUEST_TITLE="title test"
$ export CI_MERGE_REQUEST_IID=32
$ export GITLAB_USER_LOGIN=weiweiyi189
最后再次执行php ding.php
(注意:你可能需要更改下钉钉机器人关键字)
root@ddff97414a5c:~# php ding.php
{"errcode":0,"errmsg":"ok"}
剥离token
由于钉钉机器仅仅是token不一样,所以我们再把token
也变成由环境变量中取值,最终完成版的ding.php
<?php
$token = getenv("YZ_DING_TOKEN");
if (!$token) {
echo "未检测到环境变量'YZ_DING_TOKEN'" . PHP_EOL;
exit(1);
}
$projectUrl = getenv("CI_MERGE_REQUEST_PROJECT_URL");
$prId = getenv("CI_MERGE_REQUEST_IID");
if (!$prId) {
echo "当前脚本仅适用于PR" . PHP_EOL;
exit(1);
}
$prUrl = $projectUrl . "/-/merge_requests/" . $prId;
$title = getenv("CI_MERGE_REQUEST_TITLE");
$author = getenv("GITLAB_USER_LOGIN");
$text = "## 😀 😃 😄 😁 😆 \n [$title]($prUrl)运行成功,提交者: $author";
function request_by_curl($remote_server, $post_string) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $remote_server);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_HTTPHEADER, array ('Content-Type: application/json;charset=utf-8'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
// curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
$webhook = "https://oapi.dingtalk.com/robot/send?access_token=$token";
$markdown = ["title" => "这是标题", "text" => $text];
$data = array ('msgtype' => 'markdown','markdown' => $markdown);
$data_string = json_encode($data);
$result = request_by_curl($webhook, $data_string);
echo $result;
echo PHP_EOL;
?>
在使用前,我们先设置环境变量YZ_DING_TOKEN
:
$ export YZ_DING_TOKEN=65adbb5f6d99955b86e0eff562e1d562exxxx
$ php ding.php
至此,我们更完成了本地测试的部分,接下来我们便可以把它打造为公用的image,然后上传到特定的仓库中了。关于如何借助阿里云的容器服务来自动构建,请参考如何创建一个运行angular单元测试的docker容器--DOCKER一节
使用阿里云构建image的过程略,构造会的image地址为:registry.cn-beijing.aliyuncs.com/mengyunzhi/dingding:1.0.0
使用
至此,我们便可以在gitlab runner
中使用这个用于钉钉消息推送的image了.
dingding-success:
stage: notify
tags:
- docker
image: registry.cn-beijing.aliyuncs.com/mengyunzhi/dingding:1.0.0
variables:
YZ_DING_TOKEN: "65adbb5f6d99955b86e0eff562e1d562e85086cc18740e5c07b2xxxx"
script:
- php /root/ding.php
注意: 你的自定义机器的关键字,需要是运行成功,提交者
的子字符串。
此时,当前image便可以在构建成功时向钉钉中发送运行成功的消息了。
当然了,你也可以自己改写ding.php中的内容,以达到更多的个性化定义机器人发送内容的需求。
构建官方DOCKER IMAGE
docker官方注册后,可以无限制的推公开的image。我们注册docker后,在本机安装docker desktop。
接下来使用阿里云构建好的image在本地进行构建:
$ docker run --name="dingding" registry.cn-beijing.aliyuncs.com/mengyunzhi/dingding:1.0.0
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.cn-beijing.aliyuncs.com/mengyunzhi/dingding 1.0.0 3b817aa5b98b 19 minutes ago 344MB
由于docker官方仓库仅支持前缀为其用户名的image推送,所以我们在推送到官方仓库前,还需要将其重新命个名:
$ docker tag registry.cn-beijing.aliyuncs.com/mengyunzhi/dingding:1.0.0 teacherpan/gitlab-dingtalk:1.0.0
$ docker image ls
registry.cn-beijing.aliyuncs.com/mengyunzhi/dingding 1.0.0 3b817aa5b98b 19 minutes ago 344MB
teacherpan/gitlab-dingtalk 1.0.0 3b817aa5b98b 19 minutes ago 344MB
最后,打开docker desktop,找到以docker用户名为前缀的image,点击菜单中的push to hub
网速不同,上传的时间肯定也不相同:
最后,我们便可以在docker的官方库中找到它的身影并且成功的将其分享给其他的docker小伙伴了。
此时,我们便可以愉快的使用官方仓库了。
dingding-success:
stage: notify
tags:
- docker
image: teacherpan/gitlab-dingtalk
variables:
YZ_DING_TOKEN: "65adbb5f6d99955b86e0eff562e1d562e85086cc18740e5c07b2xxxx"
script:
- php /root/ding.php
最主要的,当别人对gitlab runner的钉钉推送有需求时,也可以在docker hub中快速的找到我们。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。