Dockerfmt: A Dockerfile Formatter

(github.com)

135 points | by spicypete 24 days ago ago

66 comments

  • jensenbox 24 days ago ago

    I had a chuckle when I looked at the source code and could not find a Dockerfile in there. I want to kick the tires on it and the easiest way would be to run it as a Docker container against an existing file and alas, I cannot.

    • PhilippGille 24 days ago ago

      > the easiest way would be to run it as a Docker container

      Regarding this part, you can always just run a base image and add the app yourself. I'm on mobile so can't test, but should be along these lines:

          docker run --rm --name dockerfmt \
          -v /path/to/Dockerfile:/tmp/Dockerfile \
          golang:1.24-alpine sh -c \
          "apk add git && go run github.com/reteps/dockerfmt@latest /tmp/Dockerfile"
      
      > against an existing file

      For this part yes, you'd still need one, but it can be any of your own.

    • spicypete 24 days ago ago

      Hi there — I’ll try to distribute a docker release of the binary tomorrow!

    • klysm 24 days ago ago

      The project should certainly also be formatting its own docker file via a docker invocation

      • thedougd 24 days ago ago

        And built in a multistage Dockerfile.

    • revskill 24 days ago ago

      The author doesn't know how to use AI.

    • krick 24 days ago ago

      I usually share the sentiment, but, come on, it's packaged as a single binary file...

  • mdaniel 24 days ago ago

    I don't want to vouch for the flagged and dead comment https://news.ycombinator.com/item?id=43630653 because I suspect it was killed for its tone but wow it is really illustrative of the QA that didn't go into this product

    • spicypete 24 days ago ago

      What I can do for you is fix the bugs promptly! I resolved the bugs in the `0.2.7` release. I haven't graduated college yet and don't have a full time job, so my QA skills are still improving.

      • adastra22 23 days ago ago

        Everyone starts somewhere. Good for you for putting it out there!

  • grandempire 24 days ago ago

    You aren’t a real software engineer if your project doesn’t have 50 dot files in the root for your formatters, package mangers, linters, and ci.

    Who formats the formatter configs?

    • zufallsheld 24 days ago ago

      > Who formats the formatter configs?

      Other formatters of course since the configs are often yaml, toml, ini or json.

  • mdaniel 24 days ago ago

    waaaat? https://github.com/reteps/dockerfmt#:~:text=The%20RUN%20pars...

    I am firmly in the camp of

      RUN set -e ;\
          export DEBIAN_FRONTEND=noninteractive ;\
          etc etc
    
    so I guess this tool isn't for me
    • rgovostes 24 days ago ago

      As far as I can tell from https://github.com/moby/moby/issues/4032, as of Debian 12 "bookworm" and Ubuntu 23.04 "Lunar", explicitly setting DEBIAN_FRONTEND is no longer necessary.

    • spicypete 24 days ago ago

      Is there any reason you prefer `set -e` over `&&`? I'm curious if this is a readability thing.

      • figmert 24 days ago ago

        I'm firmly in that camp but I also always add `set -eux`, which makes it so much better at debugging as that gives you individual commands it runs before the output of them.

        • figmert 24 days ago ago

          To be clear, the difference is something along this line:

              $ bash -ec 'echo hello && ls -la /tmp/ | grep systemd && false && echo testing'
              hello
              drwx------.   3 root   root      60 Mar 29 18:33 systemd-private-bluetooth.service-yuSMVM
              drwx------.   3 root   root      60 Mar 29 18:33 systemd-private-upower.service-YhHHP2
          
          versus

              $ bash -euxc 'echo hello; ls -la /tmp/ | grep systemd; false; echo testing'
              + echo hello
              hello
              + ls -la /tmp/
              + grep systemd
              drwx------.   3 root   root      60 Mar 29 18:33 systemd-private-bluetooth.service-yuSMVM
              drwx------.   3 root   root      60 Mar 29 18:33 systemd-private-upower.service-YhHHP2
              + false
          
          Docker also supports the `SHELL` syntax now, which is even better, because you can set it once at the top of the Dockerfile without having to do the whole `set -eux` on every line.
      • mdaniel 24 days ago ago

        Readability is putting it mildly; do you write your shell scripts using that && style? No? Why not, is it for readability?

        I also have a hard time reasoning about && with anything other than the most braindead sequence of commands because: $(thing && if other_thing; then inner_thing1 && thing2; fi && ohgawd)

        And I just realized while typing that out that if its parser doesn't support ; then I guess one needs to

          RUN if conditional_thing \
              then good_luck && \
              fi && \
              echo "whew"
  • yjftsjthsd-h 24 days ago ago

    > The RUN parser currently doesn't support grouping or semicolons in commands

    But then example show that it does support `&&`? Why the difference? I pretty much always write

      RUN foo && \
          bar && \
          :
    
    but it seems syntactically identical to the also valid

      RUN set -e && \
          foo ; \
          bar ; \
          :
    • mcstafford 24 days ago ago

      I prefer heredoc[1] syntax.

      I find it more readable and portable.

      [1] https://www.docker.com/blog/introduction-to-heredocs-in-dock...

      • yjftsjthsd-h 24 days ago ago

        Meta: In HN, prefix a line with 2 spaces to get code formatting, ex.

          # syntax=docker/dockerfile:1.3-labs
          FROM alpine
          RUN <<EOF
          echo "This is a heredoc example"
          echo "It allows multi-line commands"
          EOF
        
        Non-meta: Do you happen to know how portable that is across old docker, podman/buildah, kaniko, etc.? I'd like to adopt it but I don't want it to bite me when I'm not running a recent version of literal docker.
        • vbezhenar 24 days ago ago

          It is new feature and not portable to old versions. But modern podman supports it. No idea about kaniko.

    • solatic 24 days ago ago

      Or, you can write an actual shell script file (i.e. with a .sh extension) to be stored in your repository, ADD it in a throwaway context (i.e. multi-stage builds), then RUN --mount=type=bind to put it into a temporary directory in the build container so that you can execute it. This way, the script doesn't pollute the container, and you have proper separation of concerns, including the ability to use library functions, running shell linters directly, or using higher-level languages like Python if you really need it for some reason

      • xenophonf 24 days ago ago

        That's bad practice because it hides build steps from `docker inspect`. Per https://github.com/docker-library/official-images#clarity:

        > Try to make the Dockerfile easy to understand/read. It may be tempting, for the sake of brevity, to put complicated initialization details into a standalone script and merely add a RUN command in the Dockerfile. However, this causes the resulting Dockerfile to be overly opaque, and such Dockerfiles are unlikely to pass review. Instead, it is recommended to put all the commands for initialization into the Dockerfile as appropriate RUN or ENV command combinations. To find good examples, look at the current official images.

        • solatic 23 days ago ago

          That's advice specifically for official images, and it dates back before multi-stage builds. Most people are not building official images. Most people benefit from clear encapsulation and separation of concerns. The Dockerfile sets up the environment to run the provisioning script, and a provisioning script does the actual provisioning. Official images are different because usually the provisioning script is hidden in an OS package installed with e.g. apk add (or are we going to pretend that OS packages are bad practice for the same reason?).

        • yjftsjthsd-h 24 days ago ago

          Don't multi-stage builds already break `docker inspect`?

    • spicypete 24 days ago ago

      I use `mvdan/sh` [1] under the hood for processing the commands. So it will reformat

        if [ foo ] ; then
          bar
        fi
      
      to

        if [ foo ]
        then
          bar
        fi
      
      And also format your example to

        foo
        bar
      
      In this type of situation, it becomes a little trickier to disambiguate when I need to add semicolons and a backslash, and when I need to add only backslashes. If you use `&&` -- you have disambiguated the two cases so I can format it.

      [1] https://github.com/mvdan/sh

      • yjftsjthsd-h 24 days ago ago

        Between that and the difficulty with comments, it feels like maybe not an ideal tool for the job? Although, I can't throw stones; I'd do almost anything to avoid having to write my own parser. (And not meant as an attack regardless, just trying to constructively question this particular design point)

        • spicypete 24 days ago ago

          I am certainly not in the business of writing my own shell parser ;) Though this is a fair point -- I think I could get a more rich level of control over the output by hooking into their parser, albeit with a higher level of complexity.

          • yjftsjthsd-h 24 days ago ago

            /shrug Something to think about. Usually I'd say not to worry about it, but this particular point seems to be actively causing actual problems, so it might be worth looking at. Alternatively, if the pain points you've discovered really are all there are to find, then it might well be less trouble to just patch over them specifically and not worry about it. Ugly solutions that work well and don't take extra work are good solutions in my book;)

    • undefined 24 days ago ago
      [deleted]
  • urxvtcd 24 days ago ago

    I'd love to indent the body of each stage in multi-stage dockerfiles, like:

        FROM foo
            ...
    
        FROM bar
            ...
    
    It's easy to see at glance what's going on.
    • xyst 24 days ago ago

      This reminds me of SQL indentation “best practices” discussion [1]

      I personally don’t find this particularly helpful but can see it helping some folks. You write enough dockerfiles, the formatting becomes irrelevant.

      What pisses me off though is _inconsistency_. One code base uses "formatting practices 1b", then another code base uses "formatting practices 2x". Then the worst offender: a service owners that can’t make up their mind and each developer makes up their own "best practices".

      [1] https://stackoverflow.com/questions/272210/sql-statement-ind...

  • xyst 24 days ago ago

    It’s wild that this has to be a third party offering.

    I wish projects would adopt/create their own formatters like go and rust.

    The amount of time I have wasted discussing "best practices" with "senior" engineers is way too damn high.

    In code bases such as go or rust, the discussion ends with the "the built in formatter and preferences is preferred"

  • nikeee 24 days ago ago

    How does it handle multi-stage Dockerfiles? I always indent the steps following FROM to make the stages more obvious. I don't get why that isn't a norm because not doing it seems like not indenting function bodies in other languages.

  • QuarterDuplex 24 days ago ago

    OK but is there any way to layer docker files? I'm not talking about compose, I mean like combining layers from different dockers in a nice way?

  • righthand 24 days ago ago

    I just use a yaml LSP which will probably try to lookup the schema.org Containerfile format for this. I first noticed this recently when working on a Github Actions yaml file. Pretty nifty.

  • travisgriggs 24 days ago ago

    I hope there’s a config file for dockerfmt. Over time, it will get more and more options. It will approach Turing completeness.

    Then we’ll need a formatter formatter.

    Software is like onions said Shrek to Donkey.

  • sandeepgogarla 24 days ago ago

    [flagged]

  • ltbarcly3 24 days ago ago

    [flagged]

  • dddw 24 days ago ago

    This wouldve come in hansy yesterday

  • PantaloonFlames 24 days ago ago

    Side question. Why would people continue to build new dockerfiles as opposed to using Podman ?

    • dharmab 24 days ago ago

      Dockerfile has been standardized as Containerfile: https://github.com/containers/common/blob/main/docs/Containe...

      • caleblloyd 24 days ago ago

        Dockerfile seems very specific to Docker still, I don’t think they have to go through a committee to add anything to the spec

        https://docs.docker.com/build/buildkit/dockerfile-release-no...

        If any organization adopted the spec I would hope they would at least make it adopt a standard file extension like .oci so it would at least be more easily recognizable by IDEs, I have never liked having to put the use case as the extension like Dockerfile.dev

        But I do like that docker and buildkit have been able to freely evolve the spec with things like advanced caching directives that work great in buildx

    • DazWilkin 24 days ago ago

      Podman uses Dockerfiles too.

      Dockerfiles is the language for specifying a set of instructions for building container images.

      • halostatue 24 days ago ago

        It's not a very good one, but it is ubiquitous (it's also better if you remember to include the right syntax marker that enables heredocs):

            # syntax=docker/dockerfile:1
        
        I suspect that the GP was really asking "why not use a different tool", like buildah <https://buildah.io>, buildpacks <https://buildpacks.io>, nix <https://nix.dev/tutorials/nixos/building-and-running-docker-...>, kaniko <https://github.com/GoogleContainerTools/kaniko>, ko <https://github.com/ko-build/ko>, bazel <https://github.com/bazel-contrib/rules_oci>, apko <https://github.com/chainguard-dev/apko>, or other tools.

        Each of those has tradeoffs compared to Dockerfiles (I have no need for bazel, but if I did, then adding `rules_oci` might be a win-win, rather than using a Dockerfile). If I used Nix, then the Nix dockerTools would be a huge win (I don't use Nix). If I were shipping Go programs, `ko` would likely be a good baseline.

        • colonial 24 days ago ago

          Buildah is the only serious alternative in my opinion.

          You lose automatic layer caching, but in exchange you can use the same tools (RUN, ADD, etc) within a much more powerful shell environment.

          I wrote a Buildah wrapper that uses a shell script harness to polyfill the familiar Dockerfile syntax while adding several extra goodies - mainly the ability to bake runtime arguments (mounts, ports...) into the image. Very handy!

          • mikepurvis 24 days ago ago

            Buildah's ability to mount the container in an unshare environment is pretty magical for copying stuff in and out of it.

            That said, in the end I'd still rather build containers with something other than an imperative sequence of commands, so my heart is going to be forever with nix2container and bazel's rules_oci.

        • yjftsjthsd-h 24 days ago ago

          When I've used buildah and kaniko, I still handed them a Dockerfile.

    • jahsome 24 days ago ago

      Why would people continue to use hackernews as opposed to reddit?

      • bpiroman 24 days ago ago

        I feel dumber after using reddit

        • imp0cat 24 days ago ago

          The same is usually said about watching Spongebob Squarepants, but YMMV. :)

          • chuckadams 24 days ago ago

            At least with Spongebob you feel dumb and happy. Feels like the whole world is dumb and angry now.

        • acidmath 24 days ago ago

          [dead]

  • brynary 24 days ago ago

    It's great to see auto-formatting continuing to become universal across all languages. As LLMs write more code, full auto-formatting helps keep diffs clean.

    For anyone looking to try dockerfmt, I just added a plugin to Qlty CLI, which is available in v0.508.0. The plugin took about ten minutes to add: https://github.com/qltysh/qlty/blob/main/qlty-plugins/plugin...

    Full disclosure: I'm the founder of Qlty, which produces a universal code linter and formatter, Qlty CLI (https://github.com/qltysh/qlty). It is completely free and published under a Fair Source license.

    • keybored 24 days ago ago

      > As LLMs write more code, full auto-formatting helps keep diffs clean.

      Clean diffs matter irrespective of the author being a person or a program. But sure, I guess with the current hype a certain ratio of comments need to plug reminders that we are currently living in a code generation wasteland.