-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Summary
Currently, the PinShare deployment runs both the IPFS daemon and the PinShare application in a single container. This violates Kubernetes best practices and causes several operational issues, including permission conflicts, difficult resource management, and poor observability.
This issue proposes refactoring the deployment to use the sidecar pattern, where IPFS runs in a separate container within the same pod.
Current Architecture Problems
1. Single Point of Failure
- If either IPFS or PinShare crashes, the entire container restarts
- No independent process supervision
- Both processes managed via shell backgrounding (
&) which is fragile
2. Permission Conflicts
- IPFS daemon needs to run as the
ipfsuser (UID 1000) - PinShare application has different permission requirements
- Init container creates files as root, causing permission denied errors
- Current issue:
Error: error loading plugins: open /data/ipfs/config: permission denied
3. Resource Management
- Cannot set independent CPU/memory limits for IPFS vs PinShare
- Cannot independently scale IPFS and PinShare
- Resource contention between processes is not visible to Kubernetes scheduler
4. Health Checks & Observability
- Cannot independently monitor IPFS daemon health vs PinShare API health
- Liveness probe only checks IPFS, not PinShare
- Readiness probe only checks PinShare, not IPFS
- Mixed logs from both processes make debugging difficult
5. Update & Maintenance Challenges
- Cannot update IPFS independently from PinShare
- Docker image contains both IPFS (from Kubo) and PinShare binaries
- Larger image size and longer build times
- Difficult to test IPFS and PinShare separately
6. Startup Complexity
The entrypoint.sh script has brittle startup logic:
/usr/local/bin/start_ipfs daemon --migrate=true --agent-version-suffix=docker &
sleep 10 # Hope IPFS starts in 10 seconds
ipfs config ... # Configure CORS
sleep 50 # Wait more just to be safe
/opt/pinshare/bin/pinshare # Finally start PinShareHard-coded sleep timers are unreliable and waste time.
Proposed Solution: Sidecar Pattern
Architecture
Pod: pinshare-backend
├── Container: ipfs (sidecar)
│ ├── Image: ipfs/kubo:latest
│ ├── Ports: 5001 (API), 8080 (Gateway), 4001 (Swarm)
│ ├── Volume: ipfs-data (PVC)
│ ├── Health: IPFS dag stat check
│ └── Resources: Independent limits
│
├── Container: pinshare (main)
│ ├── Image: pinshare:latest (simplified, no IPFS)
│ ├── Ports: 9090 (API), 50001 (libp2p)
│ ├── Volume: backend-data (PVC)
│ ├── Health: HTTP /health check
│ ├── Resources: Independent limits
│ └── Connects to: localhost:5001 (IPFS)
│
└── InitContainer: ipfs-config
├── Configures IPFS CORS before startup
└── Sets proper permissions
Benefits
✅ Proper Separation of Concerns
- Each container has a single responsibility
- IPFS manages storage and IPFS protocol
- PinShare manages business logic and P2P metadata
✅ Independent Health Monitoring
# IPFS Container
livenessProbe:
exec:
command: ["ipfs", "dag", "stat", "/ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"]
# PinShare Container
livenessProbe:
httpGet:
path: /health
port: 9090✅ Independent Resource Management
# IPFS Container
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "2Gi"
cpu: "1000m"
# PinShare Container
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "1Gi"
cpu: "500m"✅ Cleaner Logs
kubectl logs pod/pinshare-xxx -c ipfs→ Only IPFS logskubectl logs pod/pinshare-xxx -c pinshare→ Only PinShare logs- Better for log aggregation systems (ELK, Loki, etc.)
✅ Faster Iteration
- Rebuild only PinShare without touching IPFS
- Use standard
ipfs/kuboimage directly (no custom build) - Smaller PinShare image (no IPFS binaries)
- Faster Tilt hot reload
✅ Easier Testing
- Test IPFS independently
- Test PinShare with mock IPFS
- Integration tests use the same sidecar pattern
Implementation Plan
Phase 1: Refactor Dockerfile
Current: Multi-stage build with Go builder + IPFS layer + Debian
Proposed: Simple Go builder → minimal runtime (no IPFS)
FROM golang:latest AS builder
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o pinshare .
FROM debian:stable-slim
RUN apt-get update && apt-get install -y \
chromium \
ca-certificates \
clamav clamav-daemon \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /build/pinshare /usr/local/bin/pinshare
EXPOSE 9090 50001
CMD ["pinshare"]Phase 2: Update Kubernetes Manifests
Deployment Changes:
- Add IPFS sidecar container
- Remove IPFS from main container
- Add init container for IPFS CORS configuration
- Update volume mounts (shared data, separate IPFS repo)
- Independent health checks
Service Changes:
- Ensure all necessary ports are exposed
- IPFS API (5001) accessible from PinShare container via localhost
Phase 3: Update Tiltfile
# Simplified live_update for PinShare (no IPFS layers)
docker_build(
'pinshare-backend',
'.',
dockerfile='Dockerfile',
live_update=[
sync('.', '/app'),
run('go build -o /usr/local/bin/pinshare .',
trigger=['./cmd', './internal', './pkg', 'go.mod', 'go.sum']),
],
)
# IPFS uses standard image (no rebuild needed)Phase 4: Update Documentation
- Update README with new architecture
- Update k8s/README.md with sidecar explanation
- Add architecture diagrams
- Document troubleshooting for each container
Phase 5: Docker Compose (Optional)
Consider updating docker-compose.yml to also use separate services for consistency:
services:
ipfs:
image: ipfs/kubo:latest
volumes:
- ipfs-data:/data/ipfs
ports:
- "5001:5001"
- "8080:8080"
- "4001:4001"
pinshare:
build: .
depends_on:
- ipfs
environment:
- IPFS_API=http://ipfs:5001
ports:
- "9090:9090"
- "50001:50001"Migration Strategy
Backwards Compatibility
- Keep existing Dockerfile with a
-legacysuffix for rollback - Create new
Dockerfilewith sidecar-compatible build - Both can coexist during transition
Testing
- Test locally with new Dockerfile
- Test with Tilt in local Kubernetes
- Verify all functionality works (file upload, IPFS pinning, P2P sync)
- Load testing to verify resource limits are appropriate
Rollout
- Update documentation first
- Merge Dockerfile changes
- Update Kubernetes manifests
- Update Tiltfile
- Notify users of new architecture
Acceptance Criteria
- PinShare container no longer contains IPFS binaries
- IPFS runs in a separate sidecar container
- Both containers have independent health checks
- Both containers have independent resource limits
- Permission errors are resolved
- Tilt hot reload works for PinShare code changes
- All existing functionality works (file upload, IPFS pinning, metadata sync)
- Logs are cleanly separated
- Documentation updated with new architecture
- k8s/README.md includes sidecar pattern explanation
Related Issues
- Kubernetes deployment support (depends on #TBD)
- Permission issues with IPFS persistent volumes