Вопрос или проблема
У меня есть REST API, написанный на Python, который по запросу запускает исполняемый файл, написанный на C++. Этот C++ код действительно является основным компонентом, но он может быть скомпилирован и использован только на Windows. Однако недавно возникла необходимость развернуть этот API на машине Linux.
Конечно, идея в том, чтобы развернуть его внутри Docker-контейнера. Чтобы иметь возможность запускать Windows-исполняемый файл в Linux-среде внутри него, мне нужен Wine.
В итоге, вот как выглядит мой Dockerfile:
FROM python:3.12-alpine AS build
COPY ./api/requirements.txt requirements.txt
COPY ./api/main.py /app/main.py
COPY ./api/api.conf /app/api.conf
COPY ./api/lms/ /app/lms/
COPY ./api/bin/ /app/bin/
RUN apk add python3-dev build-base linux-headers pcre-dev
RUN pip install --upgrade pip && pip install --user -r requirements.txt
FROM python:3.12-alpine AS release
# Установка необходимых пакетов для Wine
RUN apk add pcre-dev wine gnutls
# Загрузка winetricks
RUN wget -nv -O /usr/local/bin/winetricks https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks
RUN chmod +x /usr/local/bin/winetricks
RUN addgroup -S app \
&& adduser -S app -G app
COPY --from=build /root/.local /home/app/.local
COPY --from=build /app /home/app
RUN chown app:app -R /home/app
USER app
# Настройка Wine префикса
ENV WINEPREFIX=/home/app/.demo
ENV WINEARCH=win64
RUN winecfg
WORKDIR /home/app
ENV PATH=/home/app/.local/bin:$PATH
EXPOSE 80
CMD ["uwsgi", "--socket", "0.0.0.0:80", "--protocol=http", "-w", "main:app"]
Проблема в том, что когда я запускаю контейнер Docker, созданный из этого Dockerfile на нашей машине Red Hat Enterprise Linux 9.2, он работает 4-5 часов, прежде чем машина зависает и перестает отвечать. Единственным решением является ручной сброс. У нас есть несколько других контейнеров Docker, постоянно работающих на той же машине без проблем.
Проблема не возникает при использовании привилегированного пользователя внутри контейнера (т.е. я не создаю пользователя app
и не использую его). Однако не рекомендуется запускать программное обеспечение от имени пользователя root внутри контейнеров Docker по соображениям безопасности.
То же самое изображение работает без проблем на моем ноутбуке внутри WSL (как в среде Ubuntu, так и в Rocky Linux) и на других ноутбуках.
Кроме того, хост также зависает при запуске простого исполняемого файла, который просто выводит “Hello World!” без всего нашего кода Python API и любой “сложной” логики, имеющейся у нас в противном случае.
Я пробовал мониторинг ресурсов с помощью htop
, но нет никаких признаков перегрузки ни RAM, ни процессора, что привело бы к сбою. Кроме того, если бы это было из-за ресурсов, я предполагаю, что он также не работал бы успешно при использовании пользователя root
.
В контейнере ничего не монтируется (т.е. -v
не используется с docker run
), поэтому теоретически этот контейнер не должен влиять на хост-машину, но он влияет.
Кто-нибудь еще сталкивался с подобным поведением и как вы это решили?
P.S. Версия Docker 27.4.1, build b9d17ea
Ответ или решение
Проблема, с которой вы столкнулись, указывает на весьма специфическую ситуацию, когда контейнер Docker с Wine вызывает зависание хоста на Red Hat Enterprise Linux 9.2. Такая проблема довольно редка, и требует комплексного подхода для её решения, основываясь на лучших практиках и техническом анализе.
Теория
Docker предоставляет легковесную виртуализацию на уровне операционной системы, позволяя приложениям работать в изолированных контейнерах. Однако, применение Wine в Docker для запуска Windows-приложений в Linux окружении может вызвать нестандартные проблемы. Wine — это неэмулятор, а совместимая с Windows среда выполнения для операционных систем на базе Unix, такой как Linux. Когда возникает проблема, что хост зависает при запуске подобных контейнеров, особенно если использование низких системных ресурсов не является причиной, необходимо рассмотреть несколько моментов.
-
Изоляция и права доступа: Контейнеры Docker по умолчанию работают с меньшими привилегиями, чем традиционные виртуальные машины. Однако запуск от имени root, по видимому, решает вашу проблему, что может указывать на проблему с правами доступа или особенностями изоляции.
-
Комплексное взаимодействие Wine и системы: Wine, в отличие от многих нативных Linux приложений, может обладать необычными системными требованиями. Его взаимодействие с системой хост может быть сложным, что особенно касается использования системных ресурсов и межпроцессных взаимодействий.
-
Версии и совместимость: Версия Docker, версия Wine и компоненты окружения Linux могут иметь несовместимости, которые выражаются в нестабильности работы.
Пример
Рассмотрим подобный случай: компания разворачивала Windows-приложения на базе .NET в контейнерах Docker с использованием Wine. На этапе тестирования в виртуальных средах не возникало проблем, однако на продакшен-серверах приложения начинали тормозить и замедлять работу всей системы по причине конфликта Wine с системными библиотеками linux-гипервизора.
Применение
Для решения вашей проблемы вам следует предпринять следующие шаги:
-
Обновление и совместимость компонентов системы:
- Проверьте, чтобы все компоненты, включая Docker и Wine, были последней стабильной версии. Это может поправить существующие баги и обеспечить лучшую совместимость.
- Если возможно, проверьте совместимость Wine с используемыми библиотеками вашего C++ приложения.
-
Анализ прав доступа:
- Использование root эффектыно преодолевает проблему, но это не идеальное решение. Проверьте, какие именно системные вызовы или подсистемы Wine требует от имени root и попытайтесь создать логику, ограничивающую эти требования.
- Проверьте SELinux (если он включен), так как он может ограничивать работу контейнера.
-
Тестирование и логирование:
- Развертывайте отдельные контейнеры только с частью вашего функционала для изолирования проблемы (например, только Wine и простое приложение).
- Усильте логирование: пропишите более детальные логи wine и просмотрите логи хоста на предмет необычных действий.
-
Альтернативные решения:
- Можно рассмотреть использование более совершенных решений, таких как CrossOver или Bottles, которые часто предлагают больший уровень поддержки для запусков Windows приложений в Linux.
- Исследуйте возможность использования Windows контейнеров через Windows Subsystem for Linux (WSL) с интеграцией в Docker на более поздние версии для Red Hat.
Эти практические советы помогут вам понять, какие точно взаимодействия между Wine и вашим окружением вызывают зависание и что нужно изменить или адаптировать для обеспечения стабильной работы Docker-контейнера на машине с Red Hat. Надеюсь, что данные рекомендации и анализ проблемы помогут исправить вашу ситуацию.