Golang微服务项目结构

Golang microservice project structure

我正处于在 Go 中创建微服务应用程序的初始阶段,但由于处理导入路径和目录的方式,我不太确定构建项目文件的最佳方式是什么。

通常情况下,项目在 Java 中看起来像这样:

|-- gateway_microservice
   |-- src
   |-- docker
|-- config_microservice
   |-- src
   |-- docker
|-- recommendation_microservice
   |-- src
   |-- docker
|-- users_microservice
   |-- src
   |-- docker

现在,如果我在 Go 中以同样的方式进行操作,导入路径会变得有些麻烦:

import (
       "fmt" 
       "github.com/user/myproject/gateway_microservice/src/package1"
       "github.com/user/myproject/gateway_microservice/src/package2"
)

此外,我听说惯用的方法是将所有 main.go 文件放在单独的 cmd 目录中,这增加了混乱。它看起来像这样吗:

|-- cmd
   |-- gateway_microservice
      |-- main.go
   |-- config_microservice
      |-- main.go
   |-- recommendation_microservice
      |-- main.go
   |-- users_microservice
      |-- main.go
|-- gateway_microservice
   |-- src
   |-- docker
|-- config_microservice
   |-- src
   |-- docker
|-- recommendation_microservice
   |-- src
   |-- docker
|-- users_microservice
   |-- src
   |-- docker

在 Go 中构建这样的项目的 'correct' 或惯用方法是什么?

如何组织我的项目?

|-- github.com/avelino/service1
   |-- Dockerfile
   |-- main.go
|-- github.com/avelino/service2
   |-- Dockerfile
   |-- main.go
|-- github.com/avelino/service3
   |-- Dockerfile
   |-- main.go

套餐

所有 Go 代码都组织成包。 Go 中的包只是一个 directory/folder,其中包含一个或多个 .go 文件。 Go 包提供代码的隔离和组织,类似于 directories/folders 在计算机上组织文件的方式。

所有 Go 代码都在包中,包是访问 Go 代码的入口点。理解和建立围绕包的良好实践对于编写有效的 Go 代码很重要。

这里的另一个答案提倡将每个微服务放入自己的存储库中。以这种方式拆分东西可能有正当理由,但想要将所有内容都保存在一个存储库中也可能有同样正当的理由(这实际上取决于您的项目/环境)

如果你想将所有代码放在一个存储库中,你可以 - 你只需要遵循 Go 的包规则。 (这是一个很好的阅读:https://golang.org/doc/code.html#Workspaces

如果您混合使用命令和库,您在问题中提出的目录结构很接近,但您可能不需要其中的 src 目录。下面是一个包含库和命令的 repo 中目录结构的示例:

lib1/
-- some.go
-- source.go
lib2/
-- more.go
-- source.go
cmd/
-- microservice1/
   -- main.go
-- microservice2/
   -- anothermain.go

要使用此存储库,您可以将其克隆到系统上的 Go 工作区中(请参阅我上面分享的 link)。假设您的存储库位于 github.com/mybiz/project,而您的 GOPATH~/go,工作区将如下所示:

~/go/src/github.com/mybiz/
  -- project/
     <clone repo in here>

文件 cmd/microservice1/main.go 将通过它期望的相对于 $GOPATH/src 的路径包含库 lib1,如下所示:

import "github.com/mybiz/project/lib1"

现在,您的代码可以使用 lib1 下文件中声明的包名称访问该包中导出的符号...通常只是:

package lib1

cmd/microservice1/main.go 中,通过上面的导入,您可以使用 lib1 符号,如下所示:

lib1.CallMe()

我希望这有助于阐明 Go 的目录结构是如何工作的。

我是这样组织的; mono-repo 每。项目方法。考虑到这些服务密切相关:

github.com/user/some_project/
├── pkg/ (common own-created packages for all services)
|   ├── errors/
|   ├── log/
|   ├── metrics/
|   ├── sd/
|   |   ├── consul/
|   |   └── kubernetes/
|   └── tracing/
├── services/
|   ├── account/
|   |   ├── pb/
|   |   |   ├── account.proto
|   |   |   └── account.pb.go
|   |   ├── handler.go
|   |   ├── main.go
|   |   ├── main_test.go
|   |   ├── Dockerfile
|   |   └── README.md
|   ├── auth/
|   ├── frontend/
|   └── user/
├── vendor/ (common vendor-packages for all services)
├── docker-compose.yml
├── go.mod
├── go.sum
├── Makefile
└── README.md

备选方案 2:

github.com/user/some_project/
├── pkg/
├── service.account/
|   ├─ cmd/
|   |  └─ main.go
|   ├─ pb/
|   ├─ Dockerfile
|   ├─ go.mod
|   └─ go.sum
├── service.auth/
├── service.frontend/
├── service.user/
├── docker-compose.yml
├── go.mod (used primarly for packages in the /pkg dir.)
├── go.sum
├── Makefile
└── README.md

随着 go-modules 的引入,我更倾向于第二种选择。

稍后,当您开始第二个 macro/micro/nano-services 项目时,/pkg 文件夹中的许多这些包也将在那里需要。该怎么办? Copy/paste?不!相反,从项目中提取这些包,即日志、指标并制作您自己的工具包。

请记住,如果您使用某种 CI/CD(您确实应该这样做),您可以选择编写放置在项目根目录中的脚本,该脚本将只检测您在存储库中所做的更改,因此只会构建和交付受影响的服务。有几个如何执行此操作的示例。

感谢@karl-andresen。我正在研究同一主题并提出以下结构希望这对某人有所帮助

github.com/username/container/
├── pkg/ ('username' created packages - common for all services & reusable in other projects)
|   ├── errors/
|   ├── log/
|   ├── metrics/
|   ├── infra/     (sub category in packages)
|   |   ├── consul/
|   |   └── kubernetes/
|   └── tracing/
├── services/ (where all microservices will be imported as submodules - may or may not be reused)
|   ├── account/
|   |   ├── handler.go
|   |   ├── handler_test.go (unit testing, note filename with '_test')
|   |   ├── main.go
|   |   ├── main_test.go    (another unit testing)
|   |   ├── account.cfg     (configuration file for account microservice)
|   |   ├── submodule/      (sub directory)
|   |   |   ├── submodule.go
|   |   |   └── submodule_test.go   (submodule unit test)
|   |   ├── Dockerfile
|   |   └── README.md
|   ├── auth/
|   ├── booking/
|   └── user/
├── api/ (OpenAPI/Swagger specs, JSON schema files, protocol definition files.)
|   ├── proto/  (protocol buffer files)
|   |   ├── v1/
|   |   |   ├── account.proto
|   |   |   ├── account.pb.go
|   |   |   ├── booking.proto
|   |   |   └── booking.pb.go
|   |   └── v2/
|   └── rest/   (json files)
|       ├── v1/
|       |   ├── booking.json
|       |   └── account.json
|       └── v2/
├── configs/ (project config settings, default configs, file templates)
├── scripts/ (Scripts to perform various build, install, analysis, etc operations.)
├── build/ (Packaging and Continuous Integration.)
├── test / (system and module level tests)
├── docs/ (project documents folder)
├── examples/ (project examples for service interactions)
├── third_party/ (all open source, third party codes, where applicable fork and add as submodule)
├── githooks/ (project git hooks)
├── assets/ (common assests for all services)
├── Makefile
├── README.md
└── docker-compose.yml

每个微服务都应该是一个独立的服务,并使用 RESTful、RPC 或消息传递通过网络相互通信。按照 12 Factor of App is a virtue when designing a microservice to make sure it easy to ship. Check typical-go-server 获取有关如何使微服务友好项目的示例。