Иногда бывает нужно запустить рабочие программы так, чтобы отделить их от ОС (не устанавливать поверх системы, использовать другие библиотеки, сформировать portable пакет и т.д.).
Например, защитить от нежелательного обновления, или наоборот, потестировать обновление перед тем как применить его в работу.

Простейшее решение - устанавливать и запускать их внутри контейнера docker.

docker run -ti \
  --name test \
  debian

и устанавливай что хочешь.
Если контейнер будет многоразовый - полезно сразу добавить в него скрипт инициализации, например так:

docker run -ti \
  --name test \
  debian \
  /etc/startup

После создания контейнер не запустится, потому что скрипта /etc/startup нет. Его можно добавить, хотя бы минимальный:

#!/bin/sh

/bin/bash
chmod 700 startup
docker cp startup test:/etc/startup
docker start test

В работающий контейнер можно зайти рутом, и подготовить всё к установке:

docker exec -ti  test /bin/bash
apt update
apt upgrade
apt install ...

Так как запускать прикладные программы от рута - не самая лучшая идея, лучше создать отдельного юзера, и работать под ним:

apt install adduser
adduser myuser
su -l myuser

В этом случае пользователь входит так, как если бы выполнялся нормальный логин в систему, с обработкой всяких там .profile
Можно сразу логиниться в контейнер юзером:

docker exec -ti  test su -l myuser

Есть похожий способ, но это не логин в систему, это просто запуск конкретной программы под конкретным пользователем.
Это другое, переменные окружения юзера не устанавливаются:

docker exec -ti --user myuser test /bin/bash

В любом случае - это консольный вход. Текстовый редактор, работа с файлами, скрипты, обработка данных - вполне удобно.
Но в случае с графическими программами есть две дополнительные сложности:

Во-первых, нужен графический режим. Это не очень сложно, потому что X Window System изначально разработана с возможностью работы через сеть или через UNIX-socket.
Но во-вторых, некоторые программы требуют еще и работу с чем-то типа MESA/OpenGL.

Для проброса Иксов будем использовать UNIX-socket, часто он находится как /tmp/.X11-unix/X0
Для этого при создании контейнера добавим проброс файла:

docker run -ti \
 -v /tmp/.X11-unix:/tmp/.X11-unix  \
  --name test \
  debian \
  /etc/startup

В типовом случае, если вы единственный пользователь на компьютере, и программы запускаются под единственным пользователем в контейнере - скорее всего будет достаточно просто указать переменную DISPLAY и запустить программу:

su -l myuser
export DISPLAY=:0
progname

Удобнее просто добавить "export DISPLAY=:0" в .profile, именно поэтому и используется вход через su -l myuser.

Пояснение, почему так:
X-сервер на хосте проверяет подключение через сокет по списку разрешений.
Посмотреть текущий список на хосте можно так:

xhost
access control enabled, only authorized clients can connect
SI:localuser:myuser

В данном случае доступ разрешен локальному юзеру myuser, причем юзер тут определяется по UID соответствующему UID myuser в таблице пользователей.

Что это значит:
Если в контейнере создать нового пользователя с UID, соответствующим UID пользователя myuser хоста - у него будет доступ к X-серверу.
Имя пользователя роли не играет, хоть lopata - лишь бы UID совпадал.

Но кроме того, права на файл UNIX-сокета обычно также выдаются на текущего юзера хоста:

ls -l /tmp/.X11-unix/X0
srwxr-xr-x 1 myuser myuser 0 Mar  15 17:31 /tmp/.X11-unix/X0

То есть, кроме списка авторизации проверяются обычные права на файл.
Поскольку права также привязаны на UID/GID - для доступа к сокету в этом случае у пользователя в контейнере должен быть такой же UID как у пользователя myuser хоста.

Как правило, первый пользовательский UID - 1000, поэтому по умолчанию всё работает, так как UID и там и там совпадает.
Но если на хосте или в контейнере почему-то несколько пользователей, то для того чтобы дать возможность работать с графикой им всем - нужно внести их в списки разрешенных и дать нужные права на сокет.
Для этого на хосте выполнить команду:

xhost +local:
или
xhost +SI:localuser:other_user

(причем other_user должен существовать на хосте, с таким же UID, который будет у нужного юзера внутри контейнера).
А права на сокет поменять либо на "доступ для всех":

chmod 777 /tmp/.X11-unix/X0

либо на "доступ для группы" и внести нужного пользователя в группу, владеющую сокетом

ls -l /tmp/.X11-unix/X0
srwxr-xr-x 1 myuser myuser 0 Mar  6 17:31 /tmp/.X11-unix/X0
chmod 775 /tmp/.X11-unix/X0
usermod -a -G myuser other_user

и сделать это можно прямо внутри контейнера.
Причем есть нюанс: сокет может пересоздаваться при рестарте хоста, соответственно права на него будут возвращаться к первоначальному состоянию, именно поэтому может пригодиться скрипт /etc/startup:

#!/bin/sh

chmod 775 /tmp/.X11-unix/X0

/bin/bash

Но это только обычные Иксы, без аппаратного ускорения. Для работы графических ускорителей нужно подключить устройство, которое за это отвечает.
Оно может находиться в системе примерно тут:

ls -l /dev/dri
total 0
drwxr-xr-x 2 root root        100      Mar  15 16:17 by-path
crw-rw---- 1 root video  226,   0     Mar  15 16:17 card0
crw-rw---- 1 root video  226,   1     Mar  15 16:17 card1
crw-rw---- 1 root render 226, 128 Mar  15 16:17 renderD128

Кроме того, может потребоваться доступ к shared memory. Чтобы всё это сделать - изменяем скрипт создания контейнера:

docker run -ti \
  --device /dev/dri \
  --ipc host \
  -v /tmp/.X11-unix:/tmp/.X11-unix  \
  --name test \
  debian \
  /etc/startup

Но прежде чем можно будет этим пользоваться - нужно проверить доступы внутри контейнера:

ls -l /dev/dri
total 0
drwxr-xr-x 2 root root           100 Mar  15 16:17 by-path
crw-rw---- 1 root video  226,     0 Mar  15 16:17 card0
crw-rw---- 1 root video  226,     1 Mar  15 16:17 card1
crw-rw---- 1 root 105    226, 128  Mar  15 16:17 renderD128

Например, тут можно видеть, что группа video распозналась, т.к. она есть в системе контейнера, а группа с GID 105 - не распознана.
Значит, ее надо создать (возьмем то же имя render, но это непринципиально):

groupadd -a 105 render
ls -l /dev/dri
total 0
drwxr-xr-x 2 root root             100 Mar  15 16:17 by-path
crw-rw---- 1 root video  226,       0 Mar  15 16:17 card0
crw-rw---- 1 root video  226,       1 Mar  15 16:17 card1
crw-rw---- 1 root render 226, 128 Mar  15 16:17 renderD128

Теперь остается включить нужного пользователя в группы video и render:

usermod -a -G video myuser
usermod -a -G render myuser

Теперь, если приложение корректно установить внутри контейнера - оно будет работать в том числе и с 3D-ускорителем (если конечно он есть).
Итак, оно запускается, работает, но работает почти как в виртуальной машине, в своей изолированной файловой системе.

А что, если нужно обмениваться документами с хостом? Перекидывать их по сети неудобно, поэтому нужно добавить разделяемый каталог, еще немного усложнив создание контейнера:

docker run -ti \
  --device /dev/dri \
  --ipc host \
  -v /tmp/.X11-unix:/tmp/.X11-unix  \
  -v /home/myuser/shared:/shared \
  --name test \
  debian \
  /etc/startup

Вот теперь программы на хосте и в контейнере работают с одним и тем же каталогом shared.

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

#!/bin/sh

docker exec -ti test su -l myuser

или запускать окно терминала примерно так:

xterm -e 'docker exec -ti test su -l myuser'

тогда окно терминала будет сразу открываться в контексте контейнера.

Настроенный контейнер с установленными программами можно сохранить, на случай переноса на другую машину или для восстановления:

docker commit test test_image
docker save test_image | gzip > test_image.gz

Ненужный больше контейнер можно удалить:

docker stop test
docker rm test

При этом удаляются все зависимости и изменения в ОС внутри контейнера.

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