本文公众号

背景

自从上次心血来潮给树莓派装完系统,一直没想好怎么具体使用它的场景,它就这样默默地躺在抽屉吃灰了一年

再次想起它,是一个周日的下午:收到之前在腾讯云买的云服务器快过期的提醒,一个4核8G内存的ubuntu,平时主要用它作为开发机,在本地电脑性能不够的时候,辅助 调试代码,以及 编译服务 ,还是非常顺滑的

但随后登录控制台,一看续期的价格,同样性能比去年要贵个200多(去年 388,今年 646),横向对比了国内几个云厂商价格也都差不多,索性放弃续期了,想着有没有其他办法整个独立的开发环境呢?

让家里台式机一直跑着是种方法,windows 的 wsl 已经非常完善,完全可以当 linux 开发机用了

不过目前自己要跑的服务,也用不上台式机的性能,还有没有更轻量运行的方式呢?

这不就正好,终于可以重新唤醒尘封已久的树莓派咯。虽然4U4G的性能说不上绰绰有余,但就跑几个服务来说还是足够的

本文内容

  • 搭建开发环境(docker、各开发语言、code server)

  • 文件服务器(samba)

  • 监控(prometheus + grafana + node exporter)

  • 远程桌面连接

  • 智能开关

  • 后续展望

系统准备

我的树莓派上安装的是 ubuntu 22,通过 raspberry pi imager(官方刷系统工具)刷入系统并安装,具体的安装可以参考去年写的博客

安装开发环境

笔者比较熟悉的开发模式: docker + 各语言开发环境 + vscode,在树莓派上原样进行安装

docker

安装 docker 的目的主要是能快速启动与主机环境隔离的容器,并进行服务编译。特别是编译 C++ 服务的时候,centos、ubuntu 这类的系统镜像自带的 gcc、glibc 版本往往不足要求,需要升级,但 glibc 的升级稍有操作不慎,又会对系统本身造成影响,所以还是建议在容器中编译相关服务

1
2
3
# 使用阿里源安装 docker
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh --mirror Aliyun

安装后查看版本:

1
2
❯ docker -v
Docker version 24.0.7, build afdd53b

关于在国内拉取容器镜像下载加速方式: 对不同的镜像仓库,如 docker hub 官方镜像、registry.k8s.io(kubernetes 相关服务的镜像仓库,旧域名是 k8s.gcr.io)、quay.io(红帽镜像仓库)等,使用的仓库代理地址各有不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 原拉取镜像方式
docker pull mysql:8.0.31
docker pull registry.k8s.io/kube-apiserver:v1.17.3
docker pull quay.io/dexidp/dex:v2.28.1

# 使用镜像仓库代理拉取方式
## docker hub 官方镜像: 设置中科大镜像加速器
## 参考: https://mirrors.ustc.edu.cn/help/dockerhub.html
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"]
}
EOF
## 重启docker 后再拉取
docker pull mysql:8.0.31

## registry.k8s.io
docker pull registry.aliyuncs.com/google_containers/kube-apiserver:v1.17.3

## quay
docker pull quay.mirrors.ustc.edu.cn/dexidp/dex:v2.28.1

各个语言的开发环境

关于各种开发语言如何安装环境,网上教程一大把,过程无外乎是下载和解压安装包、环境变量配置和下载源配置,熟悉了操作也快,但每次重装系统,或者基于一个基础镜像安装开发环境,都需要重新操作一遍还是挺麻烦的

笔者把常用语言和服务的安装脚本整理在 shell-tools 这个仓库了,可以直接一行指令帮我安装,还可以指定需要安装的版本

比如安装 go、java、python 和 nodejs:

1
2
3
4
5
6
7
8
9
10
11
12
# go_version: 指定版本,默认版本在 Makefile.vars.version 中定义
# NET=CN: go 安装包将从国内源加速下载,并在安装后设置 GOPROXY 为 goproxy.cn
NET=CN go_version=1.21.4 make golang

# 将安装 jdk1.8 (默认开发环境 JAVA_HOME)、jdk17(vscode java 插件使用)、maven、gradle
NET=CN make java

# 将安装 conda、python 3.12
NET=CN python3_version=3.12 make python3

# 将安装 nodejs 18.16.1
NET=CN nodejs_version=v18.16.1 make nodejs

升级 gcc、glibc,也可以使用这个脚本

1
2
3
4
5
6
7
8
9
# 升级 gcc 到 12.3.0
NET=CN gcc_version=12.3.0 make gcc

# 升级 glibc 到 2.35
NET=CN glibc_version=2.35 make glibc

# glibc 的默认安装地址为 /usr/local,因此使用前需要设置环境变量,把 /usr/local/lib 放到前面
## 参考: https://unix.stackexchange.com/a/67783
export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64:/lib

code server

关于 vscode 之前写过常用插件的介绍,远程开发模式下,本地装 vscode,通过 remote ssh 连接到远端服务器,再安装各个开发语言的插件,体验还是很丝滑的

local architecture

架构如上图: 本地运行 vscode 的前端UI框架,后台服务器自动运行 vscode server,负责具体项目和具体开发语言的插件的运行,并提供 debugger、terminal 等功能

更进一步,我们还可以直接在远端服务器安装 code server,它是 vscode 的在线版,相当于UI服务也在服务器上运行,直接通过浏览器就能打开了

local and remote architecture

vscode 和 code server 的对比如上图,区别就是 nodejs(即 UI)也是运行在服务器上的,本机只需打开浏览器即可

code server 在树莓派的安装和配置方式如下:

1
2
3
4
5
6
7
8
9
10
11
# 通过 shell-tools 安装 code server 4.19.0
code_server_version=4.19.0 make code-server

# 配置: /opt/modules/code-server-4.18.0-linux-arm64/config.yaml
bind-addr: 0.0.0.0:8080
auth: password
password: codeserver
cert: false

# 启动
nohup /opt/modules/code-server-4.19.0-linux-arm64/bin/code-server --config /opt/modules/code-server-4.19.0-linux-arm64/config.yaml > /dev/null 2>&1 &

之后打开 http://树莓派内网ip:8080 就能开始愉快地享受网页版 vscode 了

code server 效果

扩展: 如果你想把 code server 提供给小伙伴们一起使用,配置就比较麻烦了,需要加一层 oauth proxy 或其他代理,以支持多用户登录。 jupyterhub 也是一种选择,后续有机会可以写写具体怎么做

文件服务器

除了用于开发,树莓派作为常驻 linux 主机,还可以安装 samba 并作为文件服务器,视频、音乐等媒体统一放到一块硬盘上,作为本地的媒体库

samba

samba 服务对应的 SMB(Server Message Block) 是一种在局域网中共享文件的协议,直接说下它在linux系统的安装方法

1
2
3
4
5
6
7
8
# 安装 samba,并添加 samba 的访问用户(注意和系统用户不同)
apt -y install samba samba-common-bin

# 添加用于登录 samba 的用户: pi, 并设置密码
smbpasswd -a pi

# 激活用户
smbpasswd -e pi

安装后,在 /etc/samba/smb.conf 中配置开放访问的目录

1
2
3
4
5
6
7
8
9
10
11

# vim /etc/samba/smb.conf

[music]
path = /data/music
writeable=Yes
valid users = pi
create mask=0777
directory mask=0777
public=yes
browseable=yes

挂载机械硬盘

在尝试把之前买的机械硬盘(作为媒体数据盘)挂载到树莓派的时候,遇上了一点小问题: 硬盘格式已经是 NTFS 并且放了一些数据了,但linux 系统无法直接读取,需要安装 ntfs-3g 驱动才行

1
apt -y install ntfs-3g

并在 /etc/fstab 中设置开机自动挂盘,参考

1
/dev/sdb1       /data/music   ntfs-3g defaults,nofail,uid=1000,gid=1000,umask=0007,x-systemd.device-timeout=5         0       0

远程桌面

对 linux 系统来说,平时开发写写代码敲敲指令,是不太需要访问桌面的。不过有时想体验 linux 版的应用(QQ),还是可以装个远程桌面来体验一下

常见的远程桌面协议是 xrdp 和 vnc,这里我们通过 xrdp 来配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 安装 xrdp
apt -y install xrdp

# 安装 lxde cinnamon 桌面
apt -y install lxde cinnamon-desktop-environment

# xsession 在用户登录桌面系统后被执行,可用于定制化桌面
# 参考: https://unix.stackexchange.com/a/47426
# 使用 cinnamon 作为桌面
echo cinnamon > ~/.xsession

## 修改 /etc/xrdp/startwm.sh 并在 "fi" 和 “test -x” 中间加3行
unset DBUS_SESSION_BUS_ADDRESS
unset XDG_RUNTIME_DIR
startlxde

# 启动 xrdp
systemctl start xrdp
# 或: /etc/init.d/xrdp restart

# 开机自启动
systemctl enable xrdp

xrdp 的端口 3389 可以在 /etc/xrdp/xrdp.ini 配置中查看和修改

然后通过 microsoft remote desktop 连接:

桌面

非常简洁的桌面

然后我们可以安装新版适配了 linux 的 QQ,从官网下载

1
2
3
4
5
# 下载
wget https://dldir1.qq.com/qqfile/qq/QQNT/2355235c/linuxqq_3.1.1-11223_arm64.deb

# 安装
dpkg -i linuxqq_3.1.1-11223_arm64.deb

监控

到这一步,我们给树莓派装的开发环境算是基本弄好了,可以愉快地在上面构建镜像、运行服务,不过摸着那微微发烫的 cpu,担心也随之而来: 是不是有个好看的面板,能直接看到当前树莓派的状态,做个监控更好呢?

那就话不多说,开始整看板吧

获取树莓派的性能指标

先来看看命令行获取树莓派 cpu 的温度的方式:

参考-使用 vcgencmd 指令查看 Raspberry Pi 的 CPU 溫度、運行速度與電壓等資訊

1
vcgencmd measure_temp | grep  -o -E '[[:digit:]].*'

cpu 温度

vcgencmd 指令是基于树莓派的内核 firmware 自带的指令,能拿到关于系统资源和硬件状态相关信息,如时钟频率、电压、内存等

但通过指令获取参数的方式,采集起来需要额外写脚本,相比 exporter 的方式来说还是不太方便,那么有没有原生的 exporter 可以直接拿到温度数据呢?

node exporter

前面说的系统指令只是粗略看看 cpu 的指标,要想持续监控,还得通过 prometheus 采集、exporter 提供系统指标的机制,把相关指标提前暴露出来

node exporter 是提供系统相关监控指标的服务,在树莓派上部署它的 arm 版本后,可通过 node_thermal_zone_temp 指标获取温度,数据来源是系统文件 /sys/class/thermal/thermal_zone0/temp 即由系统直接提供的 cpu 温度数据

部署 prometheus、node exporter 和 grafana

继续使用 shell-tools 工具一键安装

1
2
3
4
5
6
7
8
9
10
11
12
# 安装 prometheus 和 node exporter
prometheus_version=2.45.0 node_exporter_version=1.6.1 NET=CN make prometheus

# 安装 grafana
grafana_version=10.2.0 NET=CN make grafana

# 启动
/opt/modules/prometheus/prometheus --web.enable-lifecycle --config.file=/opt/modules/prometheus/prometheus.yml --web.listen-address=:3001

/opt/modules/grafana/bin/grafana-server --homepath /opt/modules/grafana --config /opt/modules/grafana/conf/custom.ini

/opt/modules/node_exporter/node_exporter --web.listen-address=":9100"

安装后,在 prometheus 配置文件中添加 node exporter 的本地地址即可开始采集指标

1
2
3
4
5
6
# vim /opt/modules/prometheus/prometheus.yml

scrape_configs:
- job_name: "node_exporter"
static_configs:
- targets: ["localhost:9100"] # node exporter 地址

prometheus 对接 grafana

采集到指标后,关键的一步就是用“酷炫”的grafana看板展示出来,让我们能及时看到系统状态

node exporter 的官方的看板是 node exporter full,分类非常详细,导入看板的 json 文件,并添加 prometheus 数据源(localhost:3001)即可

导入看板

选择 prometheus 数据源

看板效果

开机服务自动启动

前面我们给树莓派已经安装了一系列服务,那么有时候树莓派要重启,我们会想让这些服务也在系统重启后自动启动。docker 这种通过 systemctl 管理的服务,直接执行 systemctl enable docker 就可以了,手动安装的 code server 、prometheus,应该怎么配置呢?

方法也有很多种,常见的有: rc.local、init.d、crontab @reboot 等方法,它们执行的时机各有不同

参考-在树莓派上设置应用程序开机启动的五种方法

什么时候触发执行

linux 系统启动后,/sbin/init 脚本会进行一众系统服务的初始化,顺序我们可以通过 systemd-analyze plot > startup_order.svg 导出,一些自动启动的脚本启动顺序如下:

/etc/init.d: 最先初始化的一批系统服务

rc.local: network 即网络服务启动之后

crontab @reboot: network 启动之前

为什么要特别提到启动顺序,因为有的服务依赖网络相关的基础服务(如网卡初始化),如果通过 /etc/init.d 或是 crontab @reboot 很可能启动失败。相对比,rc.local 的启动顺序较后,可以保证在系统基础服务启动后开始。另外从配置方式来看,systemctl 和 /etc/init.d 都需要基于一定的格式规范,如服务名、依赖哪些服务等,rc.local 则直接写入服务的启动指令即可

下面我们来看看 rc.local 如何配置

rc.local 添加服务启动指令

root 用户下编辑 /etc/rc.local 文件,添加服务的启动指令

1
2
3
4
5
6
7
8
9
10
# vim /etc/rc.local
#!/bin/bash
# 启动 prometheus
nohup /opt/modules/prometheus/prometheus --web.enable-lifecycle --config.file=/opt/modules/prometheus/prometheus.yml --web.listen-address=:3001 > /dev/null 2>&1 &

# 启动 grafana
nohup /opt/modules/grafana/bin/grafana-server --homepath /opt/modules/grafana --config /opt/modules/grafana/conf/custom.ini > /dev/null 2>&1 &

# 启动 node exporter
nohup /opt/modules/node_exporter/node_exporter --web.listen-address=":9100" > /dev/null 2>&1 &

之后通过 chmod +x /etc/rc.local 添加可执行文件,重启树莓派再次登录,可以看到相关服务已经运行起来了

另一个注意点是 rc.local 中的指令是串行执行,前面的指令报错,后面的也不会执行,所以也建议通过 nohup 即后台方式启动服务

智能插座

毕竟性能有限,随着我们在树莓派上部署的服务越来越多,也难免会遇到资源用尽,直接卡住无法连接的情况,除了重启没有别的恢复办法

好几次在外面远程连接家里树莓派,跑了几个比较吃资源的服务卡住之后,又没法重启,真的是很无奈,索性搞了个小米智能插座,感受了一波物联网带来实际的便利

只够插一个插头的位置,稍显不足

还能看到供电量

后续展望

经过了一个多月的折腾,我的树莓派终于可以作为开发服务器长期跑起来了。相比开头说的云服务器,性能方面稍弱,但也带来可以对接本地数据、可随时在手机端重启等好处

之后还能在上面跑什么服务,或者还能和现实世界有什么交互呢?我也还没有特别想好,就粗略地列一列零散的点子吧,看看以后有没有时间继续折腾一下

nas: 我是真没想到竟然真有人去把树莓派当作 nas,参考,数据传输速度上的瓶颈应该还是挺明显的,当作小型文件服务器才比较现实

本地文档库+媒体库: 归档自己所有的音乐、相册、视频、电子书等

传感器: 搞个空气质量检测器,参考