Skip to content

Commit d760ab8

Browse files
committed
feat: implement dockerisation
1 parent ee65b16 commit d760ab8

File tree

5 files changed

+368
-0
lines changed

5 files changed

+368
-0
lines changed

.dockerignore

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Dependencies
2+
node_modules/
3+
4+
# Build output
5+
dist/
6+
7+
# Environment files
8+
.env
9+
.env.*
10+
11+
# Git
12+
.git/
13+
.gitignore
14+
.gitattributes
15+
16+
# IDE
17+
.vscode/
18+
.idea/
19+
.cursor/
20+
*.swp
21+
*.swo
22+
*~
23+
.DS_Store
24+
25+
# CI/CD
26+
.github/
27+
28+
# Documentation
29+
*.md
30+
!DOCKER.md
31+
32+
# Test files
33+
test/
34+
*.test.ts
35+
*.test.js
36+
37+
# Logs
38+
logs/
39+
*.log
40+
npm-debug.log*
41+
pnpm-debug.log*
42+
43+
# Misc
44+
.husky/
45+

DOCKER.md

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
# Docker Setup Guide
2+
3+
This document explains how to run the webdev-bot using Docker.
4+
5+
## Prerequisites
6+
7+
- Docker installed (version 20.10 or higher)
8+
- Docker Compose installed (version 2.0 or higher)
9+
- `.env.local` file with required environment variables
10+
11+
## Node Version Management
12+
13+
The Docker setup uses `.nvmrc` as the single source of truth for the Node.js version. The Dockerfile automatically reads this version at build time via the `NODE_VERSION` build argument. No need to manually sync versions between `.nvmrc` and Docker files.
14+
15+
## Environment Variables
16+
17+
Before running the bot, create a `.env.local` file in the project root with the following variables:
18+
19+
```env
20+
DISCORD_TOKEN=your_discord_bot_token
21+
CLIENT_ID=your_discord_client_id
22+
```
23+
24+
These variables are loaded automatically by docker-compose and used by `src/env.ts`.
25+
26+
## Quick Start
27+
28+
### Development Mode
29+
30+
Run the bot with hot reload enabled for development:
31+
32+
```bash
33+
pnpm run docker:dev
34+
```
35+
36+
Or using docker-compose directly:
37+
38+
```bash
39+
docker compose --profile dev up
40+
```
41+
42+
In development mode:
43+
- Code changes in `src/` are automatically detected and the bot restarts
44+
- Full development dependencies are available
45+
- Logs are streamed to your terminal
46+
47+
To stop the development container:
48+
49+
```bash
50+
pnpm run docker:stop
51+
# or
52+
docker compose --profile dev down
53+
```
54+
55+
### Production Mode
56+
57+
Run the bot in production mode with optimized image:
58+
59+
```bash
60+
pnpm run docker:prod
61+
```
62+
63+
Or using docker-compose directly:
64+
65+
```bash
66+
docker compose --profile prod up -d
67+
```
68+
69+
In production mode:
70+
- Minimal image size (only production dependencies)
71+
- Optimized for runtime performance
72+
- Runs in detached mode by default
73+
74+
To stop the production container:
75+
76+
```bash
77+
docker compose --profile prod down
78+
```
79+
80+
## Manual Docker Commands
81+
82+
### Build the Image
83+
84+
Build the production image:
85+
86+
```bash
87+
docker build -t webdev-bot:latest \
88+
--build-arg NODE_VERSION=$(cat .nvmrc | tr -d 'v') \
89+
--target production .
90+
```
91+
92+
Build the development image:
93+
94+
```bash
95+
docker build -t webdev-bot:dev \
96+
--build-arg NODE_VERSION=$(cat .nvmrc | tr -d 'v') \
97+
--target development .
98+
```
99+
100+
### Run Without Compose
101+
102+
Run the production container manually (after building with the NODE_VERSION arg):
103+
104+
```bash
105+
docker run -d \
106+
--name webdev-bot \
107+
--env-file .env.local \
108+
--restart unless-stopped \
109+
webdev-bot:latest
110+
```
111+
112+
Run the development container manually (after building with the NODE_VERSION arg):
113+
114+
```bash
115+
docker run -it \
116+
--name webdev-bot-dev \
117+
--env-file .env.local \
118+
-v $(pwd)/src:/app/src:ro \
119+
webdev-bot:dev
120+
```
121+
122+
## Troubleshooting
123+
124+
### Bot Not Starting
125+
126+
1. Check if environment variables are set correctly:
127+
```bash
128+
docker compose --profile dev run --rm bot-dev env | grep DISCORD
129+
```
130+
131+
2. View container logs:
132+
```bash
133+
docker compose --profile dev logs bot-dev
134+
# or
135+
docker logs webdev-bot-dev
136+
```
137+
138+
### Permission Issues
139+
140+
If you encounter permission issues with mounted volumes, ensure that the files have appropriate read permissions:
141+
142+
```bash
143+
chmod -R 644 src/
144+
chmod 755 src/
145+
```
146+
147+
### Hot Reload Not Working
148+
149+
If code changes aren't being detected in development mode:
150+
151+
1. Verify the volume mounts are correct:
152+
```bash
153+
docker inspect webdev-bot-dev | grep Mounts -A 10
154+
```
155+
156+
2. Restart the container:
157+
```bash
158+
docker compose --profile dev restart
159+
```
160+
161+
### Image Size Concerns
162+
163+
The production image is optimized for size using:
164+
- Alpine Linux base image
165+
- Multi-stage builds (dev dependencies not included)
166+
- Only compiled `dist/` folder and production dependencies
167+
168+
To check image size:
169+
170+
```bash
171+
docker images webdev-bot
172+
```
173+
174+
### Rebuilding After Dependency Changes
175+
176+
If you modify `package.json` or `pnpm-lock.yaml`, rebuild the image:
177+
178+
```bash
179+
pnpm run docker:build
180+
# or
181+
docker compose build --no-cache
182+
```
183+
184+
## Best Practices
185+
186+
1. **Never commit `.env.local`** - Keep your secrets secure
187+
2. **Use production profile for deployment** - Smaller, more secure images
188+
3. **Keep development profile for local testing** - Faster iteration with hot reload
189+
4. **Node version is managed in `.nvmrc`** - Update `.nvmrc` to change Node version for Docker
190+
5. **Regularly update the base image** - Rebuild images after updating `.nvmrc`
191+
6. **Monitor container resources** - Use `docker stats` to check resource usage
192+
193+
## Additional Commands
194+
195+
View running containers:
196+
```bash
197+
docker ps
198+
```
199+
200+
View all containers (including stopped):
201+
```bash
202+
docker ps -a
203+
```
204+
205+
Remove all stopped containers:
206+
```bash
207+
docker compose down -v
208+
```
209+
210+
View container logs in real-time:
211+
```bash
212+
docker compose --profile dev logs -f bot-dev
213+
```
214+
215+
Execute commands inside the container:
216+
```bash
217+
docker compose --profile dev exec bot-dev sh
218+
```
219+

Dockerfile

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Base stage - Setup Node.js and pnpm
2+
# Node version is read from .nvmrc at build time via NODE_VERSION build arg
3+
ARG NODE_VERSION=22.20.0
4+
FROM node:${NODE_VERSION}-alpine AS base
5+
6+
# Install pnpm
7+
RUN corepack enable && corepack prepare [email protected] --activate
8+
9+
WORKDIR /app
10+
11+
# Dependencies stage - Install production dependencies only
12+
FROM base AS deps
13+
14+
COPY package.json pnpm-lock.yaml ./
15+
16+
RUN pnpm install --prod --frozen-lockfile
17+
18+
# Dev dependencies stage - Install all dependencies
19+
FROM base AS deps-dev
20+
21+
COPY package.json pnpm-lock.yaml ./
22+
23+
RUN pnpm install --frozen-lockfile
24+
25+
# Build stage - Compile TypeScript
26+
FROM deps-dev AS build
27+
28+
COPY . .
29+
30+
RUN pnpm run build:ci
31+
32+
# Production stage - Minimal runtime image
33+
FROM base AS production
34+
35+
ENV NODE_ENV=production
36+
37+
# Copy production dependencies from deps stage
38+
COPY --from=deps /app/node_modules ./node_modules
39+
40+
# Copy built application
41+
COPY --from=build /app/dist ./dist
42+
COPY package.json ./
43+
44+
# Run as non-root user for security
45+
USER node
46+
47+
CMD ["node", "dist/index.js"]
48+
49+
# Development stage - Full dev environment with hot reload
50+
FROM deps-dev AS development
51+
52+
ENV NODE_ENV=development
53+
54+
COPY . .
55+
56+
# Run as non-root user for security
57+
USER node
58+
59+
CMD ["pnpm", "run", "dev"]
60+

docker-compose.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
version: '3.8'
2+
3+
services:
4+
# Production service - optimized runtime
5+
bot-prod:
6+
build:
7+
context: .
8+
target: production
9+
args:
10+
NODE_VERSION: ${NODE_VERSION}
11+
container_name: webdev-bot-prod
12+
restart: unless-stopped
13+
env_file:
14+
- .env.local
15+
profiles:
16+
- prod
17+
18+
# Development service - hot reload enabled
19+
bot-dev:
20+
build:
21+
context: .
22+
target: development
23+
args:
24+
NODE_VERSION: ${NODE_VERSION}
25+
container_name: webdev-bot-dev
26+
restart: unless-stopped
27+
env_file:
28+
- .env.local
29+
volumes:
30+
# Mount source code for hot reload
31+
- ./src:/app/src:ro
32+
# Mount config files
33+
- ./tsconfig.json:/app/tsconfig.json:ro
34+
- ./biome.json:/app/biome.json:ro
35+
# Mount package files (in case dependencies change)
36+
- ./package.json:/app/package.json:ro
37+
- ./pnpm-lock.yaml:/app/pnpm-lock.yaml:ro
38+
profiles:
39+
- dev
40+

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
"start": "node dist/index.js",
1212
"dev": "tsx watch src/index.ts",
1313
"deploy": "tsx src/util/deploy.ts",
14+
"docker:build": "NODE_VERSION=$(cat .nvmrc | tr -d 'v') docker compose build",
15+
"docker:dev": "NODE_VERSION=$(cat .nvmrc | tr -d 'v') docker compose --profile dev up",
16+
"docker:prod": "NODE_VERSION=$(cat .nvmrc | tr -d 'v') docker compose --profile prod up -d",
17+
"docker:stop": "docker compose down",
1418
"lint": "biome lint .",
1519
"lint:fix": "biome lint --fix .",
1620
"format": "biome format --write .",

0 commit comments

Comments
 (0)