博客部署更新

很久没有写博客了。几年前前把 raptium.net 放入归档模式以后,开了现在这个 hguan.me 站点。然而写了几篇烂尾的文章以后,整个站点都烂尾了,再也没有更新过🤦🏻‍♂️。 最近又想重启写博客和瞎折腾,所以就先把本站的部署方式更新了一下。 本站是一个 Jekyll 生成的静态站点,功能非常简单。原本是放在一个 Linode 机器上,在 Docker 容器中跑了 nginx,前面用了 CloudFlare。 之前的部署方式比较原始。我使用 nginx 和 nginx-proxy 等容器组合的方式来跑多个站点,而容器编排则近乎手动:基本上一个站点写一个 docker-compose.yml,然后用 docker-compose 命令行启动。虚拟机重启之类的情况下,常常需要手动去重启容器(应该是可以配置自动,我不会……),容器多了还是挺麻烦的。另外 nginx-proxy 也时有配置不更新的情况发生,大概是我打开方式不对。 这回我希望找一个更加自动化的方案,另外我希望整体比较简单,现在折腾的动力大不如以前了。 我知道 Kubernetes 是当下最常用的容器编排系统,但一直没有时间去学,并且工作上也没有机会实际上手使用。这块知识其实是脱节了。而这次只是为了自己的博客网站,使用 k8s 没有什么必要,我的 VPS 也跑不动这么高级的系统。做了一些简单调研后,我决定用 Docker 自带的编排方式:Docker Swarm。 我参照 https://dockerswarm.rocks/ 做了大部分配置工作。启用了 Docker Swarm 后,我安装了 Swarmpit,这是一个 Docker Swarm 的 Web UI;我还安装了 Traefik,这是一个 HTTP 网关,Traefik 本身自带 Web 控制面板,就不再需要另外找了。 这样基本上部署方案就齐了。之前的 docker-compose.yml 稍加修改,就能部署到 Docker Swarm 集群(尽管目前只有一个节点)上面。Traefik 作为 HTTP 网关,取代了之前用的 nginx-proxy,它可以从 Docker 的容器元信息上获取路由规则及配置,不需要额外的设置。 处理完部署,我想把 CI/CD 也都做完。现在 GitHub 有免费的 Action 可用,其实已经非常容易。在 GitHub Action 中,使用 Jekyll 生成站点 HTML 文件。因为最终需要部署到 Docker,产出最好是镜像,所以又在 Action 中加了一步,把 Jekyll 的产出放到一个 nginx 镜像中。GitHub Package 提供了免费的 Docker Image Registry,于是再加一行配置即可将构建好的 Docker 镜像推到 GitHub Package。这样只要我将站点的更新推送到 GitHub,就会触发构建流程,能在 GitHub Package 中拿到最新版的站点镜像。 ...

August 18, 2020 · GUAN Hao

GraphQL 小试

今年我一直比较关心 Facebook 的几个开源项目。一开始可能还是跟风和赶时髦心理——听说 React 比较火,为了不落伍,就尝试写了点玩具代码,用下来的感觉是极好的……然后还有个附带结果就是,我对 Facebook 的好感度涨了不少。于是最近 GraphQL 出来之后,也就迫不及待的要试一试。不过因为现在工作比较忙,也可能是我越来越懒了,这回主要还是看了一些视频跟文档。当然,基本还算是了解了这个东西的。 GraphQL 是一种查询语言,Facebook 发布的是一个 Specification,也就是一些文档,而并非一个框架或库(虽然确实 Facebook 也开源了一个基于 node.js 的参考实现 graphql-js)。给我的感觉就是这个东西是有高度的:如果是框架或者工具库,那么他可能作为工具可以提供便利。而一种查询语言,其实包含的是一种设计的思想,如果这种设计真的有优越性,那么它带来的影响将比一个框架要来的大。 API 设计的问题 认识 GraphQL 之前,可以先回顾一下其他的 API 形式。 RESTful 是一种被推崇的设计,现在很多服务对外提供的接口都是这种形式:服务提供的数据被抽象成几种 resource,然后每种 resource 可以被 get/put/update/delete 等等动词操作,当然也可以用一些更有业务意义的动词比如 list/show/upload 之类(RESTful 的定义并非是严格的)。不同的 resource 之间可以有关系,如何表达关系则是一个需要权衡的问题。 以新浪微博的接口为例:statuses/public_timeline 接口返回用户能看到的公共 Timeline,其中每一条是一个 status 也就是一条微博。 那么这个 status 上必然是有 user 字段的,也就是有这条微博的作者信息,这就表达了一条微博和一个用户的关系。那问题是,public_timeline 接口上,每个 status 需要有 user 的哪些信息呢?最少,提供一个用户的 ID 就可以,因为根据 ID 我们可以通过另一个接口 users/show 来获取这个用户的其他信息。但是如果这么设计,可能很多常用的功能——比如显示这条微博作者的名字、头像,都需要访问两个不同的接口,对调用方不友好。换一种方式,我们当然也可以把 users/show 能返回的所有信息都嵌入到这个 status 里。这么做调用方确实是方便了,但大部分场景可能也并非需要访问用户的全部字段。接口暴露过多的冗余字段会浪费服务器网络带宽,对于移动客户端来说,浪费流量又是一个头疼的问题。于是这就要在字段间做一些选择,新浪微博的做法是嵌入了部分常用字段。 如果我们并非要对外提供通用的 API,而是给自己的前端、移动端提供接口,那么 Custom Endpoint 的形式也是很常用的设计。所谓 Custom Endpoint,就是专事专办,为每一项业务场景提供单独的接口。还是以微博为例,如果我们要做的客户端显示 Public Timeline 时只需要展示作者的名字和头像,那么接口中可以只包含这两个字段。这样调用起来一次就能得到需要的信息,也不存在多余字段浪费资源的问题。 ...

December 22, 2015 · GUAN Hao

我的 GH60 键盘

还记得买 HHKB 之前,曾经在淘宝上看了好久各种机械键盘,当时的想法主要还是舍不得钱,希望能够找到一个廉价的替代品。其实对于 HHKB 的静电容轴,我倒是没有什么偏好,因为在买之前我其实根本没有用过机械键盘,也不知道那些轴有啥不同(其实现在也不知道……)。我主要的考虑还是配列,我想要一个紧凑一点的键盘,并且配列适合在 Linux/Mac 下使用,至于轴什么,无所谓,只要是机械的就好。 看了不少键盘下来,Poker 2 是最接近我想要的,大小合适,价格不贵。然而 Poker 2 有个硬伤,ESC ~ ` 在同一个键上,这三个键还都算挺常用,都要组合键的话略麻烦,所以只好排除在外了……于是就想,要是有个键盘能够自定义配列就好了,结果搜了下——还真有,那就是 GH60 了。 GH60 是 geekhack.org 上的一个开源键盘项目,硬件上 PCB 版设计开源,软件上 firmware 也开源,可以随便改配列,自己刷。顾名思义,GH60 是一款 60% 键盘,PCB 在设计的时候,充分考虑了各种不同的配列。功能键的排列、宽度等,都可以根据自己需要调整。用 GH60 照着 HHKB 配一把,那当然是没有问题的。问题是,这个板子哪儿能买到?壳子去哪儿找?轴怎么焊?记得当时在淘宝上也搜过,算下来好像也不便宜,甚至可能比 HHKB 还贵,于是作罢。 最后就是去年年初的时候我买了 HHKB,然后一直用的很爽……也没有入坑的感觉,我觉得我不会要再买一把键盘的。直到有一天,我发现家里的逻辑键盘没法忍了,按起来实在太难受了…… 大概去年11月的时候,看到 v2ex 上有团购贴,卖 GH60,全套方案,自己啥都不用做,买来就能用。既然这么好,那就买买买咯~于是,下单,开始了漫长的等待……每隔几周和卖家问一下进度,几乎等到这事儿要忘记了,键盘来了。然后发现,有一排键是坏的……和卖家商量了返修,又是等啊等……这段时间里面,海哥都已经从别家配了一把 GH60,欢快地用了一个月了……最后键盘修完回来,还是坏了两个键,只好怒退了。还好卖家态度不错,立即同意了退货,也承担了运费,我算是没有损失。但是,我还是没有 GH60 用啊…… 然后我又开始了淘宝,找啊找,让我找到一家常州的卖家,有 GH60 的板子卖。于是加了旺旺,商量让他帮我焊一把,从他家拍了全套配件:板子、外壳、钢板、轴、键帽……然后又是等了。这个掌柜还不错,多次跟我商量配列,键帽。然后键盘做完,都要过年了……想着过年快递就不靠谱,我又怕键盘再是坏的,所以就还是自取吧。年前也没啥时间,最后我竟然是在甲午年的大年三十早上去常州电脑城把键盘给拿到了。 拿回键盘后刷了 HHKB 配列,目前用了几天,感觉良好。因为是黑轴,按起来感觉要比 HHKB 硬,晚上回来用了一阵之后早上再去公司会感觉 HHKB 好软……另外就是这键盘壳子略高了,感觉用了手腕有一些吃力。不过之前看到淘宝上有卖木质手托,挺有逼格,于是又下单了……也许用上手托感觉就会好一点吧。 嗯,好久不写东西,只能写出流水帐来了。无所谓啦,写这么多,其实我想说的就是,我貌似入了键盘的坑啊……

February 27, 2015 · GUAN Hao

第一次当面试官

几周前我第一次作为面试官,对一位投了我们实习生职位的同学进行了电话面试,结果是这位同学被我拒了。也算是我第一次当面试官,写点字记录一下。 某周五收到经理一封邮件,叫我联系一位同学进行电话面试,同时邮件里附上了简历。并且经理又告诉我,如果这位同学入选了,最后会安排来帮我的忙。所以我对这场面 试还是很重视,也是很期待的。 首先是看简历,乍一看排版比较简单,于是不敢怠慢,因为据说牛人的简历常常排版很简单。再看内容——希望国某排名不靠前但也算出名的大学本科 CS Major 在读,嗯,学历上没有问题。海外求学经历略有加分,只可惜不是牛校。再看技能,Java 和 Python 精通,嗯,正好是我现在用的最多的两种语言,加分。其他么,当然少不了人人都(以为自己)会的 HTML, JavaScript, CSS……最后还有 MATLAB。然后看学的课,该学的基础课都学了,貌似还特别喜欢图像处理。项目经历里也有一 个 HDR 图像生成的项目。嗯,这么看来面试应该有得聊,他一定想不到当年我本科 FYP 也是搞的图像处理。 于是开始准备面试题,从经理那边要来一份题库,看了下,大部分我也不会:-( 只好慢慢挑,找了几条挺基础的题目。代码题找了两条,都是挺简单的。最后又准备了一道 当年我去 Google 面试的时候被问到的题目,算是智力题吧,如果答上来也能当代码题做(不过我那次没有被叫写代码)。嗯,题目准备的差不多,我再把客套题也准备了下,比如自我介绍啊,介绍自己做的项目啥的,都想了一下要怎么问,我这准备也算是充分了。 周一早上约了个下午面试,下午我准时打了电话过去,面试顺利开始,这都没啥好说的。 客套了下,叫自我介绍,再介绍一下项目经历,实习生嘛,项目经历也没太多可聊,于是就直接开始问问题了。 先问了个 OO 的概念多态,嗯,反应不快……想了会儿还是基本能答上来。 再问了个 Singleton,呃,不知道,想了一会儿能说个大概,但是不知道怎么实现。 再问问进程和线程的区别,这个就说不大清楚了,除了一个进程能有多个线程外,好像其他就都不知道了。 再问进程间常用的通讯方式有哪些,这个就……也啥都不知道了。 也许没上过 OS 课?他又说上过……好吧,也许你们学校教的比较简单吧。 没关系,会写代码就行,反正招来也就是写代码的~ 折腾了半天,打开了 collabedit.com,一个协作工具。 于是第一题 方法输入一个字符串,里面包含一些空格分隔的单词,将这些单词逆序排列,并仍旧以空格连接成字符串输出。 提示了可以随便用啥语言,随便用什么库。输入里没有奇怪的东西,不用考虑异常和边界。 既然 Python 精通,我想这题目可以用 Python 快速搞定,本来这题的目的也是热身。不说写个 Python One-Liner,写个 Loop 也就几行的事。可是,这位同学选择了用 Java……那也行,没啥不好,Java 也就稍微多几行嘛。结果后面就开始磨蹭了:先是声明个数组存单词,可是又不知道单词有多少个,倒是知道数组长度不能变,于是怎么办?不知道有 List…… 这下好,想了半天,真机智,先数一下有多少个空格,再声明数组吧…… 于是继续写,呃,好像又搞不定,数完 空格,不知道怎么把词搞到数组里去……好吧,再提示一下,别折腾了,可以用 String.split 啊!于是擦掉,改用 split,得到了一个数组,可是怎么把它倒过来呢?啊,有个数据结构叫 Stack,FILO,嗯,就用它!少年你怎么能如此机智……把一个数组倒过来输出,需要用一个 Stack 吗?Anyway,最后得到了一个逆 序的数组,可是不知道怎么拼成字符串,算了就这么输出吧。这段代码写了有20分钟吧…… 于是第二题……也就可以不用写了。本来我是准备了一个求二叉树高度的题目,也没啥难度,递归的话就几行。 嗯,这样子不开心,不如再问个题,于是把 Google 的智力题问了,想了一会儿,这题目倒是能想出来怎么做,当然代码就不写了吧。 后面又客套了几句,什么你有啥要问我的之类,后来我也记不清自己说了啥就拜拜了~ ...

June 20, 2014 · GUAN Hao

写点什么

已经有一两年没有再开博客了。之前有很长一段时间过得不是很开心,又觉得没有什么东西可写,又或者是懒,总之是不想写。 现在想来,写点东西终究是好的,哪怕只是一些废话留着将来看也很有趣。不管是生活中的事,还是工作上的事,以后有空就写点什么吧~

May 7, 2014 · GUAN Hao