Docker最全教程之Go实战,墙裂推荐(十八)
<blockquote><h1><strong>前言</strong></h1>
<p>与其他语言相比,Go非常值得推荐和学习,真香!为什么?<strong>主要是可以直接编译成机器代码(性能优越,体积非常小,可达10来M,见实践教程图片)而且设计良好,上手门槛低。</strong>本篇主要侧重于讲解了Go语言的优势,并且提供了一个推送钉钉消息的Demo。最后由于技痒,也编写了一个.NET Core的Demo,作为简单的对照(见下一篇)。</p>
</blockquote>
<p> </p>
<h1><strong>目录</strong></h1>
<p> </p>
<ul class="list-paddingleft-2">
<li>
<p>Go</p>
</li>
<li>
<p>Go的优势</p>
</li>
<li>
<p>官方镜像</p>
</li>
<li>
<p>使用Go推送钉钉消息</p>
</li>
<li>
<p>了解钉钉机器人</p>
</li>
<li>
<p>定义消息类型</p>
</li>
<li>
<p>从环境变量获取参数</p>
</li>
<li>
<p>设置消息格式并发送请求</p>
</li>
<li>
<p>设置Dockerfile</p>
</li>
<li>
<p>运行并设置环境变量推送消息</p>
</li>
</ul>
<p> </p>
<h1>Go</h1>
<p>Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。在2016年,Go被软件评价公司TIOBE 选为“TIOBE2016 年最佳语言”。</p>
<p>和其他语言的规定相比,在Go中有几项不同的强制的规定,当不匹配以下规定时编译将会产生错误:</p>
<ul class="list-paddingleft-2">
<li>
<p>每行程序结束后不需要撰写分号(;)。</p>
</li>
<li>
<p>大括号({)不能够换行放置。</p>
</li>
<li>
<p>if判断式和for循环不需要以小括号包覆起来。</p>
<p> </p>
</li>
</ul>
<h1>Go的优势</h1>
<p>相比其他语言,Go语言主要有以下优势:</p>
<ul class="list-paddingleft-2">
<li>
<p>可直接编译成机器代码,不依赖其他库;</p>
</li>
<li>
<p>丰富的内置数据类型<strong>(error也是基本的数据类型)</strong>;</p>
</li>
<li>
<p>语言层面支持并发;</p>
</li>
<li>
<p>设计良好<strong>(虽然不算优秀,但是恰到好处,特别实用)</strong>;</p>
</li>
<li>
<p>支持垃圾回收;</p>
</li>
<li>
<p>规范<strong>(不规范直接编译报错,这点太生猛了)</strong>、简单、易学;</p>
</li>
<li>
<p>丰富的标准库;</p>
</li>
<li>
<p>跨平台编译;</p>
</li>
<li>
<p>性能相对强劲;</p>
</li>
<li>
<p>部署简单;</p>
</li>
<li>
<p>生态丰富</p>
</li>
</ul>
<p>Go的性能强劲,但是又比C/C++的开发效率高(Go语言的开发者很多都是从C/C++转换过来的,上手几乎没门槛),维护成本更低,同时开发效率又不弱于Python等动态语言,而且还支持编译,可能减少很多低级错误。除此之外,Go还有个很大的优势,Go和.NET Core一样,讲的好听一点呢,就是出身名门、血统纯正,讲的不好听一点呢,都是富二代,都有一个好爹。</p>
<p><img src="https://img2018.cnblogs.com/blog/70544/201903/70544-20190320094025436-1651721141.jpg" alt=""></p>
<p>我们的系列教程的主角Docker,就是基于Go语言编写。由于以上一些特性,Go特别适合云计算相关服务开发(关于这一点,大家可以关注各大云厂商的开源项目)、服务器编程、分布式系统、网络编程、内存数据库等等。</p>
<p><img src="https://img2018.cnblogs.com/blog/70544/201903/70544-20190320094039312-1079238202.jpg" alt=""></p>
<p> </p>
<p> </p>
<h1>官方镜像</h1>
<p>官方镜像地址:</p>
<p>https://hub.docker.com/_/golang</p>
<p>由于爹好,所以官方文档比较详细:</p>
<p><img src="https://img2018.cnblogs.com/blog/70544/201903/70544-20190320094107494-1469267192.png" alt=""></p>
<p>同样,我们可以使用docker images golang命令来查看相关镜像。<strong>这里值得注意的是,一般情况下,请使用带有alpine标签的golang镜像,因为体积更小。</strong></p>
<p><img src="https://img2018.cnblogs.com/blog/70544/201903/70544-20190320094121139-1422394325.png" alt=""></p>
<p> </p>
<h1>使用Go推送钉钉消息</h1>
<p>接下来,我们使用Go编写一个简单的Demo:即通过钉钉机器人WebHooks推送消息到钉钉。</p>
<p>目前钉钉已经普遍应用于办公领域,通过对接钉钉机器人,我们可以将一些希望相关团队关注的信息推送到相应的钉钉群。</p>
<p> </p>
<h1>了解钉钉机器人</h1>
<p>在开始之前,我们需要对钉钉机器人有个大致的了解:</p>
<p>https://open-doc.dingtalk.com/microapp/serverapi2/qf2nxq</p>
<p>这里我们是使用自定义机器人。当前自定义机器人支持文本 (text)、连接 (link)、markdown (markdown)、ActionCard、FeedCard消息类型,我们可以根据自己的使用场景选择合适的消息类型,达到最好的展示样式。例如我们用的比较多的是markdown类型:</p>
<p><img src="https://img2018.cnblogs.com/blog/70544/201903/70544-20190320094201208-332047767.png" alt=""></p>
<p> </p>
<h1>定义消息类型</h1>
<p>我们暂且定义文本和markdown类型:</p>
<p><img class="img_loading" src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==" alt="" data-copyright="0" data-ratio="1.0969479353680431" data-s="300,640" data-src="https://mmbiz.qpic.cn/mmbiz_png/Mt5QjqkFG0pSBs1MmQvx2RCLnlXGEyvQvQOcC0fYqgmRI23AU40QMuc6Hz7yRhiaicLC2UbwvdMn15F6aAxdl1gw/640?wx_fmt=png" data-type="png" data-w="557"></p>
<p> <img src="https://img2018.cnblogs.com/blog/70544/201903/70544-20190320094219852-1627356742.png" alt=""></p>
<h1> </h1>
<h1> </h1>
<h1>从环境变量获取参数</h1>
<p>我们可以通过环境变量来传参。</p>
<ul class="list-paddingleft-2">
<li>
<p>定义环境变量参数:</p>
</li>
</ul>
<p> </p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">环境变量</span>
<span style="color: rgba(0, 0, 0, 1)">
varenvList </span>= []<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">钉钉机器人地址</span>
<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">WEBHOOK</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">@的手机号码</span>
<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">AT_MOBILES</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">@所有人</span>
<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">IS_AT_ALL</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">消息内容</span>
<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">MESSAGE</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">消息类型(仅支持文本和markdown)</span>
<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">MSG_TYPE</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
}
</span></pre>
</div>
<p> </p>
<p> </p>
<ul class="list-paddingleft-2">
<li>
<p>从环境变量获取参数并校验</p>
</li>
</ul>
<p> </p>
<p> </p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取环境变量</span>
<span style="color: rgba(0, 0, 0, 1)">
envs:</span>= make(map[<span style="color: rgba(0, 0, 255, 1)">string</span>]<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">)
for_, envName :</span>=<span style="color: rgba(0, 0, 0, 1)">rangeenvList {
envs</span>=<span style="color: rgba(0, 0, 0, 1)"> os.Getenv(envName)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">参数检查</span>
<span style="color: rgba(0, 0, 0, 1)">
ifenvs</span>==<span style="color: rgba(128, 0, 0, 1)">""</span>&&envName !=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">AT_MOBILES</span><span style="color: rgba(128, 0, 0, 1)">"</span>&&envName !=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">IS_AT_ALL</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">{
fmt.Println(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">envionmentvariable </span><span style="color: rgba(128, 0, 0, 1)">"</span>+envName+<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)"> isrequired</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
os.Exit(</span><span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
}
}
ifenvs[</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">AT_MOBILES</span><span style="color: rgba(128, 0, 0, 1)">"</span>] ==<span style="color: rgba(128, 0, 0, 1)">""</span>&& envs[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">IS_AT_ALL</span><span style="color: rgba(128, 0, 0, 1)">"</span>] ==<span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">{
fmt.Println(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">必须设置参数AT_MOBILES和IS_AT_ALL两者之一!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
os.Exit(</span><span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
}</span></pre>
</div>
<p> </p>
<h1>
设置消息格式并发送请求</h1>
<h5>相关包引用如下:</h5>
<p>i</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">mport(
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">bytes</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">encoding/json</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">fmt</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">io/ioutil</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">net/http</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">strings</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
)</span></pre>
</div>
<p> </p>
<p>关键代码如下所示:</p>
<p><img src="https://img2018.cnblogs.com/blog/70544/201903/70544-20190320094431716-1352594429.png" alt=""></p>
<p> </p>
<p><img src="https://img2018.cnblogs.com/blog/70544/201903/70544-20190320094448165-754463936.png" alt=""></p>
<p> </p>
<h1>
设置Dockerfile</h1>
<p>Dockerfile如下所示:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">FROM</span> golang:1.10<span style="color: rgba(0, 0, 0, 1)">-alpineasbuilder
</span><span style="color: rgba(0, 128, 128, 1)">WORKDIR</span><span style="color: rgba(0, 0, 0, 1)"> /go/src/component-dingding
</span><span style="color: rgba(0, 128, 128, 1)">COPY</span> .//go/src/component-dingding
<span style="color: rgba(0, 128, 128, 1)">RUN</span><span style="color: rgba(0, 0, 0, 1)"> set -ex&& \
go build -v -o/go/bin/component-dingding \
-gcflags</span>'-N -l'<span style="color: rgba(0, 0, 0, 1)">\
.</span>/*<span style="color: rgba(0, 0, 0, 1)">.go
FROM alpine
RUN apk update&& apk add ca-certificates
COPY --from=builder/go/bin/component-dingding /usr/bin/
CMD ["component-dingding"]
#注意不要单独使用MAINTAINER指令,MAINTAINER已被Label标签代替
LABEL MAINTAINER ="xinlai@xin-lai.com"
# LABEL指令用于将元数据添加到镜像,支持键值对和JSON,我们可以使用docker inspect命令来查看
LABEL DingtalkComponent='{\
"description": "使用钉钉发送通知消息.",\
"input": [\
{"name": "WEBHOOK","desc": "必填,钉钉机器人Webhook地址"},\
{"name": "AT_MOBILES","desc": "非必填,被@人的手机号"},\
{"name": "IS_AT_ALL","desc": "非必填,@所有人时:true,否则为:false"},\
{"name": "MESSAGE","desc": "必填,自定义发送的消息内容"},\
{"name": "MSG_TYPE","desc": "必填,自定义发送的消息类型,目前仅支持text和markdown"}\
]\
}'</span></pre>
</div>
<p> </p>
<p>这里我们使用了标签来说明参数,我们可以使用以下命令来查看标签:</p>
<p>docker inspect go-dingtalk</p>
<p><img src="https://img2018.cnblogs.com/blog/70544/201903/70544-20190320094834641-230359453.png" alt=""></p>
<p><img class="img_loading" src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==" alt="" data-copyright="0" data-ratio="0.7064989517819706" data-s="300,640" data-src="https://mmbiz.qpic.cn/mmbiz_png/Mt5QjqkFG0pSBs1MmQvx2RCLnlXGEyvQMq7oFnicv2WR8tbf8ibOA8YrNvAET1Iia1VSv2JAibtK0HpqHEggYAs8oQ/640?wx_fmt=png" data-type="png" data-w="954"></p>
<p>编译出来的镜像非常小,使用了分阶段构建,因为alpine的镜像非常小,而go可以直接编译成机器代码:</p>
<p><img src="https://img2018.cnblogs.com/blog/70544/201903/70544-20190320094847443-83445269.png" alt=""><img class="img_loading" src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==" alt="" data-copyright="0" data-ratio="0.21823204419889503" data-s="300,640" data-src="https://mmbiz.qpic.cn/mmbiz_png/Mt5QjqkFG0pSBs1MmQvx2RCLnlXGEyvQC6kvkNkehvG0YWytuhTaPqiakNiarxVgibJbtiaKTyqBXcRuia3cu8dia3GA/640?wx_fmt=png" data-type="png" data-w="724"></p>
<p>看到这个大小,是不是相对惊诧呢!!其实.NET Core也支持,需要用到CoreRT(.NET Core Runtime,C++的性能,.NET的生产力),不过目前虽然可用,但是还不算完全成熟。有兴趣的可以了解下官方的这个开源库:</p>
<p>https://github.com/dotnet/corert</p>
<p> </p>
<p><span style="background-color: rgba(0, 204, 255, 1)"><em><strong>注意:</strong></em></span></p>
<p><span style="background-color: rgba(0, 204, 255, 1)"><em>Alpine Linux 是一个社区开发的面向安全应用的轻量级Linux发行版。从上图我们可以看到,它非常非常小,只有5M,这是其最大的优势。因此,其非常适合用来做Docker镜像、路由器、防火墙、VPNs、VoIP 盒子以及服务器的操作系统。</em></span></p>
<p><span style="background-color: rgba(51, 102, 255, 1)"><em> </em></span></p>
<h1>
运行并设置环境变量推送消息</h1>
<h5>运行并设置环境变量推送消息</h5>
<p>我们使用PowerShell编写简单脚本如下所示:</p>
<div class="cnblogs_code">
<pre>docker build --rm-f<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Dockerfile</span><span style="color: rgba(128, 0, 0, 1)">"</span>-t go-<span style="color: rgba(0, 0, 0, 1)">dingtalk:latest .
docker run </span>--rm -e<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">WEBHOOK=https://oapi.dingtalk.com/robot/send?access_token={AccessToken}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">`
</span>-e<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">MESSAGE=*使用go发送钉钉消息。*</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">`
</span>-e<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">IS_AT_ALL=true</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">`
</span>-e<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">MSG_TYPE=markdown</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">`
</span>-d go-dingtalk</pre>
</div>
<p> </p>
<p><em><span style="background-color: rgba(0, 204, 255, 1)"><strong>注意:</strong></span></em></p>
<p><em><span style="background-color: rgba(0, 204, 255, 1)">--rm用于自动清理。也就是用之即来,用完即走。</span></em></p>
<p> </p>
<p>推送成功后,效果图如下所示:</p>
<p><img src="https://img2018.cnblogs.com/blog/70544/201903/70544-20190320095035479-390557680.png" alt=""></p>
<p><img src="https://img2018.cnblogs.com/blog/70544/201903/70544-20190320095050887-1027417094.png" alt=""></p>
<p>写到这里,笔者有些技痒了!!于是准备试试使用.NET Core也编写类似代码,下节内容将持续更新,敬请关注!</p>
<p> </p>
</div>
<div id="MySignature" role="contentinfo">
作者:雪雁<br>出处:http://www.cnblogs.com/codelove/
<br>如果喜欢作者的文章,请关注【CodeSpirit-码灵】公众号以便第一时间获得最新内容。本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。<br><b>静听鸟语花香,漫赏云卷云舒。</b>
<br>
<img src="https://images.cnblogs.com/cnblogs_com/codelove/315887/o_251224070213_%E5%85%AC%E4%BC%97%E5%8F%B7.jpg" width="100" height="100"><br><br>
来源:https://www.cnblogs.com/codelove/p/10563012.html
頁:
[1]