Skip to content

Commit

Permalink
migrate to bun distroless
Browse files Browse the repository at this point in the history
  • Loading branch information
musenkishi committed Aug 7, 2024
1 parent a461761 commit bed387c
Show file tree
Hide file tree
Showing 13 changed files with 76 additions and 298 deletions.
59 changes: 30 additions & 29 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,35 +1,36 @@
FROM node:20-alpine AS build
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# Production stage
FROM node:20-alpine
FROM oven/bun:latest AS base
WORKDIR /usr/src/app

# Install su-exec
RUN apk add --no-cache su-exec

# Copy only the necessary files from the build stage
COPY --from=build /usr/src/app/package*.json ./
COPY --from=build /usr/src/app/node_modules ./node_modules
COPY --from=build /usr/src/app/dist ./

# Create /data directory
RUN mkdir -p /data
# install dependencies into temp directory
# this will cache them and speed up future builds
FROM base AS install
RUN mkdir -p /temp/dev
COPY package.json bun.lockb /temp/dev/
RUN cd /temp/dev && bun install --frozen-lockfile

# install with --production (exclude devDependencies)
RUN mkdir -p /temp/prod
COPY package.json bun.lockb /temp/prod/
RUN cd /temp/prod && bun install --frozen-lockfile --production

# make node_modules readable for all users
# see https://github.com/oven-sh/bun/issues/10331 why this is needed
RUN chmod -R a+r /temp/prod/node_modules

# copy node_modules from temp directory
# then copy all (non-ignored) project files into the image
FROM base AS prerelease
COPY --from=install /temp/dev/node_modules node_modules
COPY . .

# Create symbolic link for easier volume mount
RUN ln -sfn /data /usr/src/app/data
ENV NODE_ENV=production

# Define environment variables for user and group IDs (optional)
ENV PUID=
ENV PGID=
# copy production dependencies and source code into final image
FROM oven/bun:distroless AS release
WORKDIR /

# Copy entrypoint script
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
COPY --from=install /temp/prod/node_modules node_modules
COPY --from=prerelease /usr/src/app/src .
COPY --from=prerelease /usr/src/app/package.json .

ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["node", "app.js"]
ENTRYPOINT [ "bun", "run", "app.ts", "--target=node" ]
19 changes: 9 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# Bahnhof Watchdog

Bahnhof Watchdog is a Node.js service that periodically checks for current and planned outages in your area from the ISP named Bahnhof. It also checks if your current subscription is priced higher than what is listed on their website. Notifications are sent via a Discord webhook or via email (Gmail only) if any issues are found.
Bahnhof Watchdog is a Bun-based background service that periodically checks for current and planned outages in your area from the ISP named Bahnhof. It also checks if your current subscription is priced higher than what is listed on their website. Notifications are sent through a Discord webhook or by email (Gmail only) if any issues are found.

## Features

Expand Down Expand Up @@ -58,6 +58,7 @@ MAIL_RECEIVER="[email protected]"
bahnhof-watchdog:
container_name: bahnhof-watchdog
image: musenkishi/bahnhof-watchdog:latest
user: ${PUID}:${PGID} # optional
volumes:
- data:/data
restart: unless-stopped
Expand Down Expand Up @@ -85,6 +86,10 @@ MAIL_RECEIVER="[email protected]"
```bash
docker run --env-file .env musenkishi/bahnhof-watchdog:latest
```
3. **Alternative: Run with specific user/group**
```bash
docker run --user 1000:1000 --env-file .env musenkishi/bahnhof-watchdog:latest
```

#### Building the Image Locally

Expand Down Expand Up @@ -121,21 +126,15 @@ MAIL_RECEIVER="[email protected]"
2. **Install dependencies**:

```bash
npm install
bun install
```

3. **Create a `.env` file** in the root directory and add your environment variables as described above.

4. **Build the project**

```bash
tsc
```

5. **Run the service**:
4. **Run the service**:

```bash
node dist/app.js
bun start
```

## Usage
Expand Down
Binary file added bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ services:
bahnhof-watchdog:
container_name: bahnhof-watchdog
image: musenkishi/bahnhof-watchdog:latest
user: ${PUID}:${PGID} # optional
volumes:
- data:/data
restart: unless-stopped
Expand Down
42 changes: 0 additions & 42 deletions docker-entrypoint.sh

This file was deleted.

19 changes: 8 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,23 @@
"displayName": "Bahnhof Watchdog",
"description": "A service that notifies you of changed subscription prices or scheduled/active downtime as listed by the ISP Bahnhof.",
"author": "Freddie Lust-Hed",
"version": "1.0.0",
"version": "1.1.0",
"main": "dist/app.js",
"license": "MIT",
"scripts": {
"build": "tsc",
"dev": "tsc && node dist/app.js",
"start": "node dist/app.js"
"build": "bun build ./src/app.ts --outdir ./build --target=node",
"start": "bun src/app.ts --target=node"
},
"devDependencies": {
"@types/node": "^20.14.9",
"@types/node-cron": "^3.0.11",
"@types/nodemailer": "^6.4.15",
"@types/turndown": "^5.0.4",
"typescript": "^5.5.3"
"@types/turndown": "^5.0.5",
"bun-types": "^1.1.21",
"typescript": "^5.5.4"
},
"dependencies": {
"axios": "^1.7.2",
"axios": "^1.7.3",
"cron": "^3.1.7",
"cronstrue": "^2.50.0",
"dotenv": "^16.4.5",
"node-cron": "^3.0.3",
"nodemailer": "^6.9.14",
"path": "^0.12.7",
"turndown": "^7.2.0"
Expand Down
23 changes: 5 additions & 18 deletions src/api/file.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
import { writeFileSync } from "node:fs"
import {
access,
appendFile,
constants,
mkdir,
readFile,
writeFile,
} from "node:fs/promises"
import { access, appendFile, constants, mkdir } from "node:fs/promises"
import { join } from "path"

const DATA_PATH = "data"
Expand All @@ -27,30 +19,25 @@ export const loadFile = async (filename: string) => {
await fileExists(filename).then((exists) => {
if (!exists) {
try {
createFile(filename, "")
writeFile(filename, "")
} catch (err) {
console.error("Error creating file", err.message)
}
}
})

try {
const data = await readFile(filePath, FILE_ENCODING)
const data = await Bun.file(filePath).text()
return data
} catch (err) {
console.error(`Error reading file: ${err.message}`)
throw err
}
}

export const syncFile = (filename: string, data: string) => {
console.log("Syncing file", filename, "to", getFilePath(filename))
writeFileSync(join(DATA_PATH, filename), data, FILE_ENCODING)
}

export const createFile = async (filename: string, data: string) => {
export const writeFile = async (filename: string, data: string) => {
console.log("Creating file", filename, "...")
await writeFile(getFilePath(filename), data, "utf-8")
await Bun.write(getFilePath(filename), data)
}

export const addToFile = async (filename: string, data: string) => {
Expand Down
20 changes: 10 additions & 10 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import cronstrue from "cronstrue"
import dotenv from "dotenv"
import cron from "node-cron"
import { CronJob } from "cron"
import { getOperations, getProducts, sendWebhook } from "./api/api"
import { sendMail } from "./api/mail"
import { Subscription } from "./types/subscription"
Expand All @@ -17,9 +16,6 @@ import {
import { findProductAndConvertWithReduce as getListedSubscription } from "./util/product"
import { checkVersion } from "./util/version"

//Load variables from .env file
dotenv.config()

checkVersion()

const currentSubscription: Subscription = {
Expand Down Expand Up @@ -126,11 +122,15 @@ if (CRON_SCHEDULE) {
if (process.env.SEND_STARTUP_MESSAGE == "true") {
sendReport(startMessage, true)
}
cron.schedule(CRON_SCHEDULE, () => {
doPatrol((report) => {
sendReport(report)
})
})
const job = new CronJob(
CRON_SCHEDULE,
() => {
doPatrol((report) => {
sendReport(report)
})
},
)
job.start()
} else {
console.info(
"Missing CRON_SCHEDULE environment variable. Only running patrol once..."
Expand Down
4 changes: 2 additions & 2 deletions src/util/buffer.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { loadFile, syncFile } from "../api/file"
import { loadFile, writeFile } from "../api/file"

const FILENAME_BUFFER = "watchdog_buffer.json"
const MAX_BUFFER_SIZE = 20 // No need to store more than this

export const syncBuffer = (buffer: Map<string, unknown>) => {
syncFile(FILENAME_BUFFER, JSON.stringify([...buffer]))
writeFile(FILENAME_BUFFER, JSON.stringify([...buffer]))
}

export const loadBuffer = async () => {
Expand Down
4 changes: 2 additions & 2 deletions src/util/log.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { addToFile, createFile, fileExists, loadFile } from "../api/file"
import { addToFile, writeFile, fileExists, loadFile } from "../api/file"
import { LogSubscription } from "../types/log"
import { Subscription } from "../types/subscription"

Expand Down Expand Up @@ -29,7 +29,7 @@ export const logPrice = async (

if (!fileExist) {
const header = ["Speed", "Address", "Current Price", "Listed Price", "Date"]
await createFile(LOG_PRICE_FILENAME, header.join(CSV_SEPARATOR) + "\n")
await writeFile(LOG_PRICE_FILENAME, header.join(CSV_SEPARATOR) + "\n")
} else {
// Check for duplicates
const fileContent = await loadFile(LOG_PRICE_FILENAME)
Expand Down
6 changes: 3 additions & 3 deletions src/util/version.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { loadFile, syncFile } from "../api/file"
import { loadFile, writeFile } from "../api/file"

const FILENAME_VERSION = ".version"
const VERSION = "1.0.0"
const VERSION = "1.1.0"

export const checkVersion = async () => {
const existingVerFile = await loadFile(FILENAME_VERSION)
if (existingVerFile != VERSION) {
// Handle any breaking changes in future upgrades here
}
syncFile(FILENAME_VERSION, VERSION)
writeFile(FILENAME_VERSION, VERSION)
}
14 changes: 6 additions & 8 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"target": "es6",
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist"
},
"lib": ["es2015"]
"lib": ["ESNext"],
"module": "NodeNext",
"target": "esnext",
"types": ["bun-types"],
"moduleResolution": "NodeNext"
}
}
Loading

0 comments on commit bed387c

Please sign in to comment.