This comes up from time to time in several of our dev teams, without us having figured out the "right" way:
We use a lot of react-based webapplications that "compile" into static websites that are just a few html, js and css files.
However, the "building" of these apps take a number of variables that enable/disable feature flags, configure backend urls, etc. This means that we cannot "build" a binary in the traditional sense and just apply a config file at deploy-time - the "build" itself needs to have these environment-specific variables set, and thus the only time we can "build" is at deploy-time.
For now we solve this by injecting the required environment variables into the Docker container and run a start cmd along the lines of
npm build && nginx run
This has a couple of disadvantages:
- The build process takes a lot of cpu/memory relative to the run-time requirements of the container. That means we need to scale the container for the build process instead of the run-time requirements - which feels wrong
- Build failures are hard to "track". We can use healthchecks in Kubernetes, but if a build takes 2 minutes we still have to wait for 3 mins (1 extra for safety) before we can start testing the container's healthcheck endpoint to see if its alive.
- Deployments might take a long time: If we configure Kubernetes to do a "serial" deployment, it will start each pod and wait for the "initialDelay" period of 2-3 minutes before starting the next. This means that we're easily looking at a 10-min deploy time if the deployment is scaled to 3-4 pods.
I realize that for Kubernetes we could use "init-containers" that perform the build, places the artiacts in persistent storage and then have the app containers simply pull from persistent storage during startup, but this still feels more like "bypassing" the problem than solving the root issue.