refactor: single container image, 4 deployment options in docs

This commit is contained in:
nogueiraguh
2026-04-02 16:41:04 -03:00
parent e0f83ed5e6
commit 72107a26e7
3 changed files with 158 additions and 139 deletions

208
README.md
View File

@@ -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

View File

@@ -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

View File

@@ -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) ==="