MCMMCM DocsEngineering (Internal)
Deployment
v1.2 is unreleased — see v1.1 for the current stable release.

3-Tier Architecture Reference

Detailed technical documentation of the 3-Tier Docker Swarm architecture, compose compilation, overlay networking, and container constraints.

MCM Platform — 3-Tier Swarm Internal Reference & Architecture Guide

Confidential — For Internal Operations and DevOps Engineering Teams Only.
This document details the low-level architecture, multi-node clustering mechanics, Docker Compose compilation pipeline, internal security layers, scripting engines, and overlay network topography of the MCM (Multi-Cloud Management) Platform deployed on a 3-Tier Docker Swarm.


1. High-Level Orchestration & Topography

The 3-Tier production environment consists of 26 distinct containerized services distributed across a multi-node Swarm cluster consisting of one Swarm Manager (mcm-access) and two Swarm Workers (mcm-app and mcm-db).


2. Service Inventory

The table below lists all cluster-managed services, detailing their target node labels, internal networking ports, technology stack, and description.

ServiceContainer NamePlacement LabelReplicaTech StackDescription
MCM UImcm_mcm-uinode.labels.tier == app1Next.js 16, React 19Web interface
MCM APImcm_mcm-apinode.labels.tier == app1Java 21, Spring Boot 3.4.5Core platform logic
APISIXmcm_apisixnode.labels.tier == access1Apache APISIX 3.12.0API gateway & reverse proxy
etcdmcm_etcdnode.labels.tier == access1etcd 3.5.11APISIX configuration store
Keycloakmcm_keycloaknode.labels.tier == db1Keycloak 26.3.1Identity provider (IAM/SSO)
PostgreSQLmcm_postgresnode.labels.tier == db1PostgreSQL 17.7Keycloak relational database
MongoDBmcm_mongodbnode.labels.tier == db1MongoDB 7.0.16Primary application data store
Elasticsearchmcm_elasticsearchnode.labels.tier == db1Elasticsearch 8.19.3Search and analytics engine
Kibanamcm_kibananode.labels.tier == db1Kibana 8.19.3Log dashboard visualization
Filebeatmcm_filebeatnode.labels.tier == db1Filebeat 8.19.3DB / Security log collector
Governance APImcm_mcm-governance-apinode.labels.tier == app1Java 21, Spring Boot 3.4.5Governance & compliance engine
FinOps APImcm_mcm-finops-apinode.labels.tier == app1Java 21, Spring Boot 3.4.5Financial cost analysis module
SecOps APImcm_mcm-secops-apinode.labels.tier == app1Java 21, Spring Boot 3.4.5Security operations API
Orchestration APImcm_mcm-orchestration-apinode.labels.tier == app1Java 21, Spring Boot 3.4.5IaC engine (OpenTofu)
AI APImcm_mcm-ai-apinode.labels.tier == app1Python, FastAPIChatbot service
Discovery APImcm_mcm-discovery-apinode.labels.tier == app1Java 21, Spring Boot 3.4.5Asset discovery backend
Observability APImcm_mcm-observability-apinode.labels.tier == app1Java 21, Spring Boot 3.4.5Observability manager
Fleet Servermcm_observability-fleet-servernode.labels.tier == db1Elastic Agent 8.19.3Observability fleet controller
Wazuh Managermcm_wazuh-managernode.labels.tier == db1Wazuh Manager 4.14.1SIEM coordinator
Wazuh Indexermcm_wazuh-indexernode.labels.tier == db1Wazuh Indexer 4.14.1SIEM database (OpenSearch)
Wazuh Dashboardmcm_wazuh-dashboardnode.labels.tier == db1Wazuh Dashboard 4.14.1SIEM web console

3. Docker Compose Consolidation & Compilation Deep Dive

The installer does not deploy raw Docker Compose files. Instead, it consolidates four independent configuration sources into a single optimized deployment stack file (/opt/mcm/docker-compose-stack.yml).

3.1 The Merging Command

During installation or upgrade, the script runs the following command on VM1:

docker compose \
  --env-file /opt/mcm/internal_config.env \
  --env-file /etc/mcm/secrets.env \
  --env-file /etc/mcm/user_config.env \
  -f /opt/mcm/docker-compose-access.yml \
  -f /opt/mcm/docker-compose-app.yml \
  -f /opt/mcm/docker-compose-db.yml \
  -f /opt/mcm/docker-compose-swarm-override.yml \
  config | sed -E 's|image: /|image: |g' > /opt/mcm/docker-compose-stack.yml

Why this is done:

  1. Modularity: Developers maintain clean service blocks split by tier (Access, App, DB).
  2. Constraint Isolation: Node constraints and replica policies are kept in docker-compose-swarm-override.yml to prevent leakage into standard developer builds.
  3. Secret Injection: Config attributes are pre-resolved from env files directly into the compiled output.

3.2 Compilation Transformations

Following the merge, the installer executes two critical post-processing steps to ensure Docker Swarm engine compatibility:

1. yq Sanitization

Docker Swarm ignores certain Compose parameters and throws schema validation errors if they remain in the file. The compiler strips them out using yq:

yq -i 'del(.services[].depends_on) | del(.services[].profiles) | del(.services[].links) | del(.name)' /opt/mcm/docker-compose-stack.yml
  • depends_on is stripped because Swarm relies on dynamic service health checks and DNS availability rather than startup sequencing.
  • profiles are stripped to force all services to compile into a single static stack representation.
  • links are removed in favor of native overlay network service discovery.

2. Port Quote Stripping (Integer Resolution)

Docker Compose outputs port numbers wrapped in quotes (e.g. published: "80"), which causes Docker Swarm schema parser validations to fail (rejecting strings where integers are expected).

The compiler uses a Python regex replacement engine to remove quotes around these values:

import re
c = re.sub(r"published:\s*[\x22\x27](\d+)[\x22\x27]", r"published: \1", c)
c = re.sub(r"target:\s*[\x22\x27](\d+)[\x22\x27]", r"target: \1", c)

4. Node Placement Constraints & Replica Pinning

To enforce physical isolation, services declare placement constraints referencing labeled nodes.

During the install.sh sequence, nodes are labeled by their hostname:

  • docker node update --label-add tier=access "$VM1_HOSTNAME"
  • docker node update --label-add tier=app "$VM2_HOSTNAME"
  • docker node update --label-add tier=db "$VM3_HOSTNAME"

Database Pinning & Data Volumes

Databases (postgres, mongodb, elasticsearch, wazuh-indexer) require persistent storage. In Docker Swarm:

  1. Replica Constraints: All databases are pinned to replicas: 1.
  2. Host Pinning: Databases are restricted to node.labels.tier == db. This forces Swarm to always schedule databases on VM3, binding their named persistent volumes (e.g., postgres_db_data, mongodb_data) to the local disk of VM3, preventing volume divergence across hosts.

5. Swarm Overlay Networking & Service Discovery

Services communicate across physical VM boundaries via the virtual apisix-net Overlay Network.

       VM 1 (Access Gateway)            VM 2 (Application API)           VM 3 (Data & Auth)
   +---------------------------+    +---------------------------+    +---------------------------+
   |   Ingress Traffic (443)   |    |                           |    |                           |
   |             |             |    |                           |    |                           |
   |          apisix           |    |       mcm-api (Java)      |    |          postgres         |
   +-------------+-------------+    +-------------+-------------+    +-------------+-------------+
                 |                                |                                |
                 +============= VXLAN Tunnel (UDP Port 4789) ======================+

5.1 Communication Protocols

  1. Data Plane (VXLAN): Container-to-container packets are encapsulated and transmitted over physical host interfaces using UDP Port 4789.
  2. Control Plane (Gossip): Cluster nodes exchange membership details and routing tables over TCP and UDP Port 7946 (configured as two separate rules).
  3. Docker Swarm DNS: Docker runs an internal DNS resolver at 127.0.0.11 inside each container. Resolving a container name (e.g., mongodb or keycloak) returns a service Virtual IP (VIP). Swarm's built-in IPVS load balancer routes the request directly to the hosting container.

6. Multi-VM Installation and Upgrade Flows

6.1 Multi-Node Installation Flow (install.sh)


6.2 Multi-Node Upgrade Flow (upgrade.sh)


7. Certificate Architecture & Sync Deep Dive

MCM implements a dual Certificate Authority (CA) topology to secure both application-level traffic (via the MCM Root CA) and security monitoring telemetry (via the Wazuh CA):

7.1 Keystore and Truststore Internals

Java services require secure cryptographic storage formatted as PKCS12 archives:

  • keystore.p12: Holds the individual service's private key, certificate, and CA chain.
    • Alias: mcm
    • Encryption Password: Read from KEYSTORE_PASSWORD in /etc/mcm/secrets.env
  • truststore.p12: Holds trusted certificates representing entities the service can communicate with.
    • Alias mcm: Points to the MCM Root CA (ca.crt).
    • Alias wazuh-root-ca: Points to the Wazuh Root CA (root-ca.pem).
    • Aliases <domain>-<index>: Points to certificates fetched recursively from TRUSTED_DOMAINS (e.g. login.microsoftonline.com-0, login.microsoftonline.com-1).
    • Encryption Password: Read from TRUSTSTORE_PASSWORD in /etc/mcm/secrets.env

7.2 Configuration Fingerprint and Rotation

To prevent unnecessary certificate generation, the generate-certs.sh script tracks changes using /var/lib/mcm/.config_fingerprint.

The fingerprint is an MD5 hash calculated from:

Fingerprint = MD5(HOST_SERVER_IP | DOMAIN | TRUSTED_DOMAINS | MD5(secrets.env))

If the fingerprint changes or is missing:

  1. The entire directory /var/lib/mcm/ is backed up to /var/backups/mcm/backup_<YYYYMMDD_HHMMSS>/.
  2. A new MCM Root CA is generated at /var/lib/mcm/certs/ca.key and ca.crt.
  3. Each microservice's keystore, truststore, and self-signed certificate are regenerated.
  4. Wazuh certificates are regenerated using the generator container.
  5. A new .config_fingerprint file is written.

7.3 Multi-Node Certificate Distribution Pipeline

  • Generation: On execution of the installer, generate-certs.sh executes on VM1 (Access Node). It calculates the configuration fingerprint and generates CA files, keystores, and truststores inside /var/lib/mcm/ if changes are detected.
  • Synchronization: The installer recursively copies /var/lib/mcm/ from VM1 to VM2 and VM3 over SSH prior to stack deployment, ensuring all cluster hosts share identical trust roots.

8. Wazuh SIEM Complete Reference

Wazuh operates as an independent security enclave using standard configurations and secure certificate authentication.

8.1 Deployment Profile: mcm-secops

Wazuh components are deployed dynamically under the mcm-secops Swarm profile:

  • wazuh.manager: Central analysis engine performing file integrity monitoring (FIM), system auditing, and active response. Scheduled on VM3.
  • wazuh.indexer: Security index database storing logs and vulnerability logs. Scheduled on VM3.
  • wazuh.dashboard: Security console mapping alarms to compliance frameworks. Scheduled on VM3.
  • init-wazuh-security: Configures certificate verification and index security mappings on first boot.

8.2 Certificate Generation & VM3 Distribution

Wazuh requires a strict directory structure of certificates under /var/lib/mcm/wazuh/certs/.

  • Generation: The generate-certs.sh script runs wazuh-certs-generator in a container on VM1, which compiles and generates all Wazuh node certs (wazuh.indexer.pem, wazuh.manager.pem, wazuh.dashboard.pem, admin.pem) and writes them into .tar archives.
  • Distribution & Extraction: The installer automatically transfers /var/lib/mcm/ over SSH from VM1 to VM3. It then extracts, flattens, and fixes file permissions to 755 under /var/lib/mcm/wazuh/certs/ on VM3 before Swarm services are launched.

9. Internal Configuration Reference (internal_config.env)

Location: /opt/mcm/internal_config.env (on VM1 - Access Node)

This configuration file is compiled during the packaging/release stage and contains registry locations, microservice image tags, and common environment configurations. In the 3-tier architecture, this file resides on VM1 and is sourced by the Swarm Manager during stack compilation.

VariableTypeDescription / Default Value
DOCKER_REGISTRYHostnameURL of the Nexus container registry (e.g., nexus.revdau.internal:8082)
MCM_UI_IMAGEImage TagUI service image reference (e.g., revdau/mcm-ui:1.0.0-develop)
MCM_API_IMAGEImage TagCore API service image reference
MCM_GOVERNANCE_API_IMAGEImage TagGovernance API image reference
MCM_FINOPS_API_IMAGEImage TagFinOps API image reference
MCM_SECOPS_API_IMAGEImage TagSecOps API image reference
MCM_ORCHESTRATION_API_IMAGEImage TagOrchestration API image reference
MCM_DISCOVERY_API_IMAGEImage TagDiscovery API image reference
MCM_OBSERVABILITY_API_IMAGEImage TagObservability API image reference
MCM_AI_API_IMAGEImage TagAI API image reference
APISIX_IMAGEImage Tagapache/apisix:3.12.0-debian
ETCD_IMAGEImage Tagbitnami/etcd:3.5.11
POSTGRES_IMAGEImage Tagpostgres:17.7-alpine
KEYCLOAK_IMAGEImage Tagquay.io/keycloak/keycloak:26.3.1
ELASTICSEARCH_IMAGEImage Tagdocker.elastic.co/elasticsearch/elasticsearch:8.19.3
MONGODB_IMAGEImage Tagmongo:7.0.16
YQ_IMAGEImage Tagmikefarah/yq:4.44.1
KIBANA_IMAGEImage Tagdocker.elastic.co/kibana/kibana:8.19.3
FILEBEAT_IMAGEImage Tagdocker.elastic.co/beats/filebeat:8.19.3
WAZUH_MANAGER_IMAGEImage Tagwazuh/wazuh-manager:4.14.1
WAZUH_INDEXER_IMAGEImage Tagwazuh/wazuh-indexer:4.14.1
WAZUH_DASHBOARD_IMAGEImage Tagwazuh/wazuh-dashboard:4.14.1
WAZUH_CERTS_GENERATOR_IMAGEImage Tagwazuh/wazuh-certs-generator:0.0.3
ELASTIC_AGENT_IMAGEImage Tagdocker.elastic.co/beats/elastic-agent:8.19.3
ELASTIC_USERNAMEUsernameDefault Elasticsearch superuser (elastic)
KIBANA_SYSTEM_USERNAMEUsernameKibana system process user (kibana_system)
KIBANA_READ_ONLY_USERNAMEUsernameKibana read-only user (KibanaReadOnlyUser)
TRUSTED_DOMAINSCSV ListDomain list whose SSL certs are imported into service truststores
HOST_SERVER_IPIPv4VM1's IP address (detected automatically on startup)

10. Complete Variable & Secrets Reference

All environment settings, profiles, and backend credentials are split across user configurations and system-managed secrets.

10.1 User Configuration (/etc/mcm/user_config.env)

This file is created on VM1 (Access Node) and synced to VM2 and VM3 during installation. It controls the global deployment variables and active Swarm profiles:

VariableValuesDescription
DEPLOY_ENVmainDeployment environment identifier. Set to main for production. Do not modify.
GENERATE_SECRETStrue, falseWhen true, auto-generates all passwords in secrets.env via pwgen. Set to false after first run.
GENERATE_SELF_SIGN_CERTStrue, falseWhen true, auto-generates self-signed TLS certificates for the active domain/IP. Set to false after first run.
COMPOSE_PROFILESCSV ListControls which Swarm service profiles to run. E.g., mcm-api,mcm-monitoring,mcm-governance,mcm-finops,mcm-orchestration,mcm-discovery,mcm-ai,mcm-observability.
DOMAINFQDN or emptyCustom domain (e.g., mcm.example.com). If left empty, the server's public IP address is used.

10.2 Secrets (/etc/mcm/secrets.env)

This file contains randomly generated system passwords. These are generated via pwgen on first install:

VariableKey TargetDescription
POSTGRES_KEYCLOAK_PASSWORDPostgreSQL / KeycloakRelational db authentication password
KC_BOOTSTRAP_ADMIN_PASSWORDKeycloakRealm bootstrap administrator password
KC_MCM_CLIENT_SECRETKeycloak / Backend APIsClient secret for secure client authentication
ELASTIC_PASSWORDElasticsearchElastic superuser authentication password
KEYSTORE_PASSWORDJava API KeystoresPKCS12 keystore file security password
TRUSTSTORE_PASSWORDJava API TruststoresPKCS12 truststore file security password
MONGO_INITDB_ROOT_PASSWORDMongoDBNoSQL root database administrator password
MONGO_MASTER_KEYMongoDBField-Level Encryption master key (96 bytes base64)

11. Swarm Container Mounts & Volumes

Persistent data is mapped via named Docker volumes pinned to VM3 (the database node) to protect cluster storage integrity:

Volume NameContainer PathStored Data
mongodb_data/data/dbApp collections & user configuration data
es_data/usr/share/elasticsearch/dataPlatform auditing records and analytics logs
keycloak_db_data/var/lib/postgresql/dataRelational tables, configurations, and users
wazuh-indexer-data/usr/share/wazuh-indexer/dataThreat intelligence records and SIEM logs
wazuh_etc/var/ossec/etcActive response rules and Wazuh config

12. Dynamic Health Check Endpoints

Engineers can query local diagnostic checks directly on the hosting nodes:

ServiceHostTarget PortHealth Check Query
MCM APIVM 29091curl -sk https://localhost:9091/api/actuator/health
KeycloakVM 38080curl -sk http://localhost:8080/keycloak/health
ElasticsearchVM 39200curl -sk -u elastic:<ELASTIC_PASSWORD> https://localhost:9200/_cluster/health
APISIX GatewayVM 180curl -sk http://localhost/ (redirects to HTTPS)

MCM Platform 3-Tier Swarm Engineering Reference v1.0.0

© 2026 RevDau Industries Private Limited. All rights reserved.

Proprietary and Confidential. Unauthorized distribution is strictly prohibited.

On this page