Managed Service Podman
Podman is a daemonless container engine for developing, managing, and running OCI Containers on your Linux System. Containers can be run on our managed servers in rootless mode.
Since the syntax is mostly identical to Docker, you can add the following alias for easier use:
alias docker=podman
Please keep in mind that the Podman syntax can change with newer versions and will no longer be identical to Docker eventually.
The full documentation of the Podman project can be found here:
https://podman.readthedocs.io/en/latest/index.html
Help and man pages are available in the command line:
podman --help
podman <subcommand> --help
man podman
man podman-<subcommand>
Cleanup Jobs
By default, we automatically create two cleanup jobs during the installation of Podman. One is running in the night from Sunday to Monday and will remove all unused Images. The second one is running every night to the 1st of each month and will remove all unused volumes.
These are safety measures to keep the footprint of Podman as minimal as possible and reduce the risk to overfill your disk space.
If you want to change these cleanup jobs, just write us a ticket and we will adapt it to your needs.
Searching, pulling & listing images
Search for images on remote registries with keywords:
podman search <search_term>
Enhance your search results with filters:
podman search ghost --filter=is-official
Pull the image that you would like to have locally:
podman pull docker.io/library/ghost
List all the images present on your environment:
podman images
Podman searches in different registries. It's recommended to use the full image name (e.g. docker.io/library/ghost
instead of ghost
) to ensure, that you are using the correct image.
Running a container
We run a sample Ghost container that serves the easy-to-use Ghost CMS.
podman run -dt -p 8080:2368/tcp docker.io/library/ghost
This container starts in detached mode -d
. This means you will get a container ID after the container has been started. With the option -t
, a pseudo-tty will be added to run arbitrary commands in an interactive shell.
With the -p 8080:2368/tcp
option, we use port forwarding to be able to access the webserver of Ghost running on port 2368 through the TCP port 8080 on the host system.
Show running containers
podman ps -a
gives us an overview of created and running containers.
$ podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5728ad900bc4 docker.io/library/ghost:latest node current/inde... 4 hours ago Up 4 hours ago 0.0.0.0:8080->2368/tcp gifted_edison
Attach to a running container
With the CONTAINER ID
you are able to attach to an already running container. You can catch the ID in the podman ps
output.
$ podman attach b3376ff455a0
[2020-06-10 09:17:15] INFO "GET /" 200 512ms
Test the running container
The container is now reachable on the port 8080
on your host system.
As you may have noticed above in the Podman ps output, the container has no IP address assigned.
You can test with curl
if your Ghost container application is running correctly:
$ curl localhost:8080| grep "og:site"
<meta property="og:site_name" content="Ghost" />
Proxy the port using nine-manage-vhosts
If you already have the managed services Nginx or Apache2 running, you can simply use nine-manage-vhosts
to expose your application to the outside world using a Let's Encrypt enabled vhost.
Create the new vhost:
sudo nine-manage-vhosts virtual-host create testdomain.org --template=proxy --template-variable=PROXYPORT=8080
Register at let's encrypt:
sudo nine-manage-vhosts certificate register-client --contact-email=contact@yourcompany.org
Create and enable a new let's encrypt cert on the vhost:
sudo nine-manage-vhosts certificate create --virtual-host=testdomain.org
sudo nine-manage-vhosts virtual-host update testdomain.org --template=proxy_letsencrypt_https --template-variable=PROXYPORT=8080
Only needed with apache webserver: To automatically redirect from http to https with using a Let's Encrypt certificate, you can set the template proxy_letsencrypt_https_redirect
.
docker-compose
Starting with Ubuntu 22.04 Podman supports docker-compose
natively and your installation includes docker-compose
v1.
Install the latest v2 version of docker-compose
mkdir -p ~/bin
curl -L $(curl -s https://api.github.com/repos/docker/compose/releases/latest | jq -r '.assets[] | select(.name == "docker-compose-linux-x86_64") | .browser_download_url') -o ~/bin/docker-compose
chmod +x ~/bin/docker-compose
If you are using Podman on Ubuntu 20.04, you can't use native docker-compose
. However, you can use podman-compose
, which replicates the behavior:
podman-compose
mkdir -p ~/bin
curl -o ~/bin/podman-compose https://raw.githubusercontent.com/containers/podman-compose/main/podman_compose.py
chmod +x ~/bin/podman-compose
ln -s ~/bin/podman-compose ~/bin/docker-compose # compatibility for the docker-compose command
Example Usage of docker-compose:
Next, we will run Ghost CMS in network mode slirp4netns
with a compose file. slirp4netns
is Podman's default network
driver and can be omitted in the compose file.
For this example, we use an already locally running MySQL database named nmd_ghost
.
Prepare your own docker-compose.yaml
File.
# by default, the Ghost image will use SQLite (and thus requires no separate database container)
# we have used MySQL here merely for demonstration purposes (especially environment-variable-based configuration)
services:
ghost:
image: ghost:3-alpine
restart: always
ports:
- 8080:2368
environment:
# see https://docs.ghost.org/docs/config#section-running-ghost-with-config-env-variables
database__client: mysql
database__connection__host: localhost
database__connection__user: nmd_ghost
database__connection__password: EeNae5xaoapoh5RoDah1muwu
database__connection__database: nmd_ghost
# this url value is just an example, and is likely wrong for your environment!
url: http://testdomain.org
The docker-compose.yaml
file can then be run
by the docker-compose
command:
docker-compose -f docker-compose.yml up
Generate systemd user unit files
We recommend creating a systemd user service so that the container starts automatically after a system reboot.
Generate the systemd user unit files of the pod named examplepod
:
podman generate systemd --new --files --name examplepod
HINT: with
podman ps
andpodman pod ps
, you can see theNAMES
of your running pods, to generate the correct systemd unit files.
Copy the generated systemd user unit files into your systemd directory:
cp -pv /home/www-data/pod-examplepod.service /home/www-data/container-examplepod_ghost_1.service ~/.config/systemd/user/
Finally, enable the systemd user processes:
systemctl --user enable container-examplepod_ghost_1.service
systemctl --user enable pod-examplepod.service
Networking
Modes (Host, Bridged)
In Bridged
(default) mode, all containers in the same Podman pod
are sharing the same network namespace.
Therefore, the containers will share the same IP, MAC address and port mappings.
Between the containers in one pod
, you can always communicate using localhost
.
There exists another mode called Host
, which can be specified to podman using the network=host
parameter.
If you use the Host
network mode for a container, that container's network stack is not isolated from the Podman Host (the container shares the host's networking namespace), and the container does not get its own IP address allocated. With the Host
mode, it's possible to connect to a local MySQL daemon running on a managed server or to connect to other TCP ports exposed on the host system.
Rootless
As we are running all our containers rootless, the network is set up automatically.
Port Publishing
Only so-called "high ports" can be published with rootless containers. All ports below 1024 are privileged and cannot be used for publishing.
Instead of publishing port 80, we need to switch to a higher port. In this example we will use our Ghost container, which is running on port 2368, and publish it on TCP port 8080 on localhost:
podman run -dt -p 8080:2368/tcp docker.io/library/ghost
You can use podman -P
to automatically publish and map ports.
Check the published and occupied ports:
$ podman port -a
c0194f22266c 2368/tcp -> 0.0.0.0:8080
Container to Container communication
Communicating between two rootless containers can be achieved in multiple ways.
The easiest way is to use the published ports and the underlying host.
Check for listening containers:
podman ps
Show published ports and the own host IP:
podman port <container_id>
ip a
Run a new container to contact your host IP with the published port:
podman run -it --rm fedora curl <HOST_IP_ADDRESS>:8080
Volumes: Mount Storage to Container
To make data persistent, you'd either need to save it to an external system like a database or you mount local storage using the -v
volumes flag. This will allow you to use two different mounting methods:
- Bind Mounts
- Named Volumes
Bind Mounts
Bind Mounts are created by mounting a file or directory inside the container.
Bind mounted volumes containging files and folders with subuids and subgids can be deleted with the following command:
podman unshare rm -r ${bind_mount_dir}
Named Volumes
Named Volumes are managed by Podman and can be changed with it's CLI. They are stored in a specific directory in ~/.local/share/containers/storage/volumes/
.
Backup
All volumes data is automatically backed up on a managed servers. But a separate backup is probably necessary because of the following reasons:
- You can't restore specific data out of volumes.
- The data is not persisted in a consistent state (for example database storage).
That's why we'd recommend to create separate dumps of the data. Those dumps then get backed up automatically by our managed backup.