4. Applications From a Container
Hint
Abstract
This chapter shows how to register applications which are provided by an OCI container. All examples register the app for the calling user and expect the setup described in Getting Started.
A container flake is registered with flake-ctl podman register.
The two options which are always needed are:
--containerThe name of the container as it is known in the local registry, the value of the REPOSITORY column of
podman images. An image which is not there yet is pulled by the registration.--appThe absolute path of the application on the host. This is the name the flake is called by, the path the symbolic link to the launcher is created at.
--target names the program to call inside of the container. If it
is not given, the application is called with the same path it has on
the host. Set it to / to use the entry point the image was built
with.
4.1. Amazon’s SDK Utility as a Container App
flake-ctl podman register \
--container docker.io/amazon/aws-cli --app $HOME/bin/aws --target /
aws ec2 help
This creates $HOME/bin/aws on your host, which actually launches
the amazon/aws-cli container. The default entry point of the
container was configured by Amazon to launch their cloud API
application. Thus, the target program to call inside the container
doesn’t need to be explicitly configured in the registration and is
therefore just set to /. The call of aws ec2 help launches an
instance of the container via rootless podman and shows the help text
for the ec2 subcommand.
4.2. An Editor as a Delta Container
A delta container carries only the difference to a base container. The base exists once on the host and is shared by all deltas built against it, which keeps the data to pull small:
flake-ctl podman register \
--app $HOME/bin/joe \
--container registry.opensuse.org/home/marcus.schaefer/delta_containers/containers_tw/joe \
--base registry.opensuse.org/home/marcus.schaefer/delta_containers/containers_tw/basesystem \
--target /usr/bin/joe
joe
This creates $HOME/bin/joe which is a simple but nice editor. The
launch of the container requires a provision step in which the base
container gets mounted and the delta container is layered on top of
it. This action unfortunately requires root privileges and is
forwarded to the system’s sudo binary.
Note
Delta containers have to be built against the base they are used
with. Such containers can be created with KIWI,
see How To Build Your Own App Images. Additional layers between the base and
the delta are registered with the --layer option, which can be
given more than once and is evaluated in the order of the
arguments.
4.3. Claude AI as a Container App
mkdir -p ~/ai
flake-ctl podman register \
--app $HOME/bin/claude \
--target /bin/bash \
--container public.ecr.aws/b9k1j9y6/ai/claude:latest \
--resume \
--opt "\--net host" \
--opt "\-ti" \
--opt "\--workdir %HOME/ai" \
--opt "\--volume %HOME/ai:%HOME/ai" \
--opt "\-e HOME=%HOME"
claude
This pulls the claude container from the ai space of a public ECR
which we use to offer nightly builds of the most popular AI tools.
The registered flake just starts an isolated shell if you call
claude. Further calls of claude will run in the same container
instance due to the --resume option. The ai directory is the
only path shared from the host with the container.
4.4. Engine Options
--opt passes an option to the container engine. The option can be
given more than once and is written to the flake configuration:
The leading backslash escapes the dash of the option so that it is not taken as an option of
flake-ctlitself.A word starting with
%is a placeholder for the environment variable of that name and is resolved when the app is called, not when it is registered.%HOMEtherefore becomes the home directory of the user who calls the flake. A placeholder which cannot be resolved is turned into the plain variable name.If no options are specified at all, the container starts with terminal emulation,
-ti, and is removed after the call,--rm, unless--resumeor--attachis set. As soon as one option is given, none of these defaults apply anymore.
4.5. Deeper Isolation With krun
Note
For deeper isolation based on a VM you can either use the
firecracker pilot from flake-pilot or the krun runtime with podman
which gives isolation based on KVM and should be preferred for AI
workloads. Please make sure to install the crun package which
also provides krun.
The krun OCI handler however, does not support the exec command. This limitation exists because libkrun runs workloads inside isolated microVMs, and there is no built-in mechanism or agent inside the lightweight virtual machine to spawn and inject new secondary processes. Because of this a krun based app registration cannot use the resume feature and looks as follows:
flake-ctl podman register \
--app $HOME/bin/claude \
--target /bin/bash \
--container public.ecr.aws/b9k1j9y6/ai/claude:latest \
--opt "\--net host" \
--opt "\--runtime=krun" \
--opt "\-ti" \
--opt "\--workdir %HOME/ai" \
--opt "\--volume %HOME/ai:%HOME/ai" \
--opt "\-e HOME=%HOME"
To switch the podman runtime in a user or system wide scope create
the file /etc/containers/containers.conf for a system wide setup
or $HOME/.config/containers/containers.conf for a user specific
setup and place the following content:
[engine]
runtime = "krun"
4.6. Calling a Registered Container App
Arguments given to the app are passed on to the program inside of the container, with two exceptions which are read by the launcher itself:
@NAMEA selector which allows to distribute the exact same program call to different instances, e.g
claude @id1. This is useful for flakes which are not registered with--resume.%OPTIONA runtime option of the pilot, e.g
%interactiveto force the interactive call style or%removeto delete an instance which was kept by--resumeor--attach. Seeman 8 podman-pilotfor the complete list.
4.7. Pilot Options as Part of the Registration
A pilot option which is always needed does not have to be typed at
every call. --pilot-option registers it as part of the flake:
flake-ctl podman register \
--app $HOME/bin/claude \
--target /bin/bash \
--container public.ecr.aws/b9k1j9y6/ai/claude:latest \
--opt "\--volume %HOME/ai:%HOME/ai" \
--pilot-option "%ignore_missing_volume_path"
The option can be given more than once and is stored in the
pilot_options list of the flake configuration:
container:
runtime:
pilot_options:
- "%ignore_missing_volume_path"
Registered options are read on every call. An option of the same name given at call time takes precedence over the registered one.