容器的初次构建和后续用backup文件重新部署差别虽然不大,但是有些一次性操作的关键环节如果漏掉了,重新找起来也挺麻烦,还是都记下。
初始化过程主要参照这个说明
https://nixos.wiki/wiki/Proxmox_Linux_Container
1、nixos的pve lxc镜像:
访问 https://hydra.nixos.org/jobset/nixos/trunk-combined#tabs-jobs
在搜索栏中输入proxmox,选择最近构建的proxmoxlxc任务结果tar文件下载
完了到pve里有ct templates的存储位置里上传
对网络连接有自信的当然也可以在这里download from url
存在local的话可以确认下 /var/lib/vz/template/cache/ 路径下有对应文件
2、创建容器 ,可以抄说明里的命令。其实我用网页创建也没碰到什么问题,无特权容器去掉,回头到options勾上nesting就行。
ctid="99999"
ctname="nixos"
ctt="local:vztmpl/nixos-system-x86_64-linux.tar.xz"
cts="local-lvm"
pct create ${ctid} ${ctt} \
--hostname=${ctname} \
--ostype=nixos --unprivileged=0 --features nesting=1 \
--net0 name=eth0,bridge=vmbr0,ip=dhcp \
--arch=amd64 --swap=1024 --memory=2048 \
--storage=${cts}
nixos大量小文件的模式一般会在磁盘容量塞满之前先把inode塞爆,懒得事先给虚拟磁盘做更小分块的话,就把磁盘调大点,按照jellyfin的经验,8g应该是不够的。
以上命令默认磁盘4g,可以加到16.
pct resize ${ctid} rootfs +12G
3、(可选)如果已经提前准备好了nix配置文件和应用的config以及data文件夹,可以在pve里先妥善组织好,用mountpoint挂载到容器里。没有的话就跳过,回头来弄也没差。
我的目录大致如下
nix/
├── nixfin/
│ ├── nixos-config
│ │ ├── configuration.nix
│ │ ├── smb.nix
│ │ └── jellyfin.nix
│ ├── jellyfin-data
│ └── jellyfin-config
├── nixpi
├── nixlxc
├── ...
└── others
在/etc/pve/lxc/999.conf里添加一行,根据实际情况调整绝对路径
注意格式
mp0: /nix-test/nixlxc,mp=/etc/nixos
4、启动容器,
进入容器没有环境,得先执行这个才有各种命令
source /etc/set-environment
5、nixchannel,重建
这个就是尽量无状态的尽量了,nixchannel没啥其他地方定义,即便用了flake,你总是得进容器手工跑重建,
nix-channel --add https://mirrors.ustc.edu.cn/nix-channels/nixpkgs-unstable nixpkgs
nix-channel --add https://mirrors.tuna.tsinghua.edu.cn/nix-channels/nixos-unstable/ nixos
nix-channel --update
初次重建的时候可以手工指定镜像
nixos-rebuild switch --option substituters https://mirrors.ustc.edu.cn/nix-channels/store
7、这时候最小nix容器算可以用了,补上应用所需要的nix配置,加一行import就行
如果在这里把容器保存为模板,后续需要新容器可以节省掉上面这一堆步骤
当然也可以不用模板,只要还有一个nix的容器在跑,复制一个改下mountpoint路径,调整下nix文件后重建,自然就算声明了一个新应用的容器
8、nix配置
最小容器的nix文件示例如下,放在mountpoint所指的临时路径/nix-test/nixlxc下:
configuration.nix
{ pkgs, modulesPath, ...}: {
imports = [
(modulesPath + "/virtualisation/proxmox-lxc.nix")
./std.nix
];
proxmoxLXC = { manageNetwork = false; privileged = true; };
environment.systemPackages = [
# pkgs.vim
];
system.stateVersion = "25.11";
}
std.nix ,这个文件实际上大部分可以略过,不影响其他应用,纯个人习惯
{pkgs, ...}: {
# 时区设置
time.timeZone = "Asia/Shanghai"; # 设置时区为上海(中国标准时间)
# zsh start
programs.zsh = {
enable = true; # Enable Zsh
autosuggestions.enable = true;
syntaxHighlighting.enable = true;
shellAliases = {
sc = "sudo systemctl";
clean = "nix-collect-garbage --delete-older-than ";
apply = "sudo nixos-rebuild switch";
update = "nix-channel --update";
up = "nix flake update";
};
ohMyZsh = {
enable = true; # Enable Oh My Zsh
plugins = ["git" "z"]; # Add desired plugins
theme = "random"; # Set your preferred theme (default: robbyrussell)
};
};
users.defaultUserShell = pkgs.zsh; # Set Zsh as the default shell
environment.shells = [pkgs.zsh]; # Add Zsh to available shells
# zsh end
nix.settings = {
substituters = [
"https://mirrors.tuna.tsinghua.edu.cn/nix-channels/store"
"https://mirrors.ustc.edu.cn/nix-channels/store"
];
# experimental-features = ["nix-command" "flakes"]; # 启用实验性功能:nix命令增强和flakes支持
};
environment.systemPackages = with pkgs; [
vim
];
}
9、其他
也不知道为啥用pct enter的方式进入容器,设置的默认shell不生效,ssh或者pve网页端的console都正常;ai说是Pct enter是直接执行/bin/sh的缘故,我也就信了。
在命令里存一个 source /etc/set-environment && zsh 手工跑下也不费事
10、jellyfin
底子铺好后,跑jellyfin或者其他应用,基本也都是加几行配置重建的事情,提前把应用的config,应用的data,和应用需要的外部数据这三个路径组织好。按照无状态要求,这些一般都放在共享存储的环境里,可以在pve主机挂载好mountpoint到lxc里,也可以让lxc处理挂载。
nix文档有时候比较杂,好多介绍材料或者wiki页面里的配置项可能都依赖了home manager,比较干净的还是去mynixos查,比如 https://mynixos.com/search?q=jellyfin
jellyfin和smb挂载的配置,在configuration.nix添加import引入
Jellyfin.nix
{ pkgs, lib,config, ... }:
{
services.jellyfin = {
enable = true;
openFirewall = true;
configDir = "/jellyfin-config";
dataDir = "/jellyfin-data";
};
environment.systemPackages = [
pkgs.jellyfin
pkgs.jellyfin-web
pkgs.jellyfin-ffmpeg
];
}
Smb.nix ,其中有些选项用不上,可以根据smb共享服务端的配置调整
{ config, pkgs, ... }: {
# SMB 挂载配置
fileSystems."/mnt/dsm" = { device = "//192.168.1.8/dsm"; fsType =
"cifs"; options = [
"guest"
"iocharset=utf8"
"vers=3.0"
"uid=568"
"gid=568"
"file_mode=0666"
"dir_mode=0777"
#"x-systemd.automount"
];
};
# 创建符号链接
system.activationScripts.create-symlinks = ''
ln -sf /mnt/dsm/pub /mnt
'';
environment.systemPackages = with pkgs; [ cifs-utils ];
}
11、jellyfin的媒体路径错误
jellyfin数据库比较老或者经过环境迁移(尤其是docker和原生来来去去调整)的话,在编辑library设置的时候可能会报一个媒体库路径和数据库不符的错误,从而无法保存任何更改。
解决办法是手工修改数据库里保存的媒体库路径
10.10.7以前,数据库是jellyfin的data文件夹里的library.db,表名是TypedBaseItems
10.11以后,数据文件是data文件夹里的jellyfin.db,表名是BaseItems
用sqlite打开,
防止出错的话可以先查一下
Select path from TypedBaseItems WHERE type = 'MediaBrowser.Controller.Entities.CollectionFolder';
然后修改路径,path里的内容修改成data里root文件夹所在的正确路径就行。
UPDATE TypedBaseItems SET path = '/绝对路径/jellyfin-data/root/default/' || name WHERE type = 'MediaBrowser.Controller.Entities.CollectionFolder';