mirror of
https://github.com/dockersrc/android
synced 2026-09-18 01:55:59 -04:00
📝 Update project spec and documentation 📝
- AI.md - LICENSE.md - README.md
This commit is contained in:
@@ -0,0 +1,785 @@
|
||||
# CasjaysDev Docker Base Image Specification (dockersrc)
|
||||
|
||||
**Name**: {name}
|
||||
|
||||
**About this file:** This is the complete, authoritative specification for a CasjaysDev
|
||||
Docker **base image** repository (`dockersrc/{name}`). It is a master template — copied
|
||||
into a base image repo as that repo's `AI.md`. It is **permanent** — never delete it from
|
||||
a repo that carries it.
|
||||
|
||||
**Note:** `{name}` in this file is a reference token, not setup-time replacement text. Its
|
||||
value is always the repo directory basename (`basename "$PWD"`).
|
||||
|
||||
**Maintenance procedure:** The bootstrap/update runbook (regenerating files after upstream
|
||||
template changes, creating new repos) is NOT in this file — it lives in the
|
||||
`dockersrc-bootstrap` agent. This file defines the standards that procedure enforces.
|
||||
|
||||
---
|
||||
|
||||
# PART INDEX
|
||||
|
||||
| PART | Title |
|
||||
|------|-------|
|
||||
| 0 | Critical rules |
|
||||
| 1 | Repository model & structure |
|
||||
| 2 | Template system reference |
|
||||
| 3 | Tooling — gen-dockerfile & gen-script |
|
||||
| 4 | `.env.scripts` reference |
|
||||
| 5 | Runtime system — setup scripts, entrypoint, init.d |
|
||||
| 6 | README.md standard layout |
|
||||
| 7 | CI/CD workflows |
|
||||
| 8 | Verification & commit |
|
||||
| 9 | Examples from real repos |
|
||||
|
||||
---
|
||||
|
||||
# PART 0: CRITICAL RULES
|
||||
|
||||
## Org mapping
|
||||
|
||||
| System | Org | Example |
|
||||
|--------|-----|---------|
|
||||
| GitHub (source) | `dockersrc` | `https://github.com/dockersrc/{name}` |
|
||||
| Docker Hub (push) | `casjaysdev` | `casjaysdev/{name}` |
|
||||
|
||||
`dockersrc` repos are **OS bases and toolchains** (alpine, debian, ubuntu, almalinux,
|
||||
archlinux, web, xorg, go, rust, android). Application images live in the separate
|
||||
`casjaysdevdocker` org and pull FROM these images — see the apps specification
|
||||
(`CASJAYSDEVDOCKER.md`).
|
||||
|
||||
The Docker Hub push org is always `casjaysdev` regardless of where the repo is checked out.
|
||||
|
||||
## Non-negotiable rules
|
||||
|
||||
1. **`AI.md` is permanent** — never delete it from the repo.
|
||||
2. **Generated files are owned by the template system** — never hand-tune content that
|
||||
`gen-dockerfile` regenerates (see PART 1 ownership table); fix the upstream
|
||||
`gen-dockerfile` template instead, then regenerate.
|
||||
3. **Hand-crafted files are owned by the repo** — `gen-dockerfile` must never overwrite
|
||||
app-specific init.d scripts, custom bin scripts, or a `05-custom.sh` with real content.
|
||||
4. **Removed OCI labels stay removed** (PART 2) — never re-add `base.name`,
|
||||
`schema-version`, or duplicate `authors`/`source` entries.
|
||||
5. **`image.url` is a browsable page** — `https://hub.docker.com/r/casjaysdev/{name}`.
|
||||
`docker.io` is only a registry pull host; it is never a label URL.
|
||||
6. **`image.source` and `image.documentation` are the GitHub repo** —
|
||||
`https://github.com/dockersrc/{name}`.
|
||||
7. **One variant, one file set** — every published version tag has its own
|
||||
`Dockerfile.{ver}`, `.env.scripts.{ver}`, and `.gitea/workflows/build.{ver}.yml`.
|
||||
8. **Only `root/`, `tmp/`, and `usr/` may exist at `rootfs/` top level** (PART 1).
|
||||
9. **Maintenance runs through the `dockersrc-bootstrap` agent** — do not improvise the
|
||||
update procedure from memory.
|
||||
|
||||
---
|
||||
|
||||
# PART 1: REPOSITORY MODEL & STRUCTURE
|
||||
|
||||
## What a base image repo is
|
||||
|
||||
A `dockersrc/{name}` repo builds one image family from upstream official distro images
|
||||
(never from `casjaysdev/*` — base repos ARE the `casjaysdev/*` images). OS repos publish
|
||||
one variant per supported release; toolchain repos (go, rust, android) publish `latest`
|
||||
plus whatever the toolchain needs.
|
||||
|
||||
## Standard tree
|
||||
|
||||
```
|
||||
{name}/
|
||||
├── AI.md # This specification (permanent)
|
||||
├── Dockerfile # [generated] latest/default variant
|
||||
├── Dockerfile.{ver} # [generated] one per version variant (OS repos)
|
||||
├── .dockerignore # [generated]
|
||||
├── .env.scripts # [generated] build config for the default variant
|
||||
├── .env.scripts.{ver} # [generated] one per version variant
|
||||
├── .gitattributes # [generated]
|
||||
├── .gitea/workflows/
|
||||
│ ├── build.yml # [generated] gen-dockerfile actions — default variant
|
||||
│ └── build.{ver}.yml # [generated] one per version variant
|
||||
├── .gitignore # [generated]
|
||||
├── LICENSE.md # License (WTFPL)
|
||||
├── README.md # [generated] standard layout (PART 6)
|
||||
└── rootfs/ # Container filesystem overlay
|
||||
├── root/docker/setup/ # [generated*] build-time setup scripts 00–07
|
||||
├── tmp/ # staged files installed at build time (optional)
|
||||
└── usr/local/
|
||||
├── bin/ # [generated*] entrypoint.sh, pkmgr, symlink, copy,
|
||||
│ # healthcheck + [hand-crafted] repo-specific scripts
|
||||
└── etc/docker/
|
||||
├── env/ # [hand-crafted] build/runtime env fragments (optional)
|
||||
├── functions/
|
||||
│ └── entrypoint.sh # [generated] entrypoint function library
|
||||
└── init.d/ # [hand-crafted] runtime init scripts (one per service)
|
||||
```
|
||||
|
||||
`[generated]` — safe to regenerate; local edits will be lost.
|
||||
`[generated*]` — regenerated from the template, EXCEPT files carrying repo-specific
|
||||
content (`05-custom.sh` with a real body, extra bin scripts) — those follow the
|
||||
hand-crafted rules in PART 5.
|
||||
`[hand-crafted]` — never overwritten by the template system.
|
||||
|
||||
## rootfs top-level policy
|
||||
|
||||
The only valid directories at the `rootfs/` root are `root/`, `tmp/`, and `usr/`.
|
||||
Anything else is a leftover from old patterns. Migration map:
|
||||
|
||||
| Old rootfs path | Correct rootfs path |
|
||||
|-----------------|---------------------|
|
||||
| `rootfs/etc/{path}` | `rootfs/tmp/etc/{path}` |
|
||||
| `rootfs/config/{path}` | `rootfs/tmp/etc/{path}` |
|
||||
| `rootfs/data/{path}` | `rootfs/tmp/var/{path}` |
|
||||
| `rootfs/var/{path}` | `rootfs/tmp/var/{path}` |
|
||||
| `rootfs/opt/{path}` | `rootfs/tmp/opt/{path}` |
|
||||
| `rootfs/share/{path}` | `rootfs/usr/local/share/{path}` |
|
||||
|
||||
`rootfs/usr/local/share/template-files/` is retired — the `DEFAULT_TEMPLATE_DIR`,
|
||||
`DEFAULT_FILE_DIR`, `DEFAULT_DATA_DIR`, and `DEFAULT_CONF_DIR` variables were removed
|
||||
from the template system; the entrypoint installs staged files from `rootfs/tmp/etc/`
|
||||
at container start instead.
|
||||
|
||||
## Variant detection
|
||||
|
||||
A repo is a **base** repo when `Dockerfile.*` variant files exist:
|
||||
|
||||
```bash
|
||||
if find . -maxdepth 1 -name 'Dockerfile.*' -type f | grep -q -- .; then
|
||||
REPO_TYPE="base"
|
||||
else
|
||||
REPO_TYPE="app"
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# PART 2: TEMPLATE SYSTEM REFERENCE
|
||||
|
||||
Templates ship with `gen-dockerfile`, installed at
|
||||
`/usr/local/share/CasjaysDev/scripts/templates/dockerfiles/`
|
||||
(`$CASJAYSDEVDIR/templates/dockerfiles/` in a dev checkout). To inspect what the current
|
||||
templates produce, generate a fresh reference tree in a temp dir:
|
||||
|
||||
```bash
|
||||
gen-dockerfile /tmp/gen-dockerfile/{org}/{repo} {distro}
|
||||
```
|
||||
|
||||
See `gen-dockerfile --help` for supported distros/types. Keep this PART in sync whenever
|
||||
the templates change.
|
||||
|
||||
## Template inventory
|
||||
|
||||
| Template | Final stage | Init / PID 1 | Base OS |
|
||||
|----------|-------------|--------------|---------|
|
||||
| `alpine.template` | `scratch.template` | tini | Alpine |
|
||||
| `debian.template` | `scratch.template` | tini | Debian |
|
||||
| `ubuntu.template` | `scratch.template` | tini | Ubuntu |
|
||||
| `rhel.template` | `scratch.template` | tini | AlmaLinux |
|
||||
| `archlinux.template` | `scratch.template` | tini | Arch Linux (multi-arch note below) |
|
||||
| `web.template` | `systemd.template` | `/sbin/init` | Debian |
|
||||
| `xorg.template` | `systemd.template` | `/sbin/init` | Debian |
|
||||
|
||||
## Final-stage templates
|
||||
|
||||
`scratch.template` — all non-GUI templates.
|
||||
- `ENTRYPOINT [ "tini", "-p", "SIGTERM","--", "/usr/local/bin/entrypoint.sh" ]`
|
||||
- `STOPSIGNAL SIGRTMIN+3`
|
||||
|
||||
`systemd.template` — `web` and `xorg` (systemd is PID 1; tini is redundant).
|
||||
- `ENTRYPOINT [ "/sbin/init" ]`
|
||||
- `STOPSIGNAL SIGRTMIN+3`
|
||||
- No `tini_provider` stage, no `COPY --from=tini_provider` line.
|
||||
|
||||
Both are identical apart from `ENTRYPOINT`. OCI labels, `ENV HOSTNAME`, and
|
||||
`EXPOSE`/`HEALTHCHECK` are the same in both. Neither declares `VOLUME` — `dockersrc`
|
||||
images are toolchain/distro base images, not persistent services, so there is no
|
||||
`/config`/`/data` (or any other) mount point to reserve (see "Volumes" below).
|
||||
|
||||
## OCI label standard
|
||||
|
||||
Both final-stage templates emit these labels (no others):
|
||||
|
||||
```
|
||||
LABEL maintainer="${GEN_DOCKERFILE_MAINTAINER}"
|
||||
LABEL org.opencontainers.image.vendor="${GEN_DOCKERFILE_VENDOR:-CasjaysDev}"
|
||||
LABEL org.opencontainers.image.authors="${GEN_DOCKERFILE_AUTHOR:-CasjaysDev}"
|
||||
LABEL org.opencontainers.image.licenses="${LICENSE}"
|
||||
LABEL org.opencontainers.image.title="${IMAGE_NAME}"
|
||||
LABEL org.opencontainers.image.description="Containerized version of ${IMAGE_NAME}"
|
||||
LABEL org.opencontainers.image.created="${BUILD_DATE}"
|
||||
LABEL org.opencontainers.image.version="${BUILD_VERSION}"
|
||||
LABEL org.opencontainers.image.revision="${GIT_COMMIT}"
|
||||
LABEL org.opencontainers.image.url="${GEN_DOCKERFILE_HUB_REPO}"
|
||||
LABEL org.opencontainers.image.source="${GEN_DOCKERFILE_GIT_REPO}"
|
||||
LABEL org.opencontainers.image.documentation="${GEN_DOCKERFILE_GIT_REPO}"
|
||||
LABEL org.opencontainers.image.vcs-type="Git"
|
||||
LABEL com.github.containers.toolbox="false"
|
||||
```
|
||||
|
||||
Shell-expanded values (no `\`) are evaluated at template-render time by `gen-dockerfile`.
|
||||
Dollar-escaped values (`\${...}`) become literal Docker `ARG`/`ENV` references in the
|
||||
generated `Dockerfile`.
|
||||
|
||||
Resolved values for a `dockersrc` repo pushing to Docker Hub:
|
||||
|
||||
| Label | Value |
|
||||
|-------|-------|
|
||||
| `url` | `https://hub.docker.com/r/casjaysdev/{name}` — browsable Hub page; `gen-dockerfile` derives it from the registry host (`docker.io` → `hub.docker.com/r/`) |
|
||||
| `source` | `https://github.com/dockersrc/{name}` |
|
||||
| `documentation` | `https://github.com/dockersrc/{name}` |
|
||||
|
||||
Removed labels (never re-add):
|
||||
- `org.opencontainers.image.base.name` — belongs on the base image, not this image
|
||||
- `org.opencontainers.image.schema-version` — non-spec; redundant with `version`
|
||||
- Any duplicate `authors` or `source` entries
|
||||
|
||||
## HOSTNAME convention
|
||||
|
||||
All templates set `ENV HOSTNAME="casjaysdevdocker-${IMAGE_NAME}"` in every stage that
|
||||
declares it. The prefix is always `casjaysdevdocker-`, never `casjaysdev-`.
|
||||
|
||||
## `GEN_DOCKERFILE_APP_DIR` and pull URL logic
|
||||
|
||||
`GEN_DOCKERFILE_APP_DIR` is auto-detected by `gen-dockerfile` from the parent directory
|
||||
of `$PWD` (the org the checkout lives in):
|
||||
|
||||
```bash
|
||||
GEN_DOCKERFILE_APP_DIR="${GEN_DOCKERFILE_APP_DIR:-$(basename -- "$(dirname -- "$PWD")")}"
|
||||
```
|
||||
|
||||
It selects the `GEN_DOCKER_SPECIFY_IMAGE_SOURCE_*` defaults:
|
||||
|
||||
- `casjaysdevdocker/*` repos → `FROM casjaysdev/<distro>:latest` (pre-built, multi-arch)
|
||||
- `dockersrc/*` and all other orgs → `FROM <distro>:latest` (upstream official images)
|
||||
|
||||
Base repos always pull upstream — a base image never builds FROM itself. Override by
|
||||
exporting `GEN_DOCKERFILE_APP_DIR` before calling `gen-dockerfile`.
|
||||
|
||||
## Arch Linux multi-arch (`archlinux.template`)
|
||||
|
||||
When building the base image (`GEN_DOCKERFILE_APP_DIR != "casjaysdevdocker"`), the
|
||||
template emits a three-stage FROM for `linux/amd64` + `linux/arm64`:
|
||||
|
||||
```dockerfile
|
||||
ARG TARGETARCH
|
||||
ARG TARGETPLATFORM
|
||||
FROM --platform=${TARGETPLATFORM} archlinux:latest AS base-amd64
|
||||
FROM --platform=${TARGETPLATFORM} lopsided/archlinux-arm64v8:latest AS base-arm64
|
||||
FROM base-${TARGETARCH} AS build
|
||||
```
|
||||
|
||||
App repos pull `casjaysdev/archlinux`, a multi-arch manifest, so a single
|
||||
`FROM ${PULL_URL}:${DISTRO_VERSION} AS build` suffices there.
|
||||
|
||||
## `web.template` packages
|
||||
|
||||
systemd + noVNC stack in the build stage:
|
||||
|
||||
```
|
||||
systemd systemd-sysv dbus dbus-x11 procps
|
||||
tigervnc-standalone-server novnc openbox xdotool
|
||||
```
|
||||
|
||||
Default ports: `SERVICE_PORT="5800"`, `EXPOSE_PORTS="5800 5900"`.
|
||||
|
||||
## `xorg.template` packages
|
||||
|
||||
systemd + Xorg stack in the build stage:
|
||||
|
||||
```
|
||||
systemd systemd-sysv dbus dbus-x11 procps
|
||||
xserver-xorg x11-xserver-utils xinit
|
||||
```
|
||||
|
||||
## `debian.template` / `ubuntu.template` — RUN continuation
|
||||
|
||||
The first `RUN` block must have `; \` after the `echo` line so
|
||||
`export DEBIAN_FRONTEND=noninteractive` executes before `apt-get`:
|
||||
|
||||
```dockerfile
|
||||
RUN set -e; \
|
||||
echo "Updating the system"; \
|
||||
export DEBIAN_FRONTEND=noninteractive; \
|
||||
apt-get update && apt-get upgrade -yy && apt-get dist-upgrade -yy
|
||||
```
|
||||
|
||||
Without the `; \` the export is a no-op and `apt-get` may prompt interactively.
|
||||
|
||||
## Template resolution order
|
||||
|
||||
1. `$GEN_DOCKERFILE_CONFIG_DIR/templates/<name>.template` (user override)
|
||||
2. `/usr/local/share/CasjaysDev/scripts/templates/dockerfiles/<name>.template`
|
||||
(installed; `$CASJAYSDEVDIR/templates/dockerfiles/` in a dev checkout)
|
||||
|
||||
`template_options.source` is sourced after `__set_variables`, allowing template-specific
|
||||
variable overrides.
|
||||
|
||||
---
|
||||
|
||||
# PART 3: TOOLING — gen-dockerfile & gen-script
|
||||
|
||||
## `gen-dockerfile`
|
||||
|
||||
```
|
||||
Usage: gen-dockerfile [options] [dir] [template] [repo-name] [git-repo-url]
|
||||
```
|
||||
|
||||
| Flag | Meaning |
|
||||
|------|---------|
|
||||
| `--update` | Rewrite `.env.scripts` (add/drop vars against the current template) and update ARG/LABEL lines in every `Dockerfile`/`Dockerfile.*`. Touches no other file. |
|
||||
| `--nogit` | Do not init or commit a git repo — required inside an existing repo. |
|
||||
| `--dir PATH` | Operate on / write output to PATH instead of `$PWD`. |
|
||||
| `--template NAME` | Template to use (`alpine`, `debian`, `ubuntu`, `rhel`, `archlinux`, `scratch`, `web`, `xorg`). Defaults to `alpine`. |
|
||||
| `--repo NAME` | Registry repo name (image basename). Defaults to the directory name. |
|
||||
| `--org NAME` | Registry owner / GitHub org (`--user` is an alias). Prefix `git:` or `reg:` to scope to one system; bare value sets both. |
|
||||
| `--registry URL` | Registry provider URL (e.g. `https://docker.io`). |
|
||||
| `--tag VERSION` | Image version tag (default `latest`). |
|
||||
| `--add-tags TAGS` | Comma-separated additional tags (`USE_DATE` = auto date tag). |
|
||||
| `--distro-name IMG` | Base image pull URL (overrides `ENV_PULL_URL`). |
|
||||
| `--distro-version T` | Base image tag (overrides `ENV_DISTRO_TAG`). |
|
||||
| `--startup FILE` | Generate an init.d service script at `rootfs/usr/local/etc/docker/init.d/FILE` via `gen-script other/start-service`. |
|
||||
| `--dockerfile` | Regenerate the Dockerfile only. |
|
||||
| `--force` | Overwrite existing files without prompting. |
|
||||
|
||||
Resolution order when a value is not given by a flag: flags → git remote → project dirs →
|
||||
defaults.
|
||||
|
||||
Special subcommand — `gen-dockerfile actions` writes `.gitea/workflows/build.yml`
|
||||
(`build.{ver}.yml` for versioned tags) from the existing `Dockerfile` (PART 7).
|
||||
|
||||
Base repos update `Dockerfile` AND every `Dockerfile.*` variant on `--update`; the
|
||||
matching `.env.scripts.{ver}` files carry per-variant values.
|
||||
|
||||
## `gen-script`
|
||||
|
||||
```
|
||||
Usage: gen-script [options] [template] [filename]
|
||||
```
|
||||
|
||||
| Flag / env var | Meaning |
|
||||
|----------------|---------|
|
||||
| `--dir PATH` | Write the generated file to `PATH/filename`. |
|
||||
| `-n` / `--name VALUE` | Service name substituted into the template — fills `REPLACE_SERVICE_NAME` in `other/start-service`, pre-populating `SERVICE_NAME=` without a sed step. |
|
||||
| `GEN_SCRIPT_OVERWRITE="Y"` | Overwrite the output without prompting (default `"A"` = ask). Required when the target exists, even with `GEN_SCRIPT_EDITFILE="N"`. |
|
||||
| `GEN_SCRIPT_EDITFILE="N"` | Suppress the interactive editor after generation. `-e`/`--no` sets BOTH this AND `GEN_SCRIPT_OVERWRITE="Y"`; the env var alone does not. |
|
||||
| `other/start-service` | Template path — positional arg 1, slash-joined words, matching the `@@Template` header. |
|
||||
| `filename` | Output basename — positional arg 2, combined with `--dir`. |
|
||||
|
||||
Other flags: `-k`/`--keep` (never overwrite), `--replace` (new header replaces old),
|
||||
`-d`/`--desc` (header description), `-p`/`--prev` (copy header metadata from a file).
|
||||
|
||||
---
|
||||
|
||||
# PART 4: `.env.scripts` REFERENCE
|
||||
|
||||
Generated at the repo root; sourced by `gen-dockerfile` and by CI at build time. Base
|
||||
repos carry one per variant (`.env.scripts` + `.env.scripts.{ver}`). It is a pure
|
||||
`KEY="value"` file — no logic.
|
||||
|
||||
## Variables
|
||||
|
||||
| Variable | Purpose |
|
||||
|----------|---------|
|
||||
| `ENV_DOCKERFILE` | Dockerfile the variant builds (`Dockerfile` or `Dockerfile.{ver}`) |
|
||||
| `ENV_REGISTRY_REPO` | Image name in the registry (`{name}`) |
|
||||
| `ENV_REGISTRY_ORG` | Registry namespace — `casjaysdev` for base repos |
|
||||
| `ENV_REGISTRY_URL` | Registry base URL (`https://docker.io`) — pull/push host, never a label URL |
|
||||
| `ENV_REGISTRY_PUSH` | Full push path `org/repo` (`casjaysdev/{name}`) |
|
||||
| `ENV_ADD_IMAGE_PUSH` | Extra push destinations |
|
||||
| `ENV_GIT_REPO_URL` | Full Git repo URL — `https://github.com/dockersrc/{name}`; feeds the `source`/`documentation` labels, so a wrong value here regresses labels on regeneration |
|
||||
| `ENV_USE_TEMPLATE` | Template name (`alpine`, `debian`, …) |
|
||||
| `ENV_PULL_URL` | Base image to pull FROM |
|
||||
| `ENV_DISTRO_TAG` | Tag for the pull image |
|
||||
| `ENV_IMAGE_TAG` | Default image tag (`latest`, or the variant version) |
|
||||
| `ENV_ADD_TAGS` | Additional comma-separated tags; `USE_DATE` auto-generates a date tag |
|
||||
| `ENV_PACKAGES` | Space-separated package list |
|
||||
| `ENV_VENDOR` / `ENV_AUTHOR` / `ENV_MAINTAINER` | Label metadata |
|
||||
| `SERVICE_PORT` | Primary exposed port (empty for pure base images) |
|
||||
| `EXPOSE_PORTS` | Additional exposed ports |
|
||||
| `LANG_VERSION` | Language runtime version (toolchain repos) |
|
||||
| `PHP_VERSION` / `NODE_VERSION` / `NODE_MANAGER` | Runtime versions (`system` default) |
|
||||
| `WWW_ROOT_DIR` | Web root (`/usr/local/share/httpd/default`) |
|
||||
| `DOCKER_ENTYPOINT_PORTS_WEB` / `DOCKER_ENTYPOINT_PORTS_SRV` | Ports passed to the entrypoint |
|
||||
| `DOCKER_ENTYPOINT_HEALTH_APPS` / `DOCKER_ENTYPOINT_HEALTH_ENDPOINTS` | Healthcheck targets |
|
||||
|
||||
## Legacy variable auto-migration
|
||||
|
||||
`gen-dockerfile` calls `__migrate_env_script` on every run, renaming old variables:
|
||||
|
||||
| Old name | Current name |
|
||||
|----------|-------------|
|
||||
| `ENV_IMAGE_NAME` | `ENV_REGISTRY_REPO` |
|
||||
| `ENV_IMAGE_PUSH` | `ENV_REGISTRY_PUSH` |
|
||||
| `ENV_HUB_BASE` | `ENV_REGISTRY_URL` |
|
||||
| `ENV_ORG_NAME` | `ENV_REGISTRY_ORG` |
|
||||
|
||||
Never use the old names in new files. Retired variables that must not reappear anywhere:
|
||||
`DEFAULT_TEMPLATE_DIR`, `DEFAULT_FILE_DIR`, `DEFAULT_DATA_DIR`, `DEFAULT_CONF_DIR`.
|
||||
|
||||
---
|
||||
|
||||
# PART 5: RUNTIME SYSTEM — SETUP SCRIPTS, ENTRYPOINT, INIT.D
|
||||
|
||||
## Build-time setup scripts (`rootfs/root/docker/setup/`)
|
||||
|
||||
Run in order inside the build stage:
|
||||
|
||||
| Script | Role |
|
||||
|--------|------|
|
||||
| `00-init.sh` | Initialize base directory structure and environment |
|
||||
| `01-system.sh` | Repos, locales, timezone, system settings |
|
||||
| `02-packages.sh` | App-specific packages, package managers, language runtimes |
|
||||
| `03-files.sh` | Install staged files (`rootfs/tmp/etc/*` → `/etc/*`), permissions, symlinks |
|
||||
| `04-users.sh` | Create service users/groups |
|
||||
| `05-custom.sh` | Application/toolchain-specific install logic |
|
||||
| `06-post.sh` | Post-install configuration |
|
||||
| `07-cleanup.sh` | Remove build deps, caches, temp files |
|
||||
|
||||
**`05-custom.sh` ownership:** the upstream template ships an empty stub. Any repo whose
|
||||
`05-custom.sh` has a real body (e.g. a toolchain repo's install logic) owns that content —
|
||||
it exists only in the repo's git history, never in the template. On regeneration, keep the
|
||||
existing body and pull forward only boilerplate (version-stamp header, `set` line,
|
||||
shellcheck-disable line). The same rule applies to any other `0*.sh` found to contain real
|
||||
logic beyond the stub.
|
||||
|
||||
## Entrypoint flow
|
||||
|
||||
```
|
||||
tini → /usr/local/bin/entrypoint.sh
|
||||
├─ Load /usr/local/etc/docker/functions/entrypoint.sh
|
||||
├─ Source env: /root/env.sh, /usr/local/etc/docker/env/*.sh, /config/env/*.sh
|
||||
├─ Seed /config and /data on first run
|
||||
├─ __start_init_scripts — source every init.d/*.sh in sort order
|
||||
├─ Handle `healthcheck` command
|
||||
└─ Execute main application
|
||||
```
|
||||
|
||||
`rootfs/usr/local/bin/` generated set: `entrypoint.sh`, `pkmgr`, `symlink`, `copy`,
|
||||
`healthcheck`. `pkmgr` wraps the native package manager (`apk`, `apt-get`, `dnf`,
|
||||
`pacman`) behind `pkmgr update|install|remove|clean`.
|
||||
|
||||
## App-specific bin scripts
|
||||
|
||||
Extra scripts in `rootfs/usr/local/bin/` that `gen-dockerfile` does not generate are
|
||||
repo-owned. Their `@@Template` header governs maintenance:
|
||||
|
||||
- `@@Template : shell/sh` — boilerplate synced from `$TEMPLATE_DIR/scripts/shell/sh`;
|
||||
`#!/usr/bin/env sh`, `set -e` only (`pipefail` is a bashism — must NOT appear)
|
||||
- `@@Template : shell/bash` — synced from `shell/bash`; `set -eo pipefail` required
|
||||
- No `@@Template` header — hand-written; never modified by tooling
|
||||
|
||||
## init.d scripts — critical rules
|
||||
|
||||
**Each service gets its own numbered init.d script. Never merge or remove services.**
|
||||
`__start_init_scripts` sources every `*.sh` in sort order — multi-process repos have one
|
||||
script per daemon (`01-named.sh`, `02-nginx.sh`, `03-php-fpm.sh`, …).
|
||||
|
||||
init.d scripts are **regenerated, never patched in place** — old copies may call functions
|
||||
removed from the current `functions/entrypoint.sh`. Generate fresh via
|
||||
`gen-script other/start-service` (or `gen-dockerfile --startup`), then restore the
|
||||
app-specific values. They are `#!/usr/bin/env bash` with `set -eo pipefail`.
|
||||
|
||||
Required variables in every init.d script:
|
||||
|
||||
```bash
|
||||
SERVICE_NAME="myapp"
|
||||
EXEC_CMD_BIN='myapp'
|
||||
EXEC_CMD_ARGS=''
|
||||
EXEC_PRE_SCRIPT=''
|
||||
SERVICE_USES_PID=''
|
||||
IS_WEB_SERVER="no"
|
||||
IS_DATABASE_SERVICE="no"
|
||||
USES_DATABASE_SERVICE="no"
|
||||
DATABASE_SERVICE_TYPE="sqlite"
|
||||
RUNAS_USER="root"
|
||||
```
|
||||
|
||||
Directory variables:
|
||||
|
||||
```bash
|
||||
DATA_DIR="/data/$SERVICE_NAME"
|
||||
CONF_DIR="/config/$SERVICE_NAME"
|
||||
ETC_DIR="/etc/$SERVICE_NAME"
|
||||
LOG_DIR="/data/logs/$SERVICE_NAME"
|
||||
TMP_DIR="/tmp/$SERVICE_NAME"
|
||||
RUN_DIR="/run/$SERVICE_NAME"
|
||||
ROOT_FILE_PREFIX="/config/secure/auth/root"
|
||||
USER_FILE_PREFIX="/config/secure/auth/user"
|
||||
```
|
||||
|
||||
## Hook functions
|
||||
|
||||
The `start-service` template generates all outer hooks fully implemented — customise via
|
||||
the matching `*_local()` stub, which each outer hook calls automatically if defined:
|
||||
|
||||
| Outer hook (do not redefine) | Customise via |
|
||||
|------------------------------|---------------|
|
||||
| `__run_precopy` | `__run_precopy_local` |
|
||||
| `__execute_prerun` | `__execute_prerun_local` |
|
||||
| `__run_pre_execute_checks` | `__run_pre_execute_checks_local` |
|
||||
| `__update_conf_files` | `__update_conf_files_local` |
|
||||
| `__pre_execute` | `__pre_execute_local` |
|
||||
| `__post_execute` | `__post_execute_local` |
|
||||
| `__pre_message` | `__pre_message_local` |
|
||||
| `__update_ssl_conf` | `__update_ssl_conf_local` |
|
||||
| `__create_service_env` | — |
|
||||
| `__run_start_script` | — |
|
||||
| `__run_secure_function` | — |
|
||||
|
||||
## PID sentinel guard
|
||||
|
||||
Every init.d script must guard on exactly this sentinel — leading dot, no underscores in
|
||||
the filename portion; any other form silently skips the guard:
|
||||
|
||||
```bash
|
||||
if [ ! -f "/run/.start_init_scripts.pid" ]; then
|
||||
echo "__start_init_scripts function hasn't been Initialized" >&2
|
||||
SERVICE_IS_RUNNING="no"
|
||||
__script_exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
## Volumes
|
||||
|
||||
`dockersrc/{name}` images never declare `VOLUME` — they are toolchain/distro base
|
||||
images (OS repos, `go`/`rust`/`android` toolchains), not long-running services with
|
||||
state to persist. No Dockerfile in this repo family ships a `VOLUME` instruction,
|
||||
including for directories that look stateful (module caches, package caches,
|
||||
GOPATH-style tool directories) — those are build-time/runtime cache locations
|
||||
owned by the image, not user data. `/config` and `/data` persistent-volume
|
||||
mount points belong to `casjaysdevdocker/{name}` app repos only (see
|
||||
`CASJAYSDEVDOCKER.md` → "Volumes"), which run an actual service `FROM
|
||||
casjaysdev/{name}`.
|
||||
|
||||
---
|
||||
|
||||
# PART 6: README.md STANDARD LAYOUT
|
||||
|
||||
Base image layout (`dockersrc/{name}` → `casjaysdev/{name}`). Substitute `{name}`;
|
||||
this repo family has no `-p` port mappings unless `SERVICE_PORT` is set in
|
||||
`.env.scripts` — omit all port sections when it is empty.
|
||||
|
||||
````markdown
|
||||
## 👋 Welcome to {name} 🚀
|
||||
|
||||
{name} README
|
||||
|
||||
|
||||
## Install my system scripts
|
||||
|
||||
```shell
|
||||
sudo bash -c "$(curl -q -LSsf "https://github.com/systemmgr/installer/raw/main/install.sh")"
|
||||
sudo systemmgr --config && sudo systemmgr install scripts
|
||||
```
|
||||
|
||||
## Automatic install/update
|
||||
|
||||
```shell
|
||||
dockermgr update os {name}
|
||||
```
|
||||
|
||||
## Install and run container
|
||||
|
||||
```shell
|
||||
mkdir -p "/var/lib/srv/root/docker/casjaysdev/{name}/latest"
|
||||
git clone "https://github.com/dockermgr/{name}" "$HOME/.local/share/CasjaysDev/dockermgr/{name}"
|
||||
cp -Rfva "$HOME/.local/share/CasjaysDev/dockermgr/{name}/rootfs/." "/var/lib/srv/root/docker/casjaysdev/{name}/latest/"
|
||||
docker run -d \
|
||||
--restart always \
|
||||
--privileged \
|
||||
--name casjaysdev-{name}-latest \
|
||||
--hostname {name} \
|
||||
-e TZ=${TIMEZONE:-America/New_York} \
|
||||
-v "/var/lib/srv/root/docker/casjaysdev/{name}/latest/data:/data:z" \
|
||||
-v "/var/lib/srv/root/docker/casjaysdev/{name}/latest/config:/config:z" \
|
||||
casjaysdev/{name}:latest
|
||||
```
|
||||
|
||||
## via docker-compose
|
||||
|
||||
```yaml
|
||||
version: "2"
|
||||
services:
|
||||
ProjectName:
|
||||
image: casjaysdev/{name}
|
||||
container_name: casjaysdev-{name}-latest
|
||||
environment:
|
||||
- TZ=America/New_York
|
||||
- HOSTNAME={name}
|
||||
volumes:
|
||||
- "/var/lib/srv/root/docker/casjaysdev/{name}/latest/data:/data:z"
|
||||
- "/var/lib/srv/root/docker/casjaysdev/{name}/latest/config:/config:z"
|
||||
restart: always
|
||||
```
|
||||
|
||||
## Get source files
|
||||
|
||||
```shell
|
||||
dockermgr download src os {name}
|
||||
```
|
||||
|
||||
## Build container
|
||||
|
||||
```shell
|
||||
git clone "https://github.com/dockersrc/{name}" "$HOME/Projects/github/dockersrc/{name}"
|
||||
cd "$HOME/Projects/github/dockersrc/{name}" && buildx all
|
||||
```
|
||||
|
||||
## Authors
|
||||
|
||||
🤖 casjay: [Github](https://github.com/casjay) 🤖
|
||||
⛵ casjaysdev: [Github](https://github.com/dockersrc) [Docker](https://hub.docker.com/u/casjaysdev) ⛵
|
||||
````
|
||||
|
||||
---
|
||||
|
||||
# PART 7: CI/CD WORKFLOWS
|
||||
|
||||
## Generated workflow (`gen-dockerfile actions`)
|
||||
|
||||
`gen-dockerfile actions` writes `.gitea/workflows/build.yml` from the current
|
||||
`Dockerfile`; versioned variants get `build.{ver}.yml` (named `Build and Push {ver}`, no
|
||||
schedule trigger, fixed version tag only). All actions are SHA-pinned — never tag-pinned.
|
||||
|
||||
- **Triggers:** `push` to `main`, monthly schedule, `workflow_dispatch`
|
||||
- **Registry strategy:** always logs in to the Gitea registry via the auto-provided
|
||||
`GITEA_TOKEN`; conditionally logs in to Docker Hub when `vars.DOCKER_USERNAME` is set
|
||||
(`vars.DOCKER_USERNAME` + `secrets.DOCKER_PASSWORD`; `vars.DOCKER_REGISTRY` overrides
|
||||
the registry, `vars.DOCKER_ORG` the namespace)
|
||||
- **Platforms:** `linux/amd64,linux/arm64`
|
||||
- **build-args:** only `BUILD_DATE`, `GIT_COMMIT`, `BUILD_VERSION`
|
||||
- **Tags pushed:** date tag (`yymm`) + `latest` (or the fixed variant version) to both
|
||||
registries
|
||||
- **Annotations:** mirror the OCI label standard (PART 2), with `url`/`source`/
|
||||
`documentation` set to the workflow's repository URL
|
||||
|
||||
## Legacy workflow (`docker.yaml`)
|
||||
|
||||
A hand-crafted `.gitea/workflows/docker.yaml` may exist in older repos — reference copy in
|
||||
the org-level `.github` repo. **Never overwrite it, and never use it as a template for new
|
||||
work** — it uses tag-pinned actions and retired secret names. All new/updated workflows
|
||||
come from `gen-dockerfile actions`.
|
||||
|
||||
---
|
||||
|
||||
# PART 8: VERIFICATION & COMMIT
|
||||
|
||||
## Syntax gates
|
||||
|
||||
Every touched script must pass before commit:
|
||||
|
||||
```bash
|
||||
for f in rootfs/usr/local/bin/*; do
|
||||
[ -f "$f" ] || continue
|
||||
case "$(head -1 "$f")" in
|
||||
*bash*) bash -n "$f" || exit 1 ;;
|
||||
*sh*) sh -n "$f" || exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
bash -n rootfs/usr/local/etc/docker/functions/entrypoint.sh
|
||||
|
||||
for f in rootfs/root/docker/setup/0*.sh rootfs/usr/local/etc/docker/init.d/*.sh; do
|
||||
[ -f "$f" ] || continue
|
||||
bash -n "$f" || exit 1
|
||||
done
|
||||
```
|
||||
|
||||
## Dead-reference gates
|
||||
|
||||
After any regeneration:
|
||||
|
||||
1. No script references an env var removed from `.env.scripts` (diff-driven check).
|
||||
2. No script calls a function absent from both the current
|
||||
`functions/entrypoint.sh` and the script itself.
|
||||
3. No `__copy_templates` calls remain (retired with `DEFAULT_TEMPLATE_DIR`).
|
||||
|
||||
## Commit
|
||||
|
||||
```bash
|
||||
git status --porcelain
|
||||
git diff --stat
|
||||
```
|
||||
|
||||
Write `.git/COMMIT_MESS` from the actual diff — subject ≤64 chars, body as
|
||||
`- path: change` bullets covering every changed file. Then:
|
||||
|
||||
```bash
|
||||
gitcommit --dir "$(git rev-parse --show-toplevel)" all
|
||||
```
|
||||
|
||||
`git commit` / `git push` directly are forbidden. Never commit with a failing syntax
|
||||
gate.
|
||||
|
||||
## Project Memory (.claude/memory/)
|
||||
|
||||
Durable, repo-specific knowledge discovered during work on this image — a template
|
||||
quirk, a base-image gotcha, a decision on why something deviates from the generated
|
||||
default — belongs in `.claude/memory/`, not only in a commit message or chat. Committed
|
||||
to the repo, not gitignored. One markdown file per topic, YAML frontmatter (`name`,
|
||||
`description`, `type: project`), indexed by `.claude/memory/MEMORY.md`, read on demand.
|
||||
Same credential-masking rule as everywhere else — never store secrets. `~/.claude/**`
|
||||
(global) stays read-only, deployed only via `claudemgr/config`'s `install.sh`;
|
||||
`.claude/memory/` here is read/write in this repo directly.
|
||||
|
||||
---
|
||||
|
||||
# PART 9: EXAMPLES FROM REAL REPOS
|
||||
|
||||
Real excerpts from live `dockersrc` repos, showing how the conventions look in
|
||||
practice. Use these as reference patterns — do not copy them verbatim into other
|
||||
repos; adapt names, paths, and versions.
|
||||
|
||||
## 9.1 — Non-stub `05-custom.sh` (toolchain install, from `dockersrc/go`)
|
||||
|
||||
A base/toolchain repo owns its `05-custom.sh` when it installs anything beyond
|
||||
packages. The go repo (221 lines) shows the full pattern: env block, helper
|
||||
functions, download with retries, verification, cleanup. Key excerpt:
|
||||
|
||||
```bash
|
||||
# Set bash options
|
||||
set -eo pipefail
|
||||
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS
|
||||
# Force IPv4 for all curl calls in this script — the base image IPv6 routing
|
||||
# intercepts *.github.com and presents a cert for casjay.in, causing SAN mismatch
|
||||
printf -- '-4\n' > /root/.curlrc
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set env variables
|
||||
VERSION="202607271500-git"
|
||||
CUSTOM_EXITCODE=0
|
||||
|
||||
# Installation root for the Go distribution (not GOPATH)
|
||||
CUSTOM_GOINSTALL_DIR="/usr/local/go"
|
||||
# GOPATH: module cache, pkg index, user-installed binaries — build/runtime cache
|
||||
# owned by the image, not a persistent VOLUME (dockersrc images never declare one)
|
||||
CUSTOM_GOPATH_DIR="/usr/local/share/go"
|
||||
# Baked-in tool binaries land here so they are on the default PATH
|
||||
CUSTOM_GOBIN_DIR="/usr/local/bin"
|
||||
# Throwaway build cache used only during this image build layer
|
||||
CUSTOM_GOCACHE_BUILD="/tmp/go-build-cache"
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Helpers
|
||||
|
||||
# Return the latest release tag from GitHub; retries up to 3 times on transient errors
|
||||
# (rate-limit 403s are common in parallel multi-platform builds without a token).
|
||||
# Set GITHUB_TOKEN to raise the authenticated rate limit (5000 req/hr vs 60 req/hr).
|
||||
__gh_latest() {
|
||||
local repo="$1"
|
||||
local filter="${2:-.tag_name}"
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Patterns to note:
|
||||
|
||||
- Comments sit ABOVE the line they describe, never inline
|
||||
- All script-local variables carry a `CUSTOM_` prefix so a dead-variable audit can
|
||||
distinguish them from template-provided vars
|
||||
- Version resolution queries the upstream API with retries and a pinned fallback —
|
||||
never a hardcoded latest version
|
||||
- Everything downloaded is verified (checksum or successful `--version` run) before
|
||||
the script exits 0
|
||||
|
||||
## 9.2 — Stub `05-custom.sh` (from `dockersrc/alpine`)
|
||||
|
||||
Pure OS base repos keep the generated 43-line stub untouched — header, bash
|
||||
options, `exitCode=0`, exit. A stub is template-owned: `gen-dockerfile` may
|
||||
overwrite it freely. The moment a repo adds real logic to `05-custom.sh` it becomes
|
||||
repo-owned and must never be regenerated (PART 2 ownership rules).
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2026 casjay <git-admin@casjaysdev.pro>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
1. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
@@ -0,0 +1,144 @@
|
||||
## 👋 Welcome to android 🚀
|
||||
|
||||
Debian-based Android build toolchain image. It is the shared build image
|
||||
(`casjaysdev/android`) consumed by every CasjaysDev Android app project — see
|
||||
[APPLICATION.md](https://github.com/claudemgr/android) for the project template
|
||||
that builds against it. Nothing app-specific (no baked `build.gradle`
|
||||
dependencies, no project source) lives in this image; only the toolchain that
|
||||
is identical across projects does.
|
||||
|
||||
### What's included
|
||||
|
||||
| Component | Version | Notes |
|
||||
|---|---|---|
|
||||
| Base OS | `casjaysdev/debian` | via `ENV_PULL_URL` |
|
||||
| JDK | 17 (Temurin) | installed from the Adoptium apt repo, `JAVA_HOME=/opt/jdk-17` |
|
||||
| Android SDK cmdline-tools | `15859902` | `$ANDROID_SDK_ROOT/cmdline-tools/latest` |
|
||||
| Android platforms | `android-34`, `android-35` | via `sdkmanager` |
|
||||
| Android build-tools | `35.0.0` | via `sdkmanager` |
|
||||
| Android NDK | `27.3.13750724` (r27d LTS) | via `sdkmanager`, for native/JNI builds |
|
||||
| CMake | `3.31.6` | via `sdkmanager`, for native/JNI builds |
|
||||
| Gradle | `8.14.5` | wrapper distribution pre-warmed into `$GRADLE_USER_HOME` so `./gradlew` never re-downloads it |
|
||||
| GitHub CLI | `gh` | from the official apt repo, for release/CI steps that shell out to `gh` |
|
||||
|
||||
`ANDROID_HOME` / `ANDROID_SDK_ROOT` default to `/opt/android-sdk`.
|
||||
`GRADLE_USER_HOME` defaults to `/root/.gradle`. All of the above are
|
||||
overridable at build time via `--build-arg` (see `Dockerfile` for the full
|
||||
`ARG` list and defaults: `ANDROID_CMDLINE_TOOLS_VERSION`,
|
||||
`ANDROID_PLATFORM_VERSIONS`, `ANDROID_BUILD_TOOLS_VERSION`,
|
||||
`ANDROID_NDK_VERSION`, `ANDROID_CMAKE_VERSION`, `GRADLE_VERSION`).
|
||||
|
||||
### How it's built
|
||||
|
||||
- `PACK_LIST` (wired from `ENV_PACKAGES` in `.env.scripts`) installs
|
||||
`wget unzip git curl gnupg` from the base distro's own repos — the minimum
|
||||
needed to fetch and unpack everything else. `ca-certificates` is already
|
||||
installed by the base template before `PACK_LIST` runs.
|
||||
- `rootfs/root/docker/setup/02-packages.sh` adds the Adoptium Temurin and
|
||||
GitHub CLI apt repositories (both need a keyring + `sources.list.d` entry
|
||||
that `pkmgr install` alone can't set up) and then installs
|
||||
`temurin-17-jdk` and `gh` through `pkmgr install`, same as any other
|
||||
package-manager install.
|
||||
- `rootfs/root/docker/setup/05-custom.sh` downloads and unpacks the Android
|
||||
SDK cmdline-tools, accepts the SDK licenses, installs the pinned
|
||||
platforms/build-tools/cmake/NDK via `sdkmanager`, and pre-warms the Gradle
|
||||
wrapper distribution zip so the wrapper never fetches it at build time.
|
||||
- No project `build.gradle`/dependency pre-warm is baked in here — that step
|
||||
is project-specific and belongs in each app's own CI, not in the shared
|
||||
base image.
|
||||
|
||||
## Install my system scripts
|
||||
|
||||
```shell
|
||||
sudo bash -c "$(curl -q -LSsf "https://github.com/systemmgr/installer/raw/main/install.sh")"
|
||||
sudo systemmgr --config && sudo systemmgr install scripts
|
||||
```
|
||||
|
||||
## Automatic install/update
|
||||
|
||||
```shell
|
||||
dockermgr update os android
|
||||
```
|
||||
|
||||
## Install and run container
|
||||
|
||||
```shell
|
||||
mkdir -p "/var/lib/srv/root/docker/casjaysdev/android/latest"
|
||||
git clone "https://github.com/dockermgr/android" "$HOME/.local/share/CasjaysDev/dockermgr/android"
|
||||
cp -Rfva "$HOME/.local/share/CasjaysDev/dockermgr/android/rootfs/." "/var/lib/srv/root/docker/casjaysdev/android/latest/"
|
||||
docker run -d \
|
||||
--restart always \
|
||||
--privileged \
|
||||
--name casjaysdev-android-latest \
|
||||
--hostname android \
|
||||
-e TZ=${TIMEZONE:-America/New_York} \
|
||||
-v "/var/lib/srv/root/docker/casjaysdev/android/latest/data:/data:z" \
|
||||
-v "/var/lib/srv/root/docker/casjaysdev/android/latest/config:/config:z" \
|
||||
casjaysdev/android:latest
|
||||
```
|
||||
|
||||
## Build an Android app with this image
|
||||
|
||||
This image is a build toolchain, not a long-running service — run it once per
|
||||
build and let it exit:
|
||||
|
||||
```shell
|
||||
docker run --rm --name {project_name}-$(tr -dc 'a-z0-9' </dev/urandom | head -c8) \
|
||||
--memory=4g --cpus=2 \
|
||||
-v "$PWD":/workspace -w /workspace \
|
||||
-e GRADLE_USER_HOME=/workspace/.gradle \
|
||||
casjaysdev/android:latest ./gradlew assembleDebug
|
||||
```
|
||||
|
||||
- Source tree → `/workspace`; Gradle cache → `GRADLE_USER_HOME=/workspace/.gradle`
|
||||
(project-scoped, safe for concurrent builds across app repos).
|
||||
- Never volume-mount over `/opt/android-sdk` — it overlays the SDK baked into
|
||||
the image. `ANDROID_HOME`/`ANDROID_SDK_ROOT` are preset and should be left
|
||||
alone unless the consuming project intentionally overrides the SDK.
|
||||
- `cmake`/`ndk` versions referenced in `app/build.gradle` must match the
|
||||
versions baked into this image (see the table above) — the image never
|
||||
lazily downloads SDK components mid-build, so a mismatch fails the build
|
||||
instead of silently fetching a different version.
|
||||
- `gh` is on `PATH` for CI steps (e.g. `gh release delete`, `gh release
|
||||
upload`) that run inside this image.
|
||||
|
||||
## via docker-compose
|
||||
|
||||
```yaml
|
||||
version: "2"
|
||||
services:
|
||||
ProjectName:
|
||||
image: casjaysdev/android
|
||||
container_name: casjaysdev-android-latest
|
||||
environment:
|
||||
- TZ=America/New_York
|
||||
- HOSTNAME=android
|
||||
volumes:
|
||||
- "/var/lib/srv/root/docker/casjaysdev/android/latest/data:/data:z"
|
||||
- "/var/lib/srv/root/docker/casjaysdev/android/latest/config:/config:z"
|
||||
restart: always
|
||||
```
|
||||
|
||||
## Get source files
|
||||
|
||||
```shell
|
||||
dockermgr download src os android
|
||||
```
|
||||
|
||||
## Build container
|
||||
|
||||
```shell
|
||||
git clone "https://github.com/dockersrc/android" "$HOME/Projects/github/dockersrc/android"
|
||||
cd "$HOME/Projects/github/dockersrc/android" && buildx all
|
||||
```
|
||||
|
||||
To override a pinned version at build time:
|
||||
|
||||
```shell
|
||||
docker build --build-arg ANDROID_BUILD_TOOLS_VERSION=35.0.0 -t casjaysdev/android:latest .
|
||||
```
|
||||
|
||||
## Authors
|
||||
|
||||
🤖 casjay: [Github](https://github.com/casjay) 🤖
|
||||
⛵ casjaysdev: [Github](https://github.com/dockersrc) [Docker](https://hub.docker.com/u/casjaysdev) ⛵
|
||||
Reference in New Issue
Block a user