mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 15:51:26 +00:00
feat: real service runtime — private networks, replicas, lifecycle, rollback
Services now reconcile into actual Docker containers instead of
bookkeeping rows:
- Per-project bridge network with service-name DNS aliases and
${{service.KEY}} env expansion (HOST/PORT builtins)
- Replicas, published ports, Traefik domain routing, health checks,
restart policies persisted on the service spec; spec-hash drift
recreates containers on redeploy
- Lifecycle API: start/stop/restart/redeploy, live runtime state,
real image rollback (replaces the fake sleep)
- Manual scale and PUT replicas reconcile live containers; service
and project delete remove their containers and the project network
- Canvas: real URLs, replica badges, env filter, right-click
deploy/restart/stop/delete menu, empty state
- Service detail: real lifecycle buttons, live replica/URL strip,
Networking editor, ${{ }} variable helper
- Fix prebuilt-image pulls racing the tag (drain the pull stream)
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
c16b32f56a
commit
ff356230fe
20 files changed
+2270
-243
No files matched your search
@@ -3,6 +3,7 @@ package docker
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
@@ -50,6 +52,14 @@ func (c *Client) ListContainers(ctx context.Context, all bool) ([]types.Containe
|
||||
})
|
||||
}
|
||||
|
||||
// ListContainersFiltered returns containers matching the given filters.
|
||||
func (c *Client) ListContainersFiltered(ctx context.Context, f filters.Args, all bool) ([]types.Container, error) {
|
||||
return c.cli.ContainerList(ctx, container.ListOptions{
|
||||
All: all,
|
||||
Filters: f,
|
||||
})
|
||||
}
|
||||
|
||||
// GetContainer returns detailed information about a specific container
|
||||
func (c *Client) GetContainer(ctx context.Context, containerID string) (types.ContainerJSON, error) {
|
||||
return c.cli.ContainerInspect(ctx, containerID)
|
||||
@@ -63,6 +73,7 @@ func (c *Client) CreateContainer(ctx context.Context, config ContainerConfig) (s
|
||||
Env: config.Env,
|
||||
Labels: config.Labels,
|
||||
ExposedPorts: config.ExposedPorts,
|
||||
Healthcheck: config.Healthcheck,
|
||||
}
|
||||
|
||||
hostConfig := &container.HostConfig{
|
||||
@@ -168,7 +179,9 @@ func (c *Client) ListImages(ctx context.Context, all bool) ([]image.Summary, err
|
||||
})
|
||||
}
|
||||
|
||||
// PullImage pulls an image from a registry
|
||||
// PullImage pulls an image from a registry. The pull runs as the returned
|
||||
// stream is consumed — callers must drain and close it (or use
|
||||
// PullImageWait) or the pull may be aborted.
|
||||
func (c *Client) PullImage(ctx context.Context, ref string, auth registry.AuthConfig) (io.ReadCloser, error) {
|
||||
authStr, _ := registry.EncodeAuthConfig(auth)
|
||||
return c.cli.ImagePull(ctx, ref, image.PullOptions{
|
||||
@@ -176,6 +189,33 @@ func (c *Client) PullImage(ctx context.Context, ref string, auth registry.AuthCo
|
||||
})
|
||||
}
|
||||
|
||||
// PullImageWait pulls an image and blocks until the pull stream completes.
|
||||
func (c *Client) PullImageWait(ctx context.Context, ref string, auth registry.AuthConfig) error {
|
||||
reader, err := c.PullImage(ctx, ref, auth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer reader.Close()
|
||||
// The daemon performs the pull while streaming progress; drain it fully
|
||||
// and surface any errorDetail the daemon reports in the stream.
|
||||
dec := json.NewDecoder(reader)
|
||||
var msg struct {
|
||||
ErrorDetail *struct {
|
||||
Message string `json:"message"`
|
||||
} `json:"errorDetail"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
for dec.Decode(&msg) == nil {
|
||||
if msg.ErrorDetail != nil {
|
||||
return fmt.Errorf("%s", msg.ErrorDetail.Message)
|
||||
}
|
||||
if msg.Error != "" {
|
||||
return fmt.Errorf("%s", msg.Error)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BuildImage builds an image from a Dockerfile
|
||||
func (c *Client) BuildImage(ctx context.Context, buildContext io.Reader, options BuildOptions) (types.ImageBuildResponse, error) {
|
||||
return c.cli.ImageBuild(ctx, buildContext, types.ImageBuildOptions{
|
||||
|
||||
Reference in new issue
Block a user