Container Image From Scratch. Is it possible, is there something to know about, and why isn't this the default?

Hello,

since I need Caddy with a plugin in a container, I was thinking about building my custom Caddy version with the builder image.
However, I would also like to build my own caddy image from scratch, but since the documentation recommends using the default caddy image and overwriting the binary, I wanted to ask if caddy needs any dependencies.
Or are there any other things to consider when using caddy in a from scratch image?
And if not why is the standard image not from scratch, is there a reason for this?

Any help appreciated
BR

You can see the base image here:

Why not just use that base image? What’s the problem?

1 Like

Yeah thank you, I also found some Caddy container images from scratch images repos on GitHub, and there they also install (in a multi stage build) ca-certificates and tzdata and copy /etc/ssl/certs/ca-certificates.crt and /usr/share/zoneinfo into the from scratch image. But I am not sure why it is done.
To answer your question why I not want to use the base image, I don’t see a reason to use a linux distro in a container when the program is written in a language which gets statically compiled.

We need ca-certificates to be able to connect to external servers, like Let’s Encrypt or whatever to issue certs (without it, Caddy’s main selling point, ACME automation, wouldn’t work), or if you’re reverse proxying, to trust the connection to something if it’s serving HTTPS with a publicly signed cert.

We need tzdata so that you can use the TZ env var to set the timestamp for your logs if you want it. We didn’t have it originally but we added it due to user demand. Doesn’t take up much room, fixes a usecase.

We need mailcap so that the file_server directive can properly detect mime types for the Content-Type header based on their file extension or the first few bytes, when serving files from disk. The package is a bit of a misnomer because file type information was originally designed for emails, but it expanded usefulness to other areas of computing over time.

We use Alpine because it’s very convenient if you need to debug to have access to a usable shell with some basic tools to poke around at the files inside the container. Alpine is very small, the benefit of having those tools in a pinch far outweighs the disk size benefit. It also makes it easier to install those few deps we need.

1 Like

Ok, thank you for the explanation. But I have some new questions.
I did a little bit of digging and I am wondering does Caddy then just use the /etc/mime.types file from mailcap. Because the /etc/mailcap seems very different between Ubuntu and Alpine. I use Fedora on my PC and it seems that Alpine uses, just as Fedora, the RedHat config files, were Ubuntu has different ones.
My ca-certificates.crt file (on my PC) is interestingly named completely different with tls-ca-bundle.pem and symlinked to /etc/ssl. In the directory is also a README which states that this isn’t a standard location and exists because of Debians config and the certs directory is symlinked to /etc/pki/ca-trust/extracted/pem/directory-hash/. So my question is does Caddy only looks at /etc/ssl/certs/ when searching for ca-certificates.crt and only for this file name?

Also I forgot to mention that in the base image Caddy runs as root, which I know is easier for binding to ports lower that 1024, but I would just change the standard http/https ports and would be happier to run as a normal user.
But overall I will maybe rethink my decision.

Yes, the Go stdlib loads that file. See mime package - mime - Go Packages

Similarly, the list of locations Go stdlib looks at are here: - The Go Programming Language

Yeah, our opinion is that the risks of running as root in the container are so slim because Docker escape vulns are extremely rare at this point and require some crazy circumstances to execute if at all possible, so it’s a lot easier to just do it this way. Plus it matches the general userbase’s expectations of being able to run Caddy without having to override port defaults.

IMO why bother reinventing the wheel when you can just use an off-the-shelf solution that already known to work well? I think trying to go FROM scratch is bordering on overengineering and paranoia :man_shrugging:

1 Like

You’re probaly right, but for me this is also a learning opportunity to dig a little bit deeper into containerization and the best practices of it, so I am just a little bit curious why things are this way.
And at the end of the day I still need the custom Caddy version and spending then a little bit time on learning to also do a container image how I want it doesn’t matter that much. And when it is done, updating doesn’t take more time than with the builder image and default image.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.