Skip to content

OCI Container Deployment

Eric Fitzgerald edited this page Apr 8, 2026 · 4 revisions

OCI Container Deployment

This guide covers deploying TMI to Oracle Cloud Infrastructure (OCI) using container images built on Oracle Linux 9, with Oracle Autonomous Database (ADB) support.

Overview

TMI provides specialized container images for OCI deployment:

Container Base Image Purpose Size
TMI Server Oracle Linux 9 API server with Oracle ADB support ~737MB
Redis Oracle Linux 9-slim Cache and session storage ~272MB
TMI-UX Oracle Linux 10-slim Angular frontend (from tmi-ux repo) ~350MB

Key features:

  • Oracle Instant Client 23ai - Native Oracle ADB connectivity via godror driver
  • Security patches - Applied during container build
  • CGO enabled - Required for Oracle database driver
  • Multi-architecture - Supports both amd64 and arm64
  • Multi-container support - TMI API and Redis run in a single instance for Free Tier optimization

Prerequisites

Required Tools

  • Docker or Podman
  • OCI CLI installed and configured
  • Access to an OCI tenancy with Container Registry

OCI Resources

  • Container Repository in OCI Container Registry
  • Oracle Autonomous Database (for production)
  • Auth Token for registry authentication

Quick Start

1. Set Environment Variables

# Optional: Override OCI CLI profile (default: tmi)
export OCI_CLI_PROFILE="tmi"

# Optional: Override region (default: us-ashburn-1)
export OCI_REGION="us-ashburn-1"

# Optional: Override name prefix for registry paths (default: tmi)
export TMI_NAME_PREFIX="tmi"

# Optional: Set auth token for non-interactive registry login
export OCIR_AUTH_TOKEN="<your-auth-token>"

2. Build Containers

# Build TMI server and Redis for OCI (builds, pushes, and scans)
make build-app-oci

# Or build individual components locally with Oracle support
uv run scripts/build-app-containers.py --target oci --component server
uv run scripts/build-app-containers.py --target oci --component redis

3. Authenticate with OCI Container Registry

# Get your tenancy namespace
NAMESPACE=$(oci os ns get --query 'data' --raw-output)

# Login to registry (requires Auth Token from OCI Console)
docker login <region>.ocir.io
# Username: <namespace>/<your-email>
# Password: <auth-token>

4. Push to Registry

# Push server image
docker push <region>.ocir.io/<namespace>/tmi:latest

# Push Redis image
docker push <region>.ocir.io/<namespace>/tmi-redis:latest

Or use the automated build, push, and scan:

make build-app-oci

Container Images

TMI Server (Dockerfile.server-oracle)

Multi-stage build:

  1. Builder stage - Oracle Linux 9 with Go 1.26.1 and Oracle Instant Client
  2. Runtime stage - Oracle Linux 9-slim with minimal dependencies

Features:

  • Oracle Instant Client 23ai for ADB connectivity
  • Built with -tags oracle for Oracle driver support
  • Non-root user (tmi) for security
  • Wallet mount point at /wallet with automatic extraction from wallet.zip
  • Default architecture for OCI target: linux/arm64 (Ampere A1)

Environment Variables:

Variable Required Description
TMI_DATABASE_URL Yes Database connection URL, e.g. oracle://user:password@tns_alias or oracle://user:password@host:port/service_name?wallet_location=/wallet
TMI_ORACLE_WALLET_LOCATION No Wallet path (default: set automatically by entrypoint to /tmp/wallet after extraction)
TMI_REDIS_URL Yes Redis connection URL, e.g. redis://:password@localhost:6379/0
TMI_REDIS_HOST Alt Redis host (alternative to TMI_REDIS_URL)
TMI_REDIS_PORT Alt Redis port (required when using TMI_REDIS_HOST)
TMI_REDIS_PASSWORD No Redis password (when using individual Redis fields)
TMI_REDIS_DB No Redis database number (default: 0)

Note: Health checks are configured at the OCI Container Instances level, not within the Dockerfile.

Redis (Dockerfile.redis-oracle)

Multi-stage build:

  1. Builder stage - Compiles Redis 8.4.0 from source
  2. Runtime stage - Oracle Linux 9-slim

Features:

  • Redis 8.4.0 compiled from source
  • Dangerous commands disabled by default (FLUSHDB, FLUSHALL, DEBUG)
  • Non-root user (redis, UID 6379)
  • Configurable via environment variables

Environment Variables:

Variable Default Description
REDIS_PASSWORD (none) Redis authentication password
REDIS_PORT 6379 Listen port
REDIS_PROTECTED_MODE yes Enable protected mode
REDIS_DISABLE_COMMANDS FLUSHDB,FLUSHALL,DEBUG Commands to disable

Build Script Options

Container builds are managed by scripts/build-app-containers.py, invoked via uv run:

uv run scripts/build-app-containers.py [options]

Options:
  --target TARGET       Deployment target: local, oci, aws, azure, gcp, heroku (default: local)
  --component COMP      Component: server, redis, or all (default: all)
  --arch ARCH           Target architecture: arm64, amd64, or both (default: auto-detect)
  --db-backend BACKEND  Database backend: postgresql or oracle-adb (default: postgresql)
  --registry URL        Container registry URL (auto-determined from target if not set)
  --push                Push images to registry after building
  --scan                Run security scanning (Grype + Syft SBOM) after building
  --scan-only           Scan existing images without building
  --no-cache            Build without Docker cache

For OCI targets, the script automatically:

  • Discovers the OCI tenancy namespace via oci os ns get
  • Selects Oracle-specific Dockerfiles (Dockerfile.server-oracle, Dockerfile.redis-oracle)
  • Defaults to linux/arm64 architecture (Ampere A1)
  • Uses docker buildx for cross-platform builds

Examples

# Build server only for OCI
uv run scripts/build-app-containers.py --target oci --component server

# Build, push, and scan all OCI containers
uv run scripts/build-app-containers.py --target oci --push --scan

# Build locally with Oracle ADB support (without pushing)
uv run scripts/build-app-containers.py --target local --db-backend oracle-adb

# Build for both architectures and push
uv run scripts/build-app-containers.py --target oci --arch both --push

Makefile Targets

Target Description
build-app-oci Build, push, and scan all OCI containers (server + Redis)
build-app Build app containers for local development
build-app-scan Build app containers locally with security scanning
build-server-container Build only the TMI server container locally
build-redis-container Build only the Redis container locally
build-all Build all containers (database + app) for local development
scan-containers Scan existing container images for vulnerabilities

Deprecated aliases (still functional, will be removed):

Target Maps To
build-container-oracle build-app-oci
build-containers-oracle-push build-app-oci

Running Containers Locally

TMI Server

docker run -p 8080:8080 \
  -v /path/to/wallet:/wallet:ro \
  -e TMI_DATABASE_URL=oracle://your_user:your_password@your_tns_alias \
  -e TMI_REDIS_URL=redis://localhost:6379 \
  <region>.ocir.io/<namespace>/tmi:latest

The entrypoint script automatically extracts wallet.zip from the /wallet mount to /tmp/wallet, fixes the sqlnet.ora paths, and sets TNS_ADMIN and TMI_ORACLE_WALLET_LOCATION accordingly.

Redis

docker run -p 6379:6379 \
  -e REDIS_PASSWORD=your_secure_password \
  -v redis-data:/var/lib/redis \
  <region>.ocir.io/<namespace>/tmi-redis:latest

Docker Compose Example

services:
  tmi:
    image: us-ashburn-1.ocir.io/<namespace>/tmi:latest
    ports:
      - "8080:8080"
    volumes:
      - ./wallet:/wallet:ro
    environment:
      - TMI_DATABASE_URL=oracle://${DB_USER}:${DB_PASSWORD}@${ORACLE_TNS}
      - TMI_REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379/0
    depends_on:
      - redis

  redis:
    image: us-ashburn-1.ocir.io/<namespace>/tmi-redis:latest
    ports:
      - "6379:6379"
    environment:
      - REDIS_PASSWORD=${REDIS_PASSWORD}
    volumes:
      - redis-data:/var/lib/redis

volumes:
  redis-data:

OCI Deployment

Terraform Deployment (Recommended)

The recommended way to deploy TMI to OCI is using the Terraform modules. See Terraform-Deployment for complete instructions.

The Terraform deployment creates a multi-container architecture optimized for OCI Free Tier:

Container Instance #1: TMI API + Redis (combined)
Container Instance #2: TMI-UX (optional)
Load Balancer: Hostname-based routing

Manual Container Instances

For manual deployment using OCI Container Instances:

# Create combined TMI API + Redis container instance
oci container-instances container-instance create \
  --compartment-id <compartment-ocid> \
  --display-name tmi-api-redis \
  --availability-domain <ad> \
  --shape CI.Standard.A1.Flex \
  --shape-config '{"ocpus": 2, "memoryInGBs": 6}' \
  --containers '[
    {
      "imageUrl": "<region>.ocir.io/<namespace>/tmi:latest",
      "displayName": "tmi-server",
      "environmentVariables": {
        "TMI_DATABASE_URL": "oracle://admin:<password>@tmi_high",
        "TMI_REDIS_URL": "redis://:password@localhost:6379/0"
      }
    },
    {
      "imageUrl": "<region>.ocir.io/<namespace>/tmi-redis:latest",
      "displayName": "redis",
      "environmentVariables": {
        "REDIS_PASSWORD": "your-redis-password"
      }
    }
  ]'
# Create TMI-UX container instance (optional)
oci container-instances container-instance create \
  --compartment-id <compartment-ocid> \
  --display-name tmi-ux \
  --availability-domain <ad> \
  --shape CI.Standard.A1.Flex \
  --shape-config '{"ocpus": 1, "memoryInGBs": 2}' \
  --containers '[{
    "imageUrl": "<region>.ocir.io/<namespace>/tmi-ux:latest",
    "displayName": "tmi-ux",
    "environmentVariables": {
      "PORT": "8080",
      "NODE_ENV": "production"
    }
  }]'

Kubernetes (OKE)

For Oracle Kubernetes Engine deployment, see Deploying-TMI-Server.

Oracle Wallet Configuration

The TMI server requires an Oracle wallet for ADB authentication:

  1. Download the wallet ZIP from OCI Console (Autonomous Database > DB Connection > Download Wallet)
  2. Place the wallet.zip file in a directory
  3. Mount that directory as a read-only volume at /wallet

The container entrypoint script automatically:

  • Extracts wallet.zip to /tmp/wallet
  • Fixes the sqlnet.ora DIRECTORY path to point to the extraction directory
  • Sets TNS_ADMIN and TMI_ORACLE_WALLET_LOCATION environment variables

Alternatively, you can pre-extract the wallet and mount the directory. The wallet should contain:

  • tnsnames.ora - TNS aliases
  • sqlnet.ora - SQL*Net configuration
  • cwallet.sso - Auto-login wallet

Security Considerations

Container Security

  • Non-root users in all containers
  • Security patches applied during build
  • Minimal runtime dependencies
  • Dangerous Redis commands disabled

Network Security

  • Use OCI VCN security lists to restrict access
  • Enable TLS for Redis in production
  • Use OCI Vault for secrets management

Image Scanning

The build script supports Grype vulnerability scanning and Syft SBOM generation:

# Build with scanning (OCI target includes --scan by default)
make build-app-oci

# Scan existing images without rebuilding
make scan-containers

# Or scan directly
uv run scripts/build-app-containers.py --scan-only --target oci

Security reports (SARIF, text, and CycloneDX SBOMs) are saved to security-reports/.

Troubleshooting

Authentication Errors

If you see 403 Forbidden when pushing:

  1. Verify your Auth Token is valid
  2. Check username format: <namespace>/<email>
  3. Ensure repository exists in the correct compartment

Oracle Connection Issues

  1. Verify wallet is mounted correctly
  2. Check TNS alias matches tnsnames.ora
  3. Ensure TNS_ADMIN points to wallet directory
  4. Verify database user has required permissions

Build Failures

For architecture-related build errors:

  • The Dockerfile auto-detects architecture (amd64/arm64)
  • Ensure Docker buildx is available for cross-platform builds

TMI-UX Container

The TMI-UX frontend is built from a separate repository (tmi-ux). It uses:

  • Base Image: Oracle Linux 10-slim
  • Runtime: Node.js 22 LTS with Express.js
  • Port: 8080
  • Health Check: HTTP GET on /

Building TMI-UX for OCI

From the tmi-ux repository:

# Build the OCI-optimized container
docker build -f Dockerfile.oci -t tmi-ux:latest .

# Push to OCI Container Registry
docker tag tmi-ux:latest <region>.ocir.io/<namespace>/tmi-ux:latest
docker push <region>.ocir.io/<namespace>/tmi-ux:latest

Or use the provided script:

./scripts/push-oci.sh [tag]

TMI-UX Environment

The Angular application is built with the API URL baked in at build time. The OCI build uses environment.oci.ts:

apiUrl: 'https://api.tmi.dev',

If you need a different API URL, update src/environments/environment.oci.ts before building.

Related Documentation

Clone this wiki locally