Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Publish docker #166

Merged
merged 20 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2edcf3c
chore: Beef up our EditorConfig
AverageHelper Aug 24, 2024
019aeaa
feat: Deploy a Docker image to both GitHub and Codeberg
AverageHelper Aug 24, 2024
ed07eaa
feat: Add an image tag for semver major
AverageHelper Aug 24, 2024
8d21d04
chore!: Remove `/update`
AverageHelper Aug 30, 2024
94127ab
Merge branch 'main' into avg/publish-docker
AverageHelper Sep 6, 2024
216c3bc
fix(doc): Remember to specify the env file
AverageHelper Sep 6, 2024
3c7f1ed
chore: Separate Dockerfiles for dev and prod
AverageHelper Sep 6, 2024
e806321
fix: Don't try to open nonexistent env file in Docker
AverageHelper Sep 6, 2024
bf3509a
fix: Don't init db during build, and remember to copy resource files
AverageHelper Sep 6, 2024
1585137
chore: Don't migrate twice
AverageHelper Sep 6, 2024
c67592c
chore: Note about Docker in changelog
AverageHelper Sep 6, 2024
d496b32
chore: I forgot Changelog has a Removed section!
AverageHelper Sep 6, 2024
cc3a17a
chore: Consistency
AverageHelper Sep 6, 2024
1c9e088
fix: Use `node:20-slim` in Dockerfile
AverageHelper Oct 3, 2024
917b2fe
fix: Run migrations on launch, not on build
AverageHelper Oct 3, 2024
e53f63b
fix: Install `openssl` on slim runner
AverageHelper Oct 3, 2024
8f3000b
chore: Reverse `if` condition in launch script, and enable errors
AverageHelper Oct 3, 2024
cfac559
Merge branch 'main' into avg/publish-docker
AverageHelper Oct 3, 2024
40ae93b
doc: Note about automatic db migrations in Docker
AverageHelper Oct 3, 2024
3a617f1
chore: Update changelog
AverageHelper Oct 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# TODO: extend prod#builder

FROM node:20-slim
RUN apt update
RUN apt upgrade --yes

# Necessary to install devDependencies
ENV NODE_ENV=development

WORKDIR /cs-bot
ENTRYPOINT [ "bash" ]
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Sets the run context to one level up instead of the .devcontainer folder.
"context": "..",
// Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
"dockerfile": "../Dockerfile"
"dockerfile": "./Dockerfile"
}

// Features to add to the dev container. More info: https://containers.dev/features.
Expand Down
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
# https://EditorConfig.org

# top-most EditorConfig file
root = true

# Unix-style newlines and file endings, with tab indentation for accessibility (no size specified)
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = tab

# YAML doesn't support tab indentation
[*.{yml,yaml}]
indent_style = space
58 changes: 58 additions & 0 deletions .github/workflows/deploy-docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Builds the Docker image and publishes to the GitHub container registry

name: Publish Docker Image

on:
push:
branches: ["main"]
# Publish semver tags as releases.
tags: ["v*.*.*"]

env:
# TODO: Also publish to Codeberg
REGISTRY: ghcr.io
# github.repository as <account>/<repo>
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push-image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Log in to container registry
# docker/[email protected]
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567
AverageHelper marked this conversation as resolved.
Show resolved Hide resolved
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract Docker metadata
id: meta
# docker/[email protected]
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81
with:
# e.g. 'ghcr.io/byu-cs-discord/csbot'
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}

- name: Build and push Docker image
# docker/[email protected]
uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85
with:
context: .
file: ./Dockerfile
AverageHelper marked this conversation as resolved.
Show resolved Hide resolved
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Node built-in `.env` file support
- Automatic updates for dependencies with Dependabot
- A read-only code mirror on [Codeberg](https://codeberg.org/BYU-CS-Discord/CSBot/)
- Docker support in production!

### Changed

- BREAKING: Node version to 20 LTS
- BREAKING: Use SQLite instead of PostgreSQL for simplicity and ease of transferring data between hosts.
- BREAKING: All previous automatic database migrations were removed, because Prisma cannot automatically migrate between database providers. Be sure to upgrade to v0.12.1 before using this version, as any data you might have had won't be migrated for you. See [this migration guide](https://web.archive.org/web/20231216021706/https://serverfault.com/questions/274355/how-to-convert-a-postgres-database-to-sqlite/276213#276213) for help migrating your existing database.
- Tests to use `vitest` instead of `jest`
- TypeScript build settings to be simplified and and follow `typescript-eslint` standards
- ESLint config to use new flat configuration
Expand All @@ -31,6 +31,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Release script to use `tsx` instead of `ts-node` to resolve ESM problems
- `/talk` to use `dectalk-tts` package instead of `dectalk`

### Removed

- BREAKING: All previous automatic database migrations were removed, because Prisma cannot automatically migrate between database providers. Be sure to upgrade to v0.12.1 before using this version, as any data you might have had won't be migrated for you. See [this migration guide](https://web.archive.org/web/20231216021706/https://serverfault.com/questions/274355/how-to-convert-a-postgres-database-to-sqlite/276213#276213) for help migrating your existing database. Future migrations in SQLite will happen on startup.
- BREAKING: Removed `/update`. Use Docker instead for easy upgrades.

### Fixed

- All package vulnerabilities
Expand Down
39 changes: 30 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
FROM node:20-slim
RUN apt update
RUN apt upgrade --yes
FROM node:20-slim as builder

# Necessary for /update
RUN apt install git --yes
RUN apt-get update -y
RUN apt-get install -y openssl

# Necessary to install devDependencies
ENV NODE_ENV=development
WORKDIR /app

WORKDIR /cs-bot
ENTRYPOINT [ "bash" ]
COPY . .

RUN npm ci
RUN npm run export-version
RUN npm run build --omit=dev

FROM node:20-slim as runner

RUN apt-get update -y
RUN apt-get install -y openssl

WORKDIR /app

COPY --from=builder /app/dist/ ./dist/
COPY --from=builder /app/res/ ./res/
COPY package*.json ./
COPY prisma prisma/
COPY scripts/launch_in_docker.sh .

RUN npm ci --omit=dev

# Path internal to container; use `volumes` config to specify real system path of `/db/`
ENV DATABASE_URL="file:/db/db.sqlite"

# Using bash here to get consistent behavior and configurations
CMD ["bash", "/app/launch_in_docker.sh"]
31 changes: 19 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,6 @@ By using this command, you are acknowleding that your input will be sent to a th

Begins a new game of Evil Hangman.

### /update

Pulls the latest changes from the repository and restarts the bot.

### /xkcd

Retrieves the most recent [xkcd](https://xkcd.com/) comic, or the given one.
Expand Down Expand Up @@ -165,6 +161,8 @@ Note that, by running this bot, you agree to be bound by the Discord's [Develope

### Configure the bot

This section only applies if running directly from source. See [Run the bot](#run-the-bot) for how to configure for running in [Podman](https://podman.io/) or [Docker](https://www.docker.com/).

Create a file called `.env` in the root of this project folder. Paste your token into that file, and fill in other config items as desired:

```sh
Expand All @@ -175,9 +173,6 @@ DISCORD_TOKEN=YOUR_TOKEN_GOES_HERE

DATABASE_URL=YOUR_DATABASE_URL_GOES_HERE
# Required for any DB functionality, we will get this URL in a later section

ADMINISTRATORS=COMMA,SEPARATED,ID,LIST
# Required for the update command. WARNING: The users whose ids are listed here will be able to pull, build, and run code from this repository on the machine the bot is running on. Do not include any users you do not trust.
```

**Do not commit this file to git** or your bot _will_ get "hacked".
Expand Down Expand Up @@ -218,9 +213,9 @@ $ npm run setup

### Build the bot database

_As we use Prisma for managing our database, it is up to you what relational database framework to use._
CSBot uses SQLite. All persistent data is stored in a single file.

By default, CSBot uses SQLite. All persistent data is stored in a single file.
If you're running in Docker, the database file will be created for you, at the path specified in your volume config. If the database is found, any pending database migrations will be run on startup. (See [docker-compose.yml](docker-compose.yml).) Otherwise, you'll need to configure the database URL and initialize it yourself, as described below.

First decide where you want your database file to go, then edit this line in your `.env` file:

Expand Down Expand Up @@ -262,18 +257,30 @@ If you have added new code, you should write new unit tests to cover all the cod

### Run the bot

For development purposes (the update command will not work properly, but logs are outputed to the console):
For development purposes:

```sh
$ node .
$ node --env-file=.env .
# or
$ npm run dev
```

For production purposes (this will spawn a separate thread using [PM2](https://pm2.io/) that will run in the background):
For production purposes, consider using [Podman](https://podman.io/) or [Docker](https://www.docker.com/) Compose. Copy the example [docker-compose.yml](docker-compose.yml) file to your system, and configure it accoring to your setup. Pay special attention to:

- Use the `build` field if you've cloned this repo directly to build the image from source. Use the `image` field instead if you wish to use our published image.
- Configure the `volumes` secion appropriately. By default, the SQLite database will go in an adjacent directory to your compose file. If you want the data to live somewhere else on your system, change the configuration accordingly.
- Create a `.env` file adjacent to your compose file and populate it with your Discord bot token, like so:

```sh
DISCORD_TOKEN=YOUR_TOKEN_HERE
```

Alternatively, you can run directly like so:

```sh
$ npm start
$ npm run stop
$ npm run restart
```

This will spawn a separate thread using [PM2](https://pm2.io/) that will run in the background.
25 changes: 25 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Docker compose reference guide at
# https://docs.docker.com/compose/compose-file/

# Here the instructions define your application as a service called
# "csbot". This service is built from the Dockerfile in
# the current directory.
services:
csbot:
build:
context: .
# Comment out the "build" section above and uncomment "image" below
# to pull from the published container repository instead of building
# from the local Dockerfile:
# image: ghcr.io/byu-cs-discord/csbot:latest
container_name: csbot
restart: unless-stopped
environment:
# Create a .env file and set DISCORD_TOKEN there:
DISCORD_TOKEN: ${DISCORD_TOKEN}
env_file:
- .env
volumes:
# Stores DB at ./db/db.sqlite, by default. Be sure to point the volume instead where your data should go:
- './db/:/db/'
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"main": "./dist/main.js",
AverageHelper marked this conversation as resolved.
Show resolved Hide resolved
"scripts": {
"build": "rm -rf dist && ./node_modules/.bin/tsc && npm run db:generate",
"commands:deploy": "node --env-file=.env . --deploy",
"commands:deploy": "node --env-file=.env . --deploy # TODO: Replace these with automatic command deployment",
"commands:revoke": "node --env-file=.env . --revoke",
"db:generate": "./node_modules/.bin/prisma generate --no-hints --schema ./prisma/schema.prisma",
"db:init": "npm run db:migrate:initial || ./node_modules/.bin/prisma db push && npm run db:migrate:initial",
Expand All @@ -43,8 +43,7 @@
"setup": "npm ci && npm run export-version && npm run build --production && npm run commands:deploy",
"start": "./node_modules/.bin/pm2 start ./dist/main.js --name cs-bot --node-args=\"--env-file=.env\"",
"stop": "./node_modules/.bin/pm2 delete cs-bot",
"test": "./node_modules/.bin/vitest",
"update": "git pull && npm run setup"
"test": "./node_modules/.bin/vitest"
},
"dependencies": {
"@discordjs/voice": "0.17.0",
Expand Down
20 changes: 20 additions & 0 deletions scripts/launch_in_docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash

# Fail early on nonzero exit
set -euo pipefail

# Prepare database
DATABASE_FILENAME="$(echo $DATABASE_URL | sed "s/file://g")"
if [[ -f "$DATABASE_FILENAME" ]] ; then
echo "Database found! Running migrations..."
npm run db:migrate
else
echo "No database detected, initializing..."
npm run db:init
fi

# Deploy commands
node . --deploy

# Launch
node .
2 changes: 0 additions & 2 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import { sendtag } from './sendtag.js';
import { stats } from './stats.js';
import { talk } from './talk.js';
import { toTheGallows } from './toTheGallows.js';
import { update } from './update.js';
import { xkcd } from './xkcd.js';

import { altText } from './contextMenu/altText.js';
Expand All @@ -54,7 +53,6 @@ _add(sendtag);
_add(stats);
_add(talk);
_add(toTheGallows);
_add(update);
_add(xkcd);

_add(altText);
Expand Down
Loading