<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Blog·Tanky Woo</title>
		<description>Tanky Woo&#39;s Blog, focus on Python, Linux, Gentoo, Mac OS, Vim, Open Source and so on.</description>
		<link>https://blog.tankywoo.com/</link>
		<atom:link href="/" rel="self" type="application/rss+xml" />
		
		  
		<item>
			<title>2020 小结</title>
			<description>&lt;p&gt;总感觉时间一年过得比一年快，2020 年就这么过去了。&lt;/p&gt;
&lt;p&gt;今年对我来说，几个核心的关键词就是 &lt;em&gt;疫情&lt;/em&gt;、&lt;em&gt;装修入住&lt;/em&gt;。&lt;/p&gt;
&lt;p&gt;疫情这个感触还是挺深，翻了下去年的年度小结，是2020年1月19号写的，刚回家没2天时间，而20号晚上新闻就宣布疫情的爆发了。其实之前就已经有耳闻，所以月初在湖北老家结婚前发烧，还专门去医院抽血检查，现在想想估计就算有啥当时也检测不出来，所幸也没啥。&lt;/p&gt;
&lt;p&gt;还记得应该是1月17号放假，和老婆回湖北过年，坐高铁从北京到武汉站，晚上出站后，看了下高铁站没有什么防范，大家也都没意识到这个问题的严重，不过父母依然开车过来接我们回去。20号我们还出去逛街吃饭，晚上回来看新闻，就提及武汉疫情，当时也没太重视，直到2、3天后，情况越来越严重，至此开始了封闭在家的生活，每天只能干会工作，偶尔在阳台晒太阳，然后看着醒目的确诊数字往上蹿，不知道何时是个头。&lt;/p&gt;
&lt;p&gt;当时最关心的就是武汉怎么样了，家附近有哪些小区出现了病例。白天看着楼下时不时驶过的巡逻车辆，以及救护车的声音，穿着防护服的工作人员到处消毒清理，晚上看着消毒车沿路消毒。这真是沉重的新年！&lt;/p&gt;
&lt;p&gt;期间心里的压力还是挺大的，毕竟身处湖北，不过后来疫情慢慢控制住了，不少城市也可以出入了，而湖北依然是重点被关注，直到3月20号出头，允许出入小区了，但是铁路依然没通。3月24号晚，突然接到一个电话，自称好像是北京疾控中心，询问我们明天是否愿意坐专列回北京，没有给我们思考的时间，所以答应了。事后在微博也看到大家的讨论，有说真的，也有说骗子，毕竟电话来的太突然了，不过还是抓紧收拾了东西，怀着忐忑的心情入睡。回老家时长款羽绒服加身，而再回京时已是春天，这两个多月给人的感觉太魔幻了。&lt;/p&gt;
&lt;p&gt;第二天来到车站，坐上了从湖北发往北京的第一趟专列，到北京西下车时，第一次经历了这么多闪光灯，各大媒体见人就采访。当时北京各区大巴专车送到朝阳公园，然后各街道统一带回，到晚上9点才到家，这次是开始了北京的14天居家隔离，比在湖北时更严，门上都装了开门感应器。期间也辛苦社区人员，毕竟两口人一日三餐在家吃，时不时就得订菜让社区人员送来。&lt;/p&gt;
&lt;p&gt;熬到快4月中旬，完成居家隔离，终于可以正常的出门了，刚开始天天带着口罩上班，还有点不习惯，后来发现好处还是很多，不光疫情的防护，还可以防风沙、柳絮和普通感冒以及抗寒，记得前几年每年夏季末时，柳絮满天飞，容易导致过敏性鼻炎加感冒组合双打，今年就没出现过，当然也不敢感冒。&lt;/p&gt;
&lt;p&gt;因为去年过年早，所以装修到最后，工人都提前回去，还有部分没弄完，一直到今年6月份左右，小区才允许有声作业，到7月底差不多才收尾。装修真是花了快一年的时间，乘着夏天高温通风，透了两个多月，到9月中旬才搬过去。搬家当天接到电话，第二天还赶着去上海出差了一周。&lt;/p&gt;
&lt;p&gt;接下来一阵子，全国疫情都控制的很好，除了境外输入，基本没什么问题。装修的事情也弄完了，自己也全身心的投入到今年的一个新项目上了，国庆期间父母来北京玩了几天，11月份岳父岳母也来玩了一趟。&lt;/p&gt;
&lt;p&gt;不过最近这段入冬最冷的时间，全国各地方又陆陆续续的爆发疫情，管控也严格起来了，也不知道今年能否回家过年，真希望疫情能快点过去。&lt;/p&gt;
&lt;p&gt;最后，聊点其他的，最近算是打破了近几年每年一篇博客的记录了，也是因为在年底时手上的一些事项都完成了七七八八，所以静下心来好好思考规划了下。确实也发现近几年虽然忙，但是忙过好像就忘了。最近给自己打了一点鸡血，技术上的持续学习和复盘，生活健康上给自己定了一些习惯和目标，关注点也开拓了一些，先逐步适应一阵子，不断调整完善，后面有时间和经验时再总结下。&lt;/p&gt;
&lt;p style=&#34;text-align: center&#34;&gt;Bye, 2020! Hello, 2021!&lt;/p&gt;
</description>
			<pubDate>Sat, 16 jan 2021 00:00:00 +0800</pubDate>
			<link>https://blog.tankywoo.com/2021/01/16/2020-summary.html</link>
			<guid isPermaLink="true">https://blog.tankywoo.com/2021/01/16/2020-summary.html</guid>
		</item>
			
		
		  
		<item>
			<title>博客从Jekyll迁移到Hugo</title>
			<description>&lt;p&gt;从最开始的 &lt;a href=&#34;http://www.wutianqi.com/archive.html&#34;&gt;WordPress&lt;/a&gt;，到后来的 &lt;a href=&#34;https://blog.tankywoo.com/2013/09/10/use-octopress-as-my-tech-blog.html&#34;&gt;Octopress&lt;/a&gt;，再到之前的 &lt;a href=&#34;https://blog.tankywoo.com/2014/05/03/change-from-octopress-to-jekyll.html&#34;&gt;Jekyll&lt;/a&gt;，目前再次切换到 &lt;a href=&#34;https://gohugo.io/&#34;&gt;Hugo&lt;/a&gt; 了。&lt;/p&gt;
&lt;p&gt;主要源于之前思考了下一些技术碎片的记录，发现很分散，最近几年很少在自己的博客和 &lt;a href=&#34;https://wiki.tankywoo.com/&#34;&gt;Wiki&lt;/a&gt; 上更新了，其实背后一直在继续记录在，都分散在自己的私有 Wiki、笔记 App 等上面，而且记录得也比较随意，往往导致之前调研/排查过的技术，回头想回顾下也找不到在哪。于是考虑还是统一在博客里记录，同时督促自己发出来前必须先好好梳理下，另外也是考虑定期回顾，最后归档到 Wiki 上。&lt;/p&gt;
&lt;p&gt;但是在拾起博客时，再次遇到 ruby 及包升级导致 jekyll 无法使用，本着瞎折腾的思想，于是迁移到了 Hugo，毕竟对 Golang 这种编译出来的二进制文件无依赖的方式，还是挺情有独钟的。&lt;/p&gt;
&lt;p&gt;对于技术型博客而言，最重要的元信息就是 &lt;code&gt;日期&lt;/code&gt; 和 &lt;code&gt;标签&lt;/code&gt;。日期不用多说，标签的作用非常重要，可以快速的筛选某一类型的文章，这里目录(category)的概念弱化了，基本可以只用标签就行，所以顺手加了一个 &lt;a href=&#34;https://blog.tankywoo.com/tags.html&#34;&gt;标签页面&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;在将主题迁移到 Hugo 时，最初只是看中其渲染速度，对功能支持要求不高（毕竟当初就是看中 Jekyll 的功能简洁实用），然而发现 Hugo 模板的功能比我预期的强大多了，一些挺有用的功能，在 Hugo 下都实现了，当然也有一些小地方不支持，暂时也不影响。不过 Hugo 模板的上手难度要比 Jekyll 高不少，这几天迁移的过程中，看了不少文档和别人的文章，不过 Hugo 背后实现的思想也学习了不少，只能说确实牛犇。&lt;/p&gt;
</description>
			<pubDate>Sun, 03 jan 2021 00:00:00 +0800</pubDate>
			<link>https://blog.tankywoo.com/2021/01/03/blog-jekyll-to-hugo.html</link>
			<guid isPermaLink="true">https://blog.tankywoo.com/2021/01/03/blog-jekyll-to-hugo.html</guid>
		</item>
			
		
		  
		<item>
			<title>Dpkg Conffiles</title>
			<description>&lt;p&gt;最近通过 &lt;code&gt;dpkg&lt;/code&gt; 安装升级某 &lt;code&gt;deb&lt;/code&gt; 包，发现旧版本在 &lt;code&gt;/etc/&lt;/code&gt; 下的一个文件被误删了，但是新版本也未将其安装或恢复，于是研究了打包中的 &lt;strong&gt;&lt;code&gt;conffiles&lt;/code&gt;&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;首先看看官方的&lt;a href=&#34;https://www.debian.org/doc/manuals/maint-guide/dother.en.html#conffiles&#34;&gt;介绍&lt;/a&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One of the most annoying things about software is when you spend a great deal of time and effort customizing a program, only to have an upgrade stomp all over your changes. Debian solves this problem by marking such configuration files as conffiles. [55] When you upgrade a package, you&amp;rsquo;ll be asked whether you want to keep your old configuration files or not.&lt;/p&gt;
&lt;p&gt;dh_installdeb(1) automatically flags any files under the /etc directory as conffiles, so if your program only has conffiles there you do not need to specify them in this file. For most package types, the only place conffiles should ever be is under /etc, and so this file doesn&amp;rsquo;t need to exist.&lt;/p&gt;
&lt;p&gt;If your program uses configuration files but also rewrites them on its own, it&amp;rsquo;s best not to make them conffiles because dpkg will then prompt users to verify the changes all the time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;conffiles&lt;/code&gt; 的作用就是在软件包升级时，不同于其他文件只需要简单的暴力覆盖即可，放置于 &lt;code&gt;/etc/&lt;/code&gt; 下的(配置)文件需要需要特殊考虑，是保留旧配置还是使用新配置，所以有了这个特殊的行为。&lt;/p&gt;
&lt;p&gt;经常会遇到修改后的配置文件，在软件包升级时，出现如下询问窗口：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;Configuration file &amp;#39;/etc/default/nginx&amp;#39;
 ==&amp;gt; Modified (by you or by a script) since installation.
 ==&amp;gt; Package distributor has shipped an updated version.
   What would you like to do about it ?  Your options are:
    Y or I  : install the package maintainer&amp;#39;s version
    N or O  : keep your currently-installed version
      D     : show the differences between the versions
      Z     : start a shell to examine the situation
 The default action is to keep your current version.
*** nginx (Y/I/N/O/D/Z) [default=N] ?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过如 nginx deb 包解压，可以看到有 &lt;code&gt;&amp;lt;DEBIAN&amp;gt;/conffiles&lt;/code&gt; 文件，里面存放的都是要放到 &lt;code&gt;/etc&lt;/code&gt; 下的文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;apt download nginx-common
ar xv nginx-common_1.14.0-0ubuntu1.7_all.deb
tar Jxvf control.tar.xz
cat conffiles
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;dpkg&lt;/code&gt; 对于 conffiles 更新有强制执行的选项：&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;&lt;code&gt;--force-&amp;lt;things&amp;gt;
--no-force-&amp;lt;things&amp;gt;, --refuse-&amp;lt;things&amp;gt;

   confmiss: Always install the missing conffile without prompting. This is dangerous, since it means not preserving a change (removing) made to the file.

   confnew: If a conffile has been modified and the version in the package did change, always install the new version without prompting, unless the `--force-confdef` is also specified, in which case the default action is preferred.

   confold: If a conffile has been modified and the version in the package did change, always keep the old version without prompting, unless the `--force-confdef` is also specified, in which case the default action is preferred.

   confdef: If a conffile has been modified and the version in the package did change, always choose the default action without prompting. If there is no default action it will stop to ask the user unless `--force-confnew` or `--force-confold` is also been given, in which case it will use that to decide the final action.

   confask: If a conffile has been modified always offer to replace it with the version in the package, even if the version in the package did not change (since dpkg 1.15.8). If any of `--force-confnew`, `--force-confold`, or `--force-confdef` is also given, it will be used to decide the final action.
&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;说实话，不确定是不是我理解能力不行，这段写的太有歧义了，导致产生了几个疑问：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;里面的一些 it 都无法确定到底指谁？&lt;/li&gt;
&lt;li&gt;default action 从哪里可以看到？&lt;/li&gt;
&lt;li&gt;confold/confnew 时提到同时有 confdef 时，使用默认的行为；但是 confdef 又写到如果没有 default action 时，同时有 confnew/confold 会考虑作为最终的行为。 感觉逻辑写的有问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;反复读了很多遍，最终还是看源码 &lt;code&gt;dpkg/src/configure.c&lt;/code&gt; 理解了这块的逻辑。&lt;/p&gt;
&lt;p&gt;首先，这里面的 &lt;code&gt;a conffile&lt;/code&gt; 指的是 conffiles 文件中维护的 &lt;code&gt;/etc&lt;/code&gt; 下的任一文件，在 &lt;code&gt;dpkg&lt;/code&gt; 安装 deb 包时（apt/aptitute 同理），涉及文件的三个 hash 值（这里加个简称）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;hash_real: 某 conffile 文件的实际 hash&lt;/li&gt;
&lt;li&gt;hash_old: 某 conffile 在旧版本安装时维护的 hash（维护在 &lt;code&gt;/var/lib/dpkg/status&lt;/code&gt; 文件中，可通过命令 &lt;code&gt;dpkg --status &amp;lt;package&amp;gt;&lt;/code&gt; 查看指定包的 conffiles）&lt;/li&gt;
&lt;li&gt;hash_new: 某 conffile 在即将安装的新版本中的 hash&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;大致的逻辑就是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首先对比 hash_old 和 hash_new，如果相同，则保持原样（这个就是开始我遇到的问题，某个被误删掉的 conffile，在新旧版本未变更，所以保持原样，也就是继续不存在……）&lt;/li&gt;
&lt;li&gt;如果 conffile 不存在且配置了 &lt;code&gt;--force-confmiss&lt;/code&gt;，则会将文件重新安装上（这个就是上面遇到问题的解决方法）&lt;/li&gt;
&lt;li&gt;判断 hash_real 和 hash_old 是否一致，不一致则标识为 useredited 状态，即用户修改了 conffile&lt;/li&gt;
&lt;li&gt;判断 hash_real 和 hash_new 是否一致，不一致则标识为 distedited 状态，即软件包升级会修改 conffile&lt;/li&gt;
&lt;li&gt;然后进入 prompt 环节，也就是依据这些状态和 dpkg 的选项判断是否交互式询问是否覆盖或直接变更&lt;/li&gt;
&lt;li&gt;如果用户未修改 conffile，且软件包升级&lt;strong&gt;会&lt;/strong&gt;变更此文件，则任何 &lt;code&gt;--force-&amp;lt;things&amp;gt;&lt;/code&gt; 选项都无用，会自动更新 conffile&lt;/li&gt;
&lt;li&gt;如果用户修改了 conffile，且软件包升级&lt;strong&gt;不会&lt;/strong&gt;变更此文件，则可以通过 &lt;code&gt;--force-confask&lt;/code&gt; 进入提示是使用旧配置还是新配置&lt;/li&gt;
&lt;li&gt;如果用户修改了 conffile，且软件包升级&lt;strong&gt;会&lt;/strong&gt;变更此文件，则默认是 confask 的行为，此时也可以通过 &lt;code&gt;confold/confnew/confdef&lt;/code&gt; 来取消询问的步骤&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;基于上面的疑问，dpkg 源码实现（版本 1.19.0.5）对默认的行为是保留原配置，并没有看到可以修改 default action 的配置，且如果同时设置 &lt;code&gt;confdef&lt;/code&gt; 和 &lt;code&gt;confnew/confold&lt;/code&gt;，以 &lt;code&gt;confdef&lt;/code&gt; 为主。&lt;/p&gt;
&lt;p&gt;之前 Google 搜索 &amp;ldquo;dpkg conffiles&amp;rdquo; 出来靠前的&lt;a href=&#34;https://raphaelhertzog.com/2010/09/21/debian-conffile-configuration-file-managed-by-dpkg/&#34;&gt;一篇文章&lt;/a&gt; 提到了同时配置 &lt;code&gt;--force-confdef&lt;/code&gt; 和 &lt;code&gt;--force-confold&lt;/code&gt;，包括 StackOverflow 上有个回答也是这么说，按对方意思是用户未修改文件按 confdef 行为升级，有修改的文件按 confold 行为升级(保留)，可能这个是 dpkg 之前版本的行为，目前来看这个说法是有问题的。&lt;/p&gt;
&lt;p&gt;简单而言，一是非配置文件，不要放 &lt;code&gt;/etc&lt;/code&gt; 下，防止升级引发的遗漏问题；二是 &lt;code&gt;/etc&lt;/code&gt; 下配置文件，如果做了变更(包括删除)，那么不论是升级还是恢复，这个就交给用户自己了，除非指定了上面提到的强制选项。&lt;/p&gt;
</description>
			<pubDate>Fri, 01 jan 2021 00:00:00 +0800</pubDate>
			<link>https://blog.tankywoo.com/2021/01/01/dpkg-conffiles.html</link>
			<guid isPermaLink="true">https://blog.tankywoo.com/2021/01/01/dpkg-conffiles.html</guid>
		</item>
			
		
		  
		<item>
			<title>SSH AuthorizedKeysCommand 配置和坑</title>
			<description>&lt;p&gt;最近完善一个审计功能，在 SSH 登录时需要获取登录用户的公私钥或其指纹。调研后发现 &lt;code&gt;AuthorizedKeysCommand&lt;/code&gt; 可以满足需求。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AuthorizedKeysCommand&lt;/code&gt; 指定脚本查找用户的公钥文件做认证，在登录认证层面调用，可接受的参数有用户尝试登录时使用的私钥对应公钥，指纹、登录用户等变量；输出要求是 0 或多行 &lt;strong&gt;authorized_keys&lt;/strong&gt; 格式的输出，sshd 服务会将用户登录使用的私钥和脚本输出的公钥列表校验，只要其中一个公钥满足匹配，则认证通过；通过相关配置 &lt;code&gt;AuthorizedKeysCommandUser&lt;/code&gt; 指定脚本的执行用户。&lt;/p&gt;
&lt;p&gt;默认此配置项未设置，从 &lt;code&gt;AuthorizedKeysFile&lt;/code&gt; 定义的公钥列表文件中寻找用户公钥，也就是默认的 &lt;code&gt;.ssh/authorized_keys .ssh/authorized_keys2&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;一个简单的样例，只是打印传进来的这些变量，直接输出公钥列表文件内容，实际认证依然使用公钥文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;# /etc/ssh/sshd_config
AuthorizedKeysCommand /opt/ssh_auth.sh  %u %k %t %f %h
AuthorizedKeysCommandUser root
AuthorizedKeysFile      none
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# /opt/ssh_auth.sh&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;username&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;pubkey&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$2&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;keytype&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$3&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;fingerprint&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$4&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$5&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$username&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$pubkey&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$keytype&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$fingerprint&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$home&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /tmp/ssh_auth.log

cat &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;/.ssh/authorized_keys &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;/.ssh/authorized_keys2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个配置项有一个常见的使用场景：用户的公钥列表不存在服务器本地，而是存在统一的 CMDB 中，这样当有人入职或离职需要增删公钥列表时，不需要全部服务器更新公钥文件，只需要更新 CMDB 数据即可，解决了本地公钥文件带来的更新成本、更新滞后且容易遗漏等问题。但是需要注意的是如果只依赖 &lt;code&gt;AuthorizedKeysCommand&lt;/code&gt; 脚本，可能存在和 CMDB 之间网络不通导致的无法登录服务器的情况。&lt;/p&gt;
&lt;p&gt;还有一个需要注意的地方，OpenSSH 对 &lt;code&gt;AuthorizedKeysCommand&lt;/code&gt; 和 &lt;code&gt;AuthorizedKeysFile&lt;/code&gt; 处理的逻辑顺序在新旧版本中调整了。&lt;/p&gt;
&lt;p&gt;在 8.x 之前的版本，优先使用 &lt;code&gt;AuthorizedKeysCommand&lt;/code&gt; 进行认证，如果认证失败，继续使用 &lt;code&gt;AuthorizedKeysFile&lt;/code&gt; 认证：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If a key supplied by AuthorizedKeysCommand does not successfully authenticate and authorize the user then public key authentication continues using the usual AuthorizedKeysFile files.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在 8.x 及之后版本，优先使用 &lt;code&gt;AuthorizedKeysFile&lt;/code&gt;，如果未找到匹配的才继续使用 &lt;code&gt;AuthorizedKeysCommand&lt;/code&gt; 认证：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;AuthorizedKeysCommand is tried after the usual AuthorizedKeysFile files and will not be executed if a matching key is found there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本地测试时版本是 8.1_p1，此时代码的逻辑顺序已经调整了，但是文档未更新，导致测试时发现一直未调用脚本进行认证，所以上面配置样例中强制设置 &lt;code&gt;AuthorizedKeysFile none&lt;/code&gt;。&lt;a href=&#34;https://www.openssh.com/releasenotes.html#8.3p1&#34;&gt;CHANGELOG&lt;/a&gt; / &lt;a href=&#34;https://bugzilla.mindrot.org/show_bug.cgi?id=3134&#34;&gt;BUG&lt;/a&gt;&lt;/p&gt;
</description>
			<pubDate>Tue, 29 jan 2020 00:00:00 +0800</pubDate>
			<link>https://blog.tankywoo.com/2020/12/29/ssh-authorizedkeyscommand.html</link>
			<guid isPermaLink="true">https://blog.tankywoo.com/2020/12/29/ssh-authorizedkeyscommand.html</guid>
		</item>
			
		
		  
		<item>
			<title>OpenVPN max-routes-per-client 配置</title>
			<description>&lt;p&gt;今天看到 vpn 服务端有日志疯狂刷屏：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;office-A/2.2.2.2:51159 MULTI: Learn FAILED: 10.15.0.100 -&amp;gt; office-A/2.2.2.2:51159
office-A/2.2.2.2:51159 MULTI ROUTE: route quota (256) exceeded for office-A/2.2.2.2:51159 (see --max-routes-per-client option)
office-A/2.2.2.2:51159 MULTI: Learn FAILED: 10.15.0.100 -&amp;gt; office-A/2.2.2.2:51159
office-B/3.3.3.3:34020 MULTI ROUTE: route quota (256) exceeded for office-A/2.2.2.2:51159 (see --max-routes-per-client option)
office-B/3.3.3.3:34020 MULTI: Learn FAILED: 10.15.0.100 -&amp;gt; office-A/2.2.2.2:51159
office-B/3.3.3.3:34020 MULTI ROUTE: route quota (256) exceeded for office-A/2.2.2.2:51159 (see --max-routes-per-client option)
office-B/3.3.3.3:34020 MULTI: Learn FAILED: 10.15.0.100 -&amp;gt; office-A/2.2.2.2:51159
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;大致的背景架构如下，内网通过 vpn 通信，&lt;code&gt;10.15.0.0/16&lt;/code&gt; 是 office-A 的内网网段，两个 office 之间通过 vpn 中心服务器互联。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;office-A          vpn-server          office-B

2.2.2.2 &amp;lt;--------&amp;gt; 1.1.1.1 &amp;lt;--------&amp;gt; 3.3.3.3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;看了下 &lt;code&gt;--max-routes-per-client&lt;/code&gt; 的手册，大致意思就是为了防止从已认证的客户端发送到 vpn 服务端的包有大量不同的 mac 地址，导致内部路由表扩张耗尽内存，所以加上这个默认限制。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;--max-routes-per-client n
    Allow a maximum of n internal routes per client (default=256). This is designed to help contain DoS attacks where an authenticated client floods the server with packets appearing to come from many unique MAC addresses, forcing the server to deplete virtual memory as its internal routing table expands. This directive can be used in a --client-config-dir file or auto-generated by a --client-connect script to override the global value for a particular client.

    Note that this directive affects OpenVPN&amp;#39;s internal routing table, not the kernel routing table.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;office-A 内部有很多主机和IP，当它们和 office-B 的主机互联时，就需要经过 vpn-server 进行通信。&lt;/p&gt;
&lt;p&gt;最初想看 OpenVPN 内部的路由标信息，没找到方法，于是通过对 tun 网卡抓包，评估通信的 IP，因为上面分配的是一个 &lt;code&gt;/16&lt;/code&gt; 掩码的网段，当时有多个网段，随便抓了一会包统计就有 300+ IP。&lt;/p&gt;
&lt;p&gt;按照文档，这里不做全局级的变更，仅在 &lt;code&gt;--client-config-dir&lt;/code&gt; 中 office-B 定义的文件中配置 &lt;code&gt;max-routes-per-client&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;max-routes-per-client 1024
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;默认值 256 应该也是考虑一般分配一个 C 段，最大也就 255 个。&lt;/p&gt;
&lt;p&gt;最后在继续研究时，发现通过管理口的 &lt;code&gt;status&lt;/code&gt; 命令可以看到内部路由表，确实是一个客户端 IP 一条：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;$ nc -U /var/run/vpn-server.sock
&amp;gt;INFO:OpenVPN Management Interface Version 1 -- type &amp;#39;help&amp;#39; for more info
status
OpenVPN CLIENT LIST
Updated,Mon Dec 21 22:46:04 2020
Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since
office-B,2.2.2.2:12345,1234567890,123456789,Mon Dec 21 17:30:45 2020
...
ROUTING TABLE
Virtual Address,Common Name,Real Address,Last Ref
10.15.0.100C,office-B,2.2.2.2:12345,Mon Dec 21 22:45:22 2020
10.15.1.200C,office-B,2.2.2.2:12345,Mon Dec 21 22:46:00 2020
...
GLOBAL STATS
Max bcast/mcast queue length,1
END
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
			<pubDate>Mon, 21 jan 2020 00:00:00 +0800</pubDate>
			<link>https://blog.tankywoo.com/2020/12/21/openvpn-max-routes-per-client.html</link>
			<guid isPermaLink="true">https://blog.tankywoo.com/2020/12/21/openvpn-max-routes-per-client.html</guid>
		</item>
			
		
		  
		<item>
			<title>SSH 安全配置之 MaxStartups</title>
			<description>&lt;p&gt;最近发现个别服务器 ssh 登录时偶尔出现失败，发现和 &lt;code&gt;MaxStartups&lt;/code&gt; 有关。&lt;/p&gt;
&lt;p&gt;本地模拟环境：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;10.0.7.113: 客户端&lt;/li&gt;
&lt;li&gt;10.0.7.9: 服务端&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;客户端 ssh 连接时收到的报错信息：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;kex_exchange_identification: Connection closed by remote host
Connection closed by 10.0.7.9 port 22
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;抓包看已经到应用层 ssh 协商阶段，但是服务端在收到客户端的 ssh 协议版本包之前，就已经主动关闭连接，发送了 &lt;code&gt;FIN + ACK&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://images.tankywoo.com/ssh-maxstartups/ssh-maxstartups-client-pcap.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;（客户端抓包）&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://images.tankywoo.com/ssh-maxstartups/ssh-maxstartups-server-pcap.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;（服务端抓包）&lt;/p&gt;
&lt;p&gt;在服务端 &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; 将日志级别调整到 &lt;code&gt;LogLevel VERBOSE&lt;/code&gt;，可以看到日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2020-09-02T12:48:48.289609+08:00 gentoo-pc sshd[3480]: drop connection #3 from [10.0.7.113]:57645 on [10.0.7.9]:22 past MaxStartups
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;日志层面显示客户端端口 57645 对应上面的异常连接数据包。另外提到了 past MaxStartups，查阅 man 手册：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MaxStartups
    Specifies the maximum number of concurrent unauthenticated connections to the SSH daemon.
    Additional connections will be dropped until authentication succeeds or the LoginGraceTime expires for a connection.
    The default is 10:30:100.

    Alternatively, random early drop can be enabled by specifying the three colon separated values start:rate:full (e.g. &amp;quot;10:30:60&amp;quot;).
    sshd(8) will refuse connection attempts with a probability of rate/100 (30%) if there are currently start (10) unauthenticated connections.
    The probability increases linearly and all connection attempts are refused if the number of unauthenticated connections reaches full (60).
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;即控制并发初始化连接的个数，初始化连接即还未到认证层面的连接，如默认的 &lt;code&gt;10:30:100&lt;/code&gt;，表示如果超过 10 个并发初始化连接，则后续的连接由 30% 的几率直接被关闭，如果超过 100 个连接，则所有新的连接 100% 直接关闭。&lt;/p&gt;
&lt;p&gt;再比如我本地模拟测试，配置 &lt;code&gt;MaxStartups 3:100:3&lt;/code&gt;，即表示并发初始化连接超过 3 个时，直接 100% 丢包，所以我开 tmux 四个窗口同时登陆服务端，总会有一个连接报错并关闭连接。&lt;/p&gt;
&lt;p&gt;结合实际的场景为何会出现这个问题，我们的服务器都做了 ssh 白名单防火墙限制，只有白名单的网段可以登录，其余数据包在防火墙层面直接丢弃；但是个别服务器因为一些原因，未开启此配置，导致有大量的 ssh 端口扫描，自然就达到了 MaxStartups 的限制，也就出现了偶尔丢包的情况。&lt;/p&gt;
</description>
			<pubDate>Wed, 02 jan 2020 00:00:00 +0800</pubDate>
			<link>https://blog.tankywoo.com/2020/09/02/ssh-maxstartups.html</link>
			<guid isPermaLink="true">https://blog.tankywoo.com/2020/09/02/ssh-maxstartups.html</guid>
		</item>
			
		
		  
		<item>
			<title>2019 小结</title>
			<description>&lt;p&gt;说实话有点尴尬，因为上一篇还是 &lt;a href=&#34;https://blog.tankywoo.com/2019/01/16/2018-bye-bye.html&#34;&gt;2018 小结&lt;/a&gt;，没想到时间一晃，又到一年一度写总结的时候了。&lt;/p&gt;
&lt;p&gt;杰宝每年都是第一个&lt;a href=&#34;http://www.zhangjiee.com/blog/2019/2017-2019-personal-review.html&#34;&gt;交作业&lt;/a&gt;，然后磊子&lt;a href=&#34;https://blog.opskumu.com/bye-2019.html&#34;&gt;紧随其后&lt;/a&gt;，我则是拖到现在。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;生活&#34;&gt;生活&lt;/h2&gt;
&lt;p&gt;三十而立，在这而立之年，我完成了人生的两件大事。&lt;/p&gt;
&lt;p&gt;六月底，和老婆去朝阳民政局领证，并于今年年初在老家举办了婚礼。正如 &lt;a href=&#34;https://blog.tankywoo.com/2019/01/16/2018-bye-bye.html&#34;&gt;2018 小结&lt;/a&gt;生活篇最后一句话：『最后，划个重点，2019 年和女友把事情敲定』。经历了漫漫的恋爱长路，我俩终于由恋人变为了夫妻。这算是而立之年给自己的一个礼物，也是一份责任吧！&lt;/p&gt;
&lt;p&gt;在领证并选择定居北京后，七月份开始通过链家找房子，限制好首付价格、地理位置、小区环境和交通便利等，在网上不断的筛选以及烈日下数个周末的奔波查看，最终选好房子，在和房主谈了两次后把价格谈妥成交，剩下的就是办手续，在八月底过完户，正式在帝都有了自己的家。九月份赶上中秋、出差和国庆的到来，好好的休息了一阵子，等国庆后开始着手装修，选择的是半包，主材啥的全部和老婆去建材市场自行买的，因为赶上冬天和过年师傅提前回家，所以年前还没完全弄完，年后继续装修。我和老婆经常开玩笑，搞一次装修，啥都给学了，大到橱柜门窗，小到五金零件……&lt;/p&gt;
&lt;p&gt;感谢老婆，这半年来一直没休息好，陪我一起搞定这些事情，买房时到处看房子，一天下来真的把人累的不行，再后来装修时周末都在跑建材市场，年底了还得同时准备结婚的事项。&lt;/p&gt;
&lt;p&gt;感谢父母，为我无私的付出，在老家举办婚礼，因为我还在北京上班，不方便回来准备，所以事项全是父母到处奔波操办的；也是父母给我的支持，才能让我在北京定居。&lt;/p&gt;
&lt;p&gt;最后，再给 2020 年一个小目标，希望自己能升级（或者升级中）。当然前提就是保证早睡早起，保持运动，把身体先养好。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;工作&#34;&gt;工作&lt;/h2&gt;
&lt;p&gt;今年的事项重点在运维和团队上。&lt;/p&gt;
&lt;p&gt;上半年主要负责系统升级方面事情。&lt;/p&gt;
&lt;p&gt;中间五月底去香港出差了一趟，虽然全国各地去了不少地方，但是出境还是第一次……&lt;/p&gt;
&lt;p&gt;下半年除了运维，在团队的招聘和人员培养上花费了不少功夫，团队逐步壮大了，也希望团队能越来越好。&lt;/p&gt;
&lt;p&gt;2019 年因为个人事项实在太多了，感觉人比较浮，所以 2020 年准备好好的沉淀下自我，包括技术、管理等方面。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;看了杰宝和磊子的总结后，感叹文艺小青年的文字功底就是好，读起来赏心悦目，再看看自己写的，差距有些大。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;2020 年，希望父母的身体健健康康，老婆每天开开心心，自己也向着目标继续努力前行！&lt;/p&gt;
&lt;p&gt;再见，2019！&lt;/p&gt;
</description>
			<pubDate>Sun, 19 jan 2020 00:00:00 +0800</pubDate>
			<link>https://blog.tankywoo.com/2020/01/19/2019-to-2020.html</link>
			<guid isPermaLink="true">https://blog.tankywoo.com/2020/01/19/2019-to-2020.html</guid>
		</item>
			
		
		  
		<item>
			<title>2018 小结</title>
			<description>&lt;p&gt;作为一个曾经的博客高产能者，表示很尴尬，去年就写了一篇博客，还是因为拿到驾照写的，而这篇 2018 的告别篇，也是拖到了 2019 年过了半个月才写。&lt;/p&gt;
&lt;p&gt;其实标题本来准备叫「再见，2018」，因为这次没有总结的动力，不过觉得这个标题稍微有点煽情，所以标题还是叫「2018 小结」了，也就顺带简单的记录下今年的情况。&lt;/p&gt;
&lt;h2 id=&#34;生活&#34;&gt;生活&lt;/h2&gt;
&lt;p&gt;正如 2018 年唯一写的一篇博客，今年终于逼着自己去考了个驾照，算是一件值得庆祝的事情。也就顺带开始摇号，如广大的北京摇号大军一样，漫漫长路看不到头……&lt;/p&gt;
&lt;p&gt;另外今年突然又重拾起对文玩的热爱了，早在几年前玩过一段时间就消停了，今年突然又爆发了这股狂热，并且一发不可收拾，买了各种串和配饰，就像最近流行的一句话：「啥也别说，盘就完了」，手上的老茧正是盘玩的最佳证明。空闲时光就爱喝茶撸串，已经提前为老了后的生活做好目标了。&lt;/p&gt;
&lt;p&gt;最后，划个重点，2019 年和女友把事情敲定。&lt;/p&gt;
&lt;h2 id=&#34;工作&#34;&gt;工作&lt;/h2&gt;
&lt;p&gt;年底去了成都公司一趟，和沟通了几年的网友终于面基了……&lt;/p&gt;
&lt;p&gt;今年的核心任务还是围绕运维平台的打造，一些组件还在调研和开发中。这块要做的东西不少，继续发力吧。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;最近看了 &lt;a href=&#34;https://blog.opskumu.com/bye-2018.html&#34;&gt;磊磊&lt;/a&gt; 和 &lt;a href=&#34;https://www.zhangjiee.com/microblogs&#34;&gt;杰宝&lt;/a&gt; 的 2018 小结，也算是给了我一些动力让我回顾下 2018 年。&lt;/p&gt;
&lt;p&gt;昨天和杰宝聊了下，他说现在不像以前了，研究的东西太散，很少能有大块时间钻研某个点，并且很多技术要么没必要写出来，要么没时间写出来。这里确实感同身受，不过我依然希望新的一年，能好好的分配下时间，多多回顾、记录，不论博客或者其他个人笔记，不论生活上的还是技术上的，定期温故、反省、总结下来，总能学到不少东西。停下来，也许能看到不一样的景色。&lt;/p&gt;
&lt;p&gt;再见，2018。&lt;/p&gt;
</description>
			<pubDate>Wed, 16 jan 2019 00:00:00 +0800</pubDate>
			<link>https://blog.tankywoo.com/2019/01/16/2018-bye-bye.html</link>
			<guid isPermaLink="true">https://blog.tankywoo.com/2019/01/16/2018-bye-bye.html</guid>
		</item>
			
		
		  
		<item>
			<title>拿到驾照</title>
			<description>&lt;p&gt;今年第一篇博客，庆祝下自己在六月七号高考第一天拿到驾照。&lt;/p&gt;
&lt;p&gt;学车的过程还是很痛苦的，得时不时跑到那么老远的地方去学车。&lt;/p&gt;
&lt;p&gt;其实当年高考完时就学过一点，因为太热放弃了，这一拖就是这么多年过去了。从在北京读书到工作这些年，一直没考虑过去拿个证，今年过年时，觉得自己做事太墨迹，不够雷厉风行，好多事情没有趁早做，于是年后回京，马上就去东方时尚报了个名。&lt;/p&gt;
&lt;p&gt;三月初报的名，预约的三月十五号考科目一，期间将App上的法培视频刷了一遍，然后平时上下班路上将科目一的1000多道题目刷了一遍。十五号当天下午考试，考完通过后接着去预约上模拟的课时，去了一会就撤了。&lt;/p&gt;
&lt;p&gt;科目二就是趁着周末有时间就去，每次预约的下午六个小时，最后一次桩训需要连续四天，到四月十七号上完科目二的课程。接着预约的科目二考试，可惜运气不佳。在桩训期间，第一天就将倒桩练得差不多，感觉没问题，结果到考试时有点懵，第一次让从倒桩开始，结果直接挂在倒桩上，第二次从侧方开始，直到最后一项倒桩，结果又挂在倒桩上。&lt;/p&gt;
&lt;p&gt;科二第二次考试是约在五月初，当时周一是科二考前集训和下午的科三路训，周二是第二次考科二，周五第一次考科三。这次科二考试运气不错，虽然在倒桩时还是有点发怵导致熄火了下，所幸其它地方没扣分考过了。&lt;/p&gt;
&lt;p&gt;不过周五的科三挂了，而且挂的有点无奈。前一天晚上睡得晚，然后第二天5点起来赶班车，第一把是我来跑A路线，起步直接忘打方向灯挂了，第二把重新走A路线，一切顺利，到终点停车时压黄线导致不及格，真是上一秒看到希望，下一秒希望就破灭了。&lt;/p&gt;
&lt;p&gt;再一次考科三，就从五月十一号等到六月七号了，因为这一阵子科三挂的人太多了，很多人预约了10多次都没约上。六月六号当天去考前讲解和路训，发现考试规则改简单了，以前需要完全记路，很多地方都没语音提示，而且路线也复杂，现在B路线改了下简单多了，而且除了并道全部都加上语音提醒。六月七号当天上午科三，走的我最不熟悉的C路线，也是目前三个路线中最难的，多次并道加两次掉头，第一把顺利走完，又栽到停车上，当时正半联动准备停在一辆车前面，经过那辆车时，靠的太近，考官踩了刹车，直接挂了，第二次改为我最熟悉的A路线，这次在停车时没出岔子了，有惊无险的通过。&lt;/p&gt;
&lt;p&gt;当天下午2点考的科目四，3点不到就拿到本了，效率非常高。&lt;/p&gt;
&lt;p&gt;从三月初到六月初，大概三个月，时间算是比较长了，总算是拿到本，可以好好休息一阵子了。&lt;/p&gt;
&lt;p&gt;下面给一点经验之谈：&lt;/p&gt;
&lt;p&gt;科目一和科目四（科三理论）都是做题，我是用的驾考宝典，两门都是1000多题，上下班路上每天做几套就行，考前强记下错题集就行。&lt;/p&gt;
&lt;p&gt;科二五项，都是教练帮忙找点，找好点就不要再变了，这个点的位置和座椅位置、后视镜、坐姿都有关系，建议根据一些参照物保持不要变动。&lt;/p&gt;
&lt;p&gt;科三比以前简单多了，其中A、B路都简单，C路相对困难一些，不过都还好，注意路口踩刹车，记住在哪里并道就行，以及加减档的时机。&lt;/p&gt;
</description>
			<pubDate>Sat, 09 jan 2018 00:00:00 +0800</pubDate>
			<link>https://blog.tankywoo.com/2018/06/09/learn-driving.html</link>
			<guid isPermaLink="true">https://blog.tankywoo.com/2018/06/09/learn-driving.html</guid>
		</item>
			
		
		  
		<item>
			<title>2017 总结</title>
			<description>&lt;p&gt;&lt;img src=&#34;https://images.tankywoo.com/20170709-goal.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;明天就是 2018 年了。&lt;/p&gt;
&lt;p&gt;这一年有成就感，也有迷茫感。现在让我好好回顾下这一年，发现很多都想不起来，所以迷茫。我只能努力的回忆一些大体事项，规整下这一年。&lt;/p&gt;
&lt;p&gt;依然和 &lt;a href=&#34;https://blog.tankywoo.com/2017/01/07/2016-summary.html&#34;&gt;2016 年总结&lt;/a&gt; 一样，从几个方面来总结。&lt;/p&gt;
&lt;h2 id=&#34;工作&#34;&gt;工作&lt;/h2&gt;
&lt;p&gt;这是我来公司快第六个年头了。&lt;/p&gt;
&lt;p&gt;今年四月份，原运维部门拆分为基础运维和业务运维，我则是分到了业务运维部门，从属另外一条产品线。&lt;/p&gt;
&lt;p&gt;以前做基础运维，附带协助业务运维，目前职责明确了，只负责业务运维，所以站的角度也不一样了，以前更多的是关注基础组件，现在则是关注业务的稳定性、告警的及时性等。&lt;/p&gt;
&lt;p&gt;因此我这边负责开发了一套业务运维平台，主要开发各种告警、数据收集展示、排查定位工具，供我们和运营同事使用。这套系统目前带来的效果非常好，简化了值班的工作量，能让几个部门第一时间发现问题并及时处理，这也是我开始说的成就感。&lt;/p&gt;
&lt;p&gt;不过整个平台的开发目前只占了我工作时间 40% 不到，还有源源不断的协作事项一直打断我，这也是我比较烦恼的地方。当然，这是工作性质决定，另外侧面也反映目前我们的自动化这块还不完善，这也是明年的目标，在运维平台持续开发的过程，集成自动化的流程系统，做到跨部门协助流程更方便。&lt;/p&gt;
&lt;h2 id=&#34;技术&#34;&gt;技术&lt;/h2&gt;
&lt;p&gt;这是我比较迷茫的地方，感觉折腾了不少，不过都没啥印象。感觉这一年我的技术深度没什么增长，广度也只增长了一点，就是那种很多都是半桶水的感觉。&lt;/p&gt;
&lt;p&gt;去年写了一个个人用的时间统计分析工具，不过后来没怎么折腾了，只是拿来每周自动生成周报。这个我觉得还是挺重要的，我需要好好想想这块，规划自己的技术栈，合理的分配时间，回顾知识。&lt;/p&gt;
&lt;p&gt;我的 wiki 项目 simiki 这一年也停滞了，其实最近在使用时，遇到一些觉得还是挺有需要的需求，明年我会重新拾起，其实去年的年总结我也这么说了，可惜食言了……&lt;/p&gt;
&lt;p&gt;另外就是 Golang 和 前端 的一些东西。用 Golang 写了一点小工具，好几年没写过 C/C++ 这些静态语言，习惯了 Python 等脚本的简单、快速开发，初用 Golang 写还不是很习惯，习惯了弱类型的基本无约束行为。前端这块基本目前是用在运维平台的开发，也就简单的写写，太复杂的还搞不定。明年这两块可以再加强下。&lt;/p&gt;
&lt;p&gt;总的来说，还是因为折腾的太杂，后面需要注意这块。&lt;/p&gt;
&lt;h2 id=&#34;生活&#34;&gt;生活&lt;/h2&gt;
&lt;p&gt;今年8月份，女友博士毕业了，恩，就是传说中的第三类人。然后一起搬到了离公司很远的地方，每天上下班单程需要一个半小时，加上长路导致的疲惫，所以每天回来后能干活的时间也很少。不过有一个独立整套的房子住，比以前的居住条件还是好多了，因此我也开始学着讲究点生活，买了一些盆栽，每天浇浇水弄一弄，也买了一套茶具，因为一直喜欢喝茶，所以每天回来也茗下茶，放松下。&lt;/p&gt;
&lt;p&gt;今年还有个对自己不满意的地方，就是游戏打的有点多，每天都要玩几局王者荣耀，上个赛季主玩大号的狄仁杰，作为本命英雄，新赛季被削了，目前玩另外一个法师号，本命英雄改为露娜了，一直在手残的路上坚持着，前阵子KPL结束趁着露娜皮肤打折，还搞了一个紫霞仙子的皮肤。目前这两个号都在钻石局徘徊。明年要节制一下了，小玩怡情，大玩伤身。&lt;/p&gt;
&lt;p&gt;明年对于生活这块没太多想法，一个是做到早睡早起和多运动，另外一个就是和女友把双方的事情早点定下来。&lt;/p&gt;
&lt;h2 id=&#34;最后&#34;&gt;最后&lt;/h2&gt;
&lt;p&gt;希望新的一年，在前进的道路上不再迷茫。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;题图：&lt;a href=&#34;https://unsplash.com/collections/926920/goals?photo=-87JyMb9ZfU&#34;&gt;by Joshua Earle from unsplash&lt;/a&gt;&lt;/p&gt;
</description>
			<pubDate>Sun, 31 jan 2017 00:00:00 +0800</pubDate>
			<link>https://blog.tankywoo.com/2017/12/31/2017-summary.html</link>
			<guid isPermaLink="true">https://blog.tankywoo.com/2017/12/31/2017-summary.html</guid>
		</item>
			
		
	</channel>
</rss>
