Skip to content

Microservices Example

This example demonstrates deploying a microservices architecture with service-to-service communication.

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                        API Gateway                               │
│                      (Traefik)                                  │
└──────────────────────────┬──────────────────────────────────────┘
           ┌───────────────┼───────────────┐
           │               │               │
      ┌────▼────┐    ┌────▼────┐    ┌────▼────┐
      │  Auth   │    │  Users  │    │  Orders │
      │ Service │    │ Service │    │ Service │
      └────┬────┘    └────┬────┘    └────┬────┘
           │               │               │
           └───────────────┼───────────────┘
                    ┌──────▼──────┐
                    │  Database   │
                    │  (Postgres) │
                    └─────────────┘

Application Definition

apiVersion: core.oam.dev/v1alpha2
kind: Application
metadata:
  name: microservices-demo
  labels:
    environment: staging
spec:
  components:
    # API Gateway
    - name: gateway
      type: webservice
      properties:
        image: traefik:v3.0
        args:
          - --api.insecure=true
          - --providers.consul
          - --providers.consul.catalog
        ports:
          - name: http
            port: 80
            expose: true
          - name: https
            port: 443
            expose: true
          - name: admin
            port: 8080
        resources:
          cpu: 500m
          memory: 256Mi
      traits:
        - type: ingress
          properties:
            host: api.example.com
            tls: true
        - type: scaler
          properties:
            replicas: 2

    # Auth Service
    - name: auth-service
      type: webservice
      properties:
        image: demo/auth-service:v1.2.0
        ports:
          - name: http
            port: 8080
        resources:
          cpu: 500m
          memory: 512Mi
        env:
          - name: JWT_SECRET
            valueFrom:
              vaultSecret:
                path: secret/data/auth
                field: jwt-secret
          - name: DATABASE_URL
            value: postgres://postgres:5432/auth
      traits:
        - type: servicediscovery.nomad.oam.dev
          properties:
            serviceName: auth
            tags:
              - auth
              - v1
            port: http
            check:
              type: http
              path: /health
              interval: 10s
              timeout: 3s
        - type: vault-secret
          properties:
            path: secret/data/auth
            changeMode: restart
            env:
              JWT_SECRET: jwt-secret

    # Users Service
    - name: users-service
      type: webservice
      properties:
        image: demo/users-service:v1.2.0
        ports:
          - name: http
            port: 8080
        resources:
          cpu: 1000m
          memory: 512Mi
        env:
          - name: DATABASE_URL
            value: postgres://postgres:5432/users
          - name: AUTH_SERVICE
            value: http://auth
      traits:
        - type: servicediscovery.nomad.oam.dev
          properties:
            serviceName: users
            tags:
              - users
              - v1
            port: http
            check:
              type: http
              path: /health
              interval: 10s
              timeout: 3s

    # Orders Service
    - name: orders-service
      type: webservice
      properties:
        image: demo/orders-service:v1.2.0
        ports:
          - name: http
            port: 8080
        resources:
          cpu: 1000m
          memory: 1024Mi
        env:
          - name: DATABASE_URL
            value: postgres://postgres:5432/orders
          - name: USERS_SERVICE
            value: http://users
          - name: AUTH_SERVICE
            value: http://auth
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
      traits:
        - type: scaler
          properties:
            replicas: 3
            min: 2
            max: 6
        - type: servicediscovery.nomad.oam.dev
          properties:
            serviceName: orders
            tags:
              - orders
              - v1
            port: http
            check:
              type: http
              path: /health
              interval: 10s
              timeout: 3s
        - type: affinity
          properties:
            spread: true

    # Database (external)
    - name: postgres
      type: webservice
      properties:
        image: postgres:15-alpine
        env:
          - name: POSTGRES_DB
            value: main
          - name: POSTGRES_USER
            valueFrom:
              vaultSecret:
                path: secret/data/database
                field: username
          - name: POSTGRES_PASSWORD
            valueFrom:
              vaultSecret:
                path: secret/data/database
                field: password
        resources:
          cpu: 1000m
          memory: 2048Mi
        volumes:
          - source: postgres-data
            destination: /var/lib/postgresql/data
      traits:
        - type: volume
          properties:
            name: postgres-data
            type: csi
            source: postgres-storage
            mountPath: /var/lib/postgresql/data
        - type: vault-secret
          properties:
            path: secret/data/database
            changeMode: restart
            env:
              username: username
              password: password

  scopes:
    - scopeRef:
        kind: networkscope.nomad.oam.dev
        name: staging-network
      properties:
        networkMode: bridge
        serviceMesh: true
        connectSidecar: true

    - scopeRef:
        kind: nodepool.nomad.oam.dev
        name: staging-pool
      properties:
        poolName: staging-pool
        datacenter:
          - dc1

    - scopeRef:
        kind: namespace.nomad.oam.dev
        name: staging-ns
      properties:
        namespace: microservices-staging

Service Communication

With Consul Connect (service mesh), services communicate via mTLS:

// Service discovery - Consul resolves the service name
// Example: connecting to auth service
conn, err := grpc.Dial("consul://auth", grpc.WithInsecure())

Traffic Flow

  1. External request → Traefik (Gateway)
  2. Traefik → Consul Catalog (service discovery)
  3. Consul Connect routes with mTLS
  4. Service → Service (mesh)

Secrets

All sensitive data is stored in Vault:

  • JWT secrets
  • Database credentials
  • API keys