几乎免费的 Serverless Git 私有仓库
作为一名开发者,我们总需要一个地方存放那些不方便公开的个人代码。GitHub 的私有仓库固然好,但总少了点“自己掌控”的感觉,而自建 Gitea 或者 GitLab 也太重,需要一台虚拟机长期运行在一个网页上。最近我探索出了一套省钱方案:利用云服务商的 Severless 的免费额度,配合 Alpine Linux + Dropbear,搭建一个闲时自动关机(0费用)的镜像,能够随时扩容的私有 Git 服务器。
这个方案使用了 SSH 协议来访问一个私有的 Git 仓库,使用容器镜像来运行这个 Git 服务,只有当 SSH 收到请求时才会处理,因此充分利用了云服务商闲时关闭的功能。
方案亮点
- 成本极低:计算资源利用 Azure 或者其他云服务商(例如 Google Run)每月的免费额度;存储使用 Azure Files,对于几乎只有源代码的仓库而言用量非常少。
- 数据安全:将数据作为持久化存储,容器挂了数据不会丢失。
- 自动扩缩容:云服务商往往提供了 Scale to Zero 的功能,没人用时,副本数为 0(不扣费);连上 SSH,立刻唤醒。
技术选型:为什么是 Alpine + Dropbear?
在构建这个镜像时,我没有选择常见的 Ubuntu + OpenSSH 组合,而是选择了 Alpine + Dropbear。这并非为了炫技,而是基于 Serverless 场景节省资源做出的精算。
Alpine Linux 是冷启动和嵌入式的首选。在 Azure Container Apps 设置缩容至 0 后,当你发起请求时,平台需要从零拉起容器,这就是“冷启动”的过程。Ubuntu 的基础镜像通常在 70MB+,而 Alpine 只有 5MB。更小的体积意味着更快的镜像拉取速度和解压速度。在冷启动场景下,Alpine 极简的初始化流程能让我们节省几秒钟的等待时间。
Dropbear:嵌入式灵魂 OpenSSH 是行业标准,但对于一个极轻量的微型容器来说,它显得过于“臃肿”。Dropbear 是专为嵌入式系统(如路由器 OpenWrt)设计的 SSH 服务端。它的内存占用极低(通常仅几 MB),而 OpenSSH 的每个连接进程消耗都要高得多。Dropbear 的服务端和密钥工具都在一个极小的二进制文件中,减少了系统调用的开销。这个容器不需要复杂的 PAM 认证、GSSAPI 或 X11 转发。它只需要一个能跑 git-upload-pack 的安全隧道,Dropbear 刚好提供了需要的一切。
总结: 选择 Alpine + Dropbear,就是为了在最低配的资源限制下,依然能跑出较好的响应速度,同时把内存留给 Git 的垃圾回收机制,防止 OOM(内存溢出)。这样打包好的镜像大小在 10MB 左右,在 100 MB 甚至更低的内存下都能正常运行。这个镜像也非常适合在家庭内部的路由器或者简单的嵌入式设备里运行,可以作为一个几乎无负担的 Git 仓库。
容器镜像配置
我在 GitHub 的容器注册表发布了一个镜像,目前的版本是 1.1.4,源代码发布在一个 Cloudflare 的 R2 存储桶。 sha256sum:4670df2ee8f921a3c8414f5c0e58f8d7262a9e6d8730597d887c1035adf9383e
镜像地址: ghcr.io/kwfcfc/git-server:latest
下面我通过一个 docker-compose 文件和一个 .env 的环境配置文件来介绍这个镜像的用法。
name: simple-git
services:
simple-git:
image: ghcr.io/kwfcfc/git-server:latest
container_name: git-test
ports:
- "2222:22" # 映射到你想要的端口
volumes:
- git_repo:/home/git
env_file: ".env"
volumes:
git_repo: 这是环境变量文件。
# Base64 encoded ed25519 key
ED25519_KEY=
# Base64 encoded rsa key
RSA_KEY=
# you can also mount the authorized_keys into
# /auth/authorized_keys file inside container
AUTHORIZED_KEYS='ssh-ed25519 change-me'
REPO_NAMES='repo1 repo2.git'
GIT_PORT=22 在启动这个镜像的时候,需要传入一个以 base64 编码的 ED25519 和 RSA 的私钥,这样每次容器重启时不会因为密钥的变化而引起本地端的报错。这个私钥和 OpenSSH 格式不同,因此需要使用 dropbear 的工具转换。如果你在本地有 dropbear 的程序和 base64 的编码工具,也可以用下列命令生成:
dropbearkey -t ed25519 -f dropbear_ed25519_host_key
dropbearkey -t rsa -f dropbear_rsa_host_key
base64 -i dropbear_ed25519_host_key
base64 -i dropbear_rsa_host_key 环境变量中的 AUTHORIZED_KEYS 是你本地的 SSH 公钥,一般是 ~/.ssh/id_ed25519.pub 或 ~/.ssh/id_rsa.pub,如果需要多个公钥,也可以将这些公钥每行一个的方式写成文件,挂载到 /auth/authorized_keys 这个文件。 REPO_NAMES 是你需要在这个服务器新建的仓库名称:在启动时,容器会在 /home/git/ 下新建这些仓库。最后 GIT_PORT 是默认的 dropbear 开放的端口。如果你是使用的 docker-compose 或者某些云服务商,可以映射到其他的端口。
连接方法
如果你的 Git 服务器成功运行了,你可以通过下列命令(将GIT_PORT, id_ed25519 和 your_ip 替换为你的配置)测试:
ssh -T -p GIT_PORT -i ~/.ssh/id_ed25519 git@your.ip 如果配置成功,那应该可以看到:
fatal: Interactive git shell is not enabled.
hint: ~/git-shell-commands should exist and have read and execute access. 云服务商的配置部署过程(以 Azure Container Apps 为例)
部署时,有几个关键设置决定了它的成败。
挂载存储 (Volumes):创建一个 Azure File Share。在 Container Apps 中挂载它,路径设置为
/home/git。这样你的代码仓库才能持久化。网络 (Ingress): 需要先新建一个网卡,再让容器应用使用这个地址。
Traffic: TCP
Target Port: 22
Exposed Port: 22 (或者其他,我的建议是选择一个不常用的高位端口,避免被)
极致省钱:Scale to Zero (缩容到0)
这是 Serverless 的精髓。我们要设置规则:有人连 SSH 就开机,没人连就关机。
常见问题 (Q&A)
Q: 日志里总有 100.100.x.x 的 IP 连接后立刻断开,是黑客吗?
A: 不是。这是 Azure Ingress 的健康检查探针。因为我们开启了 TCP Ingress,负载均衡器需要确认端口是通的。忽略这些 Exit before auth 的日志即可。
Q: 冷启动要多久?
A: 大约 15-30 秒。当你第一天早上 push 代码时,可能会卡在这个界面一会儿,一旦容器拉起,后续操作就非常快了。
Q: 每个月真的免费吗?
A: 计算费用: 免费额度包含 180,000 vCPU-秒。对于 0.25 vCPU 的规格,相当于每月 200 小时 的活跃使用时间。对于个人仓库,这几乎用不完。至于存储费用, Azure Files 按量付费。存 1GB 代码每月大概只要 $0.06 (约 0.4 元)。
总结
通过这套方案,我们用不到一杯咖啡的钱,在 Azure 上拥有了一个高可用、自动备份、全球可达的私有 Git 仓库。除此之外,像 Google Cloud Run 或者其他一些云服务商都有相当数量的免费额度,可以让这个镜像以非常低甚至免费的价格运行起来。你也可以尝试在自家的嵌入式设备里使用这样一个简单的 Git 仓库。
评论系统尚未配置。请在 .env 中填写 giscus 所需的环境变量。