agate
agate copied to clipboard
Refactor Dockerfile for multi-stage build
I noticed that when building the Dockerfile, the resultant image had a size of 1.15GB! This did not pass the smell test for a small static Rust binary with an alpine base container.
The current Dockerfile uses a single-stage build, which means that the entire package cache, cargo cache, build cache, etc. are saved in a Docker image layer. This results in an absolutely enormous image.
This PR refactors the Dockerfile to use a multi-stage build, which first uses the rust:alpine
Docker image to build the project. The second stage starts from a base alpine container, and only copies the statically compiled binary and the start.sh
entrypoint script, which reduces size from 1.15GB to 11.4MB.
I quickly tested this out by using the new Docker image to serve a page, which I could access using amfora
. I am not entirely familiar with all the bells and whistles of this project, so I recommend the primary maintainers further test the new Dockerfile before merging.
Passing thoughts
Use of alpine
as final base instead of scratch
Just some additional thoughts regarding the Dockerfile -- the only reason I used alpine:latest
as the final build stage instead of scratch
is due to the start.sh
script, which requires a shell to interpret it. However, the start script itself is very simple, being only one command. This command could easily be inlined directly in Dockerfile
. The only problem is that CMD
command doesn't understand ENV variables. In addition, as scratch
does not contain a shell, shell expansion of the environment variable won't work regardless.
If agate
itself can be refactored to be configured by environment variables in addition to traditional command line flags, we can use the ENV
directive in the Dockerfile to configure the runtime arguments of agate
, and skip the startup script entirely. This will allow us to use scratch
as the base container, which would save ~5.9MB -- the size of the alpine
base container (non-insignificant compared to currently proposed final size of 11.4MB).
This can be addressed in a future PR if there is sufficient interest, and I am glad to implement that as well. I just want to make sure it is actually a desired feature before spending time to implement it -- don't want to spend time writing it just to be shot down due to differing design philosophies.
I can confirm this is a good change. Multi-stage builds will greatly reduce the container size. I'd like to add a few more features, but really can't until this one is merged.
@mbrubeck are you ok with this one as-is?
As for scratch, i generally shy away from it since it makes containers extremely difficult to debug (no exec bash), but it could make sense in this case given the simplicity of agate. One feature i'd like to see is "automatically pulling a gemini website via git and hosting it on startup" (instead of relying on a volume mount). This wouldn't be possible with scratch.
I am currently waiting for the things from #145 to be modified into this PR.
Sorry folks, this slipped PR my mind. I have time to work on this now so hopefully we can get this merged soon :).
Hi,
How is this PR going? I have an alternative aproach at: https://github.com/ldotlopez/agate which builds the container from source (instead of using wget) and multi-stage build.
I would like to open a new PR for my branch if this PR is not merge.