documentation/docs/alpine-server-setup/post-install/containers.md

5.4 KiB

Containers

Containers and pods (a collection of containers in the same namespace) enables easy and secure management of hosted applications. In this case podman has been chosen to configure the pods and containers as it makes it possible to perform this task without root. Furthermore, the management of these pods which consists of automatic backups of the volumes and databases and automatically starting and updating at reboots will be performed by runsvdir.

Podman

Install podman with

# apk add podman 

Rootless podman needs cgroups to operate

# rc-update add cgroups default

Set up the network namespace configuration for the user

# modprobe tun
# echo tun >> /etc/modules-load.d/tun.conf
# for i in subuid subgid; do
> echo <username>:100000:65536 >> /etc/$i
> done

Run the following container to verify if everything works

$ podman run --rm hello-world

Management of containers

To run a single container create ~/.config/sv/<container-name>/run

#!/bin/sh

command="/usr/bin/podman"
command_args="run --replace --rm --name=<container-name> --network=pasta"
env="<container-envs>"
ports="<container-ports>"
mounts="<container-mounts>"
image="<container-image>"

exec 2>&1
exec $command $command_args $env $ports $mounts $image

Make it executable and link it to the service directory

$ chmod +x ~/.config/sv/<container-name>/run
$ ln -s <home>/.config/sv/<container-name> <home>/.local/service

Management of pods

Necessary to check if a pod is running create ~/.local/bin/checkpod

#!/bin/sh

. ./conf

exec 2>&1

state=0

while [ $state == 0 ]
do
	sleep 10
	$command pod inspect ${name}-pod | grep -q '"State": "Running"' || state=1
done

and make it executable with

$ chmod +x ~/.local/bin/checkpod

To run a pod configured with ~/.config/pods/<pod-name>/<pod-name>.yml, see alpine-server for examples, create ~/.config/sv/<pod-name>/conf

name="<pod-name>"
home="<home>"
pod_location="${home}/.config/pods/<pod-name>"
bin_location="${home}/.local/bin"
command="/usr/bin/podman"
command_args="--replace --network=pasta"

create ~/.config/sv/<pod-name>/run

#!/bin/sh

. ./conf

exec 2>&1
$command kube play $command_args ${pod_location}/${name}-pod.yml
exec ${bin_location}/checkpod

and create ~/.config/sv/<pod-name>/finish

#!/bin/sh

. ./conf

exec 2>&1
exec $command kube down ${pod_location}/${name}-pod.yml

Make both run and finish executable

$ chmod +x ~/.config/sv/<pod-name>/run
$ chmod +x ~/.config/sv/<pod-name>/finish

Finally, link the pod to the service directory

$ ln -s <home>/.config/sv/<pod-name> <home>/.local/service

Backup of volumes and databases

To back up volumes of containers and postgresql databases create ~/.local/bin/dump

#!/bin/sh

command="/usr/bin/podman"

# Dumps databases

postgres_databases="<list-of-postgres-databases>"

for database in $postgres_databases
do
    exec $command exec -it ${database}-pod-postgres sh -c "pg_dumpall -U postgres | gzip > /dump/${database}.sql.gz"
done

# Exports volumes

volumes="<list-of-volumes>"

for volume in $volumes
do
    exec $command volume export $volume --output <home>/.volumes/${volume}.tar
done

Make it executable

$ chmod +x ~/.local/bin/dump

Automate it with snooze

# apk add snooze

and create ~/.config/sv/dump/run

#!/bin/sh

exec 2>&1
exec snooze -H* /home/neutrino/.local/bin/dump

which executes dump every hour.

Make it executable and link it to the service directory

$ chmod +x ~/.config/sv/dump/run
$ ln -s <home>/.config/dump <home>/.local/service

Then a duplicati container can be used to back up the .dump and .volumes folders to another server if necessary.

The volumes and postgresql databases can be reloaded with ~/.local/bin/load

#!/bin/sh

command="/usr/bin/podman"

# Loads dumped databases

postgres_databases="<list-of-postgres-databases>"

for database in $postgres_databases
do
    exec $command exec -it ${database}-pod-postgres sh -c "gunzip -c /dump/${database}.sql.gz | psql -U postgres"
done

# Imports volumes

volumes="<list-of-volumes>"

for volume in $volumes
do
    exec $command volume import $volume <home>/.volumes/${volume}.tar
done

Make it executable

$ chmod +x ~/.local/bin/load

Reverse proxy

While it would be more optimal to run a reverse proxy in a container and link the network namespaces to this container, this is unfortunately not yet possible with pasta user network namespaces. Therefore, the reverse proxy should be run in front of the containers and thus on the system.

Install caddy with

# apk add caddy libcap

Give caddy privileges to access all ports, to be able to run caddy rootless

# setcap cap_net_bind_service=+ep /usr/sbin/caddy

Create ~/.config/caddy/caddyfile according to your needs. Then convert it with the following to make it persistent.

$ caddy adapt -c ~/.config/caddy/caddyfile -p > ~/.config/caddy/caddy.json

Create the service ~/.config/sv/caddy/run

#!/bin/sh

command="/usr/sbin/caddy"
command_args="run"

exec ps | grep '[${command}] ${command_args}' > /dev/null

if [$? != 0]; then
	exec 2>&1
	exec $command $command_args
fi

Make it executable and link it to the service directory

$ chmod +x ~/.config/sv/caddy/run
$ ln -s <home>/.config/sv/caddy <home>/.local/service