Docker: может ли контейнер A вызывать исполняемый файл, расположенный в другом контейнере B?

У меня есть два образа Docker, один из которых содержит pandoc (утилита для преобразования документов из разных форматов во многие форматы), а другой содержащий pdflatex (из texlive, чтобы преобразовать tex файлов в pdf). Моя цель здесь - преобразовать документы из md в pdf.

Я могу запустить каждое изображение отдельно:

# call pandoc inside my-pandoc-image (md -> tex)
docker run --rm \
    -v $(pwd):/pandoc \
    my-pandoc-image \
    pandoc -s test.md -o test.tex

# call pdflatex inside my-texlive-image (tex -> pdf)
docker run --rm \
    -v $(pwd):/texlive \
    my-texlive-image \
    pdflatex test.tex # generates test.pdf

Но на самом деле я хочу вызвать pandoc (из его контейнера) напрямую, чтобы преобразовать md в pdf, например:

docker run --rm \
    -v $(pwd):/pandoc \
    my-pandoc-image \
    pandoc -s test.md --latex-engine pdflatex -o test.pdf

Эта команда не работает здесь, потому что pandoc внутри контейнера пытается вызвать pdflatex (который должен быть в $PATH) для создания pdf, но pdflatex не существует, так как он не установлен в my-pandoc-image.

В моем случае pdflatex устанавливается в образ my-texlive-image.

Итак, из этого примера у меня возникает вопрос: может ли контейнер A вызывать исполняемый файл, расположенный в другом контейнере B?

Я почти уверен, что это возможно, потому что если я установлю pandoc на своем хосте (без pdflatex), я смогу запустить pandoc -s test.md--latex-engine=pdflatex -o test.pdf, просто назвав команду pdflatex псевдонимом:

pdflatex() {
    docker run --rm \
        -v $(pwd):/texlive \
        my-texlive-image \
        pdflatex "$@"
}

Таким образом, когда pdflatex вызывается pandoc, контейнер запускается и выполняет преобразование.

Но при использовании двух контейнеров, как я могу использовать псевдоним команды pdflatex, чтобы имитировать ее существование в контейнере, имеющем только pandoc?

Я взглянул на docker-compose, так как я уже использовал его для связи двух контейнеров (приложение взаимодействует с базой данных). Я даже думал о ssh переходе из контейнера A в контейнер B для вызова команды pdflatex, но это окончательно не правильное решение.

Наконец, я также создал образ, содержащий pandoc + pdflatex (это сработало, потому что два исполняемых файла находились в одном образе), но я действительно хочу сохранить 2 образа отдельно, так как они могут использоваться другими образами независимо друг от друга.

Редактировать :

Аналогичный вопрос представлен здесь, поскольку я понимаю, что предоставленный ответ требует, чтобы Docker должен быть установлен в контейнере A и требует привязки сокета докера (/var/run/docker.sock) между хостом и контейнером A. Я не думаю, что это лучшая практика, это похоже на хак, который может создать проблемы безопасности.


person norbjd    schedule 16.04.2017    source источник
comment
Не напрямую, но вы можете выполнить ssh-подключение из контейнера к другому хосту контейнера с помощью команды docker exec.   -  person Dani    schedule 17.04.2017
comment
Если я правильно понимаю, мне нужно установить ssh-сервер в контейнере B + ssh-клиент в контейнере A? Судя по тому, что я читал, это не лучшая практика (jpetazzo.github.io/2014/06/23/docker-ssh-considered-evil). Может быть, моя архитектура с двумя отдельными контейнерами неверна?   -  person norbjd    schedule 17.04.2017
comment
Вы должны предоставить какую-то службу из pdflatex, чтобы другой контейнер докеров мог использовать эту службу. Служба может быть чем угодно (остальный вызов API,...). Таким образом, оба контейнера независимы и могут работать на любой машине. тоже.   -  person Girdhar Sojitra    schedule 17.04.2017
comment
@GirdharSojitra Я взглянул на CLSI (github.com/sharelatex/clsi-sharelatex), веб-API для компиляции LaTeX, но установка его в контейнере для моих нужд кажется излишней. В более общем смысле (если такого API не существует), я хотел бы знать, как правильно вызывать команду в другом контейнере (для других случаев использования).   -  person norbjd    schedule 17.04.2017


Ответы (1)


Есть несколько решений вашей проблемы, я позволю вам выбрать то, которое подходит вам лучше всего. Они представлены ниже, от самых чистых до самых уродливых (на мой взгляд и в отношении общепринятых передовых практик).

1. Сделайте это услугой

Если вы в конечном итоге будете вызывать его часто, возможно, стоит представить pandoc как (HTTP) API. Некоторые образы уже делают это, например metal3d/pandoc -server (который я уже успешно использовал, но я уверен, что вы можете найти и другие).

В этом случае вы просто запускаете контейнер с помощью pandoc + pdflatex один раз и готово!

2. Используйте наследование изображений!

Создайте 2 изображения: одно только с pandoc, а другое с pandoc + pdflatex, наследуя первое с директивой FROM в Dockerfile.

Это решит ваши проблемы с размером и по-прежнему сможет запускать pandoc без необходимости также получать pdflatex. Затем, если вам нужно вытащить изображение с pdflatex, это будет просто дополнительный слой, а не все изображение.

Вы также можете сделать это по-другому, с базовым изображением pdflatex и другим добавлением к нему pandoc, если вы обнаружите, что часто используете только изображение pdflatex и редко используете изображение pandoc без pdflatex. Вы также можете сделать 3 изображения, pandoc, pdflatex и pdflatex + pandoc, чтобы покрыть все ваши потребности, но тогда у вас будет по крайней мере одно изображение, которое никак не связано с двумя другими (не может наследовать изображение). «детский» образ), что немного усложняет его обслуживание.

3. Клиент Docker в my-pandoc-image + монтирование сокета Docker

Это решение, которое вы упомянули в конце своего поста, и которое, вероятно, является наиболее универсальным и простым решением для вызова других контейнерных команд, не принимая во внимание ваш конкретный вариант использования pandoc + pdflatex.

Просто добавьте клиент Docker в свой образ my-pandoc-image и передайте сокет Docker как том во время выполнения, используя docker run -v /var/run/docker.sock:/var/run/docker.sock. И если вы обеспокоены тем, что не можете заставить pandoc вызывать docker run ... вместо pdflatex напрямую, просто добавьте плохую оболочку с именем pdflatex в /usr/local/bin/, которая будет отвечать за выполнение docker run

4. Используйте Volumes-from, чтобы получить двоичный файл

Этот, вероятно, самый менее чистый, который я представлю здесь. Вы можете попробовать получить либо двоичный файл pandoc в контейнере pdflatex, либо двоичный файл pdflatex в контейнере pandoc, используя --volumes-from, чтобы все было упаковано в собственный образ Docker. Но, честно говоря, это скорее клейкая лента, чем реальное решение.

Вывод

Вы можете выбрать решение, которое наилучшим образом соответствует вашим потребностям, но я бы посоветовал первые 2 и категорически не одобрял последнее.

person Horgix    schedule 18.04.2017
comment
Отличное объяснение! Наконец, я выберу решение 2 (с двумя изображениями: pandoc и pandoc + pdflatex), так как оно самое простое и наиболее адаптированное к моим потребностям. Спасибо ;) - person norbjd; 18.04.2017
comment
Где я могу найти более подробную информацию о решении 3? - person david.perez; 22.01.2019