Using Emacs for Container Development: Configuring Emacs for Podman and Docker Support
Turn Emacs into a powerful Docker development environment that supports both Docker and Podman workflows. This guide walks you through setting up Dockerfile editing, container management, and automated builds, all within Emacs. Whether you’re switching between Docker and Podman or managing complex containerized projects, Emacs can streamline your development process. Dive in to discover how to integrate Docker with Emacs and boost your workflow!
Introduction
Emacs is a powerhouse for development, and with the right configuration, it can even manage your Docker (or Podman) workflows without leaving the editor. In this guide, we’ll walk through setting up Emacs specifically to work with Docker and Podman. We’ll cover editing Dockerfiles, managing containers, and integrating Docker-specific language support.
External (non Emacs related) Dependencies
To use Docker or Podman effectively within Emacs, ensure the following external dependencies are installed and functioning on your system:
-
Docker: Expected to be installed and running.
-
Docker-Compose: Expected to be installed and functional.
and/or
-
Podman: Expected to be installed and running.
-
Podman-Compose: Expected to be installed and functional.
Setting the Docker Executable
In LEmacs (my own config for Emacs), I've created a flexible setup that allows you to toggle between Docker and Podman as your primary container engine. This makes it easy to adapt your workflow depending on your environment. No needs to use LEmacs by the way, I'll show here all the code needed.
(defcustom lemacs-docker-executable 'docker
"The executable to be used with docker-mode."
:type '(choice
(const :tag "docker" docker)
(const :tag "podman" podman))
:group 'lemacs)
Explanation: This customizable variable allows you to switch
between Docker and Podman in Emacs by simply updating the
lemacs-docker-executable
setting. It’s an efficient way to keep your
setup flexible, especially if you work with both Docker and Podman
environments.
The docker
package provides a way to manage containers directly from
Emacs. With the following setup, you can open the docker menu with
C-c d
and manage your containers, images, and volumes without ever
leaving Emacs.
(use-package docker
:defer t
:ensure t
:bind ("C-c d" . docker)
:config
(pcase lemacs-docker-executable
('docker
(setf docker-command "docker"
docker-compose-command "docker-compose"))
('podman
(setf docker-command "podman"
docker-compose-command "podman-compose"))))
Explanation: By setting up docker.el with a keybinding, you can
quickly access Docker or Podman management commands. The
lemacs-docker-executable
check allows docker.el to adapt to the
selected engine, setting the appropriate commands for docker-command
and docker-compose-command.
Editing Dockerfiles with dockerfile-mode
Writing Dockerfiles in Emacs is made easier with dockerfile-mode
,
which provides syntax highlighting, indentation, and command
customization. Here’s how we configure it:
(use-package dockerfile-mode
:defer t
:ensure t
:config
(pcase lemacs-docker-executable
('docker
(setq dockerfile-mode-command "docker"))
('podman
(setq dockerfile-docker-command "podman"))))
Explanation: This setup activates dockerfile-mode
for any file
named Dockerfile
, providing Dockerfile-specific syntax
support. Additionally, based on lemacs-docker-executable
, it sets the
command used to build images, either docker
or podman
, so you can run
dockerfile-build-buffer
with the correct tool.
Adding Language Support for Dockerfiles with lsp-mode
To enhance editing with features like autocompletion, diagnostics, and
linting, you’ve set up lsp-mode
with
dockerfile-language-server-nodejs
. This provides IDE-like
capabilities for Dockerfile editing in Emacs.
In order to do so, just run M-x lsp-install-server RET
and look for
docker
, of course, you have to properly setup lsp-mode
first.
Explanation:
With lsp-mode
and dockerfile-language-server-nodejs
, you
gain smart language features while writing Dockerfiles, such as error
checking and autocomplete. This is especially useful for complex
Dockerfiles, where syntax and structure are critical for successful
builds.
Setting Up yaml-mode
for Docker-Compose Files
To effectively work with docker-compose.yml
files, it’s beneficial to
have syntax highlighting and proper indentation for YAML. We can
achieve this by setting up yaml-mode in Emacs. Here's how you can
configure it:
(use-package yaml-mode
:defer t
:ensure t
:mode
("\\.yaml\\'" "\\.yml\\'")
:custom-face
(font-lock-variable-name-face ((t (:foreground "#cba6f7"))))
:config)
Explanation:
This setup uses use-package
to ensure yaml-mode
is
installed and deferred until needed, activates it for .yaml and .yml
files, customizes the appearance of variable names with a specific
foreground color, and allows for additional
configurations as required.
LAB Time!
Now that we’ve set up Emacs for Docker (or Podman), let's dive into some hands-on tasks to see how this configuration works in action.
1. Create and Edit a Dockerfile
Start by creating a new Dockerfile
in Emacs. Open a new buffer and
save it with the filename Dockerfile
. Once saved, dockerfile-mode
will
kick in automatically, giving you syntax highlighting and other
Dockerfile-specific features.
Given we have a React project (it could've been any other project, this
is just an example) we could containerize it by creating this Dockerfile
.
FROM node:21-alpine
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY package.json ./
COPY package-lock.json ./
RUN npm install --silent
RUN npm install react-scripts@5.0.0 -g --silent
COPY . ./
CMD ["npm", "start"]
Tip: With lsp-mode configured for Dockerfiles, you’ll get autocompletion, syntax checking, and even inline diagnostics, making it easier to spot issues as you write.
2. Build the Dockerfile
After saving your Dockerfile, it’s time to build it.
Of course, you can open shell
or eshell
and run something like:
docker build -t my-app .
or
podman build -t my-app .
But since we have the dockerfile-mode
set. We can simply issue
M-x dockerfile-build-buffer
or M-x dockerfile-build-no-cache-buffer
.
You'll be prompted for an image name, like docker-app
.
And a new buffer with the build status will appear.
Wait for it until it is finished.
3. Run a Container with Custom Options
After building your image, we could, once again, issue some shell command to have it running, like:
docker run -p 3000:3000 docker-app
or
podman run -p 3000:3000 docker-app
Now docker
package shines again, running M-x docker RET
we get:
The bottom buffer is a transient menu, much like what you get when
opening magit
, this means there's no need to focus the buffer or
navigate your cursor inside it.
We can check our built images hitting i
.
In our case we have an node image from what our image derives, and our
nice docker-app
image.
You can also mark it with m
, unmark it with u
, spin up what is
marked, delete and so on, at any sub-menu just hit ?
for a list of
options.
Let's run our recently built image. Put the cursor on the line with
our docker-app
. Hit ?
to see the options:
Now hit R
to run it, and add any arguments, like p
for port forwarding:
R
again and RET
.
And there we have it, our app is running.
Issuing M-x docker RET
again we can see the containers status:
Hitting c
will give us a list with all containers and its statuses:
Again, hitting ?
prompts us with many options, keep your time and explore it!
For now, I'll just stop it with O
.
4. Working with Docker-Compose
While docker.el
makes it easy to manage individual Docker containers,
using docker-compose
within Emacs allows us to orchestrate multiple
containers at once-perfect for projects with multiple services like
databases, backends, and frontends.
First, ensure you have a docker-compose.yml
file in your project
directory. Here’s an example:
version: "3.7"
services:
docked-app:
container_name: docked-app
build:
context: .
dockerfile: Dockerfile
volumes:
- ".:/app"
- "/app/node_modules"
ports:
- 3001:3000
environment:
- CHOKIDAR_USEPOLLING=true
Notice you can also install an LSP server to help with editing this
sort of file, like yamlls
or any other of your liking.
Also notice this is a yaml
file and it is not using our previous
installed dockerfile-mode
but yaml-mode
.
Once again, we could issue a shell
command like:
docker-compose up -d
or
podman-compose up -d
Fortunately docker
package also provides us with a nice frontend for
managing docker-compose
.
Issue M-x docker RET
once again, see the last option C
.
We are presented with all sorts of options regarding docker-compose
:
We are choosing B
for build, and them A
for all services. Note
this example has one service, but docker-compose
really shines
in a use case of several services, like backend-api
, plus
database
, plus frontend
, and so on.
Again, we wait for a complete build.
When finished we again issue M-x docker RET
, C
for compose and R
to run.
Again, add any other custom configuration and hit R RET
to run it.
And there we have it, our own little cluster is up!
From now on you can figure out what to do 😉.
All the covered code
Here it is all the presented code, for a quicker copy-paste.
(defcustom lemacs-docker-executable 'docker
"The executable to be used with docker-mode."
:type '(choice
(const :tag "docker" docker)
(const :tag "podman" podman))
:group 'lemacs)
(use-package docker
:defer t
:ensure t
:bind ("C-c d" . docker)
:config
(pcase lemacs-docker-executable
('docker
(setf docker-command "docker"
docker-compose-command "docker-compose"))
('podman
(setf docker-command "podman"
docker-compose-command "podman-compose"))))
(use-package dockerfile-mode
:defer t
:ensure t
:config
(pcase lemacs-docker-executable
('docker
(setq dockerfile-mode-command "docker"))
('podman
(setq dockerfile-docker-command "podman"))))
(use-package yaml-mode
:defer t
:ensure t
:mode
("\\.yaml\\'" "\\.yml\\'")
:custom-face
(font-lock-variable-name-face ((t (:foreground "#cba6f7"))))
:config)
Conclusion
In this blog post, we explored how to effectively set up Emacs for
Docker and Docker-Compose management, leveraging the power of
docker.el
to streamline container orchestration within our
development environment. From building Docker images to running and
managing containers seamlessly, Emacs provides an efficient interface
that enhances productivity and simplifies workflows.
By integrating yaml-mode
, we ensured that our docker-compose.yml
files are easy to read and edit, allowing us to focus on coding rather
than configuration. With these tools at our disposal, we can harness
the full potential of containerization directly from our favorite text
editor.
We encourage you to explore the myriad options available within docker.el and Docker-Compose to tailor your Emacs setup even further. Happy coding, and may your containers run smoothly!
Edit
2024-11-05: Updated from when
to pcase
logic style and removed
not required mode load for dockerfile-mode
. References, suggestions, credits:
Reddit (r/emacs)