Merge pull request #97 from Nemental/feat/docker-socket-protocol

feat: docker socket protocol
This commit is contained in:
Owen Schwartz
2025-08-30 16:53:21 -07:00
committed by GitHub
3 changed files with 64 additions and 11 deletions

View File

@@ -229,7 +229,27 @@ Newt can integrate with the Docker socket to provide remote inspection of Docker
**Configuration:**
You can specify the Docker socket path using the `--docker-socket` CLI argument or by setting the `DOCKER_SOCKET` environment variable. On most linux systems the socket is `/var/run/docker.sock`. When deploying newt as a container, you need to mount the host socket as a volume for the newt container to access it. If the Docker socket is not available or accessible, Newt will gracefully disable Docker integration and continue normal operation.
You can specify the Docker socket path using the `--docker-socket` CLI argument or by setting the `DOCKER_SOCKET` environment variable. If the Docker socket is not available or accessible, Newt will gracefully disable Docker integration and continue normal operation.
Supported values include:
- Local UNIX socket (default):
>You must mount the socket file into the container using a volume, so Newt can access it.
`unix:///var/run/docker.sock`
- TCP socket (e.g., via Docker Socket Proxy):
`tcp://localhost:2375`
- HTTP/HTTPS endpoints (e.g., remote Docker APIs):
`http://your-host:2375`
- SSH connections (experimental, requires SSH setup):
`ssh://user@host`
```yaml
services:
@@ -243,8 +263,9 @@ services:
- PANGOLIN_ENDPOINT=https://example.com
- NEWT_ID=2ix2t8xk22ubpfy
- NEWT_SECRET=nnisrfsdfc7prqsp9ewo1dvtvci50j5uiqotez00dgap0ii2
- DOCKER_SOCKET=/var/run/docker.sock
- DOCKER_SOCKET=unix:///var/run/docker.sock
```
>If you previously used just a path like `/var/run/docker.sock`, it still works — Newt assumes it is a UNIX socket by default.
#### Hostnames vs IPs

View File

@@ -53,22 +53,55 @@ type Network struct {
DNSNames []string `json:"dnsNames,omitempty"`
}
// Strcuture parts of docker api endpoint
type dockerHost struct {
protocol string // e.g. unix, http, tcp, ssh
address string // e.g. "/var/run/docker.sock" or "host:port"
}
// Parse the docker api endpoint into its parts
func parseDockerHost(raw string) (dockerHost, error) {
switch {
case strings.HasPrefix(raw, "unix://"):
return dockerHost{"unix", strings.TrimPrefix(raw, "unix://")}, nil
case strings.HasPrefix(raw, "ssh://"):
// SSH is treated as TCP-like transport by the docker client
return dockerHost{"ssh", strings.TrimPrefix(raw, "ssh://")}, nil
case strings.HasPrefix(raw, "tcp://"), strings.HasPrefix(raw, "http://"), strings.HasPrefix(raw, "https://"):
s := raw
s = strings.TrimPrefix(s, "tcp://")
s = strings.TrimPrefix(s, "http://")
s = strings.TrimPrefix(s, "https://")
return dockerHost{"tcp", s}, nil
default:
// default fallback to unix
return dockerHost{"unix", raw}, nil
}
}
// CheckSocket checks if Docker socket is available
func CheckSocket(socketPath string) bool {
// Use the provided socket path or default to standard location
if socketPath == "" {
socketPath = "/var/run/docker.sock"
socketPath = "unix:///var/run/docker.sock"
}
// Try to create a connection to the Docker socket
conn, err := net.Dial("unix", socketPath)
host, err := parseDockerHost(socketPath)
if err != nil {
logger.Debug("Docker socket not available at %s: %v", socketPath, err)
logger.Debug("Invalid Docker socket path '%s': %v", socketPath, err)
return false
}
protocol := host.protocol
addr := host.address
// ssh might need different verification, but tcp works for basic reachability
conn, err := net.DialTimeout(protocol, addr, 2*time.Second)
if err != nil {
logger.Debug("Docker not reachable via %s at %s: %v", protocol, addr, err)
return false
}
defer conn.Close()
logger.Debug("Docker socket is available at %s", socketPath)
logger.Debug("Docker reachable via %s at %s", protocol, addr)
return true
}
@@ -132,7 +165,7 @@ func ListContainers(socketPath string, enforceNetworkValidation bool) ([]Contain
// Create client with custom socket path
cli, err := client.NewClientWithOpts(
client.WithHost("unix://"+socketPath),
client.WithHost(socketPath),
client.WithAPIVersionNegotiation(),
)
if err != nil {
@@ -182,7 +215,6 @@ func ListContainers(socketPath string, enforceNetworkValidation bool) ([]Contain
hostname = containerInfo.Config.Hostname
}
// Skip host container if set
if hostContainerId != "" && c.ID == hostContainerId {
continue

View File

@@ -173,7 +173,7 @@ func main() {
flag.StringVar(&tlsPrivateKey, "tls-client-cert", "", "Path to client certificate used for mTLS")
}
if dockerSocket == "" {
flag.StringVar(&dockerSocket, "docker-socket", "", "Path to Docker socket (typically /var/run/docker.sock)")
flag.StringVar(&dockerSocket, "docker-socket", "", "Path or address to Docker socket (typically unix:///var/run/docker.sock)")
}
if pingIntervalStr == "" {
flag.StringVar(&pingIntervalStr, "ping-interval", "3s", "Interval for pinging the server (default 3s)")