refactor: single container image, 4 deployment options in docs
This commit is contained in:
208
README.md
208
README.md
@@ -94,54 +94,38 @@ Distributed as pre-built Docker containers via **Oracle Container Registry (OCIR
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Quick Start
|
## Deployment Options
|
||||||
|
|
||||||
### Prerequisites
|
The platform is distributed as a single Docker image available on **Oracle Container Registry (OCIR)**:
|
||||||
|
|
||||||
- Docker and Docker Compose v2
|
```
|
||||||
- Access to the OCI Container Registry (OCIR)
|
us-ashburn-1.ocir.io/idi1o0a010nx/oci-cis-agent:latest
|
||||||
|
```
|
||||||
|
|
||||||
### 1. Configure
|
Multi-architecture: `linux/amd64` + `linux/arm64`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Option 1 — Local Docker (any machine)
|
||||||
|
|
||||||
|
Run on any machine with Docker installed (Linux, macOS, Windows).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# 1. Login to OCIR
|
||||||
|
docker login us-ashburn-1.ocir.io
|
||||||
|
|
||||||
|
# 2. Configure
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
```
|
# Edit .env: set APP_SECRET (openssl rand -hex 64)
|
||||||
|
|
||||||
Edit `.env`:
|
# 3. Run
|
||||||
```env
|
|
||||||
OCIR_REGION=us-ashburn-1
|
|
||||||
OCIR_NAMESPACE=your_namespace
|
|
||||||
APP_SECRET=<generate with: openssl rand -hex 64>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Login to OCIR
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker login <OCIR_REGION>.ocir.io
|
|
||||||
```
|
|
||||||
|
|
||||||
- **Username:** `<namespace>/<username>` or `<namespace>/oracleidentitycloudservice/<email>`
|
|
||||||
- **Password:** Auth Token (generate in OCI Console > Profile > Auth Tokens)
|
|
||||||
|
|
||||||
### 3. Run
|
|
||||||
|
|
||||||
**Option A — Single Container** (recommended for simplicity):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose -f docker-compose.single.yml up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
One container runs everything (nginx + backend). Port `8080`.
|
|
||||||
|
|
||||||
**Option B — Two Containers** (recommended for production):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
|
|
||||||
|
# 4. Access: http://localhost:8080
|
||||||
|
docker logs oci-cis-agent | grep "password"
|
||||||
```
|
```
|
||||||
|
|
||||||
Separate backend and frontend containers with internal networking.
|
Or with `docker run` (no compose file needed):
|
||||||
|
|
||||||
**Option C — Docker Run** (no compose needed):
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -d \
|
docker run -d \
|
||||||
@@ -150,32 +134,16 @@ docker run -d \
|
|||||||
-v agent-data:/data \
|
-v agent-data:/data \
|
||||||
-e APP_SECRET=$(openssl rand -hex 64) \
|
-e APP_SECRET=$(openssl rand -hex 64) \
|
||||||
-e TZ=America/Sao_Paulo \
|
-e TZ=America/Sao_Paulo \
|
||||||
<OCIR_REGION>.ocir.io/<OCIR_NAMESPACE>/oci-cis-agent:latest
|
us-ashburn-1.ocir.io/idi1o0a010nx/oci-cis-agent:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. Access
|
|
||||||
|
|
||||||
Open `http://localhost:8080`
|
|
||||||
|
|
||||||
The initial admin password is generated automatically and displayed in the container logs:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Single container / docker run
|
|
||||||
docker logs oci-cis-agent | grep "password"
|
|
||||||
|
|
||||||
# Two containers
|
|
||||||
docker compose logs backend | grep "password"
|
|
||||||
```
|
|
||||||
|
|
||||||
> You will be prompted to change the password on first login.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Deploy on OCI (Terraform)
|
### Option 2 — OCI Compute Instance (Terraform)
|
||||||
|
|
||||||
For production deployment on Oracle Cloud Infrastructure with Load Balancer, WAF, and SSL.
|
Production deployment on Oracle Cloud with Load Balancer, WAF, SSL, and persistent storage.
|
||||||
|
|
||||||
### Architecture
|
**Architecture:**
|
||||||
|
|
||||||
```
|
```
|
||||||
+--------------------------------------------------------------+
|
+--------------------------------------------------------------+
|
||||||
@@ -189,25 +157,24 @@ For production deployment on Oracle Cloud Infrastructure with Load Balancer, WAF
|
|||||||
| | | | Compute Instance | | |
|
| | | | Compute Instance | | |
|
||||||
| +-----------------+ | | (ARM, Free Tier eligible) | | |
|
| +-----------------+ | | (ARM, Free Tier eligible) | | |
|
||||||
| | | | | | | |
|
| | | | | | | |
|
||||||
| | Load Balancer |---->| | Backend (FastAPI :8000) | | |
|
| | Load Balancer |---->| | oci-cis-agent container | | |
|
||||||
| | (HTTPS / 443) | | | Frontend (nginx :80) | | |
|
| | (HTTPS / 443) | | | Block Volume (/data) | | |
|
||||||
| | Public Subnet | | | Block Volume (/data) | | |
|
| | Public Subnet | | | | | |
|
||||||
| | | | +---------------------------+ | |
|
| | | | +---------------------------+ | |
|
||||||
| +-----------------+ +--------------------------------+ |
|
| +-----------------+ +--------------------------------+ |
|
||||||
| |
|
| |
|
||||||
+--------------------------------------------------------------+
|
+--------------------------------------------------------------+
|
||||||
```
|
```
|
||||||
|
|
||||||
### Setup
|
**Setup:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd terraform
|
cd terraform
|
||||||
cp terraform.tfvars.example terraform.tfvars
|
cp terraform.tfvars.example terraform.tfvars
|
||||||
|
# Edit terraform.tfvars with OCI credentials
|
||||||
```
|
```
|
||||||
|
|
||||||
Edit `terraform.tfvars` with your OCI credentials and configuration.
|
**Deploy:**
|
||||||
|
|
||||||
### Deploy
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
terraform init
|
terraform init
|
||||||
@@ -215,7 +182,7 @@ terraform plan
|
|||||||
terraform apply
|
terraform apply
|
||||||
```
|
```
|
||||||
|
|
||||||
### Resources Created
|
**Resources Created:**
|
||||||
|
|
||||||
| Resource | Description |
|
| Resource | Description |
|
||||||
|----------|-------------|
|
|----------|-------------|
|
||||||
@@ -224,22 +191,119 @@ terraform apply
|
|||||||
| Block Volume | 50GB persistent storage for application data |
|
| Block Volume | 50GB persistent storage for application data |
|
||||||
| Load Balancer | Flexible 10-100 Mbps with SSL (self-signed or Let's Encrypt) |
|
| Load Balancer | Flexible 10-100 Mbps with SSL (self-signed or Let's Encrypt) |
|
||||||
| WAF | OWASP protection — XSS, SQL injection, path traversal + rate limiting |
|
| WAF | OWASP protection — XSS, SQL injection, path traversal + rate limiting |
|
||||||
| OCIR | 2 private container repositories (backend + frontend) |
|
|
||||||
| DNS | OCI DNS Zone + A record (conditional — when domain is configured) |
|
| DNS | OCI DNS Zone + A record (conditional — when domain is configured) |
|
||||||
|
|
||||||
### Outputs
|
**Outputs:**
|
||||||
|
|
||||||
After `terraform apply`:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
terraform output load_balancer_ip # Public IP address
|
terraform output load_balancer_ip # Public IP address
|
||||||
terraform output app_url # Application URL
|
terraform output app_url # Application URL
|
||||||
terraform output ocir_backend_url # Backend image URL
|
|
||||||
terraform output ocir_frontend_url # Frontend image URL
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Option 3 — OCI Container Instances
|
||||||
|
|
||||||
|
Run as a serverless container on OCI without managing VMs.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
oci container-instances container-instance create \
|
||||||
|
--compartment-id <COMPARTMENT_OCID> \
|
||||||
|
--display-name "oci-cis-agent" \
|
||||||
|
--availability-domain <AD> \
|
||||||
|
--shape "CI.Standard.E4.Flex" \
|
||||||
|
--shape-config '{"ocpus": 2, "memoryInGBs": 16}' \
|
||||||
|
--containers '[{
|
||||||
|
"imageUrl": "us-ashburn-1.ocir.io/idi1o0a010nx/oci-cis-agent:latest",
|
||||||
|
"displayName": "agent",
|
||||||
|
"environmentVariables": {
|
||||||
|
"APP_SECRET": "<YOUR_SECRET>",
|
||||||
|
"TZ": "America/Sao_Paulo"
|
||||||
|
}
|
||||||
|
}]' \
|
||||||
|
--vnics '[{"subnetId": "<SUBNET_OCID>"}]' \
|
||||||
|
--image-pull-secrets '[{"registryEndpoint": "us-ashburn-1.ocir.io", "secretType": "BASIC", "username": "<OCIR_USER>", "password": "<AUTH_TOKEN>"}]'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Option 4 — Kubernetes (OKE / any K8s cluster)
|
||||||
|
|
||||||
|
Deploy on Oracle Kubernetes Engine or any Kubernetes cluster.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Minimal deployment
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: oci-cis-agent
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: oci-cis-agent
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: oci-cis-agent
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: agent
|
||||||
|
image: us-ashburn-1.ocir.io/idi1o0a010nx/oci-cis-agent:latest
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
env:
|
||||||
|
- name: APP_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: agent-secret
|
||||||
|
key: app-secret
|
||||||
|
- name: TZ
|
||||||
|
value: "America/Sao_Paulo"
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "2Gi"
|
||||||
|
limits:
|
||||||
|
memory: "4Gi"
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: agent-data
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: ocir-credentials
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: oci-cis-agent
|
||||||
|
spec:
|
||||||
|
type: LoadBalancer
|
||||||
|
ports:
|
||||||
|
- port: 443
|
||||||
|
targetPort: 8080
|
||||||
|
selector:
|
||||||
|
app: oci-cis-agent
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### First Login
|
||||||
|
|
||||||
|
After any deployment option, check the container logs for the initial admin password:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker logs oci-cis-agent | grep "password"
|
||||||
|
# or
|
||||||
|
kubectl logs deployment/oci-cis-agent | grep "password"
|
||||||
|
```
|
||||||
|
|
||||||
|
> You will be prompted to change the password on first login.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Configuration Guide
|
## Configuration Guide
|
||||||
|
|
||||||
### Step 1 — OCI Credentials
|
### Step 1 — OCI Credentials
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
backend:
|
agent:
|
||||||
image: ${OCIR_REGION}.ocir.io/${OCIR_NAMESPACE}/oci-cis-agent-backend:${IMAGE_TAG:-latest}
|
image: ${OCIR_REGION:-us-ashburn-1}.ocir.io/${OCIR_NAMESPACE:-idi1o0a010nx}/oci-cis-agent:${IMAGE_TAG:-latest}
|
||||||
container_name: oci-agent-backend
|
container_name: oci-cis-agent
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
- APP_SECRET=${APP_SECRET:?Set APP_SECRET in .env (openssl rand -hex 64)}
|
- APP_SECRET=${APP_SECRET:?Set APP_SECRET in .env (openssl rand -hex 64)}
|
||||||
@@ -10,12 +10,12 @@ services:
|
|||||||
- CORS_ORIGINS=${CORS_ORIGINS:-}
|
- CORS_ORIGINS=${CORS_ORIGINS:-}
|
||||||
- TZ=${TZ:-America/Sao_Paulo}
|
- TZ=${TZ:-America/Sao_Paulo}
|
||||||
- OCI_CLI_SUPPRESS_FILE_PERMISSIONS_WARNING=True
|
- OCI_CLI_SUPPRESS_FILE_PERMISSIONS_WARNING=True
|
||||||
|
ports:
|
||||||
|
- "${PORT:-8080}:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- agent-data:/data
|
- agent-data:/data
|
||||||
networks:
|
|
||||||
- agent-net
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:8000/api/health"]
|
test: ["CMD", "curl", "-f", "http://localhost:8080/api/health"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 3
|
retries: 3
|
||||||
@@ -26,29 +26,6 @@ services:
|
|||||||
max-file: "3"
|
max-file: "3"
|
||||||
mem_limit: 4g
|
mem_limit: 4g
|
||||||
|
|
||||||
frontend:
|
|
||||||
image: ${OCIR_REGION}.ocir.io/${OCIR_NAMESPACE}/oci-cis-agent-frontend:${IMAGE_TAG:-latest}
|
|
||||||
container_name: oci-agent-frontend
|
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
|
||||||
- TZ=${TZ:-America/Sao_Paulo}
|
|
||||||
ports:
|
|
||||||
- "${PORT:-8080}:80"
|
|
||||||
depends_on:
|
|
||||||
- backend
|
|
||||||
networks:
|
|
||||||
- agent-net
|
|
||||||
logging:
|
|
||||||
driver: "json-file"
|
|
||||||
options:
|
|
||||||
max-size: "5m"
|
|
||||||
max-file: "3"
|
|
||||||
mem_limit: 512m
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
agent-data:
|
agent-data:
|
||||||
driver: local
|
driver: local
|
||||||
|
|
||||||
networks:
|
|
||||||
agent-net:
|
|
||||||
driver: bridge
|
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ fi
|
|||||||
mkdir -p /data
|
mkdir -p /data
|
||||||
mount "$DATA_DEVICE" /data
|
mount "$DATA_DEVICE" /data
|
||||||
|
|
||||||
# Add to fstab if not already present
|
|
||||||
if ! grep -q "$DATA_DEVICE" /etc/fstab; then
|
if ! grep -q "$DATA_DEVICE" /etc/fstab; then
|
||||||
echo "$DATA_DEVICE /data ext4 defaults,_netdev,nofail 0 2" >> /etc/fstab
|
echo "$DATA_DEVICE /data ext4 defaults,_netdev,nofail 0 2" >> /etc/fstab
|
||||||
fi
|
fi
|
||||||
@@ -56,9 +55,6 @@ fi
|
|||||||
echo ">>> /data mounted successfully"
|
echo ">>> /data mounted successfully"
|
||||||
df -h /data
|
df -h /data
|
||||||
|
|
||||||
# Create application data directories
|
|
||||||
mkdir -p /data/db /data/configs /data/reports /data/terraform /data/wallets
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# 4. Docker login to OCIR
|
# 4. Docker login to OCIR
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
@@ -69,16 +65,12 @@ echo '${ocir_auth_token}' | docker login "$OCIR_ENDPOINT" \
|
|||||||
--password-stdin
|
--password-stdin
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# 5. Pull images
|
# 5. Pull image
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
BACKEND_IMAGE="$OCIR_ENDPOINT/${ocir_namespace}/${ocir_repo_prefix}/backend:latest"
|
IMAGE="$OCIR_ENDPOINT/${ocir_namespace}/${ocir_repo_prefix}:latest"
|
||||||
FRONTEND_IMAGE="$OCIR_ENDPOINT/${ocir_namespace}/${ocir_repo_prefix}/frontend:latest"
|
|
||||||
|
|
||||||
echo ">>> Pulling backend image: $BACKEND_IMAGE"
|
echo ">>> Pulling image: $IMAGE"
|
||||||
docker pull "$BACKEND_IMAGE"
|
docker pull "$IMAGE"
|
||||||
|
|
||||||
echo ">>> Pulling frontend image: $FRONTEND_IMAGE"
|
|
||||||
docker pull "$FRONTEND_IMAGE"
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# 6. Write docker-compose.yml
|
# 6. Write docker-compose.yml
|
||||||
@@ -88,43 +80,29 @@ mkdir -p "$APP_DIR"
|
|||||||
|
|
||||||
cat > "$APP_DIR/docker-compose.yml" <<'COMPOSE_EOF'
|
cat > "$APP_DIR/docker-compose.yml" <<'COMPOSE_EOF'
|
||||||
services:
|
services:
|
||||||
backend:
|
agent:
|
||||||
image: ${ocir_region}.ocir.io/${ocir_namespace}/${ocir_repo_prefix}/backend:latest
|
image: ${ocir_region}.ocir.io/${ocir_namespace}/${ocir_repo_prefix}:latest
|
||||||
container_name: cisagent-backend
|
container_name: oci-cis-agent
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
- APP_SECRET=${app_secret}
|
- APP_SECRET=${app_secret}
|
||||||
- JWT_EXPIRY_HOURS=${jwt_expiry_hours}
|
- JWT_EXPIRY_HOURS=${jwt_expiry_hours}
|
||||||
|
- DATA_DIR=/data
|
||||||
- CORS_ORIGINS=${cors_origins}
|
- CORS_ORIGINS=${cors_origins}
|
||||||
- TZ=${app_timezone}
|
- TZ=${app_timezone}
|
||||||
|
- OCI_CLI_SUPPRESS_FILE_PERMISSIONS_WARNING=True
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /data:/data
|
- /data:/data
|
||||||
mem_limit: 4g
|
mem_limit: 4g
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:8000/api/health"]
|
test: ["CMD", "curl", "-f", "http://localhost:8080/api/health"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 3
|
retries: 3
|
||||||
start_period: 30s
|
start_period: 30s
|
||||||
networks:
|
|
||||||
- agent-net
|
|
||||||
|
|
||||||
frontend:
|
|
||||||
image: ${ocir_region}.ocir.io/${ocir_namespace}/${ocir_repo_prefix}/frontend:latest
|
|
||||||
container_name: cisagent-frontend
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "8080:80"
|
|
||||||
mem_limit: 512m
|
|
||||||
depends_on:
|
|
||||||
backend:
|
|
||||||
condition: service_healthy
|
|
||||||
networks:
|
|
||||||
- agent-net
|
|
||||||
|
|
||||||
networks:
|
|
||||||
agent-net:
|
|
||||||
driver: bridge
|
|
||||||
COMPOSE_EOF
|
COMPOSE_EOF
|
||||||
|
|
||||||
echo ">>> docker-compose.yml written to $APP_DIR"
|
echo ">>> docker-compose.yml written to $APP_DIR"
|
||||||
@@ -132,7 +110,7 @@ echo ">>> docker-compose.yml written to $APP_DIR"
|
|||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# 7. Start application
|
# 7. Start application
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
echo ">>> Starting application with Docker Compose..."
|
echo ">>> Starting application..."
|
||||||
cd "$APP_DIR"
|
cd "$APP_DIR"
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
|
|
||||||
@@ -154,10 +132,10 @@ done
|
|||||||
|
|
||||||
if [ $ATTEMPTS -eq $MAX_ATTEMPTS ]; then
|
if [ $ATTEMPTS -eq $MAX_ATTEMPTS ]; then
|
||||||
echo "WARNING: Application did not become healthy within expected time"
|
echo "WARNING: Application did not become healthy within expected time"
|
||||||
echo ">>> Docker container status:"
|
echo ">>> Container status:"
|
||||||
docker compose ps
|
docker compose ps
|
||||||
echo ">>> Backend logs:"
|
echo ">>> Logs:"
|
||||||
docker compose logs backend --tail 50
|
docker compose logs --tail 50
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "=== OCI CIS Agent cloud-init finished at $(date) ==="
|
echo "=== OCI CIS Agent cloud-init finished at $(date) ==="
|
||||||
|
|||||||
Reference in New Issue
Block a user