mirror of
https://github.com/containers/podman.git
synced 2025-05-17 23:26:08 +08:00
Merge pull request #14909 from eriksjolund/add_socket_activation_tutorial
[CI:DOCS] Add socket_activation.md
This commit is contained in:
@ -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.
|
||||
|
212
docs/tutorials/socket_activation.md
Normal file
212
docs/tutorials/socket_activation.md
Normal file
@ -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 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.
|
Reference in New Issue
Block a user