This document provides an overview of the architecture and deployment of a self-hosted KernelCI instance, focusing on DevOps aspects. It covers infrastructure setup, deployment options, configuration, and maintenance strategies.
A self-hosted KernelCI instance consists of two main independent components:
Purpose: Orchestrates git checkout, kernel builds, testing jobs, and manages the overall workflow.
Components:
API Service:
Pipeline Service:
Purpose: Database and services for storing and processing test results.
Components:
Best for: Development, testing, and small to medium setups
Clone Required Repositories
# For API service
git clone https://github.com/kernelci/kernelci-api
cd kernelci-api
# For Pipeline service
git clone https://github.com/kernelci/kernelci-pipeline
cd kernelci-pipeline
Note: The kernelci-api and kernelci-pipeline are separate repositories and can be deployed independently. However, kernelci-pipeline requires a running kernelci-api instance to function.
Configure Environment Variables
For kernelci-api:
cd kernelci-api
cp env.sample .env
# Edit .env and add required configuration:
# - SECRET_KEY: Secret key for JWT token signing (required)
# - MONGO_SERVICE: MongoDB connection string (default: mongodb://db:27017)
# - REDIS_HOST: Redis host (default: redis)
# - SMTP settings for email (optional)
For kernelci-pipeline:
cd kernelci-pipeline
touch .env
# Add required environment variables:
# - KCI_API_TOKEN: API token for authentication with kernelci-api
# - KCI_SETTINGS: Path to configuration file (default: /home/kernelci/config/kernelci.toml)
# - KCIDB_REST: KCIDB REST API endpoint (optional, for sending results to KCIDB)
# - LAVA_CALLBACK_PORT: Port for LAVA callback service (default: 8100)
Edit config/kernelci.toml
to configure:
Create Admin User (API only) After starting kernelci-api services, create an admin user:
docker exec -it kernelci-api python3 /scripts/setup_admin_user
Launch Services
kernelci-api docker-compose files:
docker-compose.yaml
- Base services (production images)dev-docker-compose.yaml
- Development with local builds and volume mountstest-docker-compose.yaml
- Testing environmentkernelci-pipeline docker-compose files:
docker-compose.yaml
- Main pipeline services (monitor, scheduler, tarball, trigger, timeout, patchset, job-retry)docker-compose-lava.yaml
- LAVA callback servicedocker-compose-kcidb.yaml
- KCIDB integration servicedocker-compose-production.yaml
- Production-specific overrides for lava-callbackPipeline services include:
Prepare data directories (required for pipeline services):
cd kernelci-pipeline
# Create required directories
mkdir -p data/output
mkdir -p data/src
mkdir -p data/ssh
mkdir -p data/k8s-credentials/.kube
mkdir -p data/k8s-credentials/.config/gcloud
mkdir -p data/k8s-credentials/.azure
mkdir -p logs
# For SSH-based storage, add SSH key
cp ~/.ssh/storage_key data/ssh/id_rsa_tarball
chmod 600 data/ssh/id_rsa_tarball
# For Kubernetes schedulers, add k8s credentials
cp ~/.kube/config data/k8s-credentials/.kube/config
# For GKE: copy gcloud credentials
# For AKS: copy Azure credentials
Starting services:
# Start all pipeline services
docker-compose up -d
# Start LAVA callback service
docker-compose -f docker-compose-lava.yaml up -d
# Start KCIDB integration
docker-compose -f docker-compose-kcidb.yaml up -d
# Check service status
docker-compose ps
# View logs
docker-compose logs -f
Note:
data/
directory is mounted into containers and stores git checkouts, build artifacts, and temporary fileslogs/
directory contains service logs for debuggingBy default, Docker Compose uses pre-built images from Docker Hub. For production or customized setups, you may want to build your own images.
Available Image Types:
Compiler Images - For building kernels across different architectures:
Miscellaneous Images:
kernelci
- Base KernelCI tools imagekernelci api
- API service imagekernelci pipeline
- Pipeline service imagekernelci lava-callback
- LAVA callback handlerk8s kernelci
- Kubernetes integration imageqemu
- QEMU emulation environmentbuildroot kernelci
- Buildroot-based imagesdebos kernelci
- Debian OS buildergcc-12 kunit kernelci
- KUnit testing with GCCrustc-1.74/1.75 kselftest kernelci
- Rust toolchain imagesBuilding Custom Images:
Using the kci
command-line tool from kernelci-core:
# Clone repositories
git clone https://github.com/kernelci/kernelci-core
git clone https://github.com/kernelci/kernelci-api
git clone https://github.com/kernelci/kernelci-pipeline
# Install kernelci-core tools
cd kernelci-core
python3 -m pip install '.[dev]'
sudo cp -R config /etc/kernelci/
# Build a compiler image for specific architecture
export core_rev=$(git rev-parse HEAD)
export core_url=$(git remote get-url origin)
./kci docker build --verbose --build-arg core_rev=$core_rev \
--build-arg core_url=$core_url \
clang-17 kselftest kernelci --arch arm64
# Build service images (API, Pipeline, etc.)
cd ../kernelci-core
core_rev=$(git rev-parse HEAD)
cd ../kernelci-api
api_rev=$(git rev-parse HEAD)
cd ../kernelci-pipeline
pipeline_rev=$(git rev-parse HEAD)
cd ../kernelci-core
# Build API image
./kci docker build --verbose \
--build-arg core_rev=$core_rev \
--build-arg api_rev=$api_rev \
--build-arg pipeline_rev=$pipeline_rev \
kernelci api
# Build Pipeline image
./kci docker build --verbose \
--build-arg core_rev=$core_rev \
--build-arg api_rev=$api_rev \
--build-arg pipeline_rev=$pipeline_rev \
kernelci pipeline
Image Naming Convention:
Images are tagged based on branch and registry:
ghcr.io/kernelci/<image-name>
or kernelci/<image-name>
ghcr.io/kernelci/staging-<image-name>
or kernelci/staging-<image-name>
Pushing to Registries:
# Push to GitHub Container Registry
./kci docker build --verbose --push --prefix=ghcr.io/kernelci/ kernelci api
# Get image name and tag for Docker Hub
NAME=$(./kci docker name --prefix=ghcr.io/kernelci/ kernelci api)
DHNAME=$(./kci docker name --prefix=kernelci/ kernelci api)
docker tag $NAME $DHNAME
docker push $DHNAME
Automated Builds:
The project uses GitHub Actions for automated image building:
.github/workflows/docker_images.yml
Prerequisites for Building:
Reference:
Best for: Production environments and larger setups
kube/aks/
directory of kernelci-api repositorykube/aks/
directory (production AKS-specific deployments)Kubernetes Cluster
az
CLIRequired Tools
kubectl
- Kubernetes CLIhelm
- Kubernetes package manager (v3+)yq
(Mike Farah’s Go version v4.35.2+) - YAML processoraz
CLI configured and authenticatedConfiguration Files
You need to prepare the following configuration files before deployment:
a) deploy.cfg
Main configuration file containing sensitive deployment parameters:
export API_TOKEN="<token-for-pipeline-to-api-authentication>"
export MONGO="<mongodb-connection-string>"
export API_SECRET_KEY="<secret-for-jwt-signing>"
export EMAIL_USER="<email-sender-address>"
export EMAIL_PASSWORD="<email-password>"
export KCIDB_REST="<kcidb-rest-endpoint-url>"
export IP_API="<optional-static-ip-for-api>"
export IP_PIPELINE="<optional-static-ip-for-pipeline>"
Note: For Azure deployments, IP_API
and IP_PIPELINE
can be auto-allocated on first run.
b) kernelci-secrets.toml
Pipeline secrets configuration (see Configuration section for details). This is specific to kernelci-pipeline.
Important sections include:
[jwt]
- Secret for signing JWT tokens for pipeline API[storage.<name>]
- Storage credentials for different storage backends[runtime.lava-<name>]
- LAVA lab runtime tokens and callback tokens[send_kcidb]
- KCIDB PostgreSQL credentials (if using KCIDB integration)c) k8s.tgz
Tarball containing Kubernetes credentials for build clusters (used by kernelci-pipeline):
k8s-credentials/.kube/config
- Kubernetes config filek8s-credentials/.config/gcloud/
- gcloud credentialsk8s-credentials/.azure/
- Azure CLI credentialsd) id_rsa
SSH private key for artifact storage access (SSH-based storage only)
Note: The kernelci-api service primarily requires only the deploy.cfg
with MongoDB and Redis connection strings. The other files (b, c, d) are for kernelci-pipeline integration.
Deployment Script Variables
Edit api-pipeline-deploy.sh
to customize for your environment:
# Azure-specific (unset if not using Azure)
AZURE_RG="kernelci-api-1_group" # Azure resource group
LOCATION="westus3" # Azure region
# Cluster configuration
CONTEXT="kernelci-api-1" # kubectl context name
CLUSTER_NAME="kernelci-api-1" # Cluster name
# Namespace and DNS configuration
NS_PIPELINE="kernelci-pipeline" # Pipeline namespace
DNS_PIPELINE="kernelci-pipeline" # Pipeline DNS label
NS_API="kernelci-api" # API namespace
DNS_API="kernelci-api" # API DNS label
# TLS certificate configuration
ACME="staging" # Use "staging" for testing, "production" for live
# Repository branch
BRANCH="main" # Git branch to deploy
Azure-Specific Setup
For Azure AKS deployments, the script automates several Azure-specific tasks:
Static IP Allocation:
# Automatically creates public IPs on first run
az network public-ip create --resource-group $AZURE_RG \
--name ${DNS_API}-ip --sku Standard \
--allocation-method static --location $LOCATION
DNS Configuration:
${DNS_API}.${LOCATION}.cloudapp.azure.com
RBAC Permissions:
Load Balancer Configuration:
Deployment Steps
Clone Deployment Repository
git clone https://github.com/kernelci/kernelci-deploy
cd kernelci-deploy/kubernetes
Prepare Configuration Files
# Create deploy.cfg from example
cp deploy.cfg.example deploy.cfg
# Edit deploy.cfg with your values
vim deploy.cfg
# Prepare kernelci-secrets.toml
cp kernelci-secrets.toml.example kernelci-secrets.toml
vim kernelci-secrets.toml
# Prepare k8s credentials tarball
tar czf k8s.tgz -C /path/to/credentials .kube .azure
# Copy SSH key for storage (if using SSH storage)
cp ~/.ssh/storage_key id_rsa
Run Initial Deployment
# Full deployment
./api-pipeline-deploy.sh full
This script performs the following operations:
Verify Deployment
# Check API namespace
kubectl --context=kernelci-api-1 get pods -n kernelci-api
# Check Pipeline namespace
kubectl --context=kernelci-api-1 get pods -n kernelci-pipeline
# Test API endpoint (Azure)
curl https://kernelci-api.westus3.cloudapp.azure.com/latest/
# Test Pipeline callback endpoint
curl https://kernelci-pipeline.westus3.cloudapp.azure.com/
Post-Deployment Configuration
After initial deployment, you need to create admin user and API tokens:
# Create admin user (run inside API pod)
# The setup_admin_user script is from kernelci-api repository at scripts/setup_admin_user
kubectl exec -it -n kernelci-api <api-pod-name> -- \
python3 /scripts/setup_admin_user
# Generate API token through API or admin interface
# Update deploy.cfg with API_TOKEN
# Deploy pipeline credentials with token (for pipeline integration)
./api-pipeline-deploy.sh pipeline-credentials
The deployment uses separate ingress-nginx controllers for each namespace:
API Ingress (kernelci-api namespace):
helm install ingress-nginx ingress-nginx/ingress-nginx \
-n kernelci-api \
--set controller.replicaCount=1 \
--set controller.service.loadBalancerIP="${IP_API}" \
--set controller.ingressClassResource.name=ingressclass-api \
--set controller.scope.enabled=true \
--set controller.scope.namespace=kernelci-api
Pipeline Ingress (kernelci-pipeline namespace):
helm install ingress-nginx2 ingress-nginx/ingress-nginx \
-n kernelci-pipeline \
--set controller.service.loadBalancerIP="${IP_PIPELINE}" \
--set controller.ingressClassResource.name=ingressclass-pipeline \
--set controller.scope.enabled=true \
--set controller.scope.namespace=kernelci-pipeline \
--set controller.service.annotations."nginx\.ingress\.kubernetes\.io/proxy-body-size"="128m"
Key Features:
Pipeline Ingress Exposes:
/
(all requests routed to lava-callback)Non-Azure Deployments: For non-Azure providers, you need to:
update_fqdn
function or skip it entirelyLocal MongoDB (default in manifests):
External MongoDB (recommended for production):
# Set MONGO in deploy.cfg to external MongoDB connection string
export MONGO="mongodb://user:pass@mongo-host:27017/kernelci?authSource=admin"
For production, consider:
The deployment uses cert-manager with Let’s Encrypt:
Staging Environment (default, for testing):
ACME="staging"
Production Environment:
ACME="production"
Certificate Issuer Configuration: The script creates a ClusterIssuer with ACME DNS01 challenges configured for both API and Pipeline domains.
Update Methods:
Automated Updates (Recommended):
Manual Updates:
./api-production-update.sh
Update Process:
The update script performs the following steps:
Clone Fresh Repositories:
git clone https://github.com/kernelci/kernelci-core
git clone https://github.com/kernelci/kernelci-api
git clone https://github.com/kernelci/kernelci-pipeline
Build and Push Docker Images:
Images built:
kernelci/kernelci:api@sha256:...
kernelci/kernelci:pipeline@sha256:...
kernelci/kernelci:lava-callback@sha256:...
Update Kubernetes Manifests:
Uses yq
to update image references with new sha256 digests:
./yq e ".spec.template.spec.containers[0].image = \
\"kernelci/kernelci:api@$SHA256\"" -i api.yaml
Update Configuration:
Apply to Cluster:
kubectl apply --namespace kernelci-api -f api.yaml
kubectl apply --namespace kernelci-pipeline -f pipeline-manifests/
Verification:
# Check pod status
kubectl get pods -n kernelci-api
kubectl get pods -n kernelci-pipeline
# Check for restarts or errors
kubectl describe pod <pod-name> -n <namespace>
# Check logs if issues
kubectl logs <pod-name> -n <namespace>
The api-pipeline-deploy.sh
script provides several management commands:
# Configuration management
./api-pipeline-deploy.sh config [dir] # Update pipeline configmap
./api-pipeline-deploy.sh backup-config # Backup pipeline configmap
./api-pipeline-deploy.sh pipeline-configmap # Redeploy configmap only
# Credentials and secrets
./api-pipeline-deploy.sh token # Update API token
./api-pipeline-deploy.sh pipeline-credentials # Update pipeline secrets
./api-pipeline-deploy.sh deploy_secret_toml_only # Update kernelci-secrets.toml
./api-pipeline-deploy.sh retrieve_secrets_toml # Extract current TOML
./api-pipeline-deploy.sh retrieve_k8s_credentials # Extract k8s credentials
./api-pipeline-deploy.sh update_k8s_credentials # Update with k8s-new.tgz
# Pod management
./api-pipeline-deploy.sh api-restart-pods # Restart all API pods
./api-pipeline-deploy.sh pipeline-restart-pods # Restart all pipeline pods
# MongoDB operations
./api-pipeline-deploy.sh backup-mongo # Backup MongoDB
./api-pipeline-deploy.sh mongo-shell # Access MongoDB shell
# Infrastructure
./api-pipeline-deploy.sh cert # Update cert-manager issuer
./api-pipeline-deploy.sh patch-nginx # Patch nginx for large payloads
# Cleanup
./api-pipeline-deploy.sh delete # Delete all namespaces
For Azure deployments, use create_kci_k8s_azure_build.sh
to create dedicated build clusters:
# Create full build cluster with spot instances
./create_kci_k8s_azure_build.sh full
This creates:
rg-kbuild-westus3
aks-kbuild-medium-1
Features:
Secrets Installation:
# Install/update secrets only
./create_kci_k8s_azure_build.sh secrets
Required secrets in secrets/
directory:
token-staging-api
- API token for stagingtoken-early-access
- API token for early accessazure_sas_staging
- Azure SAS token for storageCommon Issues:
Pods not starting:
kubectl describe pod <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace>
Ingress not getting IP:
Certificate issues:
kubectl describe certificate -n <namespace>
kubectl logs -n cert-manager <cert-manager-pod>
Pipeline not connecting to API:
Large LAVA callbacks failing:
./api-pipeline-deploy.sh patch-nginx
Azure-Specific Issues:
Static IP not attaching:
DNS not resolving:
When migrating from Docker Compose to Kubernetes:
Export Data:
Deploy to Kubernetes:
Verify:
Cutover:
Requirements:
Supported Storage Types:
HTTP-based Storage (Recommended)
SSH-based Storage (Not recommended for production)
The pipeline supports submitting jobs to multiple LAVA (Linaro Automated Validation Architecture) labs and receiving results via HTTP callbacks.
Configure LAVA labs in pipeline YAML configuration files (e.g., config/pipeline.yaml
):
runtimes:
lava-collabora: &lava-collabora
lab_type: lava
url: https://lava.collabora.dev/
priority_min: 40
priority_max: 60
notify:
callback:
token: kernelci-api-token-staging
Parameters:
lab_type
: Set to lava
url
: LAVA lab API endpoint where jobs will be submittedpriority_min
/priority_max
: Job priority rangenotify.callback.token
: Token description (not the actual token value) used in LAVA job definitionLAVA uses two types of tokens:
How LAVA tokens work:
Creating tokens in LAVA:
Configure LAVA runtime tokens in kernelci-secrets.toml
:
[runtime.lava-collabora]
# Token used to submit jobs to LAVA (authentication)
runtime_token = "REPLACE-WITH-LAVA-TOKEN-VALUE"
# Token expected in LAVA callback (if different from runtime_token)
callback_token = "REPLACE-WITH-LAVA-TOKEN-VALUE"
Token Types:
runtime_token
: Used by scheduler to authenticate when submitting jobs to LAVAcallback_token
: Expected in the Authorization header of LAVA callbacksIf you use the same token for both submission and callback, only specify runtime_token
.
The lava-callback
service receives notifications from LAVA labs after jobs complete:
Authorization
headerCallback URL: Set via KCI_INSTANCE_CALLBACK
environment variable or pipeline configuration
Example callback URL: https://kernelci-pipeline.example.com/lava/callback/
notify.callback.token
)runtime_token
, callback_token
)runtime_token
to submit jobscallback_token
(or runtime_token
if callback_token
is not set)Contains Kubernetes credentials for cluster access.
Required contents:
k8s-credentials/.kube/config
- Kubernetes config fileProvider-specific additions:
k8s-credentials/.config/gcloud
k8s-credentials/.azure
Main secrets configuration file.
Required sections:
[DEFAULT]
# Default API instance to use
api_config = "production"
# Default storage config to use
storage_config = "kci-storage-production"
[jwt]
# Used to provide API over kernelci-pipeline HTTP endpoint
secret = "<secret for signing jwt tokens>"
[storage.kci-storage-production]
storage_cred = "<secret for accessing storage>"
[runtime.lava-somename]
runtime_token = "<secret for accessing lava-somename>"
[send_kcidb]
# Configure this section if sending results to KCIDB
[tarball]
kdir = "/home/kernelci/data/src/linux"
output = "/home/kernelci/data/output"
[scheduler]
output = "/home/kernelci/data/output"
Main configuration file for kernelci-pipeline.
Documentation: https://github.com/kernelci/kernelci-pipeline/blob/main/doc/config-reference.md
Contains config fragments for kernel builds.
Location: https://github.com/kernelci/kernelci-core/blob/main/config/core/build-configs.yaml
Note: Adapt this file for your specific build requirements.
The lava-callback service provides a REST API for controlling pipeline operations beyond just receiving LAVA callbacks. This API is useful for:
To enable the Pipeline API, configure a JWT secret in kernelci-secrets.toml
:
[jwt]
secret = "your-secret-string-here"
This secret is used to sign and verify JWT tokens for API authentication.
Use the jwt_generator.py
tool from the tools/
directory to generate user tokens:
cd kernelci-pipeline/tools
python3 jwt_generator.py --secret "your-secret-string-here" --email user@example.com
Parameters:
--secret
: The JWT secret from kernelci-secrets.toml [jwt]
section--email
: User email address to embed in the tokenOutput: A JWT token string that can be used for authentication
The Pipeline API is exposed through the same ingress endpoint as the LAVA callback service.
Method 1: Using kci-dev CLI Tool (Recommended)
The kci-dev tool provides a command-line interface for interacting with the Pipeline API. It’s a standalone tool for Linux kernel developers and maintainers to interact with KernelCI.
Installation:
Using PyPI (recommended for users):
# Using virtualenv
virtualenv .venv
source .venv/bin/activate
pip install kci-dev
Or for development:
# Clone and install with poetry
git clone https://github.com/kernelci/kci-dev
cd kci-dev
virtualenv .venv
source .venv/bin/activate
pip install poetry
poetry install
Configuration:
Create a configuration file using:
kci-dev config
This creates a config file template at ~/.config/kci-dev/kci-dev.toml
. Edit it with your instance details:
default_instance="staging"
[local]
pipeline="https://127.0.0.1"
api="https://127.0.0.1:8001/"
token="your-jwt-token-here"
[staging]
pipeline="https://staging.kernelci.org:9100/"
api="https://staging.kernelci.org:9000/"
token="your-jwt-token-here"
[production]
pipeline="https://kernelci-pipeline.westus3.cloudapp.azure.com/"
api="https://kernelci-api.westus3.cloudapp.azure.com/"
token="your-jwt-token-here"
Available Commands:
checkout: Trigger ad-hoc test of specific tree/branch/commit
# Test a specific commit
kci-dev checkout \
--giturl https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git \
--branch master \
--commit f06021a18fcf8d8a1e79c5e0a8ec4eb2b038e153 \
--job-filter "kbuild-gcc-12-x86"
# Test latest commit with filters and watch results
kci-dev checkout \
--giturl https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git \
--branch master \
--tipoftree \
--job-filter baseline-nfs-arm64-qualcomm \
--platform-filter sc7180-trogdor-kingoftown \
--watch
# Watch for specific test result (useful for bisection)
kci-dev checkout \
--giturl https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git \
--branch master \
--tipoftree \
--job-filter baseline \
--watch \
--test baseline.login
Exit codes when using --test
:
0
: Test passed1
: Test failed2
: Error (prior steps failed, infrastructure error)64
: Critical error (kci-dev crashed)testretry: Retry failed or incomplete test jobs
kci-dev testretry --nodeid 65a5c89f1234567890abcdef
watch: Watch for results of a specific node
kci-dev watch \
--nodeid 679a91b565fae3351e2fac77 \
--job-filter "kbuild-gcc-12-x86-chromeos-amd" \
--test crit
results: Pull results from Web Dashboard (no token required)
kci-dev results --tree mainline --branch master
maestro-results: Pull Maestro results in JSON format
kci-dev maestro-results --nodes --filter "status=fail"
Configuration Priority:
kci-dev loads configuration files in the following order (later files override earlier ones):
/etc/kci-dev.toml
~/.config/kci-dev/kci-dev.toml
.kci-dev.toml
(or override with --settings
option)Instance Selection:
Override the default instance for a specific command:
kci-dev --instance production checkout --giturl ... --branch ... --tipoftree
Method 2: Direct API Calls
You can also interact directly with the API using curl or similar tools:
# Trigger custom checkout
curl -X POST https://kernelci-pipeline.example.com/api/checkout \
-H "Authorization: YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git",
"branch": "master",
"commit": "abc123...",
"jobfilter": ["baseline"]}'
# Retry a job
curl -X POST https://kernelci-pipeline.example.com/api/jobretry \
-H "Authorization: YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"nodeid": "65a5c89f1234567890abcdef"}'
Note: The Pipeline API requires proper configuration in the [jwt]
section of kernelci-secrets.toml. Without this configuration, only LAVA callback functionality will be available.
Additional Resources:
KCIDB-NG is a complete rewrite of the KernelCI Database services, providing REST API access for submitting kernel test data and log analysis capabilities.
KCIDB-NG consists of the following components:
kcidb-restd-rs - Rust-based REST API service
ingester - Python submission processor
logspec-worker - Python log analysis service
PostgreSQL Database - Data storage
/spool
- Incoming submissions and archives/state
- Application state (processed builds/tests tracking)/cache
- Downloaded log files/db
- PostgreSQL data (self-hosted mode)/certs
- TLS certificates (optional)Best for: Deploying only the data ingestion and processing services without the web dashboard.
Prerequisites:
Setup Steps:
Clone the Repository
git clone https://github.com/kernelci/kcidb-ng
cd kcidb-ng
Configure Environment Variables
Create a .env
file in the root directory:
# PostgreSQL configuration
POSTGRES_PASSWORD=kcidb
PG_PASS=kcidb
PG_URI=postgresql:dbname=kcidb user=kcidb_editor password=kcidb host=db port=5432
# Verbosity (set to 0 in production)
KCIDB_VERBOSE=1
# LogSpec dry-run mode (set to 0 to enable database modifications)
KCIDB_DRY_RUN=1
# JWT authentication secret
JWT_SECRET=your_jwt_secret_here
Important: Generate a strong JWT secret:
openssl rand -hex 32
Choose Deployment Profile
Self-hosted mode (with local PostgreSQL):
docker compose --profile=self-hosted up -d --build
This profile:
Google Cloud SQL mode:
docker compose --profile=google-cloud-sql up -d --build
For Google Cloud SQL, you need to:
./config/db.json
Generate JWT Tokens
For production deployments with JWT authentication enabled:
kcidb-restd-rs/tools/jwt_rest.py --secret YOUR_SECRET --origin YOUR_ORIGIN
To disable JWT authentication (not recommended for production), uncomment this line in docker-compose.yaml
:
command: ["/usr/local/bin/kcidb-restd-rs","-j",""]
Verify Deployment
# Check running containers
docker compose ps
# View logs
docker logs kcidb-rest
docker logs ingester
docker logs logspec-worker
# Test API endpoint (with JWT token)
curl -X GET \
-H "Authorization: Bearer <jwt_token>" \
https://localhost:443/authtest
Submit Test Data
curl -X POST \
-H "Authorization: Bearer <jwt_token>" \
-H "Content-Type: application/json" \
-d @submission.json \
https://localhost:443/submit
Check submission status:
curl -X GET \
-H "Authorization: Bearer <jwt_token>" \
https://localhost:443/status?id=<submission_id>
Possible status values:
inprogress
- Upload not yet complete (.json.temp file exists)ready
- File ready for processingprocessed
- Successfully processed and archivedfailed
- Failed validationnotfound
- Submission ID not founderror
- Invalid requestServices and Ports:
Directory Structure:
/spool
- Stores incoming submissions/spool/failed
- Failed submissions/spool/archive
- Successfully processed submissions/state
- Application stateprocessed_builds.db
- Tracks processed buildsprocessed_tests.db
- Tracks processed tests/cache
- Downloaded log files for analysis/db
- PostgreSQL data (self-hosted mode only)Best for: Deploying only the web dashboard to visualize existing KCIDB data.
Prerequisites:
Setup Steps:
Clone Dashboard Repository
git clone https://github.com/kernelci/dashboard
cd dashboard
Configure Environment Variables
Create .env
file in /dashboard
directory:
cp ./dashboard/.env.example ./dashboard/.env
Edit .env
with your configuration:
# API endpoint for frontend
VITE_API_URL=http://localhost:8000
Create backend environment file:
# Django configuration
export DJANGO_SECRET_KEY=$(openssl rand -base64 22)
export DB_DEFAULT_USER=your_db_user@example.com
export DB_DEFAULT_NAME=kcidb
export DB_DEFAULT_HOST=db_host
export DB_DEFAULT_PORT=5432
# CORS allowed origins (required for non-production)
export CORS_ALLOWED_ORIGINS='["https://dashboard.example.com"]'
# Optional: Discord webhook for notifications
export DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/..."
Setup Database Credentials
For Google Cloud SQL:
# Setup cloud-sql-proxy
gcloud auth application-default login
cp ~/.config/gcloud/application_default_credentials.json .
# Verify permissions
ls -l application_default_credentials.json
For direct PostgreSQL connection:
# Create secrets directory
mkdir -p backend/runtime/secrets
echo "<your_password>" > backend/runtime/secrets/postgres_password_secret
Launch Dashboard Services
docker compose up --build -d
This starts:
Access Dashboard
http://localhost
http://localhost/api
http://localhost:8000
Setup Cron Jobs (optional)
The dashboard backend includes cron jobs for automated tasks (email notifications, etc.).
Verify cron jobs are running:
docker exec -it dashboard_backend_service crontab -l
Best for: Complete self-hosted KernelCI test result system with data ingestion and visualization.
Prerequisites:
Quick Start:
Clone KCIDB-NG Repository
git clone https://github.com/kernelci/kcidb-ng
cd kcidb-ng
Run Installation Script
./self-hosted.sh run
This automated script will:
.env
configuration with random JWT secretdocker-compose-all.yaml
Generated .env
contents:
# PostgreSQL configuration
POSTGRES_PASSWORD=kcidb
PG_PASS=kcidb
PG_URI=postgresql:dbname=kcidb user=kcidb_editor password=kcidb host=db port=5432
# Programs will be more talkative if this is set
KCIDB_VERBOSE=1
# logspec will not modify database in dry-run mode
KCIDB_DRY_RUN=1
# JWT authentication
JWT_SECRET=<randomly_generated>
Verify Services
# Check all running containers
docker compose -f docker-compose-all.yaml --profile=self-hosted ps
# View logs
./self-hosted.sh logs
Access Services
https://localhost:443
or http://localhost:8080
http://localhost:80
http://localhost:80/api
Management Commands
# Stop services
./self-hosted.sh down
# View logs
./self-hosted.sh logs
# Update to latest versions
./self-hosted.sh update
# Complete cleanup (removes all data)
./self-hosted.sh clean
Architecture:
The combined deployment uses a shared PostgreSQL database and separate Docker networks:
┌─────────────────────────────────────────────────────────────┐
│ Network: private │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ kcidb-rest │ │ ingester │ │logspec-worker│ │
│ │ (Port 443) │ │ │ │ │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ └───────────────────┴───────────────────┘ │
│ │ │
│ ┌──────▼───────┐ │
│ │ PostgreSQL │ │
│ │ (Port 5432)│ │
│ └──────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Backend │◄───┤ Redis │ │ Dashboard DB │ │
│ │ (Port 8000) │ │ (Port 6379) │ │ (Port 5434) │ │
│ └──────┬───────┘ └──────────────┘ └──────────────┘ │
│ │ │
└─────────┼───────────────────────────────────────────────────┘
│
┌─────────▼────────────────────────────────────────────────────┐
│ Network: public │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Proxy │ │ Dashboard │ │
│ │ (Port 80) │◄───┤ (static) │ │
│ └──────────────┘ └──────────────┘ │
│ │ │
└─────────┼────────────────────────────────────────────────────┘
│
User Browser
Docker Compose Configuration:
The docker-compose-all.yaml
includes the dashboard services via:
include:
- path: ./dashboard/docker-compose.yml
Shared Resources:
private
network for backend communicationThe database is automatically initialized by the dbinit
service when using --profile=self-hosted
.
Manual setup (if needed):
# Run setup script
./scripts/setup_pgsql.sh
This creates:
kcidb
kcidb
with password kcidb
(superuser)kcidb_editor
- Write accesskcidb_viewer
- Read-only access# Via docker container
docker exec -it postgres psql -U kcidb_editor -d kcidb
# Query test results
SELECT * FROM tests LIMIT 10;
# Check database schema
\dt
# Backup database
docker exec postgres pg_dump -U kcidb_editor kcidb > backup.sql
# Restore database
docker exec -i postgres psql -U kcidb_editor kcidb < backup.sql
Primary environment configuration:
# PostgreSQL connection
POSTGRES_PASSWORD=kcidb
PG_PASS=kcidb
PG_URI=postgresql:dbname=kcidb user=kcidb_editor password=kcidb host=db port=5432
# Logging verbosity (0=quiet, 1=verbose)
KCIDB_VERBOSE=1
# LogSpec dry-run mode (1=no database writes, 0=write to database)
KCIDB_DRY_RUN=1
# JWT secret for authentication
JWT_SECRET=<random_hex_string>
# Optional: TLS/SSL configuration
# CERTBOT_DOMAIN=example.com
# CERTBOT_EMAIL=admin@example.com
LogSpec worker configuration (copied from example on first run):
# Log analysis configuration
origins:
- microsoft
- collabora
# Issue detection patterns
patterns:
- name: kernel_panic
regex: "Kernel panic"
- name: oops
regex: "Oops:"
Dashboard backend configuration:
# Database connection
DB_DEFAULT_USER=kcidb_editor
DB_DEFAULT_NAME=kcidb
DB_DEFAULT_HOST=db
DB_DEFAULT_PORT=5432
# Django settings
DJANGO_SECRET_KEY=<random_base64_string>
DEBUG=False
# CORS configuration
CORS_ALLOWED_ORIGINS=["http://localhost","http://localhost:80"]
# Optional: Discord notifications
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
# Optional: Email configuration
# EMAIL_HOST=smtp.example.com
# EMAIL_PORT=587
# EMAIL_USE_TLS=True
JWT Authentication:
TLS/SSL:
Database:
Network:
Horizontal Scaling:
Database:
Storage:
/spool
and /cache
volumesService Health:
# Check service status
docker compose ps
# Monitor resource usage
docker stats
# Check logs for errors
docker compose logs --tail=100 -f
Database Monitoring:
# Check database connections
docker exec postgres psql -U kcidb_editor -d kcidb \
-c "SELECT count(*) FROM pg_stat_activity;"
# Monitor database size
docker exec postgres psql -U kcidb_editor -d kcidb \
-c "SELECT pg_size_pretty(pg_database_size('kcidb'));"
Submission Tracking:
# Monitor spool directory
ls -la spool/
ls -la spool/archive/
ls -la spool/failed/
# Check processing state
sqlite3 state/processed_builds.db "SELECT COUNT(*) FROM builds;"
sqlite3 state/processed_tests.db "SELECT COUNT(*) FROM tests;"
Log Rotation:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
Database Maintenance:
# Vacuum database
docker exec postgres psql -U kcidb_editor -d kcidb -c "VACUUM ANALYZE;"
# Reindex database
docker exec postgres psql -U kcidb_editor -d kcidb -c "REINDEX DATABASE kcidb;"
Archive Cleanup:
# Remove old archived submissions (older than 30 days)
find ./spool/archive -type f -mtime +30 -delete
# Remove old cached logs
find ./cache -type f -mtime +7 -delete
Update containers:
# Using self-hosted script
./self-hosted.sh update
# Manual update
docker compose -f docker-compose-all.yaml --profile=self-hosted pull
docker compose -f docker-compose-all.yaml --profile=self-hosted up -d --build
Database migrations:
Services not starting:
# Check logs
docker compose logs <service_name>
# Check configuration
docker compose config
# Verify environment variables
docker compose config | grep -A 5 "environment:"
Database connection issues:
# Test database connection
docker exec -it postgres psql -U kcidb_editor -d kcidb
# Check database logs
docker logs postgres
# Verify network connectivity
docker exec kcidb-rest ping -c 3 db
JWT authentication failing:
Dashboard not loading:
# Check proxy logs
docker logs dashboard-proxy-1
# Check backend logs
docker logs dashboard_backend_service
# Verify CORS configuration
docker exec dashboard_backend_service env | grep CORS
LogSpec not processing logs:
# Check worker logs
docker logs logspec-worker
# Verify configuration
cat config/logspec_worker.yaml
# Check cache directory permissions
ls -la cache/
Enable verbose logging:
# Edit .env
KCIDB_VERBOSE=1
DEBUG=True
DEBUG_SQL_QUERY=True # For Django SQL debugging
# Restart services
docker compose restart
Test log processing without database writes:
docker exec -it logspec-worker python /app/logspec_worker.py \
--spool-dir /app/spool \
--origins microsoft \
--dry-run
If migrating from the original Python-based KCIDB system:
Export existing data:
kcidb-query
to export data in JSON formatImport into KCIDB-NG:
Update submission scripts:
Verify data integrity: