# 11.6 openSUSE 兼容层

openSUSE 兼容层基于 Leap dnf 容器镜像构建，opi 工具会自动安装 zypper 包管理器以实现双包管理器共存。本节提供自动化脚本及软件源配置指引。

## 基于 openSUSE Leap dnf 容器的 Shell 脚本

本节脚本采用 openSUSE Leap dnf 容器镜像作为基本系统。该镜像基于 dnf 包管理器构建，但 openSUSE 的 opi 工具会自动安装 zypper，实现双包管理器共存。用户仍需按照 [清华大学镜像站 openSUSE 使用帮助](https://mirrors.tuna.tsinghua.edu.cn/help/opensuse/) 的指引，手动配置 zypper 软件源。

脚本内容如下：

```sh
#!/bin/sh                                              # 指定脚本使用的 shell

rootdir=/compat/suse                                   # 定义 openSUSE 兼容层根目录
url="https://download.opensuse.org/pub/opensuse/distribution/leap/15.6/appliances/opensuse-leap-dnf-image.x86_64-lxc-dnf.tar.xz"  # openSUSE bootstrap 下载地址。该链接会随版本更新，请自行获取最新链接；文件名实际包含版本号与构建号（如 opensuse-leap-dnf-image.x86_64-15.6.0-lxc-dnf-BuildXX.XXX.tar.xz），请查阅 https://download.opensuse.org/pub/opensuse/distribution/leap/15.6/appliances/ 获取准确文件名

echo "Starting openSUSE Leap 15.6 installation..."       # 输出安装开始信息
echo "check modules ..."                                # 输出模块检查信息

# check linux module
if [ "$(sysrc -n linux_enable)" = "NO" ]; then         # 检查 Linux 内核模块是否启用
        echo "linux module should be loaded. Continue? (Y|n)"  # 提示是否继续
        read answer                                     # 读取用户输入
        case $answer in
                [Nn][Oo]|[Nn])
                        echo "linux module not loaded" # 提示模块未加载
                        exit 1                         # 退出脚本
                        ;;
                [Yy][Ee][Ss]|[Yy]|"")
                        sysrc linux_enable=YES         # 启用 Linux 内核模块
                        ;;
        esac
fi
echo "start linux"                                       # 输出启动 Linux 信息
service linux start                                      # 启动 Linux 内核模块

# check dbus
if ! /usr/bin/which -s dbus-daemon;then                # 检查 dbus-daemon 是否存在
        echo "dbus-daemon not found. Install it [Y|n]" # 提示安装 dbus
        read  answer                                    # 读取用户输入
        case $answer in
            [Nn][Oo]|[Nn])
                echo "dbus not installed"               # 提示未安装 dbus
                exit 2                                  # 退出脚本
                ;;
            [Yy][Ee][Ss]|[Yy]|"")
                pkg install -y dbus                     # 安装 dbus
                ;;
        esac
    fi

if [ "$(sysrc -n dbus_enable)" != "YES" ]; then        # 检查 dbus 服务是否启用
        echo "dbus should be enabled. Continue? (Y|n)"  # 提示是否启用
        read answer                                     # 读取用户输入
        case $answer in
            [Nn][Oo]|[Nn])
                        echo "dbus not running"       # 提示 dbus 未运行
                        exit 2                          # 退出脚本
                        ;;
            [Yy][Ee][Ss]|[Yy]|"")
                        service dbus enable            # 启用 dbus 服务开机自启
                        ;;
        esac
fi
echo "start dbus"                                       # 输出启动 dbus 信息
service dbus start                                      # 启动 dbus 服务

echo "now we will bootstrap openSUSE"                  # 输出 bootstrap 开始信息

fetch ${url}                                            # 下载 openSUSE bootstrap 压缩包
mkdir -p ${rootdir}                                    # 创建目标目录
tar xvf opensuse-leap-dnf-image*.tar.xz -C ${rootdir} --numeric-owner  # 解压压缩包
rm opensuse-leap-dnf-image*.tar.xz                       # 删除压缩包

if [ ! "$(sysrc -f /boot/loader.conf -qn nullfs_load)" = "YES" ]; then  # 检查 nullfs 是否加载
        echo "nullfs_load should load. Continue? (Y|n)"  # 提示是否继续
        read answer                                     # 读取用户输入
        case $answer in
            [Nn][Oo]|[Nn])
                echo "nullfs is not loaded"                  # 提示未加载
		exit 3                                      # 退出脚本
                ;;
            [Yy][Ee][Ss]|[Yy]|"")
                sysrc -f /boot/loader.conf nullfs_load=yes  # 设置 nullfs 开机自启
                ;;
        esac
fi

if ! kldstat -n nullfs >/dev/null 2>&1;then            # 检查 nullfs 模块是否已加载
        echo "load nullfs module"                      # 输出加载信息
        kldload -v nullfs                               # 加载 nullfs 模块
fi

echo "mount some fs for linux"                         # 输出挂载文件系统信息
echo "devfs ${rootdir}/dev devfs rw,late 0 0" >> /etc/fstab        # devfs 挂载
echo "tmpfs ${rootdir}/dev/shm tmpfs rw,late,size=1g,mode=1777 0 0" >> /etc/fstab  # tmpfs 挂载
echo "fdescfs ${rootdir}/dev/fd fdescfs rw,late,linrdlnk 0 0" >> /etc/fstab        # fdescfs 挂载
echo "linprocfs ${rootdir}/proc linprocfs rw,late 0 0" >> /etc/fstab               # linprocfs 挂载
echo "linsysfs ${rootdir}/sys linsysfs rw,late 0 0" >> /etc/fstab                  # linsysfs 挂载
echo "/tmp ${rootdir}/tmp nullfs rw,late 0 0" >> /etc/fstab                         # /tmp 挂载
#echo "/home ${rootdir}/home nullfs rw,late 0 0" >> /etc/fstab                     # /home 挂载，可选
mount -al                                               # 挂载 fstab 中所有文件系统

echo "For openSUSE, we should change 'compat.linux.osrelease'. Continue? (Y|n)"  # 提示修改 Linux 内核版本
read answer                                             # 读取用户输入
case $answer in
	[Nn][Oo]|[Nn])
		echo "close to success"                        # 提示跳过修改
		exit 4
		;;
	[Yy][Ee][Ss]|[Yy]|"")
		echo "compat.linux.osrelease=6.2.10" >> /etc/sysctl.conf  # 持久化设置 Linux 内核版本
		sysctl compat.linux.osrelease=6.2.10                     # 立即生效
                ;;
esac
echo "complete!"                                        # 输出完成信息
echo "to use: chroot ${rootdir} /bin/bash"             # 提示使用 chroot 进入 openSUSE 兼容层
echo ""
echo "I will set resolv.conf to Ali DNS"              # 提示将 DNS 设置为阿里云公共 DNS
echo "Continue? [Y|n]"                                   # 提示是否继续
read answer                                             # 读取用户输入
case $answer in
	[Nn][Oo]|[Nn])
		echo "set your openSUSE by yourself. Bye!"  # 提示用户自行配置
		exit 0
		;;
	[Yy][Ee][Ss]|[Yy]|"")
		echo "nameserver 223.5.5.5" >> ${rootdir}/etc/resolv.conf   # 设置 DNS

    echo "I will install opi, nano, tar, and vim"           # 输出安装软件信息
    chroot ${rootdir} /bin/bash -c "dnf update && dnf install -y opi nano tar vim"  # 安装常用软件

    echo "all done."                                      # 输出完成信息
    echo "Now you can run '#chroot /compat/suse/ /bin/bash' to enter openSUSE"  # 提示用户进入 openSUSE

                ;;
esac
```

## openSUSE Tumbleweed Shell 脚本

本节存在已知问题，暂不可用。

需要指出的是，Tumbleweed 即风滚草，是 openSUSE 的滚动更新版本。

脚本内容如下：

```sh
#!/bin/sh                                              # 指定脚本使用的 shell

rootdir=/compat/suse                                   # 定义 openSUSE 兼容层根目录
url="https://download.opensuse.org/repositories/Virtualization:/containers:/images:/openSUSE-Tumbleweed/container/opensuse-tumbleweed-dnf-image.x86_64-lxc-dnf.tar.xz"  # openSUSE bootstrap 下载地址

echo "Starting openSUSE Tumbleweed installation..."        # 输出安装开始信息
echo "check modules ..."                               # 输出模块检查信息

# check linux module
if [ "$(sysrc -n linux_enable)" = "NO" ]; then         # 检查 Linux 内核模块是否启用
        echo "linux module should be loaded. Continue? (Y|n)"  # 提示是否继续
        read answer                                     # 读取用户输入
        case $answer in
                [Nn][Oo]|[Nn])
                        echo "linux module not loaded" # 提示模块未加载
                        exit 1                         # 退出脚本
                        ;;
                [Yy][Ee][Ss]|[Yy]|"")
                        sysrc linux_enable=YES         # 启用 Linux 内核模块
                        ;;
        esac
fi
echo "start linux"                                      # 输出启动 Linux 信息
service linux start                                     # 启动 Linux 内核模块

# check dbus
if ! /usr/bin/which -s dbus-daemon;then                # 检查 dbus-daemon 是否存在
        echo "dbus-daemon not found. Install it [Y|n]" # 提示安装 dbus
        read answer                                     # 读取用户输入
        case $answer in
            [Nn][Oo]|[Nn])
                echo "dbus not installed"               # 提示未安装 dbus
                exit 2                                  # 退出脚本
                ;;
            [Yy][Ee][Ss]|[Yy]|"")
                pkg install -y dbus                     # 安装 dbus
                ;;
        esac
    fi

if [ "$(sysrc -n dbus_enable)" != "YES" ]; then        # 检查 dbus 服务是否启用
        echo "dbus should be enabled. Continue? (Y|n)"  # 提示是否启用
        read answer                                     # 读取用户输入
        case $answer in
            [Nn][Oo]|[Nn])
                        echo "dbus not running"       # 提示 dbus 未运行
                        exit 2                          # 退出脚本
                        ;;
            [Yy][Ee][Ss]|[Yy]|"")
                        service dbus enable            # 启用 dbus 服务开机自启
                        ;;
        esac
fi
echo "start dbus"                                       # 输出启动 dbus 信息
service dbus start                                      # 启动 dbus 服务

echo "now we will bootstrap openSUSE"                  # 输出 bootstrap 开始信息

fetch ${url}                                            # 下载 openSUSE bootstrap 压缩包
mkdir -p ${rootdir}                                    # 创建目标目录
tar xvf opensuse*.tar.xz -C ${rootdir} --numeric-owner  # 解压压缩包
rm opensuse-tumbleweed-dnf-image.x86_64-lxc-dnf.tar.xz  # 删除压缩包

if [ ! "$(sysrc -f /boot/loader.conf -qn nullfs_load)" = "YES" ]; then  # 检查 nullfs 是否加载
        echo "nullfs_load should load. Continue? (Y|n)"  # 提示是否继续
        read answer                                     # 读取用户输入
        case $answer in
            [Nn][Oo]|[Nn])
                echo "nullfs is not loaded"                  # 提示 nullfs 未加载
		exit 3                                      # 退出脚本
                ;;
            [Yy][Ee][Ss]|[Yy]|"")
                sysrc -f /boot/loader.conf nullfs_load=yes  # 设置 nullfs 开机自启
                ;;
        esac
fi

if ! kldstat -n nullfs >/dev/null 2>&1;then            # 检查 nullfs 模块是否已加载
        echo "load nullfs module"                      # 输出加载信息
        kldload -v nullfs                               # 加载 nullfs 模块
fi

echo "mount some fs for linux"                         # 输出挂载文件系统信息
echo "devfs ${rootdir}/dev devfs rw,late 0 0" >> /etc/fstab        # devfs 挂载
echo "tmpfs ${rootdir}/dev/shm tmpfs rw,late,size=1g,mode=1777 0 0" >> /etc/fstab  # tmpfs 挂载
echo "fdescfs ${rootdir}/dev/fd fdescfs rw,late,linrdlnk 0 0" >> /etc/fstab        # fdescfs 挂载
echo "linprocfs ${rootdir}/proc linprocfs rw,late 0 0" >> /etc/fstab               # linprocfs 挂载
echo "linsysfs ${rootdir}/sys linsysfs rw,late 0 0" >> /etc/fstab                  # linsysfs 挂载
echo "/tmp ${rootdir}/tmp nullfs rw,late 0 0" >> /etc/fstab                         # /tmp 挂载
#echo "/home ${rootdir}/home nullfs rw,late 0 0" >> /etc/fstab                     # /home 挂载，可选
mount -al                                               # 挂载 fstab 中所有文件系统

echo "For openSUSE, we should change 'compat.linux.osrelease'. Continue? (Y|n)"  # 提示修改 Linux 内核版本
read answer                                             # 读取用户输入
case $answer in
	[Nn][Oo]|[Nn])
		echo "close to success"                        # 提示跳过修改
		exit 4
		;;
	[Yy][Ee][Ss]|[Yy]|"")
		echo "compat.linux.osrelease=6.2.10" >> /etc/sysctl.conf  # 持久化设置 Linux 内核版本
		sysctl compat.linux.osrelease=6.2.10                     # 立即生效
                ;;
esac
echo "complete!"                                        # 输出完成信息
echo "to use: chroot ${rootdir} /bin/bash"             # 提示使用 chroot 进入 openSUSE 兼容层
echo ""
echo "I will set resolv.conf to Ali DNS"               # 提示将 DNS 设置为阿里云公共 DNS
echo "Continue? [Y|n]"                                   # 提示是否继续
read answer                                             # 读取用户输入
case $answer in
	[Nn][Oo]|[Nn])
		echo "set your openSUSE by yourself. Bye!"       # 提示用户自行配置
		exit 0
		;;
	[Yy][Ee][Ss]|[Yy]|"")
		echo "nameserver 223.5.5.5" >> ${rootdir}/etc/resolv.conf   # 设置 DNS

    echo "Now I will install opi, nano, tar, and vim"         # 输出安装软件信息
    chroot ${rootdir} /bin/bash -c "dnf update && dnf install -y opi nano tar vim"  # 安装常用软件

    echo "all done."                                      # 输出完成信息
    echo "Now you can run '#chroot /compat/suse/ /bin/bash' to enter openSUSE"  # 提示用户进入 openSUSE

                ;;
esac
```

## 故障排除与未竟事宜

### 使用 LXC Leap 镜像时 zypper 不可用

具体而言，在使用 openSUSE Tumbleweed 时，dnf 和 zypper 均不可用。该问题不影响 Leap 对应的脚本，但影响 Tumbleweed 对应的脚本，导致无法正常使用。已提交 [Bug 报告](https://bugzilla.opensuse.org/show_bug.cgi?id=1213158)。

例如安装 Vim 时会报错：

```sh
Installation of perl-5.36.1-1.2.x86_64 failed:
Error Subprocess failed Error: RPM failed: Command exited with status 1
```

在 LXC Leap 中，用 rpm 替换 rpm-ndb 可解决该问题，且 dnf 不受影响，该问题仅存在于 zypper 中。然而，在 openSUSE Tumbleweed LXC 中，dnf 和 zypper 都存在该问题，替换 rpm-ndb 无法解决。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.bsdcn.org/di-11-zhang-linux-er-jin-zhi-jian-rong-ceng/di-11.6-jie-opensuse-jian-rong-ceng.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
