Summary
On Devsy 1.15.0 with the Kubernetes provider, a Dockerfile-backed devcontainer can fail before the Dockerless build starts because the generated .devsy-internal build artifacts are excluded from the streamed workspace mount.
Observed error:
dockerless build: rename dir: open /workspaces/.dockerless/.devsy-internal: no such file or directory
I reproduced this with https://github.com/joshyorko/actions against a Kubernetes context where the equivalent Skevetter DevPod 0.26.1 flow gets through the Dockerless build successfully.
Reproducer
Workspace:
https://github.com/joshyorko/actions
The repo contains a Dockerfile-backed .devcontainer/devcontainer.json, so the Kubernetes provider correctly falls back to Dockerless.
Run:
devsy workspace up https://github.com/joshyorko/actions
Environment from the failing run:
- Devsy Desktop / CLI:
1.15.0
- provider: Kubernetes
- Kubernetes context:
ror
- namespace:
devsy
- Dockerless image:
ghcr.io/devsy-org/dockerless:0.2.0
- architecture:
amd64
Actual behavior
Devsy successfully:
- clones the repository;
- resolves
.devcontainer/Dockerfile;
- resolves the Python base image;
- calculates the prebuild hash;
- creates the PVC and Kubernetes pod;
- injects the Devsy agent;
- streams the workspace into
/workspaces/actions.
The pod is configured with:
DOCKERLESS_CONTEXT=/workspaces/actions
DOCKERLESS_DOCKERFILE=/workspaces/actions/.devsy-internal/Dockerfile-without-features
The workspace upload reaches ~102 MB, then setup fails immediately:
Copy .../actions into DevContainer /workspaces/actions
Uploaded 102.69 MB
dockerless build: rename dir: open /workspaces/.dockerless/.devsy-internal: no such file or directory
Dockerless never reaches its actual build command.
Expected behavior
The generated Dockerless build information should survive the host -> Kubernetes workspace handoff so that prepareBuildDirectory can find either:
/workspaces/actions/.devsy-internal
or the fallback:
/workspaces/.dockerless/.devsy-internal
and then start the Dockerless build.
Likely regression / code-path evidence
The Dockerless fallback creates generated build artifacts under the context path:
// pkg/devcontainer/build.go
devsyInternalFolder := filepath.Join(contextPath, config.DevsyContextFeatureFolder)
err := os.MkdirAll(devsyInternalFolder, 0o755)
...
devsyDockerfile = filepath.Join(devsyInternalFolder, "Dockerfile-without-features")
DevsyContextFeatureFolder is the generated .devsy-internal directory.
However, pkg/agent/tunnelserver/tunnelserver.go currently applies build-artifact exclusions when streaming a mount:
excludes := append(t.workspaceIgnoreExcludes(), config.BuildArtifactExcludes()...)
...
extract.WriteTarExclude(buf, mount.Source, false, excludes)
and pkg/devcontainer/config/artifacts.go defines:
var buildArtifactNames = []string{
DevsyContextFeatureFolder,
}
So .devsy-internal is generated locally and then explicitly excluded from the mount stream that carries the workspace into the Kubernetes pod.
Inside the pod, prepareBuildDirectory then cannot find the build directory at the workspace path and falls back to /workspaces/.dockerless/.devsy-internal, which is also absent, producing the observed rename dir failure.
Working control: Skevetter DevPod
I ran the same joshyorko/actions workspace through Skevetter's DevPod 0.26.1 using the Kubernetes provider and the same Kubernetes context.
DevPod's analogous StreamMount only applies its workspace / .devpodignore exclusions; it does not add an equivalent build-artifact exclusion for .devpod-internal.
That run successfully reaches:
Copy .../actions/content into DevContainer /workspaces/actions
Uploaded 98.90 MB
starting dockerless build: /.dockerless/dockerless build ...
...
dockerless build completed
Suggested fix direction
StreamMount should not blanket-exclude .devsy-internal when that stream is also responsible for transporting the generated Dockerless build artifacts required by the Kubernetes fallback.
Possible approaches:
- do not apply
BuildArtifactExcludes() to this Dockerless workspace stream; or
- explicitly seed/persist
.devsy-internal into /workspaces/.dockerless before excluding it from the normal workspace payload.
The key invariant is that the generated Dockerless build directory must exist in one of the locations expected by prepareBuildDirectory before DockerlessBuild runs.
Acceptance criteria
- A fresh Kubernetes-provider
workspace up for a Dockerfile-backed devcontainer reaches the Dockerless build instead of failing in prepareBuildDirectory.
.devsy-internal is available at the workspace build context or the documented Dockerless fallback location inside the pod.
- Existing cleanup behavior still removes generated build artifacts after setup.
- Add a regression test covering streamed mounts + Dockerless generated build artifacts so
BuildArtifactExcludes() cannot remove the only copy needed by the in-pod builder.
Summary
On Devsy 1.15.0 with the Kubernetes provider, a Dockerfile-backed devcontainer can fail before the Dockerless build starts because the generated
.devsy-internalbuild artifacts are excluded from the streamed workspace mount.Observed error:
I reproduced this with
https://github.com/joshyorko/actionsagainst a Kubernetes context where the equivalent Skevetter DevPod 0.26.1 flow gets through the Dockerless build successfully.Reproducer
Workspace:
The repo contains a Dockerfile-backed
.devcontainer/devcontainer.json, so the Kubernetes provider correctly falls back to Dockerless.Run:
Environment from the failing run:
1.15.0rordevsyghcr.io/devsy-org/dockerless:0.2.0amd64Actual behavior
Devsy successfully:
.devcontainer/Dockerfile;/workspaces/actions.The pod is configured with:
The workspace upload reaches ~102 MB, then setup fails immediately:
Dockerless never reaches its actual build command.
Expected behavior
The generated Dockerless build information should survive the host -> Kubernetes workspace handoff so that
prepareBuildDirectorycan find either:or the fallback:
and then start the Dockerless build.
Likely regression / code-path evidence
The Dockerless fallback creates generated build artifacts under the context path:
DevsyContextFeatureFolderis the generated.devsy-internaldirectory.However,
pkg/agent/tunnelserver/tunnelserver.gocurrently applies build-artifact exclusions when streaming a mount:and
pkg/devcontainer/config/artifacts.godefines:So
.devsy-internalis generated locally and then explicitly excluded from the mount stream that carries the workspace into the Kubernetes pod.Inside the pod,
prepareBuildDirectorythen cannot find the build directory at the workspace path and falls back to/workspaces/.dockerless/.devsy-internal, which is also absent, producing the observedrename dirfailure.Working control: Skevetter DevPod
I ran the same
joshyorko/actionsworkspace through Skevetter's DevPod 0.26.1 using the Kubernetes provider and the same Kubernetes context.DevPod's analogous
StreamMountonly applies its workspace /.devpodignoreexclusions; it does not add an equivalent build-artifact exclusion for.devpod-internal.That run successfully reaches:
Suggested fix direction
StreamMountshould not blanket-exclude.devsy-internalwhen that stream is also responsible for transporting the generated Dockerless build artifacts required by the Kubernetes fallback.Possible approaches:
BuildArtifactExcludes()to this Dockerless workspace stream; or.devsy-internalinto/workspaces/.dockerlessbefore excluding it from the normal workspace payload.The key invariant is that the generated Dockerless build directory must exist in one of the locations expected by
prepareBuildDirectorybeforeDockerlessBuildruns.Acceptance criteria
workspace upfor a Dockerfile-backed devcontainer reaches the Dockerless build instead of failing inprepareBuildDirectory..devsy-internalis available at the workspace build context or the documented Dockerless fallback location inside the pod.BuildArtifactExcludes()cannot remove the only copy needed by the in-pod builder.