This note describes my development environment featuring VS Code and a permanent docker container.
Rather than deal with handling different environments depending on the computer I was using to develop on, I decided to migrate my development environment to my home lab. This also gave me some good practice setting up and running a service that doesn’t need to have high-availability like some of the services I plan to run in the future.
Creating the Dockerfile
To begin, I need to define what my development environment looks like. Docker describes containers using a Dockerfile, which is a text file that contains statements describing how to build a container. There are many Dockerfiles available on the internet to use as inspiration.
My development environment uses Debian Unstable with a few tools. The complete
Dockerfile can be seen below, but I’ll describe the major points first. I begin
with a FROM
statement to grab the latest Debian Unstable Docker image, add
myself as a maintainer, and then install packages that I want to use. I also
want to use Node, but I manage that via NVM instead of apt. Because I’m using
NVM, I need to add the Node binary to my path.
FROM debian:unstable-slim
LABEL maintainer="Nicholas Nooney <nicholasnooney@gmail.com>"
RUN apt update && apt install -y -q --no-install-recommends \
apt-transport-https \
build-essential \
ca-certificates \
curl \
git \
golang \
gpg \
hugo \
libssl-dev \
ssh \
wget
# Install NVM to manage node
ENV NVM_DIR /usr/local/nvm
ENV NODE_VERSION 16.3.0
WORKDIR ${NVM_DIR}
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh \
| bash \
&& . ${NVM_DIR}/nvm.sh \
&& nvm install ${NODE_VERSION} \
&& nvm alias default ${NODE_VERSION} \
&& nvm use default
ENV PATH ${NVM_DIR}/versions/node/v${NODE_VERSION}/bin:${PATH}
With this Dockerfile, I can build an image of my development environment. I can
upload the image to
Docker Hub and
then use Docker to instantiate a container that runs on my home lab. As with the
other services on my home lab, the development environment is described with a
docker-compose.yml
file.
version: "3.8"
networks:
traefik-public:
external: true
volumes:
developer:
driver: local-persist
driver_opts:
mountpoint: /mnt/lab/developer
services:
devbox:
image: "nicholasnooney/devbox"
hostname: "devbox"
networks:
- traefik-public
volumes:
- developer:/developer
labels:
- "traefik.enable=true"
- "traefik.http.routers.devbox.rule=Host(`${FQDN}`)"
- "traefik.http.routers.devbox.entrypoints=websecure"
- "traefik.http.routers.devbox.tls=true"
- "traefik.http.services.devbox.loadbalancer.server.port=80"
tty: true
stdin_open: true
With a single command I can connect to my development environment running on my home lab!
docker-compose config | docker -H ssh://docker.nooney.casa stack deploy -c - devbox
Automation
I’d prefer not to have to worry about updates for my development environment. I know that this may result in the occasional breakage, but I think it’s an acceptable trade off. In order to ensure my image is up to date, I need to rebuild the image and then update the container on my home lab.
Rebuilding the Image
I host the Dockerfile that defines my environment in a git repository on GitHub. Using a GitHub action, I rebuild the image when the following events occur:
- I push an update on the
main
branch to GitHub. - I manually trigger the rebuild.
- Every 24 hours.
They trigger the following workflow:
name: CI
on:
push:
branches: [ main ]
schedule:
- cron: 0 0 * * *
workflow_dispatch:
jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
-
name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and push
id: docker_build
uses: docker/build-push-action@v2
with:
pull: true
push: true
tags: nicholasnooney/devbox:latest
-
name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}
With this GitHub action, the image is updated and pushed to Docker Hub daily.
Updating the Container
Currently, I manually update the development container running on my home lab. In the future, I’ll explore options to make automatic updates possible.