In containerd, there is actually a garbage collector which can be found here: https://github.com/containerd/containerd/blob/master/docs/garbage-collection.md. In the cleanup phase, only objects that are not associated (i.e. have no image reference) are removed - those marked as "dirty" are kept. To clean up unused images and running/stopped containers, this can be used.
While not yet production-ready, the tool at https://github.com/Azure/eraser could be used to achieve this. However, it may be difficult and complex to run this on all nodes. Descheduler cannot solve this problem as it does not run as a daemonset, but kubelet garbage collection can be used instead (checking if it is enabled in the current configs): https://kubernetes.io/docs/concepts/architecture/garbage-collection/#containers-images.
It seems that containerd does not support log rotation. I found a solution that involves using kubelet (as described in containerd/containerd#3351 (comment), also pr: https