diff --git a/examples/with-docker-multi-env/.dockerignore b/examples/with-docker-multi-env/.dockerignore new file mode 100644 index 0000000000000..4d72057ef2861 --- /dev/null +++ b/examples/with-docker-multi-env/.dockerignore @@ -0,0 +1,7 @@ +Dockerfile +.dockerignore +node_modules +npm-debug.log +README.md +.next +docker diff --git a/examples/with-docker-multi-env/.env b/examples/with-docker-multi-env/.env new file mode 100644 index 0000000000000..1affd3c0a776c --- /dev/null +++ b/examples/with-docker-multi-env/.env @@ -0,0 +1 @@ +NEXT_PUBLIC_API_URL=http://localhost diff --git a/examples/with-docker-multi-env/.env.development.sample b/examples/with-docker-multi-env/.env.development.sample new file mode 100644 index 0000000000000..357551fe6e464 --- /dev/null +++ b/examples/with-docker-multi-env/.env.development.sample @@ -0,0 +1 @@ +NEXT_PUBLIC_API_URL=https://api-development.com diff --git a/examples/with-docker-multi-env/.env.production.sample b/examples/with-docker-multi-env/.env.production.sample new file mode 100644 index 0000000000000..a566eb6948ed4 --- /dev/null +++ b/examples/with-docker-multi-env/.env.production.sample @@ -0,0 +1 @@ +NEXT_PUBLIC_API_URL=https://api-production.com diff --git a/examples/with-docker-multi-env/.env.staging.sample b/examples/with-docker-multi-env/.env.staging.sample new file mode 100644 index 0000000000000..b1c8d9f9b19d4 --- /dev/null +++ b/examples/with-docker-multi-env/.env.staging.sample @@ -0,0 +1 @@ +NEXT_PUBLIC_API_URL=https://api-staging.com diff --git a/examples/with-docker-multi-env/.gitignore b/examples/with-docker-multi-env/.gitignore new file mode 100644 index 0000000000000..10d8c913baeaa --- /dev/null +++ b/examples/with-docker-multi-env/.gitignore @@ -0,0 +1,38 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel + +# lock files +yarn.lock +package-lock.json diff --git a/examples/with-docker-multi-env/Makefile b/examples/with-docker-multi-env/Makefile new file mode 100644 index 0000000000000..759e426b4a7a1 --- /dev/null +++ b/examples/with-docker-multi-env/Makefile @@ -0,0 +1,35 @@ +.PHONY: build-development +build-development: ## Build the development docker image. + docker compose -f docker/development/docker-compose.yml build + +.PHONY: start-development +start-development: ## Start the development docker container. + docker compose -f docker/development/docker-compose.yml up -d + +.PHONY: stop-development +stop-development: ## Stop the development docker container. + docker compose -f docker/development/docker-compose.yml down + +.PHONY: build-staging +build-staging: ## Build the staging docker image. + docker compose -f docker/staging/docker-compose.yml build + +.PHONY: start-staging +start-staging: ## Start the staging docker container. + docker compose -f docker/staging/docker-compose.yml up -d + +.PHONY: stop-staging +stop-staging: ## Stop the staging docker container. + docker compose -f docker/staging/docker-compose.yml down + +.PHONY: build-production +build-production: ## Build the production docker image. + docker compose -f docker/production/docker-compose.yml build + +.PHONY: start-production +start-production: ## Start the production docker container. + docker compose -f docker/production/docker-compose.yml up -d + +.PHONY: stop-production +stop-production: ## Stop the production docker container. + docker compose -f docker/production/docker-compose.yml down diff --git a/examples/with-docker-multi-env/README.md b/examples/with-docker-multi-env/README.md new file mode 100644 index 0000000000000..2799adfd136ae --- /dev/null +++ b/examples/with-docker-multi-env/README.md @@ -0,0 +1,62 @@ +# With Docker - Multiple Deployment Environments + +This examples shows how to use Docker with Next.js and deploy to multiple environment with different env values. Based on the [deployment documentation](https://nextjs.org/docs/deployment#docker-image). + +## How to use + +Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example: + +```bash +npx create-next-app --example with-docker-multi-env nextjs-docker-multi-env +# or +yarn create next-app --example with-docker-multi-env nextjs-docker-multi-env +``` + +Enter the values in the `.env.development.sample`, `.env.staging.sample`, `.env.production.sample` files to be used for each environments. + +## Using Docker and Makefile + +### Development environment - for doing testing + +``` +make build-development +make start-development +``` + +Open http://localhost:3001 + +### Staging environment - for doing UAT testing + +``` +make build-staging +make start-staging +``` + +Open http://localhost:3002 + +### Production environment - for users + +``` +make build-production +make start-production +``` + +Open http://localhost:3003 + +## Running Locally + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. + +[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. + +The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. diff --git a/examples/with-docker-multi-env/docker/development/Dockerfile b/examples/with-docker-multi-env/docker/development/Dockerfile new file mode 100644 index 0000000000000..d5cce6d2d12c1 --- /dev/null +++ b/examples/with-docker-multi-env/docker/development/Dockerfile @@ -0,0 +1,45 @@ +# 1. Install dependencies only when needed +FROM node:16-alpine AS deps +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. +RUN apk add --no-cache libc6-compat + +WORKDIR /app +COPY package.json yarn.lock ./ +RUN yarn install --frozen-lockfile + +# 2. Rebuild the source code only when needed +FROM node:16-alpine AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . +# This will do the trick, use the corresponding env file for each environment. +COPY .env.development.sample .env.production +RUN yarn build + +# 3. Production image, copy all the files and run next +FROM node:16-alpine AS runner +WORKDIR /app + +ENV NODE_ENV=production + +RUN addgroup -g 1001 -S nodejs +RUN adduser -S nextjs -u 1001 + +# You only need to copy next.config.js if you are NOT using the default configuration +# COPY --from=builder /app/next.config.js ./ +COPY --from=builder /app/public ./public +COPY --from=builder /app/package.json ./package.json + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + + +USER nextjs + +EXPOSE 3000 + +ENV PORT 3000 + +CMD ["node", "server.js"] diff --git a/examples/with-docker-multi-env/docker/development/docker-compose.yml b/examples/with-docker-multi-env/docker/development/docker-compose.yml new file mode 100644 index 0000000000000..cdf32d5e953d3 --- /dev/null +++ b/examples/with-docker-multi-env/docker/development/docker-compose.yml @@ -0,0 +1,10 @@ +version: '3' + +services: + with-docker-multi-env-development: + build: + context: ../../ + dockerfile: docker/development/Dockerfile + image: with-docker-multi-env-development + ports: + - '3001:3000' diff --git a/examples/with-docker-multi-env/docker/production/Dockerfile b/examples/with-docker-multi-env/docker/production/Dockerfile new file mode 100644 index 0000000000000..d26bdb2fef663 --- /dev/null +++ b/examples/with-docker-multi-env/docker/production/Dockerfile @@ -0,0 +1,45 @@ +# 1. Install dependencies only when needed +FROM node:16-alpine AS deps +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. +RUN apk add --no-cache libc6-compat + +WORKDIR /app +COPY package.json yarn.lock ./ +RUN yarn install --frozen-lockfile + +# 2. Rebuild the source code only when needed +FROM node:16-alpine AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . +# This will do the trick, use the corresponding env file for each environment. +COPY .env.production.sample .env.production +RUN yarn build + +# 3. Production image, copy all the files and run next +FROM node:16-alpine AS runner +WORKDIR /app + +ENV NODE_ENV=production + +RUN addgroup -g 1001 -S nodejs +RUN adduser -S nextjs -u 1001 + +# You only need to copy next.config.js if you are NOT using the default configuration +# COPY --from=builder /app/next.config.js ./ +COPY --from=builder /app/public ./public +COPY --from=builder /app/package.json ./package.json + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + + +USER nextjs + +EXPOSE 3000 + +ENV PORT 3000 + +CMD ["node", "server.js"] diff --git a/examples/with-docker-multi-env/docker/production/docker-compose.yml b/examples/with-docker-multi-env/docker/production/docker-compose.yml new file mode 100644 index 0000000000000..b903f1ddd8353 --- /dev/null +++ b/examples/with-docker-multi-env/docker/production/docker-compose.yml @@ -0,0 +1,10 @@ +version: '3' + +services: + with-docker-multi-env-production: + build: + context: ../../ + dockerfile: docker/production/Dockerfile + image: with-docker-multi-env-production + ports: + - '3003:3000' diff --git a/examples/with-docker-multi-env/docker/staging/Dockerfile b/examples/with-docker-multi-env/docker/staging/Dockerfile new file mode 100644 index 0000000000000..beb44b1b39622 --- /dev/null +++ b/examples/with-docker-multi-env/docker/staging/Dockerfile @@ -0,0 +1,45 @@ +# 1. Install dependencies only when needed +FROM node:16-alpine AS deps +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. +RUN apk add --no-cache libc6-compat + +WORKDIR /app +COPY package.json yarn.lock ./ +RUN yarn install --frozen-lockfile + +# 2. Rebuild the source code only when needed +FROM node:16-alpine AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . +# This will do the trick, use the corresponding env file for each environment. +COPY .env.staging.sample .env.production +RUN yarn build + +# 3. Production image, copy all the files and run next +FROM node:16-alpine AS runner +WORKDIR /app + +ENV NODE_ENV=production + +RUN addgroup -g 1001 -S nodejs +RUN adduser -S nextjs -u 1001 + +# You only need to copy next.config.js if you are NOT using the default configuration +# COPY --from=builder /app/next.config.js ./ +COPY --from=builder /app/public ./public +COPY --from=builder /app/package.json ./package.json + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + + +USER nextjs + +EXPOSE 3000 + +ENV PORT 3000 + +CMD ["node", "server.js"] diff --git a/examples/with-docker-multi-env/docker/staging/docker-compose.yml b/examples/with-docker-multi-env/docker/staging/docker-compose.yml new file mode 100644 index 0000000000000..231ef1e61a718 --- /dev/null +++ b/examples/with-docker-multi-env/docker/staging/docker-compose.yml @@ -0,0 +1,10 @@ +version: '3' + +services: + with-docker-multi-env-staging: + build: + context: ../../ + dockerfile: docker/staging/Dockerfile + image: with-docker-multi-env-staging + ports: + - '3002:3000' diff --git a/examples/with-docker-multi-env/next.config.js b/examples/with-docker-multi-env/next.config.js new file mode 100644 index 0000000000000..0568ecc9e5401 --- /dev/null +++ b/examples/with-docker-multi-env/next.config.js @@ -0,0 +1,5 @@ +module.exports = { + experimental: { + outputStandalone: true, + }, +} diff --git a/examples/with-docker-multi-env/package.json b/examples/with-docker-multi-env/package.json new file mode 100644 index 0000000000000..f9170ae254fa3 --- /dev/null +++ b/examples/with-docker-multi-env/package.json @@ -0,0 +1,13 @@ +{ + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "next": "latest", + "react": "^17.0.2", + "react-dom": "^17.0.2" + } +} diff --git a/examples/with-docker-multi-env/pages/_app.js b/examples/with-docker-multi-env/pages/_app.js new file mode 100644 index 0000000000000..1e1cec92425c8 --- /dev/null +++ b/examples/with-docker-multi-env/pages/_app.js @@ -0,0 +1,7 @@ +import '../styles/globals.css' + +function MyApp({ Component, pageProps }) { + return +} + +export default MyApp diff --git a/examples/with-docker-multi-env/pages/api/hello.js b/examples/with-docker-multi-env/pages/api/hello.js new file mode 100644 index 0000000000000..441a0a1006e5a --- /dev/null +++ b/examples/with-docker-multi-env/pages/api/hello.js @@ -0,0 +1,5 @@ +// Next.js API route support: https://nextjs.org/docs/api-routes/introduction + +export default function hello(req, res) { + res.status(200).json({ name: 'John Doe' }) +} diff --git a/examples/with-docker-multi-env/pages/index.js b/examples/with-docker-multi-env/pages/index.js new file mode 100644 index 0000000000000..51e835d5e8720 --- /dev/null +++ b/examples/with-docker-multi-env/pages/index.js @@ -0,0 +1,66 @@ +import Head from 'next/head' +import styles from '../styles/Home.module.css' + +export default function Home() { + return ( +
+ + Create Next App + + + +
+

+ Welcome to Next.js on Docker! +

+

with Multiple Deployment Environments

+

API_URL: {process.env.NEXT_PUBLIC_API_URL}

+

+ Get started by editing{' '} + pages/index.js +

+ +
+ +

Documentation →

+

Find in-depth information about Next.js features and API.

+
+ + +

Learn →

+

Learn about Next.js in an interactive course with quizzes!

+
+ + +

Examples →

+

Discover and deploy boilerplate example Next.js projects.

+
+ + +

Deploy →

+

+ Instantly deploy your Next.js site to a public URL with Vercel. +

+
+
+
+ + +
+ ) +} diff --git a/examples/with-docker-multi-env/public/favicon.ico b/examples/with-docker-multi-env/public/favicon.ico new file mode 100644 index 0000000000000..4965832f2c9b0 Binary files /dev/null and b/examples/with-docker-multi-env/public/favicon.ico differ diff --git a/examples/with-docker-multi-env/public/vercel.svg b/examples/with-docker-multi-env/public/vercel.svg new file mode 100644 index 0000000000000..fbf0e25a651c2 --- /dev/null +++ b/examples/with-docker-multi-env/public/vercel.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/examples/with-docker-multi-env/styles/Home.module.css b/examples/with-docker-multi-env/styles/Home.module.css new file mode 100644 index 0000000000000..42e7e6009497f --- /dev/null +++ b/examples/with-docker-multi-env/styles/Home.module.css @@ -0,0 +1,122 @@ +.container { + min-height: 100vh; + padding: 0 0.5rem; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.main { + padding: 5rem 0; + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.footer { + width: 100%; + height: 100px; + border-top: 1px solid #eaeaea; + display: flex; + justify-content: center; + align-items: center; +} + +.footer img { + margin-left: 0.5rem; +} + +.footer a { + display: flex; + justify-content: center; + align-items: center; +} + +.title a { + color: #0070f3; + text-decoration: none; +} + +.title a:hover, +.title a:focus, +.title a:active { + text-decoration: underline; +} + +.title { + margin: 0; + line-height: 1.15; + font-size: 4rem; +} + +.title, +.description { + text-align: center; +} + +.description { + line-height: 1.5; + font-size: 1.5rem; +} + +.code { + background: #fafafa; + border-radius: 5px; + padding: 0.75rem; + font-size: 1.1rem; + font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, + Bitstream Vera Sans Mono, Courier New, monospace; +} + +.grid { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + max-width: 800px; + margin-top: 3rem; +} + +.card { + margin: 1rem; + flex-basis: 45%; + padding: 1.5rem; + text-align: left; + color: inherit; + text-decoration: none; + border: 1px solid #eaeaea; + border-radius: 10px; + transition: color 0.15s ease, border-color 0.15s ease; +} + +.card:hover, +.card:focus, +.card:active { + color: #0070f3; + border-color: #0070f3; +} + +.card h3 { + margin: 0 0 1rem 0; + font-size: 1.5rem; +} + +.card p { + margin: 0; + font-size: 1.25rem; + line-height: 1.5; +} + +.logo { + height: 1em; +} + +@media (max-width: 600px) { + .grid { + width: 100%; + flex-direction: column; + } +} diff --git a/examples/with-docker-multi-env/styles/globals.css b/examples/with-docker-multi-env/styles/globals.css new file mode 100644 index 0000000000000..e5e2dcc23baf1 --- /dev/null +++ b/examples/with-docker-multi-env/styles/globals.css @@ -0,0 +1,16 @@ +html, +body { + padding: 0; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; +} + +a { + color: inherit; + text-decoration: none; +} + +* { + box-sizing: border-box; +}