Недавно мы приступили к интересной задаче, которая выведет Geektrust на новый уровень. Стремясь ускорить обратную связь с разработчиками при отправке их кода, мы хотели автоматизировать проверку ввода / вывода для всего набора проблем. Пока у нас была только одна проблема - тоже меньшая - которая могла быть оценена автоматически.

Идея высокого уровня состоит в том, чтобы получить код кандидата внутри контейнера докера и выполнить его. Этот докер-контейнер создан для языка программирования, на котором она решила проблему. Когда контейнер будет создан, будет запущен исполняемый файл для проверки ввода и вывода кода кандидата. Исполняемый файл будет запускать код кандидата, используя команду выполнения для конкретного языка. Например, для Python это может быть python main.py

Для этого нам нужно создать образы Docker. Эти образы будут иметь среду выполнения для каждого языка, на котором кандидат представит код. Таким образом, будет образ Docker для Java 1.8, другой для Java 1.11, один для Ruby 2 и т. Д. Эти файлы докеров предопределены. Но код, который выполняет код кандидатов внутри контейнера, недоступен как его часть. Это связано с тем, что он поставляется в виде исполняемого файла Go. Мы не хотим создавать это каждый раз и регистрировать его вместе с Dockerfile в репозитории git.

Поэтому вместо того, чтобы делать docker build -t build_name ., мы создаем образ программно, используя Go client для Docker’s Engine API.

Контекст сборки Docker

Прежде чем мы перейдем к программному созданию образа, важно понять, что такое контекст сборки Docker.

Контекст сборки Docker - это, по сути, исходный каталог, из которого вы выполняете сборки Docker. Для данного Dockerfile

исходный каталог будет выглядеть так

.
├── Dockerfile
├── test.env
└── test.exe

Этот Dockerfile создаст образ из базового образа Alpine Linux. При запуске программа test.exe будет выполняться внутри контейнера.

Шаг COPY ./test.exe ./ копирует исполняемый файл test.exe с хост-компьютера в рабочий каталог созданного образа Docker. Все файлы, которые вам нужны внутри контейнера, должны находиться в контексте сборки Docker до того, как вы создадите образ.

Создание образа

Есть разные способы создания образа Docker. Традиционным способом является сборка из исходного каталога (docker build -t tag.). Мы также можем создать образ из файла TAR. В этом случае мы передаем TAR-файл, содержащий контекст сборки Docker, команде docker build. Таким образом мы программно создаем образ Docker.

Шаги по созданию образа в нашем случае следующие.

  1. Клонируйте репозиторий с Dockerfile во временную папку.
  2. Загрузите и скопируйте предварительно созданный exe-файл во временную папку, созданную на предыдущем шаге.
  3. Создайте tar-файл контекста сборки Docker из временной папки.
  4. Создайте образ с помощью Docker Engine API, используя созданный нами tar-файл.

Код для шага 4 приведен ниже.

В приведенном выше коде BuildImage принимает расположение исходного каталога Docker и tagName. Экземпляр context создается с таймаутом в 5 минут. dockerFileTarReader, err := tarDirectory(dockerBuildCtxDir) преобразует каталог в файл Tar типа io.Reader. Вы можете использовать архиватор Мэтта Холта в Go для создания tar. После создания tar-файла мы передаем его ImageBuild api экземпляра клиента Docker. Этот клиентский экземпляр может быть создан из клиентской библиотеки Go для Docker Engine API.

resp, err := cli.ImageBuild(
  ctx,
  dockerFileTarReader,
  types.ImageBuildOptions{
   Dockerfile: "Dockerfile",
   Tags:       []string{tagName},
   NoCache:    true,
   Remove:     true,
   BuildArgs:  buildArgs,
  })//cli is the docker client instance created from the engine-api

ImageBuildOptions принимают параметры, необходимые для сборки Docker. Это структура Go для параметров сборки в команде docker build. NoCache гарантирует, что кеш игнорируется при каждом запуске сборки Docker. Tags добавляет теги, которые вы хотите присвоить сборке. Remove гарантирует, что созданные промежуточные контейнеры будут удалены после успешной сборки.

Возвращенный ответ имеет Body типа io.ReadCloser, который затем можно прочитать для журналов. Эти журналы точно такие же, когда вы запускаете сборку докеров из командной строки.

После успешного возврата вызова BuildImage мы программно создали образ докера.

Вы можете подключить этот код везде, где хотите создавать такие образы докеров на лету. Вы можете проверить доступность образа с помощью команды docker images на хост-машине. Вы также можете сделать docker run <image_name>, чтобы создать и запустить контейнер.

[Об авторе - Дхануш - соучредитель и технический директор Geektrust.

Geektrust создан для того, чтобы технологи могли найти замечательные вакансии.]

Присоединяйтесь к нашему сообществу Slack и читайте наши еженедельные темы о Фавнах ⬇

Если этот пост был полезен, пожалуйста, несколько раз нажмите кнопку хлопка 👏 ниже, чтобы выразить поддержку автору! ⬇