Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >从源代码级别看懂MinIO对象存储网关的实现

从源代码级别看懂MinIO对象存储网关的实现

作者头像
飞雪无情
发布于 2020-10-27 09:03:59
发布于 2020-10-27 09:03:59
4.1K00
代码可运行
举报
运行总次数:0
代码可运行

我在 《MinIO对象存储的网关架构设计》一文中介绍了MinIO的网关架构设计,它的整体架构如下图所示:

从架构图可以很清楚的看到MinIO网关的分层结构,那么这一篇我就从MinIO网关的具体代码分析它是如何实现的。

网关启动

MinIO内部已经实现了GCS、S3、NAS等几个网关,支持的网关列表如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  nas    Network-attached storage (NAS)
  azure  Microsoft Azure Blob Storage
  s3     Amazon Simple Storage Service (S3)
  hdfs   Hadoop Distributed File System (HDFS)
  gcs    Google Cloud Storage

假如要启动一个NAS网关,可以使用如下命令:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
minio gateway nas PATH

以上命令中的PATH是一个NAS挂载点路径,当然你也可以使用本地路径。假如我的NAS挂载点路径为/tmp/nas/ ,那么我通过如下命令就可以启动一个NAS网关。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 minio gateway nas /tmp/nas/

小提示:因为MinIO需要用户名和密码,所以在启动网关之前一定要设置,通过如下命令即可: export MINIO_ACCESS_KEY=accesskey export MINIO_SECRET_KEY=secretkey 其实就是设置MINIO_ACCESS_KEY和MINIO_SECRET_KEY环境变量,可以改成自己想要的用户名和密码。

启动后你可以像使用MinIO Server一样使用网关。

网关启动代码分析

MinIO的命令行启动只有2个命令,一个是server、一个是gateway,分别用于启动服务和网关,而整个MinIO的启动是从minio/main.go文件(假设存放MinIO源代码的根目录是minio)开始的。

minio/main.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main
import (
   "os"
   
   minio "github.com/minio/minio/cmd"
   // Import gateway
   _ "github.com/minio/minio/cmd/gateway"
)
func main() {
   minio.Main(os.Args)
}

整个源代码文件比较简单,主要是把命令行输入的参数交给minio.Main这个函数处理。这里需要注意的是github.com/minio/minio/cmd/gateway包的导入,它会调用github.com/minio/minio/cmd/gateway包的init函数,初始化支持的网关,后面会详细讲到。 继续跟踪minio.Main函数,它的代码实现在minio/cmd/main.go文件中,核心代码如下:

minio/cmd/main.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func newApp(name string) *cli.App {
   // Collection of minio commands currently supported are.
   commands := []cli.Command{}
   //省略无关代码
   // registerCommand registers a cli command.
   registerCommand := func(command cli.Command) {
      commands = append(commands, command)
   }
    //省略无关代码
   // Register all commands.
   registerCommand(serverCmd)
   registerCommand(gatewayCmd)//注册的网关命令。
   app := cli.NewApp()
   app.Name = name
   //省略无关代码
   app.Commands = commands
   app.CustomAppHelpTemplate = minioHelpTemplate
   //省略无关代码
   return app
}
// Main main for minio server.
func Main(args []string) {
   // Set the minio app name.
   appName := filepath.Base(args[0])
   // Run the app - exit on error.
   if err := newApp(appName).Run(args); err != nil {
      os.Exit(1)
   }
}

以上源代码我省略了很多和网关无关的,便于分析查看。从以上源代码可以清晰的看到MinIO是通过registerCommand函数注册了server和gateway这两个命令:registerCommand(serverCmd)registerCommand(gatewayCmd)。这样当你在终端输入minio回车的时候就可以看到server和gateway这两个命令的提示。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
➜  minio                      
NAME:
  minio - High Performance Object Storage
USAGE:
  minio [FLAGS] COMMAND [ARGS...]
COMMANDS:
  server   start object storage server
  gateway  start object storage gateway

到了这里,相信你已经清楚网关整体的启动流程了,那么如何启动一个具体的网关呢,比如NAS,这就要具体分析刚刚源代码中注册的gatewayCmd命令了。

gatewayCmd命令分析

gatewayCmd是一个定义在cmd包中的全局变量,它的源代码在minio/cmd/gateway-main.go文件中:

minio/cmd/gateway-main.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var (
   gatewayCmd = cli.Command{
      Name:            "gateway",
      Usage:           "start object storage gateway",
      Flags:           append(ServerFlags, GlobalFlags...),
      HideHelpCommand: true,
   }
)

gatewayCmd是一个比较顶层的命令,它下面还有很多子命令,比如nas、gcs等,一个子命令代表一个网关,那么这些子命令是如何注册作为gatewayCmd的子命令的呢?我以比较简单的NAS网关为例分析nas子命令的注册逻辑。

NAS网关子命令分析

还记得「网关启动代码分析」小节中留的github.com/minio/minio/cmd/gateway包导入使用init函数初始化的提示吧?现在就详细分析下,看MinIO是如何通过包的init函数实现nas子命令注册的。

minio/cmd/gateway/gateway.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package gateway
import (
   // Import all gateways please keep the order
   // NAS
   _ "github.com/minio/minio/cmd/gateway/nas"
   // Azure
   _ "github.com/minio/minio/cmd/gateway/azure"
   // S3
   _ "github.com/minio/minio/cmd/gateway/s3"
   // HDFS
   _ "github.com/minio/minio/cmd/gateway/hdfs"
   // GCS (use only if you must, GCS already supports S3 API)
   _ "github.com/minio/minio/cmd/gateway/gcs"
   // gateway functionality is frozen, no new gateways are being implemented
   // or considered for upstream inclusion at this point in time. if needed
   // please keep a fork of the project.
)

github.com/minio/minio/cmd/gateway包的源代码实现如上所示,没有啥东西,还是一堆包的导入,这次的每个包就代表一个网关的具体实现,比如NAS网关的实现在github.com/minio/minio/cmd/gateway/nas包中,它的命令注册源代码如下: minio/cmd/gateway/nas/gateway-nas.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func init() {
   const nasGatewayTemplate = `NAME:`//省略很多字符串
   minio.RegisterGatewayCommand(cli.Command{
      Name:               minio.NASBackendGateway,
      Usage:              "Network-attached storage (NAS)",
      Action:             nasGatewayMain,
      CustomHelpTemplate: nasGatewayTemplate,
      HideHelpCommand:    true,
   })
}

看到关键了吧?就是这个RegisterGatewayCommand函数,通过它把nas这个子命令注册给gateway这个父命令。再看下RegisterGatewayCommand函数的具体实现就可以证明了: minio/cmd/gateway-main.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// RegisterGatewayCommand registers a new command for gateway.
func RegisterGatewayCommand(cmd cli.Command) error {
   cmd.Flags = append(append(cmd.Flags, ServerFlags...), GlobalFlags...)
   gatewayCmd.Subcommands = append(gatewayCmd.Subcommands, cmd)
   return nil
}

看以上RegisterGatewayCommand函数 的源代码,把传入的命令作为gatewayCmd的子命令完成注册,而gatewayCmd就是我刚刚讲过的cmd包中的全局变量。

NAS网关启动分析

好了,nas子命令也注册好了,那么如果在终端中输入如下命令,程序会怎么运行呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 minio gateway nas /tmp/nas/

这就需要分析刚刚注册的nas子命令了,我再把注册nas子命令这段代码粘贴出来便于分析。 minio/cmd/gateway/nas/gateway-nas.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func init() {
   const nasGatewayTemplate = `NAME:`//省略很多字符串
   minio.RegisterGatewayCommand(cli.Command{
      Name:               minio.NASBackendGateway,
      Usage:              "Network-attached storage (NAS)",
      Action:             nasGatewayMain,
      CustomHelpTemplate: nasGatewayTemplate,
      HideHelpCommand:    true,
   })
}

仔细看如上源代码,看到cli.Command这个结构体的Action字段了吗?他就是一个命令在执行时运行的函数,也就是命令的处理逻辑都在这个函数中,对应nas子命令就是nasGatewayMain这个函数,现在只需要分析nasGatewayMain函数的源代码实现即可分析NAS网关的启动逻辑。 minio/cmd/gateway/nas/gateway-nas.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Handler for 'minio gateway nas' command line.
func nasGatewayMain(ctx *cli.Context) {
   // Validate gateway arguments.
   if !ctx.Args().Present() || ctx.Args().First() == "help" {
      cli.ShowCommandHelpAndExit(ctx, minio.NASBackendGateway, 1)
   }
   minio.StartGateway(ctx, &NAS{ctx.Args().First()})
}

以上源代码的核心在于StartGateway函数,它可以根据参数启动相应的网关。 minio/cmd/gateway-main.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// StartGateway - handler for 'minio gateway <name>'.
func StartGateway(ctx *cli.Context, gw Gateway) {
  //为了分析过程,我先省略这个函数的逻辑
}

StartGateway函数有两个参数,一个ctx是命令行的信息,比如你在终端输入的命令、参数以及Flag等,第二个Gateway就是你要启动哪个网关,这是一个接口: minio/cmd/gateway-interface.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Gateway represents a gateway backend.
type Gateway interface {
   // Name returns the unique name of the gateway.
   Name() string
   // NewGatewayLayer returns a new  ObjectLayer.
   NewGatewayLayer(creds auth.Credentials) (ObjectLayer, error)
   // Returns true if gateway is ready for production.
   Production() bool
}

这个Gateway接口里关键的方法就是NewGatewayLayer,通过它可以获得一个ObjectLayer来操作不同网关的文件或者对象数据(参考我画的网关架构图ObjectLayer那一层)。

NAS网关实现Gateway接口

Gateway是一个通用的网关操作接口,所以每个网关都有自己的实现,NAS网关也不例外,它的实现就是NAS这个结构体。

minio/cmd/gateway/nas/gateway-nas.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// NAS implements Gateway.
type NAS struct {
   path string
}
// Name implements Gateway interface.
func (g *NAS) Name() string {
   return minio.NASBackendGateway
}
// NewGatewayLayer returns nas gatewaylayer.
func (g *NAS) NewGatewayLayer(creds auth.Credentials) (minio.ObjectLayer, error) {
   var err error
   newObject, err := minio.NewFSObjectLayer(g.path)
   if err != nil {
      return nil, err
   }
   return &nasObjects{newObject}, nil
}
// Production - nas gateway is production ready.
func (g *NAS) Production() bool {
   return true
}

从以上NAS结构体实现Gateway接口的源代码可以看到,NAS本质上对于对象的操作使用的是MinIO自带的单点模式下的文件对象操作结构体FSObjects,这是很合理的,因为NAS操作的就是一个文件夹路径,这是MinIO的单点模式是一样的。

小提示:MinIO server启动有两种模式,一个是单点模式,一种是纠删码模式,其中单点模式就是只传了一个endpoint给minio,使用的是文件系统的操作方式,更详细的可以研究FSObjects的源代码实现。

最终网关启动

好了,NAS网关的具体实现也有了,生成的ObjectLayer也有了,那么就剩下最终网关的启动了,又回到了刚刚的nasGatewayMain函数,这部分函数的代码对所有网关都是一样的,因为它是针对Gateway接口的编程。

minio/cmd/gateway-main.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// StartGateway - handler for 'minio gateway <name>'.
func StartGateway(ctx *cli.Context, gw Gateway) {
    //省略无关很多紧要的代码
   // Handle common command args.
   handleCommonCmdArgs(ctx)
   // Handle gateway specific env
   gatewayHandleEnvVars()
   // Set when gateway is enabled
   globalIsGateway = true
   // Initialize router. `SkipClean(true)` stops gorilla/mux from
   // normalizing URL path minio/minio#3256
   // avoid URL path encoding minio/minio#8950
   router := mux.NewRouter().SkipClean(true).UseEncodedPath()
   // operations such as profiling, server info etc.
   registerAdminRouter(router, enableConfigOps, enableIAMOps)
   
   // Add API router.
   registerAPIRouter(router)
   // Use all the middlewares
   router.Use(registerMiddlewares)
   newObject, err := gw.NewGatewayLayer(globalActiveCred)
   newObject = NewGatewayLayerWithLocker(newObject)
   // Once endpoints are finalized, initialize the new object api in safe mode.
   globalObjLayerMutex.Lock()
   globalObjectAPI = newObject //关键代码,使用网关接口生成的ObjectLayer
   globalObjLayerMutex.Unlock()
   
   handleSignals()
}

以上是nasGatewayMain函数的源代码,我已经省略了很多无关紧要的代码,便于分析网关的启动。nasGatewayMain函数整体的代码逻辑和启动一个MinIO server很像,只不过全局的处理对象存储的globalObjectAPI换成了网关返回的ObjectLayer,这样通过API接口对对象的操作才会转换为底层真实网关的操作。 该函数其他的代码主要注册路由,比如前台的S3兼容API以及后台的Admin管理API等,并且通过globalIsGateway = true把这次启动标记为是作为网关启动的,便于MinIO内部其他代码逻辑的处理。

小结

这篇文章我主要以比较容易的NAS网关为例分析整个网关的启动,其他网关大同小异,主要是对于接口Gateway的具体代码实现不一样,其他都是一样的,所以当我们为MinIO新增一个网关时,只需要实现Gateway接口,然后通过init函数注册一个该网关的子命令给gatewayCmd即可,非常简单,这些都是得益于MinIO对网关架构的优秀设计。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020年10月19日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
golang 源码分析:minio(part I)路由
MinIO的命令行启动只有2个命令,一个是server、一个是gateway,分别用于启动服务和网关,而整个MinIO的启动是从main.go文件开始的
golangLeetcode
2022/08/03
1K0
MinIO对象存储的网关架构设计
MinIO是一个非常轻量的对象存储服务,它只有一个二进制文件即可运行,快速的构建分布式的对象存储集群,适合存储大容量的非结构化数据,比如图片、日志文件等这些。
飞雪无情
2020/09/15
3.8K0
MinIO对象存储的网关架构设计
golang 源码分析:mc,minio-go
对象存储服务(Object Storage Service,OSS)是一种海量、安全、低成本、高可靠的云存储服务,适合存放任意类型的文件。容量和处理能力弹性扩展,多种存储类型供选择,全面优化存储成本。Minio 除了直接作为对象存储使用,还可以作为云上对象存储服务的网关层,无缝对接到 Amazon S3、MicroSoft Azure。 在学习minio的源码之前,先阅读下minio的客户端mc和golang sdk minio-go
golangLeetcode
2022/08/03
1.5K0
使用 MinIO Gateway、MinIO Client 适配腾讯云COS
本文从通用的AWS S3协议,以及在兼容S3的第三方应用中使用COS的场景出发,介绍基于MinIO对象存储配置腾讯云对象存储COS的步骤,包括编译环境的准备工作,MinIO Client、MinIO Gateway的配置。
yjwang
2022/04/15
8.3K4
使用 MinIO Gateway、MinIO Client 适配腾讯云COS
NFT+DeFi流动性挖矿系统开发策划细节
其简洁是得力于 Geth 使用了 gopkg.in/urfave/cli.v1 扩展包,该扩展包用于管理程序的启动,以及命令行解析,其中 app 是该扩展包的一个实例。
KFZ433
2022/06/17
3730
golang 源码分析:minio(part II)文件的操作
在分析完minio请求的路由后golang 源码分析:minio(part I)路由,我们看下一个文件是如何落盘的,不考虑gateway情况,我们从serverMain开始:
golangLeetcode
2022/08/03
1.4K0
golang 源码分析:minio(part II)文件的操作
Minio对象存储
多节点的Minio会根据不同的Access_key及Secret_Key来区分不同租户,每个租户可操作对应Server获取Object。Minio Server间可以通过不同的进程模型、容器或是虚拟机来互相隔离。
仙人技术
2020/04/29
8.6K0
Minio对象存储
Python 命令行之旅:深入 click 之子命令篇
在上两篇文章中,我们介绍了 click 中的”参数“和“选项”,本文将继续深入了解 click,着重讲解它的“命令”和”组“。
HelloGitHub
2021/05/14
9460
go-zero微服务框架代码生成神器goctl原理分析(一)
推荐下go-zero 微服务框架,也是最近很火很有人气的框架,致力于打造国内最简单好用的框架。
杨永贞
2021/03/15
3.6K0
MinIO对象存储
MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。
别团等shy哥发育
2023/03/30
7K0
MinIO对象存储
对象存储:基于docker-compose 快速部署 MinIO
一、概述二、MinIO 与 Ceph 对比1)架构设计对比2)数据一致性对比3)部署和管理对比4)生态系统和兼容性对比三、前期准备1)部署 docker2)部署 docker-compose四、创建网络五、MinIO 编排部署1)下载 MinIO 安装包2)配置3)启动脚本 bootstrap.sh4)构建镜像 Dockerfile5)编排 docker-compose.yaml6)开始部署7)简单测试验证8)web 访问
Freedom123
2024/03/29
2.1K0
Micro api网关中间件
此时我们访问我们的API接口:http://localhost:9000/greeter/call
派大星在吗
2021/12/15
6230
Docker 环境下使用 Traefik v3 和 MinIO 快速搭建私有化对象存储服务
上一篇文章中,我们使用 Traefik 新版本完成了本地服务网关的搭建。接下来,来使用 Traefik 的能力,进行一系列相关的基础设施搭建吧。
soulteary
2024/08/05
2200
Docker 环境下使用 Traefik v3 和 MinIO 快速搭建私有化对象存储服务
自动监控文件并上传S3对象存储服务器 | Golang
本地平台:Windows 10 专业版 21H2 (19044.1826)、开发语言:go1.18.3 windows/amd64
ZGGSONG
2022/09/23
1.2K0
开源分布式对象存储-MinIO 顶
Minio可能在国内知道和用的人不是很多,我第一次接触Minio是也是当时我们需要使用Spinnaker集群来管理和维护内部的Kubernetes集群,而Spinnaker的中的持久化存储就使用的是Minio Spinnaker集群搭建。
BGBiao
2020/02/18
4.4K3
开源分布式对象存储-MinIO
                                                                            顶
以太坊交互工具
以太坊提供了Geth客户端用于管理API,我们可以在终端输入geth help查看其具体使用方法:
Al1ex
2021/07/21
1.8K0
以太坊交互工具
Github 29K Star的开源对象存储方案——Minio入门宝典
对象存储不是什么新技术了,但是从来都没有被替代掉。为什么?在这个大数据发展迅速地时代,数据已经不单单是简单的文本数据了,每天有大量的图片,视频数据产生,在短视频火爆的今天,这个数量还在增加。有数据表明,当今世界产生的数据,有80%是非关系型的。那么,对于图片,视频等数据的分析可以说是大数据与人工智能的未来发展方向之一。
用户6070864
2021/10/26
11.2K1
Github 29K Star的开源对象存储方案——Minio入门宝典
使用Docker Compose轻松部署MinIO对象存储
MinIO是一个开源的对象存储服务器,它兼容Amazon S3 API,并提供高性能、高可用性的存储解决方案。在本文中,我们将介绍如何使用Docker Compose快速部署MinIO。
修己xj
2023/08/25
2.3K0
使用Docker Compose轻松部署MinIO对象存储
【玩转Lighthouse】使用MinIO搭建云原生对象存储服务
本文从通用的AWS S3对象存储协议,以及在MinIO中使用 腾讯云对象存储 的场景出发,介绍基于MinIO云原生对象存储的搭建步骤和MinIO客户端的使用示例,以及MinIO SDK使用示例;包括在 CentOS8 中运行minIO服务端、minIO存储网关,在Docker环境中单点单容器运行minIO服务端、单点多容器运行minIO服务端以及单点单容器运行minIO存储网关
yjwang
2022/04/17
7.5K1
【玩转Lighthouse】使用MinIO搭建云原生对象存储服务
MinIO信息泄露漏洞(CVE-2023-28432)批量检测POC
MinIO 是一种开源对象存储服务,与 Amazon S3 API 兼容,可用于私有云或公共云。MinIO是一种高性能、高可用的分布式存储系统,可以存储大量数据,并提供高速的数据读写能力。MinIO采用分布式架构,可以在多个节点上运行,实现数据的分布式存储和处理。 在集群部署的Minio中,未授权的攻击者可发送恶意的HTTP请求来获取Minio环境变量中的敏感信息(MINIO_SECRET_KEY和MINIO_ROOT_PASSWORD),可能导致攻击者以管理员权限登录Minio。
没事就要多学习
2024/07/18
2910
MinIO信息泄露漏洞(CVE-2023-28432)批量检测POC
相关推荐
golang 源码分析:minio(part I)路由
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验