Implement Docker container engine for services#48
Merged
munezaclovis merged 14 commits intomainfrom Mar 25, 2026
Merged
Conversation
Add Pull, CreateAndStart, Start, Stop, Remove, Exec, Logs, IsRunning, Exists, and health check waiting. Connected via Colima Docker socket using github.com/docker/docker/client.
Docker is the source of truth for container state. service:status and service:list now query the engine via IsRunning. Container names are deterministic from service name + version, so no ID storage needed.
- service:add — real engine.Pull + engine.CreateAndStart - service:start — real engine.Start with container name from service def - service:stop — real engine.Stop with container name from service def - service:remove — engine.Stop + engine.Remove, preserves data - service:destroy — engine.Stop + engine.Remove + data deletion
- service:logs streams container logs to stdout via engine.Logs - MySQL CreateDatabase runs CREATE DATABASE IF NOT EXISTS via exec - PostgreSQL CreateDatabase runs CREATE DATABASE via exec - Daemon startup recovers stopped service containers after Colima VM restart
Docker bind mounts require the source path to exist. The data directory was being created after CreateAndStart, causing "bind source path does not exist" errors.
PostgreSQL 18+ stores data in version-specific subdirectories under /var/lib/postgresql/ instead of directly in /var/lib/postgresql/data. Mount at /var/lib/postgresql to support both old and new versions.
Set POSTGRES_USER and POSTGRES_PASSWORD explicitly (matching Laravel Sail's approach). Use pg_isready with -d and -U flags for a more reliable health check. Increase retries to 20 at 3s intervals to give Postgres v18 more time to initialize its new directory layout.
Allow 'pv service:logs postgres' instead of requiring the full key 'postgres:18-alpine'. ResolveServiceKey matches by name prefix when exact key is not found.
FindService now matches by name prefix when exact key not found (e.g. "postgres" matches "postgres:18-alpine"). ResolveServiceKey added for commands to resolve shorthand names. Applied to all service commands so users can type 'pv service:logs postgres' instead of 'pv service:logs postgres:18-alpine'.
…s config
- Surface engine.IsRunning() and NewEngine() errors instead of silently
defaulting to "stopped" in doctor, list, status, and process recovery
- Make ResolveServiceKey return error on ambiguous prefix match (e.g.
"mysql" matching both "mysql:8.0" and "mysql:8.4")
- Simplify FindService to delegate to ResolveServiceKey
- Make Postgres CreateDatabase idempotent (check existence before CREATE)
- Fix Postgres port parsing for suffixed versions ("18-alpine" → 54018)
- Remove POSTGRES_HOST_AUTH_METHOD=trust, use password auth consistently
- Set DB_PASSWORD to "postgres" in Postgres EnvVars to match container
- Handle time.ParseDuration errors with sensible defaults in engine
- Surface stop/remove errors in service:destroy and service:remove
- Use ui.Fail instead of ui.Subtle for errors in service:add
- Share single engine connection in service:add (pull + create)
- Check os.Getwd() error in service:env
- Add ParseServiceKey helper, consolidate inline key splitting
- Add tests: ResolveServiceKey (exact/prefix/ambiguous), FindService
fuzzy, Postgres defaults/port/env/CreateOpts, backward compat
…plication - Fix SQL/shell injection: SanitizeProjectName now strips all non-[a-zA-Z0-9_] chars - Fix service:add to return errors on Docker failure instead of saving phantom entries - Fix service:start to recreate missing containers via Exists check + CreateAndStart - Fix service:destroy to warn when Docker is unreachable (orphaned container risk) - Change FindService to return (instance, error) so ambiguity errors propagate - Fix service:list to warn on Docker connection and Lookup failures - Fix doctor.go to distinguish "unknown service type" from "Docker unavailable" - Fix Exec to use stdcopy.StdCopy for multiplexed Docker stream - Eliminate duplicate health interval parse; reuse validated value - Fix stop.go to use resolved key instead of raw args[0] - Deduplicate extractServiceName/extractVersion with services.ParseServiceKey - Add tests: ParseServiceKey, SanitizeProjectName, FindService ambiguity, Port edge case
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the entire Docker container layer that was previously stubbed out. All
pv service:*commands now create, start, stop, remove, and inspect real Docker containers via the Colima Docker socket.CREATE DATABASE IF NOT EXISTSvia docker execCREATE DATABASEvia docker execContainerIDfield (Docker is source of truth for state)Test plan
go test ./...)go vet ./...cleango build ./...cleanpv service:add mysql— verify image pulls and container startspv service:status mysql— verify shows "running"pv service:stop mysql— verify container stopspv service:start mysql— verify container restartspv service:logs mysql— verify log streamingpv service:remove mysql— verify container removed, data preservedpv service:add postgres && pv link myapp— verify database creation