Переменные среды и Go-модули

Редактор ты настроил ещё в первом уроке и с тех пор пишешь в нём весь курс. Теперь разберёмся, что у Go под капотом: где он ищет модули, куда складывает кеш и как объяснить ему, что репозиторий компании качать через прокси не надо.

Переменные среды Go

Все настройки Go хранятся в переменных среды. Посмотреть их можно одной командой:

go env

Ключевые переменные

# Где установлен Go
go env GOROOT
# /usr/local/go

# Где живут ваши модули и бинарники
go env GOPATH
# /Users/username/go

# Прокси для скачивания модулей
go env GOPROXY
# https://proxy.golang.org,direct

# Что скачивать напрямую, минуя прокси (приватные репозитории компании)
go env GOPRIVATE
# пусто по умолчанию

# Где лежит кэш скачанных модулей
go env GOMODCACHE
# /Users/username/go/pkg/mod
В инструкциях времён Go 1.11-1.15 часто встречается `GO111MODULE=on`. Это переключатель между старым режимом GOPATH и модулями, и с Go 1.16 модули включены всегда. Трогать эту переменную сегодня нужно разве что при работе с очень старым проектом. Если статья начинается с `export GO111MODULE=on`, она написана до 2021 года, и остальные советы в ней стоит перепроверить. GOPATH содержит три папки: - `bin/` - скомпилированные бинарники (`go install`) - `pkg/` - кеш модулей - `src/` - (устаревшее) раньше тут хранили исходники

Настройка PATH

Чтобы запускать установленные Go-программы из любого места, добавьте $GOPATH/bin в PATH:

# ~/.bashrc или ~/.zshrc
export PATH=$PATH:$(go env GOPATH)/bin

Проверка:

# Установим полезную утилиту
go install golang.org/x/tools/cmd/goimports@latest

# Должна работать из любой директории
goimports --help

Изменение переменных

# Временно (для текущей сессии)
export GOPATH=/custom/path

# Постоянно через go env
go env -w GOPATH=/custom/path
go env -w GOPRIVATE=github.com/mycompany/*

Полезные Go-утилиты

Расширение редактора ставит gopls и базовые инструменты само. Отдельно доставляют то, что нужно в терминале и в CI - там редактора нет:

# Форматирование + импорты (то же, что делает редактор при сохранении,
# но применимо ко всему проекту разом и в CI)
go install golang.org/x/tools/cmd/goimports@latest

# Линтер: находит то, что компилятор пропускает - непроверенные ошибки,
# затенённые переменные, мёртвый код
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest

# Статический анализ, входит в поставку Go
go vet ./...

# Документация по стандартной библиотеке локально, без интернета
go install golang.org/x/tools/cmd/godoc@latest
godoc -http=:6060
`@latest` удобен на своей машине и опасен в пайплайне: сборка, которая вчера проходила, завтра падает на новом правиле линтера. В CI версию фиксируют явно - `golangci-lint@v1.62.0`. Разберём это в уроке [CI/CD](../docker/09-gitlab-ci.md).

Go Modules

Каждый проект начинается с инициализации модуля:

mkdir myproject && cd myproject
go mod init github.com/username/myproject

Файл go.mod - манифест проекта:

module github.com/username/myproject

// Директива go задаёт минимальную версию языка для модуля.
// Ставьте ту, на которой реально собираете: она включает соответствующие
// возможности языка и правила сборки.
go 1.24

require (
    github.com/gin-gonic/gin v1.10.0
)

Основные команды:

go mod tidy      # удалить неиспользуемые, добавить недостающие
go mod download   # скачать зависимости
go mod vendor     # скопировать зависимости в vendor/

Приватные модули компании

Эта настройка понадобится в первый же рабочий день, и без неё ничего не соберётся. По умолчанию Go качает зависимости не напрямую из репозитория, а через публичный прокси proxy.golang.org и сверяет контрольные суммы с sum.golang.org. Для открытых библиотек это быстро и безопасно.

С приватным репозиторием компании выходит иначе: прокси до него не достучится и вернёт 410 Gone или 404, а сообщение будет выглядеть так, будто модуля не существует:

go: gitlab.company.ru/backend/auth@v1.2.0: verifying module:
    gitlab.company.ru/backend/auth@v1.2.0: reading
    https://sum.golang.org/lookup/...: 410 Gone

Решение - сказать Go, какие пути качать напрямую, минуя прокси и проверку сумм:

go env -w GOPRIVATE=gitlab.company.ru/*,github.com/mycompany/*

Одна переменная выключает для этих путей и прокси, и sum.golang.org сразу. Дальше Go пойдёт в репозиторий обычным git clone, и упрётся в следующее: по HTTPS он попросит логин и пароль. Обычно доступ настроен по SSH-ключу, поэтому git просят подменять протокол:

git config --global url."git@gitlab.company.ru:".insteadOf "https://gitlab.company.ru/"
В интернете встречается совет `GOFLAGS=-insecure` или `GONOSUMDB=*`. Так вы выключите проверку контрольных сумм для **всех** зависимостей, включая публичные - именно ту защиту, которая ловит подмену чужого пакета. `GOPRIVATE` точечно исключает только ваши пути и остаётся правильным ответом.

Когда сборка ведёт себя странно

Три команды, которые закрывают почти все загадочные случаи с зависимостями:

# Откуда вообще взялся этот пакет: покажет цепочку импортов до него
go mod why github.com/some/package

# Проверить, что скачанное совпадает с контрольными суммами в go.sum
go mod verify

# Снести кеш модулей целиком (~/go/pkg/mod) - последнее средство,
# когда кеш повреждён и ошибки нелогичны
go clean -modcache

go mod why полезнее, чем кажется. Когда go mod tidy тянет в проект незнакомую библиотеку, вопрос не «что это», а «кто её попросил» - и ответ почти всегда какая-то транзитивная зависимость.

Ошибка `checksum mismatch` означает, что содержимое модуля отличается от записанного в `go.sum`. Иногда это переписанный тег в чужом репозитории, иногда - повреждённый кеш. Но это же выглядит и как подмена зависимости, поэтому правильный порядок такой: сначала `go clean -modcache` и повтор, и только если ошибка осталась - разбираться, что изменилось в модуле. Удалять строку из `go.sum`, чтобы «заработало», нельзя.

Мини-задание

  • Напечатай os.Getenv("НЕТ_ТАКОЙ") и сравни с os.LookupEnv. Разница между «пусто» и «не задано» однажды будет стоить инцидента
  • Запусти программу с переменной прямо в команде: PORT=9090 go run .
  • Посмотри дерево зависимостей: go mod graph | head -20, и почему пришла конкретная библиотека: go mod why <модуль>
  • Выполни go mod tidy и посмотри диффом, что изменилось в go.mod и go.sum
  • Загляни в go.sum и объясни, зачем там по две строки на модуль

Итоги

Теперь ты умеешь:

  • ✅ Читать и менять настройки через go env и go env -w
  • ✅ Различать GOROOT (сам Go) и GOPATH (кеш и бинарники)
  • ✅ Подключать приватные репозитории через GOPRIVATE и insteadOf
  • ✅ Разбираться, откуда взялась зависимость, и чинить кеш модулей

Мини-практика

Выполни go env GOPATH GOROOT GOMODCACHE и посмотри, где что лежит. Затем в любом своём проекте запусти go mod why для одной из зависимостей в go.mod и проследи цепочку импортов до неё.

Дальше - горутины и конкурентность.

Зарегистрируйтесь бесплатно, чтобы пройти квиз, решить задание с автопроверкой, вести прогресс.