summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/tutorials/README.md4
-rw-r--r--docs/tutorials/socket_activation.md212
2 files changed, 216 insertions, 0 deletions
diff --git a/docs/tutorials/README.md b/docs/tutorials/README.md
index c7c1a3616..2cdb86fa0 100644
--- a/docs/tutorials/README.md
+++ b/docs/tutorials/README.md
@@ -31,3 +31,7 @@ Learn how to set up and use image signing with Podman.
**[Basic Networking](basic_networking.md)**
A basic guide to common network setups with Podman
+
+**[Socket activation](socket_activation.md)**
+
+Learn how to run containers that support socket activation.
diff --git a/docs/tutorials/socket_activation.md b/docs/tutorials/socket_activation.md
new file mode 100644
index 000000000..8275075f0
--- /dev/null
+++ b/docs/tutorials/socket_activation.md
@@ -0,0 +1,212 @@
+## Podman socket activation
+
+Socket activation conceptually works by having systemd create a socket (e.g. TCP, UDP or Unix
+socket). As soon as a client connects to the socket, systemd will start the systemd service that is
+configured for the socket. The newly started program inherits the file descriptor of the socket
+and can then call accept the incoming connection (in other words run the system call `accept()`).
+This description corresponds to the default systemd socket configuration
+[`Accept=no`](https://www.freedesktop.org/software/systemd/man/systemd.socket.html#Accept=)
+that lets the service accept the socket.
+
+Podman supports two forms of socket activation:
+
+* Socket activation of the API service
+* Socket activation of containers
+
+### Socket activation of the API service
+
+The architecture looks like this
+
+``` mermaid
+stateDiagram-v2
+ [*] --> systemd: client connects
+ systemd --> podman: socket inherited via fork/exec
+```
+
+The file _/usr/lib/systemd/user/podman.socket_ on a Fedora system defines the Podman API socket for
+rootless users:
+
+```
+$ cat /usr/lib/systemd/user/podman.socket
+[Unit]
+Description=Podman API Socket
+Documentation=man:podman-system-service(1)
+
+[Socket]
+ListenStream=%t/podman/podman.sock
+SocketMode=0660
+
+[Install]
+WantedBy=sockets.target
+```
+
+The socket is configured to be a Unix socket and can be started like this
+
+```
+$ systemctl --user start podman.socket
+$ ls $XDG_RUNTIME_DIR/podman/podman.sock
+/run/user/1000/podman/podman.sock
+$
+```
+The socket can later be used by for instance __docker-compose__ that needs a Docker-compatible API
+
+```
+$ export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock
+$ docker-compose up
+```
+
+### Socket activation of containers
+
+Since version 3.4.0 Podman supports socket activation of containers, i.e., passing
+a socket-activated socket to the container. Thanks to the fork/exec model of Podman, the socket will be first
+inherited by conmon and then by the OCI runtime and finally by the container
+as can be seen in the following diagram:
+
+
+``` mermaid
+stateDiagram-v2
+ [*] --> systemd: client connects
+ systemd --> podman: socket inherited via fork/exec
+ state "OCI runtime" as s2
+ podman --> conmon: socket inherited via double fork/exec
+ conmon --> s2: socket inherited via fork/exec
+ s2 --> container: socket inherited via exec
+```
+
+This type of socket activation can be used in systemd services that are generated with the command
+[`podman generate systemd`](https://docs.podman.io/en/latest/markdown/podman-generate-systemd.1.html).
+The container must also support socket activation. Not all software daemons support socket activation
+but it's getting more popular. For instance Apache HTTP server, MariaDB, DBUS, PipeWire, Gunicorn, CUPS
+all have socket activation support.
+
+#### Example: socket-activated echo server container in a systemd service
+
+Let's try out [socket-activate-echo](https://github.com/eriksjolund/socket-activate-echo/pkgs/container/socket-activate-echo), a simple echo server container that supports socket activation.
+
+Create the container
+
+```
+$ podman create --rm --name echo --network none ghcr.io/eriksjolund/socket-activate-echo
+```
+
+Generate the systemd service unit
+
+```
+$ mkdir -p ~/.config/systemd/user
+$ podman generate systemd --name --new echo > ~/.config/systemd/user/echo.service
+```
+
+A socket activated service also requires a systemd socket unit.
+Create the file _~/.config/systemd/user/echo.socket_ that defines the
+sockets that the container should use
+
+```
+[Unit]
+Description=echo server
+
+[Socket]
+ListenStream=127.0.0.1:3000
+ListenDatagram=127.0.0.1:3000
+ListenStream=[::1]:3000
+ListenDatagram=[::1]:3000
+ListenStream=%h/echo_stream_sock
+
+# VMADDR_CID_ANY (-1U) = 2^32 -1 = 4294967295
+# See "man vsock"
+ListenStream=vsock:4294967295:3000
+
+[Install]
+WantedBy=default.target
+```
+
+`%h` is a systemd specifier that expands to the user's home directory.
+
+After editing the unit files, systemd needs to reload it's configuration
+
+```
+$ systemctl --user daemon-reload
+```
+
+Start the socket unit
+
+```
+$ systemctl --user start echo.socket
+```
+
+Test the echo server with the program __socat__
+
+```
+$ echo hello | socat - tcp4:127.0.0.1:3000
+hello
+$ echo hello | socat - tcp6:[::1]:3000
+hello
+$ echo hello | socat - udp4:127.0.0.1:3000
+hello
+$ echo hello | socat - udp6:[::1]:3000
+hello
+$ echo hello | socat - unix:$HOME/echo_stream_sock
+hello
+$ echo hello | socat - VSOCK-CONNECT:1:3000
+hello
+```
+
+The echo server works as expected. It replies _"hello"_ after receiving the text _"hello"_.
+
+### Socket activate an Apache HTTP server with systemd-socket-activate
+
+Instead of setting up a systemd service to test out socket activation, an alternative is to use the command-line
+tool [__systemd-socket-activate__](https://www.freedesktop.org/software/systemd/man/systemd-socket-activate.html#).
+
+Let's build a container image for the Apache HTTP server that is configured to support socket activation on port 8080.
+
+Create a new directory _ctr_ and a file _ctr/Containerfile_ with this contents
+
+```
+FROM docker.io/library/fedora
+RUN dnf -y update && dnf install -y httpd && dnf clean all
+RUN sed -i "s/Listen 80/Listen 127.0.0.1:8080/g" /etc/httpd/conf/httpd.conf
+CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
+```
+
+Build the container image
+
+```
+$ podman build -t socket-activate-httpd ctr
+```
+
+In one shell, start __systemd-socket-activate__.
+
+```
+$ systemd-socket-activate -l 8080 podman run --rm --network=none localhost/socket-activate-httpd
+```
+
+The TCP port number 8080 is given as an option to __systemd-socket-activate__. The __--publish__ (__-p__)
+option for `podman run` is not used.
+
+In another shell, fetch a web page from _localhost:8080_
+
+```
+$ curl -s localhost:8080 | head -6
+<!doctype html>
+<html>
+ <head>
+<meta charset='utf-8'>
+<meta name='viewport' content='width=device-width, initial-scale=1'>
+<title>Test Page for the HTTP Server on Fedora</title>
+$
+```
+
+### Disabling the network with _--network=none_
+
+If the container only needs to communicate over the socket-activated socket, it's possible to disable
+the network by passing __--network=none__ to `podman run`. This improves security because the
+container then runs with less privileges.
+
+### Native network performance over the socket-activated socket
+
+When using rootless Podman, network traffic is normally passed through slirp4netns. This comes with
+a performance penalty. Fortunately, communication over the socket-activated socket does not pass through
+slirp4netns so it has the same performance characteristics as the normal network on the host.
+Note, there is a delay when the first connection is made because the container needs to
+start up. To minimize this delay, consider passing __--pull=never__ to `podman run` and instead
+pull the container image beforehand.