From 630c9d35cd4f2852398ed6f082700aa6e70f408e Mon Sep 17 00:00:00 2001 From: Prem Palanisamy Date: Tue, 17 Mar 2026 21:50:21 +0100 Subject: [PATCH 1/2] ci: add GitHub Actions workflows, PR template, dependabot --- .github/dependabot.yml | 41 + .github/pull_request_template.md | 30 + .github/workflows/develop-ci-cd.yml | 122 +++ .github/workflows/pr-checks.yml | 123 +++ .github/workflows/prod-ci-cd.yml | 136 +++ .gitlab-ci.yml | 16 - docker-compose-arm.yml | 506 --------- docker-compose.yml | 1553 ++++++++++----------------- 8 files changed, 1012 insertions(+), 1515 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/develop-ci-cd.yml create mode 100644 .github/workflows/pr-checks.yml create mode 100644 .github/workflows/prod-ci-cd.yml delete mode 100644 .gitlab-ci.yml delete mode 100644 docker-compose-arm.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..660f3fa --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,41 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + + - package-ecosystem: docker + directory: / + schedule: + interval: weekly + + - package-ecosystem: maven + directory: /api-gateway + schedule: + interval: weekly + + - package-ecosystem: maven + directory: /user-service + schedule: + interval: weekly + + - package-ecosystem: maven + directory: /post-service + schedule: + interval: weekly + + - package-ecosystem: maven + directory: /connections-service + schedule: + interval: weekly + + - package-ecosystem: maven + directory: /notification-service + schedule: + interval: weekly + + - package-ecosystem: maven + directory: /uploader-service + schedule: + interval: weekly diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..95c9a2a --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,30 @@ +## Description + + +## Type of change +- [ ] Bug fix +- [ ] New feature +- [ ] Breaking change +- [ ] Documentation update + +## Services affected +- [ ] api-gateway +- [ ] user-service +- [ ] post-service +- [ ] connections-service +- [ ] notification-service +- [ ] uploader-service +- [ ] config-server +- [ ] discovery-server + +## Testing done +- [ ] Unit tests added/updated +- [ ] Integration tests added/updated +- [ ] Manually tested on DEV + +## Checklist +- [ ] Tests pass locally +- [ ] Coverage above 70% +- [ ] No hardcoded credentials +- [ ] Flyway migration added if schema changed +- [ ] Swagger annotations added for new endpoints diff --git a/.github/workflows/develop-ci-cd.yml b/.github/workflows/develop-ci-cd.yml new file mode 100644 index 0000000..cce28f6 --- /dev/null +++ b/.github/workflows/develop-ci-cd.yml @@ -0,0 +1,122 @@ +name: Develop CI/CD + +on: + push: + branches: [develop] + +jobs: + + detect-changes: + name: Detect Changed Services + runs-on: ubuntu-latest + outputs: + api-gateway: ${{ steps.changes.outputs.api-gateway }} + user-service: ${{ steps.changes.outputs.user-service }} + post-service: ${{ steps.changes.outputs.post-service }} + connections-service: ${{ steps.changes.outputs.connections-service }} + notification-service: ${{ steps.changes.outputs.notification-service }} + uploader-service: ${{ steps.changes.outputs.uploader-service }} + config-server: ${{ steps.changes.outputs.config-server }} + discovery-server: ${{ steps.changes.outputs.discovery-server }} + steps: + - uses: actions/checkout@v4 + - uses: dorny/paths-filter@v3 + id: changes + with: + filters: | + api-gateway: + - 'api-gateway/**' + user-service: + - 'user-service/**' + post-service: + - 'post-service/**' + connections-service: + - 'connections-service/**' + notification-service: + - 'notification-service/**' + uploader-service: + - 'uploader-service/**' + config-server: + - 'config-server/**' + discovery-server: + - 'discovery-server/**' + + build-and-push: + name: Build and Push Images + runs-on: ubuntu-latest + needs: detect-changes + strategy: + matrix: + service: + - { name: api-gateway, changed: "${{ needs.detect-changes.outputs.api-gateway }}" } + - { name: user-service, changed: "${{ needs.detect-changes.outputs.user-service }}" } + - { name: post-service, changed: "${{ needs.detect-changes.outputs.post-service }}" } + - { name: connections-service, changed: "${{ needs.detect-changes.outputs.connections-service }}" } + - { name: notification-service, changed: "${{ needs.detect-changes.outputs.notification-service }}" } + - { name: uploader-service, changed: "${{ needs.detect-changes.outputs.uploader-service }}" } + - { name: config-server, changed: "${{ needs.detect-changes.outputs.config-server }}" } + - { name: discovery-server, changed: "${{ needs.detect-changes.outputs.discovery-server }}" } + steps: + - uses: actions/checkout@v4 + if: matrix.service.changed == 'true' + - name: Set up JDK 17 + if: matrix.service.changed == 'true' + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'corretto' + cache: maven + - name: Build service + if: matrix.service.changed == 'true' + run: cd ${{ matrix.service.name }} && mvn package -DskipTests + - name: Login to DockerHub + if: matrix.service.changed == 'true' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_PASS }} + - name: Build and push image + if: matrix.service.changed == 'true' + uses: docker/build-push-action@v5 + with: + context: ./${{ matrix.service.name }} + platforms: linux/amd64 + push: true + tags: | + premtsd18/${{ matrix.service.name }}:develop + premtsd18/${{ matrix.service.name }}:develop-${{ github.sha }} + + deploy-dev: + name: Deploy to DEV + runs-on: ubuntu-latest + needs: build-and-push + environment: development + steps: + - name: Deploy to Hetzner DEV + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.HETZNER_IP }} + username: ${{ secrets.HETZNER_USER }} + key: ${{ secrets.HETZNER_SSH_KEY }} + script: | + cd ~/personal/linkedin + git pull origin develop + docker compose pull + docker compose up -d --remove-orphans + docker image prune -f + - name: Health check + run: | + sleep 30 + curl -f http://${{ secrets.HETZNER_IP }}:10000/actuator/health + echo "DEV deployment successful ✅" + - name: Rollback on failure + if: failure() + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.HETZNER_IP }} + username: ${{ secrets.HETZNER_USER }} + key: ${{ secrets.HETZNER_SSH_KEY }} + script: | + cd ~/personal/linkedin + docker compose up -d + echo "Rolled back ✅" diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml new file mode 100644 index 0000000..8d4525a --- /dev/null +++ b/.github/workflows/pr-checks.yml @@ -0,0 +1,123 @@ +name: PR Checks + +on: + pull_request: + branches: [develop, main] + +jobs: + + detect-changes: + name: Detect Changed Services + runs-on: ubuntu-latest + outputs: + api-gateway: ${{ steps.changes.outputs.api-gateway }} + user-service: ${{ steps.changes.outputs.user-service }} + post-service: ${{ steps.changes.outputs.post-service }} + connections-service: ${{ steps.changes.outputs.connections-service }} + notification-service: ${{ steps.changes.outputs.notification-service }} + uploader-service: ${{ steps.changes.outputs.uploader-service }} + config-server: ${{ steps.changes.outputs.config-server }} + discovery-server: ${{ steps.changes.outputs.discovery-server }} + steps: + - uses: actions/checkout@v4 + - uses: dorny/paths-filter@v3 + id: changes + with: + filters: | + api-gateway: + - 'api-gateway/**' + user-service: + - 'user-service/**' + post-service: + - 'post-service/**' + connections-service: + - 'connections-service/**' + notification-service: + - 'notification-service/**' + uploader-service: + - 'uploader-service/**' + config-server: + - 'config-server/**' + discovery-server: + - 'discovery-server/**' + + unit-tests: + name: Unit Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'corretto' + cache: maven + - name: Run unit tests + run: mvn test -DskipIntegrationTests=true + - name: Upload test results + uses: actions/upload-artifact@v4 + if: always() + with: + name: unit-test-results + path: '**/target/surefire-reports/*.xml' + + code-coverage: + name: Code Coverage + runs-on: ubuntu-latest + needs: unit-tests + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'corretto' + cache: maven + - name: Run tests with coverage + run: mvn verify jacoco:report -DskipIntegrationTests=true + - name: Upload coverage report + uses: actions/upload-artifact@v4 + with: + name: coverage-report + path: '**/target/site/jacoco/' + + security-scan: + name: Security Scan + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'corretto' + cache: maven + - name: OWASP Dependency Check + run: mvn dependency-check:check -DfailBuildOnCVSS=7 -DskipTestScope=true + continue-on-error: true + - name: Upload OWASP report + uses: actions/upload-artifact@v4 + if: always() + with: + name: owasp-report + path: '**/target/dependency-check-report.html' + + code-quality: + name: Code Quality + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'corretto' + cache: maven + - name: Checkstyle + run: mvn checkstyle:check + continue-on-error: true + - name: SpotBugs + run: mvn spotbugs:check + continue-on-error: true diff --git a/.github/workflows/prod-ci-cd.yml b/.github/workflows/prod-ci-cd.yml new file mode 100644 index 0000000..23adfa9 --- /dev/null +++ b/.github/workflows/prod-ci-cd.yml @@ -0,0 +1,136 @@ +name: Production CI/CD + +on: + push: + branches: [main] + +jobs: + + detect-changes: + name: Detect Changed Services + runs-on: ubuntu-latest + outputs: + api-gateway: ${{ steps.changes.outputs.api-gateway }} + user-service: ${{ steps.changes.outputs.user-service }} + post-service: ${{ steps.changes.outputs.post-service }} + connections-service: ${{ steps.changes.outputs.connections-service }} + notification-service: ${{ steps.changes.outputs.notification-service }} + uploader-service: ${{ steps.changes.outputs.uploader-service }} + config-server: ${{ steps.changes.outputs.config-server }} + discovery-server: ${{ steps.changes.outputs.discovery-server }} + steps: + - uses: actions/checkout@v4 + - uses: dorny/paths-filter@v3 + id: changes + with: + filters: | + api-gateway: + - 'api-gateway/**' + user-service: + - 'user-service/**' + post-service: + - 'post-service/**' + connections-service: + - 'connections-service/**' + notification-service: + - 'notification-service/**' + uploader-service: + - 'uploader-service/**' + config-server: + - 'config-server/**' + discovery-server: + - 'discovery-server/**' + + build-and-push: + name: Build and Push Production Images + runs-on: ubuntu-latest + needs: detect-changes + strategy: + matrix: + service: + - { name: api-gateway, changed: "${{ needs.detect-changes.outputs.api-gateway }}" } + - { name: user-service, changed: "${{ needs.detect-changes.outputs.user-service }}" } + - { name: post-service, changed: "${{ needs.detect-changes.outputs.post-service }}" } + - { name: connections-service, changed: "${{ needs.detect-changes.outputs.connections-service }}" } + - { name: notification-service, changed: "${{ needs.detect-changes.outputs.notification-service }}" } + - { name: uploader-service, changed: "${{ needs.detect-changes.outputs.uploader-service }}" } + - { name: config-server, changed: "${{ needs.detect-changes.outputs.config-server }}" } + - { name: discovery-server, changed: "${{ needs.detect-changes.outputs.discovery-server }}" } + steps: + - uses: actions/checkout@v4 + if: matrix.service.changed == 'true' + - name: Set up JDK 17 + if: matrix.service.changed == 'true' + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'corretto' + cache: maven + - name: Build service + if: matrix.service.changed == 'true' + run: cd ${{ matrix.service.name }} && mvn package -DskipTests + - name: Login to DockerHub + if: matrix.service.changed == 'true' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_PASS }} + - name: Trivy security scan + if: matrix.service.changed == 'true' + uses: aquasecurity/trivy-action@master + with: + scan-type: fs + scan-ref: ./${{ matrix.service.name }} + severity: CRITICAL,HIGH + exit-code: 0 + - name: Build and push image + if: matrix.service.changed == 'true' + uses: docker/build-push-action@v5 + with: + context: ./${{ matrix.service.name }} + platforms: linux/amd64 + push: true + tags: | + premtsd18/${{ matrix.service.name }}:latest + premtsd18/${{ matrix.service.name }}:${{ github.sha }} + + deploy-prod: + name: Deploy to Production + runs-on: ubuntu-latest + needs: build-and-push + environment: production + steps: + - uses: actions/checkout@v4 + - name: Setup kubectl + uses: azure/setup-kubectl@v3 + - name: Configure kubeconfig + run: | + mkdir -p ~/.kube + echo "${{ secrets.KUBECONFIG }}" > ~/.kube/config + chmod 600 ~/.kube/config + - name: Deploy changed services + run: | + for service in api-gateway user-service post-service connections-service notification-service uploader-service config-server discovery-server; do + kubectl set image deployment/$service \ + $service=premtsd18/$service:${{ github.sha }} \ + -n linkedin-prod \ + --ignore-not-found=true + done + - name: Wait for rollouts + run: | + for service in api-gateway user-service post-service connections-service notification-service uploader-service; do + kubectl rollout status deployment/$service \ + -n linkedin-prod --timeout=5m 2>/dev/null || true + done + - name: Smoke test + run: | + sleep 30 + curl -f http://${{ secrets.HETZNER_IP }}:32000/actuator/health + echo "PROD deployment successful ✅" + - name: Rollback on failure + if: failure() + run: | + for service in api-gateway user-service post-service connections-service notification-service uploader-service; do + kubectl rollout undo deployment/$service -n linkedin-prod 2>/dev/null || true + done + echo "Rolled back PROD ✅" diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 2db562b..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,16 +0,0 @@ -stages: - - mirror - -mirror_repo: - stage: mirror - script: - - git config --global user.email "i.prem.tsd@gmail.com" - - git config --global user.name "Prem Palanisamy" - - - git clone --mirror "$CI_REPOSITORY_URL" repo-mirror - - cd repo-mirror - - - git remote set-url --push origin https://oauth2:${PERSONAL_REPO_TOKEN}@github.com/premtsd-code/LinkedIn.git - - git push --mirror - only: - - main # or whichever branch you want diff --git a/docker-compose-arm.yml b/docker-compose-arm.yml deleted file mode 100644 index 6164bb9..0000000 --- a/docker-compose-arm.yml +++ /dev/null @@ -1,506 +0,0 @@ -services: - kafka: - image: docker.io/bitnami/kafka:3.8 - container_name: kafka - platform: linux/arm64 - volumes: - - "kafka_data:/bitnami" - - ./logs/kafka:/opt/bitnami/kafka/logs - networks: - - linkedin-network - environment: - - KAFKA_CFG_NODE_ID=0 - - KAFKA_CFG_PROCESS_ROLES=controller,broker - - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka:9093 - - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 - - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092 - - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT - - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER - - KAFKA_CFG_INTER_BROKER_LISTENER_NAME=PLAINTEXT - - KAFKA_HEAP_OPTS=-Xmx512m -Xms512m - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=kafka" - - prem-portfolio: - build: - context: ./prem-portfolio - dockerfile: Dockerfile.arm64 # ARM64-specific Dockerfile - container_name: prem-portfolio - platform: linux/arm64 - ports: - - "4200:4200" - networks: - - linkedin-network - restart: unless-stopped - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost"] - interval: 30s - timeout: 10s - retries: 3 - labels: - - "traefik.enable=true" - - "traefik.http.routers.portfolio.rule=Host(`premtsd.com`) || Host(`www.premtsd.com`)" - - "traefik.http.routers.portfolio.entrypoints=websecure" - - "traefik.http.routers.portfolio.tls.certresolver=letsencrypt" - - "traefik.http.services.portfolio.loadbalancer.server.port=80" - # Redirect www to non-www - - "traefik.http.middlewares.www-redirect.redirectregex.regex=^https://www.premtsd.com/(.*)" - - "traefik.http.middlewares.www-redirect.redirectregex.replacement=https://premtsd.com/$${1}" - - "traefik.http.routers.portfolio.middlewares=www-redirect" - - kafbat-ui: - container_name: kafbat-ui - image: ghcr.io/kafbat/kafka-ui:latest - platform: linux/arm64 - ports: - - 8090:8080 - depends_on: - - kafka - networks: - - linkedin-network - environment: - KAFKA_CLUSTERS_0_NAME: local - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9092 - volumes: - - ./logs/kafbat-ui:/app/logs - labels: - - "traefik.enable=true" - - "traefik.http.routers.kafka-ui.rule=Host(`kafka.premtsd.com`)" - - "traefik.http.routers.kafka-ui.entrypoints=websecure" - - "traefik.http.routers.kafka-ui.tls.certresolver=letsencrypt" - - "traefik.http.services.kafka-ui.loadbalancer.server.port=8080" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=kafbat-ui" - - linkedin-db: - image: arm64v8/postgres:16 - container_name: linkedin-db - platform: linux/arm64 - environment: - - POSTGRES_DB=linkedinDB - - POSTGRES_USER=user - - POSTGRES_PASSWORD=password - ports: - - "5432:5432" - networks: - - linkedin-network - volumes: - - linkedin-db-data:/var/lib/postgresql/data - - ./logs/linkedin-db:/var/log/postgresql - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=linkedin-db" - - connections-db: - image: neo4j:5.15-community - container_name: connections-db - platform: linux/arm64 - environment: - - NEO4J_AUTH=neo4j/password - - NEO4J_PLUGINS=["apoc"] - ports: - - "7474:7474" - - "7687:7687" - volumes: - - connections-db-data:/data - - ./logs/connections-db:/logs - networks: - - linkedin-network - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=connections-db" - - discovery-server: - image: premtsd18/discovery-server:arm64 - restart: unless-stopped - container_name: discovery-server - platform: linux/arm64 - networks: - - linkedin-network - ports: - - "8761:8761" - depends_on: - config-server: - condition: service_healthy - volumes: - - ./logs/discovery-server:/logs/discovery-server - labels: - - "traefik.enable=true" - - "traefik.http.routers.eureka.rule=Host(`eureka.premtsd.com`)" - - "traefik.http.routers.eureka.entrypoints=websecure" - - "traefik.http.routers.eureka.tls.certresolver=letsencrypt" - - "traefik.http.services.eureka.loadbalancer.server.port=8761" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=discovery-server" - - post-service: - image: premtsd18/post-service:arm64 - container_name: post-service - platform: linux/arm64 - networks: - - linkedin-network - depends_on: - - discovery-server - - linkedin-db - - kafka - - config-server - environment: - REDIS_HOST: redis - REDIS_PORT: 6379 - REDIS_PASSWORD: secret123 - volumes: - - ./app/logs/post-service:/app/logs/post-service - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=post-service" - - user-service: - image: premtsd18/user-service:arm64 - container_name: user-service - platform: linux/arm64 - networks: - - linkedin-network - depends_on: - - discovery-server - - linkedin-db - - kafka - - config-server - volumes: - - ./app/logs/user-service:/app/logs/user-service - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=user-service" - - notification-service: - image: premtsd18/notification-service:arm64 - container_name: notification-service - platform: linux/arm64 - networks: - - linkedin-network - depends_on: - - discovery-server - - linkedin-db - - kafka - - config-server - volumes: - - ./logs/notification-service:/logs/notification-service - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=notification-service" - - connections-service: - image: premtsd18/connections-service:arm64 - container_name: connections-service - platform: linux/arm64 - networks: - - linkedin-network - depends_on: - - discovery-server - - connections-db - - kafka - - config-server - volumes: - - ./logs/connections-service:/logs/connections-service - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=connections-service" - - api-gateway: - image: premtsd18/api-gateway:arm64 - container_name: api-gateway - platform: linux/arm64 - ports: - - "8080:8080" - networks: - - linkedin-network - depends_on: - - discovery-server - - config-server - volumes: - - ./logs/api-gateway:/logs/api-gateway - labels: - - "traefik.enable=true" - - "traefik.http.routers.api.rule=Host(`api.premtsd.com`)" - - "traefik.http.routers.api.entrypoints=websecure" - - "traefik.http.routers.api.tls.certresolver=letsencrypt" - - "traefik.http.services.api.loadbalancer.server.port=8080" - # CORS middleware for API - - "traefik.http.middlewares.api-cors.headers.accesscontrolallowmethods=GET,OPTIONS,PUT,POST,DELETE,PATCH" - - "traefik.http.middlewares.api-cors.headers.accesscontrolalloworiginlist=https://premtsd.com,https://www.premtsd.com" - - "traefik.http.middlewares.api-cors.headers.accesscontrolmaxage=100" - - "traefik.http.middlewares.api-cors.headers.addvaryheader=true" - - "traefik.http.routers.api.middlewares=api-cors" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=api-gateway" - - config-server: - image: premtsd18/config-server:arm64 - container_name: config-server - platform: linux/arm64 - networks: - - linkedin-network - env_file: - - .env - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8888/actuator/health"] - interval: 10s - timeout: 5s - retries: 5 - volumes: - - ./logs/config-server:/logs/config-server - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=config-server" - - redis: - image: bitnami/redis:latest - container_name: redis - platform: linux/arm64 - environment: - - REDIS_PASSWORD=secret123 - ports: - - "6379:6379" - networks: - - linkedin-network - volumes: - - ./logs/redis:/opt/bitnami/redis/logs - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=redis" - - uploader-service: - image: premtsd18/uploader-service:arm64 - container_name: uploader-service - platform: linux/arm64 - networks: - - linkedin-network - depends_on: - - discovery-server - - config-server - volumes: - - ./app/logs/uploader-service:/app/logs/uploader-service - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=uploader-service" - - zipkin: - image: openzipkin/zipkin:latest - container_name: zipkin - platform: linux/arm64 - ports: - - "9411:9411" - networks: - - linkedin-network - environment: - - JAVA_OPTS=-Xms256m -Xmx512m - volumes: - - ./logs/zipkin:/zipkin/logs - labels: - - "traefik.enable=true" - - "traefik.http.routers.zipkin.rule=Host(`zipkin.premtsd.com`)" - - "traefik.http.routers.zipkin.entrypoints=websecure" - - "traefik.http.routers.zipkin.tls.certresolver=letsencrypt" - - "traefik.http.services.zipkin.loadbalancer.server.port=9411" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=zipkin" - - opensearch: - image: opensearchproject/opensearch:2.17.0 - container_name: opensearch - platform: linux/arm64 - environment: - - discovery.type=single-node - - DISABLE_SECURITY_PLUGIN=true - - OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m - ulimits: - memlock: - soft: -1 - hard: -1 - ports: - - "9200:9200" - networks: - - linkedin-network - volumes: - - ./logs/opensearch:/usr/share/opensearch/logs - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=opensearch" - - opensearch-dashboards: - image: opensearchproject/opensearch-dashboards:2.17.0 - container_name: opensearch-dashboards - platform: linux/arm64 - environment: - - OPENSEARCH_HOSTS=http://opensearch:9200 - - DISABLE_SECURITY_DASHBOARDS_PLUGIN=true - ports: - - "5601:5601" - depends_on: - - opensearch - networks: - - linkedin-network - volumes: - - ./logs/opensearch-dashboards:/usr/share/opensearch-dashboards/logs - labels: - - "traefik.enable=true" - - "traefik.http.routers.opensearch.rule=Host(`logs.premtsd.com`)" - - "traefik.http.routers.opensearch.entrypoints=websecure" - - "traefik.http.routers.opensearch.tls.certresolver=letsencrypt" - - "traefik.http.services.opensearch.loadbalancer.server.port=5601" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=opensearch-dashboards" - - opensearch-logstash: - image: opensearchproject/logstash-oss-with-opensearch-output-plugin:8.9.0 - container_name: opensearch-logstash - platform: linux/arm64 - volumes: - - ./logstash/pipeline/logstash.conf:/usr/share/logstash/pipeline/logstash.conf - - ./logs/opensearch-logstash:/usr/share/logstash/logs - ports: - - "5044:5044" - networks: - - linkedin-network - depends_on: - - opensearch - environment: - - LS_JAVA_OPTS=-Xms256m -Xmx512m - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=opensearch-logstash" - - filebeat: - image: docker.elastic.co/beats/filebeat:8.13.4 - container_name: filebeat - platform: linux/arm64 - user: root - volumes: - - ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro - - ./app/logs:/app/logs:ro - - ./logs:/logs:ro - - /var/lib/docker/containers:/var/lib/docker/containers:ro - - /var/run/docker.sock:/var/run/docker.sock:ro - - ./logs/filebeat:/var/log/filebeat - networks: - - linkedin-network - depends_on: - - opensearch-logstash - command: ["--strict.perms=false"] - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=filebeat" - - # ======================= - # Traefik Reverse Proxy with HTTPS (ARM64) - # ======================= - traefik: - image: traefik:v3.0 - container_name: traefik - platform: linux/arm64 - command: - - "--api.dashboard=true" - - "--api.insecure=true" - - "--providers.docker=true" - - "--providers.docker.exposedbydefault=false" - - "--entrypoints.web.address=:80" - - "--entrypoints.websecure.address=:443" - - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" - - "--certificatesresolvers.letsencrypt.acme.email=i.prem.tsd@outlook.com" - - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" - - "--entrypoints.web.http.redirections.entrypoint.to=websecure" - - "--entrypoints.web.http.redirections.entrypoint.scheme=https" - - "--log.level=INFO" - ports: - - "80:80" - - "443:443" - - "8081:8080" # Traefik dashboard (changed from 8080 to avoid conflict) - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - - ./traefik/letsencrypt:/letsencrypt - - ./traefik/certs:/certs - - ./traefik/config:/etc/traefik/dynamic - networks: - - linkedin-network - restart: unless-stopped - labels: - - "traefik.enable=true" - - "traefik.http.routers.traefik.rule=Host(`traefik.premtsd.com`)" - - "traefik.http.routers.traefik.entrypoints=websecure" - - "traefik.http.routers.traefik.tls.certresolver=letsencrypt" - - "traefik.http.routers.traefik.service=api@internal" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=traefik" - -networks: - linkedin-network: - -volumes: - kafka_data: - linkedin-db-data: - connections-db-data: - prometheus-data: - grafana-data: diff --git a/docker-compose.yml b/docker-compose.yml index 2f28bdf..23e2893 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,993 +1,560 @@ -services: - kafka: - image: docker.io/bitnami/kafka:3.8 - container_name: kafka - volumes: - - "kafka_data:/bitnami" - - ./logs/kafka:/opt/bitnami/kafka/logs - networks: - - linkedin-network - environment: - - KAFKA_CFG_NODE_ID=0 - - KAFKA_CFG_PROCESS_ROLES=controller,broker - - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka:9093 - - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 - - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092 - - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT - - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER - - KAFKA_CFG_INTER_BROKER_LISTENER_NAME=PLAINTEXT - - KAFKA_HEAP_OPTS=-Xmx512m -Xms512m - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=kafka" - - prem-portfolio: - build: - context: ./prem-portfolio - dockerfile: Dockerfile - container_name: prem-portfolio - ports: - - "4200:4200" - networks: - - linkedin-network - restart: unless-stopped - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost"] - interval: 30s - timeout: 10s - retries: 3 - labels: - - "traefik.enable=true" - - "traefik.http.routers.portfolio.rule=Host(`premtsd.com`) || Host(`www.premtsd.com`)" - - "traefik.http.routers.portfolio.entrypoints=websecure" - - "traefik.http.routers.portfolio.tls.certresolver=letsencrypt" - - "traefik.http.services.portfolio.loadbalancer.server.port=80" - # Redirect www to non-www - - "traefik.http.middlewares.www-redirect.redirectregex.regex=^https://www.premtsd.com/(.*)" - - "traefik.http.middlewares.www-redirect.redirectregex.replacement=https://premtsd.com/$${1}" - - "traefik.http.routers.portfolio.middlewares=www-redirect" - - kafbat-ui: - container_name: kafbat-ui - image: ghcr.io/kafbat/kafka-ui:latest - ports: - - 8090:8080 - depends_on: - - kafka - networks: - - linkedin-network - environment: - KAFKA_CLUSTERS_0_NAME: local - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9092 - volumes: - - ./logs/kafbat-ui:/app/logs - labels: - - "traefik.enable=true" - - "traefik.http.routers.kafka-ui.rule=Host(`kafka.premtsd.com`)" - - "traefik.http.routers.kafka-ui.entrypoints=websecure" - - "traefik.http.routers.kafka-ui.tls.certresolver=letsencrypt" - - "traefik.http.services.kafka-ui.loadbalancer.server.port=8080" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=kafbat-ui" - - linkedin-db: - image: postgres - container_name: linkedin-db - environment: - - POSTGRES_DB=linkedinDB - - POSTGRES_USER=user - - POSTGRES_PASSWORD=password - ports: - - "5432:5432" - networks: - - linkedin-network - volumes: - - linkedin-db-data:/var/lib/postgresql/data - - ./logs/linkedin-db:/var/log/postgresql - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=linkedin-db" - - connections-db: - image: neo4j - container_name: connections-db - environment: - - NEO4J_AUTH=neo4j/password - ports: - - "7474:7474" - - "7687:7687" - volumes: - - connections-db-data:/data - - ./logs/connections-db:/logs - networks: - - linkedin-network - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=connections-db" - - discovery-server: - image: premtsd18/discovery-server - restart: unless-stopped - container_name: discovery-server - networks: - - linkedin-network - ports: - - "8761:8761" - depends_on: - config-server: - condition: service_healthy - volumes: - - ./logs/discovery-server:/logs/discovery-server - labels: - - "traefik.enable=true" - - "traefik.http.routers.eureka.rule=Host(`eureka.premtsd.com`)" - - "traefik.http.routers.eureka.entrypoints=websecure" - - "traefik.http.routers.eureka.tls.certresolver=letsencrypt" - - "traefik.http.services.eureka.loadbalancer.server.port=8761" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=discovery-server" - - post-service: - image: premtsd18/post-service - container_name: post-service - networks: - - linkedin-network - depends_on: - - discovery-server - - linkedin-db - - kafka - - config-server - environment: - REDIS_HOST: redis - REDIS_PORT: 6379 - REDIS_PASSWORD: secret123 - volumes: - - ./app/logs/post-service:/app/logs/post-service - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=post-service" - - user-service: - image: premtsd18/user-service - container_name: user-service - networks: - - linkedin-network - depends_on: - - discovery-server - - linkedin-db - - kafka - - config-server - volumes: - - ./app/logs/user-service:/app/logs/user-service - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=user-service" - - notification-service: - image: premtsd18/notification-service - container_name: notification-service - networks: - - linkedin-network - depends_on: - - discovery-server - - linkedin-db - - kafka - - config-server - ports: - - "9293:9293" - volumes: - - ./logs/notification-service:/logs/notification-service - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=notification-service" - - connections-service: - image: premtsd18/connections-service - container_name: connections-service - networks: - - linkedin-network - depends_on: - - discovery-server - - connections-db - - kafka - - config-server - volumes: - - ./logs/connections-service:/logs/connections-service - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=connections-service" - - api-gateway: - image: premtsd18/api-gateway - container_name: api-gateway - ports: - - "8080:8080" - networks: - - linkedin-network - depends_on: - - discovery-server - - config-server - volumes: - - ./logs/api-gateway:/logs/api-gateway - labels: - - "traefik.enable=true" - - "traefik.http.routers.api.rule=Host(`api.premtsd.com`)" - - "traefik.http.routers.api.entrypoints=websecure" - - "traefik.http.routers.api.tls.certresolver=letsencrypt" - - "traefik.http.services.api.loadbalancer.server.port=8080" - # CORS middleware for API - - "traefik.http.middlewares.api-cors.headers.accesscontrolallowmethods=GET,OPTIONS,PUT,POST,DELETE,PATCH" - - "traefik.http.middlewares.api-cors.headers.accesscontrolalloworiginlist=https://premtsd.com,https://www.premtsd.com" - - "traefik.http.middlewares.api-cors.headers.accesscontrolmaxage=100" - - "traefik.http.middlewares.api-cors.headers.addvaryheader=true" - - "traefik.http.routers.api.middlewares=api-cors" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=api-gateway" - - config-server: - image: premtsd18/config-server - container_name: config-server - networks: - - linkedin-network - env_file: - - .env - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8888/actuator/health"] - interval: 10s - timeout: 5s - retries: 5 - volumes: - - ./logs/config-server:/logs/config-server - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=config-server" - - redis: - image: bitnami/redis:latest - container_name: redis - environment: - - REDIS_PASSWORD=secret123 - ports: - - "6379:6379" - networks: - - linkedin-network - volumes: - - ./logs/redis:/opt/bitnami/redis/logs - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=redis" - - uploader-service: - image: premtsd18/uploader-service - container_name: uploader-service - networks: - - linkedin-network - depends_on: - - discovery-server - - config-server - volumes: - - ./app/logs/uploader-service:/app/logs/uploader-service - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=uploader-service" - - zipkin: - image: openzipkin/zipkin - container_name: zipkin - ports: - - "9411:9411" - networks: - - linkedin-network - environment: - - JAVA_OPTS=-Xms256m -Xmx512m - volumes: - - ./logs/zipkin:/zipkin/logs - labels: - - "traefik.enable=true" - - "traefik.http.routers.zipkin.rule=Host(`zipkin.premtsd.com`)" - - "traefik.http.routers.zipkin.entrypoints=websecure" - - "traefik.http.routers.zipkin.tls.certresolver=letsencrypt" - - "traefik.http.services.zipkin.loadbalancer.server.port=9411" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=zipkin" - - opensearch-init: - image: busybox:latest - container_name: opensearch-init - user: root - volumes: - - opensearch-data:/usr/share/opensearch/data - - ./logs/opensearch:/usr/share/opensearch/logs - command: > - sh -c " - mkdir -p /usr/share/opensearch/logs && - mkdir -p /usr/share/opensearch/data && - chown -R 1000:1000 /usr/share/opensearch/logs && - chown -R 1000:1000 /usr/share/opensearch/data && - chmod -R 755 /usr/share/opensearch/logs && - chmod -R 755 /usr/share/opensearch/data - " - - opensearch: - image: opensearchproject/opensearch:2.17.0 - container_name: opensearch - user: "1000:1000" - environment: - - discovery.type=single-node - - DISABLE_SECURITY_PLUGIN=true - - OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m - - DISABLE_INSTALL_DEMO_CONFIG=true - - DISABLE_PERFORMANCE_ANALYZER_AGENT_CLI=true - - bootstrap.memory_lock=true - ulimits: - memlock: - soft: -1 - hard: -1 - nofile: - soft: 65536 - hard: 65536 - ports: - - "9200:9200" - networks: - - linkedin-network - volumes: - - opensearch-data:/usr/share/opensearch/data - - ./logs/opensearch:/usr/share/opensearch/logs - depends_on: - opensearch-init: - condition: service_completed_successfully - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=opensearch" - - opensearch-dashboards: - image: opensearchproject/opensearch-dashboards:2.17.0 - container_name: opensearch-dashboards - user: "1000:1000" - environment: - - OPENSEARCH_HOSTS=http://opensearch:9200 - - DISABLE_SECURITY_DASHBOARDS_PLUGIN=true - ports: - - "5601:5601" - depends_on: - - opensearch - networks: - - linkedin-network - volumes: - - ./logs/opensearch-dashboards:/usr/share/opensearch-dashboards/logs - labels: - - "traefik.enable=true" - # HTTP route for local development - - "traefik.http.routers.opensearch-http.rule=Host(`logs.premtsd.com`)" - - "traefik.http.routers.opensearch-http.entrypoints=web" - - "traefik.http.services.opensearch-http.loadbalancer.server.port=5601" - # HTTPS route for production - - "traefik.http.routers.opensearch.rule=Host(`logs.premtsd.com`)" - - "traefik.http.routers.opensearch.entrypoints=websecure" - - "traefik.http.routers.opensearch.tls.certresolver=letsencrypt" - - "traefik.http.services.opensearch.loadbalancer.server.port=5601" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=opensearch-dashboards" - - opensearch-logstash: - image: opensearchproject/logstash-oss-with-opensearch-output-plugin:8.9.0 - container_name: opensearch-logstash - volumes: - - ./logstash/pipeline/logstash.conf:/usr/share/logstash/pipeline/logstash.conf - - ./logs/opensearch-logstash:/usr/share/logstash/logs - ports: - - "5044:5044" - networks: - - linkedin-network - depends_on: - - opensearch - environment: - - LS_JAVA_OPTS=-Xms256m -Xmx512m - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=opensearch-logstash" - - filebeat: - image: docker.elastic.co/beats/filebeat:8.13.4 - container_name: filebeat - user: root - volumes: - - ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro - - ./app/logs:/app/logs:ro - - ./logs:/logs:ro - - /var/lib/docker/containers:/var/lib/docker/containers:ro - - /var/run/docker.sock:/var/run/docker.sock:ro - - ./logs/filebeat:/var/log/filebeat - networks: - - linkedin-network - depends_on: - - opensearch-logstash - command: ["--strict.perms=false"] - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=filebeat" - - # ======================= - # Traefik Reverse Proxy with HTTPS - # ======================= - traefik: - image: traefik:v3.0 - container_name: traefik - command: - - "--api.dashboard=true" - - "--api.insecure=true" - - "--providers.docker=true" - - "--providers.docker.exposedbydefault=false" - - "--entrypoints.web.address=:80" - - "--entrypoints.websecure.address=:443" - - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" - - "--certificatesresolvers.letsencrypt.acme.email=i.prem.tsd@outlook.com" - - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" - - "--entrypoints.web.http.redirections.entrypoint.to=websecure" - - "--entrypoints.web.http.redirections.entrypoint.scheme=https" - - "--log.level=INFO" - ports: - - "80:80" - - "443:443" - - "8081:8080" # Traefik dashboard (changed from 8080 to avoid conflict) - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - - ./traefik/letsencrypt:/letsencrypt - - ./traefik/certs:/certs - - ./traefik/config:/etc/traefik/dynamic - networks: - - linkedin-network - restart: unless-stopped - labels: - - "traefik.enable=true" - - "traefik.http.routers.traefik.rule=Host(`traefik.premtsd.com`)" - - "traefik.http.routers.traefik.entrypoints=websecure" - - "traefik.http.routers.traefik.tls.certresolver=letsencrypt" - - "traefik.http.routers.traefik.service=api@internal" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: "service=traefik" -networks: - linkedin-network: - -volumes: - kafka_data: - linkedin-db-data: - connections-db-data: - opensearch-data: - prometheus-data: - grafana-data: - -#services: -# kafka: -# image: docker.io/bitnami/kafka:3.8 -# container_name: kafka -# platform: linux/arm64 -# volumes: -# - "kafka_data:/bitnami" -# - ./logs/kafka:/opt/bitnami/kafka/logs -# networks: -# - linkedin-network -# environment: -# - KAFKA_CFG_NODE_ID=0 -# - KAFKA_CFG_PROCESS_ROLES=controller,broker -# - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka:9093 -# - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 -# - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092 -# - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT -# - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER -# - KAFKA_CFG_INTER_BROKER_LISTENER_NAME=PLAINTEXT -# - KAFKA_HEAP_OPTS=-Xmx512m -Xms512m -# logging: -# driver: "json-file" -# options: -# max-size: "10m" -# max-file: "3" -# labels: "service=kafka" -# -# prem-portfolio: -# build: -# context: ./prem-portfolio -# container_name: prem-portfolio -# platform: linux/arm64 -# ports: -# - "4200:4200" -# networks: -# - linkedin-network -# restart: unless-stopped -# healthcheck: -# test: ["CMD", "curl", "-f", "http://localhost"] -# interval: 30s -# timeout: 10s -# retries: 3 -# labels: -# - "traefik.enable=true" -# - "traefik.http.routers.portfolio.rule=Host(`premtsd.com`) || Host(`www.premtsd.com`)" -# - "traefik.http.routers.portfolio.entrypoints=websecure" -# - "traefik.http.routers.portfolio.tls.certresolver=letsencrypt" -# - "traefik.http.services.portfolio.loadbalancer.server.port=80" -# # Redirect www to non-www -# - "traefik.http.middlewares.www-redirect.redirectregex.regex=^https://www.premtsd.com/(.*)" -# - "traefik.http.middlewares.www-redirect.redirectregex.replacement=https://premtsd.com/$${1}" -# - "traefik.http.routers.portfolio.middlewares=www-redirect" -# -# kafbat-ui: -# container_name: kafbat-ui -# image: ghcr.io/kafbat/kafka-ui:latest -# platform: linux/arm64 -# ports: -# - 8090:8080 -# depends_on: -# - kafka -# networks: -# - linkedin-network -# environment: -# KAFKA_CLUSTERS_0_NAME: local -# KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9092 -# volumes: -# - ./logs/kafbat-ui:/app/logs -# labels: -# - "traefik.enable=true" -# - "traefik.http.routers.kafka-ui.rule=Host(`kafka.premtsd.com`)" -# - "traefik.http.routers.kafka-ui.entrypoints=websecure" -# - "traefik.http.routers.kafka-ui.tls.certresolver=letsencrypt" -# - "traefik.http.services.kafka-ui.loadbalancer.server.port=8080" -# logging: -# driver: "json-file" -# options: -# max-size: "10m" -# max-file: "3" -# labels: "service=kafbat-ui" -# -# # ======================= -# # PostgreSQL -# # ======================= -# linkedin-db: -# image: postgres:15 -# container_name: linkedin-db -# environment: -# POSTGRES_DB: linkedinDB -# POSTGRES_USER: user -# POSTGRES_PASSWORD: password -# ports: -# - "5432:5432" -# volumes: -# - linkedin-db-data:/var/lib/postgresql/data -# networks: -# - linkedin-network -# -# # ======================= -# # Neo4j Graph DB -# # ======================= -# connections-db: -# image: neo4j:5.18 -# container_name: connections-db -# environment: -# NEO4J_AUTH: neo4j/password -# ports: -# - "7474:7474" -# - "7687:7687" -# volumes: -# - connections-db-data:/data -# networks: -# - linkedin-network -# -# discovery-server: -# image: premtsd18/discovery-server:arm64 -# restart: unless-stopped -# container_name: discovery-server -# platform: linux/arm64 -# networks: -# - linkedin-network -# ports: -# - "8761:8761" -# depends_on: -# config-server: -# condition: service_healthy -# volumes: -# - ./logs/discovery-server:/logs/discovery-server -# labels: -# - "traefik.enable=true" -# - "traefik.http.routers.eureka.rule=Host(`eureka.premtsd.com`)" -# - "traefik.http.routers.eureka.entrypoints=websecure" -# - "traefik.http.routers.eureka.tls.certresolver=letsencrypt" -# - "traefik.http.services.eureka.loadbalancer.server.port=8761" -# logging: -# driver: "json-file" -# options: -# max-size: "10m" -# max-file: "3" -# labels: "service=discovery-server" -# -# post-service: -# image: premtsd18/post-service:arm64 -# container_name: post-service -# platform: linux/arm64 -# networks: -# - linkedin-network -# depends_on: -# - discovery-server -# - linkedin-db -# - kafka -# - config-server -# environment: -# REDIS_HOST: redis -# REDIS_PORT: 6379 -# REDIS_PASSWORD: secret123 -# volumes: -# - ./app/logs/post-service:/app/logs/post-service -# logging: -# driver: "json-file" -# options: -# max-size: "10m" -# max-file: "3" -# labels: "service=post-service" -# -# user-service: -# image: premtsd18/user-service:arm64 -# container_name: user-service -# platform: linux/arm64 -# networks: -# - linkedin-network -# depends_on: -# - discovery-server -# - linkedin-db -# - kafka -# - config-server -# volumes: -# - ./app/logs/user-service:/app/logs/user-service -# logging: -# driver: "json-file" -# options: -# max-size: "10m" -# max-file: "3" -# labels: "service=user-service" -# -# notification-service: -# image: premtsd18/notification-service:arm64 -# container_name: notification-service -# platform: linux/arm64 -# networks: -# - linkedin-network -# depends_on: -# - discovery-server -# - linkedin-db -# - kafka -# - config-server -# volumes: -# - ./logs/notification-service:/logs/notification-service -# logging: -# driver: "json-file" -# options: -# max-size: "10m" -# max-file: "3" -# labels: "service=notification-service" -# -# connections-service: -# image: premtsd18/connections-service:arm64 -# container_name: connections-service -# platform: linux/arm64 -# networks: -# - linkedin-network -# depends_on: -# - discovery-server -# - connections-db -# - kafka -# - config-server -# volumes: -# - ./logs/connections-service:/logs/connections-service -# logging: -# driver: "json-file" -# options: -# max-size: "10m" -# max-file: "3" -# labels: "service=connections-service" -# -# api-gateway: -# image: premtsd18/api-gateway:arm64 -# container_name: api-gateway -# platform: linux/arm64 -# ports: -# - "8080:8080" -# networks: -# - linkedin-network -# depends_on: -# - discovery-server -# - config-server -# volumes: -# - ./logs/api-gateway:/logs/api-gateway -# labels: -# - "traefik.enable=true" -# - "traefik.http.routers.api.rule=Host(`api.premtsd.com`)" -# - "traefik.http.routers.api.entrypoints=websecure" -# - "traefik.http.routers.api.tls.certresolver=letsencrypt" -# - "traefik.http.services.api.loadbalancer.server.port=8080" -# # CORS middleware for API -# - "traefik.http.middlewares.api-cors.headers.accesscontrolallowmethods=GET,OPTIONS,PUT,POST,DELETE,PATCH" -# - "traefik.http.middlewares.api-cors.headers.accesscontrolalloworiginlist=https://premtsd.com,https://www.premtsd.com" -# - "traefik.http.middlewares.api-cors.headers.accesscontrolmaxage=100" -# - "traefik.http.middlewares.api-cors.headers.addvaryheader=true" -# - "traefik.http.routers.api.middlewares=api-cors" -# logging: -# driver: "json-file" -# options: -# max-size: "10m" -# max-file: "3" -# labels: "service=api-gateway" -# -# config-server: -# image: premtsd18/config-server:arm64 -# container_name: config-server -# platform: linux/arm64 -# networks: -# - linkedin-network -# env_file: -# - .env -# healthcheck: -# test: ["CMD", "curl", "-f", "http://localhost:8888/actuator/health"] -# interval: 10s -# timeout: 5s -# retries: 5 -# volumes: -# - ./logs/config-server:/logs/config-server -# logging: -# driver: "json-file" -# options: -# max-size: "10m" -# max-file: "3" -# labels: "service=config-server" -# -# redis: -# image: bitnami/redis:latest -# container_name: redis -# platform: linux/arm64 -# environment: -# - REDIS_PASSWORD=secret123 -# ports: -# - "6379:6379" -# networks: -# - linkedin-network -# volumes: -# - ./logs/redis:/opt/bitnami/redis/logs -# logging: -# driver: "json-file" -# options: -# max-size: "10m" -# max-file: "3" -# labels: "service=redis" -# -# uploader-service: -# image: premtsd18/uploader-service:arm64 -# container_name: uploader-service -# platform: linux/arm64 -# networks: -# - linkedin-network -# depends_on: -# - discovery-server -# - config-server -# volumes: -# - ./app/logs/uploader-service:/app/logs/uploader-service -# logging: -# driver: "json-file" -# options: -# max-size: "10m" -# max-file: "3" -# labels: "service=uploader-service" -# -# zipkin: -# image: openzipkin/zipkin:latest -# container_name: zipkin -# platform: linux/arm64 -# ports: -# - "9411:9411" -# networks: -# - linkedin-network -# environment: -# - JAVA_OPTS=-Xms256m -Xmx512m -# volumes: -# - ./logs/zipkin:/zipkin/logs -# labels: -# - "traefik.enable=true" -# - "traefik.http.routers.zipkin.rule=Host(`zipkin.premtsd.com`)" -# - "traefik.http.routers.zipkin.entrypoints=websecure" -# - "traefik.http.routers.zipkin.tls.certresolver=letsencrypt" -# - "traefik.http.services.zipkin.loadbalancer.server.port=9411" -# logging: -# driver: "json-file" -# options: -# max-size: "10m" -# max-file: "3" -# labels: "service=zipkin" -# -# opensearch: -# image: opensearchproject/opensearch:2.12.0 -# container_name: opensearch -# environment: -# discovery.type: single-node -# DISABLE_SECURITY_PLUGIN: "true" -# OPENSEARCH_JAVA_OPTS: -Xms512m -Xmx512m -# ports: -# - "9200:9200" -# networks: -# - linkedin-network -# -# opensearch-dashboards: -# image: opensearchproject/opensearch-dashboards:2.12.0 -# container_name: opensearch-dashboards -# environment: -# - OPENSEARCH_HOSTS=http://opensearch:9200 -# - DISABLE_SECURITY_DASHBOARDS_PLUGIN=true -# depends_on: -# - opensearch -# labels: -# - "traefik.enable=true" -# - "traefik.http.routers.opensearch.rule=Host(`logs.premtsd.com`)" -# - "traefik.http.routers.opensearch.entrypoints=websecure" -# - "traefik.http.routers.opensearch.tls.certresolver=letsencrypt" -# - "traefik.http.services.opensearch.loadbalancer.server.port=5601" -# networks: -# - linkedin-network -# -# -# opensearch-logstash: -# image: opensearchproject/logstash-oss-with-opensearch-output-plugin:8.9.0 -# container_name: opensearch-logstash -# platform: linux/arm64 -# volumes: -# - ./logstash/pipeline/logstash.conf:/usr/share/logstash/pipeline/logstash.conf -# - ./logs/opensearch-logstash:/usr/share/logstash/logs -# ports: -# - "5044:5044" -# networks: -# - linkedin-network -# depends_on: -# - opensearch -# environment: -# - LS_JAVA_OPTS=-Xms256m -Xmx512m -# logging: -# driver: "json-file" -# options: -# max-size: "10m" -# max-file: "3" -# labels: "service=opensearch-logstash" -# -# filebeat: -# image: docker.elastic.co/beats/filebeat:8.13.4 -# container_name: filebeat -# platform: linux/arm64 -# user: root -# volumes: -# - ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro -# - ./app/logs:/app/logs:ro -# - ./logs:/logs:ro -# - /var/lib/docker/containers:/var/lib/docker/containers:ro -# - /var/run/docker.sock:/var/run/docker.sock:ro -# - ./logs/filebeat:/var/log/filebeat -# networks: -# - linkedin-network -# depends_on: -# - opensearch-logstash -# command: ["--strict.perms=false"] -# logging: -# driver: "json-file" -# options: -# max-size: "10m" -# max-file: "3" -# labels: "service=filebeat" -# -# # ======================= -# # Traefik Reverse Proxy with HTTPS (ARM64) -# # ======================= -# traefik: -# image: traefik:v3.0 -# container_name: traefik -# platform: linux/arm64 -# command: -# - "--api.dashboard=true" -# - "--api.insecure=true" -# - "--providers.docker=true" -# - "--providers.docker.exposedbydefault=false" -# - "--entrypoints.web.address=:80" -# - "--entrypoints.websecure.address=:443" -# - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" -# - "--certificatesresolvers.letsencrypt.acme.email=i.prem.tsd@outlook.com" -# - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" -# - "--entrypoints.web.http.redirections.entrypoint.to=websecure" -# - "--entrypoints.web.http.redirections.entrypoint.scheme=https" -# - "--log.level=INFO" -# ports: -# - "80:80" -# - "443:443" -# - "8081:8080" # Traefik dashboard (changed from 8080 to avoid conflict) -# volumes: -# - /var/run/docker.sock:/var/run/docker.sock:ro -# - ./traefik/letsencrypt:/letsencrypt -# - ./traefik/certs:/certs -# - ./traefik/config:/etc/traefik/dynamic -# networks: -# - linkedin-network -# restart: unless-stopped -# labels: -# - "traefik.enable=true" -# - "traefik.http.routers.traefik.rule=Host(`traefik.premtsd.com`)" -# - "traefik.http.routers.traefik.entrypoints=websecure" -# - "traefik.http.routers.traefik.tls.certresolver=letsencrypt" -# - "traefik.http.routers.traefik.service=api@internal" -# logging: -# driver: "json-file" -# options: -# max-size: "10m" -# max-file: "3" -# labels: "service=traefik" -# -#networks: -# linkedin-network: -# -#volumes: -# kafka_data: -# linkedin-db-data: -# connections-db-data: -# prometheus-data: -# grafana-data: +networks: + linkedin-network: + +volumes: + kafka_data: + linkedin-db-data: + connections-db-data: + opensearch-data: + +# ============================================================ +# PORT MAP — LinkedIn Project (10000–10999 range) +# ============================================================ +# Microservices: 10000–10099 +# 10000 → api-gateway +# 10001 → discovery-server +# 10003 → notification-service +# Databases: 10100–10199 +# 10100 → postgres (linkedin-db) +# 10101 → neo4j browser +# 10102 → neo4j bolt +# 10103 → redis +# Messaging: 10200–10299 +# 10201 → kafbat-ui +# Observability: 10300–10399 +# 10300 → zipkin +# 10301 → opensearch +# 10302 → opensearch-dashboards +# 10303 → opensearch-logstash +# Infrastructure: 10400–10499 +# 10400 → traefik http +# 10401 → traefik https +# 10402 → traefik dashboard +# App: 10500–10599 +# 10500 → prem-portfolio +# ============================================================ + +services: + + # ── Infrastructure ─────────────────────────────────────── + + traefik: + image: traefik:v3.0 + platform: linux/amd64 + container_name: linkedin-traefik + command: + - "--api.dashboard=true" + - "--api.insecure=true" + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" + - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" + - "--certificatesresolvers.letsencrypt.acme.email=i.prem.tsd@outlook.com" + - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" + - "--entrypoints.web.http.redirections.entrypoint.to=websecure" + - "--entrypoints.web.http.redirections.entrypoint.scheme=https" + - "--log.level=INFO" + ports: + - "10400:80" + - "10401:443" + - "10402:8080" + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - ./traefik/letsencrypt:/letsencrypt + - ./traefik/certs:/certs + - ./traefik/config:/etc/traefik/dynamic + networks: + - linkedin-network + restart: unless-stopped + labels: + - "traefik.enable=true" + - "traefik.http.routers.traefik.rule=Host(`traefik.premtsd.com`)" + - "traefik.http.routers.traefik.entrypoints=websecure" + - "traefik.http.routers.traefik.tls.certresolver=letsencrypt" + - "traefik.http.routers.traefik.service=api@internal" + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=traefik" + + # ── Config + Discovery ─────────────────────────────────── + + config-server: + build: + context: ./config-server + platform: linux/amd64 + container_name: linkedin-config-server + networks: + - linkedin-network + env_file: + - .env + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8888/actuator/health"] + interval: 10s + timeout: 5s + retries: 5 + volumes: + - ./logs/config-server:/logs/config-server + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=config-server" + + discovery-server: + build: + context: ./discovery-server + platform: linux/amd64 + restart: unless-stopped + container_name: linkedin-discovery-server + networks: + - linkedin-network + ports: + - "10001:8761" + depends_on: + config-server: + condition: service_healthy + volumes: + - ./logs/discovery-server:/logs/discovery-server + labels: + - "traefik.enable=true" + - "traefik.http.routers.eureka.rule=Host(`eureka.premtsd.com`)" + - "traefik.http.routers.eureka.entrypoints=websecure" + - "traefik.http.routers.eureka.tls.certresolver=letsencrypt" + - "traefik.http.services.eureka.loadbalancer.server.port=8761" + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=discovery-server" + + # ── Databases ──────────────────────────────────────────── + + linkedin-db: + image: postgres:15 + platform: linux/amd64 + container_name: linkedin-db + environment: + - POSTGRES_DB=linkedinDB + - POSTGRES_USER=user + - POSTGRES_PASSWORD=password + ports: + - "10100:5432" + networks: + - linkedin-network + volumes: + - linkedin-db-data:/var/lib/postgresql/data + - ./logs/linkedin-db:/var/log/postgresql + healthcheck: + test: ["CMD-SHELL", "pg_isready -U user"] + interval: 10s + retries: 5 + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=linkedin-db" + + connections-db: + image: neo4j:5 + platform: linux/amd64 + container_name: connections-db + environment: + - NEO4J_AUTH=neo4j/password + ports: + - "10101:7474" + - "10102:7687" + volumes: + - connections-db-data:/data + - ./logs/connections-db:/logs + networks: + - linkedin-network + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=connections-db" + + redis: + image: bitnami/redis:latest + platform: linux/amd64 + container_name: linkedin-redis + environment: + - REDIS_PASSWORD=secret123 + ports: + - "10103:6379" + networks: + - linkedin-network + volumes: + - ./logs/redis:/opt/bitnami/redis/logs + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=redis" + + # ── Messaging ──────────────────────────────────────────── + + kafka: + image: apache/kafka:3.7.0 + platform: linux/amd64 + container_name: linkedin-kafka + volumes: + - "kafka_data:/tmp/kraft-combined-logs" + - ./logs/kafka:/opt/kafka/logs + networks: + - linkedin-network + environment: + - KAFKA_NODE_ID=0 + - KAFKA_PROCESS_ROLES=controller,broker + - KAFKA_CONTROLLER_QUORUM_VOTERS=0@kafka:9093 + - KAFKA_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 + - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092 + - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT + - KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER + - KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT + - KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 + - KAFKA_HEAP_OPTS=-Xmx512m -Xms512m + - CLUSTER_ID=MkU3OEVBNTcwNTJENDM2Qk + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=kafka" + + kafbat-ui: + image: ghcr.io/kafbat/kafka-ui:latest + platform: linux/amd64 + container_name: linkedin-kafbat-ui + ports: + - "10201:8080" + depends_on: + - kafka + networks: + - linkedin-network + environment: + KAFKA_CLUSTERS_0_NAME: local + KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9092 + volumes: + - ./logs/kafbat-ui:/app/logs + labels: + - "traefik.enable=true" + - "traefik.http.routers.kafka-ui.rule=Host(`kafka.premtsd.com`)" + - "traefik.http.routers.kafka-ui.entrypoints=websecure" + - "traefik.http.routers.kafka-ui.tls.certresolver=letsencrypt" + - "traefik.http.services.kafka-ui.loadbalancer.server.port=8080" + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=kafbat-ui" + + # ── Microservices ───────────────────────────────────────── + + api-gateway: + build: + context: ./api-gateway + platform: linux/amd64 + container_name: linkedin-api-gateway + ports: + - "10000:8080" + networks: + - linkedin-network + depends_on: + - discovery-server + - config-server + volumes: + - ./logs/api-gateway:/logs/api-gateway + labels: + - "traefik.enable=true" + - "traefik.http.routers.api.rule=Host(`api.premtsd.com`)" + - "traefik.http.routers.api.entrypoints=websecure" + - "traefik.http.routers.api.tls.certresolver=letsencrypt" + - "traefik.http.services.api.loadbalancer.server.port=8080" + - "traefik.http.middlewares.api-cors.headers.accesscontrolallowmethods=GET,OPTIONS,PUT,POST,DELETE,PATCH" + - "traefik.http.middlewares.api-cors.headers.accesscontrolalloworiginlist=https://premtsd.com,https://www.premtsd.com" + - "traefik.http.middlewares.api-cors.headers.accesscontrolmaxage=100" + - "traefik.http.middlewares.api-cors.headers.addvaryheader=true" + - "traefik.http.routers.api.middlewares=api-cors" + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=api-gateway" + + user-service: + build: + context: ./user-service + platform: linux/amd64 + container_name: linkedin-user-service + networks: + - linkedin-network + depends_on: + - discovery-server + - linkedin-db + - kafka + - config-server + volumes: + - ./app/logs/user-service:/app/logs/user-service + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=user-service" + + post-service: + build: + context: ./post-service + platform: linux/amd64 + container_name: linkedin-post-service + networks: + - linkedin-network + depends_on: + - discovery-server + - linkedin-db + - kafka + - config-server + environment: + REDIS_HOST: redis + REDIS_PORT: 6379 + REDIS_PASSWORD: secret123 + volumes: + - ./app/logs/post-service:/app/logs/post-service + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=post-service" + + connections-service: + build: + context: ./connections-service + platform: linux/amd64 + container_name: linkedin-connections-service + networks: + - linkedin-network + depends_on: + - discovery-server + - connections-db + - kafka + - config-server + volumes: + - ./logs/connections-service:/logs/connections-service + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=connections-service" + + notification-service: + build: + context: ./notification-service + platform: linux/amd64 + container_name: linkedin-notification-service + ports: + - "10003:9293" + networks: + - linkedin-network + depends_on: + - discovery-server + - linkedin-db + - kafka + - config-server + volumes: + - ./logs/notification-service:/logs/notification-service + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=notification-service" + + uploader-service: + build: + context: ./uploader-service + platform: linux/amd64 + container_name: linkedin-uploader-service + networks: + - linkedin-network + depends_on: + - discovery-server + - config-server + volumes: + - ./app/logs/uploader-service:/app/logs/uploader-service + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=uploader-service" + + zipkin: + image: openzipkin/zipkin + platform: linux/amd64 + container_name: linkedin-zipkin + ports: + - "10300:9411" + networks: + - linkedin-network + environment: + - JAVA_OPTS=-Xms256m -Xmx512m + volumes: + - ./logs/zipkin:/zipkin/logs + labels: + - "traefik.enable=true" + - "traefik.http.routers.zipkin.rule=Host(`zipkin.premtsd.com`)" + - "traefik.http.routers.zipkin.entrypoints=websecure" + - "traefik.http.routers.zipkin.tls.certresolver=letsencrypt" + - "traefik.http.services.zipkin.loadbalancer.server.port=9411" + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=zipkin" + + opensearch-init: + image: busybox:latest + platform: linux/amd64 + container_name: linkedin-opensearch-init + user: root + volumes: + - opensearch-data:/usr/share/opensearch/data + - ./logs/opensearch:/usr/share/opensearch/logs + command: > + sh -c " + mkdir -p /usr/share/opensearch/logs && + mkdir -p /usr/share/opensearch/data && + chown -R 1000:1000 /usr/share/opensearch/logs && + chown -R 1000:1000 /usr/share/opensearch/data && + chmod -R 755 /usr/share/opensearch/logs && + chmod -R 755 /usr/share/opensearch/data + " + + opensearch: + image: opensearchproject/opensearch:2.17.0 + platform: linux/amd64 + container_name: linkedin-opensearch + user: "1000:1000" + environment: + - discovery.type=single-node + - DISABLE_SECURITY_PLUGIN=true + - OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m + - DISABLE_INSTALL_DEMO_CONFIG=true + - DISABLE_PERFORMANCE_ANALYZER_AGENT_CLI=true + - bootstrap.memory_lock=true + ulimits: + memlock: + soft: -1 + hard: -1 + nofile: + soft: 65536 + hard: 65536 + ports: + - "10301:9200" + networks: + - linkedin-network + volumes: + - opensearch-data:/usr/share/opensearch/data + - ./logs/opensearch:/usr/share/opensearch/logs + depends_on: + opensearch-init: + condition: service_completed_successfully + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=opensearch" + + opensearch-dashboards: + image: opensearchproject/opensearch-dashboards:2.17.0 + platform: linux/amd64 + container_name: linkedin-opensearch-dashboards + user: "1000:1000" + environment: + - OPENSEARCH_HOSTS=http://opensearch:9200 + - DISABLE_SECURITY_DASHBOARDS_PLUGIN=true + ports: + - "10302:5601" + depends_on: + - opensearch + networks: + - linkedin-network + volumes: + - ./logs/opensearch-dashboards:/usr/share/opensearch-dashboards/logs + labels: + - "traefik.enable=true" + - "traefik.http.routers.opensearch-http.rule=Host(`logs.premtsd.com`)" + - "traefik.http.routers.opensearch-http.entrypoints=web" + - "traefik.http.services.opensearch-http.loadbalancer.server.port=5601" + - "traefik.http.routers.opensearch.rule=Host(`logs.premtsd.com`)" + - "traefik.http.routers.opensearch.entrypoints=websecure" + - "traefik.http.routers.opensearch.tls.certresolver=letsencrypt" + - "traefik.http.services.opensearch.loadbalancer.server.port=5601" + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=opensearch-dashboards" + + opensearch-logstash: + image: opensearchproject/logstash-oss-with-opensearch-output-plugin:8.9.0 + platform: linux/amd64 + container_name: linkedin-opensearch-logstash + volumes: + - ./logstash/pipeline/logstash.conf:/usr/share/logstash/pipeline/logstash.conf + - ./logs/opensearch-logstash:/usr/share/logstash/logs + ports: + - "10303:5044" + networks: + - linkedin-network + depends_on: + - opensearch + environment: + - LS_JAVA_OPTS=-Xms256m -Xmx512m + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=opensearch-logstash" + + filebeat: + image: docker.elastic.co/beats/filebeat:8.13.4 + platform: linux/amd64 + container_name: linkedin-filebeat + user: root + volumes: + - ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro + - ./app/logs:/app/logs:ro + - ./logs:/logs:ro + - /var/lib/docker/containers:/var/lib/docker/containers:ro + - /var/run/docker.sock:/var/run/docker.sock:ro + - ./logs/filebeat:/var/log/filebeat + networks: + - linkedin-network + depends_on: + - opensearch-logstash + command: ["--strict.perms=false"] + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: "service=filebeat" \ No newline at end of file From 78f113be934af280f6c7b58e059d4e8b1c5ccd71 Mon Sep 17 00:00:00 2001 From: Prem Palanisamy Date: Tue, 17 Mar 2026 22:12:12 +0100 Subject: [PATCH 2/2] ci: make checks non-blocking until tests are added --- .github/workflows/pr-checks.yml | 45 ++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 8d4525a..49135e3 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -44,6 +44,7 @@ jobs: unit-tests: name: Unit Tests runs-on: ubuntu-latest + continue-on-error: true steps: - uses: actions/checkout@v4 - name: Set up JDK 17 @@ -53,10 +54,16 @@ jobs: distribution: 'corretto' cache: maven - name: Run unit tests - run: mvn test -DskipIntegrationTests=true + run: | + if [ -f "pom.xml" ]; then + mvn test -DskipIntegrationTests=true || true + else + echo "No root pom.xml found — skipping tests" + fi - name: Upload test results uses: actions/upload-artifact@v4 if: always() + continue-on-error: true with: name: unit-test-results path: '**/target/surefire-reports/*.xml' @@ -64,7 +71,7 @@ jobs: code-coverage: name: Code Coverage runs-on: ubuntu-latest - needs: unit-tests + continue-on-error: true steps: - uses: actions/checkout@v4 - name: Set up JDK 17 @@ -74,9 +81,15 @@ jobs: distribution: 'corretto' cache: maven - name: Run tests with coverage - run: mvn verify jacoco:report -DskipIntegrationTests=true + run: | + if [ -f "pom.xml" ]; then + mvn verify jacoco:report -DskipIntegrationTests=true || true + else + echo "No root pom.xml — skipping coverage" + fi - name: Upload coverage report uses: actions/upload-artifact@v4 + continue-on-error: true with: name: coverage-report path: '**/target/site/jacoco/' @@ -84,6 +97,7 @@ jobs: security-scan: name: Security Scan runs-on: ubuntu-latest + continue-on-error: true steps: - uses: actions/checkout@v4 - name: Set up JDK 17 @@ -93,11 +107,19 @@ jobs: distribution: 'corretto' cache: maven - name: OWASP Dependency Check - run: mvn dependency-check:check -DfailBuildOnCVSS=7 -DskipTestScope=true + run: | + if [ -f "pom.xml" ]; then + mvn dependency-check:check \ + -DfailBuildOnCVSS=7 \ + -DskipTestScope=true || true + else + echo "No root pom.xml — skipping OWASP" + fi continue-on-error: true - name: Upload OWASP report uses: actions/upload-artifact@v4 if: always() + continue-on-error: true with: name: owasp-report path: '**/target/dependency-check-report.html' @@ -105,6 +127,7 @@ jobs: code-quality: name: Code Quality runs-on: ubuntu-latest + continue-on-error: true steps: - uses: actions/checkout@v4 with: @@ -116,8 +139,18 @@ jobs: distribution: 'corretto' cache: maven - name: Checkstyle - run: mvn checkstyle:check + run: | + if [ -f "pom.xml" ]; then + mvn checkstyle:check || true + else + echo "No root pom.xml — skipping checkstyle" + fi continue-on-error: true - name: SpotBugs - run: mvn spotbugs:check + run: | + if [ -f "pom.xml" ]; then + mvn spotbugs:check || true + else + echo "No root pom.xml — skipping spotbugs" + fi continue-on-error: true