英文:
Golang microservice project structure
问题
在Go中,项目的结构可以根据个人偏好和项目需求进行设计。然而,有一些常见的惯例可以作为参考。
首先,关于导入路径的问题,你可以使用Go模块来管理依赖项。使用Go模块后,你可以使用相对路径或自定义的模块路径来导入包,而不必使用完整的GitHub路径。这样可以简化导入路径,例如:
import (
"fmt"
"myproject/gateway_microservice/src/package1"
"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
这种结构将每个微服务的main.go
文件放在cmd
目录下,而其他源代码文件则根据需要放在相应的微服务目录下。
总之,Go的项目结构可以根据个人喜好和项目需求进行调整,但以上提到的惯例可以作为参考。
英文:
I'm at an initial stage of creating a microservice application in Go, but due to the way that the import paths and directories are handled I'm not quite sure what's best way to structure the project files.
Normally, the project would look something like this in Java:
|-- gateway_microservice
|-- src
|-- docker
|-- config_microservice
|-- src
|-- docker
|-- recommendation_microservice
|-- src
|-- docker
|-- users_microservice
|-- src
|-- docker
Now if I do it the same way in Go, the import paths become somewhat cumbersome:
import (
"fmt"
"github.com/user/myproject/gateway_microservice/src/package1"
"github.com/user/myproject/gateway_microservice/src/package2"
)
Additionally, I hear that the idiomatic way is to put all main.go
files in a separate cmd
directory, which adds to the confusion. Would it look something like this:
|-- 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
What is the 'correct' or idiomatic way of structuring a project like this in Go?
答案1
得分: 18
我按照以下结构进行组织:每个项目使用单一仓库的方式。考虑到这些服务之间的密切关联,如下所示:
github.com/user/some_project/
├── pkg/(所有服务共用的自定义包)
| ├── 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/(所有服务共用的第三方包)
├── docker-compose.yml
├── go.mod
├── go.sum
├── Makefile
└── README.md
另一种选择是:
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(主要用于/pkg目录下的包)
├── go.sum
├── Makefile
└── README.md
随着引入go-modules,我更倾向于第二种选择。
在以后的宏观/微观/纳米服务项目中,/pkg文件夹中的许多包也将被需要。怎么办呢?复制/粘贴?不!相反,从项目中提取这些包,例如log、metric,并创建自己的工具包。
请记住,如果你使用某种CI/CD(你真的应该使用),你可以编写一个脚本放置在项目根目录中,它将仅检测你在仓库中所做的更改,因此只会构建和交付受影响的服务。有很多示例可以告诉你如何做到这一点。
英文:
I'm structuring it like this; mono-repo per. project approach. Taking into account that these services are closely related:
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
Alternative 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
With the introduction of go-modules, I'm leaning more to the second alternative.
At some later time, when you start on your second macro/micro/nano-services project, many of the these packages in the /pkg folder would be required there too. What to do? Copy/paste? No! Instead, extract these packages from the project, i.e. log, metric and make your own kit.
Remember that if you use some kind of CI/CD (you really should), you have the option to write a script placed in the project root that will only detect the changes you make in the repository, thus only the affected services will be built and delivered. There are several examples out there how to do this.
答案2
得分: 13
这里的另一个答案主张将每个微服务放入自己的代码库中。这样分割的原因可能是合理的,但保持所有内容在一个代码库中也可能有同样合理的原因(这取决于你的项目/情况)。
如果你想要将所有代码放在一个代码库中,你可以这样做-只需要遵循Go的包规则。(这是一个很好的阅读材料:https://golang.org/doc/code.html#Workspaces)
如果你有一些命令和库混合在一起,你在问题中提出的目录结构接近正确,但你可能不需要在其中包含src
目录。下面是一个在包含库和命令的代码库中的目录结构示例:
lib1/
-- some.go
-- source.go
lib2/
-- more.go
-- source.go
cmd/
-- microservice1/
-- main.go
-- microservice2/
-- anothermain.go
要使用这个代码库,你需要在你的系统上的Go工作区中克隆它(参见我上面分享的链接)。假设你的代码库位于github.com/mybiz/project,并且你的GOPATH
是~/go
,那么工作区的结构如下:
~/go/src/github.com/mybiz/
-- project/
<在这里克隆代码库>
文件cmd/microservice1/main.go
将通过相对于$GOPATH/src
的路径来包含lib1
库,如下所示:
import "github.com/mybiz/project/lib1"
现在,你的代码可以使用在lib1
文件夹下声明的包名来访问该包中的导出符号...通常只需使用:
package lib1
在cmd/microservice1/main.go
中,通过上面的导入,你可以这样使用lib1
中的符号:
lib1.CallMe()
希望这有助于解释Go的目录结构是如何工作的。
英文:
The other answer here advocates putting each microservice into its own repository. There may be valid reasons for splitting things up that way, but there may be equally valid reasons from wanting to keep everything in one repository as well (it really depends on your project / circumstances)
If you want all the code in one repository, you can- you just need to follow Go's package rules. (this is a good read: https://golang.org/doc/code.html#Workspaces)
If you have a mix of commands and libraries, the directory structure you proposed in your question comes close, but you probably don't need the src
directories in there. Here's an example of how a directory structure within a repo with libraries and commands might look:
lib1/
-- some.go
-- source.go
lib2/
-- more.go
-- source.go
cmd/
-- microservice1/
-- main.go
-- microservice2/
-- anothermain.go
To use this repository, you would clone it inside a Go workspace on your system (see the link I shared above). Assuming your repository lives in github.com/mybiz/project, and your GOPATH
was ~/go
, the workspace would look as follows:
~/go/src/github.com/mybiz/
-- project/
<clone repo in here>
The file cmd/microservice1/main.go
would include the library lib1
via a path it expects it in relative to $GOPATH/src
as follows:
import "github.com/mybiz/project/lib1"
Now, your code has access to the exported symbols in that package using the package name declared in the files under lib1
... usually just:
package lib1
In cmd/microservice1/main.go
, with the import above, you could use lib1
symbols as follows:
lib1.CallMe()
I hope that helps clear up how Go's directory structure works.
答案3
得分: 10
感谢@karl-andresen。我正在研究同一个主题,并提出了以下结构,希望能帮助到其他人。
github.com/username/container/
├── pkg/('username'创建的包-对所有服务通用,在其他项目中可重用)
| ├── errors/
| ├── log/
| ├── metrics/
| ├── infra/(包中的子类别)
| | ├── consul/
| | └── kubernetes/
| └── tracing/
├── services/(将所有微服务作为子模块导入的位置-可能会被重用)
| ├── account/
| | ├── handler.go
| | ├── handler_test.go(单元测试,请注意文件名中的'_test')
| | ├── main.go
| | ├── main_test.go(另一个单元测试)
| | ├── account.cfg(账户微服务的配置文件)
| | ├── submodule/(子目录)
| | | ├── submodule.go
| | | └── submodule_test.go(子模块单元测试)
| | ├── Dockerfile
| | └── README.md
| ├── auth/
| ├── booking/
| └── user/
├── api/(OpenAPI/Swagger规范,JSON模式文件,协议定义文件。)
| ├── proto/(协议缓冲文件)
| | ├── v1/
| | | ├── account.proto
| | | ├── account.pb.go
| | | ├── booking.proto
| | | └── booking.pb.go
| | └── v2/
| └── rest/(JSON文件)
| ├── v1/
| | ├── booking.json
| | └── account.json
| └── v2/
├── configs/(项目配置设置,默认配置,文件模板)
├── scripts/(执行各种构建、安装、分析等操作的脚本。)
├── build/(打包和持续集成。)
├── test/(系统和模块级测试)
├── docs/(项目文档文件夹)
├── examples/(用于服务交互的项目示例)
├── third_party/(所有开源的第三方代码,在适用的情况下进行fork并作为子模块添加)
├── githooks/(项目git钩子)
├── assets/(所有服务的公共资源)
├── Makefile
├── README.md
└── docker-compose.yml
英文:
Thanks to @karl-andresen. I was doing research on the same topic and came up with the below structure hope this helps someone
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
答案4
得分: 4
如何组织我的项目?
|-- github.com/avelino/service1
|-- Dockerfile
|-- main.go
|-- github.com/avelino/service2
|-- Dockerfile
|-- main.go
|-- github.com/avelino/service3
|-- Dockerfile
|-- main.go
包
所有的Go代码都被组织成包。在Go中,一个包就是一个包含一个或多个.go文件的目录/文件夹。Go包提供了类似于计算机上目录/文件夹组织文件的隔离和组织代码的功能。
所有的Go代码都存在于一个包中,而包是访问Go代码的入口点。理解和建立良好的包管理实践对于编写有效的Go代码非常重要。
英文:
How do I organize my projects?
|-- github.com/avelino/service1
|-- Dockerfile
|-- main.go
|-- github.com/avelino/service2
|-- Dockerfile
|-- main.go
|-- github.com/avelino/service3
|-- Dockerfile
|-- main.go
Packages
All Go code is organized into packages. A package in Go is simply a directory/folder with one or more .go files inside of it. Go packages provide isolation and organization of code similar to how directories/folders organize files on a computer.
All Go code lives in a package and a package is the entry point to access Go code. Understanding and establishing good practices around packages is important to write effective Go code.
答案5
得分: -2
每个微服务都应该是一个独立的服务,并通过网络使用RESTful、RPC或消息传递与其他服务进行通信。在设计微服务时,遵循12因素应用程序是一种美德,可以确保它易于部署。可以参考typical-go-server的示例,了解如何创建友好的微服务项目。
英文:
Each microservice should be an independent service and communicate with each other through network either using RESTful, RPC or messaging. Follow 12 Factor of App is a virtue when designing a microservice to make sure it easy to ship. Check typical-go-server for an example of how to make microservice friendly project.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论