DEV Community

arctic_hen7
arctic_hen7

Posted on

Setting up ZSH in Docker

I love ZSH. I love my colorful terminal prompts, I love my indicators, I love my icons. That's all very well on my computer, but what about inside Docker containers?

Well, turns out it's actually really easy to set up ZSH in Docker, it just requires a bit of doing. This post will explain how to do just that! I'll use a non-root user because that's safer, but if you want to use root to do everything, just ignore the user switching and permissions changing, it should all work fine.

I've set this up as a multi-stage build layer, but you can get rid of the AS setup in the first line if you want to do something else.

TL;DR: Here's the Gist! (If you're using NodeJS, there's a special one for you here!)

Let's break that down. We start off by using the Alpine Linux image, but this should work for any Linux image, you might just need to modify apk add to be apt install or something else. If you're using NodeJS in Docker, use node:14-alpine instead.

FROM alpine:latest AS setup
Enter fullscreen mode Exit fullscreen mode

Then we set the environment variable RUNNING_IN_DOCKER to true. I do this with all my Dockerfiles just because it's sometimes really useful to be able to tell easily if a script is running in Docker or on the host (e.g. testing automatically before a commit made in the container vs through VS Code on the host).

ENV RUNNING_IN_DOCKER true
Enter fullscreen mode Exit fullscreen mode

Next, we create a new unprivileged user called main for security (using -D to not give a password). Then we just create a a folder to put our app in, and give ownership of it to that user.

RUN adduser -D main
RUN mkdir -p /app \
    && chown -R main:main /app
Enter fullscreen mode Exit fullscreen mode

if you're using NodeJS, don't bother creating a new user, you already have the node user created for you by the NodeJS base image. That user also already has the setup to install packages without any extra config. Just get rid of the first line and change main:main to node:node.

After that, we install the dependencies for ZSH and then download Antigen (used for managing ZSH plugins) from GitHub.

RUN apk --no-cache add zsh curl git
RUN mkdir -p /home/main/.antigen
RUN curl -L git.io/antigen > /home/main/.antigen/antigen.zsh
Enter fullscreen mode Exit fullscreen mode

With Antigen installed, we copy over our ZSH configuration, which I like to store in .dockershell.sh, but it will be copied to .zshrc in the container. I have an example configuration in this Gist if you need inspiration!

COPY .dockershell.sh /home/main/.zshrc
Enter fullscreen mode Exit fullscreen mode

Then we just give the main user ownership of both the Antigen config and .zshrc.

RUN chown -R main:main /home/main/.antigen /home/main/.zshrc
Enter fullscreen mode Exit fullscreen mode

Now, we can actually run ZSH, which will automatically pull everything we need to fulfill our configuration! This may take some time depending on how complex your config is, but after you've done it once, it's the same for every other container that ever uses it! Also note that you will have to rebuild whenever you change your ZSH config of course. Anyway, we run ZSH as the main user so it sets it up with the right permissions (that's the user we'll interact with the container with). After that, we switch back to root for any remaining stages.

USER main
RUN /bin/zsh /home/main/.zshrc
USER root
Enter fullscreen mode Exit fullscreen mode

And that'll give you ZSH in Docker! Just remember to add this when you want a prompt:

ENTRYPOINT [ "/bin/zsh" ]
Enter fullscreen mode Exit fullscreen mode

Here are three Gists that might help in getting everything operational:

Thanks for reading! Happy ZSHing! 👋

Discussion (0)