Docker
Prerequisites
Before you start, you need to have a VPS. If you don't have a VPS, you can get a free one from Oracle Cloud, which you should have already set up in the previous guide.
I will be explaining, in detail, how docker works as I do not think you should blindly copy templates without understanding what they do. This will help you troubleshoot issues and make changes to the templates as needed. (and hopefully minimise the amount of people asking for help, though I am always happy to help and you can reach out to me on Discord)
If you are already familiar with Docker, you can skip ahead to the installation section.
What is Docker?
Docker is a platform for developing, shipping, and running applications in containers. It allows you to package your application and all its dependencies into a single image that can be run on any machine. This makes it easy to deploy applications in a consistent and reproducible way.
In simple terms, it allows you to run applications in isolated environments called "containers". Each container has its own filesystem, networking, and process space, so you can run multiple containers on the same machine without them interfering with each other.
We use images sourced from registries like Docker Hub to create containers. Images are read-only templates that contain everything needed to run an application, including the code, runtime, libraries, environment variables, and configuration files.
For a more in-depth explanation, you can check the official Docker documentation.
How to use Docker
Docker is controlled using the docker
command-line tool. For more information on the commands available, you can check the Docker CLI reference and/or this Learn X in Y minutes guide.
For this guide, we will be using Docker to run services in containers through Docker Compose and a compose.yaml
file. (Read this guide on YAML Syntax if you are unfamiliar with it.)
A compose.yaml file is a configuration file that defines how to run services in containers. It specifies the services, networks, and volumes needed to run the application and how they interact with each other.
Here is an example of a compose.yaml
file that defines a simple web server service:
services:
myservice1:
image: image1:tag1
container_name: mycontainer1
ports:
- "8080:80"
environment:
- ENV_VAR1=value1
- ENV_VAR2=${SERVICE1_VAR2:-default_value} # optional value that defaults to default_value or an empty string if no default is provided
- ENV_VAR3=${SERVICE1_VAR3?Error message} # required value that throws an error if not set
env_file:
- .custom.env
volumes:
- ./tmp:/tmp
- image-data:/data
labels:
- "mylabel1=myvalue1"
restart: unless-stopped
myservice2:
image: image2:tag2
container_name: mycontainer2
restart: unless-stopped
expose:
- 8080
environment:
ENV_VAR2: value2
volumes:
- ./tmp:/tmp
- /opt/image2:/data
labels:
mylabel2: myvalue2
volumes:
image-data:
In this example, we define two services, myservice1
and myservice2
, each with its own image, ports, environment variables, volumes, labels, and restart policy.
Let me break down the components of the compose.yaml
file:
At the root level, we have the services
key, which is a nested collection of service definitions.
This tells Docker Compose which services to run and how to configure them.
Each service definition has the following keys:
-
image
: The image to use for the service.-
You can use an image from a registry like Docker Hub or a local image. For example, if we wanted to use my image for
AIOStreams
, we would useviren070/aiostreams:latest
. This image is viewable at https://hub.docker.com/r/viren070/aiostreams. -
We can also optionally specify a tag to use with the image. If no tag is specified, Docker will default to
latest
. A tag is a version identifier for an image, typically following semantic versioning. -
Docker Hub is the default registry for Docker images, but you can also use other registries like GitHub Container Registry or Quay e.g. for the image, you would use
ghcr.io/viren070/aiostreams:latest
.tipSometimes, there is no image available for the service you want to run, in that case, you can create your own image using a
Dockerfile
. This can also be a remoteDockerfile
that is hosted on GitHub or GitLab.How to use a remote Dockerfile
services:
myservice:
build:
context: https://github.com/mccoy88f/OMG-Premium-TV.git
dockerfile: Dockerfile
image: myservice:latestIn this example, we are using a
Dockerfile
hosted on GitHub to build the image for themyservice
service. We tell Docker Compose to use theDockerfile
in the root of the repository athttps://github.com/mccoy88f/OMG-Premium-TV.git
to build the image for the service and then name the imagemyservice:latest
.
-
-
container_name
: The name to use for the container.- This is optional, and if not specified, Docker will generate a name for you using the format
<project-name>_<service-name>_<index>
.
- This is optional, and if not specified, Docker will generate a name for you using the format
-
restart
: The restart policy for the container.- This specifies when the container should be restarted. The possible values are
no
,always
,on-failure
,unless-stopped
, andalways
. - By setting the restart policy to
unless-stopped
, the container will be restarted unless it is explicitly stopped by the user.
- This specifies when the container should be restarted. The possible values are
-
environment
: Environment variables to set in the container.- This is a list of key-value pairs or a list of strings in the format
KEY=VALUE
. This gives the container access to environment variables that can be used to configure the application. - However, environment variables can also be used throughout the compose.yaml file using the
${}
syntax. This allows you to reference other environment variables or provide default values. These environment variables are loaded from the.env
file in the current directory and any other system environment variables. - Since $ is a special character in YAML, if we want to use a literal $, we need to escape it with another $, e.g.
$$
.
- This is a list of key-value pairs or a list of strings in the format
-
We can also load environment variables from a file using the
env_file
key. This will load the environment variables from the specified file into the container.
Volumes
Volumes are used to persist data generated by and used by Docker containers. They are directories on the host machine that are mounted into the container. This allows the container to read and write data to the host machine's filesystem.
If we do not use volumes, the data generated by the container will be lost when the container is stopped or removed. If a folder within the container is storing user data, we should use a volume to persist that data, otherwise it will be lost when the container is restarted.
The syntax for defining a volume is, in general, host-path:container-path
. Host path is the path on the host machine, and container path is the path within the container.
There are two types of volumes: named volumes and bind mounts.
Named volumes are managed by Docker and are stored in a specific location on the host machine - /var/lib/docker/volumes
.
Bind mounts are specified by providing the path to a directory on the host machine. This allows you to specify the exact location where the data should be stored.
To use a named volume, you can define it in the volumes
section of the compose.yaml
file.
For example, volumes: image-data:
defines a named volume called image-data
.
We use image-data:/data
to mount the named volume image-data
to the /data
directory within the container.
To use a bind mount, you can specify the host path directly in the volumes
section. Either an absolute path or a relative path can be used.
For example, ./tmp:/tmp
mounts the tmp
directory in the current working directory to the /tmp
directory within the container.
And /opt/image2:/data
mounts the /opt/image2
directory on the host machine to the /data
directory within the container.
Ports
Ports are used to expose services running inside a container to the outside world. They allow external clients to communicate with the services running inside the container.
The expose key, functionally does almost nothing, it is a way to document the ports that the container listens on. It does not actually publish the ports, to do that, you need to use the ports key.
We use this when there is no need to expose the port to the host machine, but we still want to document it. For example, if we were putting all our services behind a reverse proxy, we would not need to map the ports to the host machine, as our reverse proxy would be able to communicate with the services directly, and then we would only map the reverse proxy's port to the host machine. (typically port 80 and/or 443)
The syntax for defining a port is host-port:container-port
, e.g. 8080:80
.
Host port is the port on the host machine, and container port is the port on which the service is listening inside the container.
For example, our myservice1
service is listening on port 80
inside the container, and we are exposing it on port 8080
on the host machine.
This will make the service accessible at http://host-ip:8080
or http://localhost:8080
.
Without defining the ports key, the service will not be accessible from outside the container.
If you are running the container on a server that is not your local machine, you may need to open the port on the server's firewall to allow incoming connections.
Installing Docker
To install Docker on your VPS, you can follow the official installation guide at https://get.docker.com.
The installation process is straightforward and involves running a script that installs Docker and its dependencies.
The steps are copied here for convenience:
-
Download the script:
$ curl -fsSL https://get.docker.com -o install-docker.sh
-
Verify the script's content (optional):
$ cat install-docker.sh
-
Run the script with
--dry-run
to verify the steps it executes (optional):$ sh install-docker.sh --dry-run
-
Run the script either as root, or using
sudo
to perform the installation:$ sudo sh install-docker.sh
After running the script, Docker should be installed on your VPS.
You can verify the installation by running the following command:
$ docker --version
This should output the version of Docker installed on your VPS.
Conclusion
In this guide, we learned about Docker and how to use it to run services in containers.
We also learned how to define services in a compose.yaml
file and the different keys that can be used to configure a service.
In the next guide, we will go through my template compose.yaml and how to use it to host Stremio addons, Seanime, A debrid media server and more.