Docker Compose dev setup: Garage + automated bootstrap #250

Merged
raucao merged 6 commits from chore/docker-compose-setup into master 2026-10-12 19:12:20 +00:00
Owner

Summary

Two related Docker Compose dev-setup improvements.

1. Switch dev object storage from MinIO to Garage

MinIO no longer publishes prebuilt community images — quay.io/minio/minio returns 401 and Docker Hub minio/minio is gone (404) — so a fresh docker compose up cannot pull the image. Replace it with a single-node Garage instance that auto-creates the remotestorage bucket and a dev-key1 access key on first start, and point liquor-cabinet at it (region garage).

2. Automate first-run LDAP and database setup

Previously the documented flow started web (with Solid Queue in Puma) before the databases existed, and required manually creating the 389ds back-end and seeding LDAP/databases, so the first docker compose up failed with Could not find table 'solid_queue_processes'. Now:

  • an ldap-init one-shot service creates the 389ds back-end if it is missing;
  • a web entrypoint seeds LDAP and the databases on first start and runs db:prepare on later boots.

Testing

  • docker compose config is valid.
  • Fresh docker compose down -v + docker compose up --build bootstraps end to end; Solid Queue starts without errors.
  • A second up is idempotent (back-end creation skipped, no re-seed).

Merge order

Please merge the fix/seeds-active-job PR first — the bootstrap runs db:setup, which needs that seed fix.

## Summary Two related Docker Compose dev-setup improvements. ### 1. Switch dev object storage from MinIO to Garage MinIO no longer publishes prebuilt community images — `quay.io/minio/minio` returns 401 and Docker Hub `minio/minio` is gone (404) — so a fresh `docker compose up` cannot pull the image. Replace it with a single-node Garage instance that auto-creates the `remotestorage` bucket and a `dev-key1` access key on first start, and point liquor-cabinet at it (region `garage`). ### 2. Automate first-run LDAP and database setup Previously the documented flow started `web` (with Solid Queue in Puma) before the databases existed, and required manually creating the 389ds back-end and seeding LDAP/databases, so the first `docker compose up` failed with `Could not find table 'solid_queue_processes'`. Now: - an `ldap-init` one-shot service creates the 389ds back-end if it is missing; - a `web` entrypoint seeds LDAP and the databases on first start and runs `db:prepare` on later boots. ## Testing - `docker compose config` is valid. - Fresh `docker compose down -v` + `docker compose up --build` bootstraps end to end; Solid Queue starts without errors. - A second `up` is idempotent (back-end creation skipped, no re-seed). ## Merge order Please merge the `fix/seeds-active-job` PR first — the bootstrap runs `db:setup`, which needs that seed fix.
raucao force-pushed chore/docker-compose-setup from 1f55a70096 to a1423cb625 2026-10-06 13:38:46 +00:00 Compare
raucao added the kredits-2dev environment labels 2026-10-06 13:49:43 +00:00
raucao requested review from greg 2026-10-06 13:49:47 +00:00
raucao added 2 commits 2026-10-06 13:52:39 +00:00
The documented flow started web (with Solid Queue in Puma) before the
databases existed, and required manually creating the 389ds back-end
and seeding the LDAP directory and databases. Automate it:

- add an ldap-init one-shot service that creates the 389ds back-end if
  it does not exist
- add a web entrypoint that seeds LDAP and the databases on first start,
  and runs db:prepare on later boots
- update README and AGENTS accordingly, including the reset steps
Switch dev object storage from MinIO to Garage
CI / Test (pull_request) Successful in 43s
6279699c11
MinIO no longer publishes prebuilt community images (quay.io returns
401, Docker Hub 404), so the dev setup cannot pull the image.

Use a single-node Garage instance instead, which auto-creates the
remotestorage bucket and a dev-key1 access key on first start, and
point liquor-cabinet at it.
raucao force-pushed chore/docker-compose-setup from a1423cb625 to 6279699c11 2026-10-06 13:52:39 +00:00 Compare
raucao added 1 commit 2026-10-06 17:37:37 +00:00
Fix Liquor Cabinet performance in dev
CI / Test (pull_request) Failing after 46s
695977172f
Can't handle enough requests without ThreadPool, so once you hit the
limit, requests take 5s+ (having to wait for the keepalive timeout)
raucao added 2 commits 2026-10-06 17:37:51 +00:00
Allow remote access to dev services
CI / Test (pull_request) Successful in 46s
Release Drafter / Update release notes draft (pull_request) Successful in 19s
bc37df52a0
Reviewed-on: #253
Author
Owner

@greg Were you able to run it in the meantime? If not, could you post the error?

@greg Were you able to run it in the meantime? If not, could you post the error?
Owner

@greg Were you able to run it in the meantime? If not, could you post the error?

I'm getting a different error now:

dap-1            | DEBUG: DEBUG: starting with ['/usr/sbin/ns-slapd', '-D', '/etc/dirsrv/slapd-localhost', '-i', '/data/run/slapd-localhost.pid']
ldap-1            | Traceback (most recent call last):
ldap-1            |   File "/usr/lib/python3.12/site-packages/lib389/instance/setup.py", line 758, in create_from_args
ldap-1            |     self._install_ds(general, slapd, backends)
ldap-1            |   File "/usr/lib/python3.12/site-packages/lib389/instance/setup.py", line 1035, in _install_ds
ldap-1            |     ds_instance.start(timeout=60)
ldap-1            |   File "/usr/lib/python3.12/site-packages/lib389/__init__.py", line 1109, in start
ldap-1            |     raise ValueError('Failed to start DS')
ldap-1            | ValueError: Failed to start DS
ldap-1            | 
ldap-1            | During handling of the above exception, another exception occurred:
ldap-1            | 
ldap-1            | Traceback (most recent call last):
ldap-1            |   File "/usr/libexec/dirsrv/dscontainer", line 474, in <module>
ldap-1            |     begin_magic()
ldap-1            |   File "/usr/libexec/dirsrv/dscontainer", line 277, in begin_magic
ldap-1            |     if not sds.create_from_args(g2b.collect(), s2b.collect()):
ldap-1            |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ldap-1            |   File "/usr/lib/python3.12/site-packages/lib389/instance/setup.py", line 761, in create_from_args
ldap-1            |     self._remove_failed_install(slapd['instance_name'])
ldap-1            |   File "/usr/lib/python3.12/site-packages/lib389/instance/setup.py", line 258, in _remove_failed_install
ldap-1            |     remove_ds_instance(inst, force=True)
ldap-1            |   File "/usr/lib/python3.12/site-packages/lib389/instance/remove.py", line 85, in remove_ds_instance
ldap-1            |     dirsrv.stop()
ldap-1            |   File "/usr/lib/python3.12/site-packages/lib389/__init__.py", line 1141, in stop
ldap-1            |     if self.status() is False:
ldap-1            |        ^^^^^^^^^^^^^
ldap-1            |   File "/usr/lib/python3.12/site-packages/lib389/__init__.py", line 1174, in status
ldap-1            |     rc = subprocess.call(["systemctl",
ldap-1            |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ldap-1            |   File "/usr/lib/python3.12/subprocess.py", line 389, in call
ldap-1            |     with Popen(*popenargs, **kwargs) as p:
ldap-1            |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
ldap-1            |   File "/usr/lib/python3.12/subprocess.py", line 1026, in __init__
ldap-1            |     self._execute_child(args, executable, preexec_fn, close_fds,
ldap-1            |   File "/usr/lib/python3.12/subprocess.py", line 1955, in _execute_child
ldap-1            |     raise child_exception_type(errno_num, err_msg, err_filename)
ldap-1            | FileNotFoundError: [Errno 2] No such file or directory: 'systemctl'
Container akkounts-ldap-1 Error dependency ldap failed to start

Docker has always hated me

> @greg Were you able to run it in the meantime? If not, could you post the error? I'm getting a different error now: ``` dap-1 | DEBUG: DEBUG: starting with ['/usr/sbin/ns-slapd', '-D', '/etc/dirsrv/slapd-localhost', '-i', '/data/run/slapd-localhost.pid'] ldap-1 | Traceback (most recent call last): ldap-1 | File "/usr/lib/python3.12/site-packages/lib389/instance/setup.py", line 758, in create_from_args ldap-1 | self._install_ds(general, slapd, backends) ldap-1 | File "/usr/lib/python3.12/site-packages/lib389/instance/setup.py", line 1035, in _install_ds ldap-1 | ds_instance.start(timeout=60) ldap-1 | File "/usr/lib/python3.12/site-packages/lib389/__init__.py", line 1109, in start ldap-1 | raise ValueError('Failed to start DS') ldap-1 | ValueError: Failed to start DS ldap-1 | ldap-1 | During handling of the above exception, another exception occurred: ldap-1 | ldap-1 | Traceback (most recent call last): ldap-1 | File "/usr/libexec/dirsrv/dscontainer", line 474, in <module> ldap-1 | begin_magic() ldap-1 | File "/usr/libexec/dirsrv/dscontainer", line 277, in begin_magic ldap-1 | if not sds.create_from_args(g2b.collect(), s2b.collect()): ldap-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ldap-1 | File "/usr/lib/python3.12/site-packages/lib389/instance/setup.py", line 761, in create_from_args ldap-1 | self._remove_failed_install(slapd['instance_name']) ldap-1 | File "/usr/lib/python3.12/site-packages/lib389/instance/setup.py", line 258, in _remove_failed_install ldap-1 | remove_ds_instance(inst, force=True) ldap-1 | File "/usr/lib/python3.12/site-packages/lib389/instance/remove.py", line 85, in remove_ds_instance ldap-1 | dirsrv.stop() ldap-1 | File "/usr/lib/python3.12/site-packages/lib389/__init__.py", line 1141, in stop ldap-1 | if self.status() is False: ldap-1 | ^^^^^^^^^^^^^ ldap-1 | File "/usr/lib/python3.12/site-packages/lib389/__init__.py", line 1174, in status ldap-1 | rc = subprocess.call(["systemctl", ldap-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ldap-1 | File "/usr/lib/python3.12/subprocess.py", line 389, in call ldap-1 | with Popen(*popenargs, **kwargs) as p: ldap-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ldap-1 | File "/usr/lib/python3.12/subprocess.py", line 1026, in __init__ ldap-1 | self._execute_child(args, executable, preexec_fn, close_fds, ldap-1 | File "/usr/lib/python3.12/subprocess.py", line 1955, in _execute_child ldap-1 | raise child_exception_type(errno_num, err_msg, err_filename) ldap-1 | FileNotFoundError: [Errno 2] No such file or directory: 'systemctl' Container akkounts-ldap-1 Error dependency ldap failed to start ``` Docker has always hated me
Author
Owner

And you definitely deleted any existing volumes before docker compose up --build, correct?

Edit: I looked into it and it's not the container. Nevertheless, to remove the broken state, run this before trying again:

docker compose down -v

Since I think you're on Apple silicon, could you check if this helps?

On Apple Silicon/arm64, this amd64 image runs emulated. ns-slapd is a big C daemon and can crash (SIGSEGV/SIGBUS) or blow the 60s window under QEMU. Enabling "Use Rosetta for x86/amd64 emulation" in Docker Desktop usually fixes it.

And you definitely deleted any existing volumes before `docker compose up --build`, correct? Edit: I looked into it and it's not the container. Nevertheless, to remove the broken state, run this before trying again: docker compose down -v Since I think you're on Apple silicon, could you check if this helps? > On Apple Silicon/arm64, this amd64 image runs emulated. ns-slapd is a big C daemon and can crash (SIGSEGV/SIGBUS) or blow the 60s window under QEMU. Enabling "Use Rosetta for x86/amd64 emulation" in Docker Desktop usually fixes it.
Author
Owner

Also, to get the actual error log for why the setup is failing, add the DEBUGGING env var, which should then keep the error log.

  ldap:
    environment:
      DS_DM_PASSWORD: passthebutter
      SUFFIX_NAME: "dc=kosmos,dc=org"
      DEBUGGING: "1"

Then after it fails:

docker run --rm -v akkounts_389ds-data:/data --entrypoint sh 4teamwork/389ds:latest -c 'cat /data/logs/error'
Also, to get the actual error log for why the setup is failing, add the `DEBUGGING` env var, which should then keep the error log. ```yaml ldap: environment: DS_DM_PASSWORD: passthebutter SUFFIX_NAME: "dc=kosmos,dc=org" DEBUGGING: "1" ``` Then after it fails: ```bash docker run --rm -v akkounts_389ds-data:/data --entrypoint sh 4teamwork/389ds:latest -c 'cat /data/logs/error' ```
Owner

And you definitely deleted any existing volumes before docker compose up --build, correct?

Edit: I looked into it and it's not the container. Nevertheless, to remove the broken state, run this before trying again:

docker compose down -v

Yes, this was a clean install of Docker Desktop

Since I think you're on Apple silicon, could you check if this helps?

On Apple Silicon/arm64, this amd64 image runs emulated. ns-slapd is a big C daemon and can crash (SIGSEGV/SIGBUS) or blow the 60s window under QEMU. Enabling "Use Rosetta for x86/amd64 emulation" in Docker Desktop usually fixes it.

Yes I'm on an M2 Pro. Just checked, this is enabled by default.

> And you definitely deleted any existing volumes before `docker compose up --build`, correct? > > Edit: I looked into it and it's not the container. Nevertheless, to remove the broken state, run this before trying again: > > docker compose down -v Yes, this was a clean install of Docker Desktop > > Since I think you're on Apple silicon, could you check if this helps? > > > On Apple Silicon/arm64, this amd64 image runs emulated. ns-slapd is a big C daemon and can crash (SIGSEGV/SIGBUS) or blow the 60s window under QEMU. Enabling "Use Rosetta for x86/amd64 emulation" in Docker Desktop usually fixes it. Yes I'm on an M2 Pro. Just checked, this is enabled by default.
Author
Owner

OK, then we should look at the error to see if it's worth swapping out the whole Docker image for a multi-arch one (which we may or may not have to create ourselves).

If the emulation is just slow, we could probably increase the 60s hard timeout somehow.

OK, then we should look at the error to see if it's worth swapping out the whole Docker image for a multi-arch one (which we may or may not have to create ourselves). If the emulation is just slow, we could probably increase the 60s hard timeout somehow.
Owner

I've been getting different errors now:

ldap-1  | Traceback (most recent call last):
ldap-1  |   File "/usr/libexec/dirsrv/dscontainer", line 474, in <module>
ldap-1  |     begin_magic()
ldap-1  |   File "/usr/libexec/dirsrv/dscontainer", line 277, in begin_magic
ldap-1  |     if not sds.create_from_args(g2b.collect(), s2b.collect()):
ldap-1  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ldap-1  |   File "/usr/lib/python3.12/site-packages/lib389/instance/setup.py", line 747, in create_from_args
ldap-1  |     self._prepare_ds(general, slapd, backends)
ldap-1  |   File "/usr/lib/python3.12/site-packages/lib389/instance/setup.py", line 674, in _prepare_ds
ldap-1  |     assert_c(len(insts) == 0, "Another instance named '%s' may already exist" % slapd['instance_name'])
ldap-1  |   File "/usr/lib/python3.12/site-packages/lib389/utils.py", line 1512, in assert_c
ldap-1  |     raise AssertionError(msg)
ldap-1  | AssertionError: Another instance named 'localhost' may already exist

After searching a bit I tried the following workaround: DOCKER_DEFAULT_PLATFORM=linux/amd64 docker compose up --build. It took a long time but it failed with the same error

I've been getting different errors now: ``` ldap-1 | Traceback (most recent call last): ldap-1 | File "/usr/libexec/dirsrv/dscontainer", line 474, in <module> ldap-1 | begin_magic() ldap-1 | File "/usr/libexec/dirsrv/dscontainer", line 277, in begin_magic ldap-1 | if not sds.create_from_args(g2b.collect(), s2b.collect()): ldap-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ldap-1 | File "/usr/lib/python3.12/site-packages/lib389/instance/setup.py", line 747, in create_from_args ldap-1 | self._prepare_ds(general, slapd, backends) ldap-1 | File "/usr/lib/python3.12/site-packages/lib389/instance/setup.py", line 674, in _prepare_ds ldap-1 | assert_c(len(insts) == 0, "Another instance named '%s' may already exist" % slapd['instance_name']) ldap-1 | File "/usr/lib/python3.12/site-packages/lib389/utils.py", line 1512, in assert_c ldap-1 | raise AssertionError(msg) ldap-1 | AssertionError: Another instance named 'localhost' may already exist ``` After searching a bit I tried the following workaround: `DOCKER_DEFAULT_PLATFORM=linux/amd64 docker compose up --build`. It took a long time but it failed with the same error
Author
Owner

You will have to delete the volume every time after a failed start like that. If you could fetch the actual full error log and post it here, that would help:

#250 (comment)

You will have to delete the volume every time after a failed start like that. If you could fetch the actual full error log and post it here, that would help: https://gitea.kosmos.org/kosmos/akkounts/pulls/250#issuecomment-15204
Owner

Good news, I deleted everything and started over again, this time it's running!

DOCKER_DEFAULT_PLATFORM=linux/amd64 docker compose up --build works on a Mac with an ARM CPU.

Good news, I deleted everything and started over again, this time it's running! `DOCKER_DEFAULT_PLATFORM=linux/amd64 docker compose up --build` works on a Mac with an ARM CPU.
greg approved these changes 2026-10-12 13:14:14 +00:00
Dismissed
greg left a comment
Owner

👍

👍
raucao added 1 commit 2026-10-12 13:34:11 +00:00
Pin platform for amd64-only Docker services
CI / Test (pull_request) Successful in 45s
Release Drafter / Update release notes draft (pull_request) Successful in 10s
8c395ce737
Author
Owner

OK, great!

I have pushed a small change that adds the platform explicitly in the Compose config. Could you docker compose down -v again and try to run docker compose up --build without any env var?

If that works, then this is cleaner than adding a longer command to the README.

OK, great! I have pushed a small change that adds the platform explicitly in the Compose config. Could you `docker compose down -v` again and try to run `docker compose up --build` without any env var? If that works, then this is cleaner than adding a longer command to the README.
Owner

OK, great!

I have pushed a small change that adds the platform explicitly in the Compose config. Could you docker compose down -v again and try to run docker compose up --build without any env var?

If that works, then this is cleaner than adding a longer command to the README.

That worked!

beavis-on-computer.gif

> OK, great! > > I have pushed a small change that adds the platform explicitly in the Compose config. Could you `docker compose down -v` again and try to run `docker compose up --build` without any env var? > > If that works, then this is cleaner than adding a longer command to the README. That worked! ![beavis-on-computer.gif](attachments/2df2b0f3-92f4-4817-aa71-e326fa06487d)
raucao requested review from greg 2026-10-12 18:19:50 +00:00
greg approved these changes 2026-10-12 18:41:26 +00:00
greg left a comment
Owner

👍

👍
Author
Owner

dancing.gif

![dancing.gif](attachments/cce94924-487c-4661-a32d-6094ea0733c4)
raucao merged commit dbf76b64b6 into master 2026-10-12 19:12:20 +00:00
raucao deleted branch chore/docker-compose-setup 2026-10-12 19:12:21 +00:00
Sign in to join this conversation.