docker 内部挂载 aliyun oss

最后发布时间 : 2025-11-27 15:21:42 浏览量 :
# vim /etc/ossfs2.conf
--oss_endpoint=https://oss-cn-beijing.aliyuncs.com
--oss_bucket=***
--oss_access_key_id=****
--oss_access_key_secret=***
docker run   --rm -it -v $PWD:$PWD -w $PWD \
    --cap-add SYS_ADMIN \
    --device /dev/fuse \
    --security-opt apparmor:unconfined \
     ubuntu bash
ossfs2 mount /opt -c /etc/ossfs2.conf 
参数作用
--device /dev/fuse容器访问宿主机 FUSE 设备,用户空间文件系统挂载必须
--cap-add SYS_ADMIN允许挂载文件系统所需的管理权限
/dev/fuseFUSE 内核接口节点

生信小木屋

下面我用 最清晰、最形象的方式解释 /dev/fuse 的工作原理,并用一个完整的例子说明 FUSE 是如何让“用户态写的代码”变成一个真正可挂载的文件系统。

🧩 什么是 /dev/fuse

/dev/fuse 是一个 字符设备,是 FUSE 文件系统在 Linux 中和内核通信的唯一接口。

它的作用是:

允许一个普通用户态程序,实现一个虚拟文件系统,并通过 /dev/fuse 把请求交给内核,由内核挂载到系统中。

换句话说:

  • 内核通过 /dev/fuse 给用户态程序发送 “open file”、“read file”、“list directory” 等请求
  • 用户态程序通过 /dev/fuse 回答这些请求
  • 内核把用户态程序的回答当成真正的文件系统来呈现

这就是 用户态文件系统框架(Filesystem in Userspace)。

🏗 FUSE工作流程(简化)

流程图:

         用户程序(如 ossfs, s3fs, 自定义FS)
                         │
         (实现 read, write, getattr, readdir 等逻辑)
                         │
                    /dev/fuse
                         │
                FUSE 内核模块
                         │
                 Linux VFS (虚拟文件系统层)
                         │
                 应用程序(ls, cat, python)

你写的文件系统逻辑跑在 用户空间,但最终被内核当成正式文件系统看待。

🎯 一个最直观的示例:实现一个 "Hello FS" 文件系统

下面是一个典型 最简单的 FUSE 文件系统示例

当你挂载它时:

ls /mnt/hello

你只会看到一个文件:

hello.txt

内容永远是:

Hello from FUSE!

🧪 示例代码(使用 libfuse)

一个最小可运行的 FUSE 文件系统示例:

#define FUSE_USE_VERSION 26
#include <fuse.h>
#include <string.h>

static int hello_getattr(const char *path, struct stat *stbuf) {
    memset(stbuf, 0, sizeof(struct stat));

    if (strcmp(path, "/") == 0) {
        stbuf->st_mode = S_IFDIR | 0755;
        stbuf->st_nlink = 2;
    } else if (strcmp(path, "/hello.txt") == 0) {
        stbuf->st_mode = S_IFREG | 0444;
        stbuf->st_nlink = 1;
        stbuf->st_size = strlen("Hello from FUSE!\n");
    } else {
        return -ENOENT;
    }
    return 0;
}

static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
                         off_t offset, struct fuse_file_info *fi) {
    filler(buf, ".", NULL, 0);
    filler(buf, "..", NULL, 0);
    filler(buf, "hello.txt", NULL, 0);
    return 0;
}

static int hello_read(const char *path, char *buf, size_t size,
                      off_t offset, struct fuse_file_info *fi) {
    const char *hello_str = "Hello from FUSE!\n";

    if (strcmp(path, "/hello.txt") != 0)
        return -ENOENT;

    size_t len = strlen(hello_str);
    if (offset < len) {
        if (offset + size > len)
            size = len - offset;
        memcpy(buf, hello_str + offset, size);
    } else {
        size = 0;
    }

    return size;
}

static struct fuse_operations hello_ops = {
    .getattr = hello_getattr,
    .readdir = hello_readdir,
    .read = hello_read,
};

int main(int argc, char *argv[]) {
    return fuse_main(argc, argv, &hello_ops, NULL);
}

🔍 运行步骤

1. 编译

gcc hello.c -o hello_fs `pkg-config fuse --cflags --libs`

2. 创建挂载点

mkdir /mnt/hello

3. 运行(注意!需要 FUSE 权限)

./hello_fs /mnt/hello

现在你可以测试文件系统了:

📁 结果演示

查看目录:

ls /mnt/hello

输出:

hello.txt

查看内容:

cat /mnt/hello/hello.txt

输出:

Hello from FUSE!

🧠 理解:是谁响应 cat 读取文件?

cat → Linux 内核 → VFS → FUSE 内核模块 → /dev/fuse → 你的用户态程序 → 返回内容 → 最终显示

也就是说:

👉 hello_read 函数是 cat 的“底层文件系统”

🚀 总结:/dev/fuse 的工作原理

步骤描述
1用户程序实现文件系统(getattr, read, write 等)
2程序通过 /dev/fuse 注册为一个文件系统
3内核通过 /dev/fuse 把文件请求传给你的程序
4程序返回结果
5内核把结果当作真正文件系统返回给上层应用

本质就是:

你写的用户态程序 “假装” 是一个文件系统,而 /dev/fuse 是它与内核的桥梁。