devcontainers / templates

Repository for Dev Container Templates that are managed by Dev Container spec maintainers. See https://github.com/devcontainers/template-starter to create your own!
https://containers.dev/templates
MIT License
1.01k stars 259 forks source link

Presence of Dockerfile in spec-provided Templates #135

Open bamurtaugh opened 1 year ago

bamurtaugh commented 1 year ago

Context

Before opening the dev container spec, we hosted a set of dev container Templates that each included a Dockerfile and devcontainer.json. Once we opened up the spec, we moved a set of Templates to this repo, and we made some changes, including having each Template only include a devcontainer.json in the .devcontainer folder (example).

Our goal was to make things simpler: you don't need to be a Dockerfile expert to use dev containers, and dev containers can be as simple as just a devcontainer.json referencing an image. The spec also still supports using a Dockerfile, so this change didn't break existing setups using a Dockerfile.

Problem

We've started seeing feedback (example) that the lack of Dockerfile (in this repo, or when running "Add Dev Container Configuration Files" in a supporting tool like VS Code or GitHub Codespaces) is confusing, with questions such as:

Potential solutions

We added a comment in the Templates to try to help clarify: / Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile. But, we'd like to discuss making this an even clearer / easier process.

There are a few ways to address this, including:

Next steps

Share this issue with the community, including existing issues and our dev container community Slack channel, to get broader feedback.

andreujuanc commented 1 year ago

Hi @bamurtaugh , Thanks for dedicating time to this issue. I'm pretty sure that like me, many others "hardcore" devContainer fans appreciate the effort.

I want to start by saying that a Docker container is a DEV TOOL. Therefore should be geared towards developers. And that, you don't need to know all the details about containerization, groups, etc, but instead just know the basics to get you around and use the tool as such.

I understand that the intention was not to make things "too simple" or to cut off complexities, but was made to on-board users who have little to no experience with Docker. And I think it's a good move, but you are forgetting that these new devs will learn, and then will need more advanced usage of it.

DevContainers is the tech, good!, and it works!, great!. But the actual issue is, how do we help developers create their images faster, but without "segregating" the experienced and the new devs apart?

I think the trick lies in the UX (as always). Think about it, Visual Basic.Net never took off, and C# is the leader now for .Net projects. Cos it was easier? no, but because it was powerful and brought other developers who were familiar with C, C++, Java and the rest of the C family.

If we want devContainers to succeed, it needs to be powerful but, at the same time, easy to start with. That's where the "features" came and, at least for me, ruined my flow, because I often need to create new repos, for PoC or quick tests, and will always need to tweak my container. I often have to copy paste the dockerfile definition because I have my own customization that I cannot publish openly (generally customer's repos), and now I have to not only change the source, but also all the file structure to get it "back as it were".

I would love to find middle-ground of this, and if the answer is a extra check when selecting the templates to see if you want a "features" or a "raw" version, I would be happy with it.

The other problem with the "features" that seems to be shared amongst others is that, now , instead of searching for "how to add X to ubuntu", a dev would have to search "how to add X as a feature in a devcontainer" which will definitely create fragmentation of the possible answers.

The other bit about docker is that it's possible to share the dockerfile (or even dockercompose) with the service's infrastructure definition, that makes it so the developer can run almost the same infra, but locally, within the same environment as the application will be running into. This takes a lot of possible issues out, and makes things smoother.

Cheers

markphip commented 1 year ago

Like any feedback, this is all probably subjective, and just my personal opinions.

I have been helping several large teams adopt Codespaces and devcontainers. While I certainly agree that some good examples that include Dockerfile as well as docker-compose should definitely exist, in my own experience I am steering teams away from using Dockerfile. I prefer the declarative nature of using features. To speed up the build process I will usually use a dotnet or node base image and then just use features to install additional tools as opposed to using the base image and installing everything with features. I like that features can customize both the devcontainer as well as the IDE.

There will often be a small number of distro packages I need to add for something like tests that are run by the app that need these packages installed. For that, I have taken to including a shell script that is called during onCreateCommand. I prefer this approach because I have seen so many Dockerfiles that do not make any effort to reduce the number of layers that are created. I have never tried to measure the impact, but I have to assume many of these images end up being much larger than needed which presumably means they take longer to start as well as use up more of your quota for storage when using a service like Codespaces.

I have also taken to creating my own features but that only makes sense when they will be used across many devcontainers and usually is only done AFTER I have manually done it in the scope of the first devcontainer that needed it. When I am tweaking and developing within my own devcontainer I use the lifecycle scripts. onCreateCommand is an easier way to do anything one would need to do in Dockerfile and generally postStartCommand is where I will do the user-specific customizations for the devcontainer. I prefer this approach as working in a bash script(s) is easier than a Dockerfile with the additional RUN or other commands you need to deal with.

Anyway, agree that there ought to be at least one good template for Dockerfile and docker-compose provided but I otherwise think the current examples that favor the use of image and features makes sense as the default to steer people towards best practices.

andreujuanc commented 1 year ago

favor the use of image and features makes sense as the default to steer people towards best practices.

Features are best practices? According to whom? Following that logic then is using Dockerfiles a malpraxis?

markphip commented 1 year ago

Features are best practices? According to whom? Following that logic then is using Dockerfiles a malpraxis?

I hoped to address that with my first sentence ... me.

This is all subjective. My experience, yours, whoever made the original suggestions that led to this issue. It is all subjective, there is no right answer.

I gave my reasons why I am preferring the declarative approach of using features and adding lifecycle scripts where needed. I would rather see a devcontainer.json like this:

{
  "image": "mcr.microsoft.com/devcontainers/typescript-node:16",
  "features": {
    "ghcr.io/devcontainers/features/powershell:1": {},
    "ghcr.io/devcontainers/features/go:1": {"version": "1.18"} 
  },
  "customizations": {
    "vscode": {
      "extensions": ["dbaeumer.vscode-eslint", "GitHub.copilot", "ms-vscode.powershell"]
    }
  },
  "postCreateCommand": "/.devcontainer/setup.sh"
}

Then the equivalent that uses Dockerfile and a bunch of manual installation steps that need to be understood and maintained over time.

I think this is easier to understand and maintain and while it does not have to lead to smaller container images, I believe in most cases it will.

Finally, I am 100% in agreement that there ought to be templates for using a Dockerfile as well as docker-compose. There is no one size fits all. I only posted to provide @bamurtaugh with a counterpoint about the use of features in the templates.

I have not contributed to this project. If the experience of the people that are contributing leads them to believe that this is the better approach, I am inclined to agree with them.

markphip commented 1 year ago

I've never used the templates (they do not work with Enterprise accounts) so I have not spent much time looking through them.

Looking at the templates now, I do not see why this issue is even opened. There are already specific examples for Dockerfile and Docker Compose, and some of the templates are using Dockerfiles. For example these:

https://github.com/devcontainers/templates/tree/main/src/dotnet-mssql https://github.com/devcontainers/templates/tree/main/src/java-postgres

If someone wants to suggest that say the Javascript, Go or Dotnet templates ought to use a Dockerfile to install the language on top of a base image as opposed to using the existing images that are published, I would say that ought to be an easy to reject suggestion.

Not seeing what the issue is here or what needs to be done.

andreujuanc commented 1 year ago

that need to be understood and maintained over time. Features must be maintained as well. Someone has to do it anyway.

I'm not saying that "features" must go away. But just a simple checkbox (at least) to go back to the previous behavious would be a time saver.

bamurtaugh commented 1 year ago

Thank you both so much for your thoughtful feedback so far. We'll continue seeking user feedback on this topic to shape the direction of the Templates.

In the meantime, I've also started a VS Code extension that provides a code action to select an "image" property in devcontainer.json and convert it to a Dockerfile: https://marketplace.visualstudio.com/items?itemName=Brigit.devcontainer-image-convert. While this won't convert Features, it could at least save a few clicks if wanting to switch over to a Dockerfile setup.

bluesherpa commented 1 year ago

Adding my two cents here. Along with others, I prefer using Docker for configuration when developing some apps, because it provides a way for me to modularize everything required for running the application when I deploy it to different systems like staging and production. Moving configuration from Dockerfile to VSCode Features would reduce this ease of deployment.

andreujuanc commented 1 year ago

One of the containers I have uses "features". Today I was in a cafe for an hour and could not do much because I didn't have internet: image

I have used this container before, yesterday to be precise, so this is another issue that features might introduce.

I already turned off updates on vscode and all extensions because I have bad experiences during flights where without internet the containers try to install a pending update and will not load, even if the images are already downloaded.

I think the most important thing here is that the images should be immutable, no post-scripts, nothing that is not cached by docker.

Simplicity and reproducibility are key here.