Google Cloud Container Builder — сборка контейнера Docker из исходного кода Go с зависимостями от поставщиков

Фон

Связанный вопрос: Google Container Builder: как установить govendor зависимости на этапе сборки?

Я пытаюсь использовать Google Cloud Container Builder для автоматизации создания контейнеров Docker с помощью триггеров сборки.

Мой код находится в Go, и у меня есть папка vendor (зарегистрированная в Git) в корне моего проекта, которая содержит все мои зависимости Go.

В моем проекте есть четыре двоичных файла, которые необходимо докеризовать, и они структурированы следующим образом:

vendor/
   ...
program1/
    program1.go
    main/
        main.go
        Dockerfile
program2/
    program2.go
    main/
        main.go
        Dockerfile
...

Dockerfile каждой программы прост:

FROM alpine
ADD main main
ENTRYPOINT ["/main"]

У меня есть триггер сборки, настроенный для отслеживания моей ветки master. Триггер запускает следующий запрос на сборку (cloudbuild.yaml), в котором используется этап сборки Docker с открытым исходным кодом:

steps:
- name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'gcr.io/$PROJECT_ID/program1:0.1.15-$SHORT_SHA', '.']
  dir: 'program1/main'

  ... (repeated for each program)
  (images, tags omitted)

Подводя итог, мой текущий процесс сборки выглядит следующим образом:

  1. Изменить код.
  2. Соберите каждый исполняемый файл Go, используя go build. Исполняемый файл называется main и сохраняется в каталоге programX/main/ вместе с main.go.
  3. Зафиксируйте и отправьте код (поскольку исполняемые файлы main отслеживаются Git) в мою основную ветку.
  4. Build Trigger создает четыре образа Docker, используя файл main, созданный на шаге 1.

Цель

Я хотел бы исключить Шаг 1 из моего процесса сборки, чтобы мне больше не нужно было компилировать мои исполняемые файлы локально и не нужно было отслеживать мои исполняемые файлы main в Git.

В общем, вот мой идеальный процесс:

  1. Отредактируйте код, зафиксируйте, отправьте на удаленный сервер.
  2. Build Trigger компилирует все четыре программы, собирает все четыре образа.
  3. Расслабляться :)

Попытка решения

Я использовал шаг сборки с открытым исходным кодом следующим образом:

cloudbuild.yaml: (обновлено)

steps:
- id: 'build-program1'
  name: 'gcr.io/cloud-builders/go'
  args: ['build', '-a', '-installsuffix', 'cgo', '-ldflags', '''-w''', '-o', 'main', './main.go']
  env: ['PROJECT_ROOT=/workspace', 'CGO_ENABLED=0', 'GOOS=linux']
  dir: 'program1/main'
- name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'gcr.io/$PROJECT_ID/program1:0.1.15-$SHORT_SHA', '.']
  dir: 'program1/main'
  waitFor: ['build-program1']

  ... (repeated for each program)
  (images, tags omitted)

Попробовав различные комбинации настроек PROJECT_ROOT и GOPATH в поле env build-programX, я продолжал получать одну и ту же ошибку для каждого отдельного пакета, используемого в моем проекте (путь к файлу варьируется):

cannot find package "github.com/acoshift/go-firebase-admin" in any of
Step #0 - "build-program1": /usr/local/go/src/github.com/acoshift/go-firebase-admin (from $GOROOT) 
Step #0 - "build-program1": /workspace/auth/main/gopath/src/github.com/acoshift/go-firebase-admin (from $GOPATH)

Он даже не ищет каталог поставщиков?

Что дальше?

Я предполагаю, что верно одно из следующего:

  1. Я неправильно указываю GOPATH/PROJECT_ROOT в файле запроса на сборку. Но если да, то какова правильная настройка?
  2. Мой проект неправильно структурирован.
  3. То, что я пытаюсь сделать, невозможно :(*
  4. Мне нужно каким-то образом сделать пользовательский шаг сборки.
  5. Используемая версия Go устарела — но как это проверить?

Я не могу найти в Интернете примеры того, чего я пытаюсь достичь, и я считаю, что документации GCP по этому вопросу совершенно не хватает.

Любая помощь будет принята с благодарностью!




Ответы (2)


Проблема с № 1: PROJECT_ROOT относится к желаемому пути импорта ваших двоичных файлов. Например, если в program1/main/main.go вы импортируете "github.com/foo/bar/program1", чтобы получить пакет, определенный в program1/program1.go, вы должны установить PROJECT_ROOT=github.com/foo/bar.

person John Asmuth    schedule 02.10.2017
comment
Я не понимаю... Я могу установить PROJECT_ROOT только один раз, но в program1/main/main.go я импортирую несколько разных пакетов: my_root/program1, my_root/utils, github.com/golang/glog, чтобы назвать несколько (my_root — это имя общего пакета Go и имя каталога моего исходного кода), поэтому я не уверен, что установить PROJECT_ROOT. - person Ismail Khan; 03.10.2017
comment
Я попытался установить PROJECT_ROOT на: my_root (это должно было сработать, я думаю), my_root/program1, program1, но все привело к одной и той же проблеме. Поскольку my_root не является реальной папкой в ​​моем репозитории Git, может быть, шаг сборки Go не знает о каталоге my_root, что искажает мои пути? - person Ismail Khan; 03.10.2017
comment
(извините за спам, просто продолжайте получать больше информации, чтобы поделиться) Когда я устанавливаю PROJECT_ROOT в my_root, я получаю несколько ошибок, которые выглядят следующим образом: cannot find package "my_root/utils" in any of /usr/local/go/src/my_root/utils (from $GOROOT) /workspace/program1/main/gopath/src/my_root/utils (from $GOPATH) Последний путь к файлу ошибки кажется мне абсурдным... кажется, смотрит внутрь program1/main/! - person Ismail Khan; 03.10.2017
comment
неважно, я поигрался с полем dirs, и теперь оно работает. Спасибо! - person Ismail Khan; 03.10.2017
comment
Как вы обнаружили, если вы установили PROJECT_ROOT, вам нужно запустить шаг gcr.io/cloud-builders/go из каталога, содержащего вещи, непосредственно внутри корня - env ​​var сообщает сборщику, что этот каталог является корнем проекта, и называет его «как угодно». - person John Asmuth; 04.10.2017
comment
@IsmailKhan, не могли бы вы предоставить настройку, которую вы сделали, чтобы избежать ошибки, не могу найти пакет, пожалуйста - person John Balvin Arias; 19.09.2018

Исправлена ​​проблема (но не совсем уверен как...) благодаря этим изменениям:

  1. Установите PROJECT_ROOT в my_root, чтобы код, который я хочу скомпилировать, находился в my_root/program1/main/main.go (спасибо Джону Асмуту за его ответ: https://stackoverflow.com/a/46526875/6905609)
  2. Удалите поле dirs для шага сборки Go.
  3. Установите для флага -o значение ./program1/main/main, а для окончательного аргумента сборки значение ./program1/main/main.go.

Раньше я cd заходил в каталог program1/main на этапе сборки, и по какой-то причине go build искал пакеты в my_root/program1/main вместо my_root. Странный!

person Ismail Khan    schedule 03.10.2017
comment
Подскажите, пожалуйста, какую командную строку вы применяли и где? - person John Balvin Arias; 24.09.2018