Skip to content

AmmannChristian/docker-service-manager

Repository files navigation

Docker Service Manager

CI codecov License: MIT

A REST API for managing Docker containers, built with Quarkus. This service provides endpoints for container lifecycle management including starting, stopping, restarting, and updating containers, as well as log streaming capabilities via Server-Sent Events.

Table of Contents

Documentation

Detailed technical documentation is available in the docs/ directory:

  • Architecture Overview -- System design, component relationships, request processing flows, and deployment architecture with Mermaid diagrams
  • API Reference -- Complete REST API specification including endpoint details, request/response schemas, error formats, and authentication requirements

Features

  • Container lifecycle management (start, stop, restart, update)
  • Container listing with filtering options
  • Log retrieval and real-time log streaming via SSE
  • Service blacklist for protecting critical containers
  • OpenID Connect authentication with ZITADEL support
  • Role-based access control
  • OpenAPI documentation
  • Health checks on dedicated management port
  • Multi-architecture Docker images (amd64, arm64)
  • Native executable support via GraalVM

Requirements

  • Java 21 or later
  • Maven 3.9 or later
  • Docker Engine (for container management)
  • OIDC Provider (ZITADEL recommended, but any compliant provider works)

Quick Start

  1. Clone the repository:
git clone https://github.com/AmmannChristian/docker-service-manager.git
cd docker-service-manager
  1. Configure the OIDC settings (see Configuration section below).

  2. Run in development mode:

./mvnw quarkus:dev

The API will be available at http://localhost:9080. The Quarkus Dev UI is accessible at http://localhost:9080/q/dev/. Health checks are available on the management port at http://localhost:9090/q/health.

Configuration

Environment Variables

OIDC Authentication

Variable Description Required
OIDC_AUTH_SERVER_URL OIDC provider base URL Yes
OIDC_CLIENT_ID OAuth2 client ID Yes
OIDC_JWT_KEY_FILE Path to private key file for JWT authentication Yes
OIDC_JWT_KEY_ID Key ID for JWT signing Yes
OIDC_JWT_LIFESPAN JWT token lifespan in seconds (default: 300) No
OIDC_JWT_AUDIENCE JWT audience claim No

HTTP Server

Variable Description Default
HTTP_HOST Bind address 0.0.0.0
HTTP_PORT HTTP port 9080
HTTPS_PORT HTTPS port 9443
MANAGEMENT_PORT Management port (health checks) 9090
HTTP_CORS_ENABLED Enable CORS support true
HTTP_CORS_ORIGINS Allowed CORS origins (regex) /.*/
HTTP_CORS_METHODS Allowed HTTP methods GET,POST,PUT,DELETE,OPTIONS
HTTP_CORS_HEADERS Allowed request headers accept,authorization,content-type,x-requested-with
HTTP_CORS_EXPOSED_HEADERS Headers exposed to clients content-disposition
HTTP2_ENABLED Enable HTTP/2 support true

Service Protection

Variable Description Default
SERVICE_BLACKLIST Comma-separated list of protected containers (by ID, name, or image) ``

The blacklist protects critical containers from being stopped, restarted, or updated via the API. Matching is performed against container ID, container name, and image name. Requests to modify blacklisted containers return HTTP 403 Forbidden.

Example Configuration

Create a .env file or set environment variables:

export OIDC_AUTH_SERVER_URL=https://your-zitadel-instance.com
export OIDC_CLIENT_ID=your-client-id
export OIDC_JWT_KEY_FILE=/path/to/private-key.json
export OIDC_JWT_KEY_ID=your-key-id

# Optional: Protect critical infrastructure containers
export SERVICE_BLACKLIST=traefik,docker-socket-proxy-ro,docker-socket-proxy-rw

Docker Socket Access

The application requires access to the Docker socket. When running in Docker, mount the socket:

docker run -v /var/run/docker.sock:/var/run/docker.sock your-image

API Reference

All endpoints require authentication and the ADMIN_ROLE role.

Base URL

/api/v1/containers

Endpoints

Method Path Description
GET / List all containers
POST /{id}/start Start a container
POST /{id}/stop Stop a container
POST /{id}/restart Restart a container
POST /{id}/update Pull latest image and recreate container
GET /{id}/logs Get container logs
GET /{id}/logs/stream Stream container logs via SSE

List Containers

curl -X GET "http://localhost:9080/api/v1/containers?all=true" \
  -H "Authorization: Bearer <token>"

Query parameters:

  • all (boolean, default: false): Include stopped containers

Start Container

curl -X POST "http://localhost:9080/api/v1/containers/{containerId}/start" \
  -H "Authorization: Bearer <token>"

Stop Container

curl -X POST "http://localhost:9080/api/v1/containers/{containerId}/stop" \
  -H "Authorization: Bearer <token>"

Restart Container

curl -X POST "http://localhost:9080/api/v1/containers/{containerId}/restart" \
  -H "Authorization: Bearer <token>"

Update Container

Pulls the latest version of the container image and recreates the container with the same configuration.

curl -X POST "http://localhost:9080/api/v1/containers/{containerId}/update" \
  -H "Authorization: Bearer <token>"

Get Container Logs

curl -X GET "http://localhost:9080/api/v1/containers/{containerId}/logs?tail=100" \
  -H "Authorization: Bearer <token>"

Query parameters:

  • tail (integer, default: 100, range: 1-10000): Number of log lines to return

Stream Container Logs

curl -X GET "http://localhost:9080/api/v1/containers/{containerId}/logs/stream?follow=true" \
  -H "Authorization: Bearer <token>" \
  -H "Accept: text/event-stream"

Query parameters:

  • follow (boolean, default: true): Continue streaming new log entries

OpenAPI Documentation

When running the application, the OpenAPI specification is available at:

  • Swagger UI: http://localhost:9080/q/swagger-ui
  • OpenAPI JSON: http://localhost:9080/q/openapi

Authentication

The application uses OpenID Connect for authentication. It supports both JWT tokens (verified locally) and opaque tokens (verified via introspection).

ZITADEL Integration

This application includes a custom security identity augmentor that extracts roles from ZITADEL-specific JWT claims:

  • urn:zitadel:iam:org:project:roles - Standard ZITADEL roles claim
  • urn:zitadel:iam:org:project:{projectId}:roles - Project-specific roles

The augmentor also falls back to standard claims:

  • groups - Standard groups claim
  • scope - OAuth2 scopes as roles

Required Role

All container management endpoints require the ADMIN_ROLE role.

Development

Prerequisites

  • JDK 21
  • Maven 3.9+
  • Docker (for running containers)

Running in Dev Mode

Development mode enables live coding with automatic restart on code changes:

./mvnw quarkus:dev

Code Style

The project uses Google Java Format via Spotless. To check formatting:

./mvnw spotless:check

To automatically format code:

./mvnw spotless:apply

Building

Build the application:

./mvnw package

Build without running tests:

./mvnw package -DskipTests

Running the JAR

java -jar target/quarkus-app/quarkus-run.jar

Testing

Running Tests

./mvnw test

Running Tests with Coverage

./mvnw verify

Coverage reports are generated in target/site/jacoco/.

Coverage Requirements

The project enforces a minimum line coverage of 90%. The build will fail if coverage falls below this threshold.

Docker

Building Images

The project includes a multi-stage Dockerfile with several targets:

Development image (with hot reload):

docker build --target dev -t docker-service-manager:dev .

Production image (JVM mode):

docker build --target prod -t docker-service-manager:latest .

Native image (GraalVM):

docker build --target prod-native -t docker-service-manager:native .

Running with Docker

docker run -d \
  --name docker-service-manager \
  -p 9080:9080 \
  -p 9090:9090 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e OIDC_AUTH_SERVER_URL=https://your-zitadel.com \
  -e OIDC_CLIENT_ID=your-client-id \
  -e OIDC_JWT_KEY_FILE=/keys/private-key.json \
  -e OIDC_JWT_KEY_ID=your-key-id \
  -e SERVICE_BLACKLIST=traefik,docker-socket-proxy \
  -v /path/to/keys:/keys:ro \
  docker-service-manager:latest

Docker Compose

version: '3.8'

services:
  docker-service-manager:
    image: ghcr.io/ammannchristian/docker-service-manager:latest
    ports:
      - "9080:9080"   # API port
      - "9090:9090"   # Management port (health checks)
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./keys:/keys:ro
    environment:
      OIDC_AUTH_SERVER_URL: https://your-zitadel.com
      OIDC_CLIENT_ID: your-client-id
      OIDC_JWT_KEY_FILE: /keys/private-key.json
      OIDC_JWT_KEY_ID: your-key-id
      SERVICE_BLACKLIST: traefik,docker-socket-proxy  # Protect critical containers
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9090/q/health/live"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

Pre-built Images

Multi-architecture images are available on GitHub Container Registry:

docker pull ghcr.io/ammannchristian/docker-service-manager:latest

Available tags:

  • latest - Latest build from main branch
  • x.y.z - Specific version (e.g., 1.0.0)
  • x.y - Minor version (e.g., 1.0)
  • sha-xxxxxxx - Specific commit

Project Structure

docker-service-manager/
├── src/
│   ├── main/
│   │   ├── java/com/ammann/servicemanager/
│   │   │   ├── config/          # CDI producers and configuration
│   │   │   ├── dto/             # Data transfer objects
│   │   │   ├── health/          # Health check implementations
│   │   │   ├── properties/      # Configuration properties
│   │   │   ├── resource/        # REST endpoints
│   │   │   ├── security/        # Security augmentors
│   │   │   └── service/         # Business logic
│   │   └── resources/
│   │       └── application.properties
│   └── test/
│       └── java/                # Unit and integration tests
├── .github/
│   └── workflows/               # CI/CD pipelines
├── Dockerfile                   # Multi-stage Docker build
├── pom.xml                      # Maven configuration
└── README.md

Contributing

Contributions are welcome. Please follow these steps:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/your-feature)
  3. Make your changes
  4. Ensure tests pass (./mvnw verify)
  5. Ensure code is formatted (./mvnw spotless:apply)
  6. Commit your changes
  7. Push to your branch
  8. Open a Pull Request

Please ensure your PR:

  • Includes tests for new functionality
  • Maintains or improves code coverage
  • Follows the existing code style
  • Updates documentation if needed

License

This project is licensed under the MIT License. See the LICENSE file for details.

About

REST API for Docker container lifecycle management (start, stop, restart, update, log streaming via SSE), built with Quarkus

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors