Skip to content

[Feature]: Garage module (S3-compatible object store) as an alternative to MinIO #3937

Open

Description

@acouvreur

Problem

The minio module no longer has an image that anyone can pull without logging in. minio/minio has been removed from Docker Hub (the repository returns 404), and as #3932 found, quay.io/minio/minio requires authentication. The module is now excluded from CI "until an accessible image is available".

That leaves projects that used the module as a real S3-compatible server in their tests without a replacement in the catalog. We hit this in our own CI: every test package that started MinIO failed at the image pull. The s3mock and localstack modules cover some of the same ground, but neither is an object store you would run in production.

Solution

Add a modules/garage module for Garage, an open-source S3-compatible object store built for self-hosting. Images are published as dxflrs/garage on Docker Hub with versioned tags, and anyone can pull them.

Since v2.3.0, garage server --single-node --default-bucket sets up a single-node cluster layout and creates an access key and a bucket from environment variables, all before the S3 API starts listening. That keeps the module small:

  • write a minimal garage.toml into the container (metadata and data dirs, replication_factor = 1, an RPC secret, [s3_api] bind address and region)
  • set GARAGE_DEFAULT_ACCESS_KEY, GARAGE_DEFAULT_SECRET_KEY and GARAGE_DEFAULT_BUCKET
  • wait for the log line S3 API server listening and port 3900/tcp

The default key is allowed to create buckets, so tests can create more buckets with S3 CreateBucket.

We've been running this as a small helper on top of testcontainers.Run with the AWS SDK for Go v2 (put, delete, ListObjectsV2, presigned GETs, CreateBucket). Roughly:

ctr, err := testcontainers.Run(ctx, "dxflrs/garage:v2.4.1",
	testcontainers.WithFiles(testcontainers.ContainerFile{
		Reader:            strings.NewReader(config), // minimal garage.toml
		ContainerFilePath: "/etc/garage.toml",
		FileMode:          0o644,
	}),
	testcontainers.WithEnv(map[string]string{
		"GARAGE_DEFAULT_ACCESS_KEY": accessKeyID, // at least 8 chars
		"GARAGE_DEFAULT_SECRET_KEY": secretKey,   // at least 16 chars
		"GARAGE_DEFAULT_BUCKET":     bucket,
	}),
	testcontainers.WithCmd("/garage", "server", "--single-node", "--default-bucket"),
	testcontainers.WithExposedPorts("3900/tcp"),
	testcontainers.WithWaitStrategy(
		wait.ForLog("S3 API server listening"),
		wait.ForListeningPort("3900/tcp"),
	),
)

A module version would add options for credentials, bucket and region, plus a ConnectionString for the S3 endpoint. Its default credentials need to be longer than MinIO's: Garage refuses to start if the access key ID is shorter than 8 characters or the secret is shorter than 16, so the usual minioadmin/minioadmin fails on the secret.

Points that may need discussion:

  • Minimum version: the bootstrap flags require v2.3.0 or later. Older images would need to be set up through the admin API instead.
  • Stopping the container: in our suites, a Garage container that had served S3 requests used the full 10s stop timeout before being killed. A fresh container stops in about a second on SIGTERM. We haven't found the cause yet, and work around it by terminating with StopTimeout(0).
  • Admin API: exposing the admin API (3903/tcp) for creating extra keys or buckets could come later.

Benefit

  • A real S3-compatible store with versioned images that anyone can pull, for users of the minio module who now have none.
  • It's the same server some projects run in production. We run Garage in production, and the tests now hit the same S3 implementation the code talks to.
  • Startup takes no mc calls or admin API requests, only one config file and three environment variables.

Alternatives

  • minio module with an authenticated image: works only for users who have quay.io access, and it's excluded from CI here.
  • Chainguard's MinIO image (cgr.dev/chainguard/minio): anyone can pull it, but it only has latest and latest-dev tags, so a MinIO version can't be pinned by tag.
  • s3mock and localstack: useful mocks and emulators, but not a storage server people run in production.
  • Each project wiring Garage up with testcontainers.Run: works, as above, but everyone has to work out the config file, key format and wait strategy again.

Would you like to help contributing this feature?

Yes

Activity

  1. mdelapenya commented on Oct 5, 2026

    @mdelapenya
    Member

    @acouvreur I'm happy to support this! The Minio incident was going to happen sooner than later, so having a drop-in replacement SGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions