Skip to main content

Deploy Docker Apps

warning

Using Docker requires Kit Plan or above.

Docker in DOM Cloud is powered by Docker rootless mode. Enabling docker features is implicitly allows running 24/7 (doesn't have to actually using docker). Because of how powerful and resouce consuming this is only available starting with Kit plan.

Docker is available only in some servers as they offer the most computing resources we currently offer.

When this feature enabled, these things applied:

  • assign /etc/subuid + /etc/subgid to allow docker using sub uids for assigning containers.
  • assign /var/lib/systemd/linger to allow backround processes not get killed when SSH session terminates.
  • registering dockerd as user-scoped systemd daemon by dockerd-rootless-setuptool.sh and set it to run at startup.

Because Docker run as daemon, the feature also allows any app under the site have a long running processes i.e. the 3 hour process limit is automatically appealed no matter if it actually uses Docker or not.

Enable docker with writing this to the deployment script:

features:
- docker

Getting Started

The deployment script below activates docker capabilities and set up a docker-compose.yml file from services script.

# Requires Kit plan or higher!
source: clear
features:
- docker
services:
hello_world:
# https://github.com/cernoel/docker-hello-world
image: cernoel/hello-world:main
restart: always
ports:
- 8080:8000

The services subpath is equal to services declared in docker compose file. In fact, you can simply copy paste any docker compose file from internet to our deployment script! The port mapping will be linked automatically to our NGINX system. After deployment, you can examine the final docker-compose.yml in the ~/public_html:

cat ~/public_html/docker-compose.yml
services:
hello_world:
image: cernoel/hello-world:main
restart: always
ports:
- 12345:8000/tcp

The host port has been changed to ensure it's only assigned to your website. The port range chosen is between 10000 to 30000, which is a port range that blocked from outside. If you already set the port range >32000 the port chosen will be left unchanged to allow you expose that to the greater internet.

When calling services in deployment system, docker compose down and docker compose up will be automatically everytime a deployment script is called with services: prop. Note that you cannot declare volumes: and networks: using deployment script. See With Existing Docker Compose for solution.

How does it know if port 8080 is the web gateway? Because we're guessing. To enforce which port forwarded by NGINX, use

With Existing Docker Compose

What if you already have docker-compose.yml file, perhaps from a GitHub repo?

The example below setup Plausible self-hosting with their depedencies.

source: https://github.com/plausible/hosting
features: docker
services: docker-compose.yml # docker compose always ran after commands
commands:
- echo BASE_URL=https://$DOMAIN > plausible-conf.env
- echo SECRET_KEY_BASE=$(openssl rand -base64 48) >> plausible-conf.env
- echo TOTP_VAULT_KEY=$(openssl rand -base64 32) >> plausible-conf.env

You can configure your containers using docker commands in SSH. To reconfigure composer file cleanly just like running services: via deployment script without leaving SSH you can run:

docker compose -f ~/public_html/docker-compose.yml down --remove-orphans
docker compose -f ~/public_html/docker-compose.yml up --build --detach

Healthcheck

While your app and it services runs 24/7, sometimes your app can crash on itself. Use proxfix NOHUP mode to watch docker on every request.

nginx:
root: public_html/public
passenger:
enabled: on
app_start_command: proxfix docker compose up --force-recreate -d
env_var_list:
- NOHUP=1
- TARGET=127.0.0.0:8080

The proxfix process spawns and check if TARGET=127.0.0.0:8080 still running. If it not, it will spawn docker compose up --force-recreate -d and forwarding requests to TARGET address, which is should be where docker listening to. To know the correct TARGET value, check to your docker-compose.yml file.

Playing Docker with SSH

You can also play with Docker directly using SSH with docker run -ti --rm ubuntu /bin/bash. It will create a root Ubuntu shell that you can play with. To make your changes persistent, please consider writing a Dockerfile or explore existing container images with Docker Hub.

Managing containers

All docker commands is available as usual. To make managing a bit easier, DOM Cloud also installed lazydocker, a TUI for managing docker available via SSH.

lazydocker

Managing systemd daemon

Your docker instance is registered as user-scoped systemd service. You can call these systemd commands to diagnose docker problems

  • systemctl status docker --user
  • systemctl start docker --user

You can also install or uninstall docker engine via SSH by running below.

  • dockerd-rootless-setuptool.sh install
  • dockerd-rootless-setuptool.sh uninstall

Troubleshooting

502 Bad Gateway

This could means your docker container is unable to run. Please check docker ps and docker logs.

If it running normally, please check if NGINX and docker compose running the same proxy_pass. Try deploying service: docker-compose.yml again.

exec format error in docker logs

This means the container is not available in system architecture. Our servers can be an arm64 (ARM) not amd64 (Intel), not every image containers have this platform arch. Check it with Docker Hub.

If you confirm that the image containers is amd64 only, please move the server to x64 variant, that's SGA/WDC server -- or build your own image.

Network Slow / Not Working

We use pasta driver for rootless networking which is fast for incoming connections to the container but not for outgoing networks. If you experience frequent network errors during docker build please add --network=host to the docker build args or below for compose file:

services:
app:
build:
context: .
network: host

Diagnose network by running dockerd-rootless-setuptool.sh nsenter. This will put you into a shell environment inside RootlessKit namespace.

Can't Choose Host IP to forward

If you set port forwarding such as 127.1.2.3:8080:80 it won't work since the pasta driver listens to 0.0.0.0:<port> on the host system. It listen to all addresses so it doesn't require NAT / packet translation. Basically that request would go from 127.1.2.3:8080 in the host then 127.1.2.3:80 in the container.

If you have a burning desire to do IP forwarding, you can switch to docker's default slirp4netns by removing envars in systemctl edit docker --user. Please consult to Official docker documentation for more information