feat: Add Dockerization support
This commit is contained in:
31
.dockerignore
Normal file
31
.dockerignore
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Rust
|
||||||
|
target/
|
||||||
|
**/*.rs.bk
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
Dockerfile
|
||||||
|
.dockerignore
|
||||||
|
|
||||||
|
# Config and local data
|
||||||
|
*.json
|
||||||
|
!config.json.example
|
||||||
|
!response.json.example
|
||||||
|
status.json
|
||||||
|
|
||||||
|
# IDEs and Editors
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# CI/CD
|
||||||
|
.gitea/
|
||||||
|
.github/
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
44
Dockerfile
Normal file
44
Dockerfile
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# Build stage
|
||||||
|
FROM rust:alpine AS builder
|
||||||
|
|
||||||
|
# Install build dependencies
|
||||||
|
RUN apk add --no-cache musl-dev
|
||||||
|
|
||||||
|
WORKDIR /usr/src/dhl
|
||||||
|
|
||||||
|
# 1. Copy only the dependency manifests
|
||||||
|
COPY Cargo.toml Cargo.lock ./
|
||||||
|
|
||||||
|
# 2. Create a dummy source file to build dependencies
|
||||||
|
RUN mkdir src && echo "fn main() {}" > src/main.rs && \
|
||||||
|
cargo build --release && \
|
||||||
|
rm -rf src
|
||||||
|
|
||||||
|
# 3. Now copy the real source code
|
||||||
|
COPY src ./src
|
||||||
|
|
||||||
|
# 4. Build the actual application
|
||||||
|
# We touch the main file to ensure cargo rebuilds it
|
||||||
|
RUN touch src/main.rs && cargo build --release
|
||||||
|
|
||||||
|
# Final stage
|
||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
# Set environment variable to signal the app it's running in Docker
|
||||||
|
ENV DOCKER_CONTAINER=true
|
||||||
|
|
||||||
|
# Install runtime dependencies
|
||||||
|
RUN apk add --no-cache ca-certificates
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy the binary from the builder stage
|
||||||
|
COPY --from=builder /usr/src/dhl/target/release/dhl /usr/local/bin/dhl
|
||||||
|
|
||||||
|
# Volume for configuration and response files
|
||||||
|
VOLUME ["/app"]
|
||||||
|
|
||||||
|
# Default port
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["dhl"]
|
||||||
46
README.md
46
README.md
@@ -99,6 +99,52 @@ cargo run
|
|||||||
cargo build --release
|
cargo build --release
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Using with Docker
|
||||||
|
|
||||||
|
You can run DHL as a Docker container. The application automatically generates a default `config.json` and `response.json` if they are missing in the work directory.
|
||||||
|
|
||||||
|
#### Build the Image
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t dhl .
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Run with Docker CLI
|
||||||
|
|
||||||
|
To persist your configuration and response files, mount a local directory to `/app` in the container. The application will create default files in that directory if it is empty.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create a folder for your mock data
|
||||||
|
mkdir mock-data
|
||||||
|
|
||||||
|
# Run the container and mount the folder
|
||||||
|
docker run -p 3000:3000 -v $(pwd)/mock-data:/app dhl
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Run with Docker Compose
|
||||||
|
|
||||||
|
An example `docker-compose.yml` is provided in the root directory:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
dhl:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
volumes:
|
||||||
|
- ./mock-data:/app
|
||||||
|
restart: unless-stopped
|
||||||
|
```
|
||||||
|
|
||||||
|
To start:
|
||||||
|
```bash
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** The default host is set to `0.0.0.0` for Docker compatibility. If you are using a custom `config.json`, ensure the `host` is set to `0.0.0.0`.
|
||||||
|
|
||||||
### Release Assets
|
### Release Assets
|
||||||
|
|
||||||
When downloading a release, you will find:
|
When downloading a release, you will find:
|
||||||
|
|||||||
11
docker-compose.yml
Normal file
11
docker-compose.yml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
services:
|
||||||
|
dhl:
|
||||||
|
build: .
|
||||||
|
image: dhl:latest
|
||||||
|
container_name: dhl
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
volumes:
|
||||||
|
# Mount a local folder to /app to manage config.json and response files
|
||||||
|
- ./mock-data:/app
|
||||||
|
restart: unless-stopped
|
||||||
@@ -1,28 +1,28 @@
|
|||||||
use serde::Deserialize;
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
pub struct TlsConfig {
|
pub struct TlsConfig {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub cert_path: PathBuf,
|
pub cert_path: PathBuf,
|
||||||
pub key_path: PathBuf,
|
pub key_path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
pub struct MaskingConfig {
|
pub struct MaskingConfig {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub headers: Vec<String>,
|
pub headers: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
pub struct RouteConfig {
|
pub struct RouteConfig {
|
||||||
pub path: String,
|
pub path: String,
|
||||||
pub response_file: PathBuf,
|
pub response_file: PathBuf,
|
||||||
pub status_code: u16,
|
pub status_code: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub host: String,
|
pub host: String,
|
||||||
pub port: u16,
|
pub port: u16,
|
||||||
@@ -41,7 +41,11 @@ impl Config {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
Self::default()
|
let default_config = Self::default();
|
||||||
|
if let Ok(json) = serde_json::to_string_pretty(&default_config) {
|
||||||
|
let _ = fs::write("config.json", json);
|
||||||
|
}
|
||||||
|
default_config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,7 +54,7 @@ impl Config {
|
|||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
host: "127.0.0.1".to_string(),
|
host: "0.0.0.0".to_string(),
|
||||||
port: 3000,
|
port: 3000,
|
||||||
routes: vec![RouteConfig {
|
routes: vec![RouteConfig {
|
||||||
path: "/".to_string(),
|
path: "/".to_string(),
|
||||||
|
|||||||
@@ -47,7 +47,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
.layer(axum_middleware::from_fn_with_state(state.clone(), logging_middleware))
|
.layer(axum_middleware::from_fn_with_state(state.clone(), logging_middleware))
|
||||||
.with_state(state);
|
.with_state(state);
|
||||||
|
|
||||||
let addr: SocketAddr = format!("{}:{}", config.host, config.port).parse()?;
|
let mut host = config.host.clone();
|
||||||
|
|
||||||
|
// In Docker, we usually want to bind to 0.0.0.0 to be accessible
|
||||||
|
if std::env::var("DOCKER_CONTAINER").is_ok() {
|
||||||
|
host = "0.0.0.0".to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
let addr: SocketAddr = format!("{}:{}", host, config.port).parse()?;
|
||||||
|
|
||||||
// 4. Start server
|
// 4. Start server
|
||||||
if config.tls.enabled {
|
if config.tls.enabled {
|
||||||
|
|||||||
Reference in New Issue
Block a user