在 Linode 上部署 Guix 镜像

Lobsters Hottest 工具

摘要

本文提供了一篇技术指南,关于直接在 Linode 云服务器上部署 Guix 系统镜像,包括用于系统配置的代码片段。

<p><a href="https://lobste.rs/s/mf2lic/deploying_guix_images_on_linode">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/09/27 01:31

# 在Linode上部署Guix系统镜像 — dthompson 来源:https://dthompson.us/posts/deploying-guix-images-on-linode.html 今日,我将从Digital Ocean迁移至Linode(现为Akamai Cloud,但我绝不会*真的*用这个名字称呼它),原因之一是Digital Ocean最近向Omarchy(https://www.digitalocean.com/blog/digitalocean-joins-omacom-foundation)捐赠了300万美元——这是一个为法西斯主义者准备的劣质发行版。为自由开源软件开发筹集资金本就艰难,因此当某个*甚至不再编写代码的人*(https://jardo.dev/what-about-rails)能轻松获得巨额资金,而诚实的项目却只能争夺小型资助机构那点微薄经费时,这种现象确实*颇具讽刺意味*。不过暂且不谈这些! Guix手册中有一些关于在Linode上运行Guix的文档(https://guix.gnu.org/cookbook/en/html_node/Running-Guix-on-a-Linode-Server.html)。其方法是从Linode内置的Debian(安息吧(https://toot.cat/@dthompson/117322463609022181))镜像开始,然后将其转换为Guix系统。作为前运维人员,我对此方案并不满意。我真正希望的是直接上传一个可直接用于Linode的Guix镜像。长话短说:我找到了解决方案。 我的Linode磁盘镜像实现了以下功能: - 允许在初始内存盘中使用虚拟磁盘设备 - 为根目录 `/` 和交换空间挂载正确的设备 - 在启动时调整根文件系统大小以使用Linode底层卷的全部空间(需要自定义服务实现,因为Guix自带的`resize-file-system-service`在此场景下无法工作) - 启动能识别我公钥的SSH服务器 - 启用免密码`sudo`以便后续使用`guix deploy` - 将引导文件安装到Linode能识别的位置 - 除IPv4地址外,通过DHCP获取IPv6地址 以下是最终实现的代码: ```scheme (define-module (dthompson linode) #:use-module (gnu) #:use-module (gnu packages linux) #:use-module (gnu packages ssh) #:use-module (gnu services) #:use-module (gnu services admin) #:use-module (gnu services networking) #:use-module (gnu services shepherd) #:use-module (gnu services ssh) #:use-module (gnu system linux-initrd) #:use-module (guix gexp) #:use-module (guix modules) #:use-module (guix profiles) #:use-module (nongnu packages linux) #:export (%linode-base-services linode-base-os)) (define ssh-authorized-keys `(("dave" ,(local-file "../keys/dave.pub")))) (define guix-signing-keys (list (local-file "../keys/signing-key.pub"))) ;; 理想情况下我们应直接使用Guix的resize-file-system-service, ;; 但其预设假设与Linode环境不兼容。 (define (resize2fs-shepherd-service device) (list (shepherd-service (provision '(resize2fs)) (requirement '(user-processes)) (one-shot? #f) (respawn? #f) (start (with-imported-modules (source-module-closure '((guix build utils))) #~(lambda _ (invoke #$(file-append e2fsprogs "/sbin/resize2fs") #$device)))) (documentation "启动时调整ext文件系统大小。")))) (define resize2fs-service-type (service-type (name 'resize2fs) (extensions (list (service-extension shepherd-root-service-type resize2fs-shepherd-service))) (default-value #f) (description "启动时调整ext文件系统大小"))) (define %linode-base-services (cons* (service dhcpcd-service-type (dhcpcd-configuration ;; Linode服务器通过SLAAC获取IPv6地址, ;; 默认"private"设置无法正常工作。 (slaac "hwaddr"))) ;; 仅通过公私钥对访问SSH。 (service openssh-service-type (openssh-configuration (password-authentication? #f) (authorized-keys ssh-authorized-keys))) ;; 自动调整根文件系统大小以利用全部分配空间。 (service resize2fs-service-type "/dev/sda") ;; 防火墙默认阻止几乎所有连接。 (service nftables-service-type) (modify-services %base-services ;; 允许其他Guix机器通过'guix deploy'推送存储项。 (guix-service-type config => (guix-configuration (inherit config) (authorized-keys (append guix-signing-keys %default-authorized-guix-keys))))))) (define linode-base-os (operating-system (locale "en_US.utf8") (timezone "America/New_York") (host-name "linode") (users (cons (user-account (name "dave") (comment "David Thompson") (group "users") (home-directory "/home/dave") (supplementary-groups '("wheel"))) %base-user-accounts)) (sudoers-file (plain-file "sudoers" (string-append (plain-file-content %sudoers-specification) ;; 'guix deploy'需要免密码sudo权限。 "%wheel ALL=NOPASSWD: ALL\n"))) (packages (cons openssh %base-packages)) (services %linode-base-services) ;; 使用虚拟磁盘设备需要virtio_scsi模块。 (initrd-modules (append '("virtio_scsi") (base-initrd-modules linux))) ;; Guix默认在启动设备上运行grub-install的做法 ;; 在Linode环境中不适用。我们采用Guix处理磁盘镜像的方式: ;; 将字体和GRUB模块安装到根文件系统。 (bootloader (bootloader-configuration (bootloader (bootloader (inherit grub-bootloader) (installer #~(lambda (bootloader device mount-point) (let* ((install-dir (string-append mount-point "/boot")) (fonts (string-append install-dir "/grub/fonts"))) (mkdir-p fonts) (copy-file (string-append bootloader "/share/grub/unicode.pf2") (string-append fonts "/unicode.pf2")) (copy-recursively (string-append bootloader "/lib/") install-dir)))))) (targets '("/dev/sda")))) (file-systems (cons (file-system (device "/dev/sda") (mount-point "/") (type "ext4")) %base-file-systems)) (swap-devices (list (swap-space (target "/dev/sdb")))))) ;; 允许使用'guix system image'构建初始磁盘镜像。 (when (batch-mode?) linode-base-os) ``` 此代码也可在此Git仓库(https://git.dthompson.us/guix-config/tree/dthompson/linode.scm)中找到。 现在需要将此操作系统配置转换为可用的磁盘镜像。Guix可以使用`mbr-raw`镜像类型生成与Linode兼容的镜像。上传前需对Linode镜像进行gzip压缩。我编写了如下处理脚本: ```sh #!/bin/sh set -e # 首先需要用Guix生成可上传至Linode的原始磁盘镜像。 # Guix的'mbr-raw'镜像类型基本满足需求,但不完全匹配。 # 如名称所示,这类镜像包含主引导记录(MBR), # 并将GRUB安装在MBR后间隙中。经过反复测试, # 我们发现Linode需要的是*仅*包含根分区的镜像。 image=$(guix system image -L . --image-type=mbr-raw dthompson/linode.scm) # Guix将根分区放置在磁盘起始位置偏移1048576字节处, # 因此生成最终镜像时需要跳过这部分数据。 # # 为提升操作速度,我们选择128K作为'dd'的块大小(而非默认512字节)。 # 8个128K块=1048576字节,因此使用'skip=8'参数。 # # Linode还要求上传的镜像必须经过gzip压缩。 dd if="$image" bs=128K skip=8 conv=sync,noerror | gzip -c > linode-base.gz ``` 创建并上传磁盘镜像后,我可以使用它启动新的Linode实例。*但是*,Linode的默认配置文件不适用,新实例会直接内核恐慌。首先我关闭服务器,然后编辑其配置文件并进行以下修改: - 在"启动设置"下打开"选择内核"下拉菜单,选择"GRUB 2" - 关闭*所有*文件系统/启动辅助开关 保存后重启服务器。至此我可以通过SSH使用`guix deploy`进行所有系统更新。大功告成! 或许应该将此改进流程更新到Guix手册中,但我目前无暇顾及,希望这篇博客能暂时提供帮助。

相似文章

Guix: 从二进制创建包

Lobsters Hottest

使用copy-build-system从二进制创建Guix包的指南,解释如何设置安装计划。

切换到 GNU Guix:初学者的视角

Lobsters Hottest

一位初学者分享了从 Arch Linux 切换到 GNU Guix 的经验,讨论了声明式系统管理的好处、与 NixOS 的比较以及所面临的挑战。

我喜欢的 NixOS 声明式安装方式

Michael Stapelberg

一份关于使用 nixos-anywhere 等工具通过网络声明式安装 NixOS 的指南,重点强调在版本控制下管理配置文件。