I’ve been working on a project to make development using containers easier (specifically Podman), to remove dependency conflicts, and make it easier to run applications on other servers.
The project is called pod
, you can learn more at pod.willhbr.net or willhbr/pod on GitHub. It’s a wrapper around the podman
command-line tool, with the aim of reducing the amount of boilerplate commands you have to type.
Local versions of both this website and my photos website have been using pod
for a while. This has made it really easy to run a server while I’ve been making changes, as well as allowing me to easily daemonise the server and have it continue to run in the background.
At its core, pod
is a YAML file that configures the arguments to a Podman command. Most commands will map one-to-one. The simplest example is something like:
# pods.yaml
containers:
alpine-shell:
name: pod-alpine-example
image: docker.io/library/alpine:latest
interactive: yes
args:
- sh
This defines an interactive container that runs an Alpine Linux shell. You can start it with pod run
.
Where pod
really shines is configuring a setup for a development server, and a production server. As I talked about in my previous blog post, having a development container that mounts the source code from the host machine speeds up development massively. The server behind my photo publishing system follows this pattern, with this config:
defaults:
build: dev
run: dev
update: prod
images:
dev:
tag: pixelfed-piper:dev-latest
from: Containerfile.dev
prod:
tag: pixelfed-piper:prod-latest
from: Containerfile.prod
flags: &default-flags
feed_url: https://pixelfed.nz/users/willhbr.atom
repo_url: git@github.com:willhbr/sturdy-guacamole.git
containers:
dev:
name: pixelfed-piper-dev
image: pixelfed-piper:dev-latest
interactive: true
autoremove: true
bind_mounts:
src: /src/src
ports:
4201: 80
flags:
<<: *default-flags
prod:
name: pixelfed-piper
image: pixelfed-piper:prod-latest
interactive: false
ports:
4200: 80
flags:
<<: *default-flags
check_period: 54m
When I’m ready to deploy a change, I can build a production image with pod build prod
—which will make a release Crystal build—and then start a container on a server using that image.
pod
second half is a simple updating system. It will look at the containers running on your server, match their config against the config in pods.yaml
, and update any containers that have changed. So instead of having to stop and start the prod container myself, I can just run:
$ pod update --diff prod
Which will show the difference and then update the running containers to match the intent. pod
fully supports podman-remote, so it can handle containers running on a different machine just as easily as it can handle those running locally.
I’m super happy with what pod
is able to do, and plan on using it to manage building and running any container I use. You can find it on GitHub, the project website, or read my previous post explaining some more of the backstory