An echo server that supports systemd socket activation
family | type | support |
---|---|---|
AF_UNIX | SOCK_STREAM | yes |
AF_INET | SOCK_STREAM | yes |
AF_INET6 | SOCK_STREAM | yes |
AF_VSOCK | SOCK_STREAM | yes |
AF_UNIX | SOCK_DGRAM | yes (but no support for outgoing traffic when run in container because the client socket path on the host is not accessible from within the container) |
AF_INET | SOCK_DGRAM | yes |
AF_INET6 | SOCK_DGRAM | yes |
- podman version 3.4.0 (released September 2021) or newer
- container-selinux version 2.183.0 (released April 2022) or newer
If you are using an older version of container-selinux and it does not work, add --security-opt label=disable
to podman run
.
- Install socat
sudo dnf -y install socat
The container image ghcr.io/eriksjolund/socket-activate-echo is built by the GitHub Actions workflow .github/workflows/publish_container_image.yml from the file ./Containerfile.
-
Start the echo server sockets
git clone https://github.com/eriksjolund/socket-activate-echo.git mkdir -p ~/.config/systemd/user cp -r socket-activate-echo/systemd/* ~/.config/systemd/user systemctl --user daemon-reload systemctl --user start echo@demo.socket
-
Run the commands
$ 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.demo hello $ echo hello | socat - VSOCK-CONNECT:1:3000 hello
-
Try establishing an outgoing connection
$ podman exec -t echo-demo curl https://podman.io curl: (6) Could not resolve host: podman.io $
(The command-line option
--network=none
was added to prevent the container from establishing outgoing connections)
-
Socket activate the echo server
systemd-socket-activate -l /tmp/stream.sock \ -l 4000 -l vsock:4294967295:4000 podman run --rm --name echo2 \ --network=none ghcr.io/eriksjolund/socket-activate-echo
Instead of VMADDR_CID_ANY (4294967295) we could also have used VMADDR_CID_LOCAL (1), in other words,
-l vsock:1:4000
(seeman 7 vsock
). -
In another shell
$ echo hello | socat - unix:/tmp/stream.sock hello $ echo hello | socat - tcp4:127.0.0.1:4000 hello $ echo hello | socat - tcp6:[::1]:4000 hello $ echo hello | socat - VSOCK-CONNECT:1:4000 hello
-
Try establishing an outgoing connection
$ podman exec -t echo2 curl https://podman.io curl: (6) Could not resolve host: podman.io $
-
Socket activate the echo server
systemd-socket-activate --datagram \ -l 5000 podman run --rm --name echo3 \ --network=none ghcr.io/eriksjolund/socket-activate-echo
-
In another shell
$ echo hello | socat - udp4:127.0.0.1:5000 hello $ echo hello | socat - udp6:[::1]:5000 hello
-
Try establishing an outgoing connection
$ podman exec -t echo3 curl https://podman.io curl: (6) Could not resolve host: podman.io $
-
Install requirements
sudo dnf install -y qemu butane coreos-installer
-
Start the Fedora CoreOS VM by running these commands on the host
STREAM=next CID=20 mkdir -p ~/.local/share/libvirt/images/ file=$(coreos-installer download -s "${STREAM}" -p qemu -f qcow2.xz --decompress -C ~/.local/share/libvirt/images/) cat vm/echo.butane | butane --strict --pretty --files-dir systemd > file.ign qemu-kvm -m 2048 \ -device "vhost-vsock-pci,id=vhost-vsock-pci0,guest-cid=$CID" \ -cpu host -nographic -snapshot \ -drive "if=virtio,file=$file" \ -fw_cfg name=opt/com.coreos/config,file=file.ign -nic "user,model=virtio"
The Context Identifier (CID) is an arbitrary number that is used to identify the VM (see
man vsock
). -
Run on the host
$ CID=20 $ echo hello | socat -t 30 - VSOCK-CONNECT:$CID:3000 hello
Pulling a container image may take long time. This delay can be avoided by pulling the container
image beforehand and adding the command-line option --pull=never
to podman run
.
If socat does not receive any reply within a certain time limit it terminates before getting the reply. The timeout is 0.5 seconds by default. Symptoms of this could be
$ systemctl --user start echo@demo.socket
$ echo hello | socat - udp4:127.0.0.1:3000
$ echo hello | socat - udp4:127.0.0.1:3000
hello
To configure the timeout to be 30 seconds, add the command-line option -t 30
.
$ echo hello | socat -t 30 - udp4:127.0.0.1:3000
hello
Another way to handle the problem is to use the command-line option readline to get an interactive user interface. Type the word hello and see it being echoed back.
$ socat readline udp4:127.0.0.1:3000
hello
hello
In this case there will be no timeout because none of the channels have reached EOF.
A good way to diagnose problems is to look in the journald log for the service:
journalctl -xe --user -u echo@demo.service