デフォルトプールを対象外にしてLXDを導入

Ubuntuシステム全体はTimeshiftで保護出来るようになったので、次はLXDを導入していきます。
なお、LXDコンテナはTimeshiftの対象外としておいたほうが運用しやすいでしょう。システムに不具合があり環境を巻き戻しても、LXDコンテナは影響を受けなくなります。
そのため、LXDコンテナ部分は監視対象から除外されるように、@lxdというサブボリュームを作成し、デフォルトプールをサブボリュームにマウントするよう設定します。

サブボリュームを作成してLXDを導入

サブボリューム作成

# デバイス名とUUID確認
findmnt -t btrfs

# Btrfsルートをマウント
sudo mount -o subvolid=5 /dev/デバイス名 /mnt

# サブボリューム作成
sudo btrfs subvolume create /mnt/@lxd

sudo umount /mnt

サブボリュームにマウント

# UUIDを確認
sudo blkid /dev/デバイス名

# マウントポイント作成
sudo mkdir -p /var/snap/lxd/common/lxd

# fstabに追記(UUIDは実際の値に置き換え)
echo "UUID=xxxx  /var/snap/lxd/common/lxd  btrfs  defaults,subvol=@lxd,noatime  0 0" | sudo tee -a /etc/fstab

# マウント確認
sudo mount -a
findmnt /var/snap/lxd/common/lxd

systemdへ反映

sudo systemctl daemon-reload

LXDインストール

# LXD インストール
sudo snap install lxd --channel=latest/stable

# lxd グループにユーザー追加
sudo usermod -aG lxd $USER

# 初期化
cat <<EOF | sudo lxd init --preseed
config: {}
networks:
- name: lxdbr0
  type: bridge
  config:
    ipv4.address: auto
    ipv6.address: none
storage_pools:
- name: default
  driver: btrfs
  config:
    source: /var/snap/lxd/common/lxd/storage-pools/default
profiles:
- name: default
  devices:
    root:
      path: /
      pool: default
      type: disk
    eth0:
      name: eth0
      network: lxdbr0
      type: nic
EOF

# HTTPS API 有効化
sudo lxc config set core.https_address :8443

# UI 有効化
sudo snap set lxd ui.enable=true
sudo systemctl reload snap.lxd.daemon

ここで一度再ログインします。確実に、再起動しておきましょう。
再起動したら、確認してみます。

sudo btrfs subvolume list /mnt

一時的にマウントが必要なので。

sudo mount -o subvolid=5 /dev/デバイス名 /mnt
sudo btrfs subvolume list /mnt
sudo umount /mnt

@lxd配下にサブボリュームが作られているはずで、Timeshiftは@@homeのみをスナップショット対象にするため、@lxd以下は自動的に除外されます。

TimeshiftのGUIで「スナップショット」タブを見ると対象サブボリュームが確認できるので、念のためチェックしておくと安心です。

top level 5 (Btrfsルート)
├── @ ← Timeshift対象 ✅
├── @home ← Timeshift対象 (✅ 設定で対象外)
├── timeshift-btrfs/... ← スナップショット保存先
└── @lxd ← Timeshift対象外
└── storage-pools/default ← LXDデフォルトプール(対象外)

ちなみに@homeは除外設定していればスナップショットされません。Timeshiftは@のみが実質の対象になっています。

Timeshiftでホストを戻した場合@(ルートファイルシステム)のみが巻き戻るので、@lxd以下のコンテナデータは一切影響を受けません。

ただし一点注意があり、ホストを巻き戻すとLXDの設定ファイル(/var/snap/lxd/以下のunix socketや設定など)も古い状態に戻ります。コンテナのデータ自体は無事でも、巻き戻し後にlxd initのやり直しや設定の再投入が必要になるケースがあります。

なので重要な設定変更をしたタイミングでTimeshiftのスナップショットを手動で取っておくと、ホスト側の設定とコンテナの状態が乖離するリスクを減らせます。

LXDインストールまでを1クリックで実行

ここまでの内容を1クリックで実行するなら、下記スクリプトを貼り付けて実行します。

#!/bin/bash
# =============================================================================
# LXD セットアップスクリプト
# - Btrfsデバイスを自動検出
# - @lxd サブボリューム作成
# - LXDインストール・初期設定・UI有効化
# 実行後は再起動してください(lxdグループの反映のため)
# =============================================================================

set -euo pipefail

# -----------------------------------------------------------------------------
# 色付きログ
# -----------------------------------------------------------------------------
info()  { echo -e "\e[32m[INFO]\e[0m  $*"; }
warn()  { echo -e "\e[33m[WARN]\e[0m  $*"; }
error() { echo -e "\e[31m[ERROR]\e[0m $*" >&2; exit 1; }

# -----------------------------------------------------------------------------
# root確認
# -----------------------------------------------------------------------------
if [ "$EUID" -eq 0 ]; then
    error "このスクリプトは一般ユーザーで実行してください(sudo不要)"
fi

# -----------------------------------------------------------------------------
# Step 1: Btrfsデバイスを自動検出
# -----------------------------------------------------------------------------
info "Btrfsデバイスを検出中..."

# / にマウントされているBtrfsデバイスを取得
DEVICE=$(findmnt -n -o SOURCE -t btrfs / | sed 's/\[.*\]//')

if [ -z "$DEVICE" ]; then
    error "Btrfsデバイスが見つかりません"
fi

info "デバイス: $DEVICE"

# UUIDを取得
UUID=$(sudo blkid -s UUID -o value "$DEVICE")

if [ -z "$UUID" ]; then
    error "UUIDの取得に失敗しました"
fi

info "UUID: $UUID"

# -----------------------------------------------------------------------------
# Step 2: @lxd サブボリューム作成
# -----------------------------------------------------------------------------
info "@lxd サブボリュームを作成中..."

# すでに存在するか確認
if sudo btrfs subvolume list / | grep -q " path @lxd$"; then
    warn "@lxd サブボリュームはすでに存在します。スキップします。"
else
    sudo mount -o subvolid=5 "$DEVICE" /mnt
    sudo btrfs subvolume create /mnt/@lxd
    sudo umount /mnt
    info "@lxd サブボリュームを作成しました"
fi

# -----------------------------------------------------------------------------
# Step 3: マウントポイント作成 & fstab追記
# -----------------------------------------------------------------------------
MOUNT_POINT="/var/snap/lxd/common/lxd"
FSTAB_ENTRY="UUID=$UUID  $MOUNT_POINT  btrfs  defaults,subvol=@lxd,noatime  0 0"

info "マウントポイントを作成中: $MOUNT_POINT"
sudo mkdir -p "$MOUNT_POINT"

# fstabに重複追記しないよう確認
if grep -q "@lxd" /etc/fstab; then
    warn "fstabに@lxdのエントリがすでに存在します。スキップします。"
else
    echo "$FSTAB_ENTRY" | sudo tee -a /etc/fstab > /dev/null
    info "fstabに追記しました"
fi

# マウント & systemd反映
sudo mount -a
sudo systemctl daemon-reload

# マウント確認
if findmnt "$MOUNT_POINT" > /dev/null 2>&1; then
    info "$MOUNT_POINT のマウント確認OK"
else
    error "$MOUNT_POINT のマウントに失敗しました"
fi

# -----------------------------------------------------------------------------
# Step 4: LXD インストール
# -----------------------------------------------------------------------------
if snap list lxd > /dev/null 2>&1; then
    warn "LXDはすでにインストールされています。スキップします。"
else
    info "LXDをインストール中..."
    sudo snap install lxd --channel=latest/stable
fi

# -----------------------------------------------------------------------------
# Step 5: lxdグループにユーザー追加
# -----------------------------------------------------------------------------
if groups "$USER" | grep -q "\blxd\b"; then
    warn "$USER はすでにlxdグループに所属しています。"
else
    sudo usermod -aG lxd "$USER"
    info "$USER をlxdグループに追加しました"
fi

# -----------------------------------------------------------------------------
# Step 6: LXD 初期化
# -----------------------------------------------------------------------------
# すでに初期化済みか確認(storage poolが存在するか)
if sudo lxc storage list 2>/dev/null | grep -q "default"; then
    warn "LXDはすでに初期化されています。スキップします。"
else
    info "LXDを初期化中..."
    cat <<EOF | sudo lxd init --preseed
config: {}
networks:
- name: lxdbr0
  type: bridge
  config:
    ipv4.address: auto
    ipv6.address: none
storage_pools:
- name: default
  driver: btrfs
  config:
    source: /var/snap/lxd/common/lxd/storage-pools/default
profiles:
- name: default
  devices:
    root:
      path: /
      pool: default
      type: disk
    eth0:
      name: eth0
      network: lxdbr0
      type: nic
EOF
    info "LXD初期化完了"
fi

# -----------------------------------------------------------------------------
# Step 7: HTTPS API & UI 有効化
# -----------------------------------------------------------------------------
info "HTTPS APIを有効化中..."
sudo lxc config set core.https_address :8443

info "LXD UIを有効化中..."
sudo snap set lxd ui.enable=true
sudo systemctl reload snap.lxd.daemon

# -----------------------------------------------------------------------------
# 完了メッセージ
# -----------------------------------------------------------------------------
echo ""
echo "====================================================="
info "セットアップ完了!"
echo "====================================================="
echo ""
echo "  デバイス : $DEVICE"
echo "  UUID     : $UUID"
echo "  マウント : $MOUNT_POINT"
echo ""
warn "lxdグループを反映するために再起動してください:"
echo ""
echo "    sudo reboot"
echo ""
echo "  再起動後、ブラウザで以下にアクセスしてUIを確認:"
echo "    https://localhost:8443"
echo ""

サービスごとにサブボリュームを作成

Btrfsバックエンドにしたなら、コンテナをコピーしても使用量は増えないので、1サービス1コンテナで運用するほうが良いでしょう。小さなサービスであれば、1コンテナなすべて閉じ込めておけば、バックアップや移行もしやすくなります。
immichやNextcloudのようなデータが大きくなりがちなサービスは、データ保存用にサブボリュームを作成したほうが管理しやすくなります。

Btrfsルート (subvolid=5)
├── @
├── @home
├── @lxd
│ └── storage-pools/default
├── @data-immich ← サービスごとに個別サブボリューム
└── @data-nextcloud

つまり、次のようなイメージでコンテナにデータ部分のディレクトリをマウントして運用する形です。

LXDコンテナ: immich
├── / (rootfs)          ← @lxd/storage-pools/default 内のサブボリューム
│                          (OS、アプリ、設定)
└── /var/lib/immich     ← @data-immich をマウント
                           (写真・動画データ)

LXDコンテナ: nextcloud
├── / (rootfs)          ← @lxd/storage-pools/default 内のサブボリューム
│                          (OS、アプリ、設定)
└── /var/lib/nextcloud  ← @data-nextcloud をマウント
                           (ユーザーファイル)

コンテナ作成例。

lxc config device add immich data disk \
source=/mnt/data/immich \
path=/var/lib/immich

lxc config device add nextcloud data disk \
source=/mnt/data/nextcloud \
path=/var/lib/nextcloud

これでコンテナを丸ごとlxc exportしてもデータは含まれず、アプリ設定だけの軽いバックアップになります。データは別途btrbkなどで管理、という役割分担がきれいにできます。

なお、TimeshiftのGUIはあくまで@@home専用なので、@data-immichのような独自サブボリュームはコマンドで管理することになります。手動スナップショットの例は次の通り。

手動スナップショット

# スナップショット作成
sudo btrfs subvolume snapshot /mnt/data/immich /mnt/data/immich-snap-20260330

# 確認
sudo btrfs subvolume list / | grep data

特定時点に戻す場合

# LXDコンテナを止めてから
lxc stop immich

# 現行を退避(念のため)
sudo mv /mnt/data/immich /mnt/data/immich-broken

# スナップショットから戻す
sudo btrfs subvolume snapshot /mnt/data/immich-snap-20260330 /mnt/data/immich

lxc start immich

スナップショット置き場の整理

スナップショットが増えると散らかるので、置き場を決めておくと良いです。

sudo mkdir -p /mnt/data/.snapshots/immich
sudo btrfs subvolume snapshot /mnt/data/immich /mnt/data/.snapshots/immich/20260330

自動化したい場合

cronやsystemd timerで定期実行するスクリプトを作るのが現実的です。世代管理ツールとしてbtrbkが使いやすくておすすめです。

sudo apt install btrbk

設定ファイルでサブボリュームごとに保持世代数を指定できるので、Timeshiftに近い感覚で使えます。

タイトルとURLをコピーしました