普通视图

发现新文章,点击刷新页面。
昨天以前Holmesian Blog

Seafile docker部署相关问题记录

作者 Holmesian
2025年1月5日 17:46

前言

服务器到期了才发现博客已经超过2年没有更新了,虽然博客的时代早已过去,但是留下一些记录总归算是积攒一些情怀。恰好腾讯搞活动,重新开了一台3年的轻云服务,把博客和一些零小服务迁过来,一直在用的 Seafile 服务占用的空间和资源太大就回迁到家庭服务器上,说是家庭服务器,其实就是一台低功耗的小主机,恰好运营商送了两条有IPv4公网的IP,双WAN叠加上行100M、下行2000M,内网2.5G,就跑了photoprism、Seafile、jellyfin等几个吃资源的服务,家里重新装修至今也稳定跑了快一年。现在不当夜猫子,借助全屋智能,每天后半夜服务器自动关机,早上7:50自动开机,所以有些问题可能是因此导致的。

迁移时同步升级到了最新的Seafile Pro v12.0,现将安装过程中遇到一些问题记录下来,算水了一篇文章。

Seafile 服务安装遇到的问题

Docker Desktop 服务自启动

因为这个主机还承担了跟儿子一起电视投屏打游戏的功能,所以只能装windows,所有服务通过Docker Desktop一代docker运行(WSL的二代IO性能实在太差,而且小问题不断)。

众所周知,Docker Desktop需要登录后才能运行,所以要通过计划任务设置不登录自启动,这样开机后即使windows的用户不登陆,Docker服务也可以启动启动了。

windows docker 不登录自启动.png

为了确保网络无问题和系统完全启动,还可以增加等待网络连接和延迟启动的参数。

触发器时间.png

等待网络连接.png

Seafile docker-compose重启之后无法启动问题

Seafile 的docker镜像一直有这样那样的问题,特别是V12版本以前docker部署的服务。总结起来主要是两大类:

mysql服务未启动就绪,Seafile镜像就启动的问题

主要是数据库服务没完全就绪导致seafile镜像中seahub出错退出,这类问题等mysql镜像启动之后,用docker start Seafile可以启动服务;

彻底解决的办法:通过检查机制依赖调整启动顺序,控制mysql 、elasticsearch、seafile镜像服务依次启动,Seafile Pro V12版的 docker-compose.yml 文件已经有相应的内容,可以直接参考使用。

mysql服务已正常工作,Seafile仍无法启动的问题

确认数据库服务启动并就绪,seahub仍然报错往往是因为上一次Seafile镜像关闭时错误导致的(相当于异常关机),重新启动时seafile镜像中的seahub 找不到内部链接报错,这类情况docker start Seafile无法启动seafile服务,必须 docker-compose downdocker-compose up -d重新创建几个关联的docker服务。

彻底解决的办法:
Seafile未完全关闭导致的问题,通过计划任务,在关机前预留关闭seafile服务的时间,开机后预留系统启动和网络连接的时间

关闭前操作.png

Seafile 服务器内部错误

服务器内部错误.png

上传文件块错误.png

升级和迁移完成之后,客户端与服务端同步时看到“内部错误”几个字的错误提示一头雾水,查了官方论坛发现是祖传艺能,好在我之前用了几年都没碰到过,用以下的方法处理后没有再出现过,权当是意外了,希望Seafile服务能一直稳定下去,别再出状况。

对文件系统进行检查

假设Seafile的数据文件是在 E: 驱动器,在cmd中执行以下命令对磁盘文件系统进行检查和修复,确保文件系统正常。

fsck E: /x /f

磁盘文件系统检查完成后,通过以下命令进入Seafile镜像内部,

docker exec -it Seafile /bin/bash

再使用自带的 seaf-fsck.sh 对Seafile的自身文件块进行检查(不加--repair)/修复(加--repair)

cd Seafile-server-latest
./seaf-fsck.sh
./seaf-fsck.sh --repair

没有指定repo 资料库时候,seaf-fsck 会检查所有的文件块,时间可能较长,检查和修复的结果在控制台直接输出。

如果是因迁移、版本升级、磁盘文件系统破坏等原因导致的Seafile 文件块出现问题,一般情况下seaf-fsck即使检查出来大概率也是无法修复的(修复后的服务端资料库与客户端的版本不一致而无法同步,只能二选一),为了后续系统的稳定着想,建议提前备份数据,清空服务端数据后,重新从客户端上传。

解除最大同步文件数量限制

在 .\opt\Seafile-data\Seafile\conf\Seafile.conf 文件中修改或添加以下内容

[fileserver]
port = 8082
max_sync_file_count = -1
fs_id_list_request_timeout = -1

check_virus_on_web_upload = false

避免小文件特别多的文件夹同步

我记得官方原来强调过Seafile不适合用来同步Git仓库,因为Seafile采用文件分块存储机制,将文件拆分成多个小块进行存储,因此可能会破坏这些元数据的完整性,同时也有同步机制的冲突,缺乏针对 Git 的优化,导致同步 Git 仓库出现问题。同理 node_modules 、vendor 之类的目录通常包含大量小文件,Seafile 在同步大量文件时可能会遇到性能问题,导致同步速度变慢,甚至出现错误。

所以添加Seafile-ignore.txt,同步时根据规则排除指定的文件和文件夹,只在客户端生效,以下是的coding文件夹在用的列表,供参考。

# Seafile-ignore.txt
Desktop.ini
*/Desktop.ini
.sync/
*/.sync/
Icon?
*/Icon?
.git/
*/.git/
# OS generated files #
$RECYCLE.BIN/
*/$RECYCLE.BIN/
System Volume Information/
*/System Volume Information/
ehthumbs.db
*/ehthumbs.db
desktop.ini
*/desktop.ini
Thumbs.db
*/Thumbs.db
lost+found/
*/lost+found/
.DocumentRevisions-V100/
*/.DocumentRevisions-V100/
.TemporaryItems/
*/.TemporaryItems/
.fseventsd/
*/.fseventsd/
.iCloud/
*/.iCloud/
.DS_Store
*/.DS_Store
.DS_Store?
*/.DS_Store?
.Spotlight-V100/
*/.Spotlight-V100/
.Trashes/
*/.Trashes/
.Trash-*/
*/.Trash-*/
*.swn
*.swp
*.swo
*.crdownload
.@__thumb/
.thumbnails/
*/.thumbnails/
*.tmp/
*/*.tmp/
*.tmp.chck
*.tmp.chck/
.dropbox/
.dropbox.attr/
.dropbox.cache/
.streams/
.caches/
*/.caches/
.Statuses/
.teamdrive/
.SynologyWorkingDirectory/
@eaDir/
@SynoResource/
DfsrPrivate/
.UTSystemConfig/
*/.UTSystemConfig/
.rqd/
._sync_*.db*
.sync_*.db*
.csync_journal.db*
.owncloudsync.log*
.test/
*/.test/
.idea/
*/.idea/
node_modules/
*/node_modules/
vendor/
*/vendor/
GolangProjects/src/pkg/
GolangProjects/pkg/
GolangProjects/bin/
GolangProjects/test/
*/.vscode/
*/dist/
*/unpackage/
*/__pycache__/
www/rageframe2/backend/runtime/debug
www/rageframe2/web/backend/assets

Seafile 使用过程中遇到的问题

Web 端文件下载失败问题

表现为在 Web 界面中可以正常查看纯文本内容,但需要下载的文件无法打开。经排查发现,问题源于 HTTP 与 HTTPS 协议头的冲突。

我的家庭服务器在 Seafile Docker 前增加了一个原生的 Nginx 来提供 HTTPS 服务,所有请求通过 Nginx 反向代理到 Seafile Docker。由于 Docker 映射的端口仅提供 HTTP 服务,Seafile 将所有 URL 默认定义为 HTTP 协议,导致前端 Web 无法正常下载文件。

解决方法
在 Seafile 的 docker-compose 配置文件 .env 中,添加或修改以下内容:

SEAFILE_SERVER_HOSTNAME=Seafile.youname.com:1234
SEAFILE_SERVER_PROTOCOL=https

如果服务已经初始化,可在 .\opt\Seafile-data\Seafile\conf\seahub_settings.py 中添加以下内容:

SERVICE_URL = "https://Seafile.youname.com:1234"
CSRF_TRUSTED_ORIGINS = ["https://Seafile.youname.com:1234"]
FILE_SERVER_ROOT = 'https://Seafile.youname.com:1234/seafhttp'

日志文件过大问题

运行一段时间后,.\opt\Seafile-data\Seafile\logs 文件夹可能会膨胀至十几 GB。经检查,主要由全文搜索和监控服务的日志引起,尤其是 Seafile-monitor.log 文件,常见错误如下:

Syntax Error (101813): Illegal character <23> in hex string
Syntax Error (101814): Illegal character <1c> in hex string
...

原因
这些错误主要由全文搜索服务引起,而该功能是专业版特有的。由于配置文件中的 log_level 参数在 Seafile Pro 12 中已失效,建议尝试以下措施:

  1. 如果关闭监控服务,在 .\opt\Seafile-data\Seafile\conf\Seafile.conf 中设置

    [monitor]
    enable = false
  2. 如果需要保留监控服务,可关注后续更新以寻找有效的日志级别控制参数。

建议的配置

开启两步认证并关闭 Web 端设置

.\opt\Seafile-data\Seafile\conf\seahub_settings.py 中添加:

TIME_ZONE = 'Asia/Shanghai'
ENABLE_SETTINGS_VIA_WEB = False
ENABLE_TWO_FACTOR_AUTH = True

文件传输性能优化

如果 Seafile 前端有 Nginx 服务,需在配置中增加以下内容:

client_max_body_size 0m;
proxy_request_buffering off;

原因

  1. client_max_body_size:限制客户端上传文件的大小,默认值为 1MB,设置为 0 表示无限制。值过小可能导致客户端上传时出现 413 Request Entity Too Large 错误。
  2. proxy_request_buffering:控制 Nginx 是否在将请求主体(如上传文件)完全读取到临时文件后再转发到后端。设置为 off 禁用缓冲,适合反向代理场景。

再谈Go语言的交叉编译

作者 Holmesian
2021年2月9日 23:42

起因

之前有谈到过 Go 语言的交叉编译,虽然七七八八写了一堆,但是实际上的可操作性还是比较差的,当时使用go-ui-crossbuild项目也已经超过3年没有维护了。

golang-docker.jpg

最近从各个方面感受到了 docker 的方便,又恰好有个老项目需要跨平台编译,就顺手看了一下有没有类似 go-ui-crossbuild 的项目,结果才知道我真的是孤陋寡闻,因为不常用 Go,之前连大名鼎鼎的 xgo 项目都没有发现。

关于 xgo

简单地说 xgo 由两部分组成:一部分是一个(或者说一系列)已经预装好交叉编译环境的 docker 镜像;另一部分是 Go 语言编写的 xgo 可执行程序,xgo 通过调用准备好的 docker 镜像解决涉及到 CGO 的交叉编译问题,可达到一键编译多个发行版本或指定版本的效果。

这里先要大概要把我看到的 xgo 经历捋一捋:xgo项目最早是由 karalabe 大佬创建的,虽然几经发展,可是若干年前就没再更新,停滞的版本不支持Go mod,也存在一定的bug; techknowlogick 大佬 Fork 之后持续更新到支持Go mod,并且兼容到了 Go 1.13 ,但是之后也基本停滞了更新。接着 monkeywie 大佬修正了一些问题并且开始用 github actions 构建 docker 镜像。

PS:突然发现这几天 techknowlogick 大佬又开始活跃更新,做了不少修正,并且通过 github actions 实现了自动构建支持最新 golang 版本的 docker 镜像。

github actions 确实是个好东东。

毒打

作为一个小白,自然是要接受社会(网络)的毒打才能成长的。

我的初始需求是在 MacOS 平台上将一个涉及 CGO 的老项目 Go 源码编译出 win64 平台可以运行的可执行文件。

有了对 xgo 的了解自然就高高兴兴地用起来了。然而当我配置好 xgo 环境,在项目根目录满怀希望地运行

    xgo -v --targets=windows-6.1/amd64 . 

之后久久地沉默让我感觉自己遭受了莫名地毒打,还好当我看到形如


    " go: github.com/PuerkitoBio/goquery@v1.6.1: Get https://proxy.golang.org/github.com/%21puerkito%21bio/goquery/@v/v1.6.1.mod: net/http: TLS handshake timeout  " 

字样的提示之后我就明白毒打我的是谁了。 (下载依赖包的时候遭受网络的毒打)

解决

如果是单纯要梯子的问题很容易解决,但是一方面我的现实情况是这个 docker 是跑在 Parallels Desktop 里面虚拟出来的 Ubuntu 上,这个环境有点套娃的意思,哪怕是从外到内的全局也有点烦,另一方面全局出去终究不是长久之计,于是我就想到了在 xgo 的镜像里添加 goproxy 配置来解决,同时也能够方便使用大陆网络的 TX 。

有遇到同样情况的TX可以直接用我修改的版本

    docker pull holmesian/xgo:latest
    
    go get github.com/holmesian/xgo

所有的用法和原版的xgo一样,只是在拉取依赖的时候使用了 goproxy 。

不放心的TX想自己修改也很简单:先 fork 大佬们的成果,再在 Base 镜像里的 Dockerfile 中加上

ENV GOPROXY=https://goproxy.cn ,direct 

大陆使用代理下载依赖,出错回退direct连接,接着GitHub Action 制作镜像推送到 docker hub,然后修改 xgo 里面的镜像地址编译出可执行文件就可以用啦。

后记

感谢 https://github.com/karalabe/xgohttps://github.com/techknowlogick/xgohttps://github.com/monkeyWie/xgo 等大佬们为 go 交叉编译做出的贡献。

开源的力量令人钦佩。

自行更换 MacBook Pro (A1708) 的电池

作者 Holmesian
2020年11月4日 00:42

老婆大人给我买的 MacBook Pro ,才200多循环电池最大余量就只剩下60%多了(说好能经受 1000 次折腾呢),查了一下相关资料感觉最近几年 MBP 的质量基本上都是在下滑,尤其是电池。

让人最不能忍的是无差别无规律的断电黑屏,重置 SMC(系统管理控制器), NVRAM 等等的方法用尽依然不能解决,今天官方授权点检测确认是电池的问题,鉴于过保售后更换要¥1773,于是自己动手淘了块原厂bq20z45 替换A1713电芯(bq20z451)。

我的这款机型在 iFixit 上的拆解评分为 1 果然不是盖的(表示非常难以拆解和维修),前后折腾了一个半小时,好在满血复活了,省下来的钱可以给S.H买AirPods了。

考虑到现在市面上 2017款 MacBook Pro的拆机教程都或多存在误导,这里就把相关的内容记录一下,希望能帮助到有需要的TX。

注:本文仅供参考,拆机有风险,并将彻底丧失原厂保修资格,动手前请三思。

写在前面

电池型号

2017款 MacBook Pro 有13寸、15寸,其中13寸分带TouchBar和不带TouchBar,不同的版本电池是不通用的,对应的关系如下:

新款无"Touch Bar" 13寸 A1708机型,电池型号:A1713
新款带"Touch Bar" 13寸 A1706机型,电池型号:A1819
新款带"Touch Bar" 15寸 A1707机型,电池型号:A1820


我的是 2017 13寸无 TouchBar 版(A1708),电池型号是 A1713 。因为根据网友的反馈,第三方的电池实在无法达到正常续航的预期,所以我选择了号称原厂的拆机电池(也是胆肥)。

原电池1.png

原电池2.png

更换前自带电池是用 TI 电源管理芯片 BQ20Z451 ,电池生产日期为2017年10月15日,电池固件版本901。

新电池1.png

新电池2.png

更换的电池是用 TI 电源管理芯片 是 BQ20Z45 ,电池生产日期为2016年10月9日,电池固件版本901。

更换的电池比原厂带的电池还大一岁,BQ20Z45 是通用物料,BQ20Z451是客户定制物料,固件一般会略有不同,目前充满电之后使用良好,暂时还没有遇到什么问题,等用一段时间之后再来反馈状况。

基本流程

网上找了一下 MacBook Pro (A1708) 换电池的视频,大多是引导把触摸板拆掉再铲电池,有的甚至是要把主板拆掉再铲电池,这类视频(地址1 地址2 )的步骤仅供参考,可能是考虑到电池底部的胶条实在太难铲除,担心下铲的时候把 触摸板FPC 或者其他元件碰坏所以才做进一步拆除,我是在基本没有拆除其他附件的情况情况下单换了电池。

大概流程是:拆开后盖->解下触摸板接口->拆除电池控制板->铲除电池底部胶条->拆除原电池->安放新电池->接上电池控制板->安装触摸板接口->安装后盖。

初次拆这款机器可能的难点应该在打开后盖、铲除电池底部胶条这两步,要特别小心的是拆除电池控制板的FPC,毕竟FPC很细接口卡扣又非常小,详细步骤和要点记录如下。

详细步骤

拆开后盖

初次拆这款机器可能第一个难关就是打开后盖,后盖有6颗螺丝,两两一组,用的是统一号梅花螺丝刀,对应的位置和螺丝的形状如下图。(为避免歧义,从背面看过去,以转轴在的长边(2颗螺丝边)为前方,4颗螺丝在的长边为后方)

背面.jpg

螺丝位置与形状.jpg

6颗螺丝取下来之后,用拨片从后方边撬开背面板,再以此将背板左右两侧的卡口打开,再稍用力向后抽出背板,如图所示。

拆开外壳.jpg

拆开外壳2.jpg

拆开外壳3.jpg

不出意外的话后盖就顺利打开了,接下来要取下触摸板接口上的排线,再来拆解电池控制板。

后盖打开照.jpg

解下触摸板接口

取下触摸板接口上的螺丝和压扣之后可以轻松取下排线。

拔出触摸板接口详细.jpg

拆除触摸板接口之后.JPG

揭开上图中电池电源板上条形胶纸,露出电池的控制板,建议从做往右揭开条形胶纸,右边不小心容易把排线拔下来。

拆除电池控制板连接

拆除胶条纸之后,看到的排线就是电池与主板的连接线了。排线左右两端均有小插头和卡扣,要把小卡扣掰成竖直状态再将排线从插头中拔出来,后续装排线的时候先插进去再小卡扣掰下去卡住。

拆除电源与主板之间的连接.JPG

取下主板与电池连接的排线之后,取下控制板上的3颗螺丝,中间那颗螺丝上有白色的纸片,应该是用来判断是否拆过电池的,无视或者取下就好。

搞定之后要开始重头戏,拆电芯了……

从左往右撕开胶条纸.JPG

铲除电池底部胶条

原厂电池三块电芯的底部是用胶条粘在机器上的,胶条的粘性非常的好,三块电芯建议先铲两侧的,熟练了之后再来铲中间的。

先放一个错误的铲法,千万不能这样直接撬,或者是一戳一戳的铲,伤机器、坏铲子。

错误的铲出法.jpg

正确的做法是先用铲子的一个胶切进去,根据胶条的位置顶进去,只要铲子顶进去开了小口,再不断扭动就很容易铲下来了。

正确的铲法.jpg

正确的铲法2.jpg

正确的铲法3.jpg

正确的铲法4.jpg

正确的铲法5.jpg

铲中间电芯的时候要特别注意,从左右两侧空余量比较多的一侧入手,结合胶条的位置参照两侧的铲法入手横着铲,千万要避开下方触摸板的排线,一个不小弄坏排线就亏了……

估计拆触摸板换电池的视频就是担心会破坏触摸板的排线。

把3颗电芯底部的胶条都铲开后很轻松的就可以取下旧电池。

终于铲下来了.jpg

安装新电池

电池铲下来之后强迫症可以清理胶条,我尝试着清理完左边电芯的胶条感觉很烦,反正后面换上去的电池也有胶条,就懒得清理了。

铲下来后清理胶条.jpg

新旧电池合影

新旧电池对比.jpg

换上去的电池比原电池年龄还大一岁,上机测试之后是0循环,希望后续别有什么毛病……

上新电池.jpg

电池很轻松地装上去了,装回电池与主板之间排线这里要特别提示一下

FPC右侧.jpg

FPC左侧.jpg

排线左右两侧的卡扣一定要按拆的顺序反向操作,排线插入插座必须足够长,否则后续回认不到电池。安装好电池后可以尝试开机测试,能找到电池没问题了再压实电池再往后装回后盖。

收尾

收尾部分没什么好说的,装回触摸板排线,反向操作安装回后盖。

测试开机.jpg

临时处理OCSP域名无法访问的问题

作者 Holmesian
2020年4月28日 12:59

之前的文章有提到过OCSP,现在本站用的 SSL 证书换成了 Let's Encrypt ,近期由于众所周知的原因,国内无法直接访问 Let's Encrypt 的 OSCP 域名,导致出现了不能签发证书、OCSP Stapling 失败、网页打开慢等问题。

ocsp-stapling-cover.png

经检查目前是 ocsp.int-x3.letsencrypt.org 的 cname 域名 a771.dscq.akamai.net 受到了干扰,可以采用本地修改hosts的方案进行临时处理。

在/etc/hosts中添加

    23.32.3.72     ocsp.int-x3.letsencrypt.org

获取 OCSP 响应

    openssl ocsp -no_nonce \
                 -respout /path/to/certs/holmesian.org/ocsp_res.der \
                 -issuer /path/to/certs/holmesian.org/ca.cer \
                 -cert /path/to/certs/holmesian.org/holmesian.org.cer \
                 -url http://ocsp.int-x3.letsencrypt.org/ \
                 -header "HOST" "ocsp.int-x3.letsencrypt.org"

-cert 、 -issuer 、 -CAfile 分别对应的是子证书、中间证书、根证书,其实全部使用 acme.sh 文件夹中的 fullchain.cer 也是可以的。

-respout 是 OCSP 响应保存位置,将这个位置填入在 nginx 配置文件的 ssl_stapling_file 中,如下开启ssl_stapling。

这里如果出现如下错误的话,说明你的openssl使用了1.1.0版本,这个时候已经不需要指定HOST,把上面命令中的“-header "HOST" "ocsp.int-x3.letsencrypt.org"”删掉就好了。

Missing = in header key=value
ocsp: Use -help for summary.

    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_stapling_file /root/.acme.sh/*.holmesian.org_ecc/ocsp_res.der;

重载nginx服务之后,检查是否成功开启。

    openssl s_client -connect holmesian.org:443 -status -tlsextdebug < /dev/null 2>&1 | grep -i "OCSP response"

1.PNG

最后将有关操作制成脚本,添加到 crontab 中自动更新。

交叉编译Go程序

作者 Holmesian
2018年11月18日 09:30

有几个Go的程序需要放在树莓派上跑,由于树莓派的性能太差、编译工具版本又低,想想还是在其他设备上编译好可执行文件直接拿来用方便,毕竟无需依赖的静态编译是Go的亮点嘛。

Go对交叉编译的支持是极好的:对于没有使用CGO的程序,只需要通过设置$CGO_ENABLED、$GOOS、$GOARCH参数即可轻松地实现跨平台编译;对于使用CGO的程序,大部分情况可以通过配置$CC参数使用自行准备的交叉编译工具进行编译。

cross-compile.png

重点在这里

1、简单来说,没有用到 CGO 的 Golang 程序,直接用编译器自带的跨平台特性即可全平台编译;

2、用到了 CGO 需要发布到ARM平台的Golang程序,推荐自己配置ARM交叉编译环境;

3、用到了 CGO 需要发布到Win/Linux/Mac平台的Golang程序,推荐用使用go-ui-crossbuild 。


下面以macOS为例,简单记录一下过程中踩的坑吧。

不使用CGO的交叉编译

一般做法

在macOS编译Linux和Windows的arm可执行程序:

    CGO_ENABLED=0 GOOS=linux GOARCH=arm go build main.go
    CGO_ENABLED=0 GOOS=windows GOARCH=arm go build main.go

其中:

  • $CGO_ENABLED:0表示关闭CGO
  • $GOOS:目标平台(编译后要运行的目标平台)的操作系统(darwin、freebsd、linux、windows)
  • $GOARCH:目标平台(编译后要运行的目标平台)的体系架构(386、amd64、arm)分别对应(32位、64位、ARM平台)的架构

树莓派属于ARM平台,对于编译给ARM使用的Go程序,需要根据实际情况配置$GOARM,这是用来控制CPU的浮点协处理器的参数。$GOARM默认是6,对于不支持VFP使用软件运算的老版本ARM平台要设置成5,支持VFPv1的设置成6,支持VFPv3的设置成7,详细说明如下:

GOARM=5: use software floating point; when CPU doesn't have VFP co-processor

GOARM=6: use VFPv1 only; default if cross compiling; usually ARM11 or better cores (VFPv2 or better is also supported)

GOARM=7: use VFPv3; usually Cortex-A cores

综上,给跑着linux的老版本树莓派编译Go程序的命令为:

    CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build main.go

关于协处理器

协处理器是协助CPU完成其无法执行或执行效率、效果低下的处理工作而开发和应用的处理器。

这种CPU无法执行的专项工作有很多,比如设备间的信号传输、接入设备的管理等;执行效率、效果低下的有图形处理、声频处理等。为了进行这些专项处理,各种辅助处理器就诞生了。现在的计算机构架(x86、amd64)中,整数运算器与浮点运算器已经集成在一起,一般来讲因此浮点处理器内建于CPU中的协处理器,不算是辅助处理器,不过ARM架构因为低功耗的原因是个例外。

ARM架构中的VFP coprocessor是典型的协处理器,它提供浮点数基本运算(加、减、乘、除、开方、比较、取反)以及向量(vectors)功能,一般来讲,VFP可以同时支持最多8组单精度4组双精度浮点数的运算。

简单地说,使用协处理器可以提升某一方面的性能,可以粗暴地认为是一种硬件加速。

使用CGO的交叉编译

什么是CGO

C语言经过数十年发展,各个方面的开源代码、闭源库已经非常丰富。这对于一门现代编程语言而言,如何用好现成的C代码就显得极为重要,CGO就是一个令人惊异的技术,它允许Go与C的类库交互操作,让Go能够使用C语言积累的各种资源。

CGO作为Go中使用C语言代码的一种方式,在获得好处的同时就必定得有付出,这是亘古不变之理:由于CGO相当于使用了C语言,所以编译使用CGO部分的代码就必须按C语言路子来,而C语言原生的跨平台支持相对Go来说可是差远了,使得使用CGO后要编译跨平台的可执行文件就麻烦多了。

目前解决CGO跨平台编译问题的思路有:

  1. 用目标平台的工具链进行交叉编译
  2. 用原生代码重写CGO实现的功能

用目标平台的工具链进行交叉编译

以树莓派的ARM平台为例,用ARM GNU Linux工具链,编译使用了CGO的Go项目。

macOS的文件系统默认是大小写不敏感的,而交叉编译工具链是基于大小写敏感的文件系统的,所以应当新建一个大小写敏感的磁盘镜像用于安放ARM GNU Linux工具链。打开Disk Utility,然后 File>New Image>Blank Image,然后在弹出窗口中设置名称为armx(名称自定),大小大于512MB,格式为Mac OS Extended的映像。

DiskUtility.png

下载或者按说明自行编译ARM GNU Linux工具链。

假设工具链包已经在~/Download目录中,解压缩工具链到到新建的磁盘镜像中:

    tar -zxv -C /Volumes/armx/ --strip-components 1 -f ~/Download/ARMx-2009q3-67.tar.bz2

ARM-Tool.png

现在,你就已经能够直接使用ARM工具链了,比如要编译main.c程序,可以在终端执行:

    /Volumes/Armx/bin/arm-none-linux-gnueabi-gcc main.c -o main

就可以获得一个名为main的可执行程序,这个程序在macOS是不能运行的,只能在ARM平台设备上的Linux系统中才能执行。

好了,现在开始编译用了CGO的Go程序给树莓派用吧:

    CGO_ENABLED=1 GOOS=linux GOARCH=arm CC=/Volumes/Armx/bin/arm-none-linux-gnueabi-gcc GOARM=5 go build -x main.go

其中$CC参数指定的是ARM工具链位置,如果不出意外的话,编译完成后就可以得到可以在树莓派上运行的Go程序了。

ARMfile.png

如果使用Beego提供的bee工具进行编译和打包,效果也是一样的的。

    CGO_ENABLED=1 GOOS=linux GOARCH=arm CC=/Volumes/Armx/bin/arm-none-linux-gnueabi-gcc GOARM=5 ~/go/bin/bee pack main.go 

Beego-pack.png

交叉编译过程中如果出现错误,多半是因为使用CGO部分的代码,在不同的平台存在不兼容的问题,需要根据错误提示逐项解决。

使用go-ui-crossbuild

go-ui-crossbuild是通过预制好的CGO跨平台编译环境,实现一键编译MacOS、Linux和Windows成品的项目,该项目的地址托管在Github上,使用起来也很简单,下载好docker镜像启动之后在go程序目录执行如下命令即可。

    docker run -v $GOPATH/project_name:/go/src/project_name magj/go-ui-crossbuild gouicrossbuild project_name ./cmd/gui

如果涉及到自身的包依赖,可以参考下列命令,将本地的src都映射到docker中去,编译成功之后会在项目文件夹下生成一个build文件夹,里面分别有MacOS用的app文件,Windows用的exe文件和Linux用的可执行文件。

    docker run -v /Users/holmesian/go/src/:/go/src/ magj/go-ui-crossbuild gouicrossbuild getDocument getDocument ./build

其中getDocument是项目名称,项目目录为/Users/holmesian/go/src/getDocument 。

树莓派安装CentOS

作者 Holmesian
2018年8月25日 13:12

之前在办公室放了块A+型的树莓派跑一些推送、隧道之类的零碎小任务,本来一直都比较稳定,但自从前几个月多加了一个定点爬虫之后就明显性能不足了。恰好这几天收拾老房子的时候找到一块2代的B型版,这简直是久旱逢甘霖啊~

想到今年发布了支持树莓派2和3的armhfp版CentOS,所以在距2018年一建考试只剩21天之际的今天,忍不住手痒要折腾下了。

051111083756523.png


准备SD卡

树莓派2用的是Micro SD卡,把一块容量大于4G的Micro SD卡插在读卡器上接入电脑上后,先找到对应的设备符号:打开「Terminal」,执行diskutil list命令。

    #diskutil list 
    /dev/disk0 (internal):
       #:                       TYPE NAME                    SIZE       IDENTIFIER
       0:      GUID_partition_scheme                         500.3 GB   disk0
       1:                        EFI EFI                     314.6 MB   disk0s1
       2:                 Apple_APFS Container disk1         500.0 GB   disk0s2
    
    /dev/disk1 (synthesized):
       #:                       TYPE NAME                    SIZE       IDENTIFIER
       0:      APFS Container Scheme -                      +500.0 GB   disk1
                                     Physical Store disk0s2
       1:                APFS Volume Macintosh HD            278.8 GB   disk1s1
       2:                APFS Volume Preboot                 21.8 MB    disk1s2
       3:                APFS Volume Recovery                519.0 MB   disk1s3
       4:                APFS Volume VM                      5.4 GB     disk1s4
    
    /dev/disk2 (external, physical):
       #:                       TYPE NAME                    SIZE       IDENTIFIER
       0:     FDisk_partition_scheme                        *15.9 GB    disk2

可以看到系统给SD卡分配的设备符是/dev/disk2。当SD卡中含有macOS能够识别的分区时(比如FAT32、extFAT之类的),会被Finder自动挂载,如果不将系统自动挂载的分区卸载掉的话,后面dd烧写操作将会提示device busy,导致无法写入。在Terminal中执行diskutil umount命令:

    #diskutil umount `mount | grep "/dev/disk2" | awk '{print $3}'`
    Volume NONAME on disk2s1 unmounted

顺便提一下的这里的坑,如果SD卡挂载的分区名称中含有空格,例如"NO NAME"(如果烧录中断重新插卡就会是这个名字),那么用上面的命令进行卸载会失败,请手动将“NO NAME”中间的空格去掉。

烧录镜像

SD卡准备好,接下来就要开始下载镜像,官方的下载地址:

http://mirror.centos.org/altarch/7/isos/armhfp/

这里我选择了 CentOS-Userland-7-armv7hl-RaspberryPI-Minimal-1804-sda.raw.xz 这个压缩包,文件名中:Minimal表示最小化(无GUI),RaspberryPI表示树莓派定制版。下载完成检查checksum后,进行解压

    xz -d  /Users/holmesian/Downloads/CentOS-Userland-7-armv7hl-RaspberryPI-Minimal-1804-sda.raw.xz

这个压缩包解压之后得到的是raw文件,和其他发行版提供的img格式不一样,如果是在windows操作,就不能用WinImage烧了。在macOS和Linux下用dd进行烧录:

    sudo dd bs=4m if=/Users/holmesian/Downloads/CentOS-Userland-7-armv7hl-RaspberryPI-Minimal-1804-sda.raw of=/dev/disk2

其中值得关注的是bs参数,bs = bytes 同时设置读/写缓冲区的字节数(等于设置ibs和obs)。正确调整bs参数可以显著提升烧录的速度。

在dd命令的执行过程中可以通过 killall -SIGINFO dd 来查看传输进度,相应的反馈是这样的:

    #sudo killall -SIGINFO dd
    17+0 records in
    16+0 records out
    67108864 bytes transferred in 26.935566 secs (2491459 bytes/sec)

    678+0 records in
    678+0 records out
    2843738112 bytes transferred in 1062.362222 secs (2676807 bytes/sec)

烧录完成之后,用 diskutil eject 命令弹出SD卡,成功弹出后将SD卡从电脑上拔下来:

    #diskutil eject /dev/disk2
    Disk /dev/disk2 ejected

配置系统

把SD卡插入树莓派,网口连接上配置好DHCP服务的网络,加上1000毫安(为5.0 W)的电源,指示灯正常闪烁的话就可以通过分配的IP地址SSH连接上CentOS,初始用户名和密码如下:

UserName:root
Password:centos

成功登陆之后首先应当将可用分区扩展到整个SD卡:

    /usr/bin/rootfs-expand

接着修改root密码,并新建一个用户holmesian:

    #useradd holmesian
    #passwd holmesian
    
    #usermod -aG root holmesian

将新建的用户加入sudo列表

    #visudo

增加内容,让holmesian用户能够免密码使用sudo:

holmesian ALL=(ALL) NOPASSWD: ALL

启用BBR换回iptables服务SELinux放行SSH端口就参照以前的内容了。

yum源配置

很遗憾,国内几乎没有可用的armfhp版CentOS源,所以只能用其自带的源,好在速度勉强可以接受。至于EPEL源的话官方提供了一个未经质检或测试的自动建设EPEL源,使用方法如下

    vi /etc/yum.repos.d/epel.repo

添加下列内容

    [epel]
    name=Epel rebuild for armhfp
    baseurl=https://armv7.dev.centos.org/repodir/epel-pass-1/
    enabled=1
    gpgcheck=0

测试之后发现,这是一个基于fedora aarch64版的源,所以可以将epel.repo的内容改为上海交大的源:

    [epel]
    name=Extra Packages for Enterprise Linux 7
    baseurl=http://ftp.sjtu.edu.cn/fedora/epel/7/aarch64/
    enabled=1
    gpgcheck=1
    gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7

鉴于两个都是没有质保的,且支持armhfp的CentOS源是在是太少,请需要的TX自己选择吧。配置好yum源之后就赶紧更新,在装点必要的编译工具吧:

    yum update
    yum install -y gcc-c++ pcre pcre-devel zlib zlib-devel openssl openssl-devel 

其他内容

后续在这里更新一点相关的Tips吧。

内核更新

对于树莓派2和树莓派3,直接yum update会将内核更新,无须做任何其他的事情,只要重新开机便能运用新的内核。

armv7hl与其他版

你也许应知道 armv7hl 平台的发行版本被称为 CentOS Userland Linux 而不是 CentOS Linux。个中原因是由于 CentOS 替换结构 SIG 有权加入其它组件,取代某些组件,或不创建上游发行版本的某些组件。内核就是最显著的例子,因为 kernel 3.10.0-*(即 CentOS 7 x86_64 发行版本用的内核)并不支持 armv7hl 底板/结构。

更多内容详见官方说明

内核版本

    # uname -a
    Linux RPi 4.14.65-v7.1.el7 #1 SMP Mon Aug 20 19:04:20 UTC 2018 armv7l armv7l armv7l GNU/Linux

发行版信息

    # cat /etc/os-release
    NAME="CentOS Linux"
    VERSION="7 (AltArch)"
    ID="centos"
    ID_LIKE="rhel fedora"
    VERSION_ID="7"
    PRETTY_NAME="CentOS Linux 7 (AltArch)"
    ANSI_COLOR="0;31"
    CPE_NAME="cpe:/o:centos:centos:7"
    HOME_URL="https://www.centos.org/"
    BUG_REPORT_URL="https://bugs.centos.org/"
    
    CENTOS_MANTISBT_PROJECT="CentOS-7"
    CENTOS_MANTISBT_PROJECT_VERSION="7"
    REDHAT_SUPPORT_PRODUCT="centos"
    REDHAT_SUPPORT_PRODUCT_VERSION="7"

安装python3 gevent

    yum install python34 python34-devel python34-pip
    pip3 install -U setuptools
    pip3 install -U pip
    pip3 install gevent
❌
❌