Skip to content

Commit a000aee

Browse files
committed
use 3 different dockerfiles
1 parent 461df27 commit a000aee

File tree

15 files changed

+377
-54
lines changed

15 files changed

+377
-54
lines changed

Makefile

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,35 @@
1-
.PHONY: build-production
2-
build-production: ## Build the production docker image.
3-
BUILDKIT_PROGRESS=plain docker compose build
1+
.PHONY: build-dev
2+
build-dev: ## Build the development docker image.
3+
BUILDKIT_PROGRESS=plain docker compose -f docker/development/docker-compose.yml build
44

5-
.PHONY: start-production
6-
start-production: ## Start the production docker container.
7-
BUILDKIT_PROGRESS=plain docker compose up -d
5+
.PHONY: start-dev
6+
start-dev: ## Start the development docker container.
7+
BUILDKIT_PROGRESS=plain docker compose -f docker/development/docker-compose.yml up -d
88

9-
.PHONY: stop-production
10-
stop-production: ## Stop the production docker container.
11-
BUILDKIT_PROGRESS=plain docker compose down
9+
.PHONY: stop-dev
10+
stop-dev: ## Stop the development docker container.
11+
BUILDKIT_PROGRESS=plain docker compose -f docker/development/docker-compose.yml down
12+
13+
.PHONY: build-stag
14+
build-stag: ## Build the staging docker image.
15+
BUILDKIT_PROGRESS=plain docker compose -f docker/staging/docker-compose.yml build
16+
17+
.PHONY: start-stag
18+
start-stag: ## Start the staging docker container.
19+
BUILDKIT_PROGRESS=plain docker compose -f docker/staging/docker-compose.yml up -d
20+
21+
.PHONY: stop-stag
22+
stop-stag: ## Stop the staging docker container.
23+
BUILDKIT_PROGRESS=plain docker compose -f docker/staging/docker-compose.yml down
24+
25+
.PHONY: build-prod
26+
build-prod: ## Build the production docker image.
27+
BUILDKIT_PROGRESS=plain docker compose -f docker/production/docker-compose.yml build
28+
29+
.PHONY: start-prod
30+
start-prod: ## Start the production docker container.
31+
BUILDKIT_PROGRESS=plain docker compose -f docker/production/docker-compose.yml up -d
32+
33+
.PHONY: stop-prod
34+
stop-prod: ## Stop the production docker container.
35+
BUILDKIT_PROGRESS=plain docker compose -f docker/production/docker-compose.yml down

docker-compose.yml

Lines changed: 0 additions & 15 deletions
This file was deleted.

docker/development/Dockerfile

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
FROM node:20-alpine AS base
2+
3+
# mostly inspired from https://github.com/BretFisher/node-docker-good-defaults/blob/main/Dockerfile & https://github.com/remix-run/example-trellix/blob/main/Dockerfile
4+
5+
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
6+
RUN apk add --no-cache libc6-compat
7+
RUN corepack enable && corepack prepare pnpm@8.15.4 --activate
8+
# set the store dir to a folder that is not in the project
9+
RUN pnpm config set store-dir ~/.pnpm-store
10+
RUN pnpm fetch
11+
12+
# 1. Install all dependencies including dev dependencies
13+
FROM base AS deps
14+
# Root user is implicit so you don't have to actually specify it. From https://stackoverflow.com/a/45553149/6141587
15+
# USER root
16+
USER node
17+
# WORKDIR now sets correct permissions if you set USER first so `USER node` has permissions on `/app` directory
18+
WORKDIR /app
19+
20+
# Install dependencies based on the preferred package manager
21+
COPY --chown=node:node package.json pnpm-lock.yaml* ./
22+
COPY --chown=node:node /src/app/db/migrations ./migrations
23+
24+
RUN pnpm install --frozen-lockfile --prefer-offline
25+
RUN pnpm install sharp@0.32.6
26+
27+
# 2. Start the development server
28+
# Inspired by https://github.com/vercel/next.js/discussions/36935
29+
RUN mkdir -p /app/.next/cache && chown -R node:node /app/.next/cache
30+
# Persist the next cache in a volume
31+
VOLUME ["/app/.next/cache"]
32+
# COPY --from=deps --chown=node:node /app/node_modules ./node_modules
33+
COPY --chown=node:node . .
34+
35+
# This will do the trick, use the corresponding env file for each environment.
36+
COPY --chown=node:node .env.development .env.development
37+
38+
# Copied from https://stackoverflow.com/a/69867550/6141587
39+
USER root
40+
# Give /data directory correct permissions otherwise WAL mode won't work. It means you can't have 2 users writing to the database at the same time without this line as *.sqlite-wal & *.sqlite-shm are automatically created & deleted when *.sqlite is busy.
41+
RUN mkdir -p /data && chown -R node:node /data
42+
43+
USER node
44+
EXPOSE 3000
45+
46+
ENV PORT 3000
47+
ENV HOSTNAME 0.0.0.0
48+
ENV NODE_ENV development
49+
ENV NEXT_TELEMETRY_DISABLED 1
50+
51+
COPY --chown=node:node public ./public
52+
53+
# Move the drizzle directory to the runtime image
54+
COPY --chown=node:node src/app/db/migrations ./migrations
55+
COPY --chown=node:node scripts/drizzle-migrate.mjs ./scripts/drizzle-migrate.mjs
56+
COPY --chown=node:node scripts/package.json ./scripts/package.json
57+
COPY --chown=node:node scripts/pnpm-lock.yaml ./scripts/pnpm-lock.yaml
58+
COPY --chown=node:node scripts/run.dev.sh ./run.dev.sh
59+
RUN chmod +x run.dev.sh
60+
61+
CMD ["sh", "run.dev.sh"]

docker/development/docker-compose.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
version: '3.8'
2+
3+
services:
4+
redis:
5+
image: redis:7.2.4-alpine
6+
container_name: en_redis_dev
7+
env_file:
8+
- ../../.env.development
9+
restart: always
10+
ports:
11+
- 6379:6379
12+
command: redis-server --save 60 1 --loglevel warning --requirepass 422af0c647e8c81cf20e
13+
healthcheck:
14+
test: ['CMD', 'redis-cli', 'ping']
15+
interval: 5s
16+
timeout: 30s
17+
retries: 50
18+
volumes:
19+
- redis_data:/data
20+
web:
21+
image: easypanel-nextjs:0.0.1
22+
build:
23+
context: ../../
24+
dockerfile: docker/development/Dockerfile
25+
container_name: en_dev
26+
env_file:
27+
- ../../.env.development
28+
ports:
29+
- 3000:3000
30+
volumes:
31+
- ../../data:/data
32+
restart: unless-stopped
33+
depends_on:
34+
redis:
35+
condition: service_healthy
36+
volumes:
37+
redis_data:
38+
driver: local

Dockerfile renamed to docker/production/Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ COPY --from=builder --chown=node:node /app/litestream.yml /etc/litestream.yml
8080
COPY --from=builder --chown=node:node /app/scripts/drizzle-migrate.mjs ./scripts/drizzle-migrate.mjs
8181
COPY --from=builder --chown=node:node /app/scripts/package.json ./scripts/package.json
8282
COPY --from=builder --chown=node:node /app/scripts/pnpm-lock.yaml ./scripts/pnpm-lock.yaml
83-
COPY --from=builder --chown=node:node /app/scripts/run.sh ./run.sh
84-
RUN chmod +x run.sh
83+
COPY --from=builder --chown=node:node /app/scripts/run.prod.sh ./run.prod.sh
84+
RUN chmod +x run.prod.sh
8585

86-
CMD ["sh", "run.sh"]
86+
CMD ["sh", "run.prod.sh"]

docker/production/docker-compose.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
version: '3.8'
2+
3+
services:
4+
redis:
5+
image: redis:7.2.4-alpine
6+
container_name: en_redis_prod
7+
env_file:
8+
- ../../.env.production
9+
restart: always
10+
ports:
11+
- 6379:6379
12+
command: redis-server --save 60 1 --loglevel warning --requirepass 422af0c647e8c81cf20e
13+
healthcheck:
14+
test: ['CMD', 'redis-cli', 'ping']
15+
interval: 5s
16+
timeout: 30s
17+
retries: 50
18+
volumes:
19+
- redis_data:/data
20+
web:
21+
image: easypanel-nextjs:0.0.1
22+
build:
23+
context: ../../
24+
dockerfile: docker/production/Dockerfile
25+
container_name: en_prod
26+
env_file:
27+
- ../../.env.production
28+
ports:
29+
- 3000:3000
30+
volumes:
31+
- ../../data:/data
32+
restart: unless-stopped
33+
depends_on:
34+
redis:
35+
condition: service_healthy
36+
volumes:
37+
redis_data:
38+
driver: local

docker/staging/Dockerfile

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
FROM node:20-alpine AS base
2+
3+
# mostly inspired from https://github.com/BretFisher/node-docker-good-defaults/blob/main/Dockerfile & https://github.com/remix-run/example-trellix/blob/main/Dockerfile
4+
5+
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
6+
RUN apk add --no-cache libc6-compat
7+
RUN corepack enable && corepack prepare pnpm@8.15.4 --activate
8+
# set the store dir to a folder that is not in the project
9+
RUN pnpm config set store-dir ~/.pnpm-store
10+
RUN pnpm fetch
11+
12+
# 1. Install all dependencies including dev dependencies
13+
FROM base AS deps
14+
# Root user is implicit so you don't have to actually specify it. From https://stackoverflow.com/a/45553149/6141587
15+
# USER root
16+
USER node
17+
# WORKDIR now sets correct permissions if you set USER first so `USER node` has permissions on `/app` directory
18+
WORKDIR /app
19+
20+
# Install dependencies based on the preferred package manager
21+
COPY --chown=node:node package.json pnpm-lock.yaml* ./
22+
COPY --chown=node:node /src/app/db/migrations ./migrations
23+
24+
USER root
25+
RUN pnpm install --frozen-lockfile --prefer-offline
26+
RUN pnpm install sharp@0.32.6
27+
28+
# 2. Rebuild the source code only when needed
29+
FROM base AS builder
30+
WORKDIR /app
31+
# Inspired by https://github.com/vercel/next.js/discussions/36935
32+
RUN mkdir -p /app/.next/cache && chown -R node:node /app/.next/cache
33+
# Persist the next cache in a volume
34+
VOLUME ["/app/.next/cache"]
35+
COPY --from=deps --chown=node:node /app/node_modules ./node_modules
36+
37+
COPY --chown=node:node . .
38+
39+
# This will do the trick, use the corresponding env file for each environment.
40+
COPY --chown=node:node .env.staging .env.staging
41+
42+
# Copied from https://stackoverflow.com/a/69867550/6141587
43+
USER root
44+
# Give /data directory correct permissions otherwise WAL mode won't work. It means you can't have 2 users writing to the database at the same time without this line as *.sqlite-wal & *.sqlite-shm are automatically created & deleted when *.sqlite is busy.
45+
RUN mkdir -p /data && chown -R node:node /data
46+
47+
# set to production otherwise it throws error ⚠ You are using a non-standard "NODE_ENV" value in your environment. This creates inconsistencies in the project and is strongly advised against. Read more: https://nextjs.org/docs/messages/non-standard-node-env
48+
ENV NODE_ENV production
49+
ENV NEXT_TELEMETRY_DISABLED 1
50+
51+
RUN pnpm build
52+
53+
# 3. Production image, copy all the files and run next
54+
FROM base AS runner
55+
USER node
56+
WORKDIR /app
57+
58+
EXPOSE 3000
59+
60+
ENV PORT 3000
61+
ENV HOSTNAME 0.0.0.0
62+
ENV NODE_ENV production
63+
ENV NEXT_TELEMETRY_DISABLED 1
64+
65+
COPY --from=builder --chown=node:node /app/public ./public
66+
67+
# Automatically leverage output traces to reduce image size
68+
# https://nextjs.org/docs/advanced-features/output-file-tracing
69+
COPY --from=builder --chown=node:node /app/.next/standalone ./
70+
COPY --from=builder --chown=node:node /app/.next/static ./.next/static
71+
72+
# Move the drizzle directory to the runtime image
73+
COPY --from=builder --chown=node:node /app/src/app/db/migrations ./migrations
74+
75+
# Move the litestream binary to the runtime image from the litestream image
76+
# You can use a specific version of litestream by changing the tag
77+
# COPY --from=litestream/litestream:0.3.13 /usr/local/bin/litestream /usr/local/bin/litestream
78+
COPY --from=litestream/litestream:latest --chown=node:node /usr/local/bin/litestream /usr/local/bin/litestream
79+
COPY --from=builder --chown=node:node /app/litestream.yml /etc/litestream.yml
80+
81+
COPY --from=builder --chown=node:node /app/scripts/drizzle-migrate.mjs ./scripts/drizzle-migrate.mjs
82+
COPY --from=builder --chown=node:node /app/scripts/package.json ./scripts/package.json
83+
COPY --from=builder --chown=node:node /app/scripts/pnpm-lock.yaml ./scripts/pnpm-lock.yaml
84+
COPY --from=builder --chown=node:node /app/scripts/run.staging.sh ./run.staging.sh
85+
RUN chmod +x run.staging.sh
86+
87+
CMD ["sh", "run.staging.sh"]

docker/staging/docker-compose.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
version: '3.8'
2+
3+
services:
4+
redis:
5+
image: redis:7.2.4-alpine
6+
container_name: en_redis_staging
7+
env_file:
8+
- ../../.env.staging
9+
restart: always
10+
ports:
11+
- 6379:6379
12+
command: redis-server --save 60 1 --loglevel warning --requirepass 422af0c647e8c81cf20e
13+
healthcheck:
14+
test: ['CMD', 'redis-cli', 'ping']
15+
interval: 5s
16+
timeout: 30s
17+
retries: 50
18+
volumes:
19+
- redis_data:/data
20+
web:
21+
image: easypanel-nextjs:0.0.1
22+
build:
23+
context: ../../
24+
dockerfile: docker/staging/Dockerfile
25+
container_name: en_staging
26+
env_file:
27+
- ../../.env.staging
28+
ports:
29+
- 3000:3000
30+
volumes:
31+
- ../../data:/data
32+
restart: unless-stopped
33+
depends_on:
34+
redis:
35+
condition: service_healthy
36+
volumes:
37+
redis_data:
38+
driver: local

drizzle.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { Config } from 'drizzle-kit'
22
import * as dotenv from 'dotenv'
33

4+
// bug in drizzle: see https://github.com/drizzle-team/drizzle-orm/issues/1228
45
// import { env } from '@app/lib/env'
56

67
dotenv.config({ path: '.env.development' })
@@ -10,7 +11,7 @@ if (!process.env.SQLITE_DATABASE_NAME) {
1011
}
1112

1213
// only ran in development so no need to dd a production check
13-
export const url = `${process.env.SQLITE_DATABASE_NAME}`
14+
const url = `${process.env.SQLITE_DATABASE_NAME}`
1415

1516
export default {
1617
schema: './src/app/db/schema.ts',

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
"clean": "rimraf .next",
1414
"db:push": "drizzle-kit push:sqlite",
1515
"db:generate": "drizzle-kit generate:sqlite",
16-
"db:migrate": "node --env-file .env.development ./scripts/drizzle-migrate.mjs",
1716
"db:seed": "node --import tsx --env-file .env.development ./scripts/seed/insert.ts",
1817
"db:delete": "node --import tsx --env-file .env.development ./scripts/seed/delete.ts",
18+
"db:migrate:dev": "node --env-file .env.development ./scripts/drizzle-migrate.mjs",
1919
"db:migrate:prod": "node --env-file .env.production ./scripts/drizzle-migrate.mjs"
2020
},
2121
"dependencies": {

0 commit comments

Comments
 (0)