Skip to content

Dockerλ︎

Docker enables a consistent approach to building and running Clojure projects along with a range of other services locally (database, cache, streams, etc.), The Clojure project is built from source when starting services (a watch feature can rebuild on code changes). Heath checks and conditions are set to ensure dependant services start in the correct order.

Running Docker is relatively fast once image overlays (layers) are cached on their first run, so its a viable approach for local system integration testing and acceptance testing, before pushing changes to a remote Continuous Integration service.

A Docker workflow complements a REPL Driven Development workflow, it does not replace it. The main development effort should still be done via a REPL connected editor, with Docker Compose focused on orchestration of services.

General Workflowλ︎

Try the Docker getting started tutorial

Follow the Docker Getting Started tutorial from within Docker Desktop or via the command line.

docker run -d -p 80:80 docker/getting-started

Docker Desktopλ︎

Docker desktop provides an easy way to manage Docker images, containers and volumes. Sign in to Docker Desktop to manage your images on DockerHub.

Docker Desktop - images view

There is a growing marketplace of extensions that provide very useful tools to extend the capabilities of Docker Desktop. Search within the Docker Desktop extensions or for extensions on Docker Hub.

  • Resource Usage monitor resources (cpu, memory, network, disk) used by containers and docker compose systems over time
  • Disk Usage optimise use of local disk space by removing unused images, containers and volumes
  • Volumes Backup & Share to backup, clone, restore and share Docker volumes easily
  • Logs Explorer view all container logs in one place to assist troubleshooting
  • Postgres Admin PGAdmin4 open source management tool for Postgres
  • Trivy scan local and remote images for security vulnerabilities
  • Snyk scan local and remote images for security vulnerabilities
  • Ddosify high-performance, open-source and simple load testing tool

Docker Desktop extension - disk usage

Choosing Docker Imagesλ︎

Docker Official Images from Docker Hub are highly recommended. Look for the Docker Official Image tag on the image page.

Docker Official Image Tag

  • Clojure - official Docker Image - built by the Clojure community, provides tools to build Clojure projects (Clojure CLI, Leiningen)
  • Eclipse temurin OpenJDK - official Docker image - built by the community - provides the Java run-time
  • Amazon Corretto is an OpenJDK distribution by Amazon AWS team, Amazon Corretto can also be installed for the local development environment
  • Postgres open-source object-relational database management system
  • Redis open-source, networked, in-memory, key-value data store with optional durability
  • nginx open source reverse proxy & load balancing for HTTP, HTTPS, SMTP, POP3 & IMAP protocols, HTTP cache and a web server
  • mariadb open source relational database by the original developers of MySQL and is much more efficient
Docker Official Image meaning

An Official Docker Image means the configuration of that image follows the Docker recommended practices, is well documented and designed for common use cases.

There is no implication as to the correctness of tools, languages or service that image provides, only in the means in which they are provided.

However, if time was invested in creating an image good enough to pass the Docker review, then it has a higher probability of being a useful image that others that are not official.

Dockerfile Designλ︎

Dockerfile design in detail

A multi-stage Dockerfile contains builder stage and an unnamed stage used as the run-time. Optionally, the configuration can use a base image which both build and run-time stages extend.

The builder stage caches dependencies to optimise building Clojure and the run-time stage optimises running the service efficiently and securely.

The uberjar created by the builder image is copied over to the run-time image to keep that image as clean and small as possible (to minimise resource use).

Docker Multi-stage build file with cached overlays

Docker init - beta feature

docker init is a new (beta) feature to create Dockerfile, .dockerignore andcompose.yaml files using Docker recommended practices.

Compose servicesλ︎

Define a compose.yaml file that builds the Clojure project and run services that the Clojure service requires or talks too (database, cache, mock API, etc.).

Each service can define a heart beat which can be used as a conditional startup for other services.

compose.yaml new Compose configuration file

compose.yaml is the new configuration file for orchestrating services locally, a simplified and extended version of docker-compose.yaml.

Include the build: option for the Clojure service with the path to the multi-stage Dockerfile for the project (typically in the same root directory of the project, although a remote Git repository can also be used)

The Clojure service defines a dependency on a Postgres Database. The dependency has a condition so the Clojure service is only started once the Postgres service is healthy

Clojure Service with Postgres Database

services:
  clojure-service:
    platform: linux/amd64
    build: ./
    ports: # host:container
      - 8080:8080
    depends_on:
      postgres-database:
        condition: service_healthy

  postgres-database:
    image: postgres:15.2-alpine
    environment:
      POSTGRES_PASSWORD: "$DOCKER_POSTGRES_ROOT_PASSWORD"
    healthcheck:
      test: [ "CMD", "pg_isready" ]
      timeout: 45s
      interval: 10s
      retries: 10
    ports:
      - 5432:5432

Run the services using docker from the root of the project

docker compose up --build

File watcherλ︎

Docker provides watch as an experimental feature which can rebuild the Clojure service when a file change is detected. This seems most useful when troubleshooting issues that occur during system integration testing.

Add an x-develop configuration with watch under the Clojure service configuration

Automated rebuild on file change

    x-develop:
      watch:
        - path: ./deps.edn
          action: rebuild
        - path: ./src
          action: rebuild

Start the services and the file watch mode

docker compose up --detach && docker compose alpha watch

Save changes to files and a new image for the Clojure service will be built and deployed when ready.

Summaryλ︎

Docker desktop provides lots of tools to support local system integration work before code is sent to a continuous integration service (or as a temporary alternative if that CI service id down)

Practicalli Project Templates include Dockerfile, .dockerignore and compose.yaml configurations for Clojure development, kick-starting the use of Docker.

Docker images are a relatively clean way of trying out different services or even different operating systems, e.g.Ubuntu or ArchLinux. Deleting the images removes the whole service without affecting the underlying operating system.

MegaLinter is an excellent example of a docker image that provides a large number of tools that would otherwise need to be installed directly on the operating system.


Last update: May 16, 2023