mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 07:41:27 +00:00
feat: build-on-node — git checkouts, remote image builds, image transport (#60)
Git-sourced deploys never materialized a checkout: sourcePath was build_path resolved against the server cwd, so builds consumed the backend's own directory. Remote placement could only run registry-pulled images. - internal/source: per-deployment checkout (init/fetch/checkout) at branch or commit; GIT_ASKPASS keeps tokens out of argv, .git/config, and the build context; dumb-transport and SHA-refusal fallbacks; build_path validated inside the checkout. - BuildManager.PackageContext: produces the same tar context Build ships to the daemon — generated Dockerfile at tar root, .git excluded. Fixes nixpacks passing the Dockerfile path as content. - Agent artifact endpoint: GET /api/agents/artifacts/:id streams build contexts and docker-save tarballs behind agent-token auth; hex-validated ids, per-deployment cleanup, boot-time purge. - Agent commands: build_image (docker build -, --build-arg values via process env, not argv) and load_image (docker load for containr-* rollback tags no registry serves). - Deployment flow: remote git builds package context → artifact → node docker-builds the deployment tag; remote rollbacks of local tags export via SaveImage → artifact → node docker-loads. Verified end-to-end: agent-pinned git service built on the node (build_image → create_container → deployed) and rollback shipped a docker-save tarball (load_image → deployed). Artifact auth returns 401/404 correctly; workspaces and blobs are removed after deploy. Authored By: TDvorak <[email protected]>
This commit is contained in:
1 parent
d57ac72aa5
commit
3cc84553f4
18 files changed
+1020
-51
No files matched your search
@@ -95,12 +95,29 @@ type ServiceConfig struct {
|
||||
// reuses it so public URLs survive restarts. 0 = pick ephemeral.
|
||||
PublishedPort int32 `json:"published_port,omitempty"`
|
||||
// NodeID pins the service to a registered node agent; "" = local Docker
|
||||
// host. Remote placement requires a registry-pullable image — builds stay
|
||||
// on the local host (build-on-node is not yet supported).
|
||||
// host.
|
||||
NodeID string `json:"node_id,omitempty"`
|
||||
// Spread distributes replicas across every online, schedulable agent.
|
||||
// Same registry-image constraint as NodeID.
|
||||
Spread bool `json:"spread,omitempty"`
|
||||
// RemoteBuild, when set, makes each target node docker-build the image
|
||||
// itself from a packaged context artifact instead of pulling a registry
|
||||
// tag. The image name comes from the deployment, not the spec.
|
||||
RemoteBuild *RemoteBuildSpec `json:"remote_build,omitempty"`
|
||||
// RemoteLoad ships a docker-save tarball to each target node — used for
|
||||
// rollbacks of locally-built tags that no registry can serve.
|
||||
RemoteLoad *RemoteLoadSpec `json:"remote_load,omitempty"`
|
||||
}
|
||||
|
||||
// RemoteBuildSpec is the agent-side docker build request.
|
||||
type RemoteBuildSpec struct {
|
||||
ArtifactID string `json:"artifact_id"`
|
||||
BuildArgs map[string]string `json:"build_args,omitempty"`
|
||||
NoCache bool `json:"no_cache,omitempty"`
|
||||
}
|
||||
|
||||
// RemoteLoadSpec asks the agent to docker-load an image tarball artifact.
|
||||
type RemoteLoadSpec struct {
|
||||
ArtifactID string `json:"artifact_id"`
|
||||
}
|
||||
|
||||
type PortMapping struct {
|
||||
@@ -211,6 +228,12 @@ func (de *DeploymentEngine) DockerClient() *docker.Client {
|
||||
return de.dockerClient
|
||||
}
|
||||
|
||||
// BuildManager exposes the engine's builders for context packaging — remote
|
||||
// nodes build the tar this produces themselves.
|
||||
func (de *DeploymentEngine) BuildManager() *build.BuildManager {
|
||||
return de.buildManager
|
||||
}
|
||||
|
||||
// SetNodeRunner wires remote-node dispatch for services pinned to an agent.
|
||||
func (de *DeploymentEngine) SetNodeRunner(r NodeRunner) {
|
||||
de.nodeRunner = r
|
||||
@@ -326,11 +349,19 @@ func (de *DeploymentEngine) executeDeployment(ctx context.Context, deployment *D
|
||||
})
|
||||
}
|
||||
|
||||
// buildImage builds the container image
|
||||
// buildImage builds the container image. "remote" build types produce no
|
||||
// local image — the target node builds or loads it from an artifact; the
|
||||
// deployment still needs a deterministic tag so every node names it alike.
|
||||
func (de *DeploymentEngine) buildImage(ctx context.Context, deployment *Deployment, buildConfig *BuildConfig) (string, error) {
|
||||
if buildConfig == nil {
|
||||
return "", fmt.Errorf("build config is required")
|
||||
}
|
||||
if buildConfig.BuildType == "remote" {
|
||||
if buildConfig.PrebuiltImage != "" {
|
||||
return buildConfig.PrebuiltImage, nil
|
||||
}
|
||||
return fmt.Sprintf("containr-%s-%s:%s", deployment.ServiceID, deployment.Environment, deployment.ID), nil
|
||||
}
|
||||
|
||||
buildReq := &types.BuildRequest{
|
||||
BuildType: buildConfig.BuildType,
|
||||
@@ -393,6 +424,8 @@ func (de *DeploymentEngine) deployService(ctx context.Context, deployment *Deplo
|
||||
BasicAuthUsers: cfg.BasicAuthUsers,
|
||||
NodeID: cfg.NodeID,
|
||||
Spread: cfg.Spread,
|
||||
RemoteBuild: cfg.RemoteBuild,
|
||||
RemoteLoad: cfg.RemoteLoad,
|
||||
}
|
||||
for _, pm := range cfg.PortMappings {
|
||||
if spec.Port == 0 {
|
||||
|
||||
@@ -63,6 +63,12 @@ type RuntimeSpec struct {
|
||||
// PlacementTags restricts auto/spread candidates to agents carrying
|
||||
// every listed tag. An explicit NodeID pin bypasses tag filtering.
|
||||
PlacementTags []string
|
||||
// RemoteBuild makes target nodes docker-build Image from a packaged
|
||||
// context artifact before replicas start (git-sourced remote deploys).
|
||||
RemoteBuild *RemoteBuildSpec
|
||||
// RemoteLoad makes target nodes docker-load a saved image tarball —
|
||||
// remote rollbacks of locally-built tags.
|
||||
RemoteLoad *RemoteLoadSpec
|
||||
}
|
||||
|
||||
// RuntimeContainer describes one live replica.
|
||||
|
||||
Reference in new issue
Block a user