Docker Find File
2025-04-03
I regularly need to view/edit/manipulate files in a Docker container that are not mounted from the outside. It sure is nice to do that from the comfort of Emacs.My desired behavior was a this:
- invoke a function
- see a list of running containers and select one
- find file or directory from that container
docker.el can be used for interacting with the Docker API. For the second step, I use ivy/counsel as my completion framework but anything works, really. For the final and most important step, there's the almighty TRAMP.
I have a function for listing containers, which is just a wrapper around docker.el functions.
(defun kz/docker-container-entries (&rest filters)
(if (and filters (car filters))
(aio-wait-for
(docker-container-entries
(mapconcat (lambda (f) (format "-f %s" f)) filters " "))))
(aio-wait-for (docker-container-entries "--all")))
This will synchronously call docker-container-entries (from docker.el), with provided filters.
What I didn't know and learned while trying to do this, was the completing-read function. I used it all the time,
but not in my own functions. Here's the documentation. ivy (and alternatives) make this "minibuffer completions"
smoother.
(completing-read "Select container: " (kz/docker-container-entries "status=running"))
If I need to open, for example, /etc/nginx/nginx.conf from nginx-container, using TRAMP, I could write:
(find-file "/docker:root@nginx-container:/etc/nginx/nginx.conf")
For my purpose, since I want a more interactive experience, I will use counsel-find-file and
pass it the prefix /docker:root@container:/ to make my life easier. This is the final product:
(defun kz/docker-find-file ()
(interactive)
(let ((container (completing-read "Select container: " (kz/docker-container-entries "status=running"))))
(counsel-find-file (concat "/docker:root@" container ":/"))))