build: dockerize app, migrate on boot
This commit is contained in:
7
.dockerignore
Normal file
7
.dockerignore
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
**/target
|
||||||
|
**/node_modules
|
||||||
|
**/.svelte-kit
|
||||||
|
frontend/build
|
||||||
|
.git
|
||||||
|
**/.env
|
||||||
|
**/.env.*
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -18,5 +18,8 @@ node_modules/
|
|||||||
|
|
||||||
# ─── env / secrets ─── #
|
# ─── env / secrets ─── #
|
||||||
.env
|
.env
|
||||||
|
.env.test
|
||||||
.env.local
|
.env.local
|
||||||
.env.*.local
|
.env.*.local
|
||||||
|
|
||||||
|
docs/
|
||||||
|
|||||||
27
Dockerfile
Normal file
27
Dockerfile
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
FROM node:22-alpine AS frontend-builder
|
||||||
|
WORKDIR /frontend
|
||||||
|
RUN npm install -g pnpm@10
|
||||||
|
COPY frontend/package.json frontend/pnpm-lock.yaml ./
|
||||||
|
RUN pnpm install --frozen-lockfile
|
||||||
|
COPY frontend/ ./
|
||||||
|
RUN pnpm build
|
||||||
|
|
||||||
|
FROM rust:1-bookworm AS backend-builder
|
||||||
|
WORKDIR /backend
|
||||||
|
ENV SQLX_OFFLINE=true
|
||||||
|
COPY backend/ ./
|
||||||
|
RUN cargo build --release
|
||||||
|
|
||||||
|
FROM debian:12-slim AS runtime
|
||||||
|
WORKDIR /app
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends ca-certificates \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& mkdir -p /app/storage
|
||||||
|
COPY --from=backend-builder /backend/target/release/backend /app/backend
|
||||||
|
COPY --from=frontend-builder /frontend/build /app/static
|
||||||
|
ENV STORAGE_PATH=/app/storage
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["/app/backend"]
|
||||||
@@ -13,7 +13,11 @@ use axum::{
|
|||||||
};
|
};
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use tower_cookies::CookieManagerLayer;
|
use tower_cookies::CookieManagerLayer;
|
||||||
use tower_http::{cors::CorsLayer, services::ServeDir, trace::TraceLayer};
|
use tower_http::{
|
||||||
|
cors::CorsLayer,
|
||||||
|
services::{ServeDir, ServeFile},
|
||||||
|
trace::TraceLayer,
|
||||||
|
};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
|
|
||||||
@@ -39,8 +43,10 @@ async fn main() -> Result<()> {
|
|||||||
.init();
|
.init();
|
||||||
|
|
||||||
dotenvy::dotenv().ok();
|
dotenvy::dotenv().ok();
|
||||||
|
|
||||||
let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
||||||
let pool = PgPool::connect(&database_url).await.unwrap();
|
let pool = PgPool::connect(&database_url).await.unwrap();
|
||||||
|
sqlx::migrate!().run(&pool).await?;
|
||||||
let file_repository = FileRepository::new(pool.clone())?;
|
let file_repository = FileRepository::new(pool.clone())?;
|
||||||
let routes_file = routes_file(file_repository.clone())
|
let routes_file = routes_file(file_repository.clone())
|
||||||
.route_layer(middleware::from_fn(mw_require_auth))
|
.route_layer(middleware::from_fn(mw_require_auth))
|
||||||
@@ -67,7 +73,9 @@ async fn main() -> Result<()> {
|
|||||||
.allow_credentials(true)
|
.allow_credentials(true)
|
||||||
.allow_headers([header::CONTENT_TYPE]),
|
.allow_headers([header::CONTENT_TYPE]),
|
||||||
)
|
)
|
||||||
.fallback_service(ServeDir::new("./"));
|
.fallback_service(
|
||||||
|
ServeDir::new("/app/static").fallback(ServeFile::new("/app/static/index.html")),
|
||||||
|
);
|
||||||
|
|
||||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
|
||||||
info!("listening on {}", listener.local_addr().unwrap());
|
info!("listening on {}", listener.local_addr().unwrap());
|
||||||
|
|||||||
36
compose.yml
Normal file
36
compose.yml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: docker.io/library/postgres:16
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=postgres
|
||||||
|
- POSTGRES_PASSWORD=pass
|
||||||
|
- POSTGRES_DB=loft
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- loft_db_data:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U postgres -d loft"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
app:
|
||||||
|
image: loft
|
||||||
|
restart: unless-stopped
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=postgres://postgres:pass@db:5432/loft
|
||||||
|
- STORAGE_PATH=/app/storage
|
||||||
|
volumes:
|
||||||
|
- loft_storage:/app/storage
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
loft_db_data:
|
||||||
|
loft_storage:
|
||||||
Reference in New Issue
Block a user