Skip to content

Commit 57e5a4b

Browse files
committed
chores: docker set-up
1 parent 0f5b5b3 commit 57e5a4b

File tree

7 files changed

+921
-4
lines changed

7 files changed

+921
-4
lines changed

.dockerignore

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Dependencies
2+
node_modules/
3+
npm-debug.log
4+
yarn-error.log
5+
package-lock.json
6+
yarn.lock
7+
8+
# Build output
9+
dist/
10+
build/
11+
12+
# Environment files
13+
.env
14+
.env.local
15+
.env.*.local
16+
17+
# Firebase credentials
18+
firebase-service-account.json
19+
20+
# Testing
21+
coverage/
22+
.nyc_output/
23+
24+
# IDEs
25+
.vscode/
26+
.idea/
27+
*.swp
28+
*.swo
29+
*~
30+
.DS_Store
31+
32+
# Git
33+
.git/
34+
.gitignore
35+
.gitattributes
36+
37+
# Documentation (not needed in image)
38+
*.md
39+
docs/
40+
41+
# CI/CD
42+
.github/
43+
.gitlab-ci.yml
44+
.travis.yml
45+
46+
# Docker
47+
Dockerfile
48+
.dockerignore
49+
docker-compose*.yml
50+
51+
# Logs
52+
logs/
53+
*.log

.github/workflows/docker-build.yml

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
name: Build and Push Docker Image
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
- main
8+
tags:
9+
- 'v*'
10+
pull_request:
11+
branches:
12+
- master
13+
- main
14+
15+
env:
16+
REGISTRY: ghcr.io
17+
IMAGE_NAME: ${{ github.repository }}
18+
19+
jobs:
20+
test:
21+
name: Test Application
22+
runs-on: ubuntu-latest
23+
24+
steps:
25+
- name: Checkout code
26+
uses: actions/checkout@v4
27+
28+
- name: Setup Node.js
29+
uses: actions/setup-node@v4
30+
with:
31+
node-version: '18'
32+
cache: 'npm'
33+
34+
- name: Install dependencies
35+
run: npm ci
36+
37+
- name: Run linter
38+
run: npm run lint
39+
40+
- name: Run tests
41+
run: npm run test
42+
continue-on-error: true
43+
44+
- name: Build application
45+
run: npm run build
46+
47+
build-and-push:
48+
name: Build and Push Docker Image
49+
runs-on: ubuntu-latest
50+
needs: test
51+
if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
52+
53+
permissions:
54+
contents: read
55+
packages: write
56+
57+
steps:
58+
- name: Checkout code
59+
uses: actions/checkout@v4
60+
61+
- name: Set up Docker Buildx
62+
uses: docker/setup-buildx-action@v3
63+
64+
- name: Log in to GitHub Container Registry
65+
uses: docker/login-action@v3
66+
with:
67+
registry: ${{ env.REGISTRY }}
68+
username: ${{ github.actor }}
69+
password: ${{ secrets.GITHUB_TOKEN }}
70+
71+
# Optional: Uncomment to push to Docker Hub instead
72+
# - name: Log in to Docker Hub
73+
# uses: docker/login-action@v3
74+
# with:
75+
# username: ${{ secrets.DOCKERHUB_USERNAME }}
76+
# password: ${{ secrets.DOCKERHUB_TOKEN }}
77+
78+
- name: Extract metadata (tags, labels)
79+
id: meta
80+
uses: docker/metadata-action@v5
81+
with:
82+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
83+
tags: |
84+
type=ref,event=branch
85+
type=ref,event=pr
86+
type=semver,pattern={{version}}
87+
type=semver,pattern={{major}}.{{minor}}
88+
type=semver,pattern={{major}}
89+
type=sha,prefix={{branch}}-
90+
type=raw,value=latest,enable={{is_default_branch}}
91+
92+
- name: Build and push Docker image
93+
uses: docker/build-push-action@v5
94+
with:
95+
context: .
96+
file: ./Dockerfile
97+
push: true
98+
tags: ${{ steps.meta.outputs.tags }}
99+
labels: ${{ steps.meta.outputs.labels }}
100+
cache-from: type=gha
101+
cache-to: type=gha,mode=max
102+
platforms: linux/amd64,linux/arm64
103+
104+
- name: Image digest
105+
run: echo ${{ steps.meta.outputs.digest }}

Dockerfile

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Multi-stage Dockerfile for IoT Cloud MCP Bridge Server
2+
3+
# Stage 1: Build
4+
FROM node:18-alpine AS builder
5+
6+
# Set working directory
7+
WORKDIR /app
8+
9+
# Copy package files
10+
COPY package*.json ./
11+
12+
# Install dependencies (including dev dependencies for build)
13+
RUN npm ci
14+
15+
# Copy source code
16+
COPY . .
17+
18+
# Build the application
19+
RUN npm run build
20+
21+
# Remove dev dependencies
22+
RUN npm prune --production
23+
24+
# Stage 2: Production
25+
FROM node:18-alpine AS production
26+
27+
# Set working directory
28+
WORKDIR /app
29+
30+
# Create a non-root user
31+
RUN addgroup -g 1001 -S nodejs && \
32+
adduser -S nestjs -u 1001
33+
34+
# Copy package files
35+
COPY package*.json ./
36+
37+
# Copy built application from builder stage
38+
COPY --from=builder --chown=nestjs:nodejs /app/dist ./dist
39+
COPY --from=builder --chown=nestjs:nodejs /app/node_modules ./node_modules
40+
41+
# Create config directory for Firebase service account
42+
RUN mkdir -p /app/config && chown nestjs:nodejs /app/config
43+
44+
# Switch to non-root user
45+
USER nestjs
46+
47+
# Expose port
48+
EXPOSE 3001
49+
50+
# Health check
51+
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
52+
CMD node -e "require('http').get('http://localhost:3001/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
53+
54+
# Start the application
55+
CMD ["node", "dist/main"]

README.md

Lines changed: 99 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ A Model Context Protocol (MCP) bridge server for the IoT Cloud REST API, enablin
3636

3737
- **[Quick Start Guide](docs/setup/QUICK_START.md)** - Get started quickly
3838
- **[Setup Checklist](docs/setup/SETUP_CHECKLIST.md)** - Complete setup guide
39+
- **[Docker Deployment](docs/deployment/DOCKER_DEPLOYMENT.md)** - Deploy with Docker & CI/CD
3940
- **[Render Deployment](docs/deployment/RENDER_DEPLOYMENT.md)** - Deploy to Render.com
4041
- **[Implementation Notes](docs/development/IMPLEMENTATION_NOTES.md)** - Development notes
4142
- **[Session Summary](docs/development/SESSION_SUMMARY.md)** - Development session logs
@@ -253,11 +254,12 @@ iot-cloud-mcp/
253254
- [x] Health check endpoint
254255
- [x] **MVP REST API endpoints** (Definitions, Locations, Groups, Devices, State)
255256
- [x] **Render deployment guide** (see [RENDER_DEPLOYMENT.md](docs/deployment/RENDER_DEPLOYMENT.md))
257+
- [x] **Docker configuration** (see [DOCKER_DEPLOYMENT.md](docs/deployment/DOCKER_DEPLOYMENT.md))
258+
- [x] **CI/CD pipeline** (GitHub Actions for automated builds)
256259
- [ ] Testing with real Firebase credentials
257260
- [ ] MCP resources (Partner, Project, Device, Location, Group) - Optional
258261
- [ ] MCP tools (CRUD operations) - Optional
259262
- [ ] Extended REST API (POST/PATCH/DELETE operations)
260-
- [ ] Docker configuration
261263

262264
## API Endpoints
263265

@@ -327,12 +329,105 @@ npm run test:cov
327329

328330
### Docker
329331

332+
#### Quick Start with Docker Compose
333+
334+
The easiest way to run with Docker:
335+
336+
```bash
337+
# Create .env file with your configuration
338+
cp .env.example .env
339+
340+
# Build and start the container
341+
docker-compose up -d
342+
343+
# View logs
344+
docker-compose logs -f
345+
346+
# Stop the container
347+
docker-compose down
348+
```
349+
350+
#### Manual Docker Build and Run
351+
330352
```bash
331-
# Build image
353+
# Build the image
332354
docker build -t iot-cloud-mcp .
333355

334-
# Run container
335-
docker run -p 3001:3001 --env-file .env iot-cloud-mcp
356+
# Run with environment file
357+
docker run -d \
358+
--name iot-cloud-mcp \
359+
-p 3001:3001 \
360+
--env-file .env \
361+
iot-cloud-mcp
362+
363+
# Or run with inline environment variables
364+
docker run -d \
365+
--name iot-cloud-mcp \
366+
-p 3001:3001 \
367+
-e NODE_ENV=production \
368+
-e PORT=3001 \
369+
-e IOT_API_BASE_URL=https://your-api.com \
370+
-e IOT_API_KEY=your-key \
371+
-e FIREBASE_SERVICE_ACCOUNT='{"type":"service_account",...}' \
372+
iot-cloud-mcp
373+
374+
# View logs
375+
docker logs -f iot-cloud-mcp
376+
377+
# Stop and remove container
378+
docker stop iot-cloud-mcp && docker rm iot-cloud-mcp
379+
```
380+
381+
#### Pull from GitHub Container Registry
382+
383+
Once CI/CD is set up, pull pre-built images:
384+
385+
```bash
386+
# Pull latest image
387+
docker pull ghcr.io/YOUR_USERNAME/iot-cloud-mcp:latest
388+
389+
# Run the pulled image
390+
docker run -d \
391+
--name iot-cloud-mcp \
392+
-p 3001:3001 \
393+
--env-file .env \
394+
ghcr.io/YOUR_USERNAME/iot-cloud-mcp:latest
395+
```
396+
397+
### CI/CD Pipeline
398+
399+
The project includes a GitHub Actions workflow that automatically:
400+
401+
- ✅ Runs tests and linting on every push and pull request
402+
- ✅ Builds Docker images on push to `master`/`main` branch
403+
- ✅ Pushes images to GitHub Container Registry (GHCR)
404+
- ✅ Tags images with version numbers (from git tags)
405+
- ✅ Supports multi-architecture builds (amd64, arm64)
406+
407+
**Setup Steps:**
408+
409+
1. The workflow is already configured in [.github/workflows/docker-build.yml](.github/workflows/docker-build.yml)
410+
2. GitHub automatically provides `GITHUB_TOKEN` for GHCR access
411+
3. Push to `master` or `main` branch triggers the build
412+
4. Images are available at `ghcr.io/YOUR_USERNAME/iot-cloud-mcp`
413+
414+
**Optional: Push to Docker Hub**
415+
416+
To also push to Docker Hub, add secrets to your GitHub repository:
417+
418+
1. Go to **Settings****Secrets and variables****Actions**
419+
2. Add `DOCKERHUB_USERNAME` and `DOCKERHUB_TOKEN`
420+
3. Uncomment the Docker Hub login section in the workflow file
421+
422+
**Triggering Builds:**
423+
424+
```bash
425+
# Automatic build on push to master
426+
git push origin master
427+
428+
# Create a version tag for releases
429+
git tag -a v1.0.0 -m "Release v1.0.0"
430+
git push origin v1.0.0
336431
```
337432

338433
### Railway

0 commit comments

Comments
 (0)