Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Binaries
flatrun-agent
__debug_bin*
/agent
flatrun-linux-*
*.exe
Expand Down Expand Up @@ -41,3 +42,6 @@ config.yaml
tmp/
temp/
.tmp/

# Deployments
deployments/
19 changes: 19 additions & 0 deletions cmd/agent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"log"
"os"
"os/exec"
"os/signal"
"syscall"

Expand Down Expand Up @@ -42,6 +43,15 @@ func main() {
log.Fatalf("Failed to load config from %s: %v", resolvedConfigPath, err)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using exec.Command("docker", "info") relies on the docker CLI being installed in the PATH. Since you've added the moby/moby client dependency, it is more efficient and reliable to check connectivity using the library's Ping() or Info() methods instead of spawning a shell process.

Suggested change
}
func ensureDockerReachable(socket string) {
ctx := context.Background()
cli, err := client.NewClientWithOpts(client.WithHost(socket), client.WithAPIVersionNegotiation())
if err != nil {
log.Fatalf("Failed to create Docker client: %v", err)
}
defer cli.Close()
if _, err := cli.Ping(ctx); err != nil {
log.Fatalf("Docker is not reachable: %v", err)
}
}


os.Setenv("DOCKER_HOST", cfg.DockerSocket)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting DOCKER_HOST globally via os.Setenv can cause side effects if other parts of the application or third-party libraries expect a different environment. Since you've already added the Moby client, it is better to pass the socket explicitly to constructors rather than relying on global environment variables.

Suggested change
os.Setenv("DOCKER_HOST", cfg.DockerSocket)
ensureDockerReachable(cfg.DockerSocket)

log.Printf("Using Docker socket from config: %s", cfg.DockerSocket)

ensureDockerReachable(cfg.DockerSocket)

if err := os.MkdirAll(cfg.DeploymentsPath, 0755); err != nil {
log.Fatalf("Failed to create deployments directory '%s': %v", cfg.DeploymentsPath, err)
}

log.Printf("Starting Flatrun Agent v%s", version.Version)
log.Printf("Config loaded from: %s", resolvedConfigPath)
log.Printf("Deployments path: %s", cfg.DeploymentsPath)
Expand Down Expand Up @@ -70,6 +80,15 @@ func main() {
_ = apiServer.Stop()
}

func ensureDockerReachable(_ string) {
Copy link
Contributor

@nfebe nfebe Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The os.Setenv("DOCKER_HOST") above unconditionally overwrites the env var even when empty, and this function accepts a socket param but ignores it (_ string). There is also no timeout a hanging daemon blocks startup forever.

Let's use the Docker Go SDK instead: client.NewClientWithOpts(client.FromEnv) + client.Ping(ctx) handles host resolution, timeouts via context, and doesn't need the docker binary in PATH.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use github.com/compose-spec/compose-go just did not want add to do just one thing

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous review suggested using the Moby client library's Ping() or Info() instead of exec.Command("docker", "info"). This implementation still uses the shell command, which depends on the CLI being installed in the PATH and carries more overhead than an API call.

Suggested change
func ensureDockerReachable(_ string) {
func ensureDockerReachable(socket string) {
log.Println("Checking if Docker is reachable...")
ctx := context.Background()
cli, err := client.NewClientWithOpts(client.WithHost(socket), client.WithAPIVersionNegotiation())
if err != nil {
log.Fatalf("Failed to create Docker client: %v", err)
}
defer cli.Close()
if _, err := cli.Ping(ctx); err != nil {
log.Fatalf("Docker is not reachable: %v", err)
}
log.Println("Docker is reachable")
}

log.Println("Checking if Docker is reachable...")
cmd := exec.Command("docker", "info")
if _, err := cmd.CombinedOutput(); err != nil {
log.Fatalf("Docker is not reachable: Ensure the Docker daemon is running and docker socket in config is correct (e.g. unix:///var/run/docker.sock).")
}
log.Println("Docker is reachable")
}

func printVersion() {
info := version.Get()
fmt.Printf("Flatrun Agent\n")
Expand Down
2 changes: 1 addition & 1 deletion config.example.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
deployments_path: /home/nfebe/work/deployments
deployments_path: ./deployments
docker_socket: unix:///var/run/docker.sock
api:
host: 0.0.0.0
Expand Down
41 changes: 37 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/aws/aws-sdk-go-v2/credentials v1.19.6
github.com/aws/aws-sdk-go-v2/service/route53 v1.62.0
github.com/cloudflare/cloudflare-go v0.116.0
github.com/compose-spec/compose-go v1.20.2
github.com/creack/pty v1.1.24
github.com/digitalocean/godo v1.171.0
github.com/fsnotify/fsnotify v1.7.0
Expand All @@ -27,6 +28,7 @@ require (

require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/aws/aws-sdk-go-v2 v1.41.0 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect
Expand All @@ -41,29 +43,60 @@ require (
github.com/aws/smithy-go v1.24.0 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-connections v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.14.0 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/moby/api v1.53.0 // indirect
github.com/moby/moby/client v0.2.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.9.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
golang.org/x/time v0.11.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gotest.tools/v3 v3.5.2 // indirect
)
Loading
Loading