AS4 Microservices Docker-Compose Dokumentation

Das AS4 System kann über docker bereitgestellt werden.

Es folgt der Aufbau unseres Testsystems. Dieses basiert auf docker-compose.yml Dateien.

Das Testsystem trennt sich dabei in mehrere Bereiche, getrennt durch unterschiedliche docker-compose.yml Dateien:

  • Infrastruktur (RabbitMQ, Keycloak)
  • AS4-Services
  • AS4-Crypto-Services
  • Traefik (zur Steuerung der externen API)

Die Dokumentation folgt dieser Struktur, wobei auf die Infrastruktur hier nicht weiter eingegangen wird.

Weitere Hinweise für den produktiven Einsatz finden Sie im Abschnitt Nächste Schritte.

Mehr Details zum Testsystem finden Arvato Mitarbeiter in der internen Doku.

Infrastruktur

Details zu RabbitMQ finden Sie hier.

Details zu Keycloak finden Sie hier.

AS4-Services

Vorbedingungen

Die AS4-Services erfordern Zugriff auf RabbitMQ. Hierfür werden von RabbitMQ Docker Images bereitgestellt.

Zur Absicherung der REST-APIs per oauth2 kann Keycloak genutzt werden.

Die AS4-Workflows können nur ausgeführt werden, wenn sowohl AS4-Services als auch die AS4-Crypto-Services eingerichtet sind.

AS4-Services in docker-compose

Die folgende docker-compose.yml Datei beinhaltet die AS4 Services. Ebenso werden SQL Datenbanken bereitgestellt.

version: "3.7"

networks:
    default:
        name: localas4

volumes:
    as4-database:

services:
    as4-database:
        image: docker.io/library/postgres:14.1-alpine
        container_name: as4-database
        hostname: as4-database
        restart: always
        ports:
            - "5435:5432"
        environment:
            - TZ=${TIME_ZONE}
            - POSTGRES_USER=postgres
            - POSTGRES_PASSWORD=${AS4_DATABASE_PASSWORD}
        volumes:
            - as4-database:/var/lib/postgresql/data
            - ./conf/as4-database/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d/
    as4-outbound-market-message-service:
        image: ${DOCKER_REPO}/as4-outbound-market-message-service:${VERSION_OUTBOUND_MARKET_MESSAGE_SERVICE}
        container_name: as4-outbound-market-message-service
        restart: always
        environment:
            - SPRING_CONFIG_ADDITIONAL-LOCATION=/var/lib/config/as4-outbound-market-message-service.properties
            - TZ=${TIME_ZONE}
            - RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD}
        volumes:
            - ./conf/as4-outbound-market-message-service/:/var/lib/config
        labels:
            - "traefik.enable=true"
            - "traefik.http.services.as4-outbound-market-message-service.loadbalancer.server.port=8080"
            - "traefik.http.routers.as4-outbound-market-message-service.rule=Host(`${HOST}`) && PathPrefix(`/aep-as4-outbound-market-message-service`)"
            - "traefik.http.routers.as4-outbound-market-message-service.entrypoints=websecure"
            - "traefik.http.routers.as4-outbound-market-message-service.tls.certresolver=resolver1"
    as4-outbound-sender:
        image: ${DOCKER_REPO}/as4-outbound-sender:${VERSION_OUTBOUND_SENDER}
        container_name: as4-outbound-sender
        restart: always
        ports:
            - "8082:8080"
        environment:
            - SPRING_CONFIG_ADDITIONAL-LOCATION=/var/lib/config/as4-outbound-sender.properties
            - TZ=${TIME_ZONE}
            - RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD}
        volumes:
            - ./conf/as4-outbound-sender/:/var/lib/config
    as4-inbound-endpoint:
        image: ${DOCKER_REPO}/as4-inbound-endpoint:${VERSION_INBOUND_ENDPOINT}
        container_name: as4-inbound-endpoint
        restart: always
        hostname: as4-inbound-endpoint
        ports:
            - "8083:8080"
        expose:
            - "8083"
        environment:
            - SPRING_CONFIG_ADDITIONAL-LOCATION=/var/lib/config/as4-inbound-endpoint.properties
            - TZ=${TIME_ZONE}
            - RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD}
        volumes:
            - ./conf/as4-inbound-endpoint:/var/lib/config
            - ./conf/workspace/:/workspace/as4-data
    as4-address-service:
        image: ${DOCKER_REPO}/as4-address-service:${VERSION_ADDRESS_SERVICE}
        container_name: as4-address-service
        depends_on:
            - as4-database
        restart: always
        environment:
            - SPRING_CONFIG_ADDITIONAL-LOCATION=/var/lib/config/as4-address-service.properties
            - TZ=${TIME_ZONE}
            - DB_PASSWORD=${AS4_DATABASE_PASSWORD}
            - RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD}
        volumes:
            - ./conf/as4-address-service/:/var/lib/config
        labels:
            - "traefik.enable=true"
            - "traefik.http.services.as4-address-service.loadbalancer.server.port=8080"
            - "traefik.http.routers.as4-address-service.rule=Host(`${HOST}`) && PathPrefix(`/aep-as4-address-service`)"
            - "traefik.http.routers.as4-address-service.entrypoints=websecure"
            - "traefik.http.routers.as4-address-service.tls.certresolver=resolver1"
    as4-message-service:
        image: ${DOCKER_REPO}/as4-message-service:${VERSION_MESSAGE_SERVICE}
        container_name: as4-message-service
        depends_on:
            - as4-database
        restart: always
        environment:
            - SPRING_CONFIG_ADDITIONAL-LOCATION=/var/lib/config/as4-message-service.properties
            - TZ=${TIME_ZONE}
            - DB_PASSWORD=${AS4_DATABASE_PASSWORD}
            - RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD}
        volumes:
            - ./conf/as4-message-service/:/var/lib/config
        labels:
            - "traefik.enable=true"
            - "traefik.http.services.as4-message-service.loadbalancer.server.port=8080"
            - "traefik.http.routers.as4-message-service.rule=Host(`${HOST}`) && PathPrefix(`/aep-as4-message-service`)"
            - "traefik.http.routers.as4-message-service.entrypoints=websecure"
            - "traefik.http.routers.as4-message-service.tls.certresolver=resolver1"
    as4-receipt-service:
        image: ${DOCKER_REPO}/as4-receipt-service:${VERSION_RECEIPT_SERVICE}
        container_name: as4-receipt-service
        restart: always
        ports:
            - "8095:8080"
        environment:
            - SPRING_CONFIG_ADDITIONAL-LOCATION=/var/lib/config/as4-receipt-service.properties
            - TZ=${TIME_ZONE}
            - RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD}
        volumes:
            - ./conf/as4-receipt-service/:/var/lib/config

Diese docker-compose.yml ist von Umgebungsvariablen abhängig. Diese können in einer .env Datei wie folgt konfiguriert werden:

COMPOSE_PROJECT_NAME=AS4-Market-Communication

TIME_ZONE=Europe/Berlin

#Image versions
DOCKER_REPO=docker-nob-erp.next-level-apps.com/as4
VERSION_OUTBOUND_MARKET_MESSAGE_SERVICE=2023-08-04
VERSION_OUTBOUND_SENDER=2023-08-04
VERSION_INBOUND_ENDPOINT=2023-08-04
VERSION_ADDRESS_SERVICE=2023-08-04
VERSION_MESSAGE_SERVICE=2023-08-04
VERSION_RECEIPT_SERVICE=2023-08-04

AS4_DATABASE_PASSWORD=change_me
RABBITMQ_PASSWORD=change_me

Beachten Sie die gemounteten Volumes in den volumes Abschnitten. Hier sind entsprechende Konfigurationsdateien, z.B. application.yml, zu hinterlegen. Weitere Details zu den Konfigurationsdateien finden Sie in den Dokumentationen der einzelnen Services. Falls Sie die gedockerten Datenbanken auf Ihrem Testsystem nutzen möchten, sind ebenfalls Datenbank-Create-Scripte zu hinterlegen.

Die Labels dienen der Traefik Konfiguration. Vergleichen Sie hierzu auch den Traefik-Doku-Abschnitt.

Gestartet wird die Umgebung mit dem üblichen Docker-Compose Befehl:

docker-compose --env-file .env up -d

AS4-Crypto-Services

Vorbedingungen

Die AS4-Crypto-Services erfordern Zugriff auf RabbitMQ. Hierfür werden von RabbitMQ Docker Images bereitgestellt.

Zur Absicherung der REST-APIs per oauth2 kann Keycloak genutzt werden.

Es wird zwingend ein HSM (Hardware Security Module) benötigt. Produktiv nutzbare HSMs sind NICHT als Docker-Image verfügbar.

Es wird ein FSS benötigt. Die Anbindung des FSS ans HSM wird hier beschrieben.

Die AS4-Workflows können nur ausgeführt werden, wenn sowohl AS4-Services als auch die AS4-Crypto-Services eingerichtet sind.

AS4-Crypto-Services in docker-compose

Die folgende docker-compose.yml Datei beinhaltet die AS4 Crypto Services. Ebenso werden SQL Datenbanken sowie der FSS bereitgestellt.

version: '3.8'

networks:
  default:
    name: localas4        

volumes:
  csr-data:
  csr-database:

services:
  csr-service:
    image: ${DOCKER_REPO}/as4/csr-service:${VER_CSR}
    container_name: csr-service
    ports:
      - "3333:3333"
    volumes:
      - ./config/crypto-csr/application.properties:/opt/config/application.properties
      - ./config/crypto-csr/application.yml:/opt/config/application.yml
      - csr-data:/opt/out
    environment:
      - TZ=${TIME_ZONE}
      - CSR_DATABASE_PASSWORD=${CSR_DATABASE_PASSWORD}
    labels:
      - "traefik.enable=true"
      - "traefik.http.services.as4-crypto-csr.loadbalancer.server.port=3333"
      - "traefik.http.routers.as4-crypto-csr.rule=Host(`${HOST}`) && PathPrefix(`/csr-service`)"
      - "traefik.http.routers.as4-crypto-csr.entrypoints=websecure"
      - "traefik.http.routers.as4-crypto-csr.tls.certresolver=resolver1"

  csr-database:
    image: docker.io/library/postgres:14.1-alpine
    container_name: csr-database
    hostname: csr-database
    restart: always
    ports:
      - "7432:5432"
    environment:
      - TZ=${TIME_ZONE}
      - POSTGRES_PASSWORD=${CSR_DATABASE_PASSWORD}
    volumes:
      - csr-database:/var/lib/postgresql/data
      - ./config/csr-database/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
    logging:
      driver: "json-file"
      options:
        max-size: "20m"
        max-file: "10"

  crl-downloader:
    image: ${DOCKER_REPO}/crypto/crl-downloader:${VER_CRL}
    container_name: crl-downloader
    ports:
      - "8090:8090"
    volumes:
      - ./config/crl-downloader:/var/lib/config
    environment:
      - TZ=${TIME_ZONE}
      - SPRING_CONFIG_ADDITIONAL-LOCATION=optional:${AS4_PROP_FILE}, optional:${AS4_YML_FILE}, optional:${AS4_KEYCLOAK_ENRICHED_FILE}
    labels:
      - "traefik.enable=true"
      - "traefik.http.services.crl-downloader.loadbalancer.server.port=8090"
      - "traefik.http.routers.crl-downloader.rule=Host(`${HOST}`) && PathPrefix(`/crl-downloader`)"
      - "traefik.http.routers.crl-downloader.entrypoints=websecure"
      - "traefik.http.routers.crl-downloader.tls.certresolver=resolver1"

  as4-crypto-operations:
    container_name: as4-crypto-operations
    restart: always
    image: ${DOCKER_REPO}/as4/as4-crypto-operations:${VER_CRYPTO}
    pull_policy: always
    ports:
        - "8096:8096"
    env_file:
      - .env
    volumes:
      - ./config/as4-crypto-operations:/var/lib/config
    environment:
      - SPRING_CONFIG_ADDITIONAL-LOCATION=optional:${AS4_CRYPTO_OPERATIONS_PROP_FILE}, optional:${AS4_CRYPTO_OPERATIONS_YML_FILE}
      - TZ=${TIME_ZONE}
      - RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD}

Diese docker-compose.yml ist von Umgebungsvariablen abhängig. Diese können in einer .env Datei wie folgt konfiguriert werden:

COMPOSE_PROJECT_NAME=as4-cryptography

DOCKER_REPO=docker-nob-erp.next-level-apps.com

CSR_DATABASE_PASSWORD=change_me
RABBITMQ_PASSWORD=change_me

TIME_ZONE=Europe/Berlin

VER_CSR=2023-07-29
VER_CRYPTO=2023-07-29

AS4_CRYPTO_OPERATIONS_PROP_FILE=/var/lib/config/application.properties
AS4_CRYPTO_OPERATIONS_YML_FILE=/var/lib/config/application.yml
AS4_PROP_FILE=/var/lib/config/application.properties
AS4_YML_FILE=/var/lib/config/application.yml
AS4_KEYCLOAK_ENRICHED_FILE=/var/lib/config/application-keycloak-enriched.properties

Beachten Sie die gemounteten Volumes in den volumes Abschnitten. Hier sind entsprechende Konfigurationsdateien, z.B. application.yml, zu hinterlegen. Weitere Details zu den Konfigurationsdateien finden Sie in den Dokumentationen der einzelnen Services. Falls Sie die gedockerten Datenbanken auf Ihrem Testsystem nutzen möchten, sind ebenfalls Datenbank-Create-Scripte zu hinterlegen.

Die Labels dienen der Traefik Konfiguration. Vergleichen Sie hierzu auch den Traefik-Doku-Abschnitt.

Gestartet wird die Umgebung mit dem üblichen Docker-Compose Befehl:

docker-compose --env-file .env up -d

HTTPS mit Docker-Compose und Traefik

Ziel

Sie möchten nur über HTTPS auf Ihre Frontends und REST-APIs zugreifen.

Voraussetzung:

  • Sie haben eine Domain und einen Server mit einer öffentlichen IP-Adresse.
  • Sie haben Docker und Docker-Compose auf Ihrem Server installiert.
  • Sie haben Keycloak in Ihrer docker-compose.yml konfiguriert.
  • Sie haben Ihre Angular-Frontends in Ihrer docker-compose.yml konfiguriert.
  • Sie haben alle Anwendungen mit Frontends (z. B. RabbitMQ) in Ihrer docker-compose.yml konfiguriert.

Lösung

Sie können Traefik in Ihrer docker-compose.yml konfigurieren und nutzen.

Schritte

Traefik in docker-compose

Fügen Sie eine neue docker-compose.yml hinzu. Diese beinhaltet Traefik & letsEncrypt.

version: '3.8'

volumes:
  letsencrypt:

networks:
  default:
    external:
      name: localas4

services:
  traefik:
    image: "traefik:v2.8.1"
    restart: always
    ports:
      - 443:443
    command:
      - "--api.insecure=true"
      - "--api.dashboard=True"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.resolver1.acme.tlschallenge=true"
      - "--certificatesresolvers.resolver1.acme.email=test@green-energy.de"
      - "--certificatesresolvers.resolver1.acme.storage=/letsencrypt/acme.json"
      - "--entrypoints.traefik.address=:7777"
      - "--entryPoints.web.forwardedHeaders.insecure"
      - "--accesslog=true"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - letsencrypt:/letsencrypt

Stellen Sie sicher, dass Traefik dasselbe Docker-Netzwerk verwendet wie Ihre anderen Anwendungen (Abschnitt networks).

Traefik verwendet in dieser Konfiguration Lets Encrypt, um Zertifikate zu bestellen. Es speichert sie im Volume letsencrypt.

Traefik stellt die websecure endpoints auf Port 443 (https) bereit.

Folgende Umgebungsvariable muss für alle anderen docker-compose.yml konfiguriert werden: $HOST.

Keycloak

Voraussetzung: Sie haben den Keycloak-Pfad auf /auth konfiguriert. Sie können hierfür die folgende Umgebungsvariable verwenden:

KC_HTTP_RELATIVE_PATH=/auth

Fügen Sie Keycloak die folgenden Labels hinzu:

    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.sslheader.headers.sslProxyHeaders.X-Forwarded-Proto=https"
      - "traefik.http.routers.keycloak.middlewares=sslheader"
      - "traefik.http.routers.keycloak-https.rule=Host(`$HOST`) && PathPrefix(`/auth`)"
      - "traefik.http.routers.keycloak-https.entrypoints=websecure"
      - "traefik.http.routers.keycloak-https.tls=true"
      - "traefik.http.routers.keycloak-https.tls.certresolver=resolver1"

Achten Sie darauf, dass die Umgebungsvariable HOST gesetzt ist.

Ergänzen Sie folgende Umgebungsvariable:

KC_PROXY=passthrough

Sie müssen keinen Keycloak-Port freigeben, da wir Traefik verwenden.

Aktualisieren Sie in der Keycloak-Benutzeroberfläche die Redirect-URIs aller verwendeten Clients auf https.

Angular Frontends

Aktualisieren Sie in keycloak.json die Auth-Server-URL auf https.

Fügen Sie die folgenden Labels hinzu (Beispiel: B2B-UI)

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.b2b-ui.rule=Host(`${HOST}`) && PathPrefix(`/B2B-UI`)"
      - "traefik.http.routers.b2b-ui.entrypoints=websecure"
      - "traefik.http.routers.b2b-ui.tls.certresolver=resolver1"

Achten Sie darauf, dass die Umgebungsvariable HOST gesetzt ist.

Der PathPrefix muss gemäß Ihres jeweiligen Frontends konfiguriert werden.

Sie müssen keinen Port offenlegen, da wir Traefik verwenden.

RabbitMQ UI

Fügen Sie die folgenden Labels hinzu:

     labels:
       - "traefik.enable=true"
       - "traefik.http.services.rabbitmq3ui.loadbalancer.server.port=15672"
       - "traefik.http.routers.rabbitmq3.service=rabbitmq3ui"
       - "traefik.http.routers.rabbitmq3.rule=Host(`${HOST}`)"
       - "traefik.http.routers.rabbitmq3.entrypoints=websecure"
       - "traefik.http.routers.rabbitmq3.tls.certresolver=resolver1"

Achten Sie darauf, dass die Umgebungsvariable HOST gesetzt ist.

Sie müssen den Frontend Port 15672 nicht offenlegen, da wir Traefik verwenden.

Nächste Schritte

Dieses Testsystem stellt von jedem Service nur eine Instanz bereit. Für den produktiven Einsatz empfehlen wir den Einsatz mehrerer parallel ausgeführter Instanzen, aus Gründen der Ausfallsicherheit und Lastverteilung. Alle Services, die REST-APIs anbieten, benötigen dann entsprechend jeweils einen vorgeschalteten Loadbalancer. Kubernetes ist hervorragend geeignet, um mehrere Microservice-Instanzen parallel auszuführen.

Das AS4 System verfügt über kein eigenes Frontend, sondern nutzt das Frontend der B2B. Sie können das AS4 System an eine bestehende B2B anschließen. Zum Anschluss wird der neue B2B-Message-Service benötigt.

Falls Sie die B2B nicht für die Marktkommunikation einsetzen, empfehlen wir die Einrichtung der B2B Frontends sowie Backends, um die B2B allein als AS4 Frontend einzusetzen. Die B2B ist dann zwischen das AS4 System und Ihre Marktkommunikationsanwendung zu schalten.

View Me   Edit Me