This document establishes a method to successfully install a docker application on OMV.
This document is divided into four parts
What is docker?
“ A container is a standard unit of software that packages up code and all its dependencies so the application runs quickly and reliably from one computing environment to another. A Docker container image is a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries and settings.
Container images become containers at runtime and in the case of Docker containers – images become containers when they run on Docker Engine. Available for both Linux and Windows-based applications, containerized software will always run the same, regardless of the infrastructure. Containers isolate software from its environment and ensure that it works uniformly despite differences for instance between development and staging. ”
Or, more briefly, it is a way to install any application on OMV without breaking the system.
That's all very well, but… What the hell is docker? :)
After a while I read this definition again and I don't even understand it, so I'll try to explain it in a simpler way.
Docker is a system that allows you to run an application using the main resources of the system but in such a way that it does not have the capacity to modify (damage) the existing system. The operation is similar to a virtual machine but lighter.
Docker can be run from the command line directly. A single command with the right parameters will do all the work. Docker-compose was developed to make it easy to create that command and those parameters using easy-to-read configuration files. The openmediavault-compose plugin uses docker-compose for container management.
Docker is based on packages (images) that are usually created by a third party and downloaded from a remote repository. Using docker-compose we create a compose file that allows us to configure various parameters to define and create a container from that image. For example, the access ports to the application or the system folders that will be accessible to that container. If we run that compose file it will download the image and create the container following the instructions we have given it.
The author of the image we have downloaded will usually do maintenance and at some point create another updated image, at which point we need to update our container. The way to update a container is to delete it and recreate it again by downloading a new updated image. To recreate it simply run the compose file again after removing the container.
While we use the container, depending on the type of application it is, we will probably modify some files inside it, for example to define an access username and password, or other configurations. If we delete the container without doing anything else we will lose that data. This is what we will call persistent data. We need to keep this persistent data somehow if we want to be able to update this container, remember that to update it we must first delete it.
The way to keep persistent data is resolved in docker by mapping volumes. What we do is define a real folder on our system and “trick” the container into writing to that folder as if it were one of its internal folders. In this way, that folder will collect all that data and it will still be there when we delete the container.
Now yes, we can delete the container, download a new image, recreate the container, and when it starts you can continue to use the persistent data in that folder. Nice!
This procedure aims to use docker-compose through the plugin in a simple and safe way.
We need to define several folders needed for docker-compose, the plugin will help with this.
We will also define a specific user to run the containers under this user.
appdata folder (or whatever you want to call it)
- ./config:/config
the config folder will be created in the subfolder of that container in this case /appdata/jellyfin/config
.- /srv/dev-disk-by-uuid-384444bb-f020-4492-acd2-5997e908f49f/app/jellyfin/config:/config
will cause the files in the config folder of the container to appear in the path /srv/ dev-disk-by-uuid-384444bb-f020-4492-acd2-5997e908f49f/app/jellyfin/config
. You can use openmediavault-symlink to simplify those paths with uuid, docker-compose accepts symlinks just fine.
data folder (or whatever you want to call it)
CHANGE_TO_COMPOSE_DATA_PATH
expression. This will allow easily reusable paths to be set in compose files./data
that contains all our data (it is not necessary to share the folders, it is enough to create them in the OMV GUI). In the compose file we could do this to define the movies folder - CHANGE_TO_COMPOSE_DATA_PATH/media/movies:/movies
and the container will have access to the /movies
folder on our server.
backup_appdata folder (or whatever you want to call it)
docker folder (or whatever you want to call it)
/var/lib/docker
folder inside the OMV operating system drive. The necessary files for docker to work, containers, downloaded images, docker networks, etc. will be generated in this folder. This field allows you to modify the default location of this folder.
Note | |
If you don't want to use a dedicated docker disk you can use any disk formatted preferably in EXT4. Avoid mounting docker folders under mergerfs. If you have installed docker on another hard drive you can delete the contents of the /var/lib/docker folder to recover that space on the system drive. This will not affect how docker works. |
Warning | |
Never use an NTFS file system to host docker folders. NTFS is not native to Linux and will cause file permission issues. |
Beginners Note | |
Except for very controlled special cases, never designate the admin user (UID=998) or the root user (UID=0) to manage a container. This is a serious security flaw. If we do this we are giving the container complete freedom to do whatever it wants in our system. Have you created this container? Do you know what he is capable of doing? |
Global environment variables will be used in the procedure that follows this document.
The plugin allows you to define global environment variables in a file that will be available to all running containers. This means that the variables defined in this file can be used in the different compose files, and when we do so, each variable in the compose file will be replaced by the value that we have defined in the global variable.
This is very useful for defining paths to folders or the user running the container. We define these values once and have them updated automatically in all containers.
Example:
PUID=1000 PGID=100 TZ=Europe/Madrid SSD=/srv/dev-disk-by-uuid-8a3c0a8f-75bb-47b0-bccb-cec13ca5bb85 DATA=/srv/dev-disk-by-uuid-384444bb-f020-4492-acd2-5997e908f49f
--- version: "2.1" services: jellyfin: image: lscr.io/linuxserver/jellyfin:latest container_name: jellyfin environment: - PUID=${PUID} - PGID=${PGID} - TZ=${TZ} volumes: - ${SSD}/app/jellyfin:/config - ${SSD}/app/jellyfin/cache:/cache - ${DATA}/media:/media ports: - 8096:8096 restart: unless-stopped
--- version: "2.1" services: jellyfin: image: lscr.io/linuxserver/jellyfin:latest container_name: jellyfin environment: - PUID=1000 - PGID=100 - TZ=Europe/Madrid volumes: - /srv/dev-disk-by-uuid-8a3c0a8f-75bb-47b0-bccb-cec13ca5bb85/app/jellyfin:/config - /srv/dev-disk-by-uuid-8a3c0a8f-75bb-47b0-bccb-cec13ca5bb85/app/jellyfin/cache:/cache - /srv/dev-disk-by-uuid-384444bb-f020-4492-acd2-5997e908f49f/media:/media ports: - 8096:8096 restart: unless-stopped
The advantage of using this system is that we define the compose file once and never need to modify it. Even if we reinstall the OMV system we just need to update those global variables and all our containers will be up to date and continue to work as before.
For paths you could combine this system with symlinks, if you still need to use symlinks for other reasons. If you don't need it you can skip the use of symbolic links, this system is more than enough for handling containers.
Note | |
At this time, the plug-in backup utility does not resolve variables in volume paths. Define paths using global environment variables only for paths that you do not need to include in a backup. Alternatively you can use symlinks in the compose file. |
Note | |
Folders created in the OMV GUI by default have 775 permissions, the owner is root, and the owner group is users. This way the procedure in this guide will work normally. If for some reason this is not the case on your system, make sure that the appuser user has read and write permissions on these folders. If you need to reset the permissions of a folder to the standard OMV permissions you can use the plugin openmediavault-resetperms. |
Warning | |
A symlink like /SSD/docker may not work here, it is preferable to use the full path. Example: /srv/dev-disk-by-uuid-861acf8c-761a-4b60-9123-3aa98d445f72/docker |
PUID=1000 PGID=100 TZ=Europe/Madrid
--- version: "2.1" services: jellyfin: image: lscr.io/linuxserver/jellyfin:latest container_name: jellyfin environment: - PUID=1000 - PGID=1000 - TZ=Europe/London - JELLYFIN_PublishedServerUrl=192.168.0.5 #optional volumes: - /path/to/library:/config - /path/to/tvseries:/data/tvshows - /path/to/movies:/data/movies ports: - 8096:8096 - 8920:8920 #optional - 7359:7359/udp #optional - 1900:1900/udp #optional restart: unless-stopped
Note | |
Verify on the official page that this stack has not changed before installing it |
/DATA
we have the media folder that contains other subfolders with movies, photos, etc, such as the image structure:
---
version: "2.1"
services:
jellyfin:
image: lscr.io/linuxserver/jellyfin:latest
container_name: jellyfin
environment:
- PUID=${PUID} # See Comment 1
- PGID=${PGID} # See Comment 1
- TZ=${TZ} # See Comment 2
#- JELLYFIN_PublishedServerUrl=192.168.0.5 # See Comment 3
volumes:
- ./config:/config # See Comment 4
- CHANGE_TO_COMPOSE_DATA_PATH/media:/media # See Comment 4
ports:
- 8096:8096 # See Comment 5
restart: unless-stopped
Note | |
Verify on the official page that this stack has not changed before installing it |
cat /etc/timezone
in a terminal.#
at the beginning and replace the IP with the real IP of your server.192.168.1.100
the line would look like this: - JELLYFIN_PublishedServerUrl=192.168.1.100
Note | |
Mapping folders means to "mount" the folder inside the container. The container does not "see" what is on our host. Similarly our host does not "see" what is in the container. In order for the container to see a folder on our host, we have to mount it inside the container. This assembly is done in each line of this section. The colon is used as a separator. To the left of the colon we write the actual path of the folder on our host. On the right we tell the container with what name it will "see" that folder when it is running. |
./config
./
. That means that folder /config
will be mounted on our system in the /jellyfin
subfolder inside the /appdata
folder. The plugin takes care of creating the /jellyfin
folder in this case (within the folder defined in the Settings tab, Compose Files section, that is, /appdata
if you called it that) and that the folders defined as relative paths end up as subfolders within it. That is, /appdata/jellyfin/config
:
:
, the name we want the container to “see” when it writes to that folder, in this case, following the original stack, it must be /config
Note | |
When the container writes to /config what will actually happen on the system is that the user appuser will be writing to /appdata/jellyfin/config This is why the appuser user must have permissions to write to the appdata folder, otherwise the container would not work. There is no need to create the /jellyfin folder, docker will do it for us when starting the container. |
/srv/dev-disk-by-uuid-384444bb-f020-4492-acd2-5997e908f49f/data/media
. We can use that route or take advantage of the facilities that the plugin gives us to define routes.CHANGE_TO_COMPOSE_DATA_PATH
is equivalent in our case to /srv/dev-disk-by-uuid-384444bb-f020-4492-acd2-5997e908f49f/data
DATA=/srv/dev-disk-by-uuid-384444bb-f020-4492-acd2-5997e908f49f
and in the compose file we would write this line - ${DATA}/media:/media
:
/media
Note | |
In the case of jellyfin the libraries are configured from the container, we just need it to be able to see them. That is to say, it is not necessary to map movies on the one hand and photos on the other hand, although we could do it that way too. To make it easier, we map a single volume that contains everything. Later from jellyfin we will search each folder for each library. /media/movies /media/photos etc. |
8096
on both sides of :
8888
, then the separator :
and on the right the one that specifies the original stack 8096
, which is used internally by the container.
Beginners Note | |
This file is of type yaml. Indents are important, don't manipulate them while editing. If you do docker won't be able to interpret the file, the container will give an error and won't start. |
jellyfin
.:
and the access port defined in the previous point.http://192.168.1.100:8096
to access Jellyfin.
If for any reason you need to modify the container configuration, change the location of a volume or any other circumstance, do the following:
If you want to restore the container to its initial state, do the following (This will remove any configuration we have made to the container):
We, who support the openmediavault project, hope that you’ll find your openmediavault server to be
enjoyable, efficient, and easy to use.
If you found this guide to be helpful, please consider a modest donation to support the
hosting costs of this server (OMV-Extras) and the project (Openmediavault).
OMV-Extras.org