Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Minimal Version Selection - dependency management in Go 1.11, Golang Meetup 06.09.2018 [RUS]

Ivan Korolev
September 06, 2018

Minimal Version Selection - dependency management in Go 1.11, Golang Meetup 06.09.2018 [RUS]

Minimal Version Selection (MVS) is a new dependency management algorithm in the upcoming Go 1.11 release, available out-of-box.
This talk covers how MVS helps to resolve the existing problems with dependency vendoring and how one should use new go tooling from the upcoming release.

В новом релизе Go 1.11 появится возможность работы с зависимостями "из коробки". В докладе рассказывается про используемый алгоритм разрешения зависимостей "Minimal Version Selection", решаемые с его помощью проблемы, и показано, как жить в чудесном новом мире Go 1.11

Обновлённая версия слайдов для Golang Meetup Moscow, 06.09.2018

#dependency_management #go #go1.11 #mvs #vgo

Ivan Korolev

September 06, 2018
Tweet

More Decks by Ivan Korolev

Other Decks in Programming

Transcript

  1. Зависимости в Go • Как это было? • Minimal Version

    Selection • Текущий статус • Примеры работы с зависимостями • Подводные камни 04
  2. Вместо предисловия 05 What is Software Engineering? Software engineering is

    what happens to programming when you add time and other programmers.
  3. В начале было... 06 • pre-go1 - makefiles, gobuild (2009)

    • pre-go1 - goinstall (2010) - VCS-репозитории • go 1 - go get (2011) • go 1.2 FAQ: Import Compatibility Rule (2013) • создан gopkg.in (2014) - gopkg.in/yaml.v2 go get -u golang.org/x/tools/cmd/goimports
  4. Vendoring и воспроизводимые сборки (reproducible builds) 07 • goven (2012)

    - модификация импортов • godep (2013) - модификация $GOPATH • gb, glide, gom ... (2014) • go 1.5 - vendoring в тулчейне "original.com/pkg" -> "you.com/external/original.com/pkg" GO15VENDOREXPERIMENT=1 go build
  5. Vendoring - проблемы 08 • Дюжина менеджеров зависимостей (с разным

    форматом) • Нет поддержки SemVer в go toolchain • Коммитить папку vendor в репу - 
 cannot use opts 
 (type "<lib>/vendor/google.golang.org/ grpc".CallOption) as type []"<app>/vendor/ google.golang.org/grpc".CallOption
  6. Встречаем... vgo (февраль 2018) 010 • Semantic Import Versioning
 import

    "github.com/go-yaml/yaml/v2" • Go module - коллекция пакетов с общим путём • Minimal Version Selection • $GOPATH - больше не завязаны на src
  7. Go modules 012 package main import ( "fmt" "rsc.io/quote" )

    func main() { fmt.Println(quote.Hello()) }
  8. Go modules 013 $ go mod init example.com/test go: creating

    new go.mod: module example.com/test $ cat go.mod module example.com/test
  9. Go modules 014 $ go mod tidy go: finding rsc.io/quote

    v1.5.2 go: downloading rsc.io/quote v1.5.2 go: finding rsc.io/sampler v1.3.0 go: finding golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c go: downloading rsc.io/sampler v1.3.0 go: downloading golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
  10. Зависимости в Go • Как это было? • Minimal Version

    Selection • Текущий статус • Примеры работы с зависимостями • Подводные камни 016
  11. Minimal Version Selection 017 build list - список всех модулей

    зависимостей и их версий Задачи: • Построение build list • Обновление всех зависимостей • Обновление модуля до нужной версии • Откат модуля до нужной версии
  12. MVS - мин. список зависимостей алгоритм R 022 Реверсивный обратный

    обход E1.3, D1.4, B1.2, G1.1, F1.1, C1.3 C1.3, F1.1, G1.1, B1.2, D1.4, E1.3
  13. MVS - обновление одного модуля 024 build list + алгоритм

    R E1.2, D1.3, B1.2, D1.4, C1.2, G1.1, F1.1, C1.3 C1.3, F1.1, G1.1, C1.2, D1.4, B1.2, D1.3 E1.2
  14. Minimal Version Selection 027 Простота реализации - алгоритмы на графах

    Минимальность вносимых изменений Не NP-полная (не нужно решать 3SAT) Локальные replace и exclude Воспроизводимость билдов
  15. MVS - воспроизводимость билдов 028 Библиотека не должна диктовать сборку

    - replace и exclude локальные. Cargo и Dep - навязывают последние версии через манифест. Есть вероятность забыть обновить манифест - билд нестабилен (B > 1.1, используем B 1.2)
  16. Зависимости в Go • Как это было? • Minimal Version

    Selection • Текущий статус • Примеры работы с зависимостями • Подводные камни 029
  17. Статус 13 июля - vgo влили в go devel 20

    июля - go1.11beta2 24 августа - go1.11 go help modules 030
  18. Статус - обратная совместимость GO111MODULE=auto GO111MODULE=on go build <...> Зачем?

    Можно бы было определять "динамически" по наличию go.mod в репозитории... 031
  19. Статус - обратная совместимость $GOPATH/src/A - без go.mod, импортирует B

    $GOPATH/src/B - есть go.mod, импортирует C $GOPATH/src/C - отсутствует 032
  20. Статус - обратная совместимость 033 $ cd $GOPATH/src/A $ go

    build # B ../B/b.go:10: import "C": C not found <Странно, попробуем собрать B напрямую> $ go build B ../B/b.go:10: import "C": C not found
  21. Статус - обратная совместимость 034 <Но я же только что

    работал с B!> $ cd ../B $ go build $ <ЧТО? Собирается же> $ go build B $ go build С $
  22. Начало работы (fail 1) $ cd `mktemp -d` $ go

    get github.com/gorilla/mux@latest go: cannot use path@version syntax in GOPATH mode Почему?! GO111MODULE=auto 036
  23. Начало работы (fail 2) $ export GO111MODULE=on ... $ go

    get github.com/alecthomas/gometalinter go: cannot find main module; see 'go help modules' 037
  24. Начало работы $ cd `mktemp -d` $ go mod init

    example.com/test $ go get github.com/gorilla/mux@latest go: finding github.com/gorilla/mux v1.6.2 go: downloading github.com/gorilla/mux v1.6.2 $ cat go.mod module example.com/test require github.com/gorilla/mux v1.6.2 // indirect 038
  25. go.mod 039 module example.com/test require ( github.com/BurntSushi/toml v0.3.0 // indirect

    github.com/apache/thrift v0.0.0-20180627210808-129f332d72fa // indirect github.com/go-chi/chi v3.3.3+incompatible github.com/go-chi/cors v1.0.0 ... google.golang.org/grpc v1.13.0 )
  26. go.sum $ cat go.sum github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/ r4CpKzC5xBM/qW1uVLV+IhRZpIIk= github.com/gorilla/mux v1.6.2/go.mod

    h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= $GOPATH/pkg/mod/<import_path> $GOPATH/pkg/mod/cache $ go clean -modcache 040
  27. Хранение версий $ ls -al $GOPATH/pkg/mod/cache/download/github.com/gorilla/mux/@v/ total 360 drwxr-xr-x 15

    ikorolev staff 480 Jul 24 13:18 . drwxr-xr-x 3 ikorolev staff 96 Jul 24 13:06 .. -rw-r--r-- 1 ikorolev staff 21 Jul 24 13:18 list -rw------- 1 ikorolev staff 123 Jul 24 13:18 v1.5.0.info -rw------- 1 ikorolev staff 30 Jul 24 13:18 v1.5.0.mod -rw-r--r-- 1 ikorolev staff 37948 Jul 24 13:18 v1.5.0.zip -rw-r--r-- 1 ikorolev staff 47 Jul 24 13:18 v1.5.0.ziphash -rw------- 1 ikorolev staff 123 Jul 24 13:17 v1.6.1.info -rw------- 1 ikorolev staff 30 Jul 24 13:17 v1.6.1.mod -rw-r--r-- 1 ikorolev staff 46619 Jul 24 13:17 v1.6.1.zip -rw-r--r-- 1 ikorolev staff 47 Jul 24 13:17 v1.6.1.ziphash 041
  28. Хранение версий $ ls -al $GOPATH/src/mod/github.com/gorilla/ total 0 drwxr-xr-x 5

    ikorolev staff 160 Jul 24 13:18 . drwxr-xr-x 9 ikorolev staff 288 Jul 24 13:44 .. dr-xr-xr-x 16 ikorolev staff 512 Jul 24 13:18 [email protected] dr-xr-xr-x 21 ikorolev staff 672 Jul 24 13:17 [email protected] dr-xr-xr-x 22 ikorolev staff 704 Jul 24 13:06 [email protected] 042
  29. go get 043 # или просто 'go get') go get

    github.com/gorilla/mux@latest # зафиксирует v1.6.2 в go.mod go get github.com/gorilla/[email protected] # тоже зафиксирует v1.6.2 go get github.com/gorilla/mux@e3702bed2 # запишет v1.6.3-0.20180517173623-c85619274f5d go get github.com/gorilla/mux@c856192 # запишет v1.6.3-0.20180903154305-9e1f5955c0d2 go get github.com/gorilla/mux@master
  30. Как релизить v2, v3...? 044 Указать в go.mod новую версию

    module github.com/utrack/clay/v2 
 • master + версия в go.mod • Бранч v2 (поддержка нескольких версий сразу) • Директория /v2
  31. go get (v2+) 046 $ go get github.com/utrack/clay/v2 go: finding

    github.com/utrack/clay/v2 v2.2.6 ... $ go get github.com/utrack/[email protected] go: finding github.com/utrack/clay v2.2.6 go: github.com/utrack/ [email protected]: go.mod has post- v0 module path "github.com/utrack/clay/v2" at revision 0c2090de4d77 go: error loading module requirements
  32. go get (v2+) 047 $ go get github.com/utrack/clay/v2 go: finding

    github.com/utrack/clay/v2 v2.2.6 ... $ go get github.com/utrack/[email protected] go: finding github.com/utrack/clay v2.2.6 go: github.com/utrack/ [email protected]: go.mod has post- v0 module path "github.com/utrack/clay/v2" at revision 0c2090de4d77 go: error loading module requirements $ go get github.com/utrack/clay/[email protected]
  33. А в старых проектах? 048 import "github.com/go-chi/chi/v3" - сломает клиентов

    со старыми версиями go... go1.9.7 go1.10.3 And don't forget to suffer :)
  34. go get (старые проекты v2+) 049 $ go get github.com/go-chi/chi

    go: finding github.com/go-chi/chi v3.3.3+incompatible go: downloading github.com/go-chi/chi v3.3.3+incompatible $ go get github.com/go-chi/[email protected] go: finding github.com/go-chi/chi v3.3.0 go: downloading github.com/go-chi/chi v3.3.0+incompatible
  35. go install, go build/run 050 $ go install github.com/utrack/clay/v2/cmd/protoc-gen- goclay

    Работает с go.mod - установит нужную версию Не умеет в @<version> $ go build -mod=vendor . Соберёт бинарь, используя ./vendor $ go build -mod=readonly . Упадёт, если go.mod должен быть изменён в процессе
  36. go mod 051 $ go mod init # создаст go.mod,

    подтянув зависимости из ваших манифестов glide, dep и пр. (проблема с replace - #24087) $ go mod tidy -v # обновит go.mod $ go mod vendor # заполнит vendor $ go mod verify # сверит кеш модулей с go.sum $ go mod graph # полный граф зависимостей $ go mod graph | grep github.com/gogo/protobuf gitlab.ozon.ru/map/fleet github.com/gogo/[email protected] github.com/utrack/clay/[email protected] github.com/gogo/[email protected] gitlab.ozon.ru/map/types/[email protected] github.com/gogo/[email protected]
  37. go mod 052 $ go mod edit # редактирование go.mod

    (для роботов) -module - поменять имя модуля -require=path@version и -droprequire=path -exclude=path@version и -dropexclude=path@version -replace=old[@v]=new[@v] и -dropreplace=old[@v] -json - печатает текущий go.mod в json -fmt -print
  38. go mod 053 $ go mod why [-m] [-vendor] packages...

    Выводит список пакетов (путь по графу зависимостей), до использования пакета (или пакетов модуля) $ go mod why -m github.com/mwf/vgo-modules/a # github.com/mwf/vgo-modules/a github.com/mwf/vgo-modules/c_user github.com/mwf/vgo-modules/c github.com/mwf/vgo-modules/a
  39. go list 054 $ go list -m all # build

    list github.com/mwf/vgo-modules github.com/mwf/vgo-modules/a v0.0.1 github.com/mwf/vgo-modules/b v0.0.1 $ go list -m -versions github.com/gorilla/mux github.com/gorilla/mux v1.2.0 v1.3.0 v1.4.0 v1.5.0 v1.6.0 v1.6.1 v1.6.2
  40. go list - обновление зависимостей 055 $ go get github.com/go-chi/[email protected]

    $ go list -m -u all example.com/test github.com/go-chi/chi v3.2.0+incompatible [v3.3.3+incompatible] $ go get -u github.com/go-chi/chi go: downloading github.com/go-chi/chi v3.3.3+incompatible Есть go get -u=patch, работает только при наличии go.mod у зависимости ¯\_(ツ)_/¯
  41. go test 056 $ go test ./... # как и

    раньше $ go test all # запуск тестов всех зависимостей Внимание, all включает тесты стандартной библиотеки! #26317 cmd/go: exclude standard library from "all" pattern in modules go test $(go list -f "{{if not .Standard}}{{.ImportPath}}{{end}}" $(go list -f '{{ join .Deps "\n"}}' $(go list -m)/...) $(go list -m)/...)
  42. Вложенные модули 057 ├── cmd/ │ ├── main.go # Точка

    входа в приложение │ ├── go.mod # Зависимости бинаря │ ├── <пакеты библиотеки> ├── go.mod # Зависимости библиотеки
  43. Вложенные модули 059 ├── example/ │ ├── ... │ ├──

    go.mod ├── go.mod # Основные зависимости module example.com/lib/example require example.com/lib replace example.com/lib => ../
  44. Вложенные модули 060 https://github.com/heptiolabs/healthcheck Liveness и Readiness хэндлеры для k8s

    ├─ checker/ │ ├─ db/ │ │ ├─ postgres/ # go.mod │ │ ├─ mysql/ # go.mod │ ├─ kafka/ # go.mod ├─ metrics/ # go.mod ├─ handler.go ├─ go.mod
  45. Зависимости в Go • Как это было? • Minimal Version

    Selection • Текущий статус • Примеры работы с зависимостями • Подводные камни 061
  46. go run vs go build 062 https://github.com/golang/go/issues/26483 $ cd `mktemp

    -d` $ curl -sS https://swtch.com/hello.go >hello.go $ go mod -init -module=example.com/test $ go run hello.go $ cat go.mod module example.com/test require rsc.io/quote v1.5.2 // indirect
  47. Откат обновления зависимостей 064 #26481 - cmd/go: downgrading a module

    with `go get` retains indirect dependencies С 0.1 -> A 0.1 C 0.2 -> A 0.2 (bug) $ go list -m all github.com/mwf/vgo-modules/c_user github.com/mwf/vgo-modules/a v0.1.0 github.com/mwf/vgo-modules/c v0.1.0
  48. Откат обновления зависимостей 065 main -> C 0.1 - хотим

    обновить до 0.2 go get github.com/mwf/vgo-modules/[email protected] $ go list -m all github.com/mwf/vgo-modules/c_user github.com/mwf/vgo-modules/a v0.2.0 github.com/mwf/vgo-modules/c v0.2.0
  49. Откат обновления зависимостей 066 go test -> fail -> откат

    go get github.com/mwf/vgo-modules/[email protected] module github.com/mwf/vgo-modules/c_user require ( github.com/mwf/vgo-modules/a v0.2.0 // indirect github.com/mwf/vgo-modules/c v0.1.0 )
  50. Важные issue 069 • #24250 cmd/go: allow installing programs (at

    specific versions) to GOBIN • #25922 cmd/go: clarify best practice for tool dependencies • #25873 cmd/go: allow forcing tags on/off during go mod vendor, tidy • #26404 cmd/go: export module information for binaries programmatically
  51. Итоги 070 Скорость работы Воспроизводимость сборок (high-fidelity builds) Можно использовать

    v1, v2... одновременно Подмодули - гибкое управление зависимостями - Боль с установкой бинарей