Как загружаются, кешируются и удаляются зависимости на Go, и что здесь изменилось с появлением GOPROXY и модулей? Как избежать ошибок сборки и обеспечить ее воспроизводимость?
Работаете на Go? Тогда вы наверняка сталкивались с этими загадочными GOPATH, GOPRIVATE, Go111module и т. д. Хлопот они обычно не доставляют, но иногда возможны ошибки, из-за которых разработка резко замедляется.
Покажем, как этих ошибок избежать. Итак, начнем!
Внимание: применимо только к Go 1.15 и новее.
GOROOT
GOROOT — это место хранения SDK для Go, компиляторов по умолчанию, исполняемых команд и библиотек. Не изменяйте эту переменную, если не переходите на другую версию Go.
При импорте библиотеки поиск файла начинается с GOROOT. Если файл не найден, поиск продолжается в GOPATH.
GOPATH
В GOPATH имеется три каталога: pkg, src и bin.
$GOPATH/pkg
- $GOPATH/pkg/mod — это местоположение кеша модулей по умолчанию, где хранятся и кешируются загруженные через go get или go install зависимости.
- Оно изменяется посредством редактирования переменной GOMODCACHE в go env.
$GOPATH/bin
- В каталоге bin хранятся установленные через go install исполняемые команды, в том числе сторонние и из исходных файлов.
- Стандартные команды, такие как gofmt, хранятся в каталоге GOROOT/bin.
$GOPATH/src
- В каталоге src хранятся исходные файлы.
- Но с появлением модулей он менее значим.
Модули Go
До модулей проекты и зависимости на Go хранились в каталоге $GOPATH/src/.
Контроль версий отсутствовал. В проектах каталога src библиотеки использовались в одной и той же стабильной версии, ветке master.
Появились модули, и теперь:
- проекты можно создавать вне каталога $GOPATH/src/;
- проект, он же модуль, — это набор выпускаемых вместе файлов и пакетов;
- в каждом модуле содержится файл go.mod, которым определяются требуемые зависимости и версии;
- зависимости загружаются из соответствующих репозиториев во время сборки.
Go.mod
Файлом go.mod определяются:
- путь к модулю, используемый при импорте пакетов/файлов в одном и том же модуле Go;
- зависимости и версии, необходимые для успешной сборки модуля.
Go.sum
При сборке на удаленном сервере в модуль из соответствующих систем контроля версий добавляются и загружаются указанные в файле go.mod зависимости.
Здесь неизбежны проблемы:
- Что, если кто-то намеренно поменяет версию библиотеки?
- Как гарантировать, что на удаленном сервере добавляется библиотека с точным содержимым локальной копии?
Но с go.sum они решаются:
- Это контрольная сумма всех прямых и косвенных зависимостей, перечисленных в go.mod.
- Ею проверяется и гарантируется, что локальная загруженная копия зависимостей аналогична удаленной.
Go mod tidy
При запуске go mod tidy:
- нужные зависимости загружаются, а ненужные из go.mod удаляются;
- из локального кеша, то есть $GOPATH/pkg/mod, библиотеки не удаляются.
Go clean -modcache
Когда в Go выполняется go get или go mod tidy, зависимости загружаются и кешируются в GOMODCACHE, то есть в $GOPATH/pkg/mod/ по умолчанию.
Этими кешированными библиотеками локальная разработка и локальная сборка сглаживаются.
Все загруженные пакеты удаляются из каталога GOMODCACHE с помощью go clean -modcache.
Go mod vendor
При сборке на удаленном сервере в модуль добавляются и загружаются указанные в файле go.mod зависимости.
Но проблема с сетью или удаление одной из зависимостей в системе контроля версий чревато ошибками сборки.
Чтобы гарантировать воспроизводимую сборку, командой go mod vendor в модуле создается папка и в каталоге сохраняются исходные файлы зависимостей.
Каталог vendor сохраняется вместе с изменением кода.
Так обеспечивается:
- воспроизводимость и последовательность сборки;
- легкость просмотра изменений в зависимостях.
Однако каталог занимает дополнительное место и увеличивается время клонирования репозитория. В итоге CI/CD удлиняется.
GOPROXY
До появления GOPROXY зависимости загружались из удаленных систем контроля версий напрямую.
Имелись две фундаментальные проблемы — безопасность и доступность. Зависимости в удаленной системе контроля версий можно было:
- в любое время удалить;
- изменить и скомпрометировать.
GOPROXY — это централизованный репозиторий, в котором размещаются и кешируются общедоступные сторонние модули.
Теперь каждый запрос на загрузку перенаправляется на общедоступный GOPROXY, а загруженный модуль проверяется на соответствие общедоступной базе данных контрольных сумм.
GOPROXY настраивается в go env. По умолчанию:
GOPROXY="https://proxy.golang.org"
Если нужный модуль в GOPROXY не найден, добавляем direct:
GOPROXY="https://proxy.golang.org,direct"
и загружаем модуль из удаленной системы контроля версий.
GOPRIVATE
С общедоступными модулями хорошо справляется GOPROXY. А что, если нужна зависимость из приватного репозитория, например репозитория компании?
Какие модули считать приватными, определяется командой GOPRIVATE. Например:
GOPRIVATE=*github.com/org_name
В Go любой путь, соответствующий такому шаблону, приватный. Следовательно, прокси- и глобальная база данных контрольных сумм не используются.
Go111module
GO111module означает режим с поддержкой модулей.
Диспетчера пакетов в Go не было до версии 1.11, когда появились модули. Зависимости получались через go get и сохранялись с исходными файлами в $GOPATH/src.
С появлением модулей загрузка, импорт и сохранение зависимостей изменились.
При GO111module=on в Go активировано модульное поведение, при GO111module=off — поведение GOPATH.
Поскольку модули Go теперь применяются на практике, поведение по умолчанию — GO111module=on.
Заключение
У команд Go и переменных среды́ еще много нюансов.
Мы рассмотрели те, что встречаются в рабочем процессе разработки почти каждый день.
Оцените данную статью подпиской на канал, если она вам понравилась!