I'm experimenting with Podman Quadlets and trying to scale an app using a Quadlet template. However, I'm running into an issue with the port format when using a dynamic variable %i
in the PublishPort
field.
After running a dry run with podman-system-generator --user --dryrun
, I get the following error:
quadlet-generator[24155]: Loading source unit file /home/filip/.config/containers/systemd/node-app@.container
quadlet-generator[24155]: converting "node-app@.container": invalid port format '300%i'
Quadlet file node-app@.container
:
[Service]
Restart=always
[Container]
ContainerName=node-app-%i
Image=localhost/node-app:latest
Environment=NODE_ENV=production
PublishPort=300%i:3000
I plan to scale the instances like this:
systemctl --user enable --now node-app@1
systemctl --user enable --now node-app@2
systemctl --user enable --now node-app@3
Containerfile:
FROM node:22-slim
WORKDIR /app
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
Simple app example server.js
:
const http = require("node:http")
const hostname = "0.0.0.0";
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader("Content-Type", "text/plain");
res.end("Hello World\n");
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
Is there a correct way to dynamically assign ports in Quadlet using something like $i
in the PublishPort
field, or is there another approach I should take to achieve this?
Since version v5.3.0-rc2 implemented the PublishPort
key in Quadlet .container
and .pod
files can now accept variables in its value.
I've updated quadlets and app
[Service]
Restart=always
[Container]
ContainerName=node-app-%i
Image=localhost/node-app:latest
Environment=NODE_ENV=production
Environment=PORT=300%i
PublishPort=300%i:300%i
const http = require("node:http")
const hostname = "0.0.0.0";
const port = process.env.PORT || 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader("Content-Type", "text/plain");
res.end("Hello World\n");
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
Now I can run
$ systemctl --user start node-app@1
$ systemctl --user start node-app@2
$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
368c4f8e1a6c localhost/node-app:latest node --no-warning... 2 minutes ago Up 2 minutes 0.0.0.0:3001->3001/tcp node-app-1
a8c69395e4de localhost/node-app:latest node --no-warning... 1 second ago Up 2 seconds 0.0.0.0:3002->3002/tcp node-app-2
$ curl localhost:3001
Hello World
$ curl localhost:3002
Hello World