Gatsby Dev Container Refactored

December 23, 2024#Tools
Article
Author image.

Sarah Dutkiewicz, Senior Trainer

In our post on Running Gatsby in a Dev Container, we set up a dev container running a non-root user. While prepping for our Dev Containers Unwrapped! webinar, I ended up simplifying our dev container to show how we can run that container as a root user. I also refactored some of the variables from the Dockerfile into their respective spots in the devcontainer.json file. So let’s talk about those changes.

You can see this whole process in our Dev Containers Unwrapped! webinar on YouTube!

Starting Dockerfile

This is our starting Dockerfile:

FROM node:20.10.0
# Install basic development tools
RUN apt update && apt install -y less man-db sudo
# Ensure default `node` user has access to `sudo`
ARG USERNAME=node
RUN echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
    && chmod 0440 /etc/sudoers.d/$USERNAME
# Install the Gatsby CLI
RUN npm install -g gatsby-cli --unsafe-perm=true --allow-root
# Set `DEVCONTAINER` environment variable to help with orientation
ENV DEVCONTAINER=true
# Use this to enable polling when Docker is used
ENV CHOKIDAR_USEPOLLING=true
# This is also used for Hot Module Reloading with Gatsby
ENV INTERNAL_STATUS_PORT=5001

When we change from a non-root user to the default root user setup, we don’t need to do some of the stuff here. There are other settings in the Dockerfile that I put there because that was where happened to be when I realized I needed to add those settings. However, those can be refactored into devcontainer.json as well. So we’ll break this up slowly.

Remove the Non-Root User Stuff

Let’s focus on the part we need to remove. In this diff, I’ve highlighted the non-root user parts to be removed.

FROM node:20.10.0
- # Install basic development tools
- RUN apt update && apt install -y less man-db sudo
- # Ensure default `node` user has access to `sudo`
- ARG USERNAME=node
- RUN echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
-    && chmod 0440 /etc/sudoers.d/$USERNAME
# Install the Gatsby CLI
RUN npm install -g gatsby-cli --unsafe-perm=true --allow-root
# Set `DEVCONTAINER` environment variable to help with orientation
ENV DEVCONTAINER=true
# Use this to enable polling when Docker is used
ENV CHOKIDAR_USEPOLLING=true
# This is also used for Hot Module Reloading with Gatsby
ENV INTERNAL_STATUS_PORT=5001

These changes include:

  • No need to install sudo.
  • No need to grant a node user to sudo.

So Dockerfile now looks like this:

FROM node:20.10.0
# Install the Gatsby CLI
RUN npm install -g gatsby-cli --unsafe-perm=true --allow-root
# Set `DEVCONTAINER` environment variable to help with orientation
ENV DEVCONTAINER=true
# Use this to enable polling when Docker is used
ENV CHOKIDAR_USEPOLLING=true
# This is also used for Hot Module Reloading with Gatsby
ENV INTERNAL_STATUS_PORT=5001

Now let’s move things - most to devcontainer.json, with a deletion as well.

Current devcontainer.json

This is our current devcontainer.json:

{
	"name": "SITE_NAME Gatsby blog",
	"build": {
		"dockerfile": "Dockerfile"
	},
  "appPort": [8000,9000],
  "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind",
  "workspaceFolder": "/workspace",
  "remoteUser": "node",
  "mounts": [
    "source=${localWorkspaceFolderBasename}-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume"
  ],
  "runArgs": ["--name","SITE_NAME_gatsby_devcontainer"],
  "postCreateCommand": "sudo chown node ${containerWorkspaceFolder}/node_modules && sudo npm install --legacy-peer-deps && sudo npx playwright install-deps",
  "postStartCommand": "npx playwright install && gatsby clean && gatsby develop --host 0.0.0.0"
}

Move Environment Variables to devcontainer.json

The first part I want to move from the Dockerfile is the environment variables. They could either go in containerEnv or remoteEnv in devcontainer.json. I lean towards containerEnv because I want the changes on the container itself. remoteEnv applies only to the VS Code server process running in the container and won’t be seen by a background process that starts in the container. See more in this GitHub issue on containerEnv or remoteEnv.

So… what do these changes look like? Let’s start with the devcontainer.json:

{
	"name": "SITE_NAME Gatsby blog",
	"build": {
		"dockerfile": "Dockerfile"
	},
  "appPort": [8000,9000],
  "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind",
  "workspaceFolder": "/workspace",
  "remoteUser": "node",
  "mounts": [
    "source=${localWorkspaceFolderBasename}-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume"
  ],
+   "containerEnv": {
+    // Use this to help with orientation
+    "DEVCONTAINER":"true",
+   // Use this to enable polling when Docker is used
+   "CHOKIDAR_USEPOLLING":"true",
+   // This is also used for Hot Module + Reloading with Gatsby
+    "INTERNAL_STATUS_PORT":"5001"
+  },
  "runArgs": ["--name","SITE_NAME_gatsby_devcontainer"],
  "postCreateCommand": "sudo chown node ${containerWorkspaceFolder}/node_modules && sudo npm install --legacy-peer-deps && sudo npx playwright install-deps",
  "postStartCommand": "npx playwright install && gatsby clean && gatsby develop --host 0.0.0.0"
}

Now let’s remove that out of the Dockerfile:

FROM node:20.10.0
# Install the Gatsby CLI
RUN npm install -g gatsby-cli --unsafe-perm=true --allow-root
-# Set `DEVCONTAINER` environment variable to help with orientation
-ENV DEVCONTAINER=true
-# Use this to enable polling when Docker is used
-ENV CHOKIDAR_USEPOLLING=true
-# This is also used for Hot Module Reloading with Gatsby
-ENV INTERNAL_STATUS_PORT=5001

That leaves our Dockerfile with:

FROM node:20.10.0
# Install the Gatsby CLI
RUN npm install -g gatsby-cli --unsafe-perm=true --allow-root

Moving the rest of the Dockerfile

Now let’s move those last 2 things from the Dockerfile into devcontainer.json:

{
	"name": "SITE_NAME Gatsby blog",
-	"build": {
-		"dockerfile": "Dockerfile"
-	},
+ "image": "node:20.10.0",
  "appPort": [8000,9000],
  "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind",
  "workspaceFolder": "/workspace",
  "remoteUser": "node",
  "mounts": [
    "source=${localWorkspaceFolderBasename}-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume"
  ],
+   "containerEnv": {
+    // Use this to help with orientation
+    "DEVCONTAINER":"true",
+   // Use this to enable polling when Docker is used
+   "CHOKIDAR_USEPOLLING":"true",
+   // This is also used for Hot Module + Reloading with Gatsby
+    "INTERNAL_STATUS_PORT":"5001"
+  },
  "runArgs": ["--name","SITE_NAME_gatsby_devcontainer"],
- "postCreateCommand": "sudo chown node ${containerWorkspaceFolder}/node_modules && sudo npm install --legacy-peer-deps && sudo npx playwright install-deps",
+ "postCreateCommand": "npm install -g gatsby-cli --unsafe-perm=true --allow-root && npm install --legacy-peer-deps && npx playwright install-deps",
  "postStartCommand": "npx playwright install && gatsby clean && gatsby develop --host 0.0.0.0"
}

At this point, you can delete the Dockerfile.

Summary

In our previous post, we set up a dev container with a non-root user since some companies may have policies that require that. When you have a non-root user, you need to make sure they have permissions to install things and update things (such as the node_modules folder). You need to find ways to script those.

By default, many containers default to running as a root user, including the node image. So in this post, we pulled out the non-root user changes.

In the last post, we also had things in our Dockerfile that were put there because that’s where I was when I found those settings. We refactored those to devcontainer.json because that is possible. With that, we also have a simplified dev container setup!

Additional Links


Copyright © 2024 NimblePros - All Rights Reserved