Недавно мы начали использовать Go для новых микросервисов. Каждый микросервис — это модуль Go, и мы управляем им как монорепозиторием:
/
services/
s1/
go.mod
main.go
s2/
go.mod
main.go
Это прекрасно работает, но теперь нам нужно разделить некоторый код между s1
и s2
— некоторые структуры, используемые обоими сервисами, функцию, которая загружает в S3, и т. д.
Каков правильный способ управления этой ситуацией? В идеале я должен иметь каталог common
в корне репозитория (брат services
) и помещать туда общий код — но как Go будет брать оттуда код при компиляции s1
и s2
?
Я думаю, то, что вы спрашиваете, на самом деле просто вариант «Как структурировать приложение Go для создания нескольких двоичных файлов?».
Вы бы переместили свой go.mod
в переименование каталога верхнего уровня, чтобы у вас был такой макет:
.
├── common
│ └── common.go
├── go.mod
└── services
├── s1
│ └── main.go
└── s2
└── main.go
И go.mod
, начинающийся примерно так:
module mymodule
Если common/common.go
выглядит так:
package common
func CommonFunction() string {
return "This is a common function"
}
Затем в services/s1/main.go
вы можете импортировать модуль common
:
package main
import (
"mymodule/common"
"fmt"
)
func main() {
res := common.CommonFunction()
fmt.Println(res)
}
И вы бы построили сервис s1
следующим образом:
go build ./services/s1
Здание s2
будет похоже:
go build ./services/s2
Обычно у вас есть Makefile
верхнего уровня для автоматизации создания нескольких сервисов.
Что, если s1
нужны зависимости, которые не нужны s2
? Один go.mod
означает, что они оба получат его, а образ докера будет больше.
Я не уверен, что это правда. Я думаю, что компоновщик Go достаточно умен, чтобы не включать ненужные зависимости в скомпилированный двоичный файл. Я не уверен на 100%, поэтому, если ваш существующий проект обладает такими характеристиками, попробуйте эту структуру и посмотрите, как она повлияет на окончательные размеры.
Это выглядит великолепно, спасибо. Я попробую, и если он сделает то, что мне нужно, я соглашусь.