無標題文檔

使用斐讯 N1 作为 Prometheus 监控服务器

新出了树莓派4,性能方面可以说对于老的 3B+ 的版本可以说是有全面的提升。但价格方面 4G 内存配置的就已经需要 50$,已经逼近台 x86 的准系统。同时因为树莓派是裸板,如果想要在生产环境使用,后面还需要自己增加存储、外壳等,全套上去其实性价比已经不高。

个人在家里部署了几台树莓派用来做小的应用服务器以及网关,详细看这里。在社区讨论新的树莓派4的时候,网友无意间说道「为什么不考虑下斐讯的N1?」

N1

由于原先的 Prometheus 和 Grfana 是在台虚拟机里,从安全的角度叫上说监控还是使用单独的硬件更加合适些,所就立马入了台 N1 用来当作单独的监控系统。

硬件

购买的渠道先不说了,总之你总能办法到手的,普遍价格依据成色从几十到一百出头不等。由于是矿难的遗留物,所以建议还是买带包装以及三码合一的产品,差价其实并不是很大。

下面硬件方面,我们对比斐讯的 N1 和树莓派3B+做个对比:

/斐讯 N1树莓派 3B+
CPU 和平台Amlogic ARM64BCM2835 ARMv7
内存2G1G
存储自带 8g EMMC另外安装 SD 卡
外观自带外壳裸板,需要外壳自行购买
价格100+裸板200+,外壳和存储另算

总体来说,对于性能(平台)以及性价比方面,斐讯 N1 都是要比树莓派3B+要强不少的,尤其是 EMMC 是非常加分的项目。具体性能方面,可以参考这篇文档这里不放具体的指标和数字了。

系统

目前二手市场上很多卖家都提供了刷机服务,我这边为了节省时间直接让卖家给刷了 Armbian 系统。

到手以后 SSH 上去发现存储空间有些不对,还需要些调整。原先还有部分 Android 的文件在其他的分区,可以直接执行 blkid 查看可以的块设备。

大概有那么几个块设备可以使用:

/dev/cache
/dev/tee
/dev/system
/dev/data

可用的几个:/dev/data 是目前的根分区,我们不用动它,而 /dev/tee 这个分区太小没有使用的价值,所以个人将 /dev/system 格式化为 ext4 mount 到了 /home 以及将 /dev/cache 作为 swap 分区备用(512MB 有点鸡肋)。

Filesystem      Size  Used Avail Use% Mounted on
udev            789M     0  789M   0% /dev
tmpfs           180M   17M  164M  10% /run
/dev/data       4.4G  2.4G  2.0G  56% /
tmpfs           900M     0  900M   0% /dev/shm
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           900M     0  900M   0% /sys/fs/cgroup
tmpfs           900M     0  900M   0% /tmp
/dev/system     1.2G  294M  855M  26% /home
log2ram          50M   13M   38M  25% /var/log
tmpfs           180M     0  180M   0% /run/user/1000

以及 free(已经运行了部分服务的情况):

              total        used        free      shared  buff/cache   available
Mem:           1.8G        205M        837M         28M        756M        1.5G
Swap:          511M          0B        511M

所以,总体分区调整配置完了以后,大概是这样子总计占用的空间大概 7G 不到一点,但其实足够日常使用了(其实是不想在系统瘦身这块花更多的时间)。

调整完分区,然后关闭不必要的服务和启动项。关闭和删除红外线服务:

systemctl disable lircd.service lircd-setup.service lircd.socket lircd-uinput.service lircmd.service
apt remove -y lirc

关闭 NFS 服务,在集群里已经有 NFS 服务器了,所以不需要:

systemctl disable nfs-server

禁止图形界面启动的 Hook,这个其实没必要操作,但为了避免自启动有些图形应用:

systemctl disable graphical.target

后面添加清华的镜像源,安装 Docker CE 等操作就不复述了。这样子,重启以后系统层面的配置就完成了。

配置

下面主要说下这个机子安装 Prometheus 和 Grafana 遇到的些坑。首先,就是平台的问题,由于是 ARM64 的设备,所以直接用 Docker 镜像(默认 x86/amd64)是行不通的,需要使用针对平台的 Docker 镜像。

下面是我简单的 docker-compose 配置,注意镜像的名称:

services:
  prometheus:
    image: prom/prometheus-linux-arm64:v2.10.0
    container_name: prometheus
    hostname: prometheus
    user: "root"
    restart: unless-stopped
    volumes:
      - /etc/hosts:/etc/hosts:ro
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - ./targets.json:/prometheus-targets.json:ro
      - prometheus-storage:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=6month'
      - '--storage.tsdb.retention.size=2GB'
      - '--web.enable-lifecycle'
    ports:
      - 9090:9090

  grafana:
    image: grafana/grafana:6.2.5
    container_name: grafana
    hostname: grafana
    user: "root"
    restart: unless-stopped
    links:
      - prometheus
    volumes:
      - /etc/hosts:/etc/hosts:ro
      - grafana-storage:/var/lib/grafana
      - grafana-provisioning:/etc/grafana/provisioning
    ports:
      - 3000:3000
    depends_on:
      - prometheus

因为机子的存储容量较少,针对 Prometheus 最好追加个容量方面的限定参数,例如我这边配置了:

- '--storage.tsdb.retention.time=6month'
- '--storage.tsdb.retention.size=2GB'

6个月或者总容量到达 2GB 的时候自动清除老的数据,默认 Prometheus 清除时间为 15d,很多刚开始接触 Prometheus 的同学表示为什么会「丢数据」也是因为这个原因。

注意到 Alert ManagerNode Exporter 以及 Push GateWay 都没有加入 Docker 的部署。原因一来是官方没有针对 ARM64 平台的镜像,二来这些服务相对比较简单、同时数据也不用纳入 Docker Volume 管理,因此就直接下载安装包运行。

后续

安装配置好了以后,上面跑了十几个 Job 用来 Pull 各个节点的状态负载其实并不高:

Status

总体来说,用来监控十几个节点的小集群常规数据是足够了的,还能带起 Grafana 服务。说起来,这些只要一百出头三顿麦当劳的价格,性价比超高。

由于还是担心存储的问题(一般来说是足够了),我还是给它增加了块 64G 的 U 盘(存储比机子贵),挂在 /var/lib/docker 专门用来跑 Docker 服务以及保存 Docker Volume 使用,这样子安心多了。

由于价格便宜,我后面又追加了几台 N1 机器当作备用机以及单独的集群。估计以后 Docker Build 出来的镜像都是 ARM 平台的了(例如我单独给树莓派维护的 Syncthing 镜像),谁叫它性价比高呢。

- eof -

迁移到 Google Cloud Platform

Google Cloud Platform

好吧,又是个比较蛋疼的经历。后来由于发现 Azure 的香港线路非常不友好(电信),最后还是迁移到了 Google Cloud Platform,话说我真的不想再迁移了。

有国际信用卡还是方便的,根据我目前的配置 Google Cloud Platform 几乎可以实打实用一年。据说 Google Cloud Platform 的流量费用还是不便宜的,所以到时候做些必要的优化(虽然访问量其实不高)。后面的具体费用,等账单出来以后再观察。

Microsoft Azure

如果您能看到这篇博客,那么说明站点迁移到 Microsoft Azure 已经完成了。

其实并不是原先的 Linode 空间不好,而是某些不可抗力导致 Linode 日本节点在中国大陆的可用 IP 越来越少。顺便说一句,Vultr 更甚几乎可以说是全军覆没。

虽然相比 Linode,Azure 的性价比并不是很高,但是它有个「东亚」节点(其实就是香港)对于国内线路优化很好。如果不考虑性价比这块的话,Azure 其实也算是个很好的去处。

那么为什么不迁移到阿里云的香港节点呢?嗯,咱聊点别的吧…

整理汇总下最近用 Golang 写的些小玩意

由于工作的关系,所以又点了 Golang 这个技能树。几个月下来,对于这个语言以及对应技术栈的理解不算透彻,但多多少少会有些心得。

在这里整理下最近用 Golang 写的些小工具以及类库,希望能对大家有所帮助。

Genpasswd 简单的密码生成工具

源码地址:https://github.com/mingcheng/genpasswd.go ,根据名字就知道这是个生成随机密码的小工具。这个项目是本人的第一个 Goalng 项目,主要是熟练使用了些对应的脚本和配套的 CI 等工具(Travis 非常好用)。

QQWry 基于纯真 IP 库的微服务应用

源码地址:https://github.com/mingcheng/qqwry.go ,根据 IP 地址反查对应的地理位置等信息。

纯真 IP 库其实不是新东西了,早在以前 QQ 时代显示对方的 IP 信息就基本上会拿这个库来处理。其实,这个项目也只是根据线上现成的项目改进了下,使其支持在线获取以及更新最新的数据库(后续考虑增加 GRPC 的支持)。

NCMDump 云音乐 NCM 格式分析

源码地址: https://github.com/mingcheng/ncmdump.go ,云音乐出于版权方面的考虑有些歌曲在下载到本地的时候,格式是所谓的 NCM 格式。这在导入到其他设备的时候会有些麻烦。

网络上有对应的 C++ 以及 Python 的实现。其实也有对应 Golang 的实现,但会有些 Bug 例如解析某些 flac 封装的歌曲的时候会报异常,所以改进了下。通过这个项目,对于 AES 加密以及文件操作有了很直观的认知。

PIDFile 生成 PID 文件的库

源码地址:https://github.com/mingcheng/pidfile ,由于些 Golang 通常用于 Daemon 的编写,所以会考虑使用 PID 文件避免程序重复启动,因此就有了这个库。

Obsync 华为对象存储同步工具

源码地址:https://github.com/mingcheng/obsync.go ,尝试使用了下华为云的对象存储服务(OBS),发现支持的节点不错而且对比阿里云相对便宜些。诡异的是它还有非洲的节点,速度也不慢电信直连。

这样子,我的线上备份以及同步就有了另外个去处,数据方面也会安心一点。在中美这个节点上,支持下华为吧。

最后,顺便说下 Chaosblade 这个项目,它是阿里的混沌实验实施工具。其源代码相对来说不会很复杂,可以阅读下以后多给它做些改进。

One more thing. 还有个小玩意是 NSFW 的,我改造了下使其支持代理下载,具体的看链接吧:https://github.com/mingcheng/pornhub-dl.go

- eof -

使用多个版本交叉编译 Golang 项目

在编写内部项目中,往往不同的项目因为历史遗留问题,会有存在多个版本的 golang 编译器共存的情况。

同时,由于 golang 的包管理的短板(虽然在 golang 1.11 以后推出了 go mod),因此不可避免的安装 govendorgo dep 等多个包管理工具,非常的混乱。

本地使用多个 golang 的编译器版本其实更容易造成混乱,同时 env 满天飞也非常不方面维护。解决这块的问题很容易就想到了使用 Docker 去编译和检查本地项目, Docker 官方维护了多个版本的 golang 镜像

那么考虑的目标是:

  1. 使用同一个 Makefile 以及 Dockerfile 去维护项目的编译
  2. 因为 golang 1.11 以后官方推出了 go mod,所以尽量使用官方的包管理工具
  3. 接上条,老版本的依赖和本地编译使用 go mod vendor 去管理
  4. Makefile 不管 golang 编译器的版本问题,编译器版本让 Dockerfile 去管理
  5. 本地环境尽量使用最新版本的 golang 编译器,然后导入到 vendor 中

那么这样子,我们可以简单的使用 Dockerfile 去编译执行,例如下面使用编译器版本 golang 1.9.7 类似:

FROM golang:1.9.7 AS builder
# ...
RUN go build .
# ...

但需要注意的是,golang 1.11 之前必须代码在 $GOPATH 中,所以需要映射

ENV GOPATH /go
ENV GOROOT /usr/local/go
ENV PACKAGE ${YOUR_PACKAGE_NAME}
ENV BUILD_DIR ${GOPATH}/src/${PACKAGE}

# ...
COPY . ${BUILD_DIR}

然后在本地使用 go mod vendor 下载依赖包到项目的 /vendor 就可以在老版本中免去使用 dep、govendor 等依赖工具,统一使用官方的 go mod 去管理和下载依赖。

还有需要关注的是 Makefile 需要加个判断,为了增加通用性,建议根据路径判断 golang 的环境路径,而不是判断是否在 Docker 环境下:

# ...
ifneq ("$(wildcard /go)","")
    GOPATH=/go
    GOROOT=/usr/local/go
endif

GO=env $(GO_ENV) $(GOROOT)/bin/go

# ...

build:$(DIR_SRC)/main.go
    @$(GO) build $(GO_FLAGS) -o $(BIN) $(DIR_SRC)

这样子 Makefile 文件就可以同时同于本地高版本的环境以及 Docker 编译环境了。

详细的示例代码可以参看 这个简单的项目(作用只是用于生成随机密码),其中的 Makefile 以及 Dockerfile

最后,有个讨论 vendor 目录到底要不要纳入到版本控制中?我个人的看法是看情况,大部分情况下不会将这些第三方代码纳入版本控制中。主要的理由有:

  1. 这些代码是第三方库的代码,不会直接更改以及维护;
  2. go.mod 以及 go.sum 文件已经保存了第三方依赖的库信息(版本、hash 等等);
  3. 库文件通常会很多,纳入这些的文件会「污染」本地的 git history;
  4. 不同于开源项目,我们本地的开发环境是可控的。

所以,类似的 Consul 等比较大型的项目还是会将 vendor 目录纳入到版本控制中,个人认为这也是因为兼容方面的考虑更多些,而如果个本地项目往往环境是可控的。

- eof -

记次网桥的 Mac 地址改变导致无法链接的问题

家里的小服务器装的是 ArchLinux,在有次 pacman -Syu 以后发现无法连接了,登录上去以后发现原来是网桥的 Mac 地址没有复制过来,导致路由器无法根据 Mac 地址分配正确的 IP 地址。

# ip link show br0
4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether <mac> brd ff:ff:ff:ff:ff:ff
# ip link show eno1
2: eno1: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br0 state UP mode DEFAULT group default qlen 1000 link/ether <mac2> ff:ff:ff:ff:ff:ff

原先的网桥配置如下

$ cat /etc/netctl/bridge
Description="Bridge Connection for KVM"
Interface=br0
IP=no
Connection=bridge
BindsToInterfaces=(eno1)
MACAddressOf="eno1"
## Ignore (R)STP and immediately activate the bridge
SkipForwardingDelay=yes

根据配置上的定义 MACAddressOf="eno1" 为复制 eno1 的 Mac 地址,这样子网桥和网卡的 Mac 地址应该一致才是。不知道为何更新重启以后就无法复制 Mac 地址了。

查看了相关的文档,用换了一种方式绑定网卡的 Mac 地址:

$ cat /etc/netctl/bridge
Description="Bridge Connection for KVM"
Interface=br0
IP=no
Connection=bridge
BindsToInterfaces=(eno1)
#MACAddressOf="eno1"
ExecUpPost="ip link set dev br0 address $(cat /sys/class/net/eno1/address); IP=dhcp; ip_set"
ExecDownPre="IP=dhcp"
## Ignore (R)STP and immediately activate the bridge
SkipForwardingDelay=yes

其中,主要是以下两行

ExecUpPost="ip link set dev br0 address $(cat /sys/class/net/eno1/address); IP=dhcp; ip_set"
ExecDownPre="IP=dhcp"

由于 dhcp 让 hook 去获取了,所以务必设置为 IP=no,否则会重复释放 IP 导致网桥无法建立。以下是相关的参考连接:

我的照片

嗨!我叫「明城」,八零后、码农、宁波佬,现居杭州。除了这里,同时也欢迎您关注我的 GitHubTwitterInstagram 等。

这个 Blog 原先的名字叫 Gracecode.com 、现在叫 「無標題文檔」 。 其实无所谓叫什么名字,作为码农知道取名是件很难的事情。最后想到的这个名字,其实都没啥特别的含义,系统默认的文件名而已。

作为八零后,自认为还仅存点傲娇式的幽默感,以及对平淡生活的追求和向往。 为了免得对号入座和不必要的麻烦,声明本站点所持观点仅代表个人意见,不代表自己所服务公司的立场。

如果您想联系我,可以发我邮件 `echo bWluZ2NoZW5nQGdyYWNlY29kZS5jb20K | base64 -d`

文章

项目