fix(docker): install the MySQL 8.4 auth plugin; report why a dump fails
Build and Push Images / Build jorgecuadros-web (push) Successful in 1m56s
Build and Push Images / Build jorgecuadros-api (push) Successful in 3m3s

The pre-migrate backup failed with "mysqldump exited 2" and nothing else.
Reproduced on the host with stderr captured:

  ERROR 1045: Plugin caching_sha2_password could not be loaded:
    /usr/lib/mariadb/plugin/caching_sha2_password.so: No such file or directory

Alpine's `mysql-client` is MariaDB's client and ships an EMPTY plugin
directory, so it cannot perform caching_sha2_password — MySQL 8.4's default and
effectively only auth method. `mariadb-connector-c` provides the plugin.

This was never about the deploy backup alone. Every mysqldump/mysql call from
the API container was broken, which means the whole Operaciones panel — backup,
restore, sync, re-import — could not work in a container. It went unnoticed
because that feature had only ever been run with the API on a developer
machine, where the Oracle client is installed. Verified after the fix: dump
exits 0, gzip valid, 31 CREATE TABLEs.

Also fixed, both found while chasing the above:

- The backup script reported an exit code and nothing else, because a detached
  exec captures no output — which is precisely why this needed a manual
  reproduction. mysqldump's stderr is now redirected to a file and read back
  through a short attached exec on failure, so the deploy log states the cause.
  Verified against live prod: the log now carries the 1045 line itself.

- Listing ONLY 100.100.100.100 as the containers' resolver costs them public
  DNS, since MagicDNS does not forward upstream unless the tailnet defines
  global nameservers. Nothing at runtime needed it, but `apk` inside the
  container stopped resolving, and anything outbound would have too. A public
  fallback resolver is now listed after MagicDNS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-30 15:52:03 -07:00
co-authored by Claude Opus 5
parent b2cdcbe2cd
commit 19f03198d6
4 changed files with 82 additions and 5 deletions
+21
View File
@@ -232,6 +232,27 @@ moment the app is served over TLS or reachable off-tailnet. Behind a
TLS-terminating reverse proxy, set `trust proxy` on the Nest app instead of
disabling the flag.
## The MySQL client inside the API image
Alpine's `mysql-client` package is **MariaDB's** client, and it installs an
empty `/usr/lib/mariadb/plugin`. It therefore cannot speak
`caching_sha2_password`, which is MySQL 8.4's default and effectively only auth
method, and every `mysqldump`/`mysql` call from the container fails with:
```
ERROR 1045: Plugin caching_sha2_password could not be loaded:
... /usr/lib/mariadb/plugin/caching_sha2_password.so: No such file or directory
```
`mariadb-connector-c` supplies that plugin and is installed in
`docker/api.Dockerfile` for exactly this reason — do not drop it as an unused
dependency. It affects far more than the deploy backup: the entire
**Operaciones** panel (backup, restore, sync, re-import) shells out to these
binaries, so without it none of those work in a container either. The feature
had only ever been exercised with the API running on a developer machine, where
the Oracle client is installed, which is why this went unnoticed until the
first containerised deploy.
## Known caveats in the deploy path
- The pre-migrate backup step sets `NODE_TLS_REJECT_UNAUTHORIZED=0` because