added migration
Build and publish Docker image / build (push) Failing after 41s

This commit is contained in:
NikoKS committed 2026-10-15 00:05:11 +07:00
1 parent 125eab3cd4
commit 045d3a8fd3
8 files changed
+375 -65

No files matched your search

+77 -54
View File
@@ -3,7 +3,8 @@
This stack runs PHP 8.3/Apache, MySQL 8.4 LTS, and phpMyAdmin 5.2. No Node build,
registry, or separate Komodo Build resource is required. The app image is built
on your Docker host. MySQL has no published port. Database, application sessions,
and phpMyAdmin sessions use persistent named volumes.
and phpMyAdmin sessions use persistent named volumes. Two one-shot services import
an initial SQL dump safely and apply migrations before Apache starts.
To build/publish the app in Gitea Actions instead of on the server, see
[the image build guide](image-build.md), including registry secrets and Komodo
@@ -32,9 +33,10 @@ secrets. Generate each password with `openssl rand -hex 32`. Use Komodo secrets
if available; do not commit the populated environment to Git. Leave the environment
file path at `.env`: Komodo writes it and passes it to Compose.
Deploy the Stack. **The app may initially be unhealthy** until you explicitly
import the base database and run migrations below. Do not enable a deploy
`--wait` flag on this first launch: it cannot become ready before that setup.
Before deploying, transfer your trusted initial SQL dump to the Docker host and
set `DB_INIT_SQL_PATH` as described below. Deploy the Stack: startup waits for
MySQL, runs `db-init`, runs `migrate`, then starts the app. The one-shot services
should finish with exit code 0; they do not remain running.
For a files-on-host Stack instead, put the repository on the server, select
**Files on host**, set Run directory to its absolute path, and use the same
@@ -42,52 +44,70 @@ Compose/build/environment settings.
Official reference: [Komodo Compose Stacks](https://komo.do/docs/deploy/compose).
## 2. Import the database once
On the Docker server, change to the Stack's checked-out **run directory**. The
commands below assume the project name `recruitment-hc` and Komodo's default
`.env` file; if you choose another project name/env path, adjust **every** command
accordingly. Never run commands against a different project by accident.
Wait for `db` to be healthy:
```sh
docker compose --env-file .env -p recruitment-hc ps
```
## 2. Automatic database initialization
Obtain a trusted recruitment SQL export containing `in_daper`, `in_soal`, and
`in_jawab`. Transfer it privately to a path **outside the checkout/document root**,
for example `/srv/recruitment-private/initial.sql`, with restricted permissions.
The repository currently also tracks an export under `DB/`; it may contain
personal data and existing accounts. Keep the repository private, review/sanitize
any export used in production, and remove unwanted demo/test access before opening
the site. Neither `DB/` nor any export is included in the image or auto-imported.
`in_jawab`. Transfer it privately to the **Docker host**, outside the
checkout/document root, for example `/srv/recruitment-private/initial.sql`.
Restrict access to the file and set this in the Stack Environment (or `.env`):
**Only import into a new, empty database.** Dumps can contain `DROP TABLE` and
existing accounts/passwords. Check first; this should return **no table names**:
```sh
docker compose --env-file .env -p recruitment-hc exec -T db sh -c \
'MYSQL_PWD="$MYSQL_PASSWORD" mysql -u "$MYSQL_USER" "$MYSQL_DATABASE" -e "SHOW TABLES"'
```dotenv
DB_INIT_SQL_PATH=/srv/recruitment-private/initial.sql
```
If it is empty, import and apply the migrations:
For local Docker use, the default is
`./DB/recruitment_local_2026-10-14.sql`. That dump contains personal data and
existing accounts, not just schema. Review/sanitize production exports and remove
unwanted demo/test access before opening the site. Dumps are not shipped in the
app image or fetched from Git. The file is mounted read-only into `db-init`;
it must exist on the Docker host even on later deployments. A missing path fails
startup instead of silently creating a directory. Dumps must not reference the
reserved `rec_bootstrap_state` safety table; exclude it from exports/backups using
the command in section 5. This prevents a restored marker from masking a failed
import.
Normal deployment handles setup automatically:
1. `db` becomes healthy.
2. `db-init` imports the dump **only if the database contains no tables or views**.
A persistent `rec_bootstrap_state` table records `importing` before the import
and `imported` only after success and validation of the three base tables.
3. On subsequent deployments, an `imported` marker and the base tables skip the
dump entirely. A pre-existing database without a marker is accepted only if
all seven recruitment tables are present. Partial/unexpected databases are
refused, not overwritten. This check cannot validate the contents of a dump
imported outside this setup; review such databases yourself before deployment.
4. `migrate` applies the idempotent admin/exam migrations and validates readiness.
5. `app` starts only after both one-shot services exit successfully.
On the Docker server, change to the Stack's checked-out **run directory**. The
commands below assume project name `recruitment-hc` and `.env`; adjust every
command if your Stack uses different settings.
```sh
docker compose --env-file .env -p recruitment-hc exec -T db sh -c \
'MYSQL_PWD="$MYSQL_PASSWORD" mysql -u "$MYSQL_USER" "$MYSQL_DATABASE"' \
< /srv/recruitment-private/initial.sql
docker compose --env-file .env -p recruitment-hc exec -T app \
php /usr/local/share/recruitment/migrate.php
docker compose --env-file .env -p recruitment-hc ps -a
docker compose --env-file .env -p recruitment-hc logs db-init migrate
```
The migration command requires the three base tables, creates the admin and exam
protection tables, and handles the historical admin identity schema when needed.
It can be rerun without resetting users or test progress. Migrations are explicit,
not run automatically on every container restart. Back up before applying them to
an existing database. Future migrations must be added to the migration runner as
part of their release.
The import guard has a database-free regression suite:
`python3 dev/test-db-init.py`.
**Failed import:** SQL DDL is not transactional. An `importing` marker deliberately
blocks retries, including when only some tables were restored. Inspect the logs
and affected database, then restore a trusted backup or use a separately verified
empty database/volume. Do not delete the marker or run a dump over partial data
blindly. Never delete the production volume merely to retry setup.
Migrations can be rerun without resetting users or test progress. They run during
Compose deployment, not on an individual Apache container restart. Back up before
deploying changes against an existing database. Add future migrations to the
migration runner as part of their release. If a migration fails, fix the cause and
rerun setup without reimporting:
```sh
docker compose --env-file .env -p recruitment-hc run --rm migrate
docker compose --env-file .env -p recruitment-hc up -d
```
If you need a new admin account, run this from an **interactive SSH terminal**:
@@ -169,17 +189,17 @@ Never expose phpMyAdmin directly on an unrestricted public HTTP port.
Add these new settings from `.env.example` to the Komodo Stack Environment and
redeploy. `PHPMYADMIN_PORT` defaults to `8087`; `PHPMYADMIN_UPLOAD_LIMIT` defaults
to `64M`. For browser imports, adjust your reverse proxy's upload size/timeouts as
needed; large dumps are better imported using the CLI command in section 2.
Browser imports can also overwrite data: only import into a verified empty
database, then run the migration command. No database initialization is automated.
needed; large dumps are better handled by the setup service in section 2.
Browser imports can also overwrite data. Prefer the automatic `db-init` service
for first-time setup; do not import another dump over an initialized database.
## 4. Verify
```sh
docker compose --env-file .env -p recruitment-hc ps
docker compose --env-file .env -p recruitment-hc ps -a
curl --fail http://127.0.0.1:8086/healthz
curl --fail http://127.0.0.1:8087/ > /dev/null
docker compose --env-file .env -p recruitment-hc logs --tail=100 app db phpmyadmin
docker compose --env-file .env -p recruitment-hc logs --tail=100 app db db-init migrate phpmyadmin
```
Adjust the curl address if you changed the bind IP or port. `/healthz` returns
@@ -211,19 +231,20 @@ snapshot for InnoDB. Include any active test data when planning maintenance.
umask 077
mkdir -p /srv/recruitment-private/backups
docker compose --env-file .env -p recruitment-hc exec -T db sh -c \
'MYSQL_PWD="$MYSQL_ROOT_PASSWORD" mysqldump -u root --single-transaction --routines --triggers --no-tablespaces "$MYSQL_DATABASE"' \
'MYSQL_PWD="$MYSQL_ROOT_PASSWORD" mysqldump -u root --single-transaction --routines --triggers --no-tablespaces --ignore-table="$MYSQL_DATABASE.rec_bootstrap_state" "$MYSQL_DATABASE"' \
> "/srv/recruitment-private/backups/recruitment-$(date +%Y%m%d-%H%M%S).sql"
```
Check the command's exit status and backup contents before relying on the file.
SQL backups contain personal data and password hashes; restrict and protect them.
Restore using the import command in section 2 **only after selecting a new empty
database or explicitly approving replacement of the target data**; migrate after
restoring if needed.
To restore into a new empty stack, set `DB_INIT_SQL_PATH` to the trusted backup
and deploy; initialization and migrations run automatically. Restoring over an
existing database requires a separate, explicitly approved recovery procedure;
normal startup never replaces its tables.
To update, back up, pull the new commit in Komodo and redeploy with **Run build**
enabled. The database volume is reused; imports are never repeated automatically.
Apply migration changes explicitly when a release requires them. Rolling back an
enabled. The database volume is reused; successful imports are never repeated.
The migration service runs before the updated app starts. Rolling back an
image does not undo schema changes; use a tested database restore if necessary.
Image tags track compatible patch releases; consider pinning tested image digests
in production for reproducible upgrades.
@@ -246,11 +267,13 @@ From the repository root on the server:
```sh
cp .env.example .env
chmod 600 .env
# Edit .env and replace both password placeholders before proceeding.
# Edit .env: replace both passwords and set DB_INIT_SQL_PATH to your trusted dump.
# The SQL file must already exist on this Docker host.
docker compose --env-file .env -p recruitment-hc config --quiet
docker compose --env-file .env -p recruitment-hc up -d --build
```
Then follow sections 2–5. Docker uses its own environment-backed
Setup is automatic. Inspect `db-init`/`migrate` logs, create an admin as needed
(section 2), then follow sections 3–5. Docker uses its own environment-backed
`includes/conn.php` baked into the image; it never reads or overwrites the host's
private `includes/conn.php`. Standalone PHP/local preview behavior is unchanged.