wissel.net

Usability - Productivity - Business - The web - Singapore & Twins

Development Containers - the fine print


Development Containers are supposed to liberate your development environment from a specific local installation, like container technology liberated your runtimes (a.k.a YAMLed them into Docker or Kubernetes).

Helmchart Pun

Development != Runtime

Containerization for development has some overlap and quite some difference to containerization for production:

Topic Development Production
Mutability You alter container content Container is static
Network Use internal network Use internal network
Access Developer tools++ Browser / App
Containers multiple multiple
Volumes primary container binds projectdir
all others mount only
all: bind or mount
Configuration devcontainer.json, docker-compose.yml docker-compose.yml,Helm Chart
Scope Runtime & Tooling Runtime
Dockerfile Setup development environment Configure production

Insights

  • There are many getting started resources available: here, here, here, here and here. They are working examples, commonly strong on what and how, but light on why
  • There are plenty of templates to learn by example
  • There seem to be substantial differences how it works on different platforms, subtle and annoying
  • On macOS (14.4.1) with with the devcontainer plugin 0.364.0 mount binds would not work in auxiliary containers, only in the main app
  • I couldn't find any descrption which subset of docker-compose.yml is supported
  • The most interesting templates, for now, live on the Microsoft Artifact Registry, when you know how to look. Starting with those saves you tons of time and frustration
  • You will love code --list-extensions to figure out the extensions you have in your vscode (unless you are a code n00b and don't have any)

A practical example

You need some kind of Docker, Rancher or Podman Desktop, Visual Studio Code and the Remote Development Extension Pack. You know how to install all this.

Planning

We need to configure the environment, to make it more ~~powerfull~~ confusing, you can add:

So we have a few places where e.g. npm install could live, or tooling.

We will setup a Dockerfile, a docker-compose.yml and the devcontainer.json, all three located in .devcontainer. Make sure to add this to git, it's kind of the point to share this setup with others, including your future self. Devcontainers are infrastructure as code for developers. So besides your code and servers, you have your tooling and settings in one place. Let's start with the simple one:

Dockerfile

FROM mcr.microsoft.com/devcontainers/javascript-node:dev-20-bookworm
RUN su node -c "npm install -g npm-check-updates nodemon vite"

docker-compose.yml

In the example we have one service (our code)and one NoSQL database.

services:
  app:
    container_name: nodejs
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - ../..:/workspaces:cached
    volumes_from:
      - couchdb:rw
    command: sleep infinity
    network_mode: service:couchdb
    depends_on:
      - couchdb
  couchdb:
    image: couchdb:latest
    container_name: couchdb
    environment:
      COUCHDB_USER: admin
      COUCHDB_PASSWORD: password
    volumes:
      - type: volume
        source: couchdb_etc
        target: /opt/couchdb/etc
      - type: volume
        source: couchdb_data
        target: /opt/couchdb/data
      - type: volume
        source: couchdb_logs
        target: /opt/couchdb/logs
    restart: unless-stopped
volumes:
  couchdb_data:
  couchdb_etc:
  couchdb_logs:
  • the volume syntax is ../..:/workspaces:cached to mount the workspace
  • volumes_from is used to get easy access to the couchDB inin configuration
  • command: sleep infinity is necessary to prevent the container from exiting
  • network_mode enforces one network setting. To reach it from the outside, you need and entry in devcontainer.json

devcontainer.json

{
  "name": "Node.js & couch",
  "dockerComposeFile": "docker-compose.yml",
  "service": "app",
  "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
  "features" : {
    "ghcr.io/devcontainers/features/common-utils:2" : {},
    "ghcr.io/devcontainers/features/github-cli:1": {},
    "ghcr.io/devcontainers/features/sshd:1": {}
  },
  "postCreateCommand": "yarn install",
  "customizations": {
    "vscode": {
      "extensions": [
        "esbenp.prettier-vscode",
        "msjsdiag.debugger-for-chrome",
        "oderwat.indent-rainbow",
        "visualstudioexptteam.vscodeintellicode",
        "ritwickdey.liveserver",
        "shengchen.vscode-checkstyle",
        "sketchbuch.vsc-quokka-statusbar"
        "WallabyJs.quokka-vscode",
        "WallabyJs.wallaby-vscode"
      ]
    }
  },
  "forwardPorts": [3000, 5984]
}

In a future post, I'll cover a setup with more than one application / service.

As usual YMMV


Posted by on 12 May 2024 | Comments (0) | categories: Container Docker Java NodeJS WebDevelopment

Comments

  1. No comments yet, be the first to comment