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 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: firstname.lastname@example.org: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