tomsquest / docker-radicale

Docker image for Radicale calendar and contact server :calendar: + security :closed_lock_with_key: + addons :rocket:
GNU General Public License v3.0
562 stars 80 forks source link

podman support #122

Closed Greylinux closed 1 year ago

Greylinux commented 1 year ago

Hi, sorry to open an issue, if it's not practical please close it. But I wonder if you have every tried to run this using podman ? And therefore add it as an option in the readme ?

tomsquest commented 1 year ago

Hi @Greylinux , This could be a good idea. I don't use Podman (plain docke-compose here :) ), but if you do, it would be very welcome.

Greylinux commented 1 year ago

Hi @tomsquest , sorry for the delay, I'm currently learning all the different way, podman can be used to create, run and restart a container/containers. Some of these options being podman-compose , similar to docker-compose, a systemd service and a kubernetes yaml file. So I can report back here with my results, it may be a while though.

Greylinux commented 1 year ago

Hi @tomsquest , Sorry I haven't updated this for a while. Ok so after a lot of research I decided the best way to run Podman is with systemd.

Your docker run command will work without issue with podman , so you could add a note that its possible to run with podman and without sudo.

podman run --detach --label "io.containers.autoupdate=registry" --name radicale --init --publish 5232:5232 --cap-drop ALL --cap-add CHOWN --cap-add SETUID --cap-add SETGID --cap-add KILL --security-opt="no-new-privileges:true" --volume /path/to/data/radicale/data:/data:Z --volume /path/to/configfile/radicale/config:/config:ro,Z --volume /path/to/passwordfile/radicale/users:/etc/radicale/users:Z --health-cmd="curl --fail http://localhost:5232 || exit 1" --health-interval=30s --health-retries=3 --env TZ=Europe/London docker.io/tomsquest/docker-radicale

you may notice the 'Z' after each volume and this is because I run this fedora with selinux enabled , so this adds another layer of protection , but of course its not necessary.

If you want to have something similar to docker compose then you can add this systemd unit file to your system and just change the volume mounts. To run rootless you have to add the systemd unit files to ~/.config/systemd/user/ instead of /etc/

you then have to use the --user tag with systemctl to restart , start ,stop containers.

systemctl --user enable --now container-radicale.service

one cool feature with running podman containers using systemd is if you add the entry

--label "io.containers.autoupdate=registry" \ to the unit file you can then update the containers with a simple

podman auto-update

I found systemd to be the easiest solution to run podman similar to docker compose , just copy the systemd unit files to the right location , enable container service and then sit back and relax.

here is the systemd unit file

# container-radicale.service
# autogenerated by Podman 4.3.1
# Sun Dec  4 13:15:43 GMT 2022

[Unit]
Description=Podman container-radicale.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=%t/containers

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStartPre=/bin/rm \
    -f %t/%n.ctr-id
ExecStart=/usr/bin/podman run \
    --cidfile=%t/%n.ctr-id \
    --cgroups=no-conmon \
    --rm \
    --sdnotify=conmon \
    --replace \
    --detach \
        --label "io.containers.autoupdate=registry" \
    --name radicale \
    --init \
    --publish 5232:5232 \
    --cap-drop ALL \
    --cap-add CHOWN \
    --cap-add SETUID \
    --cap-add SETGID \
    --cap-add KILL \
    --security-opt=no-new-privileges:true \
    --volume /path/to/data/radicale/data:/data:Z \
    --volume /path/to/config/radicale/config:/config:ro,Z \
    --volume /path/to/passwordfile/radicale/users:/etc/radicale/users:Z "--health-cmd=curl --fail http://localhost:5232 || exit 1" \
    --health-interval=30s \
    --health-retries=3 \
    --env TZ=Europe/London docker.io/tomsquest/docker-radicale
ExecStop=/usr/bin/podman stop \
    --ignore -t 10 \
    --cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm \
    -f \
    --ignore -t 10 \
    --cidfile=%t/%n.ctr-id
Type=notify
NotifyAccess=all

[Install]
WantedBy=default.target 

any questions just let me know, if you want to add this to your readme , then please do.

github-actions[bot] commented 1 year ago

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 14 days.

github-actions[bot] commented 1 year ago

This issue was closed because it has been stalled for 14 days with no activity.

tomsquest commented 1 year ago

Added a link in the README to this issue.

strauss115 commented 8 months ago

Hi @tomsquest and @Greylinux, thanks for this wonderful hardened image of radicale. As podman generate systemd is deprecated I would like to share an alternative based on a Quadlet and a Kubernetes Pod definition. I have tested it with Podman version 4.7.2 which is the current Debian testing version. Please note that Quadlets are supported since Podman 4.4.

The configuration is more or less based on the one above and assumes that the mounts already exist with proper permissions. Therefore "TAKE_FILE_OWNERSHIP" is set to false. Further, it assumes host users/groups are used, however, using Podmans namespace mapping might be a good alternative too.

Here is the YAML Pod definition proposal

apiVersion: apps/v1
kind: Pod
metadata:
  name: radicale
  labels:
    app: radicale
spec:
  containers:
  - name: server
    image: docker.io/tomsquest/docker-radicale:latest # pin version if needed
    resources:
      limits:
        memory: "256Mi"
        cpu: "250m" # increase if needed
    ports:
    - containerPort: 5232
      hostPort: 5232
    env:
    - name: TZ
      value: "Europe/London" # adjust to your timezone
    - name: TAKE_FILE_OWNERSHIP
      value: false
    volumeMounts:
    - mountPath: /data
      name: data
      readOnly: false
    - mountPath: /config
      name: config
      readyOnly: true
    - mountPath: /etc/radicale/users
      name: users
      readOnly: true
    livenessProbe:
      httpGet:
        path: /
        port: 5232
      initialDelaySeconds: 10
      periodSeconds: 30
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: ["ALL"]
        add: ["SETUID", "SETGID", "KILL"] # Add CHOWN if TAKE_FILE_OWNERSHIP is set to TRUE
      privileged: false
      readOnlyRootFilesystem: true
      runAsUser: 2999
      runAsGroup: 2999
  volumes:
  - name: data
    hostPath:
      path: /opt/radicale/data # adjust path
      type: Directory
  - name: config
    hostPath:
      path: /opt/radicale/config # adjust path
      type: Directory
  - name: users
    hostPath:
      path: /opt/radicale/users # adjust path
      type: File

In order to manage the pod with systemctl just create a .kube file in /etc/containers/systemd (for rootful podman) such as radicale.kube with the following content (uncomment & adjust the network parameters if you needed)

[Kube]
AutoUpdate=registry
#Network=radicale-network
#PodmanArgs=--ip 192.168.1.2
Yaml=/path/to/your/yaml/radicale-pod.yaml

[Install]
WantedBy=default.target # Auto run at boot

Afterwards execute systemctl daemon-reload which will create the radicale.service unit. Of course you can also create the Pod by using podman kube play radicale-pod.yaml

tomsquest commented 8 months ago

Hi @strauss115 ,

Great example with Podman!

I will make a note about it in the Readme. :+1:

WhoIsHans commented 2 weeks ago

Hi @tomsquest

I've created another configuration that makes use of Podman Quadlets but rolls everything into a single .container file.

The configuration is based on the official docker-compose.yml.

I've decided to let systemd take care of ressource usage and therefore placed the necessary options into the System section of the file:

[Container]
ContainerName=radicale
Image=docker.io/tomsquest/docker-radicale
RunInit=true
PublishPort=5232:5232
ReadOnly=true
NoNewPrivileges=true
DropCapability=ALL
AddCapability=SETUID SETGID CHOWN KILL
HealthCmd=curl -f http://127.0.0.1:5232 || exit 1
HealthInterval=30s
HealthRetries=3
Volume=/path/to/data:/data
Volume=/path/to/config:/config:ro

[Service]
TasksMax=50
#This option does not set an absolute max of memory after which the unit would be killed. Rather it will allow the unit to take more memory if needed but slow it down and take down away the memory agressively. See: https://www.freedesktop.org/software/systemd/man/latest/systemd.resource-control.html
MemoryHigh=256M
Restart=always

[Install]
#This option will enable the service to automatically start at system boot. See: https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html#enabling-unit-files
WantedBy=default.target

Hope this can help someone who is looking to have the whole Podman Quadlets setup in a single file.

tomsquest commented 1 week ago

Thanks for the nice example @WhoIsHans !