Package or bust!

This commit is contained in:
2025-10-17 15:09:03 -05:00
parent c8c4bd4e9b
commit 1fe434ea3e
20 changed files with 288 additions and 416 deletions

View File

@@ -3,17 +3,17 @@
"id": "io.knel.apisix",
"title": "Apache APISIX",
"author": "KNEL",
"description": "Apache APISIX API Gateway for microservices and API management",
"website": "https://apisix.apache.org",
"contactEmail": "admin@knownelement.com",
"version": "3.8.0",
"changelog": "Initial Cloudron package for Apache APISIX API Gateway",
"healthCheckPath": "/apisix/admin/routes",
"description": "Cloudron packaging template for Apache APISIX",
"website": "https://example.com",
"contactEmail": "admin@example.com",
"version": "0.1.0",
"changelog": "Initial package template",
"healthCheckPath": "/",
"httpPort": 9180,
"addons": {
"localstorage": {}
},
"tags": ["api", "gateway", "microservices", "proxy"],
"tags": ["template", "example"],
"icon": "logo.png"
}

View File

@@ -1,44 +1,38 @@
FROM apache/apisix:3.8.0-debian
FROM cloudron/base:5.0.0
# Metadata labels
# Metadata labels (edit as needed)
LABEL org.opencontainers.image.title="Apache APISIX"
LABEL org.opencontainers.image.description="Cloudron package for Apache APISIX API Gateway"
LABEL org.opencontainers.image.source="https://github.com/apache/apisix"
LABEL org.opencontainers.image.description="Cloudron package for Apache APISIX"
LABEL org.opencontainers.image.source="https://example.com"
# Switch to root to modify the image
USER root
# Install OS dependencies here as needed
# RUN apt-get update && apt-get install -y --no-install-recommends \
# curl ca-certificates tini \
# && rm -rf /var/lib/apt/lists/*
# Install additional dependencies if needed
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# App code lives in /app/code (read-only at runtime)
WORKDIR /app/code
# Create cloudron user
RUN useradd -r -s /bin/bash -d /app -m cloudron
# Copy application code (adjust as needed)
# COPY . /app/code
# Create APISIX data directories
RUN mkdir -p /app/data/apisix && \
mkdir -p /app/data/apisix/logs && \
mkdir -p /app/data/apisix/conf && \
chown -R cloudron:cloudron /app/data
# Create persistent directory for application data
RUN mkdir -p /app/data && chown -R cloudron:cloudron /app/data
# Copy startup script
COPY start.sh /app/pkg/start.sh
RUN chmod +x /app/pkg/start.sh && chown cloudron:cloudron /app/pkg/start.sh
# Switch to cloudron user
USER cloudron
# Expose APISIX ports
EXPOSE 9180 9080
# Expose the app port specified in manifest
EXPOSE 9180
# APISIX environment variables
ENV APISIX_HOME=/app/data/apisix \
APISIX_WORKDIR=/app/data/apisix \
# Default environment (customize per app)
ENV NODE_ENV=production \
APP_PORT=9180
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD curl -fsS http://127.0.0.1:${APP_PORT}/apisix/admin/routes || exit 1
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD curl -fsS http://127.0.0.1:${APP_PORT}/ || exit 1
CMD ["/app/pkg/start.sh"]

View File

@@ -9,15 +9,31 @@ abort() { echo "[start] ERROR: $*" >&2; exit 1; }
log "Starting Apache APISIX on port ${APP_PORT}"
# Ensure APISIX data directory exists
mkdir -p /app/data/apisix
# Example: ensure /app/data exists and is writable
mkdir -p /app/data
chown -R cloudron:cloudron /app/data || true
# Set APISIX environment
export APISIX_HOME=/app/data/apisix
export APISIX_WORKDIR=/app/data/apisix
# Example addon integration (uncomment and adapt as needed)
# if [[ -n "${CLOUDRON_POSTGRESQL_URL:-}" ]]; then
# log "Detected PostgreSQL addon"
# # Use $CLOUDRON_POSTGRESQL_* env vars
# fi
# Start APISIX using the official entrypoint
log "Starting APISIX API Gateway"
exec /docker-entrypoint.sh docker-start
# if [[ -n "${CLOUDRON_REDIS_URL:-}" ]]; then
# log "Detected Redis addon"
# fi
# If your app needs config generation, do it here
# cat > /app/data/config.yaml <<'YAML'
# key: value
# YAML
# Example: start a simple HTTP server (placeholder)
# Replace with your actual app start command
if command -v python3 >/dev/null 2>&1; then
log "Launching placeholder server: python3 -m http.server ${APP_PORT}"
exec python3 -m http.server "${APP_PORT}" --bind 0.0.0.0
else
abort "No application command configured. Replace placeholder with your app's start command."
fi

View File

@@ -3,17 +3,17 @@
"id": "io.knel.jenkins",
"title": "Jenkins CI/CD",
"author": "KNEL",
"description": "Jenkins CI/CD Platform for automated builds, testing, and deployment",
"website": "https://jenkins.io",
"contactEmail": "admin@knownelement.com",
"version": "2.450.0",
"changelog": "Initial Cloudron package for Jenkins CI/CD Platform",
"healthCheckPath": "/login",
"description": "Cloudron packaging template for Jenkins CI/CD",
"website": "https://example.com",
"contactEmail": "admin@example.com",
"version": "0.1.0",
"changelog": "Initial package template",
"healthCheckPath": "/",
"httpPort": 8080,
"addons": {
"localstorage": {}
},
"tags": ["ci", "cd", "automation", "build", "deployment"],
"tags": ["template", "example"],
"icon": "logo.png"
}

View File

@@ -5,7 +5,7 @@ LABEL org.opencontainers.image.title="Jenkins CI/CD"
LABEL org.opencontainers.image.description="Cloudron package for Jenkins CI/CD Platform"
LABEL org.opencontainers.image.source="https://github.com/jenkinsci/jenkins"
# Install Java and Jenkins dependencies
# Install Java and dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
openjdk-17-jdk \
curl \
@@ -23,7 +23,7 @@ RUN mkdir -p /app/data/jenkins_home && \
mkdir -p /app/pkg && \
chown -R cloudron:cloudron /app/data
# Download and install Jenkins WAR file
# Download Jenkins WAR file
ARG JENKINS_VERSION=2.450
RUN cd /tmp && \
curl -fsSL "https://get.jenkins.io/war/${JENKINS_VERSION}/jenkins.war" -o jenkins.war && \
@@ -34,19 +34,25 @@ RUN cd /tmp && \
COPY start.sh /app/pkg/start.sh
COPY CloudronManifest.json /app/pkg/CloudronManifest.json
COPY CloudronManifest.json /CloudronManifest.json
RUN chmod +x /app/pkg/start.sh && chown cloudron:cloudron /app/pkg/start.sh /app/pkg/CloudronManifest.json /CloudronManifest.json
# Set permissions
RUN chmod +x /app/pkg/start.sh && \
chown cloudron:cloudron /app/pkg/start.sh /app/pkg/CloudronManifest.json /CloudronManifest.json
# Switch to cloudron user
USER cloudron
# Expose Jenkins port
# Expose port
EXPOSE 8080
# Jenkins environment variables
# Set environment variables
ENV JENKINS_HOME=/app/data/jenkins_home \
JENKINS_OPTS="--httpPort=8080 --httpListenAddress=0.0.0.0" \
APP_PORT=8080
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -fsS http://127.0.0.1:${APP_PORT}/login || exit 1
CMD curl -fsS http://127.0.0.1:${APP_PORT}/login || exit 1
CMD ["/app/pkg/start.sh"]
# Start Jenkins
CMD ["/app/pkg/start.sh"]

View File

@@ -15,100 +15,8 @@ mkdir -p "${JENKINS_HOME}"
chown -R cloudron:cloudron /app/data || true
# Set Jenkins environment variables
export JENKINS_HOME="${JENKINS_HOME}"
export JENKINS_HOME
export JENKINS_OPTS="--httpPort=${APP_PORT} --httpListenAddress=0.0.0.0"
# Configure Jenkins for Cloudron with OIDC support
log "Configuring Jenkins for Cloudron environment with OIDC authentication"
# Create basic Jenkins configuration if not exists
if [[ ! -f "${JENKINS_HOME}/config.xml" ]]; then
log "Creating initial Jenkins configuration with OIDC support"
mkdir -p "${JENKINS_HOME}"
# Create OIDC configuration if environment variables are provided
if [[ -n "${CLOUDRON_OIDC_ISSUER_URL:-}" && -n "${CLOUDRON_OIDC_CLIENT_ID:-}" ]]; then
log "Configuring OIDC authentication for Jenkins"
mkdir -p "${JENKINS_HOME}/org.jenkinsci.plugins.openid_connect"
# Create OIDC security realm configuration
cat > "${JENKINS_HOME}/org.jenkinsci.plugins.openid_connect.OpenIdConnectSecurityRealm.xml" <<'OIDC_XML'
<?xml version='1.1' encoding='UTF-8'?>
<org.jenkinsci.plugins.openid_connect.OpenIdConnectSecurityRealm plugin="openid-connect@2.4">
<issuer>${CLOUDRON_OIDC_ISSUER_URL}</issuer>
<clientId>${CLOUDRON_OIDC_CLIENT_ID}</clientId>
<clientSecret>${CLOUDRON_OIDC_CLIENT_SECRET}</clientSecret>
<scopes>openid,email,profile</scopes>
<usernameField>preferred_username</usernameField>
<fullNameField>name</fullNameField>
<emailField>email</emailField>
<disableSslVerification>false</disableSslVerification>
<logoutFromOpenidProvider>true</logoutFromOpenidProvider>
<postLogoutRedirectUrl>${CLOUDRON_OIDC_REDIRECT_URI}</postLogoutRedirectUrl>
<escapeHatchEnabled>false</escapeHatchEnabled>
<escapeHatchUsername>admin</escapeHatchUsername>
<escapeHatchSecret>jenkins-escape-hatch</escapeHatchSecret>
<escapeHatchGroup>admin</escapeHatchGroup>
<automanualconfigure>false</automanualconfigure>
<wellKnownOpenIDConfigurationUrl></wellKnownOpenIDConfigurationUrl>
<readTimeout>20</readTimeout>
<connectTimeout>10</connectTimeout>
<tokenServerUrl></tokenServerUrl>
<authorizationServerUrl></authorizationServerUrl>
<userInfoServerUrl></userInfoServerUrl>
<userNameField></userNameField>
<tokenFieldToCheckKey></tokenFieldToCheckKey>
<tokenFieldToCheckValue></tokenFieldToCheckValue>
</org.jenkinsci.plugins.openid_connect.OpenIdConnectSecurityRealm>
OIDC_XML
fi
# Create basic config.xml for Jenkins
cat > "${JENKINS_HOME}/config.xml" <<'XML'
<?xml version='1.1' encoding='UTF-8'?>
<hudson>
<version>2.450</version>
<numExecutors>2</numExecutors>
<mode>NORMAL</mode>
<useSecurity>true</useSecurity>
<authorizationStrategy class="hudson.security.FullControlOnceLoggedInAuthorizationStrategy"/>
<securityRealm class="hudson.security.HudsonPrivateSecurityRealm">
<disableSignup>true</disableSignup>
</securityRealm>
<disableRememberMe>false</disableRememberMe>
<projectNamingStrategy class="jenkins.model.ProjectNamingStrategy$DefaultProjectNamingStrategy"/>
<workspaceDir>${JENKINS_HOME}/workspace/${ITEM_FULLNAME}</workspaceDir>
<buildsDir>${JENKINS_HOME}/builds/${ITEM_FULLNAME}</buildsDir>
<markupFormatter class="hudson.markup.RawHtmlMarkupFormatter" plugin="antisamy-markup-formatter@3.1"/>
<jdks/>
<viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
<myViewsTabBar class="hudson.views.DefaultMyViewsTabBar"/>
<clouds/>
<slaves/>
<scm class="hudson.scm.NullSCM"/>
<views>
<hudson.model.AllView>
<owner class="hudson" reference="../../.."/>
<name>all</name>
<filterExecutors>false</filterExecutors>
<filterQueue>false</filterQueue>
<properties class="hudson.model.View$PropertyList"/>
</hudson.model.AllView>
</views>
<primaryView>all</primaryView>
<slaveAgentPort>50000</slaveAgentPort>
<disabledAgentProtocols>
<string>JNLP-connect</string>
<string>JNLP2-connect</string>
</disabledAgentProtocols>
<label></label>
<nodeProperties/>
<globalNodeProperties/>
</hudson>
XML
fi
# Start Jenkins
log "Starting Jenkins WAR file"
exec java -jar /app/pkg/jenkins.war ${JENKINS_OPTS}
exec java -jar /app/pkg/jenkins.war

View File

@@ -5,20 +5,21 @@ ARG ARCH=x86_64-unknown-linux-gnu
USER root
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl ca-certificates unzip python3 \
&& apt-get install -y --no-install-recommends curl ca-certificates tar python3 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app/pkg
# Download Rathole release binary (adjust version/arch via build args)
RUN set -eux; \
url="https://github.com/rathole-org/rathole/releases/download/${RATHOLE_VERSION}/rathole-${ARCH}.zip"; \
url="https://github.com/rathole-org/rathole/releases/download/${RATHOLE_VERSION}/rathole-${ARCH}.tar.gz"; \
echo "Fetching ${url}"; \
curl -fsSL "$url" -o rathole.zip; \
unzip rathole.zip; \
rm rathole.zip; \
chmod +x rathole; \
chown cloudron:cloudron rathole
curl -fsSL "$url" -o rathole.tar.gz; \
tar -xzf rathole.tar.gz; \
rm rathole.tar.gz; \
mv rathole /app/pkg/rathole; \
chmod +x /app/pkg/rathole; \
chown cloudron:cloudron /app/pkg/rathole
# Start script
COPY start.sh /app/pkg/start.sh

View File

@@ -0,0 +1,11 @@
# Ignore typical build context clutter
.git
.gitignore
node_modules
npm-debug.log
*.log
dist
build
Dockerfile.*
.DS_Store

View File

@@ -0,0 +1,19 @@
{
"manifestVersion": 2,
"id": "io.knel.rundeck",
"title": "Rundeck Job Scheduler",
"author": "KNEL",
"description": "Cloudron packaging template for Rundeck Job Scheduler",
"website": "https://example.com",
"contactEmail": "admin@example.com",
"version": "0.1.0",
"changelog": "Initial package template",
"healthCheckPath": "/",
"httpPort": 4440,
"addons": {
"localstorage": {}
},
"tags": ["template", "example"],
"icon": "logo.png"
}

View File

@@ -0,0 +1,38 @@
FROM cloudron/base:5.0.0
# Metadata labels (edit as needed)
LABEL org.opencontainers.image.title="Rundeck Job Scheduler"
LABEL org.opencontainers.image.description="Cloudron package for Rundeck Job Scheduler"
LABEL org.opencontainers.image.source="https://example.com"
# Install OS dependencies here as needed
# RUN apt-get update && apt-get install -y --no-install-recommends \
# curl ca-certificates tini \
# && rm -rf /var/lib/apt/lists/*
# App code lives in /app/code (read-only at runtime)
WORKDIR /app/code
# Copy application code (adjust as needed)
# COPY . /app/code
# Create persistent directory for application data
RUN mkdir -p /app/data && chown -R cloudron:cloudron /app/data
# Copy startup script
COPY start.sh /app/pkg/start.sh
RUN chmod +x /app/pkg/start.sh && chown cloudron:cloudron /app/pkg/start.sh
USER cloudron
# Expose the app port specified in manifest
EXPOSE 4440
# Default environment (customize per app)
ENV NODE_ENV=production \
APP_PORT=4440
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD curl -fsS http://127.0.0.1:${APP_PORT}/ || exit 1
CMD ["/app/pkg/start.sh"]

View File

@@ -0,0 +1,33 @@
# Package Template for Cloudron Apps
This is a minimal template to package an application for Cloudron.
## Docker Artifact Naming Convention
All KNEL Cloudron packages follow the `KNELCloudron-` prefix convention:
- **Development Images**: `<appname>:dev` (built locally for testing)
- **Production Images**: `<appname>:latest` (final packaged versions)
- **Container Names**: Use descriptive names like `<appname>-dev` for development containers
## Template Usage
Replace placeholders in files with your app specifics:
- `io.knel.rundeck` (e.g., com.example.myapp)
- `Rundeck Job Scheduler` (human name)
- `4440` (default internal app port)
- `5.0.0` (Cloudron base image tag, e.g., 5.0.0)
Files
- `CloudronManifest.json` base manifest
- `Dockerfile` uses cloudron/base, non-root user, healthcheck
- `start.sh` startup script with addon detection examples
- `nginx.conf` (optional) example reverse proxy
- `supervisord.conf` (optional) process manager example
- `config.yaml` (optional) sample app config
- `logo.png` add your 512x512 PNG icon here (not provided in template)
Usage
1. Create a new package from this template using `scripts/new-package.sh`:
`scripts/new-package.sh MyApp --id com.example.myapp --title "My App" --port 3000`
2. Adjust Dockerfile and start.sh to run your app.
3. Build and test locally; then commit and push.

View File

@@ -0,0 +1,11 @@
# Example configuration template for Rundeck Job Scheduler
server:
port: 4440
data:
dir: /app/data
database:
# url: ${CLOUDRON_POSTGRESQL_URL}
# redis: ${CLOUDRON_REDIS_URL}

View File

@@ -0,0 +1,26 @@
user cloudron;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
events { worker_connections 1024; }
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log main;
sendfile on;
server {
listen 4440;
server_name _;
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:4440;
}
}
}

View File

@@ -0,0 +1,39 @@
#!/usr/bin/env bash
set -euo pipefail
log() { echo "[start] $(date -Is) $*"; }
abort() { echo "[start] ERROR: $*" >&2; exit 1; }
# Defaults
: "${APP_PORT:=4440}"
log "Starting Rundeck Job Scheduler on port ${APP_PORT}"
# Example: ensure /app/data exists and is writable
mkdir -p /app/data
chown -R cloudron:cloudron /app/data || true
# Example addon integration (uncomment and adapt as needed)
# if [[ -n "${CLOUDRON_POSTGRESQL_URL:-}" ]]; then
# log "Detected PostgreSQL addon"
# # Use $CLOUDRON_POSTGRESQL_* env vars
# fi
# if [[ -n "${CLOUDRON_REDIS_URL:-}" ]]; then
# log "Detected Redis addon"
# fi
# If your app needs config generation, do it here
# cat > /app/data/config.yaml <<'YAML'
# key: value
# YAML
# Example: start a simple HTTP server (placeholder)
# Replace with your actual app start command
if command -v python3 >/dev/null 2>&1; then
log "Launching placeholder server: python3 -m http.server ${APP_PORT}"
exec python3 -m http.server "${APP_PORT}" --bind 0.0.0.0
else
abort "No application command configured. Replace placeholder with your app's start command."
fi

View File

@@ -0,0 +1,12 @@
[supervisord]
logfile=/var/log/supervisor/supervisord.log
pidfile=/run/supervisord.pid
nodaemon=true
[program:app]
command=/app/pkg/start.sh
autorestart=true
stdout_logfile=/var/log/supervisor/app.stdout.log
stderr_logfile=/var/log/supervisor/app.stderr.log
user=cloudron