containerkit

module
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 8, 2026 License: MIT

README

containerkit

Go Reference Go Report Card Go Version License

Define Docker stacks in Go. The same *kit.Container is a Compose service or an Engine create config. Compose runs in-process through github.com/docker/compose/v5 and does not need a docker compose binary.

Demo

package main

import (
	"context"
	"log"
	"os"

	"github.com/aptd3v/containerkit/pkg/kit"
)

func main() {
	project := kit.NewProject("hello-world")
	project.WithService(kit.NewService("hello",
		kit.NewContainer().
			Image("alpine:latest").
			Command("echo", "Hello from containerkit!"),
	))

	if err := project.Validate(); err != nil {
		log.Fatal(err)
	}

	app := kit.NewCompose(project)
	if err := app.Up(context.Background(), &kit.Up{Writer: os.Stdout}); err != nil {
		log.Fatal(err)
	}
}

The echo container exits when the command finishes.

Getting started

go get github.com/aptd3v/containerkit@v0.7.0
  • Go 1.26.8+
  • Docker Engine
  • Linux, macOS, or Windows

v0.7.0

  • Astronomy Shop showcase (examples/astronomy_shop): CNCF OpenTelemetry demo as a Go Compose project with shop / full / observability profiles, health waits, kit-probe Dockerfile-as-Go, and a taskflow Build -> Up -> probe DAG.
  • Dockerfile injection harden: fluent Dockerfile scalars reject newline / control-character injection before build context is sent.
  • Trap-removal cleanup: nil-safe Container.Validate, dead daemon deps and unused Makefile targets removed from the published tree.

Features

The published core is pkg/kit and pkg/client, with optional pkg/taskflow for DAGs over the same values. One *kit.Container feeds both Engine create and Compose. Fluent setters accumulate errors; call Validate (or let Up / Export / ContainerCreate do it) before side effects. Dockerfile-as-Go plus Build.Reader, in-process Compose option structs, health/DependsOnHealthy/Up.Wait, and project.WriteTo / Export for plan preview are the agent-friendly path. An HTTP daemon or canvas UI is not part of this module.

Two ways to run the same container
Piece Import Role
Project, *Container github.com/aptd3v/containerkit/pkg/kit Stack and container config. Fluent methods set image, env, ports, mounts, and the rest.
SDK value types github.com/aptd3v/containerkit/pkg/kit/types ByteSize, PortBinding, Capability, host modes, mount aliases.
NewCompose, Up, Down, … pkg/kit In-process Compose runner. Each command takes an option struct.
Engine client github.com/aptd3v/containerkit/pkg/client Docker Engine SDK wrapper. Each call takes a per-op struct (Remove, Exec, ImageBuild, …).

Compose fits a multi-service stack: networks, volumes, profiles, and Up / Down / Logs. The Engine client fits one container, image builds, and an interactive TTY. A hybrid program uses the client to build or exec, then Compose to run the stack. See examples/nginx, examples/image_inline, and examples/mongo_replica.

Type stacks

pkg/kit config types come from github.com/docker/docker/api/types/.... pkg/client talks to github.com/moby/moby/client and github.com/moby/moby/api/types/.... Those are distinct Go types. Pass kit configs through the client APIs (they convert internally); do not assign across packages by hand.

Compose stack
project := kit.NewProject("my-app")
project.
	WithNetwork("backend").
	WithVolume("data").
	WithService(kit.NewService("api",
		kit.NewContainer().
			Image("alpine:latest").
			Command("sleep", "inf").
			PortBinding(types.PortBinding{Protocol: types.TCP, HostIP: "0.0.0.0", HostPort: "8080", ContainerPort: "8080"}).
			RWNamedVolumeMount("data", "/data").
			Endpoint("backend"),
	).DependsOn("db"))

if err := project.Validate(); err != nil {
	log.Fatal(err)
}

app := kit.NewCompose(project)
if err := app.Up(ctx, &kit.Up{
	Detach:        true,
	RemoveOrphans: true,
	Writer:        os.Stdout,
}); err != nil {
	log.Fatal(err)
}
defer app.Down(ctx, &kit.Down{RemoveVolumes: true, Writer: os.Stdout})

Export writes the project as Compose YAML. Print writes that YAML to stdout. WriteTo writes it to any io.Writer.

if err := project.Export("./docker-compose.yaml", 0644); err != nil {
	log.Fatal(err)
}
_ = project.Print()
_, _ = project.WriteTo(w)
Engine client

NewContainer joins every name part with a hyphen ("my", "api" becomes my-api). Pass a name for ContainerCreate. A Compose service can omit it. Construction options stay funcs on client.

cli, err := client.NewClient(client.FromEnv(), client.WithAPIVersionNegotiation())
if err != nil {
	log.Fatal(err)
}

ctr := kit.NewContainer("my-api")
ctr.Image("alpine:latest").Command("sleep", "inf")

resp, err := cli.ContainerCreate(ctx, ctr)
if err != nil {
	log.Fatal(err)
}
_ = cli.ContainerRemove(ctx, resp.ID, &client.Remove{Force: true, RemoveVolumes: true})

Pass that same *kit.Container to NewService when the stack should run under Compose.

Task graph

pkg/taskflow is optional. It orders the same *kit.Container, kit.Build, and *kit.Compose values as a DAG. Import it only when you want that; pkg/kit and pkg/client do not depend on it.

flow := taskflow.New("ci", cli)
build := flow.Build("build",
	kit.NewBuild().Dockerfile(df),
	&client.ImageBuild{Tags: []string{"app:ci"}},
)
up := flow.Compose("up-db", db, &kit.Up{Detach: true, Wait: true})
test := flow.Container("test", kit.NewContainer().Image("app:ci"), nil)

test.DependsOn(up.DependsOn(build))

defer flow.Remove(ctx)
err := flow.Run(ctx, &taskflow.Run{Writer: os.Stdout})

A failed step skips its successors. Full guide: pkg/taskflow. Demo: examples/taskflow.

Dockerfile

NewDockerFile writes a Dockerfile in Go. ParseDockerfile wraps a string and ReadDockerfile loads a file. Export writes the file to disk. A Build carries the Dockerfile plus the build context: pass it to Service.Build for Compose, or call Reader for the tar client.ImageBuild accepts.

df := kit.NewDockerFile().
	FromAs("alpine:latest", "build").
	Run("echo ok > /out/app").
	From("alpine:latest").
	Copy("/out/app", "/app", kit.CopyOpts{From: "build"})

if err := df.Export("Dockerfile", 0644); err != nil {
	log.Fatal(err)
}

build := kit.NewBuild().Context(".").Dockerfile(df)

project.WithService(kit.NewService("app",
	kit.NewContainer().Image("my-image:tag"),
).Build(build))

r, err := build.Reader()
if err != nil {
	log.Fatal(err)
}
resp, err := cli.ImageBuild(ctx, r, &client.ImageBuild{Tags: []string{"my-image:tag"}})

Reader packs the context directory, writes the generated Dockerfile over any Dockerfile already there, and honors .dockerignore. An empty context packs only the Dockerfile. When only Context or DockerfilePath is set, Reader reads that file from disk. See examples/dockerfile and examples/image_inline.

Rules
  • Setters append to Container.Errors and to the project. Call Validate before Up, Export, or ContainerCreate. Those three calls run Validate themselves.
  • A nil Up or Down uses defaults. The writer is os.Stdout.
  • Service.Profiles is Compose’s profiles: key. If the project has any profiled service, set Profiles on the command (Up.Profiles, Down.Profiles, and the rest). Compose returns an error when that list is empty.
project.WithService(kit.NewService("worker",
	kit.NewContainer().Image("alpine:latest"),
).Profiles("full"))
_ = app.Up(ctx, &kit.Up{Profiles: []string{"full"}, Writer: os.Stdout})
  • Compose-only settings are methods on *Service: DependsOn, Profiles, Build, Deploy. *Container stays the process config.
  • Sizes are a types.ByteSize: MemoryLimit(100 * types.MiB).
  • Branch with an ordinary if.
c := kit.NewContainer().Image("node:latest")
if runtime.GOOS == "linux" {
	c.RWNamedVolumeMount("data", "/app")
} else {
	c.VolumeBinds("./:/app/:rw")
}
API surface

Full signatures are on pkg.go.dev.

Naming families (as they exist today; no forced rename):

Family Pattern Examples
Container fluent method on *Container .Image(), .Env(), .HealthCheck(...)
Project builders With* on *Project WithService, WithNetwork
Service Compose-only method on *Service .DependsOn(), .Profiles()
Client construction functional options client.WithAPIVersionNegotiation()
Client / Compose ops per-op structs &client.Remove{…}, &kit.Up{…}
Registry auth With* options auth.WithUsername (WithEmail is deprecated)

Container. Image, env, command, ports, mounts, health, restart, resources, capabilities, logging, and platform. You can also mix in Docker SDK structs. See examples/structs.

Service. NewService(name, container), then DependsOn, DependsOnHealthy, Profiles, Build, Deploy, Secret, and the other Compose-only methods. Pass the service to Project.WithService.

Project. WithService, WithNetwork, WithVolume, WithSecret, WithJob, and WithModel.

Compose commands (selection). Full list: pkg.go.dev.

Group Commands
Lifecycle Up, Down, Create, Start, Stop, Restart, Kill, Rm, Run, Scale, Pause, Unpause
Observe Logs, Ps, Events, Top, Stats, Wait, Images, Ls, Port
Files / build / config Build, Pull, Push, Config, Export, Watch, Cp, Exec, Attach, Commit
Also Publish, Version, Volumes, Viz, Generate, LoadProject, Bridge* (see pkg.go.dev)

Engine client. Containers, images, networks, volumes, swarm, and plugins, plus interactive TTY in pkg/client/terminal. See pkg.go.dev/pkg/client.

Examples

Run from the repo root.

Path Path type What it shows
examples/simple Compose Minimal NewProject → Up
examples/wordpress Compose Multi-service, OS-conditional mounts, logs, signal Down
examples/profiles Compose Profiles mirrored on Up / Kill
examples/events Compose Events channel + healthcheck
examples/compose_commands Compose Build, Ps, Start, Stop, Restart, Exec, Config, Images, Top, Pause, Run
examples/nginx Hybrid client.ImageBuild then compose Up
examples/image_inline Hybrid Inline Dockerfile; Engine inspect skips a rebuild when the tag exists
examples/dockerfile Client Multi-stage NewDockerFile, Export, ImageBuild, ContainerCreate
examples/mongo_replica Hybrid Compose Up with Wait, then client exec to init a replica set
examples/terminal Client Interactive TTY exec + resize
examples/structs Config Mix Docker SDK structs with fluent methods
examples/taskflow Task graph pkg/taskflow: build, Compose Up, parallel test containers, retry, Down
examples/supabase Compose Full multi-profile stack. See its README
examples/astronomy_shop Task graph / Compose hybrid OpenTelemetry Astronomy Shop: profiles, health waits, kit-probe Dockerfile-as-Go, taskflow Build -> Up -> probe. See its README
go run ./examples/simple/
go run ./examples/supabase/                    # minimal
go run ./examples/supabase/ -profile full
go run ./examples/astronomy_shop/              # store + observability (default)
go run ./examples/astronomy_shop/ -follow

Migrating from go-contain

This project was renamed from go-contain.

Old New
github.com/aptd3v/go-contain github.com/aptd3v/containerkit
pkg/create, cc.WithImage, … pkg/kit, fluent .Image(), …
pkg/compose, up.WithRemoveOrphans() kit.NewCompose + &kit.Up{…}
pkg/client/options/** per-op structs on pkg/client (Remove, Exec, …)

Contributing

Issues and pull requests are welcome: issues · discussions

License

MIT. See LICENSE.

Directories

Path Synopsis
examples
astronomy_shop command
Package main: write embedded Astronomy Shop bind-mount assets under a volumes path.
Package main: write embedded Astronomy Shop bind-mount assets under a volumes path.
compose_commands command
This example demonstrates compose CLI commands: Build, Ps, Start, Stop, Restart, Exec, Config, Images, Top, Pause, Unpause, and Run.
This example demonstrates compose CLI commands: Build, Ps, Start, Stop, Restart, Exec, Config, Images, Top, Pause, Unpause, and Run.
dockerfile command
Write a multi-stage Dockerfile with NewDockerFile, build it with the Engine client, and serve it.
Write a multi-stage Dockerfile with NewDockerFile, build it with the Engine client, and serve it.
events command
This example shows how to use the events API to get real-time updates about the state of a service.
This example shows how to use the events API to get real-time updates about the state of a service.
image_inline command
Build an image if it doesn't exist, tag it, then run it.
Build an image if it doesn't exist, tag it, then run it.
mongo_replica command
This example demonstrates how to create a MongoDB replica set with x members and a Mongo Express instance to manage the replica set.
This example demonstrates how to create a MongoDB replica set with x members and a Mongo Express instance to manage the replica set.
nginx command
profiles command
this example shows how to use profiles to start a service with a specific profile
this example shows how to use profiles to start a service with a specific profile
simple command
This is a simple example of how to use containerkit to create a simple project.
This is a simple example of how to use containerkit to create a simple project.
structs command
this example shows how to use the structs to create a service if you prefer to use them
this example shows how to use the structs to create a service if you prefer to use them
supabase command
Package main: write embedded Supabase volume files to disk for the example.
Package main: write embedded Supabase volume files to disk for the example.
taskflow command
A CI-shaped task graph: build an image, bring a database up, run tests in parallel, retry a flaky step, then tag the image only when everything passed.
A CI-shaped task graph: build an image, bring a database up, run tests in parallel, retry a flaky step, then tag the image only when everything passed.
terminal command
in this example we will create a container and run a command in it to demonstrate the use of the terminal exec attach
in this example we will create a container and run a command in it to demonstrate the use of the terminal exec attach
wordpress command
pkg
client/response
Package response provides thin wrappers around the docker client response types.
Package response provides thin wrappers around the docker client response types.
client/terminal
Package terminal attaches a local terminal to a hijacked container stream.
Package terminal attaches a local terminal to a hijacked container stream.
kit
Package kit is a Go SDK for defining and running Docker containers.
Package kit is a Go SDK for defining and running Docker containers.
kit/types
Package types holds Docker Engine and Compose SDK wrappers used by kit.
Package types holds Docker Engine and Compose SDK wrappers used by kit.
taskflow
Package taskflow is an optional DAG runner for containerkit.
Package taskflow is an optional DAG runner for containerkit.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL