Load ERPNext image internally on Coolify deploy via Skopeo.

Add image-preload init service on Forgejo Docker network, default PULL_POLICY never, and preload host docker after Jenkins push.
This commit is contained in:
epistemophiliac 2026-06-16 20:58:32 -04:00
parent e73912541e
commit 4126cbf737
4 changed files with 78 additions and 22 deletions

View file

@ -4,8 +4,13 @@
# --- Custom image (required — from Jenkins Forgejo registry) ---
CUSTOM_IMAGE=git.aexoradao.com/epistemophiliac/erpnext
CUSTOM_TAG=main-26933f3
# Use if_not_present after scripts/coolify/preload-image.sh on the Coolify host
PULL_POLICY=if_not_present
PULL_POLICY=never
# Forgejo registry read (internal image-preload service — same creds as Jenkins)
REGISTRY_USER=epistemophiliac
REGISTRY_PASSWORD=replace-with-forgejo-token
FORGEJO_HOST=forgejo-vydgeq365afzmxe4s1d75fwv
FORGEJO_NETWORK=vydgeq365afzmxe4s1d75fwv
# --- Secrets (required — change before first deploy) ---
DB_PASSWORD=replace-with-strong-secret

View file

@ -6,21 +6,50 @@
x-customizable-image: &customizable_image
image: ${CUSTOM_IMAGE:-git.aexoradao.com/epistemophiliac/erpnext}:${CUSTOM_TAG:-main}
pull_policy: ${PULL_POLICY:-if_not_present}
pull_policy: ${PULL_POLICY:-never}
restart: ${RESTART_POLICY:-unless-stopped}
x-depends-on-image-preload: &depends_on_image_preload
depends_on:
image-preload:
condition: service_completed_successfully
x-depends-on-configurator: &depends_on_configurator
depends_on:
configurator:
condition: service_completed_successfully
x-backend-defaults: &backend_defaults
<<: [*depends_on_configurator, *customizable_image]
<<: [*depends_on_image_preload, *depends_on_configurator, *customizable_image]
platform: linux/amd64
volumes:
- sites:/home/frappe/frappe-bench/sites
services:
image-preload:
image: quay.io/skopeo/stable:v1.17.0
exclude_from_hc: true
restart: 'no'
networks:
- default
- forgejo-internal
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- 'CUSTOM_IMAGE=${CUSTOM_IMAGE:-git.aexoradao.com/epistemophiliac/erpnext}'
- 'CUSTOM_TAG=${CUSTOM_TAG:-main}'
- 'FORGEJO_HOST=${FORGEJO_HOST:-forgejo-vydgeq365afzmxe4s1d75fwv}'
- 'REGISTRY_USER=${REGISTRY_USER}'
- 'REGISTRY_PASSWORD=${REGISTRY_PASSWORD}'
entrypoint: ['sh', '-c']
command:
- >
if [ -z "$$REGISTRY_USER" ] || [ -z "$$REGISTRY_PASSWORD" ]; then echo "[image-preload] ERROR: set REGISTRY_USER and REGISTRY_PASSWORD in Coolify"; exit 1; fi;
echo "[image-preload] copying from http://$$FORGEJO_HOST:3000/epistemophiliac/erpnext:$$CUSTOM_TAG (internal Forgejo)";
skopeo copy "docker://$$FORGEJO_HOST:3000/epistemophiliac/erpnext:$$CUSTOM_TAG" "docker-daemon:$$CUSTOM_IMAGE:$$CUSTOM_TAG" --src-creds "$$REGISTRY_USER:$$REGISTRY_PASSWORD" --src-tls-verify=false --retry-times 3;
if [ "$$CUSTOM_TAG" != "main" ]; then skopeo copy "docker://$$FORGEJO_HOST:3000/epistemophiliac/erpnext:main" "docker-daemon:$$CUSTOM_IMAGE:main" --src-creds "$$REGISTRY_USER:$$REGISTRY_PASSWORD" --src-tls-verify=false --retry-times 3; fi;
echo "[image-preload] OK: $$CUSTOM_IMAGE:$$CUSTOM_TAG on host docker";
db:
image: mariadb:11.8
restart: unless-stopped
@ -91,7 +120,7 @@ services:
condition: service_healthy
create-site:
<<: *customizable_image
<<: [*depends_on_image_preload, *customizable_image]
exclude_from_hc: true
restart: 'no'
platform: linux/amd64
@ -156,7 +185,7 @@ services:
start_period: 120s
websocket:
<<: [*depends_on_configurator, *customizable_image]
<<: [*depends_on_image_preload, *depends_on_configurator, *customizable_image]
platform: linux/amd64
command:
- node
@ -168,7 +197,7 @@ services:
condition: service_completed_successfully
frontend:
<<: *customizable_image
<<: [*depends_on_image_preload, *customizable_image]
platform: linux/amd64
command:
- nginx-entrypoint.sh
@ -238,3 +267,8 @@ volumes:
sites:
db-data:
redis-queue-data:
networks:
forgejo-internal:
external: true
name: ${FORGEJO_NETWORK:-vydgeq365afzmxe4s1d75fwv}

View file

@ -24,7 +24,9 @@ Copy from [`coolify.env.example`](../coolify.env.example). **Required before fir
|----------|----------------|--------|
| `CUSTOM_IMAGE` | yes | Jenkins artifact / `dist/coolify-image.env` |
| `CUSTOM_TAG` | yes | e.g. `main-26933f3` (pin) or `main` |
| `PULL_POLICY` | yes | `if_not_present` (after host preload; see below) |
| `PULL_POLICY` | yes | `never` (image-preload loads internally) |
| `REGISTRY_USER` | yes | Forgejo username |
| `REGISTRY_PASSWORD` | yes | Forgejo token (package read) |
| `DB_PASSWORD` | yes | strong secret |
| `ADMIN_PASSWORD` | yes | Frappe `Administrator` password |
| `INSTALL_APPS` | yes | `erpnext,payments,hrms,lending,lms` |
@ -45,24 +47,21 @@ Copy from [`coolify.env.example`](../coolify.env.example). **Required before fir
**Order matters:** assign domain **then** deploy. If `create-site` runs with an empty site name, the stack exits with a clear error.
## 4. Preload image on Coolify host (required once per tag)
## 4. Internal image load (automatic)
The custom image is **~1.2 GB**. Coolify deploy can fail with `exit code 255` while pulling large layers through Cloudflare/Traefik (you may see progress stop around ~100 MB).
Compose includes an **`image-preload`** init service (Skopeo → internal Forgejo, same path as Jenkins push). It copies the image into host Docker **before** ERPNext services start — no Cloudflare pull.
**On the Coolify server as root** (SSH or Coolify terminal):
Required Coolify env vars (see [`coolify.env.example`](../coolify.env.example)):
```bash
git clone https://git.aexoradao.com/epistemophiliac/erpnext.git /tmp/erpnext
cd /tmp/erpnext
export REGISTRY_USER=epistemophiliac
export REGISTRY_PASSWORD='<forgejo-token-with-package-read>'
export CUSTOM_TAG=main-26933f3 # from Jenkins dist/coolify-image.env
bash scripts/coolify/preload-image.sh
```env
REGISTRY_USER=epistemophiliac
REGISTRY_PASSWORD=<forgejo-token>
CUSTOM_IMAGE=git.aexoradao.com/epistemophiliac/erpnext
CUSTOM_TAG=main-26933f3
PULL_POLICY=never
```
This copies from internal Forgejo (`forgejo-vydgeq365afzmxe4s1d75fwv:3000`) — same path Jenkins uses for push — and tags `git.aexoradao.com/epistemophiliac/erpnext:<tag>` locally.
Set `PULL_POLICY=if_not_present` in Coolify so redeploys skip the large pull.
Jenkins also preloads the host after each green build, so redeploys are fast.
## 5. First deploy

View file

@ -33,4 +33,22 @@ push_with_skopeo() {
push_with_skopeo "${REGISTRY_IMAGE}:${IMAGE_TAG}"
push_with_skopeo "${REGISTRY_IMAGE}:main"
echo "Pushed via internal Forgejo (public pull: ${REGISTRY_IMAGE}:<tag>)"
preload_host_docker() {
local tag="${1##*:}"
echo "Preloading Coolify host docker: ${REGISTRY_IMAGE}:${tag}"
$DOCKER run --rm \
--network "${FORGEJO_NETWORK}" \
-v /var/run/docker.sock:/var/run/docker.sock \
quay.io/skopeo/stable:v1.17.0 \
copy \
"docker://${FORGEJO_HOST}:3000/epistemophiliac/erpnext:${tag}" \
"docker-daemon:${REGISTRY_IMAGE}:${tag}" \
--src-creds "${REGISTRY_USER}:${REGISTRY_PASSWORD}" \
--src-tls-verify=false \
--retry-times 3
}
preload_host_docker "${REGISTRY_IMAGE}:${IMAGE_TAG}"
preload_host_docker "${REGISTRY_IMAGE}:main"
echo "Pushed via internal Forgejo and preloaded on host docker"