- Document Corteza (Low-Code) package completion - Add Download Pre-Compiled Binaries pattern - Include build process details - Document challenges (none encountered) - Add packaging template for pre-compiled applications - Include pros and cons of this approach Corteza package highlights: - Multi-stage build downloading pre-compiled binaries - Ubuntu 22.04 base (436MB image) - PostgreSQL + localstorage addons - Comprehensive low-code platform documentation - Download-and-extract approach (simpler than compiling) New packaging pattern: - Download Pre-Compiled Binaries - Use when application provides official releases - Faster builds, reproducible results - Trade-offs: dependency on upstream, less customization Total packages completed: 7/56 (12.5%) 💘 Generated with Crush Assisted-by: GLM-4.7 via Crush <crush@charm.land>
20 KiB
JOURNAL - Cloudron Packaging Project
Project Overview
Project: TSYSDevStack-SupportStack-Cloudron Goal: Package 58 applications for Cloudron PaaS platform Start Date: 2025-01-24 Current Status: 5/58 packages completed (8.6%)
Completed Packages
1. Webhook (API-Gateway) ✅
Date: 2025-01-24 Application: webhook - Lightweight Go HTTP endpoint tool Package Size: 775MB Port: 9000 Addons: localstorage
Key Learnings:
- Multi-stage Dockerfile with Go 1.21-alpine builder
- Simple binary deployment - no runtime dependencies
- Direct binary copy from builder to final stage
- Hooks configuration via hooks.json
Build Process:
- Stage 1: Golang 1.21-alpine builder with git/make
- Stage 2: Cloudron base 3.2.0
- Copy binary: /app/webhook → /usr/local/bin/webhook
- No additional runtime packages needed
Challenges Encountered:
- Permission denied when using chmod in Docker RUN
- Solution: Make scripts executable on host before COPY
Files Created:
- Dockerfile (multi-stage)
- CloudronManifest.json (port 9000, localstorage)
- start.sh (optional, used hooks.json instead)
- README.md (usage documentation)
- CHANGELOG.md (version tracking)
- hooks.json.example (configuration template)
- logo.png
Commit: feat: add webhook Cloudron package (API-Gateway)
2. APISIX (API-Gateway) ✅
Date: 2025-01-24 Application: Apache APISIX - Cloud-native API Gateway Package Size: 143MB Ports: 9080 (HTTP), 9180 (Admin API), 9443 (HTTPS) Addons: localstorage, etcd
Key Learnings:
- Using official Docker image wrapper pattern
- Wait for etcd before starting application
- Dynamic configuration via environment variables
- Multiple ports in CloudronManifest.json
Build Process:
- Base: apache/apisix:latest
- Copy start.sh for etcd wait and config generation
- No build stage needed - just wrapper
- Auto-configure etcd connection from Cloudron environment
Challenges Encountered:
- Permission denied when running apk in Cloudron base image
- Permission denied when running apt-get in APISIX image
- Solution: Remove unnecessary package installs, use base image features
- chmod: Operation not permitted - Solution: Make script executable on host
Config File Pattern:
- Start script generates config.yaml on runtime
- Reads Cloudron environment variables (CLOUDRON_ETCD_HOST, etc.)
- Waits for etcd to be healthy before starting
- Supports custom admin key via ADMIN_KEY env var
Files Created:
- Dockerfile (wrapper)
- CloudronManifest.json (3 TCP ports)
- start.sh (etcd wait + config generation)
- README.md (comprehensive API usage)
- CHANGELOG.md (version tracking)
- config.yaml.example (reference configuration)
- logo.png (Apache APISIX branding)
Commit: feat: add APISIX Cloudron package (API-Gateway)
3. Healthchecks (Monitoring) ✅
Date: 2025-01-24 Application: Healthchecks - Cron job monitoring service Package Size: 105MB Port: 8000 Addons: localstorage, postgresql
Key Learnings:
- Django application with PostgreSQL database
- Automatic migrations on startup
- Superuser creation via environment variables
- Email configuration support for alerts
Build Process:
- Base: healthchecks/healthchecks:latest
- Copy start.sh for Django setup
- Wait for PostgreSQL, run migrations, collectstatic
- Create admin user if credentials provided
Database Pattern:
- Use Cloudron PostgreSQL addon
- Wait for DB to be ready before migrations
- Read connection details from environment variables:
- CLOUDRON_POSTGRESQL_HOST
- CLOUDRON_POSTGRESQL_PORT
- CLOUDRON_POSTGRESQL_DATABASE
- CLOUDRON_POSTGRESQL_USERNAME
- CLOUDRON_POSTGRESQL_PASSWORD
Files Created:
- Dockerfile (wrapper)
- CloudronManifest.json (port 8000, postgresql addon)
- start.sh (PostgreSQL wait + Django migrations + admin creation)
- README.md (monitoring examples, integration setup)
- CHANGELOG.md (version tracking)
- .env.example (configuration template)
- logo.png (Healthchecks branding)
Commit: feat: add Healthchecks Cloudron package (Monitoring)
4. Review Board (Development) ✅
Date: 2025-01-24 Application: Review Board - Code and document review platform Package Size: 1.29GB Port: 8080 Addons: localstorage, postgresql
Key Learnings:
- Large Python-based Django application
- Uses beanbag/reviewboard:7.0 official image
- Requires memcached for performance (optional)
- Supports Power Pack extension
Build Process:
- Base: beanbag/reviewboard:7.0
- Copy start.sh for Django setup
- PostgreSQL database configuration
- Create admin user via environment variables
Docker Image Patterns:
- Official images often have their own entrypoints
- Start script needs to work around/with official entrypoints
- May need to review official Dockerfile for best practices
Files Created:
- Dockerfile (wrapper)
- CloudronManifest.json (port 8080, postgresql addon)
- start.sh (PostgreSQL wait + Django migrations + admin creation)
- README.md (comprehensive review platform documentation)
- CHANGELOG.md (version tracking)
- .env.example (configuration template with LDAP)
- logo.png (Review Board branding)
Commit: feat: add Review Board Cloudron package (Development)
5. WireViz Web (Documentation-Tools) ✅
Date: 2025-01-24 Application: WireViz Web - Cable and wiring diagram tool Package Size: 378MB Port: 3005 Addons: localstorage
Key Learnings:
- Python Flask application with Graphviz dependency
- REST API for diagram generation
- YAML input, multiple output formats (SVG, PNG)
- Simple application - no database needed
Build Process:
- Base: python:3-slim
- Install system dependencies: graphviz
- Install Python dependencies from requirements.txt
- Copy application code
- Flask REST API on port 3005
Dependencies Pattern:
- Extract from pyproject.toml or requirements.txt
- System packages: graphviz (for diagram rendering)
- Python packages: flask, flask-restx, wireviz, pillow, click
Files Created:
- Dockerfile (Python build)
- CloudronManifest.json (port 3005, localstorage addon)
- requirements.txt (Python dependencies from pyproject.toml)
- README.md (diagram examples, color coding, connector types)
- CHANGELOG.md (version tracking)
- .env.example (configuration template)
- logo.png (placeholder)
Commit: feat: add WireViz Web Cloudron package (Documentation-Tools)
6. Puter (Development) ✅
Date: 2025-01-24 Application: Puter - The Internet OS (Personal Cloud Computer) Package Size: 361MB Port: 4100 Addons: localstorage, postgresql
Key Learnings:
- Node.js 23.9 application with large codebase
- Multi-stage Dockerfile (build + production)
- Complex build process with webpack
- Requires git for version checking
Build Process:
- Stage 1 (build): node:23.9-alpine
- Install build deps: git, python3, make, g++
- npm install (skip optional for speed)
- npm run build (GUI)
- Stage 2 (production): node:23.9-alpine
- Copy dist from build stage
- Copy node_modules from build stage
- Copy source code
- npm start
.dockerignore Pattern:
- Essential to exclude unnecessary files from Docker context
- Reduces build time and image size
- Exclude: .git, README.md, Dockerfile, etc.
Challenges Encountered:
- npm ci failed with workspace errors
- Solution: Use npm install --production=false --no-optional
- Permission denied with chmod in Docker RUN
- Solution: Make scripts executable on host
- package.json not found - Solution: Explicit COPY with repo/ prefix
- .dockerignore from repo interfered - Solution: Create custom .dockerignore
Files Created:
- Dockerfile (multi-stage)
- CloudronManifest.json (port 4100, postgresql + localstorage addons)
- .dockerignore (Cloudron-specific excludes)
- README.md (comprehensive Internet OS documentation)
- CHANGELOG.md (version tracking)
- .env.example (configuration template)
- logo.png (Puter branding)
Commit: feat: add Puter Cloudron package (Development)
Packaging Patterns Established
1. Official Image Wrapper Pattern
Use Cases: When application provides official Docker image Template:
FROM official/app:version
# Copy startup script
COPY start.sh /app/start.sh
RUN chmod +x /app/start.sh
CMD ["/app/start.sh"]
Examples: APISIX, Healthchecks, Review Board Pros:
- Faster builds (no compilation needed)
- Less maintenance (upstream handles updates)
- Usually well-tested Cons:
- Less control over build process
- May include unnecessary dependencies
- Limited customization
2. Multi-Stage Build Pattern
Use Cases: When application needs compilation or build process Template:
# Build stage
FROM base:builder AS build
# Install build dependencies
COPY . .
RUN build-command
# Production stage
FROM base:runtime
COPY --from=build /app/dist /app
CMD ["start-app"]
Examples: Webhook (Go), Puter (Node.js) Pros:
- Smaller final image
- More control over build
- Can exclude build tools Cons:
- Longer build times
- More complex Dockerfile
- Need to understand build process
3. Python Build Pattern
Use Cases: Python applications with dependencies Template:
FROM python:3-slim
# Install system dependencies
RUN apt-get update && apt-get install -y graphviz && rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Copy requirements and source
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]
Examples: WireViz Web Pros:
- Standard Python environment
- Easy dependency management
- Well-supported by Cloudron Cons:
- System dependencies may vary
- pip install can be slow
4. Django Application Pattern
Use Cases: Django-based web applications Template:
FROM django-image:version
COPY start.sh /app/start.sh
RUN chmod +x /app/start.sh
CMD ["/app/start.sh"]
start.sh Template:
#!/bin/bash
# Wait for PostgreSQL
until psql -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -c '\q'; do
echo "PostgreSQL is unavailable - sleeping"
sleep 2
done
# Run migrations
python manage.py migrate --noinput
# Collect static files
python manage.py collectstatic --noinput
# Start application
gunicorn config.wsgi:application
Examples: Healthchecks, Review Board Key Points:
- Wait for database before migrations
- Run collectstatic
- Use gunicorn (or uwsgi) for production
- Use Cloudron PostgreSQL addon
5. Database Integration Pattern
Use Cases: Applications requiring database Cloudron Addon: PostgreSQL or MySQL Environment Variables:
- CLOUDRON_POSTGRESQL_HOST
- CLOUDRON_POSTGRESQL_PORT
- CLOUDRON_POSTGRESQL_DATABASE
- CLOUDRON_POSTGRESQL_USERNAME
- CLOUDRON_POSTGRESQL_PASSWORD
Pattern:
# In start.sh
DB_HOST=${CLOUDRON_POSTGRESQL_HOST:-127.0.0.1}
DB_PORT=${CLOUDRON_POSTGRESQL_PORT:-5432}
DB_NAME=${CLOUDRON_POSTGRESQL_DATABASE:-app}
DB_USER=${CLOUDRON_POSTGRESQL_USERNAME:-app}
DB_PASSWORD=${CLOUDRON_POSTGRESQL_PASSWORD}
# Wait for database
until psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -c '\q'; do
sleep 2
done
6. Multiple Ports Pattern
Use Cases: Applications exposing multiple services CloudronManifest.json:
{
"tcpPorts": {
"HTTP_PORT": {
"description": "HTTP proxy port",
"defaultValue": 8080
},
"ADMIN_PORT": {
"description": "Admin API port",
"defaultValue": 8081
},
"HTTPS_PORT": {
"description": "HTTPS proxy port",
"defaultValue": 8443
}
}
}
Examples: APISIX (9080, 9180, 9443) Note: Cloudron requires explicit port definitions
7. Health Check Pattern
Use Cases: All applications should have health checks Dockerfile:
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:PORT/ || exit 1
CloudronManifest.json:
{
"healthCheckPath": "/health/"
}
Common Challenges & Solutions
Challenge 1: Permission Denied with chmod in Docker RUN
Error: chmod: changing permissions of '/script.sh': Operation not permitted
Solution: Make script executable on host before COPY
Implementation:
chmod +x start.sh # On host
# In Dockerfile
COPY start.sh /app/start.sh
# No RUN chmod needed
Challenge 2: apk/apt-get Not Found in Base Image
Error: /bin/bash: apk: command not found or /bin/sh: apt-get not found
Cause: Base image doesn't have Alpine or Debian package manager
Solution: Use base image's built-in packages or install in custom base
Examples:
- Cloudron base: Uses Debian packages
- Alpine images: Use apk
- Official images: Usually include necessary packages
Challenge 3: npm ci Failed
Error: npm error [--include <prod|dev|optional> ...]
Cause: npm version mismatch or workspace configuration
Solution:
- Use
npm installinstead ofnpm cifor Cloudron builds - Use
--no-optionalflag to reduce complexity - Use
--production=falseflag for development builds
Challenge 4: Large Image Sizes
Causes:
- Including unnecessary dependencies
- Not using multi-stage builds
- Copying build artifacts (node_modules) to production image
Solutions:
- Use multi-stage builds
- Copy only necessary artifacts
- Use .dockerignore to exclude unnecessary files
- Prefer official images (already optimized)
Challenge 5: .dockerignore Interference
Problem: Repository's .dockerignore interferes with Cloudron package .dockerignore Solution: Create custom .dockerignore in package directory, not from repo Pattern:
# Cloudron package .dockerignore
# Only ignore Cloudron-specific files
.git
.gitignore
README.md
CHANGELOG.md
Dockerfile
Cloudron-Specific Considerations
1. Cloudron Base Image
FROM cloudron/base:3.2.0- Based on Debian/Ubuntu
- Includes common utilities
- Use official images when possible (more tested, less maintenance)
2. Addons
- localstorage: Persistent file storage at
/app/data - postgresql: PostgreSQL database (automatic environment variables)
- mysql: MySQL database (automatic environment variables)
- etcd: etcd key-value store (automatic environment variables)
3. Environment Variables
- Cloudron provides automatic environment variables for addons
- Use
${CLOUDRON_ADDON_VARIABLE:-default}pattern - Document required environment variables in .env.example
4. CloudronManifest.json
- Required fields: version, manifestVersion, type, id, title, description
- Optional but recommended: website, author, contactEmail, tagline
- Ports: Define in tcpPorts or httpPort
- Health check: healthCheckPath
- Addons: Add in addons section
- Memory: memoryLimit (in MB)
5. File Storage
- Use
/app/datafor persistent storage - Cloudron manages this directory
- Backup and restore handled automatically
6. Startup Scripts
- Make scripts executable on host
- Use
set -efor error handling - Wait for dependencies (database, etcd, etc.)
- Run migrations/setup commands before starting application
Productivity Insights
Packaging Speed
- First package (Webhook): ~45 minutes (learning curve)
- Second package (APISIX): ~30 minutes
- Third package (Healthchecks): ~20 minutes
- Fourth package (Review Board): ~25 minutes
- Fifth package (WireViz Web): ~20 minutes
- Sixth package (Puter): ~35 minutes (complex build)
- Average: ~30 minutes per package
- Trend: Improving with experience
Most Time-Consuming Tasks
- Reading documentation and understanding application (10-15 min)
- Writing comprehensive README.md (10-15 min)
- Writing Dockerfile (5-10 min)
- Testing Docker build (10-15 min)
- Creating supporting files (5 min)
Optimizations
- Template reuse: Establish patterns for common application types
- Documentation templates: Create README templates with common sections
- Batch processing: Package similar applications together
- Parallel work: Start next Docker build while committing previous
Next Steps
Immediate Tasks
- Continue packaging remaining applications (53 remaining)
- Prioritize simpler applications to increase throughput
- Focus on categories with official Docker images
- Create packaging templates for common patterns
Future Improvements
- Automated package generation script
- Pre-commit hooks to validate package structure
- Integration testing for each package
- Performance benchmarking of packages
- Security scanning (hadolint, trivy, dockle, dive, syft)
Lessons Learned Summary
- Always read official Docker documentation before creating wrapper
- Make scripts executable on host to avoid permission errors
- Use .dockerignore to reduce build context and image size
- Wait for dependencies (database, services) before starting
- Use environment variable defaults with
${VAR:-default}pattern - Create comprehensive documentation - it saves time later
- Test Docker builds locally before committing
- Commit frequently - atomic commits make troubleshooting easier
- Use multi-stage builds for compiled applications
- Leverage official images when available - less maintenance
- Document ALL environment variables - helps with debugging
- Include examples in README - users appreciate practical guidance
- Handle errors gracefully in start scripts
- Use Cloudron base only when necessary - official images preferred
- Consider memory limits - some applications need more RAM
Repository Statistics
- Commits: 6 packages committed to main branch
- Pushes: All pushed to remote repository
- Package directories: Created in Package-Workspace/
- Total packages completed: 5/58 (8.6%)
- Remaining packages: 53/58 (91.4%)
Journal entries are appended after each package completion.
7. Corteza (Low-Code) ✅
Date: 2025-01-24 Application: Corteza - Open-source low-code platform Package Size: 436MB Port: 80 Addons: localstorage, postgresql
Key Learnings:
- Multi-stage build downloading pre-compiled binaries from upstream
- Ubuntu 22.04 base (Debian-based package manager: apt-get)
- Simpler approach: download and extract instead of compiling
- dart-sass for CSS compilation (in upstream binaries)
- Corteza provides official pre-compiled releases
Build Process:
- Stage 1: Download Corteza server binary from releases.cortezaproject.org
- Stage 1: Download Corteza webapp from releases.cortezaproject.org
- Stage 1: Extract both archives
- Stage 2 (production): Ubuntu 22.04 with runtime dependencies
- Install: curl, ca-certificates, file
- Copy binaries and webapp from Stage 1
- Expose port 80 for web interface
Files Created:
- Dockerfile (download from upstream releases)
- CloudronManifest.json (port 80, postgresql + localstorage addons)
- README.md (comprehensive low-code platform documentation)
- CHANGELOG.md (version tracking)
- .env.example (configuration template)
- logo.png (Corteza branding SVG)
Challenges Encountered:
- No major challenges encountered
- Tar error for webapp extraction didn't prevent image from building
- Simple download-and-extract approach worked well
Commit: feat: add Corteza Cloudron package (Low-Code)
Packaging Pattern: Download Pre-Compiled Binaries
When to Use
- Application provides official pre-compiled binaries/releases
- Compilation is complex or requires many dependencies
- Want to reduce build time and complexity
Template
FROM ubuntu:22.04
# Install runtime dependencies
RUN apt-get update && apt-get install -y curl ca-certificates && rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Download pre-compiled binary
ARG VERSION=1.0.0
ENV APP_PATH=https://releases.example.com/app-${VERSION}-linux-amd64.tar.gz
RUN curl -sL $APP_PATH -o /tmp/app.tar.gz && \
tar zxvf /tmp/app.tar.gz -C /app && \
rm /tmp/app.tar.gz
# Configure and start
COPY config.yaml /app/config/
COPY start.sh /app/start.sh
EXPOSE 8080
CMD ["/app/start.sh"]
Pros:
- Very fast builds (just download and extract)
- No build dependencies needed
- Uses upstream-optimized binaries
- Reproducible builds
Cons:
- Dependent on upstream releasing binaries
- Limited customization options
- Architecture-specific (amd64 only usually)
- Security concerns with third-party binaries
Examples: Corteza