Skip to main content

Container Best Practices for Marketplace

This guide covers essential best practices for containerizing applications to meet Armada Edge Platform marketplace requirements and ensure optimal performance, security, and maintainability.

Container Image Standards

Base Image Selection

Recommended Base Images:

# For production applications
FROM ubuntu:22.04
FROM debian:bullseye-slim
FROM alpine:3.18
FROM distroless/static:nonroot

# For specific runtimes
FROM node:18-alpine
FROM python:3.11-slim
FROM openjdk:17-jre-slim
FROM golang:1.21-alpine AS builder

Avoid Deprecated Images:

# ❌ Avoid these
FROM ubuntu:16.04 # EOL
FROM centos:7 # EOL
FROM node:12 # EOL
FROM python:2.7 # EOL

Multi-Stage Builds

Optimize Image Size:

# Example: Go application
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .

FROM alpine:3.18
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/main .
CMD ["./main"]

Node.js Application:

FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["npm", "start"]

Security Best Practices

Non-Root User Execution

Always run as non-root:

# Create non-root user
RUN groupadd -r appuser && useradd -r -g appuser appuser

# Set ownership
RUN chown -R appuser:appuser /app

# Switch to non-root user
USER appuser

Using distroless images:

FROM gcr.io/distroless/static:nonroot
COPY --chown=nonroot:nonroot app /app
CMD ["/app"]

Image Scanning Requirements

Pre-build scanning:

# Scan base images before use
trivy image --severity HIGH,CRITICAL ubuntu:22.04

# Scan application dependencies
trivy fs --severity HIGH,CRITICAL .

# Generate SBOM
trivy image --format cyclonedx myapp:v1.2.0 > sbom.json

Vulnerability thresholds:

# Acceptable vulnerability levels for marketplace
vulnerability_thresholds:
critical: 0 # Must be zero
high: 0 # Must be zero
medium: 5 # Maximum 5 medium issues
low: 20 # Maximum 20 low issues

Secrets Management

Never embed secrets in images:

# ❌ Wrong - secrets in image
ENV DB_PASSWORD=secret123
ENV API_KEY=abc123

# ✅ Correct - use runtime injection
ENV DB_PASSWORD=""
ENV API_KEY=""

Use Kubernetes secrets:

apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
db-password: <base64-encoded>
api-key: <base64-encoded>
---
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: app
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: db-password

Performance Optimization

Image Size Optimization

Minimize layers:

# ❌ Bad - many layers
RUN apt-get update
RUN apt-get install -y package1
RUN apt-get install -y package2
RUN apt-get install -y package3

# ✅ Good - single layer
RUN apt-get update && \
apt-get install -y \
package1 \
package2 \
package3 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

Use .dockerignore:

# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.nyc_output
coverage
.DS_Store
*.log

Resource Efficiency

Set appropriate resource limits:

apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: app
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"

Optimize for edge environments:

# Edge-specific optimizations
edge_optimizations:
memory_efficiency:
- use_alpine_base_images: true
- enable_compression: true
- optimize_binary_size: true

startup_time:
- minimize_dependencies: true
- use_static_linking: true
- optimize_layer_caching: true

Health Checks

Application Health Endpoints

Implement health checks:

# Add health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1

Kubernetes health checks:

apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: app
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3

Health Check Implementation

Go application example:

package main

import (
"net/http"
"time"
)

func healthHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("healthy"))
}

func readyHandler(w http.ResponseWriter, r *http.Request) {
// Check database connection
if err := db.Ping(); err != nil {
http.Error(w, "not ready", http.StatusServiceUnavailable)
return
}

w.WriteHeader(http.StatusOK)
w.Write([]byte("ready"))
}

Logging Standards

Structured Logging

Use structured logging:

{
"timestamp": "2024-01-15T10:30:00Z",
"level": "INFO",
"service": "myapp",
"version": "1.2.0",
"message": "Application started",
"pod": "myapp-xyz123",
"namespace": "default"
}

Log configuration:

apiVersion: v1
kind: ConfigMap
metadata:
name: app-logging-config
data:
log-level: "INFO"
log-format: "json"
log-output: "stdout"

Log Rotation

Configure log rotation:

# Log rotation settings
log_rotation:
max_size: "100MB"
max_files: 5
max_age: "7d"
compress: true

Configuration Management

Environment Variables

Use environment variables for configuration:

# Define environment variables
ENV APP_ENV=production
ENV LOG_LEVEL=INFO
ENV PORT=8080

Kubernetes ConfigMaps:

apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_ENV: "production"
LOG_LEVEL: "INFO"
DATABASE_URL: "postgresql://db:5432/myapp"
REDIS_URL: "redis://redis:6379"
---
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: app
envFrom:
- configMapRef:
name: app-config

Configuration Validation

Validate configuration at startup:

package main

import (
"log"
"os"
)

func validateConfig() error {
required := []string{
"DATABASE_URL",
"REDIS_URL",
"API_KEY",
}

for _, env := range required {
if os.Getenv(env) == "" {
return fmt.Errorf("required environment variable %s not set", env)
}
}

return nil
}

func main() {
if err := validateConfig(); err != nil {
log.Fatal(err)
}
// Start application
}

Edge-Specific Considerations

Offline Operation

Handle intermittent connectivity:

# Offline operation configuration
offline_operation:
enabled: true
data_sync:
- sync_on_connect: true
- retry_interval: "5m"
- max_retries: 10

local_storage:
- cache_duration: "24h"
- max_cache_size: "1GB"

Resource Constraints

Optimize for limited resources:

# Resource optimization for edge
edge_optimizations:
memory:
- use_streaming_processing: true
- implement_garbage_collection: true
- limit_concurrent_operations: 10

cpu:
- use_async_processing: true
- implement_rate_limiting: true
- optimize_algorithm_complexity: true

Network Efficiency

Optimize network usage:

# Network optimization
network_optimization:
compression:
- enable_gzip: true
- compression_level: 6

caching:
- enable_http_cache: true
- cache_headers: ["ETag", "Last-Modified"]

connection_pooling:
- max_connections: 100
- connection_timeout: "30s"
- keep_alive: true

Testing Requirements

Container Testing

Unit tests in container:

# Multi-stage build with testing
FROM golang:1.21-alpine AS test
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go test -v ./...

FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o main .

FROM alpine:3.18
COPY --from=builder /app/main .
CMD ["./main"]

Integration Testing

Test container integration:

# Integration test configuration
integration_tests:
- name: "Database Connection"
test: "Verify database connectivity"
timeout: "30s"

- name: "API Endpoints"
test: "Verify all API endpoints respond"
timeout: "60s"

- name: "Health Checks"
test: "Verify health check endpoints"
timeout: "30s"

Marketplace Compliance

Image Signing

Sign container images:

# Sign image with Cosign
cosign sign --key cosign.key myapp:v1.2.0

# Verify signature
cosign verify --key cosign.pub myapp:v1.2.0

SBOM Generation

Generate Software Bill of Materials:

# Generate SBOM with Trivy
trivy image --format cyclonedx myapp:v1.2.0 > sbom.json

# Include in package
tar -czf myapp-package.tar.gz \
manifests/ \
charts/ \
sbom.json \
scan-report.json

Documentation Requirements

Required documentation:

# Required documentation files
documentation:
- README.md # Setup and deployment
- INSTALL.md # Installation guide
- CONFIGURATION.md # Configuration options
- TROUBLESHOOTING.md # Common issues
- SECURITY.md # Security considerations
- API.md # API documentation

Summary

Following these container best practices ensures:

  1. Security: Non-root execution, vulnerability scanning, secrets management
  2. Performance: Optimized image size, resource efficiency, health checks
  3. Maintainability: Structured logging, configuration management, documentation
  4. Edge Compatibility: Offline operation, resource constraints, network efficiency
  5. Marketplace Compliance: Image signing, SBOM generation, testing requirements

These practices are essential for successful certification and deployment on the Armada Edge Platform marketplace.