Deployment
unpublished draft
ReactJsAsp.Net CoreNginxKubernetes
General#
- Check current listen ports:
sudo netstat -tulpn
|sudo netstat -tulpn | grep LISTEN
- Check if specific port listening:
sudo netstat -tulpn | grep :80
- List all current service:
sudo service --status-all
- Check specific service status:
sudo systemctl status [service-name]
- Do something with service:
systemctl [start | stop | restart] [service-name]
Self-sign ssl key
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localdev.com.key -out localdev.com.crt
SPA#
ReactJs#
Containerized#
nginx>default.conf
Navigate all request to index.html
# server listening port can be vary
server{
listen 3000;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
Dockerfile
FROM node:16-alpine as builder
WORKDIR /app
COPY ./package.json ./
RUN npm i --legacy-peer-deps
COPY . .
RUN npm run build
FROM nginx
# depend on Nginx config listen port
EXPOSE 3000
COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/build /usr/share/nginx/html
# OR
FROM node:16-alpine as builder
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn --frozen-lockfile
COPY . .
RUN yarn build
FROM nginx
EXPOSE 3000
COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/build /usr/share/nginx/html
.dockerignore
node_modules/*
.husky/*
SSR#
Next.Js#
No Docker Compose?
# Build images
docker build --tag nextjs-image .
docker build --tag nginx-image ./nginx
# Create shared network
docker network create my-network
# Run containers
# [nextjs-veclan] is server in upstream block nginx config
docker run --network my-network --name nextjs-container nextjs-image
docker run --network my-network --link nextjs-container:nextjs-veclan --publish 80:80 nginx-image
Containerized#
Next.Js#
Dockerfile - Standard
FROM node:16-alpine as builder
# Check https://github.com/nodejs/docker-node#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 --frozen-lockfile
# RUN yarn add sharp
COPY . .
RUN yarn build
FROM node:16-alpine as runner
WORKDIR /app
ENV NODE_ENV=production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# 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 --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
USER nextjs
EXPOSE 3000
ENV PORT=3000
CMD ["node_modules/.bin/next", "start"]
Dockerfile - Output tracing - Experimental - Starting since Next.Js 12
FROM node:16-alpine as builder
# Check https://github.com/nodejs/docker-node#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 --frozen-lockfile
# Check https://nextjs.org/docs/messages/sharp-missing-in-production to understand why sharp might be needed
RUN yarn add sharp
COPY . .
RUN yarn build
FROM node:16-alpine as runner
WORKDIR /app
ENV NODE_ENV=production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# 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 | Starting with NextJs 12
# 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"]
next.config.js - If using Output tracing
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
experimental: {
outputStandalone: true,
},
};
module.exports = nextConfig;
.dockerignore
.git/
.gitignore
.husky/
node_modules/
.next/
nginx/
Dockerfile
docker-compose.yml
Nginx#
default.conf
# Cache zone
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=STATIC:10m inactive=3d use_temp_path=off;
upstream nextjs_demo_ecom {
server nextjs-veclan:3000;
}
server {
listen 80 default_server;
server_name localdev.com www.localdev.com;
return 301 https://$server_name$request_uri;
server_tokens off;
}
server {
listen 443 ssl;
server_name localdev.com www.localdev.com;
ssl_certificate /etc/nginx/ssl/localdev.com.crt;
ssl_certificate_key /etc/nginx/ssl/localdev.com.key;
server_tokens off;
gzip on;
gzip_proxied any;
gzip_comp_level 4;
gzip_types text/css application/javascript image/svg+xml;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
# BUILT ASSETS (E.G. JS BUNDLES)
# Browser cache - max cache headers from Next.js as build id in url
# Server cache - valid forever (cleared after cache "inactive" period)
location /_next/static {
proxy_cache STATIC;
proxy_pass http://nextjs_demo_ecom;
}
# STATIC ASSETS (E.G. IMAGES)
# Browser cache - "no-cache" headers from Next.js as no build id in url
# Server cache - refresh regularly in case of changes
location /static {
proxy_cache STATIC;
proxy_ignore_headers Cache-Control;
proxy_cache_valid 60m;
proxy_pass http://nextjs_demo_ecom;
}
# DYNAMIC ASSETS - NO CACHE
location / {
proxy_pass http://nextjs_demo_ecom;
}
}
Dockerfile
FROM nginx:alpine
# Remove any existing config files
RUN rm /etc/nginx/conf.d/*
# Copy config files
# *.conf files in "conf.d/" dir get included in main config
COPY ./default.conf /etc/nginx/conf.d/
# copy ssl material
COPY ./ssl /etc/nginx/ssl/
# Expose the listening port
EXPOSE 80
EXPOSE 443
# Launch NGINX
CMD [ "nginx", "-g", "daemon off;" ]
Deploy multisite#
Folder structure:
- ecommerce-nextjs-tailwind-typescript | NextJs
- material-ui-admin-template | Plain ReactJs
- nginx | Config folder
- .dockerignore
- Dockerfile
The spirit was:
- Build and containerize NextJs Proj separately as it can stand for itself.
- Build and containerize Nginx with all static site (Plain ReactJs in this case).
- Then run the project.