Теперь Кью работает в режиме чтения

Мы сохранили весь контент, но добавить что-то новое уже нельзя

Делаем докер образ для разработки

Вступление
В этом руководстве я расскажу о том, как я обычно собираю рабочий докер образ для разработки решения задачи компьютерного зрения. Создаётся он так, чтобы в нём было удобно разрабатывать, отлаживать и исполнять код.
Задачи образа
Полученный образ будет выполнять следующие задачи:
  1. Фиксировать зависимости.
  2. В примонтированные папки к контейнерам этого образа, файлы и папки изнутри контейнера пишутся так, чтобы из хоста с ними можно было работать под своим пользователем.
  3. Вся среда запускалась одной командой.
Конструируем образ
Для начала создадим обязательные файлы в корне проекта:
  1. Dockerfile – докер файл, из которого будет собираться образ.
  2. requirements.txt – файл для задания питоновских зависимостей.
  3. build.sh – файл скрипта сборки докер образа.
  4. run.sh – файл скрипта запуска образа.
requirements.txt
requirements.txt – это обычный requirements файл для pip. Запишем в него питоновские зависимости проекта.
Dockerfile
Теперь напишем наш докер образ.
Для начала нужно задать базовый образ. Как правило, его выбирают так, чтобы он был как можно ближе к тому, что нужно. В нашем случае для примера возьмём простой образ для разработки с CUDA от NVidia:
FROM nvidia/cuda:11.0-cudnn8-devel-ubuntu18.04
Возможно, будет полезно указать информацию о том, кто создал и поддерживает образ (например, себя). Она даст контакт пользователям на случай каких-либо проблем.
MAINTAINER Stepan Kudin <kudin.stepan@yandex.ru>
Питоновские зависимости мы записываем в файл requirements.txt, скопируем его внутрь образа:
COPY requirements.txt /tmp/requirements.txt
В переменные окружения запишем имя пользователя и его группу. Это удобно тем, что можно не копировать одну и ту же информацию по всему файлу.
ENV USER=docker
ENV GROUP=docker
В отдельную переменную окружения запишем абсолютный путь до рабочей папки с проектом внутри контейнера. Так, её будет проще подставлять в пути внутри файла и, если понадобится, будет легко поменять этот путь.
ENV WORKDIR=/app
Включим в PYTHONPATH путь до рабочей папки, чтобы при исполнении питоновского кода внутри контейнера модули искались и в ней (это позволяет делать адресацию до модулей в коде от корня проекта):
ENV PYTHONPATH=$WORKDIR:$PYTHONPATH
Зададим локаль:
ENV LC_ALL=C.UTF-8
С переменными окружения всё. Теперь создадим рабочую папку и назначим её WORKDIR образа:
RUN mkdir $WORKDIR
WORKDIR $WORKDIR
Установим необходимые deb пакеты, в том числе Python 3, pip и зависимости OpenCV (он часто используется в решении задач компьютерного зрения). Стоит обратить внимание на то, что была задана таймзона Etc/UTC, для того чтобы сборка образа не останавливалась на вопросе её выбора.
RUN apt-get update --fix-missing
RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get install -y --no-install-recommends \
        apt-utils \
        libgl1-mesa-glx \
        libglib2.0-0 \
        libgdcm-tools \
        curl \
        git \
        python3 \
        python3-pip \
        python3-setuptools
При желании ненужные пакеты можно убрать. Теперь обновим pip и установим наши питоновские зависимости:
RUN pip3 install -U pip
RUN python3 -m pip install -r /tmp/requirements.txt
Добавим группу и создадим пользователя:
RUN addgroup --gid 1000 $GROUP
RUN adduser --uid 1000 --ingroup docker --home /home/docker --shell /bin/sh --disabled-password --gecos "" $USER
Установим fixuid, он исправит проблемы с правами на файлы на хосте в папках, которые будут примонтированы к контейнеру:
RUN curl -SsL https://github.com/boxboat/fixuid/releases/download/v0.5/fixuid-0.5-linux-amd64.tar.gz | \
        tar -C /usr/local/bin -xzf -
RUN chown root:root /usr/local/bin/fixuid && chmod 4755 /usr/local/bin/fixuid
RUN mkdir -p /etc/fixuid
RUN printf "user: $USER\ngroup: $GROUP\n" > /etc/fixuid/config.yml
Недавно созданного пользователя и группу назначим пользователем и группой в контейнере по умолчанию:
USER $USER:$GROUP
Назначим запуск fixuid в ETRYPOINT:
ENTRYPOINT ["fixuid"]
Всё, описание образа готово.
build.sh
Теперь создадим скрипт сборки образа. В нашем случае он будет совсем не сложный.
#!/usr/bin/env bash

docker build --no-cache --network host -t demo_image:dev -f Dockerfile .
run.sh
Осталось написать скрипт запуска контейнера. Он будет подлиннее скрипта сборки. Что мы в нём делаем:
  1. Узнаём путь текущей директории для её монтирования в создаваемый контейнер.
  2. Узнаём текущие user id и group id.
  3. Задаём объём shared memory, это полезно, потому что лимита по умолчанию частенько не хватает для работы Dataloader из Pytorch.
  4. В аргументы скрипта могут передаваться параметры видимости GPU для контейнера. Если они не передаются, то по умолчанию доступны все.
  5. Сам контейнер запускается в интерактивном режиме с запущенным башем и будет удалён при выходе из него. В него монтируется текущая директория в /app внутри контейнера, передаются uid и gid текущего пользователя для fixuid и новый лимит shared memory.
При необходимости, все параметры запуска можно скопировать в нужную IDE, если она поддерживает отладку внутри докер контейнера, например в PyCharm.
#!/usr/bin/env bash

path=$(pwd)

uid=$(id -u)
gid=$(id -g)
shm_size="16G"

if [[ $1 ]]; then
  gpus=$1
else
  gpus="all"
fi

docker run -it --rm --gpus $gpus -u "$uid":"$gid" --net host --shm-size "$shm_size" \
 --volume "$path":/app:rw  demo_image:dev /bin/bash
Заключение
На этом всё, благодарю за внимание. Надеюсь, это руководство поможет вам в вашей работе. Желаю удачи!
Стоит добавить, что если вы хотите запускать приложения с графическим интерфейсом внутри контейнера, то команда... Читать дальше