feat: implement automated Docker deployment and update README
- Replaced manual rsync/npm_deploy workflow with multi-stage Docker builds. - Added Dockerfile and .dockerignore for staging and production environments. - Added 'deploy:staging' and 'deploy:prod' scripts to package.json. - Updated README.md with new deployment instructions.
This commit is contained in:
12
.dockerignore
Normal file
12
.dockerignore
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
node_modules
|
||||||
|
build
|
||||||
|
.svelte-kit
|
||||||
|
.git
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.staging
|
||||||
|
!.env.prod
|
||||||
|
npm_deploy
|
||||||
|
test-results
|
||||||
|
test_results
|
||||||
|
documentation
|
||||||
46
Dockerfile
Normal file
46
Dockerfile
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Stage 1: Build the application
|
||||||
|
# Using node:21-alpine for a lightweight, secure build environment.
|
||||||
|
FROM node:21-alpine AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install dependencies first for better Docker layer caching.
|
||||||
|
# This step only reruns if package.json or package-lock.json changes.
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# Copy the rest of the source code.
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build Argument to determine build environment (staging, prod, or production).
|
||||||
|
# Defaults to "staging".
|
||||||
|
ARG BUILD_MODE=staging
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
|
# Perform the build based on the BUILD_MODE argument.
|
||||||
|
# This runs the existing scripts in package.json, which already
|
||||||
|
# handle copying the correct .env file to .env.production for Vite.
|
||||||
|
RUN if [ "$BUILD_MODE" = "prod" ] || [ "$BUILD_MODE" = "production" ]; then \
|
||||||
|
npm run build:prod; \
|
||||||
|
else \
|
||||||
|
npm run build:staging; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Stage 2: Final runtime image
|
||||||
|
FROM node:21-alpine AS deploy-node
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy only the built files and necessary scripts from the builder stage.
|
||||||
|
COPY --from=builder /app/build .
|
||||||
|
COPY --from=builder /app/package.json .
|
||||||
|
|
||||||
|
# Install only production dependencies for a smaller, cleaner image.
|
||||||
|
RUN npm install --omit=dev
|
||||||
|
|
||||||
|
# Copy the resulting .env.production file to .env.
|
||||||
|
# adapter-node reads from .env at runtime for non-PUBLIC_ variables.
|
||||||
|
COPY --from=builder /app/.env.production .env
|
||||||
|
|
||||||
|
# SvelteKit (via adapter-node) defaults to port 3000.
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["node", "index.js"]
|
||||||
40
README.md
40
README.md
@@ -123,36 +123,34 @@ Developer sandbox pages — not for production use.
|
|||||||
|
|
||||||
# How to build and deploy SvelteKit:
|
# How to build and deploy SvelteKit:
|
||||||
|
|
||||||
Copy the contents of the "build" directory to ./npm_deploy/build/
|
The deployment is now fully automated using Docker Compose. The application is built directly from source inside a clean Docker environment, eliminating the need for manual `rsync` or `npm_deploy` management.
|
||||||
|
|
||||||
|
### Commands
|
||||||
|
|
||||||
|
Run these commands from the root of the `aether_app_sveltekit` project:
|
||||||
|
|
||||||
|
#### 1. Deploy to Staging (Dev)
|
||||||
|
This builds and restarts the staging containers (`ae_app_node_dev`, etc.) on your local workstation.
|
||||||
```bash
|
```bash
|
||||||
npm run build
|
npm run deploy:staging
|
||||||
```
|
```
|
||||||
|
|
||||||
If this is just a quick build update then only the build directory needs to be copied (rsync).
|
#### 2. Deploy to Production
|
||||||
|
This builds the image using production flags and restarts the production containers.
|
||||||
```bash
|
```bash
|
||||||
rsync -vhrz --exclude 'node_modules' ~/OSIT_dev/aether_app_sveltekit/build/ ~/OSIT_dev/ae_env_node_app/npm_deploy/build/ --delete
|
npm run deploy:prod
|
||||||
|
|
||||||
rsync -vhrz ~/OSIT_dev/ae_env_node_app/npm_deploy/build/ scott@linode.oneskyit.com:/srv/env/prod_aether_sveltekit/npm_deploy/build/ --delete
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If this includes package updates (not development) we need to copy the new package.json. Manually copy the new package.json file to ./npm_deploy/. This also needs to be copied to the server. Copy the package.json even though not really used.
|
### Technical Details
|
||||||
|
|
||||||
Run the --omit dev to clear out the node_modules directory. Copy the root node_modules directory to ./npm_deploy/build/node_modules/ after running te omit dev command.
|
- **Dockerfile**: Uses a multi-stage build. Stage 1 (builder) installs dependencies and builds the app using the `BUILD_MODE` argument. Stage 2 (runtime) creates the final lightweight image.
|
||||||
|
- **Environment Handling**:
|
||||||
|
- `PUBLIC_` variables are baked into the image during the build step based on `.env.staging` or `.env.prod`.
|
||||||
|
- Private runtime variables are passed via the `env_file` in `docker-compose.yml`.
|
||||||
|
- **Networking**: Containers are automatically joined to the `ae_dev_net` network to allow local Nginx proxying.
|
||||||
|
- **Legacy Migration**: The `upstream` in the local Nginx configuration has been updated to point to these new SvelteKit containers on port 3000.
|
||||||
|
|
||||||
```bash
|
---
|
||||||
npm ci --omit dev
|
|
||||||
|
|
||||||
# copy/paste, rsync, or cp
|
|
||||||
rsync -vhrz ~/OSIT_dev/aether_app_sveltekit/node_modules ~/OSIT_dev/ae_env_node_app/npm_deploy/build/ --delete
|
|
||||||
|
|
||||||
# copy package.json as well
|
|
||||||
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
Everything should be ready to run on the development server and production server.
|
|
||||||
|
|
||||||
# Rebuild the node_modules directory and manually install extra Svelte packages
|
# Rebuild the node_modules directory and manually install extra Svelte packages
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,9 @@
|
|||||||
"lint": "prettier --check . && eslint .",
|
"lint": "prettier --check . && eslint .",
|
||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
"test:integration": "playwright test",
|
"test:integration": "playwright test",
|
||||||
"test:unit": "vitest"
|
"test:unit": "vitest",
|
||||||
|
"deploy:staging": "docker compose -f ../ae_env_node_app/docker-compose.yml up -d --build --remove-orphans",
|
||||||
|
"deploy:prod": "docker compose -f ../ae_env_node_app/docker-compose.yml build --build-arg BUILD_MODE=prod && docker compose -f ../ae_env_node_app/docker-compose.yml up -d --remove-orphans"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.39.1",
|
"@eslint/js": "^9.39.1",
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
// *** Libraries & Stores
|
// *** Libraries & Stores
|
||||||
import { liveQuery } from 'dexie';
|
import { liveQuery } from 'dexie';
|
||||||
import { Modal } from 'flowbite-svelte';
|
import { Modal } from 'flowbite-svelte';
|
||||||
|
import { db_core } from '$lib/ae_core/db_core';
|
||||||
import { db_journals } from '$lib/ae_journals/db_journals';
|
import { db_journals } from '$lib/ae_journals/db_journals';
|
||||||
import { journals_func } from '$lib/ae_journals/ae_journals_functions';
|
import { journals_func } from '$lib/ae_journals/ae_journals_functions';
|
||||||
import { ae_loc, ae_api, slct } from '$lib/stores/ae_stores';
|
import { ae_loc, ae_api, slct } from '$lib/stores/ae_stores';
|
||||||
@@ -47,6 +48,13 @@
|
|||||||
let log_lvl = 0;
|
let log_lvl = 0;
|
||||||
|
|
||||||
// *** LiveQueries
|
// *** LiveQueries
|
||||||
|
let lq__account = $derived(
|
||||||
|
liveQuery(async () => {
|
||||||
|
if (!$slct.account_id) return null;
|
||||||
|
return await db_core.account.get($slct.account_id);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
let lq__journal_obj_li = $derived(
|
let lq__journal_obj_li = $derived(
|
||||||
liveQuery(async () => {
|
liveQuery(async () => {
|
||||||
return await db_journals.journal
|
return await db_journals.journal
|
||||||
@@ -105,7 +113,7 @@
|
|||||||
</h1>
|
</h1>
|
||||||
<p class="text-surface-600 dark:text-surface-400 font-medium">
|
<p class="text-surface-600 dark:text-surface-400 font-medium">
|
||||||
Managed by <span class="text-primary-500"
|
Managed by <span class="text-primary-500"
|
||||||
>{$ae_loc.account_name ?? 'Æ loading...'}</span
|
>{$lq__account?.name ?? $ae_loc.account_name ?? 'Æ loading...'}</span
|
||||||
>
|
>
|
||||||
{#if $ae_loc.person.given_name}
|
{#if $ae_loc.person.given_name}
|
||||||
• <span class="opacity-75"
|
• <span class="opacity-75"
|
||||||
|
|||||||
Reference in New Issue
Block a user