-
Notifications
You must be signed in to change notification settings - Fork 27.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs(deployment): Add Docker Image section #17794
Conversation
Add a Docker Image section with an example.
Stats from current PRDefault Server Mode (Decrease detected ✓)General
Page Load Tests Overall decrease
|
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
/ failed reqs | 0 | 0 | ✓ |
/ total time (seconds) | 2.477 | 2.553 | |
/ avg req/sec | 1009.3 | 979.36 | |
/error-in-render failed reqs | 0 | 0 | ✓ |
/error-in-render total time (seconds) | 1.398 | 1.398 | ✓ |
/error-in-render avg req/sec | 1788.66 | 1788.42 |
Client Bundles (main, webpack, commons)
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
677f882d2ed8..133b.js gzip | 11.1 kB | 11.1 kB | ✓ |
framework.HASH.js gzip | 39 kB | 39 kB | ✓ |
main-faae5f7..727a.js gzip | 7.22 kB | 7.22 kB | ✓ |
webpack-e067..f178.js gzip | 751 B | 751 B | ✓ |
Overall change | 58 kB | 58 kB | ✓ |
Client Bundles (main, webpack, commons) Modern
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
677f882d2ed8..dule.js gzip | 6.9 kB | 6.9 kB | ✓ |
framework.HA..dule.js gzip | 39 kB | 39 kB | ✓ |
main-d2ce890..dule.js gzip | 6.28 kB | 6.28 kB | ✓ |
webpack-07c5..dule.js gzip | 751 B | 751 B | ✓ |
Overall change | 52.9 kB | 52.9 kB | ✓ |
Legacy Client Bundles (polyfills)
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
polyfills-4b..e242.js gzip | 31 kB | 31 kB | ✓ |
Overall change | 31 kB | 31 kB | ✓ |
Client Pages
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
_app-9a0b9e1..b37e.js gzip | 1.28 kB | 1.28 kB | ✓ |
_error-ed1b0..8fbd.js gzip | 3.44 kB | 3.44 kB | ✓ |
hooks-89731c..c609.js gzip | 887 B | 887 B | ✓ |
index-17468f..5d83.js gzip | 227 B | 227 B | ✓ |
link-409b283..e3ab.js gzip | 1.32 kB | 1.32 kB | ✓ |
routerDirect..924c.js gzip | 284 B | 284 B | ✓ |
withRouter-7..c13d.js gzip | 284 B | 284 B | ✓ |
Overall change | 7.73 kB | 7.73 kB | ✓ |
Client Pages Modern
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
_app-75d3a82..dule.js gzip | 625 B | 625 B | ✓ |
_error-4469a..dule.js gzip | 2.29 kB | 2.29 kB | ✓ |
hooks-cbf13f..dule.js gzip | 387 B | 387 B | ✓ |
index-b9a643..dule.js gzip | 226 B | 226 B | ✓ |
link-92d3016..dule.js gzip | 1.28 kB | 1.28 kB | ✓ |
routerDirect..dule.js gzip | 284 B | 284 B | ✓ |
withRouter-f..dule.js gzip | 282 B | 282 B | ✓ |
Overall change | 5.37 kB | 5.37 kB | ✓ |
Client Build Manifests
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
_buildManifest.js gzip | 323 B | 323 B | ✓ |
_buildManife..dule.js gzip | 329 B | 329 B | ✓ |
Overall change | 652 B | 652 B | ✓ |
Rendered Page Sizes
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
index.html gzip | 1 kB | 1 kB | ✓ |
link.html gzip | 1.01 kB | 1.01 kB | ✓ |
withRouter.html gzip | 995 B | 995 B | ✓ |
Overall change | 3.01 kB | 3.01 kB | ✓ |
Serverless Mode
General
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
buildDuration | 15.3s | 15s | -262ms |
nodeModulesSize | 63.4 MB | 63.4 MB | ✓ |
Client Bundles (main, webpack, commons)
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
677f882d2ed8..133b.js gzip | 11.1 kB | 11.1 kB | ✓ |
framework.HASH.js gzip | 39 kB | 39 kB | ✓ |
main-faae5f7..727a.js gzip | 7.22 kB | 7.22 kB | ✓ |
webpack-e067..f178.js gzip | 751 B | 751 B | ✓ |
Overall change | 58 kB | 58 kB | ✓ |
Client Bundles (main, webpack, commons) Modern
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
677f882d2ed8..dule.js gzip | 6.9 kB | 6.9 kB | ✓ |
framework.HA..dule.js gzip | 39 kB | 39 kB | ✓ |
main-d2ce890..dule.js gzip | 6.28 kB | 6.28 kB | ✓ |
webpack-07c5..dule.js gzip | 751 B | 751 B | ✓ |
Overall change | 52.9 kB | 52.9 kB | ✓ |
Legacy Client Bundles (polyfills)
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
polyfills-4b..e242.js gzip | 31 kB | 31 kB | ✓ |
Overall change | 31 kB | 31 kB | ✓ |
Client Pages
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
_app-9a0b9e1..b37e.js gzip | 1.28 kB | 1.28 kB | ✓ |
_error-ed1b0..8fbd.js gzip | 3.44 kB | 3.44 kB | ✓ |
hooks-89731c..c609.js gzip | 887 B | 887 B | ✓ |
index-17468f..5d83.js gzip | 227 B | 227 B | ✓ |
link-409b283..e3ab.js gzip | 1.32 kB | 1.32 kB | ✓ |
routerDirect..924c.js gzip | 284 B | 284 B | ✓ |
withRouter-7..c13d.js gzip | 284 B | 284 B | ✓ |
Overall change | 7.73 kB | 7.73 kB | ✓ |
Client Pages Modern
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
_app-75d3a82..dule.js gzip | 625 B | 625 B | ✓ |
_error-4469a..dule.js gzip | 2.29 kB | 2.29 kB | ✓ |
hooks-cbf13f..dule.js gzip | 387 B | 387 B | ✓ |
index-b9a643..dule.js gzip | 226 B | 226 B | ✓ |
link-92d3016..dule.js gzip | 1.28 kB | 1.28 kB | ✓ |
routerDirect..dule.js gzip | 284 B | 284 B | ✓ |
withRouter-f..dule.js gzip | 282 B | 282 B | ✓ |
Overall change | 5.37 kB | 5.37 kB | ✓ |
Client Build Manifests
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
_buildManifest.js gzip | 323 B | 323 B | ✓ |
_buildManife..dule.js gzip | 329 B | 329 B | ✓ |
Overall change | 652 B | 652 B | ✓ |
Serverless bundles
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
_error.js | 1.05 MB | 1.05 MB | ✓ |
404.html | 4.34 kB | 4.34 kB | ✓ |
hooks.html | 3.92 kB | 3.92 kB | ✓ |
index.js | 1.05 MB | 1.05 MB | ✓ |
link.js | 1.1 MB | 1.1 MB | ✓ |
routerDirect.js | 1.09 MB | 1.09 MB | ✓ |
withRouter.js | 1.09 MB | 1.09 MB | ✓ |
Overall change | 5.41 MB | 5.41 MB | ✓ |
Stats from current PRDefault Server ModeGeneral
Page Load Tests Overall increase ✓
Client Bundles (main, webpack, commons)
Client Bundles (main, webpack, commons) Modern
Legacy Client Bundles (polyfills)
Client Pages
Client Pages Modern
Client Build Manifests
Rendered Page Sizes
Serverless ModeGeneral
Client Bundles (main, webpack, commons)
Client Bundles (main, webpack, commons) Modern
Legacy Client Bundles (polyfills)
Client Pages
Client Pages Modern
Client Build Manifests
Serverless bundles
|
Using Next.js w/ Docker in has been a bit of a pain, tbh. There are a couple issues in the Discussion section about it, mostly because Next.js is designed assuming all the env vars will be available during the build step, which isn't necessarily the case with Docker (presumably, you'd build it once and deploy to different envs, with different runtime env vars). Next.js + SSG/ISG features don't really play nicely with that set up (in my experience so far). I would love to see Docker considered as more of a first-class citizen for Next.js, but I can't imagine encouraging people towards a poorly-supported use case is a great idea. |
I think people already use Next.js on Docker nevertheless, as companies and folks really model their ways around differently. The developer can always setup their CI system for this as well and still build static docker images as artifacts containing the static builds. Every platform nowadays is basically running workloads in containers, Next.js will not stop being one of these anytime soon IMO |
Any chance you could explain this in more depth? We're using Docker and the issues I mentioned above are problems we're having with Next.js + Docker, so if you've worked around them, I'd love to hear how you handled it. |
@mAAdhaTTah In the case to support proper SSG you would have to defer the build process from nextjs to the startup of the container. The way to do this is to have a customized entry point to your container. Here is an example of how you could do that with Docker (not covering user permissions):
FROM node:alpine
# Adds `tini` to be the PID 1 wrapping our entrypoint
RUN apk add --no-cache libc6-compat tini
# Setup dependencies with layer cache for fast builds
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn
# Copy remaining src code to the image fs
COPY . .
# Setup environment and ports
ENV NODE_ENV production
EXPOSE 3000
# Copy entrypoint and wrap it with tini
COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["tini", "--", "docker-entrypoint.sh"]
CMD ["start"]
Note: make sure to #!/bin/sh
set -e
if [ "$1" = 'start' ]; then
exec yarn build && yarn start
fi
if [ "$1" = 'build' ]; then
exec yarn build
fi
exec "$@" This will basically make usage of all the environment variables you pass to your container in your deployment environment to build your application and start it. Your CI process would have to change though so you can properly build and test it, that is why there is a This entrypoint also makes it available for you to access the container through an interactive shell: docker build . -t my-nextjs-app
docker run -it my-nextjs-app -- sh There are a few cons on this, like the startup time being definitely slower, but if you're deploying containers you also have the ability to hide them through a Load Balancer with Healthchecks, so you should be fine. |
Ok, that makes sense conceptually, but has two other issues besides the startup time:
Appreciate you sharing the approach though! |
@mAAdhaTTah You're welcome. As I've said, there are indeed a lot of cons with the build on startup approach, but they're no different than doing it in an EC2 instance for example. The 1st issue you mentioned basically states that. Another way you can try to solve this is by just setting the needed env vars in your CI and packing the generated static versions from there in your image. This also has its own drawbacks, as your CI process will depend on other services or anything your build might depend to generate these static assets, bringing the possibility for them to be flaky. Regarding the 2nd issue, you'd probably have to go through another kind of setup where you can actually mount the static builds in the container. If you're using Kubernetes or any container orchestrator, that can be done quite easily. You'd still have to build your CI/CD pipelines or some kind of cronjob to update these static assets anyway though. Another way would be to My point is mainly that these are not issues with Docker itself but architectural decisions based on project needs. Different strategies will have different implementations, but the goal of this PR is just to add the simplest one so people have a place to start with. |
I'm not suggesting it's an issue w/ Docker so much as an issue Next.js, which is being designed for an environment where env vars are available during build, which conflicts w/ "standard" build-once, run-everywhere Docker philosophy. All of those are feasible workarounds but feel like hacks due to a fundamental difference in design philosophy (so maybe not an "issue" with Next.js so much as a conflict). |
These workarounds may feel like a hack but they're actually a feature. They're not that different from what the #!/bin/bash
set -e
if [ "$1" = 'postgres' ]; then
chown -R postgres "$PGDATA"
if [ -z "$(ls -A "$PGDATA")" ]; then
gosu postgres initdb
fi
exec gosu postgres "$@"
fi
exec "$@" Note: it is a bit more complex than this example, but it pictures enough. https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#entrypoint |
Stats from current PRDefault Server Mode (Decrease detected ✓)General
Page Load Tests Overall decrease
|
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
/ failed reqs | 0 | 0 | ✓ |
/ total time (seconds) | 2.43 | 2.406 | -0.02 |
/ avg req/sec | 1028.73 | 1038.88 | +10.15 |
/error-in-render failed reqs | 0 | 0 | ✓ |
/error-in-render total time (seconds) | 1.246 | 1.257 | |
/error-in-render avg req/sec | 2005.89 | 1989.38 |
Client Bundles (main, webpack, commons)
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
677f882d2ed8..34b9.js gzip | 12.8 kB | 12.8 kB | ✓ |
framework.HASH.js gzip | 39 kB | 39 kB | ✓ |
main-3c9ff84..1d7c.js gzip | 6.56 kB | 6.56 kB | ✓ |
webpack-e067..f178.js gzip | 751 B | 751 B | ✓ |
Overall change | 59 kB | 59 kB | ✓ |
Legacy Client Bundles (polyfills)
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
polyfills-4b..e242.js gzip | 31 kB | 31 kB | ✓ |
Overall change | 31 kB | 31 kB | ✓ |
Client Pages
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
_app-7231d4b..5856.js gzip | 1.28 kB | 1.28 kB | ✓ |
_error-01375..90b6.js gzip | 3.69 kB | 3.69 kB | ✓ |
hooks-d4591d..e7c2.js gzip | 887 B | 887 B | ✓ |
index-17468f..5d83.js gzip | 227 B | 227 B | ✓ |
link-db223d9..dbd7.js gzip | 1.61 kB | 1.61 kB | ✓ |
routerDirect..924c.js gzip | 284 B | 284 B | ✓ |
withRouter-7..c13d.js gzip | 284 B | 284 B | ✓ |
Overall change | 8.27 kB | 8.27 kB | ✓ |
Client Build Manifests
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
_buildManifest.js gzip | 322 B | 322 B | ✓ |
Overall change | 322 B | 322 B | ✓ |
Rendered Page Sizes
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
index.html gzip | 615 B | 615 B | ✓ |
link.html gzip | 621 B | 621 B | ✓ |
withRouter.html gzip | 608 B | 608 B | ✓ |
Overall change | 1.84 kB | 1.84 kB | ✓ |
Serverless Mode
General
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
buildDuration | 11.8s | 11.7s | -91ms |
nodeModulesSize | 82.4 MB | 82.4 MB | ✓ |
Client Bundles (main, webpack, commons)
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
677f882d2ed8..34b9.js gzip | 12.8 kB | 12.8 kB | ✓ |
framework.HASH.js gzip | 39 kB | 39 kB | ✓ |
main-3c9ff84..1d7c.js gzip | 6.56 kB | 6.56 kB | ✓ |
webpack-e067..f178.js gzip | 751 B | 751 B | ✓ |
Overall change | 59 kB | 59 kB | ✓ |
Legacy Client Bundles (polyfills)
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
polyfills-4b..e242.js gzip | 31 kB | 31 kB | ✓ |
Overall change | 31 kB | 31 kB | ✓ |
Client Pages
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
_app-7231d4b..5856.js gzip | 1.28 kB | 1.28 kB | ✓ |
_error-01375..90b6.js gzip | 3.69 kB | 3.69 kB | ✓ |
hooks-d4591d..e7c2.js gzip | 887 B | 887 B | ✓ |
index-17468f..5d83.js gzip | 227 B | 227 B | ✓ |
link-db223d9..dbd7.js gzip | 1.61 kB | 1.61 kB | ✓ |
routerDirect..924c.js gzip | 284 B | 284 B | ✓ |
withRouter-7..c13d.js gzip | 284 B | 284 B | ✓ |
Overall change | 8.27 kB | 8.27 kB | ✓ |
Client Build Manifests
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
_buildManifest.js gzip | 322 B | 322 B | ✓ |
Overall change | 322 B | 322 B | ✓ |
Serverless bundles
vercel/next.js canary | armand1m/next.js patch-1 | Change | |
---|---|---|---|
_error.js | 1 MB | 1 MB | ✓ |
404.html | 2.67 kB | 2.67 kB | ✓ |
hooks.html | 1.92 kB | 1.92 kB | ✓ |
index.js | 1 MB | 1 MB | ✓ |
link.js | 1.06 MB | 1.06 MB | ✓ |
routerDirect.js | 1.05 MB | 1.05 MB | ✓ |
withRouter.js | 1.05 MB | 1.05 MB | ✓ |
Overall change | 5.16 MB | 5.16 MB | ✓ |
I would suggest taking some inspiration from #16995 (comment) related to multi-stage since it will be a common use case out there in the wild. |
Add a Docker Image section into the Deployment Documentation with an example and how to build and run it.
The example is a multi-stage docker image with node modules layer caching for faster builds in development and a result image just with the node_modules and build code needed to run the application within a custom user with restricted access.
The example contains a commented piece of code on how to disable telemetry as well.
This is useful for folks that are deploying to container orchestrators like ECS, Kubernetes (GKE, EKS, AKS) or Hashicorp Nomad, as well as just running a docker container in a single node in some cloud provider.