Infrastructure Setup on Ionos
This page describes the full deployment setup I use on my Ionos VPS. It’s based on Traefik, Docker Compose, Kafka (KRaft), Spring Boot Admin, and Spring Boot image-build.
Everything runs inside a single network called ccpp-network.
Docker Compose
Below is the full Compose file, including Traefik labels, Kafka, frontend, API Gateway, microservices, and Spring Boot Admin.
services:
discovery:
image: ghcr.io/jbonifay/discovery:latest
ports:
- "8761:8761"
networks:
- ccpp-network
api-gateway:
image: ghcr.io/jbonifay/api-gateway:latest
environment:
EUREKA_CLIENT_SERVICEURL_DEFAULTZONE: http://discovery:8761/eureka
JWT_SECRET: ${JWT_SECRET}
labels:
- "traefik.enable=true"
- "traefik.http.routers.api-gateway.rule=Host(`ccpp.joffreybonifay.fr`) && PathPrefix(`/api`)"
- "traefik.http.routers.api-gateway.entrypoints=websecure"
- "traefik.http.routers.api-gateway.tls.certresolver=letsencrypt"
- "traefik.http.routers.api-gateway.priority=10"
- "traefik.http.middlewares.api-stripprefix.stripprefix.prefixes=/api"
- "traefik.http.routers.api-gateway.middlewares=api-stripprefix"
- "traefik.http.services.api-gateway.loadbalancer.server.port=8080"
networks:
- ccpp-network
project-planning:
image: ghcr.io/jbonifay/project-planning:latest
environment:
SPRING_KAFKA_BOOTSTRAP_SERVERS: kafka:9092
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/project-planning
SPRING_DATASOURCE_USERNAME: ${DB_USER}
SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD}
EUREKA_CLIENT_SERVICEURL_DEFAULTZONE: http://discovery:8761/eureka
depends_on:
- kafka
networks:
- ccpp-network
workspace:
image: ghcr.io/jbonifay/workspace:latest
environment:
SPRING_KAFKA_BOOTSTRAP_SERVERS: kafka:9092
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/workspace
SPRING_DATASOURCE_USERNAME: ${DB_USER}
SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD}
EUREKA_CLIENT_SERVICEURL_DEFAULTZONE: http://discovery:8761/eureka
depends_on:
- kafka
networks:
- ccpp-network
ideation:
image: ghcr.io/jbonifay/ideation:latest
environment:
SPRING_KAFKA_BOOTSTRAP_SERVERS: kafka:9092
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/ideation
SPRING_DATASOURCE_USERNAME: ${DB_USER}
SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD}
EUREKA_CLIENT_SERVICEURL_DEFAULTZONE: http://discovery:8761/eureka
depends_on:
- kafka
networks:
- ccpp-network
notification:
image: ghcr.io/jbonifay/notification:latest
environment:
SPRING_KAFKA_BOOTSTRAP_SERVERS: kafka:9092
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/notification
SPRING_DATASOURCE_USERNAME: ${DB_USER}
SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD}
EUREKA_CLIENT_SERVICEURL_DEFAULTZONE: http://discovery:8761/eureka
depends_on:
- kafka
networks:
- ccpp-network
user-management:
image: ghcr.io/jbonifay/user-management:latest
environment:
SPRING_KAFKA_BOOTSTRAP_SERVERS: kafka:9092
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/user-management
SPRING_DATASOURCE_USERNAME: ${DB_USER}
SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD}
EUREKA_CLIENT_SERVICEURL_DEFAULTZONE: http://discovery:8761/eureka
JWT_SECRET: ${JWT_SECRET}
depends_on:
- kafka
networks:
- ccpp-network
# admin-server:
# image: ghcr.io/jbonifay/spring-boot-admin:latest
# environment:
# - SPRING_BOOT_ADMIN_CONTEXT_PATH=/admin
# labels:
# - "traefik.enable=true"
# - "traefik.http.routers.admin.rule=Host(`ccpp.joffreybonifay.fr`) && PathPrefix(`/admin`)"
# - "traefik.http.routers.admin.entrypoints=websecure"
# - "traefik.http.routers.admin.tls.certresolver=letsencrypt"
# - "traefik.http.routers.admin.priority=10"
# - "traefik.http.services.admin.loadbalancer.server.port=8080"
# networks:
# - ccpp-network
kafka:
image: confluentinc/cp-kafka:latest
environment:
# KRaft mode settings
KAFKA_NODE_ID: 1
KAFKA_PROCESS_ROLES: "broker,controller"
KAFKA_CONTROLLER_QUORUM_VOTERS: "1@kafka:9093"
KAFKA_CONTROLLER_LISTENER_NAMES: "CONTROLLER"
# TODO: verify why
# Listeners: one for Docker network, one for host
KAFKA_LISTENERS: "INTERNAL://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093"
KAFKA_ADVERTISED_LISTENERS: "INTERNAL://kafka:9092,CONTROLLER://kafka:9093"
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: "INTERNAL:PLAINTEXT,CONTROLLER:PLAINTEXT"
KAFKA_INTER_BROKER_LISTENER_NAME: "INTERNAL"
# Cluster settings
CLUSTER_ID: "MkU3OEVBNTcwNTJENDM2Qk"
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
KAFKA_NUM_PARTITIONS: 1
# Log settings
KAFKA_LOG_DIRS: "/tmp/kraft-combined-logs"
networks:
- ccpp-network
kafka-ui:
image: provectuslabs/kafka-ui:latest
ports:
- "8762:8080"
environment:
KAFKA_CLUSTERS_0_NAME: "local"
KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: "kafka:9092"
networks:
- ccpp-network
postgres:
image: postgres:latest
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d postgres"]
interval: 5s
timeout: 5s
retries: 5
# volumes:
# - ./init-scripts:/docker-entrypoint-initdb.d
networks:
- ccpp-network
volumes:
postgres_data:
networks:
ccpp-network:
# external: true
Spring Boot Admin: Monitoring and Management
Spring Boot Admin provides:
- Real-time monitoring of all Spring Boot microservices
- Health status and metrics visualization
- Application logs and environment information
- Accessible at
/adminpath through Traefik
The admin server automatically discovers and monitors:
- API Gateway
- Project Planning service
- Workspace service
- Ideation service
- Notification service