Skip to main content

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 use viren070/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.

      tip

      Sometimes, 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 remote Dockerfile 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:latest

      In this example, we are using a Dockerfile hosted on GitHub to build the image for the myservice service. We tell Docker Compose to use the Dockerfile in the root of the repository at https://github.com/mccoy88f/OMG-Premium-TV.git to build the image for the service and then name the image myservice: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>.
  • 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, and always.
    • By setting the restart policy to unless-stopped, the container will be restarted unless it is explicitly stopped by the user.
  • 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. $$.
  • 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.

note

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:

  1. Download the script:

    $ curl -fsSL https://get.docker.com -o install-docker.sh
  2. Verify the script's content (optional):

    $ cat install-docker.sh
  3. Run the script with --dry-run to verify the steps it executes (optional):

    $ sh install-docker.sh --dry-run
  4. 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.