go-contain

module
v0.1.7 Latest Latest
Warning

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

Go to latest
Published: Jul 24, 2025 License: MIT

README

go-contain

go-contain brings declarative, dynamic Docker Compose to Go. Programmatically define, extend, and orchestrate multi-container environments with the flexibility of code, all while staying fully compatible with existing YAML workflows.

Go Version Go Reference Go Report Card

Features

  • Support for Docker Compose commands up, down, logs, (more coming soon!)
  • Declarative container/service creation with chainable options
  • Native Go option setters for containers, networks, volumes, and health checks etc.
  • IDE-friendly
  • Designed for automation, CI/CD pipelines, and advanced dev environments

Why go-contain?

While Docker Compose YAML files work great for simple, static configurations, go-contain unlocks the full power of programmatic infrastructure definition. Here's why you might choose go-contain over traditional approaches:

Programmatic Infrastructure Control
// Generate infrastructure from data, APIs, configs - A real pain with static YAML

//// Generate a unique environment for each microservice from a config object.
func setupEnvironment(envConfig EnvironmentConfig) *create.Project {
    project := create.NewProject(envConfig.Name)
    
    // Generate services from database records, API responses, etc.
    for _, service := range envConfig.Services {
        replicas := envConfig.GetReplicas(service.Name)
        
        for i := 0; i < replicas; i++ {
            project.WithService(fmt.Sprintf("%s-%d", service.Name, i),
                create.NewContainer(service.Name).
                    WithContainerConfig(
                        cc.WithImagef("%s:%s", service.Image, envConfig.Version),
                        cc.WithEnv("INSTANCE_ID", strconv.Itoa(i)),
                        cc.WithEnv("ENVIRONMENT", envConfig.Environment),
                    ).
                    WithHostConfig(
                        hc.WithPortBindings("tcp", "0.0.0.0", 
                            strconv.Itoa(8080+i), "8080"),
                    ),
            )
        }
    }
    return project
}

// Call with live data from your application
envConfig := fetchEnvironmentFromAPI()
project := setupEnvironment(envConfig)
compose.NewCompose(project).Up(context.Background())
# Docker Compose scaling creates IDENTICAL containers - no per-instance customization
version: '3.8'
services:
  api:
    image: myapp:v1.2.3
    environment:
      - ENVIRONMENT=production
      # All scaled instances get the SAME environment variables
      # No way to give each replica different INSTANCE_ID or ports
    ports:
      - "8080:8080"  # Port conflicts when scaling!

# docker compose up --scale api=3
# ↑ Creates 3 identical containers, but:
# - All have the same environment variables
# - Port binding conflicts (all try to bind to 8080)
# - No way to customize individual instances
Dynamic & Conditional Configuration
// Environment-based logic, loops, and conditionals
for _, env := range []string{"dev", "staging", "prod"} {
    project.WithService(fmt.Sprintf("api-%s", env),
    	create.NewContainer().
            WithContainerConfig(
                cc.WithImagef("myapp:%s", env),
                tools.WhenTrue(env == "prod", 
                    cc.WithEnv("CACHE_ENABLED", "true"),
                ),
            ),
    )
}

// Static configuration requires multiple files or templating
// No native support for conditionals or loops
Code Reusability & Composition
// Create reusable components and patterns
func DatabaseContainer(name, version string)  *create.Container {
    return create.NewContainer().
        WithContainerConfig(
            cc.WithImagef("postgres:%s", version),
            cc.WithEnv("POSTGRES_DB", name),
        ).
        WithHostConfig(
            hc.WithPortBindings("tcp", "0.0.0.0", "5432", "5432"),
        )
}

func RedisContainer() *create.Container {
    return create.NewContainer().
        WithContainerConfig(
            cc.WithImage("redis:7-alpine"),
        ).
        WithHostConfig(
            hc.WithPortBindings("tcp", "0.0.0.0", "6379", "6379"),
        )
}

// Microservices architecture - each service gets its own database
project.WithService("user-service-db", DatabaseContainer("users", "latest"))
project.WithService("user-service-cache", RedisContainer())
project.WithService("order-service-db", DatabaseContainer("orders", "latest"))
project.WithService("order-service-cache", RedisContainer())
Perfect for Automation & CI/CD
// Integrate with existing Go tools and workflows
func DeployEnvironment(ctx context.Context, env string, replicas int) error {
    project := create.NewProject(fmt.Sprintf("app-%s", env))
    
    // Build services programmatically based on parameters
    for i := 0; i < replicas; i++ {
        project.WithService(fmt.Sprintf("worker-%d", i), 
            // ... configure based on env and replica count
        )
    }
    
    compose := compose.NewCompose(project)
    return compose.Up(ctx, up.WithDetach())
}
Portable Container Configuration

In go-contain the underlying docker sdk is also wrapped as well, allowing you to use the same configuration for docker client control, and compose.

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/aptd3v/go-contain/pkg/client"
	"github.com/aptd3v/go-contain/pkg/create"
	"github.com/aptd3v/go-contain/pkg/create/config/cc"
)

func main() {
	cli, err := client.NewClient()
	if err != nil {
		log.Fatalf("Error creating client: %v", err)
	}
	// Reuse the same config to create a container using the Docker SDK
	resp, err := cli.ContainerCreate(
		context.Background(),
		MySimpleContainer("latest"),
	)
	if err != nil {
		log.Fatalf("Error creating container: %v", err)
	}
	fmt.Println(resp.ID) //container id

	//create a compose project with the same container configuration
	project := create.NewProject("my-project")

	project.WithService("simple-service", MySimpleContainer("latest"))

	err = project.Export("./docker-compose.yml", 0644)
	if err != nil {
		log.Fatalf("Error exporting project: %v", err)
	}

}

func MySimpleContainer(tag string) *create.Container {
	return create.NewContainer().
		WithContainerConfig(
			cc.WithImagef("alpine:%s", tag),
			cc.WithCommand("echo", "hello world"),
		)
}

Leverage Go's Ecosystem
  • Testing: Write unit tests for your infrastructure code
  • Debugging: Use Go's debugging tools and error handling
  • Libraries: Integrate with any Go package (HTTP clients, databases, etc.)
  • Tooling: Build CLIs, APIs, and automation around your containers
Still Docker Compose Compatible
// Export to standard YAML when needed
if err := project.Export("./docker-compose.yaml", 0644); err != nil {
    log.Fatal(err)
}
// Now use with: docker compose up -d

go-contain gives you the best of both worlds: the flexibility and power of Go programming with full compatibility with the Docker Compose ecosystem.


Prerequisites

  • Go: 1.23+
  • Docker: 28.2.0+ with Docker Compose v2.37.0
  • Operating System: Linux, macOS, or Windows

Installation

go get github.com/aptd3v/go-contain@latest

Quick Start

Get up and running in 30 seconds:

# Create a new Go module
mkdir my-containers && cd my-containers
go mod init my-containers
go get github.com/aptd3v/go-contain@latest

Create main.go

package main

import (
	"context"
	"github.com/aptd3v/go-contain/pkg/compose"
	"github.com/aptd3v/go-contain/pkg/create"
	"github.com/aptd3v/go-contain/pkg/create/config/cc"
)

func main() {
	project := create.NewProject("hello-world")
	project.WithService("hello-service", 
		create.NewContainer().
			WithContainerConfig(
				cc.WithImage("alpine:latest"),
				cc.WithCommand("echo", "Hello from go-contain!"),
			),
	)
	
	compose.NewCompose(project).Up(context.Background())
}

Run it

go run main.go

Basic Usage

package main

import (
	"context"
	"log"
	"os"

	"github.com/aptd3v/go-contain/pkg/compose"
	"github.com/aptd3v/go-contain/pkg/compose/options/up"
	"github.com/aptd3v/go-contain/pkg/create"
	"github.com/aptd3v/go-contain/pkg/create/config/cc"
)

func main() {

	project := create.NewProject("my-app")

	project.WithService("my-service",
		create.NewContainer("my-container").
			WithContainerConfig(
				cc.WithImage("alpine:latest"),
				cc.WithCommand("tail", "-f", "/dev/null"),
			),
	)
	//export yaml if desired. (not needed)
	if err := project.Export("./docker-compose.yaml", 0644); err != nil {
		log.Fatal(err)
	}
	//create a new compose instance
	compose := compose.NewCompose(project)

	//execute the up command
	err := compose.Up(
		context.Background(),
		up.WithWriter(os.Stdout),
		up.WithRemoveOrphans(),
		up.WithDetach(),
	)
	if err != nil {
		log.Fatal(err)
	}
}

Declarative Container Configuration

Each setter type is defined in its own package

project.WithService("api",
	create.NewContainer("my-api-container").
        WithContainerConfig(
			//cc == container config
            cc.WithImagef("ubuntu:%s", tag)
        ).
        WithHostConfig(
			// hc == host config
            hc.WithPortBindings("tcp", "0.0.0.0", "8080", "80"),
        ).
        WithNetworkConfig(
			// nc == network config
            nc.WithEndpoint("my-network"),
        ).
        WithPlatformConfig(
			//pc == platform config
            pc.WithArchitecture("amd64"),
        ),
)

Or use underlying docker SDK structs if desired

Check out examples/structs to see how using both can be useful.

project.WithService("api", &create.Container{
		Config: &create.MergedConfig{
			Container: &container.Config{
				Image: fmt.Sprintf("ubuntu:%s", tag),
			},
			Host: &container.HostConfig{
				PortBindings: nat.PortMap{
					"8080/tcp": []nat.PortBinding{
						{
							HostIP:   "0.0.0.0",
							HostPort: "8080",
						},
					},
				},
			},
			Network: &network.NetworkingConfig{
				EndpointsConfig: map[string]*network.EndpointSettings{
					"my-network": {
						Aliases: []string{"my-api-container"},
					}},
			},
			Platform: &ocispec.Platform{
				Architecture: "amd64",
			},
		},
	})

tools Package: Declarative Logic for Setters

The tools package provides composable helpers for conditional configuration. These are useful when flags, environment variables, or dynamic inputs control what options get applied.

Highlights
  • tools.WhenTrue(...) – Apply setters only if a boolean is true
  • tools.WhenTrueFn(...) – Like above, but accepts predicate closure func() bool
  • tools.OnlyIf(...) – Apply a setter only if a runtime check passes func () (bool, error)
  • tools.Group(...) – Combine multiple setters into one func[T any, O ~func(T) error](fns ...O) O
  • tools.And(...), tools.Or(...) – Compose multiple predicate closures
Example
package main

import (
	"context"
	"log"
	"os"
	"runtime"

	"github.com/aptd3v/go-contain/pkg/compose"
	"github.com/aptd3v/go-contain/pkg/create"
	"github.com/aptd3v/go-contain/pkg/create/config/cc"
	"github.com/aptd3v/go-contain/pkg/create/config/hc"
	"github.com/aptd3v/go-contain/pkg/create/config/nc"
	"github.com/aptd3v/go-contain/pkg/create/config/sc"
	"github.com/aptd3v/go-contain/pkg/tools"
)

func main() {
	enableDebug := true //imagine this is a flag from your cli or something
	isLinux := runtime.GOOS == "linux"
	project := create.NewProject("conditional-env")
	envVars := tools.Group(
		cc.WithEnv("MYSQL_ROOT_PASSWORD", "password"),
		cc.WithEnv("MYSQL_DATABASE", "mydb"),
		cc.WithEnv("MYSQL_USER", "myuser"),
		cc.WithEnv("MYSQL_PASSWORD", "mypassword"),

		tools.WhenTrueFn(
			tools.Or(enableDebug, os.Getenv("NODE_ENV") == "development"),
			cc.WithEnv("DEBUG", "true"),
		),
	)

	project.WithService("express",
		create.NewContainer().
			WithContainerConfig(
				cc.WithImage("node:latest"),
				cc.WithCommand("npm", "start"),
				envVars,
			).
			WithHostConfig(
				tools.WhenTrueElse(isLinux,//if
					hc.WithRWNamedVolumeMount("node-data", "/app"),//true 
					hc.WithVolumeBinds("./:/app/:rw"),//else 
				),
			).
			WithNetworkConfig(
				nc.WithEndpoint("express-network"),
			),
		// service level configuration
		tools.OnlyIf(EnvFileExists(".ThisFileDoesNotExist.env"),
			sc.WithEnvFile(".ThisFileDoesNotExist.env"),
		),
	).
		WithNetwork("express-network").
		WithVolume("node-data")

	compose := compose.NewCompose(project)

	if err := compose.Up(context.Background()); err != nil {
		// will output .ThisFileDoesNotExist.env: no such file or directory
		log.Fatal(err)

	}
}
// CheckClosure is just a func() (bool, error)
func EnvFileExists(name string) tools.CheckClosure {
	return func() (bool, error) {
		_, err := os.Stat(name)
		if err != nil {
			return false, err
		}
		return true, nil
	}
}
Examples

Explore examples in the examples/ directory:

Getting Help

Roadmap

Current Features
  • ✅ Core Compose commands: up, down, logs
  • ✅ Container, network, and volume service configuration
  • ✅ Conditional logic with tools package
  • ✅ YAML export for compatibility
In Development
  • Additional Compose commands: restart, stop, start, ps
  • Enhanced Docker SDK client features
  • Image registry authentication helpers
  • More comprehensive test coverage
Ideas & Suggestions

Have ideas for go-contain? We'd love to hear them! Open an issue or start a discussion.

License

MIT License. See LICENSE for details.

Contributions

Contributions, feedback, and issues are welcome! Fork the repo and submit a PR or open an issue with your idea.

Directories

Path Synopsis
examples
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
this program runs and builds the image if it does not exist and then tags it with a label and then uses the image for a container the second time it runs
this program runs and builds the image if it does not exist and then tags it with a label and then uses the image for a container the second time it runs
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 go-contain to create a simple project.
This is a simple example of how to use go-contain 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
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/options/container/attach
package attach provides options for the container attach.
package attach provides options for the container attach.
client/options/container/checkpointcreate
package checkpointcreate provides options for the container checkpoint create.
package checkpointcreate provides options for the container checkpoint create.
client/options/container/checkpointdelete
package checkpointdelete provides options for the container checkpoint delete.
package checkpointdelete provides options for the container checkpoint delete.
client/options/container/checkpointlist
package checkpointlist provides options for the container checkpoint list.
package checkpointlist provides options for the container checkpoint list.
client/options/container/commit
package commit provides options for the container commit.
package commit provides options for the container commit.
client/options/container/copyto
package copyto provides options for the container copy to container.
package copyto provides options for the container copy to container.
client/options/container/execattach
package execattach provides options for the container exec attach.
package execattach provides options for the container exec attach.
client/options/container/execopt
package execopt provides options for the container exec create.
package execopt provides options for the container exec create.
client/options/container/execresize
package execresize provides options for the container exec resize.
package execresize provides options for the container exec resize.
client/options/container/execstart
package execstart provides options for the container exec start.
package execstart provides options for the container exec start.
client/options/container/list
Package list provides the options for the container list options
Package list provides the options for the container list options
client/options/container/logs
package logs provides options for the container logs.
package logs provides options for the container logs.
client/options/container/prune
package prune provides options for the container prune.
package prune provides options for the container prune.
client/options/container/remove
Package remove provides the options for the container remove options
Package remove provides the options for the container remove options
client/options/container/start
Package start provides the options for the container start options
Package start provides the options for the container start options
client/options/container/stop
Package stop provides the options for the container stop options
Package stop provides the options for the container stop options
client/options/container/update
package update provides options for the container update.
package update provides options for the container update.
client/options/container/wait
Package wait provides options for container wait.
Package wait provides options for container wait.
client/options/image/build
package build provides options for the image build.
package build provides options for the image build.
client/options/image/create
package create provides options for the image create.
package create provides options for the image create.
client/options/image/imports
Package imports provides options for image import.
Package imports provides options for image import.
client/options/image/list
package list provides options for the image list.
package list provides options for the image list.
client/options/image/load
Package load provides options for image load.
Package load provides options for image load.
client/options/image/prune
Package prune provides options for image prune.
Package prune provides options for image prune.
client/options/image/pull
package pull provides options for the image pull.
package pull provides options for the image pull.
client/options/image/remove
Package remove provides options for image remove.
Package remove provides options for image remove.
client/options/image/save
Package save provides options for image save.
Package save provides options for image save.
client/options/image/search
Package search provides options for image search.
Package search provides options for image search.
client/options/network/connect
package connect provides options for the network connect.
package connect provides options for the network connect.
client/options/network/create
package create provides options for the network create.
package create provides options for the network create.
client/options/network/create/ipam
package ipam provides options for the network IPAM.
package ipam provides options for the network IPAM.
client/options/network/create/ipam/ipamconfig
package ipamconfig provides options for the network IPAM config.
package ipamconfig provides options for the network IPAM config.
client/options/network/inspect
package inspect provides options for the network inspect.
package inspect provides options for the network inspect.
client/options/network/list
package list provides options for the network list.
package list provides options for the network list.
client/options/network/prune
package prune provides options for the network prune.
package prune provides options for the network prune.
client/options/swarm/swarminit
Package swarminit provides options for the swarm init command.
Package swarminit provides options for the swarm init command.
client/options/swarm/swarmjoin
Package swarmjoin provides options for the swarm join command.
Package swarmjoin provides options for the swarm join command.
client/options/volume/create
package create provides options for the volume create.
package create provides options for the volume create.
client/options/volume/create/clusterspec
package clusterspec provides options for the volume cluster volume spec.
package clusterspec provides options for the volume cluster volume spec.
client/options/volume/create/clusterspec/accessibility
package accessibility provides options for the volume cluster volume spec accessibility requirements.
package accessibility provides options for the volume cluster volume spec accessibility requirements.
client/options/volume/create/clusterspec/accessmode
package accessmode provides options for the volume cluster volume spec access mode.
package accessmode provides options for the volume cluster volume spec access mode.
client/options/volume/list
Package list provides options for volume list operations.
Package list provides options for volume list operations.
client/options/volume/prune
Package vpo provides options for volume prune operations.
Package vpo provides options for volume prune operations.
client/options/volume/update
Package vuo provides options for volume update operations.
Package vuo provides options for volume update operations.
client/response
Package response provides thin wrappers around the docker client response types.
Package response provides thin wrappers around the docker client response types.
compose
package compose is a wrapper around the docker compose cli.
package compose is a wrapper around the docker compose cli.
compose/options/down
Package down is the package for the compose down options
Package down is the package for the compose down options
compose/options/kill
Package kill is the package for the compose kill options
Package kill is the package for the compose kill options
compose/options/logs
Package logs is the package for the compose logs options
Package logs is the package for the compose logs options
compose/options/up
Package up provides options for the compose up command
Package up provides options for the compose up command
create
Package create provides the container config for the wrapped client.
Package create provides the container config for the wrapped client.
create/config/cc
Package cc provides the options for the container config.
Package cc provides the options for the container config.
create/config/hc
Package hc provides the options for the host config.
Package hc provides the options for the host config.
create/config/hc/mount
Package mount provides the options for the mount config in the host config.
Package mount provides the options for the mount config in the host config.
create/config/nc
Package nc provides the options for the network config.
Package nc provides the options for the network config.
create/config/nc/endpoint
Package endpoint provides the options for the endpoint config in the network config.
Package endpoint provides the options for the endpoint config in the network config.
create/config/nc/endpoint/ipam
Package ipam provides the options for the IPAM config in the endpoint config.
Package ipam provides the options for the IPAM config in the endpoint config.
create/config/pc
Package pc provides the options for the platform config.
Package pc provides the options for the platform config.
create/config/sc
Package sc provides functions to set the service config
Package sc provides functions to set the service config
create/config/sc/build
Package build provides functions to set the build config for a service
Package build provides functions to set the build config for a service
create/config/sc/build/ulimit
Package ulimit provides a set of functions to configure the ulimits for the build
Package ulimit provides a set of functions to configure the ulimits for the build
create/config/sc/deploy
Package deploy provides functions to set the deploy configuration for a service
Package deploy provides functions to set the deploy configuration for a service
create/config/sc/deploy/resource
Package resource provides functions to set the resource configuration for a service deploy
Package resource provides functions to set the resource configuration for a service deploy
create/config/sc/deploy/resource/device
Package device provides functions to set the device configuration for a service deploys resource
Package device provides functions to set the device configuration for a service deploys resource
create/config/sc/deploy/update
Package update provides functions to set the update configuration for a service deploy
Package update provides functions to set the update configuration for a service deploy
create/config/sc/network
Package network provides functions to set the network configuration for a project
Package network provides functions to set the network configuration for a project
create/config/sc/network/pool
Package pool provides functions to set the ipam pool configuration for a project
Package pool provides functions to set the ipam pool configuration for a project
create/config/sc/secrets/projectsecret
Package projectsecret provides a set of functions to configure the secret for the project
Package projectsecret provides a set of functions to configure the secret for the project
create/config/sc/secrets/secretservice
Package secretservice provides a set of functions to configure the secrets for the service
Package secretservice provides a set of functions to configure the secrets for the service
create/config/sc/volume
Package volume provides functions to set the volume configuration for a project
Package volume provides functions to set the volume configuration for a project
terminal
Package terminal
Package terminal
tools
Package tools provides various helpers for writing declarative option setters.
Package tools provides various helpers for writing declarative option setters.

Jump to

Keyboard shortcuts

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