Как загрузить и запустить контейнер во время выполнения из запущенного модуля
Я работаю над вычислительной средой, которая будет работать на Google Container Engine (Kubernetes).
Желаемое поведение заключается в том, что пользователи будут предоставлять контейнер для выполнения (это пользовательская полезная нагрузка, мы в порядке, поскольку пользователей мало и им доверяют). Пользовательский контейнер будет загружен в реестр заранее.
Когда платформа запускается, она запускает несколько рабочих (каждый из них в стручке, слушает очередь из сельдерея), а главный узел загружает кучу аргументов для передачи рабочим (через celery/rabbitmq).
Когда рабочий бежит, он выполняет 3 вещи (для каждого рабочего элемента):
SET UP
: Работник будет копировать файлы и конфигурации из облачного хранилища Google и других мест. Файлы будут помещены в томе модуля.EXECUTION
: Рабочий должен загрузить пользовательский контейнер из реестра и запустить его. Я тоже хочу запечатлетьstdout
а такжеstderr
из процесса контейнера и, если возможно, добавьте крайний срок (если контейнер не завершил выполнение в течение X секунд, остановите). Пользовательский контейнер будет генерировать свои результаты в виде файлов в каталоге томов.CLEAN UP and REPORTING
Модуль хоста скопирует некоторые артефакты, сгенерированные пользовательским контейнером, обратно в облако Google. Другие результаты будут сообщены частной заявке.
Я хочу, чтобы инфраструктура была невидимой для пользователей (потому что мы не хотим делиться с ними учетными данными и не позволяем им иметь какую-либо логику управления задачами).
Поскольку хост сам является контейнером, мы не нашли хорошего способа добиться этого (вытащить и запустить контейнер в скрипте, запущенном в другом контейнере).
Можно ли этого достичь в Кубернетесе? Есть ли какая-либо документация или проекты, делающие что-то подобное? и есть ли подводные камни с этим подходом?
Спасибо!
1 ответ
Закончилось решение его следующим образом:
Во-первых, я создал job
определяется следующим образом (фрагмент):
apiVersion: batch/v1
kind: Job
metadata:
name: item-001
spec:
template:
metadata:
name: item-xxx
spec:
containers:
- name: worker
image: gcr.io/<something>/worker
volumeMounts:
- mountPath: /var/run/docker.sock
name: docker-socket-mount
- mountPath: /workspace
name: workspace
volumes:
- name: docker-socket-mount
hostPath:
path: /var/run/docker.sock
- name: workspace
hostPath:
path: /home/workspace
Есть 2 крепления, первый docker-socket-mount
монтирует /var/run/docker.sock
в контейнер, так что я могу использовать Docker изнутри, а во-вторых, он монтирует том, который будет разделен между хостом и гостевым контейнером workspace
,
worker
запускает скрипт, похожий на этот:
#!/usr/bin/env bash
IMAGE=gcr.io/some/guest/image
# ...
gsutil -m cp -r gs://some/files/I/need/* /workspace
# ...
export DOCKER_API_VERSION=1.23
gcloud docker -- pull ${IMAGE}
docker run -v /home/workspace:/workspace ${IMAGE}
# ...
Имея док-сокет в наличии, достаточно установить клиент Docker и нормально его вызывать. Хитрость заключалась в том, чтобы смонтировать образ гостя из /home/workspace
как видно из узла kubernetes, а не из образа хоста (/workspace
). Файлы, загруженные в /workspace
теперь также доступны в гостевом контейнере.
Наконец, Dockerfile
выглядит примерно так:
FROM ubuntu:14.04
# ...
# Install Docker
RUN curl -fsSL https://get.docker.com/ | sh
# Install Google Cloud SDK
ADD xxx.json /home/keys/xxx.json
RUN curl https://sdk.cloud.google.com > /tmp/gcloud.sh
RUN bash /tmp/gcloud.sh --disable-prompts --install-dir=/home/tools/
RUN /home/tools/google-cloud-sdk/bin/gcloud auth activate-service-account name@my-project.iam.gserviceaccount.com --key-file=/home/keys/xxx.json
RUN /home/tools/google-cloud-sdk/bin/gcloud config set project my-project
# ...