Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Universal image build and reuse semantics #74

Open
Chuxel opened this issue Aug 5, 2022 · 0 comments
Open

Universal image build and reuse semantics #74

Chuxel opened this issue Aug 5, 2022 · 0 comments
Labels
proposal Still under discussion, collecting feedback

Comments

@Chuxel
Copy link
Member

Chuxel commented Aug 5, 2022

As dev container features (#61) are introduced into the spec and related CLI and tools/services, pre-building an image that includes features using a devcontainer.json file becomes critically important. However, devcontainer.json's semantics currently support referencing an image or a Dockerfile/Docker Compose file. This means that you end up needing two devcontainer.json files to pre-build: one for the pre-build, and one for actual use with the image reference. While this works, ideally, we could have one file that can be used in either case. Even better, ideally this would work with any orchestrator.

To resolve this, I'd propose we decouple the idea of the build section from orchestration and enable referencing an image name to act as the primary label for a build. This label is then what is used by default when doing the build (unless a different label is passed into the dev container CLI via the --image-name argument). The image name can then be referenced either in the devcontainer.json file, or in a Docker Compose file.

This could be enabled through the introduction of an imageNames property into the build section of devcontainer.json. If specified, the logic would be to do the following:

  1. First try to pull the image referenced in the image property - if this works, use it.
  2. If this fails, build it using the contents of the build property features, and give it the names specified under imageNames. Then use the image.
  3. If a rebuild is fired, then would ignore any centrally pushed images and then build as described in (2). An argument passed into the dev container CLI can also signal this should happen.

For Docker Compose or other orchestrators, the logic would be the same, but the image reference would just be in the orchestration format instead. Consider these examples...

Single container example:

{
    "image": "image-name-from-build",
    "build": {
        "imageNames": [ "image-name-from-build" ],
        "dockerfile": "Dockerfile"
    },
    "features": {
       "ghcr.com/devcontainers/features/docker-in-docker": {}
   }
}

Docker Compose:

devcontainer.json

{
    "dockerComposeFile": "docker-compose.yaml",
    "service": "foo",
    "workspaceFolder": "/workspace",
    "build": {
        "imageNames": [ "image-name-from-build" ],
        "dockerfile": "Dockerfile"
    },
   "features": {
       "ghcr.com/devcontainers/features/docker-in-docker": {}
   }
}

Related docker-compose.yaml:

#...
services:
  foo:
    image: image-name-from-build
#...

For cases where a base image is all that is needed beyond features, we could also allow for an baseImage property in the build section. e.g.,

{
    "image": "image-name-from-build",
    "build": {
        "imageNames": [ "image-name-from-build" ],
        "baseImage": "mcr.microsoft.com/vscode/devcontainers/base:ubuntu"
    },
    "features": {
       "ghcr.com/devcontainers/features/docker-in-docker": {}
   }
}

This also allows for pre-builds as we consider long term support for supporting orchestrator formats in the dev container spec that do not inherently have a supported way to first do a build before spinning up a container.

Support for multi-container scenarios here can be handled in a similar way, though likely we want to at least introduce an array syntax to devcontainer.json to encapsulate multiple container image builds where appropriate as discussed in #10. For example:

[
    {
        "dockerComposeFile": "docker-compose.yaml",
        "service": "foo1",
        "workspaceFolder": "/workspace/foo1",
        "build": {
            "imageNames": [ "image-name-from-build-1" ],
            "dockerfile": "foo/Dockerfile"
        },
       "features": {
           "ghcr.com/devcontainers/features/docker-in-docker": {}
       }
    },
    {
        "dockerComposeFile": "docker-compose.yaml",
        "service": "foo2",
        "workspaceFolder": "/workspace/foo2",
        "build": {
            "imageNames": [ "image-name-from-build-2" ],
            "dockerfile": "foo2/Dockerfile"
        },
       "features": {
           "ghcr.com/devcontainers/features/node": {}
       }
    }
]

//cc @craiglpeters @chrmarti given we've had discussions along these lines to date. FYI @bamurtaugh @jkeech @alexdima

@Chuxel Chuxel added the proposal Still under discussion, collecting feedback label Aug 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal Still under discussion, collecting feedback
Projects
None yet
Development

No branches or pull requests

1 participant