This post says a lot more about the javascript ecosystem than Docker. Multi-stage image builds are nothing new or extraordinary, and in fact it's Docker 101. However, being forced to install 500MB worth of tooling and dependencies just to deploy a measly 30MB static website on nginx is something unbelievable.
How is that any different from build tooling for any other language? On my system, gcc with a bunch of commonly used dependencies requires just about the same space (and it's a full Linux system, not a trimmed down container).
> How is that any different from build tooling for any other language?
On the one hand yes, on the other hand it's a large amount of crap just to build a static site. `npm install @11ty/eleventy` pulls 600 packages and yields a 100MB node_modules folder.
Even Sphinx (whose scope goes way beyond static site generation) "only" pulls in about 75MB worth of stuff (a third of that being Babel) over two dozen dependencies (half a dozen being sphinx's own subcomponents).
There are real problems with NPM, like the proliferation of packages that include things they shouldn't (babel included a picture of Guy Feiri for a while...) but the simplistic "there's a lot of files" argument is nonsense. If you need a lot of files then you need a lot of files.
> babel included a picture of Guy Feiri for a while...
I refuse to believe that there are real people so eager to jump on the JS hate bandwagon that they unironically believed every word of an obviously satirical article.
(babel has never included a picture of Guy Fieri.)
It was checked in as a humorous response to the very satirical article I'm talking about, and never actually published to the package registry.
But again, people are so ready to froth at the mouth wherever JS is even mildly concerned that I really shouldn't be surprised they'd take a meme that lasted for a handful of days seriously.
Obvious: Because GCC is a compiler not a runtime. Node is a runtime. You (usually) don't ship the compiler.
Less obvious: You probably wont need Nginx, especially for small static files, in languages where the native servers are fast enough (e.g. http.FileServer)
Why even have a docker image for a static site? If the site has to be built like this one then just put the output of the build process behind some webserver. We were doing this back in the 90s and didn't have to write blog posts about how not to make your site 400MB.
> just put the output of the build process behind some webserver.
That's what this is doing.
You are skipping over two other parts which are installing and setting up nginx / similar and creating a process for the build itself. This ties the three together.
I use Hugo as my static site generator, single binary, no dependencies, generating hundreds of pages in milliseconds ... so reading this feels so wrong, I want to call it JavaScript masochism.
Taking a simple concept like a static site and adding a ton of complex tooling around it because it is the trend now?
Why would you even need a docker image to run a static website? The best thing about a static website us you can host it everyone without requiring any extra resources, like putting it directly to some CDN as files, etc.
best thing: you could easily pack your static Hugo binary in a container with nothing else. But somehow nobody does this without talking about microkernels (and probably internal google-apps)
At work, we build a couple SPA React application for internal tools. All of these SPAs talk to other internal APIs via REST, so you can think of these as static websites.
In production, we do exactly what you suggest: serve through a CDN.
However, for our dev environments and PR builds, programmatically setting up CDN to handle these use cases is not easily integrated with our CI/CD workflow. Our CI/CD environment is, however, good at quickly deploying containerized services.
For this, using an nginx container to serve the produced static bundle enables us to easily have PR builds for the dev team and product owners to see changes without having to check out and build the code.
It's not old fashioned. However, it does mean you have two methods of deployment. In larger ecosystems, a suboptimal release system for some components is less harmful than multiple release systems that have to interact.
I wouldn't suggest moving to docker for this use case, but if everything else was in docker, I'd want this in docker as well, even if that docker container was just running apache.
(Practically, though, if I was starting from scratch, I'd be using NginX.)
I highly recommend nginx over apache. It's both more performant AND much easier to configure. Other than inertia for an existing deployment I don't think there's any reason to use Apache in 2020.
These days if configured correctly there is not a huge amount of difference in performance between nginx and Apache. I have stayed with Apache because I know it and dealing with a http server is about 0.1% of my job.
Milliseconds really don't matter for internal tools or legacy or low-use external websites. If someone wants to see our financial report from 2005, I'm sure they're happy to wait the extra 300ms to download it from a static site on the other side of the world. They should be happy that the link to it in the 2006 document they have still works. (The Apache server listens on 4 ports, to support redirecting various 2000s-era CMSs to their replacements.)
We also have some small but important sites using obscure Apache features (semantic web stuff). I have no idea if Nginx supports the necessary configuration, but since I spend 1-2 hours per year dealing with either scenario -- usually to 'archive' another site -- I'm quite happy to use Apache.
I just looked at Hugo. Their docs menu doesn't work with JS disabled. I know it's a tangent from the point of this thread, but it just makes me crestfallen.
For simple websites you need no "scaffolding", you can just edit the html in a text editor. Really just write the text between the tags. Better to meditate over simplicity and minimalism than to start another software project just to publish a blog.
Ah ok, you started with suggesting Hugo might be a bit complex...
I thought I might have found an ally, someone who has been around for a bit and wary of the cambrian explosion of software projects. Someone who no longer believes in all that software that comes out, with new, cool features that add functionality, but, in my opinion, add subtle difficulty along the way that's hard to account for, death by a thousand cuts that must eventually lead to some kind of fatigue. Things that update and break and change and are deprecated and abandoned and require use of a different language, different build chain, different mental model, just to "add some posts from time to time" to a blog.
Please excuse this little rant. I truly believe that anyone can find their sweet spot with any system. But what is the right fit for your relatives who want it dead simple?
It is complex. I found the documentation was not structured to naturally align with the discovery process I went through in learning how it works. I found myself reading the Go source and using a debugger to step through execution to get a better understanding. I had a similar first experience.
There is still software powering your static site. That software has to live somewhere or on something. Maybe you upload it to GitLab Pages, then you're relying on the cloud to power your static site. Maybe you upload it to your local server where nginx is running. But something is still running it, and if you're doing it yourself - you can run it in a docker container.
I've taken both routes. I have a static site that uses Hugo to generate - just like you mention. It's distribution pipeline is a Docker container inside of GitLab CI/CD. So that it has all the tools needed to both run hugo and upload to AWS S3.
Other static sites I have are generated into HTML, dumped into a docker container with nginx. Then are pulled on relevant servers which run everything else in docker as well, along with the front end load balancer. It would actually be Significantly more work to NOT have the static site in Docker.
I kept infrastructure and data separate. Infrastructure I deploy on DO with ansible. nginx up front, letsencrypt auto renew TLS cert etc. Static content I deploy with rsync.
Takes ~3 seconds to deploy a content change by typing “make deploy”
No CI platform. No docker. Much simpler. Much faster. Much cheaper than AWS.
Sometimes you can get space savings on docker images from seemingly odd sources. For example, I found that running a chown command on files after they've been COPY'd in bloats the image size significantly (100s of MB). However, at some point Docker added a "--chown" flag to the COPY command which brings it back in line.
This post talks about a single-container setup though, with the static site bundled with Nginx. That's what I'm replying to, not the usecase where you have many containers you need to proxy to.
So, if you want to host multiple sites on the same port of your server, from the same process, then you can also have Caddy behind Traefik, but then why would you need Caddy ? Traefik got docker load balancing right: watch docker.sock and self configure on the fly.
I missed the whole Caddy thing anyway because the source code was not completely open back in the days I was looking for nginx alternatives that provided with LetsEncrypt automatically.
However, it seems Caddy can be used as an alternative to Traefik if you use a plugin: https://caddyserver.com/v1/docs/docker Apparently it requires swarm though, which I don't need anyway, so, still no reason for me to try Caddy unfortunately because it does look pretty cool now.
The Caddy source code has always been open source (Apache 2.0 licensed) from day one all the way to today, and will continue to be in the future.
Beware when using other Let's Encrypt integrations. Caddy will keep your site online when other servers don't. (We saw this recently when Let's Encrypt had a revocation incident and when OCSP responders / other network infrastructure went down. Caddy kept the sites up, where other sites went down or left sysadmins scrambling to renew their certs.)
Interesting, I thought they only solved these issues last October, I guess I'm just part of the people that were confused by the situation back then. Sorry about that !
We distributed commercial binaries to businesses for a time and considered making various plugins paid-only to fund its development. But the source code has always been open and Apache-licensed, and there was never any requirement that you had to use the commercial binaries. Caddy has always been an open source project. Arguably more open than nginx, which hides many features behind paid versions, enterprise support, and expensive licensing restrictions. Several of nginx's paid features are free in Caddy, for example NTLM proxying and a config API.
> Caddy will keep your site online when other servers don't.
Interestingly, the LetsEncrypt incident you mentioned went completely under my radar, none of my traefik instances in production or else were affected at all, or it wasn't caught by my uptimerobot, so I'm really not sure what you were talking about then. Maybe the 2017 incident, but I was still using nginx at the time. Pretty concerning, going to check it out.
Honestly I didn't require any of the nginx paid features ever nor did I with traefik, which also has an EE edition that I just found about, I suppose needing those would be a "problem I want to have" kind of problem (meaning the project I'm taking care of is growing). I'm more into software that will generate configuration by introspecting my systems but configuration APIs are also nice to have otherwise.
Nonetheless, Caddy is a great alternative in a domain where innovation had been stalling for a while. I would like to send over a one-time donation to help Caddy development if possible to support development.
(Not the one you replied to, but) I was actually affected — but my nginx setup as ingress controller in kubernetes worked just fine, and automatically handled everything. I actually read in the news about it later, but my systems never went down.
And in contrast to caddy, my setup actually follows the DNS and URL standards, and actually handles Absolute URIs correctly, in contrast to e.g. http://caddyserver.com./, which doesn’t even set HSTS on caddyserver.com., while even browsers consider caddyserver.com. the same origin for the purpose of TLS and HSTS.
If you have a situation where due to your search domain, e.g. corp.com, both exampleA.tld and exampleA.tld.corp.com would be valid DNS resolutions.
If you’re already using something like kubernetes, which does such resolutions, this can actually become an issue. e.g. in the cluster ServiceA can call ServiceB by navigating to http://serviceb/, and if the name of serviceb overlaps with an actual real-world domain, you need to use http://serviceb./ to ensure you call the outside-world site.
Okay. As far as I can tell, Caddy can be configured to handle that, you just need to tell it to. Have you tried to configure Caddy to accept requests to hostnames with a trailing dot recently?
Well that’s the issue. I need to access external websites that way. You could imagine it as a user entering a URL, and a service fetching that URL. To ensure this service doesn’t accidentally fetch an internal site, it transforms the URL to one with a . at the end.
So, I need all websites intended to be fetched this way to support the proper DNS RFCs.
Ever since Caddy and Traefik became a thing my tool has stopped working for more and more non-standard webpages.
Even caddyserver.com itself is broken.
In the end, I’ve simply chosen not to use caddy or traefik based websites.
So if I have a kubernetes env hosting all my stuff, with standardized CI /deployment flows, and one site is static, hosting it from a container like everything else would be a cardinal sin? Thats a strangely black-and-white way to put it...
One of the beautiful things about a static site is it’s ability to be served by object stores like S3 as your origin, and cached by a CDN.
From an operations standpoint, you are not responsible for maintaining much of anything, the performance is super fast, highly available, and relatively cheap (no dedicated servers, just paying for bandwidth and storage costs)
Contrast that with a docker container as your origin... it must be running (and that is your problem to ensure it is).
If you’re optimizing for developer convenience, your traffic is low or not mission critical, or maybe you have a globally distributed highly available k8s cluster and that is “the way” your company does all the things... sure why not
Docker is nice because you end up with the same configuration in development and production. There are many hidden details that "just let someone else host your site" or "just rsync your files to a server" gloss over. Who is renewing your TLS certificate? Where do you configure headers, redirects, mime type mappings, etc.? Where do access logs go? How do you update the version of the web server? What effects does that update have?
When you manually do these things, you rely on a bunch of implicit defaults. Maybe your production server and your workstation happen to have the same version of nginx, and happen to set the same defaults. So you can test a change on your workstation and the same change works in production. But more likely, that is not the case. So you get weird differences between development and production, and you only notice when you push to production. That is not ideal. Building an image with your webserver and static files ensures that you see the same things in both places. There is no need to test anything in production, as you have a copy of the exact code and data that is going to be running in production, locally. You can tweak and poke to your heart's content, confident that you'll have the same effect when you push to production. There is no need to maintain documentation about how to build your project and what versions of things you use; you specify them in a machine-readable format and the machine dutifully builds the project correctly every single time.
(One disadvantage of clean builds, though, is that sometimes you want old artifacts to exist. Consider a case where you use webpack to generate javascript. Typically, you'll output a bundle like "main.abc123.js" which is loaded from "index.html" via a script tag. What happens when the browser loads index.html from your last build, then you the next request goes to an updated server, which says to get "main.def456.js" instead? The page silently breaks, because the server doesn't have a file called "main.def456.js" anymore. "rsync --delete" has the same problem. And if you never delete anything, you eventually use an infinite amount of disk space. So there is definitely room for improvement here, but "it will probably work if I don't think about it and cross my fingers" is not the improvement we're looking for.)
I understand the sentiment and agree to a point. At the same time, I sometimes use docker for seemingly trivial problems because the most important requirement is build consistency. I don't know how to get around using containers when I need that. I can see a static site generator actually needing a reliable build process. What would you suggest though? Just manually/automatically test builds?
Disagreed, because an LB like Traefik will easily self configure watching docker.sock, otherwise, you'd need to change your LB configuration manually every time you add / remove a site.
Back in 2015 when cloud offerings were still marginally new, a lot of big providers were gettting into the game with Docker offerings (ie, IBM Bluemix) where the charge was based entirely on RAM*Hours.
Naturally this lead to me gaming the system and making my docker images as in RAM usage small as possible. In the end I even abandoned SSH as too heavy and switched to shadowsocks (2MB resident) for networking the docker instances together.
> This docker image resulted in a 419MB final image and took about 3 minutes to build. There are some obvious issues with this. For instance every-time I change any file it must go through and reinstall all of my node_modules.
He doesn't tell whether there have been any build time improvements after the changes to the Dockerfile. Will the builder docker images get cached and thus reduce the build and deployment time?
Well, the article mentions an obvious improvement. The node_moduoes won't be rebuilt after any changes to the code, only changes specific to the packages.json.
Basically the main step is the COPY . . step (previously COPY . /app) which will invalidate the cache every change to the code.
Also that on the builder, the steps beyond npm run are not needed, but well they won't improve much on the performance or space of the overall process.
TBH I have such a setup on yourlabs.io/oss/blog because I like SASS too (SASS, the nice CSS language that integrates nicely with webpack, as long as there's node-gyp which needs python2 and g++ to build CSS, guess I'm not doing it right ><), and to serve as a template project for others that would require more elaborated frontends...
... But in my experience it's pretty boring to wait for the whole JS rebuild when you just add a post, I think next time I'm going to remove the JS build from CI and just commit the built things when I change the frontend code, which is not often.
To be honest, GitHub sites have been amazing for me. I just have a simple static website with personal information. HTML and CSS with minimal JS. Purchasing a shared webhost still means extra cost on top of domain registration. With GitHub, I just followed their instructions with my domain, and everything just worked. I'm also not paying anything per month or year besides domain registration which is really nice when you have to start budgeting tightly.
I don't know about docker and all of that, though.
It’s been awesome for me too. I’ve had a static site hosted on github since high school. It’s been a cheap way to host a website for free (I use github + cloudflare) since before I had a credit card. I’m willing to bet it helped me get at least one of my internships.
It’s been a great way for me to learn, as I’ve re-written the site every 2 years or so.
With GitLab Pages it's even easier, just fork one of the examples in gitlab.com/pages, push a content update in a commit and it's online a minute later thanks to GitLab-CI and GitLab Pages.
This workflow seems almost exactly the same as GitHub Pages, I'm not sure it's worth my time to switch platforms and go through the hassle when everything works now.
Yeah but...but... that would just get the job done. Nothing to write about, nothing to whine about, no weird dependencies being pulled, nothing to hand-wave, nothing to yell and humblebrag about. No theatre.
I've only been doing it for 25 years rather than the full 30 but in my noob opinion I'll take Docker and Github over it every time. The number of times a site failed to update because an FTP file failed to transfer completely, or that the permissions were wrong, or that the FTP client changed a file's CRLFs, or that a directory on the server wasn't writable by the FTP user, or... well, let's just admit that FTP sucked and things are far more reliable now.
If there's a blog post: "I got my Ford F-350 to use less fuel by using this One Weird Trick", it's not much use to say how a Honda Civic is a much more simple and efficient solution to the given problem; the domain has already been defined to be the complicated solution.
I'd probably choose the sftp and webhost route myself, but you know.
Aside: one should not use package.json to install dependencies. Use either package-lock.json (and command "npm ci") or yarn.lock (and... I forget). Keep the lock file as part of repo too, or each build could be different.
`npm ci` installs the exact dependencies specified in the lockfile. This way, transitive dependencies that were upgraded via `npm audit fix` are guaranteed to be installed.
It therefore forces the image to be rebuilt when a transitive dependency changes. Copying only the package.json wouldn't do that.
It also errors if the lockfile and the package.json are inconsistent.
3 minutes to build a static blog (with a grand total of five posts) that doesn’t look any different from decade-old blogs. Pulling hundreds of MB from the Internet in the process. Wow.
yes it is sub-optimal, but that is not because building it takes so much time, it is because of the node_modules. I am looking into migrating to Hugo as has been suggested by MANY people
This approach is akin to installing all of the build tooling inside of Docker, then generating the build artifact. I'd think it'd be even slimmer to generate the build artifact first, then just copy that into the container.
Is there an advantage to building inside of Docker?
We've found one advantage to be more reproducible builds since you don't have to worry about different versions of build tooling affecting the artifact.
Wouldn't the advantage be consistent build fragments? If you use the build tools outside of docker, you won't get the same repeatable build artifact across different machines (or as your own host system changes). Maybe I'm not understanding you though.
yeah, that is a mistake. I just did not fully rethink my code when I moved the build layers. I will be removing that tonight along with a few changed suggested here
On a second thought, I also don't understand why do npm in two different images, why not just copy the webpack bundles from the builder image into the nginx image ?
For me the cause of the big image size was in
COPY --from=npmpackages /app /app
From your third Dockerfile, it seems replacing the above with the following would have done the trick without adding an extra stage
I do npm in two different images so that the node_modules can be cached between builds. this massively speeds up my build. The npmpackages layer only installs the npm modules
Can we put "Docker image" in the title somewhere? Otherwise, it seems like the article is talking about the site itself (i.e. having less JavaScript, optimizing the images, …)
106 comments
[ 222 ms ] story [ 3463 ms ] threadOn the one hand yes, on the other hand it's a large amount of crap just to build a static site. `npm install @11ty/eleventy` pulls 600 packages and yields a 100MB node_modules folder.
Even Sphinx (whose scope goes way beyond static site generation) "only" pulls in about 75MB worth of stuff (a third of that being Babel) over two dozen dependencies (half a dozen being sphinx's own subcomponents).
I refuse to believe that there are real people so eager to jump on the JS hate bandwagon that they unironically believed every word of an obviously satirical article.
(babel has never included a picture of Guy Fieri.)
https://github.com/babel/babel/blob/f36d07d30334f86412a9d277...
But again, people are so ready to froth at the mouth wherever JS is even mildly concerned that I really shouldn't be surprised they'd take a meme that lasted for a handful of days seriously.
Less obvious: You probably wont need Nginx, especially for small static files, in languages where the native servers are fast enough (e.g. http.FileServer)
That's what this is doing.
You are skipping over two other parts which are installing and setting up nginx / similar and creating a process for the build itself. This ties the three together.
Taking a simple concept like a static site and adding a ton of complex tooling around it because it is the trend now?
Why would you even need a docker image to run a static website? The best thing about a static website us you can host it everyone without requiring any extra resources, like putting it directly to some CDN as files, etc.
In production, we do exactly what you suggest: serve through a CDN.
However, for our dev environments and PR builds, programmatically setting up CDN to handle these use cases is not easily integrated with our CI/CD workflow. Our CI/CD environment is, however, good at quickly deploying containerized services.
For this, using an nginx container to serve the produced static bundle enables us to easily have PR builds for the dev team and product owners to see changes without having to check out and build the code.
I wouldn't suggest moving to docker for this use case, but if everything else was in docker, I'd want this in docker as well, even if that docker container was just running apache.
(Practically, though, if I was starting from scratch, I'd be using NginX.)
Milliseconds really don't matter for internal tools or legacy or low-use external websites. If someone wants to see our financial report from 2005, I'm sure they're happy to wait the extra 300ms to download it from a static site on the other side of the world. They should be happy that the link to it in the 2006 document they have still works. (The Apache server listens on 4 ports, to support redirecting various 2000s-era CMSs to their replacements.)
We also have some small but important sites using obscure Apache features (semantic web stuff). I have no idea if Nginx supports the necessary configuration, but since I spend 1-2 hours per year dealing with either scenario -- usually to 'archive' another site -- I'm quite happy to use Apache.
I also have this one, single site I want to be independent and not at risk of me misconfiguring caddy, playing around etc. Truly standalone.
So I generate the static code, embark a minimal web server and push it to my registry.
https://gohugo.io/documentation/
Took Hugo for a test drive using official quick start.
Half the themes from official docs wouldn't compile.
Started looking into architecture but official docs do not explain the big picture just a bunch of instructions.
The official documentation does not explain on what is going behind the scenes very well.
I mean, I will obviously want some sort of scaffolding and a way of changing it but this https://gohugo.io/getting-started/directory-structure/ is not helping very much.
Since you are not supposed to write go code everything has to be done through .toml config files as far as I could grok.
I feel I'd rather write my own static generator in language of my choice(say Python) than keep up with the Hugo docs.
Lately I've been writing a lot of .md when writing Jupyter Notebooks.
Thus I figured that Hugo would offer some advantages to relatives who wanted a dead simple site that they wanted to add some posts from time to time.
Static site would be perfect for them but I do not want to manually add their posts...
Started looking into Forestry.io and well it is not quite as simple as Netlify.
I thought I might have found an ally, someone who has been around for a bit and wary of the cambrian explosion of software projects. Someone who no longer believes in all that software that comes out, with new, cool features that add functionality, but, in my opinion, add subtle difficulty along the way that's hard to account for, death by a thousand cuts that must eventually lead to some kind of fatigue. Things that update and break and change and are deprecated and abandoned and require use of a different language, different build chain, different mental model, just to "add some posts from time to time" to a blog.
Please excuse this little rant. I truly believe that anyone can find their sweet spot with any system. But what is the right fit for your relatives who want it dead simple?
I've taken both routes. I have a static site that uses Hugo to generate - just like you mention. It's distribution pipeline is a Docker container inside of GitLab CI/CD. So that it has all the tools needed to both run hugo and upload to AWS S3.
Other static sites I have are generated into HTML, dumped into a docker container with nginx. Then are pulled on relevant servers which run everything else in docker as well, along with the front end load balancer. It would actually be Significantly more work to NOT have the static site in Docker.
Takes ~3 seconds to deploy a content change by typing “make deploy”
No CI platform. No docker. Much simpler. Much faster. Much cheaper than AWS.
https://hub.docker.com/_/caddy/
You also get automatic TLS certificate management and tons of other goodies that nginx doesn't offer out of the box.
I missed the whole Caddy thing anyway because the source code was not completely open back in the days I was looking for nginx alternatives that provided with LetsEncrypt automatically.
However, it seems Caddy can be used as an alternative to Traefik if you use a plugin: https://caddyserver.com/v1/docs/docker Apparently it requires swarm though, which I don't need anyway, so, still no reason for me to try Caddy unfortunately because it does look pretty cool now.
The Caddy source code has always been open source (Apache 2.0 licensed) from day one all the way to today, and will continue to be in the future.
Beware when using other Let's Encrypt integrations. Caddy will keep your site online when other servers don't. (We saw this recently when Let's Encrypt had a revocation incident and when OCSP responders / other network infrastructure went down. Caddy kept the sites up, where other sites went down or left sysadmins scrambling to renew their certs.)
https://github.com/caddyserver/caddy/issues/2786
Interestingly, the LetsEncrypt incident you mentioned went completely under my radar, none of my traefik instances in production or else were affected at all, or it wasn't caught by my uptimerobot, so I'm really not sure what you were talking about then. Maybe the 2017 incident, but I was still using nginx at the time. Pretty concerning, going to check it out.
Honestly I didn't require any of the nginx paid features ever nor did I with traefik, which also has an EE edition that I just found about, I suppose needing those would be a "problem I want to have" kind of problem (meaning the project I'm taking care of is growing). I'm more into software that will generate configuration by introspecting my systems but configuration APIs are also nice to have otherwise.
Nonetheless, Caddy is a great alternative in a domain where innovation had been stalling for a while. I would like to send over a one-time donation to help Caddy development if possible to support development.
It didn't affect every site. But it did affect millions of them. You're lucky!
And in contrast to caddy, my setup actually follows the DNS and URL standards, and actually handles Absolute URIs correctly, in contrast to e.g. http://caddyserver.com./, which doesn’t even set HSTS on caddyserver.com., while even browsers consider caddyserver.com. the same origin for the purpose of TLS and HSTS.
If you’re already using something like kubernetes, which does such resolutions, this can actually become an issue. e.g. in the cluster ServiceA can call ServiceB by navigating to http://serviceb/, and if the name of serviceb overlaps with an actual real-world domain, you need to use http://serviceb./ to ensure you call the outside-world site.
So, I need all websites intended to be fetched this way to support the proper DNS RFCs.
Ever since Caddy and Traefik became a thing my tool has stopped working for more and more non-standard webpages.
Even caddyserver.com itself is broken.
In the end, I’ve simply chosen not to use caddy or traefik based websites.
One of the beautiful things about a static site is it’s ability to be served by object stores like S3 as your origin, and cached by a CDN.
From an operations standpoint, you are not responsible for maintaining much of anything, the performance is super fast, highly available, and relatively cheap (no dedicated servers, just paying for bandwidth and storage costs)
Contrast that with a docker container as your origin... it must be running (and that is your problem to ensure it is).
If you’re optimizing for developer convenience, your traffic is low or not mission critical, or maybe you have a globally distributed highly available k8s cluster and that is “the way” your company does all the things... sure why not
When you manually do these things, you rely on a bunch of implicit defaults. Maybe your production server and your workstation happen to have the same version of nginx, and happen to set the same defaults. So you can test a change on your workstation and the same change works in production. But more likely, that is not the case. So you get weird differences between development and production, and you only notice when you push to production. That is not ideal. Building an image with your webserver and static files ensures that you see the same things in both places. There is no need to test anything in production, as you have a copy of the exact code and data that is going to be running in production, locally. You can tweak and poke to your heart's content, confident that you'll have the same effect when you push to production. There is no need to maintain documentation about how to build your project and what versions of things you use; you specify them in a machine-readable format and the machine dutifully builds the project correctly every single time.
(One disadvantage of clean builds, though, is that sometimes you want old artifacts to exist. Consider a case where you use webpack to generate javascript. Typically, you'll output a bundle like "main.abc123.js" which is loaded from "index.html" via a script tag. What happens when the browser loads index.html from your last build, then you the next request goes to an updated server, which says to get "main.def456.js" instead? The page silently breaks, because the server doesn't have a file called "main.def456.js" anymore. "rsync --delete" has the same problem. And if you never delete anything, you eventually use an infinite amount of disk space. So there is definitely room for improvement here, but "it will probably work if I don't think about it and cross my fingers" is not the improvement we're looking for.)
https://github.com/gunjank/docker-nginx-scratch/blob/master/...
Same also applies to even Java. Maven downloads tons of stuff these days. You may only be using single static string from a dependency.
Naturally this lead to me gaming the system and making my docker images as in RAM usage small as possible. In the end I even abandoned SSH as too heavy and switched to shadowsocks (2MB resident) for networking the docker instances together.
He doesn't tell whether there have been any build time improvements after the changes to the Dockerfile. Will the builder docker images get cached and thus reduce the build and deployment time?
Basically the main step is the COPY . . step (previously COPY . /app) which will invalidate the cache every change to the code.
Also that on the builder, the steps beyond npm run are not needed, but well they won't improve much on the performance or space of the overall process.
But that's only if the builder image gets cached and can be reused, right?
... But in my experience it's pretty boring to wait for the whole JS rebuild when you just add a post, I think next time I'm going to remove the JS build from CI and just commit the built things when I change the frontend code, which is not often.
how about good old ftp and a cheap shared webhost? like its been done for 30 years.
I don't know about docker and all of that, though.
It’s been a great way for me to learn, as I’ve re-written the site every 2 years or so.
You are right, this IS madness.
I'd probably choose the sftp and webhost route myself, but you know.
Or not working.
https://docs.npmjs.com/cli/ci.html
https://github.com/herohamp/eleventy-blog/tree/master/posts
Is there an advantage to building inside of Docker?
That's what this is doing. It creates builder containers, uses them to make the artifact and copies it in:
The final image is nginx with the static files copied over.For me the cause of the big image size was in
COPY --from=npmpackages /app /app
From your third Dockerfile, it seems replacing the above with the following would have done the trick without adding an extra stage
COPY --from=npmpackages /app/_site/ /usr/share/nginx/html/