Deploy Docker Apps
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 bydockerd-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
:
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.
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