Skip to content

Latest commit

 

History

History
268 lines (219 loc) · 7.21 KB

File metadata and controls

268 lines (219 loc) · 7.21 KB

Adding Services to the A.R.C. Catalog

This guide explains how to add new services to the A.R.C. service catalog.

Overview

Adding a new service involves:

  1. Define the service in services.yaml
  2. Create a Docker Compose template
  3. Create config file templates (if needed)
  4. Define dependencies
  5. Test and validate

Step 1: Define Service in services.yaml

Edit pkg/catalog/data/services.yaml:

services:
  # Use a unique codename (lowercase, can include hyphens)
  my-service:
    codename: my-service
    technology: MyTech  # The underlying technology
    role: Infrastructure  # One of: Infrastructure, Data, AI, Observability
    description: "Short description of what the service does."
    version: "1.0"
    image: "myorg/myimage:v1.0"

    # Port mappings
    ports:
      - host: 8080
        container: 8080
        protocol: tcp  # tcp or udp
        description: "HTTP API"

    # Dependencies on other services (by codename)
    dependencies:
      - oracle
      - sonic

    # Environment variables
    environment:
      - name: MY_VAR
        default: "value"
        required: false
        description: "Description of the variable"
      - name: SECRET_KEY
        required: true
        description: "Required secret"

    # Volume mounts
    volumes:
      - host: "./.arc/data/myservice"
        container: "/data"
        description: "Data storage"
        read_only: false

    # Config files needed
    config_files:
      - "myservice.yml"

    # Alternative names for lookup
    aliases:
      - mytech
      - myalias

Service Roles

Choose the appropriate role:

Role Description
Infrastructure Core platform services (gateway, auth, messaging)
Data Data storage (databases, caches, object storage)
AI AI/ML services (agents, models, guardrails)
Observability Monitoring (metrics, logs, traces)

Port Guidelines

  • Avoid conflicts with existing services
  • Use standard ports where applicable (5432 for PostgreSQL, etc.)
  • Document each port's purpose

Step 2: Create Docker Compose Template

Create pkg/catalog/templates/docker-compose/<codename>.yml.tmpl:

# {{ .Service.Codename }} ({{ .Service.Technology }}) - {{ .Service.Description }}
{ { .Service.Codename } }:
image: { { .Service.Image } }
container_name: arc-{{ .Service.Codename }}
restart: unless-stopped
  { { - if .Service.Ports } }
ports:
  { { - range .Service.Ports } }
- "{{ .Host }}:{{ .Container }}"
  { { - end } }
  { { - end } }
environment:
  - MY_VAR={{ default "default" .Vars.my_var }}
  - SECRET_KEY=${SECRET_KEY}
  { { - if .Service.Dependencies } }
depends_on:
  { { - range .Service.Dependencies } }
- { { . } }
  { { - end } }
  { { - end } }
volumes:
  - { { .Workspace.DataDir } }/myservice:/data
networks:
  - {{ .Workspace.Network }}
labels:
  - "arc.service={{ .Service.Codename }}"
  - "arc.technology={{ .Service.Technology }}"
  - "arc.role={{ .Service.Role }}"
healthcheck:
  test: [ "CMD", "curl", "-f", "http://localhost:8080/health" ]
  interval: 30s
  timeout: 10s
  retries: 3

Template Variables

Available in templates:

Variable Description
.Service.Codename Service codename
.Service.Technology Technology name
.Service.Image Docker image
.Service.Role Service role
.Service.Ports Port mappings
.Service.Dependencies Dependency list
.Workspace.Name Workspace name
.Workspace.DataDir Data directory path
.Workspace.ConfigDir Config directory path
.Workspace.Network Docker network name
.Vars.<name> User-provided variables

Template Functions

Function Description Example
default Default value {{ default "value" .Vars.key }}
quote Quote string {{ quote .Vars.name }}
env Env var reference {{ env "VAR" "default" }}
toYAML Convert to YAML {{ .Data | toYAML }}
indent Indent lines {{ indent 4 .Content }}
lower Lowercase {{ lower .Name }}
upper Uppercase {{ upper .Name }}

Step 3: Create Config Templates (Optional)

If your service needs configuration files, create them under: pkg/catalog/templates/configs/<service>/

Example: pkg/catalog/templates/configs/myservice/myservice.yml.tmpl

# {{ .Service.Codename }} Configuration
server:
  port: 8080
  host: 0.0.0.0

database:
  url: postgresql://{{ default "arc" .Vars.postgres_user }}:${POSTGRES_PASSWORD}@oracle:5432/mydb

logging:
  level: { { default "info" .Vars.log_level } }

Step 4: Validate

Run tests to validate your changes:

# Run catalog tests
go test ./pkg/catalog/... -v

# Verify service loads
go build -o /tmp/arc-test ./cmd/arc
/tmp/arc-test services info my-service

# Check for port conflicts
/tmp/arc-test services ports

# Verify dependencies
/tmp/arc-test services deps my-service

Step 5: Update Golden Files (If Needed)

If you modified existing services or templates:

go test ./pkg/catalog/... -update-golden

Best Practices

  1. Unique Codenames: Choose memorable, themed codenames
  2. Clear Descriptions: Explain what the service does
  3. Document Ports: Describe what each port is for
  4. Minimal Dependencies: Only require what's necessary
  5. Sensible Defaults: Provide defaults for optional vars
  6. Health Checks: Always include a healthcheck

Example: Complete Service

Here's a complete example of adding a new service:

services.yaml entry

  jarvis-jr:
    codename: jarvis-jr
    technology: OAuth2Proxy
    role: Infrastructure
    description: "The Intern. Handles OAuth2 authentication proxying."
    version: "7.5"
    image: "quay.io/oauth2-proxy/oauth2-proxy:v7.5"
    ports:
      - host: 4180
        container: 4180
        protocol: tcp
        description: "Proxy port"
    dependencies:
      - jarvis
    environment:
      - name: OAUTH2_PROXY_CLIENT_ID
        required: true
        description: "OAuth2 client ID"
      - name: OAUTH2_PROXY_CLIENT_SECRET
        required: true
        description: "OAuth2 client secret"
    aliases:
      - oauth2-proxy
      - proxy

Docker Compose template

# jarvis-jr (OAuth2Proxy) - OAuth2 authentication proxy
jarvis-jr:
  image: { { .Service.Image } }
  container_name: arc-jarvis-jr
  restart: unless-stopped
  ports:
    - "4180:4180"
  environment:
    - OAUTH2_PROXY_CLIENT_ID=${OAUTH2_PROXY_CLIENT_ID}
    - OAUTH2_PROXY_CLIENT_SECRET=${OAUTH2_PROXY_CLIENT_SECRET}
    - OAUTH2_PROXY_OIDC_ISSUER_URL=http://jarvis:4433
  depends_on:
    - jarvis
  networks:
    - { { .Workspace.Network } }
  healthcheck:
    test: [ "CMD", "curl", "-f", "http://localhost:4180/ping" ]
    interval: 30s
    timeout: 10s
    retries: 3