Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Ignore build artifacts
mimic
*.db
*.log

# Ignore development files
.git
.gitignore
README.md
*.md
justfile

# Ignore test files
*_test.go
test/

# Ignore IDE files
.vscode/
.idea/
*.swp
*.swo

# Ignore OS files
.DS_Store
Thumbs.db

# Ignore temporary files
tmp/
temp/
*.tmp

# Ignore helm chart (built separately)
helm/

# Ignore docker files
Dockerfile*
.dockerignore
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
*.dll
*.so
*.dylib
mimic
mimic-*

./mimic

# Test binary, built with `go test -c`
*.test

Expand Down
83 changes: 83 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Multi-architecture Dockerfile for Mimic
# Supports both amd64 and arm64 architectures

# Build stage
FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS builder

# Build arguments for cross-compilation
ARG TARGETOS
ARG TARGETARCH
ARG BUILDPLATFORM

# Install build dependencies including gcc for CGO (required for SQLite)
RUN apk update && apk add --no-cache \
git \
ca-certificates \
tzdata \
gcc \
musl-dev \
sqlite-dev \
&& update-ca-certificates

# Create appuser for security
RUN adduser -D -g '' appuser

# Set working directory
WORKDIR /app

# Copy go mod files first for better caching
COPY go.mod go.sum ./

# Download dependencies
RUN go mod download
RUN go mod verify

# Copy source code
COPY . .

# Build the binary with optimizations for target architecture
RUN CGO_ENABLED=1 GOOS=$TARGETOS GOARCH=$TARGETARCH go build \
-ldflags='-w -s' \
-o mimic .

# Final stage - minimal runtime image
FROM --platform=$TARGETPLATFORM alpine:latest

# Install runtime dependencies
RUN apk --no-cache add \
ca-certificates \
sqlite \
musl \
wget

# Create appuser
RUN addgroup -g 1001 appuser && adduser -u 1001 -G appuser -s /bin/sh -D appuser

# Create directories
RUN mkdir -p /app/web/static /app/protos /data && \
chown -R appuser:appuser /app /data

WORKDIR /app

# Copy static files for web UI
COPY --from=builder --chown=appuser:appuser /app/web/static ./web/static

# Copy the binary
COPY --from=builder --chown=appuser:appuser /app/mimic .

# Copy example configurations
COPY --from=builder --chown=appuser:appuser /app/config*.yaml ./

# Use non-root user
USER appuser

# Expose ports
EXPOSE 8080 9090

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/ || exit 1

# Set entrypoint
ENTRYPOINT ["./mimic"]
CMD ["--config", "/app/config/config.yaml"]
83 changes: 83 additions & 0 deletions Dockerfile.multiarch
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Multi-architecture Dockerfile for Mimic
# Supports both amd64 and arm64 architectures

# Build stage
FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS builder

# Build arguments for cross-compilation
ARG TARGETOS
ARG TARGETARCH
ARG BUILDPLATFORM

# Install build dependencies including gcc for CGO (required for SQLite)
RUN apk update && apk add --no-cache \
git \
ca-certificates \
tzdata \
gcc \
musl-dev \
sqlite-dev \
&& update-ca-certificates

# Create appuser for security
RUN adduser -D -g '' appuser

# Set working directory
WORKDIR /app

# Copy go mod files first for better caching
COPY go.mod go.sum ./

# Download dependencies
RUN go mod download
RUN go mod verify

# Copy source code
COPY . .

# Build the binary with optimizations for target architecture
RUN CGO_ENABLED=1 GOOS=$TARGETOS GOARCH=$TARGETARCH go build \
-ldflags='-w -s' \
-o mimic .

# Final stage - minimal runtime image
FROM --platform=$TARGETPLATFORM alpine:latest

# Install runtime dependencies
RUN apk --no-cache add \
ca-certificates \
sqlite \
musl \
wget

# Create appuser
RUN addgroup -g 1001 appuser && adduser -u 1001 -G appuser -s /bin/sh -D appuser

# Create directories
RUN mkdir -p /app/web/static /app/protos /data && \
chown -R appuser:appuser /app /data

WORKDIR /app

# Copy static files for web UI
COPY --from=builder --chown=appuser:appuser /app/web/static ./web/static

# Copy the binary
COPY --from=builder --chown=appuser:appuser /app/mimic .

# Copy example configurations
COPY --from=builder --chown=appuser:appuser /app/config*.yaml ./

# Use non-root user
USER appuser

# Expose ports
EXPOSE 8080 9090

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/ || exit 1

# Set entrypoint
ENTRYPOINT ["./mimic"]
CMD ["--config", "/app/config/config.yaml"]
172 changes: 172 additions & 0 deletions GRPC_ROUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# gRPC Path-Based Routing

Mimic uses a single gRPC server with intelligent path-based routing to handle multiple backend services. This approach is more efficient and easier to manage than running multiple gRPC server instances.

## How gRPC Routing Works
```yaml
# config-grpc-routing.yaml
proxies:
user-service:
mode: "record"
protocol: "grpc"
target_host: "user-api.internal.com"
target_port: 9090
session_name: "user-session"
service_pattern: "com\\.example\\.userservice\\..*" # Routes based on service name

order-service:
mode: "record"
protocol: "grpc"
target_host: "order-api.internal.com"
target_port: 9091
session_name: "order-session"
service_pattern: "com\\.example\\.orderservice\\..*"

default-backend:
mode: "record"
protocol: "grpc"
target_host: "default-api.internal.com"
target_port: 9090
session_name: "default-session"
is_default: true # Catches unmatched requests
```

**Result**: Creates 1 gRPC server on configurable port (defaults to 9080) that routes based on service patterns

## How It Works

### Service/Method Routing

gRPC method names follow the format: `/package.ServiceName/MethodName`

Examples:
- `/com.example.userservice.UserService/GetUser` → routed to user-api.internal.com:9090
- `/com.example.orderservice.OrderService/CreateOrder` → routed to order-api.internal.com:9091
- `/grpc.health.v1.Health/Check` → routed to default-api.internal.com:9090

### Pattern Types

1. **Service Pattern**: Routes based on service name
```yaml
service_pattern: "com\\.example\\.userservice\\..*"
```

2. **Method Pattern**: Routes based on method name
```yaml
method_pattern: "Get.*|List.*" # Only GET and LIST methods
```

3. **Combined Patterns**: Both service and method must match
```yaml
service_pattern: "com\\.example\\..*"
method_pattern: "Health.*"
```

4. **Default Route**: Catches everything that doesn't match other patterns
```yaml
is_default: true
```

## Usage Examples

### Start the Server with gRPC Routing
```bash
# Start mimic with gRPC routing (routing is automatic for gRPC proxies)
mimic --config config-grpc-routing.yaml

# Output:
# Starting multi-proxy server
# Web UI available at http://0.0.0.0:8080/
# gRPC router server listening on 0.0.0.0:9080
# → Route 'user-service': com\.example\.userservice\..* -> user-api.internal.com:9090
# → Route 'order-service': com\.example\.orderservice\..* -> order-api.internal.com:9091
# → Route 'default-backend': (default) -> default-api.internal.com:9090
# gRPC router server available at 0.0.0.0:9080
```

### Test Routing
```bash
# This goes to user-api.internal.com:9090
grpcurl -plaintext localhost:9080 com.example.userservice.UserService/GetUser

# This goes to order-api.internal.com:9091
grpcurl -plaintext localhost:9080 com.example.orderservice.OrderService/CreateOrder

# This goes to default-api.internal.com:9090 (default route)
grpcurl -plaintext localhost:9080 some.other.service.SomeService/SomeMethod
```

## Benefits of gRPC Routing

1. **Resource Efficiency**: Single gRPC server handles all routes
2. **Simplified Deployment**: One configurable gRPC port to manage
3. **Flexible Routing**: Route by service name, method patterns, or any combination
4. **Session Isolation**: Different sessions per route for organized recording
5. **Fallback Support**: Default routes for unmatched requests
6. **Automatic**: No special configuration needed - just define gRPC proxies with patterns

## Advanced Examples

### Method-Specific Routing
```yaml
# Route only health checks to a dedicated service
health-service:
mode: "record"
protocol: "grpc"
target_host: "health.internal.com"
target_port: 9093
session_name: "health-session"
method_pattern: "Check|Watch" # Only health check methods
```

### Environment-Based Routing
```yaml
# Route staging services to staging backends
staging-services:
mode: "record"
protocol: "grpc"
target_host: "staging-api.internal.com"
target_port: 9090
session_name: "staging-session"
service_pattern: ".*\\.staging\\..*"

# Route production services to production backends
prod-services:
mode: "record"
protocol: "grpc"
target_host: "prod-api.internal.com"
target_port: 9090
session_name: "prod-session"
service_pattern: ".*\\.prod\\..*"
```

### Mock Mode with Routing
```yaml
# Same routing works for mock mode
proxies:
user-service-mock:
mode: "mock" # Switch to mock mode
protocol: "grpc"
session_name: "user-session" # Use recorded session
service_pattern: "com\\.example\\.userservice\\..*"

order-service-mock:
mode: "mock"
protocol: "grpc"
session_name: "order-session"
service_pattern: "com\\.example\\.orderservice\\..*"
```

## Implementation Details

The routing is implemented using:

1. **GRPCRouter**: Manages multiple routes and pattern matching
2. **GRPCRoute**: Individual route with target configuration and patterns
3. **UnknownServiceHandler**: Intercepts all gRPC calls and routes them
4. **Pattern Matching**: Uses regex patterns to match service/method names
5. **MultiProxyServer**: Automatically creates routing when gRPC proxies are configured

The router extracts the service and method from the full gRPC method name (`/package.ServiceName/MethodName`) and matches against configured patterns to determine the target backend.

This approach provides the flexibility of multiple gRPC proxies while maintaining the simplicity of a single server endpoint. Routing is enabled automatically when you configure gRPC proxies - no special commands or setup required!
Loading