# Docker Spaces

Spaces поддерживают пользовательские [контейнеры Docker](https://docs.docker.com/get-started/) для приложений, выходящих за рамки Streamlit и Gradio. Docker Spaces позволяют пользователям преодолеть ограничения, которые ранее накладывали стандартные SDK. От эндпоинтов FastAPI и Go до Phoenix-приложений и инструментов ML Ops — Docker Spaces пригодятся во множестве различных конфигураций.

## Настройка Docker Spaces

Выбор **Docker** в качестве SDK при [создании нового Space](https://huggingface.co/new-space) инициализирует ваш Space, задавая свойство `sdk` со значением `docker` в YAML-блоке файла `README.md`. Альтернативно, для существующего репозитория Space установите `sdk: docker` внутри блока `YAML` в начале файла **README.md** вашего Space. Также можно изменить порт по умолчанию `7860`, задав `app_port: 7860`. После этого вы можете создать обычный `Dockerfile`.

```Yaml
---
title: Basic Docker SDK Space
emoji: 🐳
colorFrom: purple
colorTo: gray
sdk: docker
app_port: 7860
---
```

Внутри вы можете открыть столько портов, сколько пожелаете. Например, вы можете установить Elasticsearch внутри вашего Space и обращаться к нему по внутреннему адресу на его порту по умолчанию 9200.

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

## Управление секретами и переменными
 

Вы можете управлять переменными окружения Space в настройках Space. Подробнее — [здесь](./spaces-overview#managing-secrets).

### Переменные

#### Время сборки

Переменные передаются в виде `build-arg` при сборке вашего Docker Space. Полное руководство по их использованию в Dockerfile см. в [документации Docker](https://docs.docker.com/engine/reference/builder/#arg).

```Dockerfile
	# Declare your environment variables with the ARG directive
	ARG MODEL_REPO_NAME

	FROM python:latest
	# [...]
	# You can use them like environment variables
	RUN predict.py $MODEL_REPO_NAME
```

#### Время выполнения

Переменные внедряются в окружение контейнера во время выполнения.

### Секреты

#### Время сборки

В Docker Spaces управление секретами отличается по соображениям безопасности. После создания секрета на вкладке [Settings](./spaces-overview#managing-secrets) вы можете сделать его доступным, добавив следующую строку в ваш Dockerfile:

Например, если `SECRET_EXAMPLE` — это имя секрета, который вы создали на вкладке Settings, вы можете прочитать его во время сборки, смонтировав его в файл, а затем прочитав с помощью `$(cat /run/secrets/SECRET_EXAMPLE)`.

Пример приведён ниже:
```Dockerfile
# Expose the secret SECRET_EXAMPLE at buildtime and use its value as git remote URL
RUN --mount=type=secret,id=SECRET_EXAMPLE,mode=0444,required=true \
 git init && \
 git remote add origin $(cat /run/secrets/SECRET_EXAMPLE)
```

```Dockerfile
# Expose the secret SECRET_EXAMPLE at buildtime and use its value as a Bearer token for a curl request
RUN --mount=type=secret,id=SECRET_EXAMPLE,mode=0444,required=true \
	curl test -H 'Authorization: Bearer $(cat /run/secrets/SECRET_EXAMPLE)'
```

#### Время выполнения

Как и в случае с публичными переменными, во время выполнения к секретам можно обращаться как к переменным окружения. Например, в Python для этого используется `os.environ.get("SECRET_EXAMPLE")`. Ознакомьтесь с этим [примером](https://huggingface.co/spaces/DockerTemplates/secret-example) Docker Space, использующим секреты.

## Права доступа

Контейнер запускается с идентификатором пользователя 1000. Чтобы избежать проблем с правами доступа, создайте пользователя и задайте его `WORKDIR` до любого `COPY` или загрузки.

```Dockerfile
# Set up a new user named "user" with user ID 1000
RUN useradd -m -u 1000 user

# Switch to the "user" user
USER user

# Set home to the user's home directory
ENV HOME=/home/user \
	PATH=/home/user/.local/bin:$PATH

# Set the working directory to the user's home directory
WORKDIR $HOME/app

# Try and run pip command after setting the user with `USER user` to avoid permission issues with Python
RUN pip install --no-cache-dir --upgrade pip

# Copy the current directory contents into the container at $HOME/app setting the owner to the user
COPY --chown=user . $HOME/app

# Download a checkpoint
RUN mkdir content
ADD --chown=user https://<SOME_ASSET_URL> content/<SOME_ASSET_NAME>
```

Всегда указывайте `--chown=user` вместе с `ADD` и `COPY`, чтобы убедиться, что новые файлы принадлежат вашему пользователю.

Если проблемы с правами доступа сохраняются, возможно, вам потребуется использовать `chmod` или `chown` в вашем `Dockerfile`, чтобы предоставить необходимые права. Например, если вы хотите использовать каталог `/data`, вы можете сделать следующее:

```Dockerfile
RUN mkdir -p /data
RUN chmod 777 /data
```

Всегда следует избегать лишних вызовов chown.
> [!WARNING]
> Обновление метаданных файла создаёт новую копию, которая сохраняется в новом слое. Поэтому рекурсивный chown может привести к очень большому размеру образа из-за дублирования всех затронутых файлов.

Вместо того чтобы исправлять права доступа с помощью `chown`:
```
COPY checkpoint .
RUN chown -R user checkpoint
```
вы всегда должны делать следующее:
```
COPY --chown=user checkpoint .
```
(то же самое касается команды `ADD`)

## Сохранение данных

Данные, записанные на диск, теряются при каждом перезапуске вашего Docker Space. Чтобы сохранить данные между перезапусками, вы можете подключить [Storage Bucket](./storage-buckets) к вашему Space.

На данный момент том `/data` доступен только во время выполнения, то есть вы не можете использовать `/data` на этапе сборки вашего Dockerfile.

Вы также можете использовать наш Datasets Hub для конкретных случаев, где состояние и данные хранятся в репозитории git LFS. Пример персистентности можно найти [здесь](https://huggingface.co/spaces/Wauplin/space_to_dataset_saver); в нём используется библиотека [`huggingface_hub`](https://huggingface.co/docs/huggingface_hub/index) для программного загрузки файлов в репозиторий датасета. Этот пример Space вместе с [этим руководством](https://huggingface.co/docs/huggingface_hub/main/en/guides/upload#scheduled-uploads) поможет вам определить, какое решение лучше всего подходит для вашего типа данных.

Наконец, в некоторых случаях вы можете захотеть использовать внешнее решение для хранения данных из кода вашего Space, например, внешнюю хостинговую БД, S3 и т. д.

### Контейнер Docker с GPU

Вы можете запускать Docker-контейнеры с поддержкой GPU, используя один из наших вариантов [Spaces Hardware](./spaces-gpus) с GPU.

Мы рекомендуем использовать [`nvidia/cuda`](https://hub.docker.com/r/nvidia/cuda) из Docker Hub в качестве базового образа, в котором уже установлены CUDA и cuDNN.

Во время сборки Docker у вас нет доступа к GPU-оборудованию. Поэтому не пытайтесь выполнять команды, связанные с GPU, на этапе сборки в вашем Dockerfile. Например, вы не можете выполнить `nvidia-smi` или `torch.cuda.is_available()` при сборке образа. Подробнее — [здесь](https://github.com/NVIDIA/nvidia-docker/wiki/nvidia-docker#description).

## Подробнее

- [Полный пример демонстрации Docker](spaces-sdks-docker-first-demo)
- [Список примеров Docker Spaces](spaces-sdks-docker-examples)
- [Примеры Spaces](https://huggingface.co/SpacesExamples)

