Skip to content

Commit 09dc59c

Browse files
authored
fix: mount config.toml from ConfigMap in K8s (#62)
* refactor: drop bloat in docs/config * chore: trigger CI with PR description
1 parent 3b1997b commit 09dc59c

File tree

4 files changed

+96
-250
lines changed

4 files changed

+96
-250
lines changed

k8s/README.md

Lines changed: 12 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -2,82 +2,14 @@
22

33
This directory contains Kubernetes manifests for deploying the Rewards Eligibility Oracle with persistent state management.
44

5-
## Prerequisites
6-
7-
- Kubernetes cluster (version 1.19+)
8-
- `kubectl` configured to access your cluster
9-
- Docker image published to `ghcr.io/graphprotocol/rewards-eligibility-oracle`
10-
- **Storage class configured** (see Storage Configuration below)
11-
12-
## Quick Start
13-
14-
### 1. Create Secrets (Required)
15-
16-
```bash
17-
# Copy the example secrets file
18-
cp k8s/secrets.yaml.example k8s/secrets.yaml
19-
20-
# Edit with your actual credentials
21-
# IMPORTANT: Never commit secrets.yaml to version control
22-
nano k8s/secrets.yaml
23-
```
24-
25-
**Required secrets:**
26-
27-
- **`google-credentials`**: Service account JSON for BigQuery access
28-
- **`blockchain-private-key`**: Private key for Arbitrum Sepolia transactions
29-
- **`arbitrum-api-key`**: API key for Arbiscan contract verification
30-
- **`slack-webhook-url`**: Webhook URL for operational notifications
31-
32-
### 2. Configure Storage (Required)
33-
34-
```bash
35-
# Check available storage classes
36-
kubectl get storageclass
37-
38-
# If you see a default storage class (marked with *), skip to step 3
39-
# Otherwise, edit persistent-volume-claim.yaml and uncomment the appropriate storageClassName
40-
```
41-
42-
**Common storage classes by platform:**
43-
44-
- **AWS EKS**: `gp2`, `gp3`, `ebs-csi`
45-
- **Google GKE**: `standard`, `ssd`
46-
- **Azure AKS**: `managed-premium`, `managed`
47-
- **Local/Development**: `hostpath`, `local-path`
48-
49-
### 3. Deploy to Kubernetes
50-
51-
```bash
52-
# Apply all manifests
53-
kubectl apply -f k8s/
54-
55-
# Verify deployment
56-
kubectl get pods -l app=rewards-eligibility-oracle
57-
kubectl get pvc -l app=rewards-eligibility-oracle
58-
```
59-
60-
### 4. Monitor Deployment
61-
62-
```bash
63-
# Check pod status
64-
kubectl describe pod -l app=rewards-eligibility-oracle
65-
66-
# View logs
67-
kubectl logs -l app=rewards-eligibility-oracle -f
68-
69-
# Check persistent volumes
70-
kubectl get pv
71-
```
72-
735
## Architecture
746

757
### Persistent Storage
768

779
The service uses **two persistent volumes** to maintain state across pod restarts:
7810

79-
- **`rewards-eligibility-oracle-data` (5GB)**: Circuit breaker state, last run tracking, BigQuery cache, CSV outputs
80-
- **`rewards-eligibility-oracle-logs` (2GB)**: Application logs
11+
- **`rewards-eligibility-oracle-data`**: Circuit breaker state, last run tracking, BigQuery cache, CSV outputs
12+
- **`rewards-eligibility-oracle-logs`**: Application logs
8113

8214
**Mount points:**
8315

@@ -86,98 +18,17 @@ The service uses **two persistent volumes** to maintain state across pod restart
8618

8719
### Configuration Management
8820

89-
**Non-sensitive configuration**`ConfigMap` (`configmap.yaml`)
90-
**Sensitive credentials**`Secret` (`secrets.yaml`)
91-
92-
This separation provides:
93-
94-
- ✅ Easy configuration updates without rebuilding images
95-
- ✅ Secure credential management with base64 encoding
96-
- ✅ Clear separation of concerns
97-
98-
### Resource Allocation
99-
100-
**Requests (guaranteed):**
101-
102-
- CPU: 250m (0.25 cores)
103-
- Memory: 512M
104-
105-
**Limits (maximum):**
106-
107-
- CPU: 1000m (1.0 core)
108-
- Memory: 1G
109-
110-
## State Persistence Benefits
111-
112-
With persistent volumes, the service maintains:
113-
114-
1. **Circuit breaker state** → Prevents infinite restart loops
115-
2. **Last run tracking** → Enables proper catch-up logic
116-
3. **BigQuery cache** → Dramatic performance improvement (30s vs 5min restarts)
117-
4. **CSV audit artifacts** → Regulatory compliance and debugging
118-
119-
## Health Checks
120-
121-
The deployment uses **file-based health checks** (same as docker-compose):
122-
123-
**Liveness probe:** Checks `/app/healthcheck` file modification time
124-
**Readiness probe:** Verifies `/app/healthcheck` file exists
125-
126-
## Troubleshooting
127-
128-
### Pod Won't Start
129-
130-
```bash
131-
# Check events
132-
kubectl describe pod -l app=rewards-eligibility-oracle
133-
134-
# Common issues:
135-
# - Missing secrets
136-
# - PVC provisioning failures
137-
# - Image pull errors
138-
```
139-
140-
### Check Persistent Storage
141-
142-
```bash
143-
# Verify PVCs are bound
144-
kubectl get pvc
145-
146-
# Check if volumes are mounted correctly
147-
kubectl exec -it deployment/rewards-eligibility-oracle -- ls -la /app/data
148-
```
149-
150-
### Debug Configuration
151-
152-
```bash
153-
# Check environment variables
154-
kubectl exec -it deployment/rewards-eligibility-oracle -- env | grep -E "(BIGQUERY|BLOCKCHAIN)"
155-
156-
# Verify secrets are mounted
157-
kubectl exec -it deployment/rewards-eligibility-oracle -- ls -la /etc/secrets
158-
```
159-
160-
## Security Best Practices
161-
162-
**Secrets never committed** to version control
163-
**Service account** with minimal BigQuery permissions
164-
**Private key** stored in Kubernetes secrets (base64 encoded)
165-
**Resource limits** prevent resource exhaustion
166-
**Read-only filesystem** where possible
21+
The application requires a `config.toml` file to run. Configuration is split across two Kubernetes resources:
16722

168-
## Production Considerations
23+
**ConfigMap (`configmap.yaml`):**
16924

170-
- **Backup strategy** for persistent volumes
171-
- **Monitoring** and alerting setup
172-
- **Log aggregation** (ELK stack, etc.)
173-
- **Network policies** for additional security
174-
- **Pod disruption budgets** for maintenance
175-
- **Horizontal Pod Autoscaler** (if needed for scaling)
25+
- Contains the complete `config.toml` file structure
26+
- Includes non-sensitive settings (RPC URLs, contract addresses, batch sizes, etc.)
27+
- Uses `$VARIABLE_NAME` placeholders for sensitive values
28+
- **Mounted as a file** at `/app/config.toml`
17629

177-
## Next Steps
30+
**Secret (`secrets.yaml`):**
17831

179-
1. **Test deployment** in staging environment
180-
2. **Verify state persistence** across pod restarts
181-
3. **Set up monitoring** and alerting
182-
4. **Configure backup** for persistent volumes
183-
5. **Enable quality checking** after successful validation
32+
- Contains sensitive credentials
33+
- **Injected as environment variables** into the container
34+
- Values are substituted into `config.toml` placeholders at runtime

k8s/configmap.yaml

Lines changed: 68 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,51 +5,71 @@ metadata:
55
labels:
66
app: rewards-eligibility-oracle
77
data:
8-
# BigQuery Configuration
9-
BIGQUERY_LOCATION_ID: "US"
10-
BIGQUERY_PROJECT_ID: "graph-mainnet"
11-
BIGQUERY_DATASET_ID: "internal_metrics"
12-
BIGQUERY_TABLE_ID: "metrics_indexer_attempts"
13-
BIGQUERY_CURATION_TABLE_ID: "metrics_curator_signals"
14-
BIGQUERY_CURATOR_MAINNET_TABLE_ID: "curator_name_signal_dimensions_daily"
15-
BIGQUERY_CURATOR_ARBITRUM_TABLE_ID: "curator_name_signal_dimensions_arbitrum_daily"
16-
BIGQUERY_SUBGRAPH_LOOKUP_TABLE_ID: "subgraph_version_id_lookup"
17-
BIGQUERY_ANALYSIS_PERIOD_DAYS: "28"
18-
19-
# Blockchain Configuration (Arbitrum Sepolia)
20-
BLOCKCHAIN_CONTRACT_ADDRESS: "0x6d5550698F930210c3f50efe744bF51C55D791f6"
21-
BLOCKCHAIN_FUNCTION_NAME: "renewIndexerEligibility"
22-
BLOCKCHAIN_CHAIN_ID: "421614"
23-
BLOCK_EXPLORER_URL: "https://sepolia.arbiscan.io"
24-
TX_TIMEOUT_SECONDS: "30"
25-
26-
# RPC Provider URLs (Arbitrum Sepolia)
27-
BLOCKCHAIN_RPC_URL_1: "https://arbitrum-sepolia.drpc.org"
28-
BLOCKCHAIN_RPC_URL_2: "https://sepolia-rollup.arbitrum.io/rpc"
29-
BLOCKCHAIN_RPC_URL_3: "https://api.zan.top/arb-sepolia"
30-
BLOCKCHAIN_RPC_URL_4: "https://arbitrum-sepolia.gateway.tenderly.co"
31-
32-
# Scheduling Configuration
33-
SCHEDULED_RUN_TIME: "10:00"
34-
35-
# Subgraph URLs
36-
SUBGRAPH_URL_PRE_PRODUCTION: "https://api.studio.thegraph.com/query/110664/issuance-eligibility-oracle/v0.1.4"
37-
SUBGRAPH_URL_PRODUCTION: "https://gateway.thegraph.com/api/subgraphs/id/"
38-
39-
# Processing Configuration
40-
BATCH_SIZE: "125"
41-
MAX_AGE_BEFORE_DELETION: "120"
42-
43-
# Caching Configuration
44-
CACHE_MAX_AGE_MINUTES: "30"
45-
FORCE_BIGQUERY_REFRESH: "false"
46-
47-
# Eligibility Criteria
48-
MIN_ONLINE_DAYS: "5"
49-
MIN_SUBGRAPHS: "1"
50-
MAX_LATENCY_MS: "5000"
51-
MAX_BLOCKS_BEHIND: "50000"
52-
MIN_CURATION_SIGNAL: "500"
53-
54-
# Runtime Configuration
55-
RUN_ON_STARTUP: "true"
8+
config.toml: |
9+
# Service Quality Oracle Configuration
10+
# This file separates sensitive secrets from non-sensitive configuration values
11+
12+
# =============================================================================
13+
# NON-SENSITIVE CONFIGURATION
14+
# =============================================================================
15+
16+
[bigquery]
17+
BIGQUERY_LOCATION_ID = "US"
18+
BIGQUERY_PROJECT_ID = "graph-mainnet"
19+
BIGQUERY_DATASET_ID = "internal_metrics"
20+
BIGQUERY_TABLE_ID = "metrics_indexer_attempts"
21+
BIGQUERY_CURATION_TABLE_ID = "metrics_curator_signals"
22+
BIGQUERY_CURATOR_MAINNET_TABLE_ID = "curator_name_signal_dimensions_daily"
23+
BIGQUERY_CURATOR_ARBITRUM_TABLE_ID = "curator_name_signal_dimensions_arbitrum_daily"
24+
BIGQUERY_SUBGRAPH_LOOKUP_TABLE_ID = "subgraph_version_id_lookup"
25+
26+
[blockchain]
27+
BLOCKCHAIN_CONTRACT_ADDRESS = "0x9BED32d2b562043a426376b99d289fE821f5b04E"
28+
BLOCKCHAIN_FUNCTION_NAME = "renewIndexerEligibility"
29+
BLOCKCHAIN_CHAIN_ID = 421614
30+
BLOCKCHAIN_RPC_URLS = [
31+
"https://arbitrum-sepolia.drpc.org",
32+
"https://sepolia-rollup.arbitrum.io/rpc",
33+
"https://api.zan.top/arb-sepolia",
34+
"https://arbitrum-sepolia.gateway.tenderly.co"
35+
]
36+
BLOCK_EXPLORER_URL = "https://sepolia.arbiscan.io"
37+
TX_TIMEOUT_SECONDS = "30"
38+
39+
[scheduling]
40+
SCHEDULED_RUN_TIME = "10:00"
41+
42+
[subgraph]
43+
SUBGRAPH_URL_PRE_PRODUCTION = "https://api.studio.thegraph.com/query/110664/issuance-eligibility-oracle/v0.1.4"
44+
SUBGRAPH_URL_PRODUCTION = "https://gateway.thegraph.com/api/subgraphs/id/"
45+
46+
[processing]
47+
BATCH_SIZE = 125
48+
MAX_AGE_BEFORE_DELETION = 120
49+
BIGQUERY_ANALYSIS_PERIOD_DAYS = "28"
50+
51+
[caching]
52+
# Maximum age in minutes for cached data to be considered fresh
53+
CACHE_MAX_AGE_MINUTES = "30"
54+
# Force BigQuery refresh even if fresh cached data exists (true/false)
55+
FORCE_BIGQUERY_REFRESH = "false"
56+
57+
[eligibility_criteria]
58+
MIN_ONLINE_DAYS = "5"
59+
MIN_SUBGRAPHS = "1"
60+
MAX_LATENCY_MS = "5000"
61+
MAX_BLOCKS_BEHIND = "50000"
62+
MIN_CURATION_SIGNAL = "500"
63+
64+
# =============================================================================
65+
# SENSITIVE CONFIGURATION
66+
# =============================================================================
67+
68+
[secrets]
69+
GOOGLE_APPLICATION_CREDENTIALS = "$GOOGLE_APPLICATION_CREDENTIALS"
70+
BLOCKCHAIN_PRIVATE_KEY = "$BLOCKCHAIN_PRIVATE_KEY"
71+
ETHERSCAN_API_KEY = "$ETHERSCAN_API_KEY"
72+
ARBITRUM_API_KEY = "$ARBITRUM_API_KEY"
73+
STUDIO_API_KEY = "$STUDIO_API_KEY"
74+
STUDIO_DEPLOY_KEY = "$STUDIO_DEPLOY_KEY"
75+
SLACK_WEBHOOK_URL = "$SLACK_WEBHOOK_URL"

k8s/deployment.yaml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,10 @@ spec:
1717
containers:
1818
- name: rewards-eligibility-oracle
1919
image: ghcr.io/graphprotocol/rewards-eligibility-oracle:v0.4.1 # x-release-please-version
20-
envFrom:
21-
# Load all non-sensitive configuration from ConfigMap
22-
- configMapRef:
23-
name: rewards-eligibility-oracle-config
2420
env:
21+
# Runtime-only configuration (not in config.toml)
22+
- name: RUN_ON_STARTUP
23+
value: "true"
2524
# Secrets from Kubernetes Secret
2625
- name: GOOGLE_APPLICATION_CREDENTIALS
2726
valueFrom:
@@ -59,6 +58,10 @@ spec:
5958
name: rewards-eligibility-oracle-secrets
6059
key: slack-webhook-url
6160
volumeMounts:
61+
- name: config-volume
62+
mountPath: /app/config.toml
63+
subPath: config.toml
64+
readOnly: true
6265
- name: data-volume
6366
mountPath: /app/data
6467
- name: logs-volume
@@ -90,6 +93,9 @@ spec:
9093
initialDelaySeconds: 10
9194
periodSeconds: 30
9295
volumes:
96+
- name: config-volume
97+
configMap:
98+
name: rewards-eligibility-oracle-config
9399
- name: data-volume
94100
persistentVolumeClaim:
95101
claimName: rewards-eligibility-oracle-data

0 commit comments

Comments
 (0)