Skip to content

Commit 188569d

Browse files
committed
Tighten and standardize infrastructure documentation
1 parent 93a9672 commit 188569d

5 files changed

Lines changed: 109 additions & 120 deletions

File tree

.dockerignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Rust build artifacts — never send to Docker daemon
1+
# Rust build artifacts
22
target/
33
**/*.rs.bk
44

Dockerfile

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,29 @@
1-
# =============================================================================
2-
# minikv - Multi-Stage Dockerfile
1+
# minikv multi-stage Dockerfile
32
#
4-
# Stages:
5-
# 1. chef - installs cargo-chef for dependency caching
6-
# 2. planner - computes the dependency recipe
7-
# 3. builder - compiles dependencies (cached), then the binary
8-
# 4. runtime - minimal distroless image with only the binary
3+
# Build stages:
4+
# 1. chef - installs cargo-chef for dependency layer caching
5+
# 2. planner - computes the dependency recipe
6+
# 3. builder - compiles dependencies (cached) and the binary
7+
# 4. runtime - minimal distroless image containing only the binary
98
#
10-
# BLAKE3 hashing requires no external C libs - fully pure Rust.
11-
# rusty-leveldb is pure Rust - no libleveldb.so dependency.
12-
# Final image has zero shell, zero package manager, zero attack surface.
13-
# =============================================================================
9+
# BLAKE3 and rusty-leveldb are pure Rust implementations.
10+
# No external C libraries are required at runtime.
11+
# The final image contains no shell and no package manager.
1412

1513
# -----------------------------------------------------------------------------
1614
# Stage 1: chef
17-
# Installs cargo-chef for layer-cached dependency compilation.
15+
# Installs cargo-chef for reproducible dependency caching.
1816
# -----------------------------------------------------------------------------
1917
FROM rust:1.88-slim-bookworm AS chef
2018

21-
# Install cargo-chef for reproducible dependency caching
2219
RUN cargo install cargo-chef --locked
2320

2421
WORKDIR /build
2522

2623
# -----------------------------------------------------------------------------
2724
# Stage 2: planner
28-
# Computes the dependency recipe from Cargo.toml + Cargo.lock.
29-
# This layer only re-runs when dependencies change.
25+
# Generates the dependency recipe from Cargo manifests.
26+
# This layer changes only when dependency definitions change.
3027
# -----------------------------------------------------------------------------
3128
FROM chef AS planner
3229

@@ -38,68 +35,62 @@ RUN cargo chef prepare --recipe-path recipe.json
3835

3936
# -----------------------------------------------------------------------------
4037
# Stage 3: builder
41-
# Compiles dependencies first (cached layer), then the application.
38+
# Compiles dependencies first (cached), then the application.
4239
# -----------------------------------------------------------------------------
4340
FROM chef AS builder
4441

45-
# Build-time dependencies only - no runtime C libs needed.
46-
# rusty-leveldb and blake3 are both pure Rust.
42+
# Build-time dependencies only.
4743
RUN apt-get update && apt-get install -y --no-install-recommends \
4844
pkg-config \
4945
&& rm -rf /var/lib/apt/lists/*
5046

5147
COPY --from=planner /build/recipe.json recipe.json
5248

53-
# Compile dependencies - this layer is cached unless Cargo.toml/lock changes
5449
RUN cargo chef cook --release --recipe-path recipe.json
5550

56-
# Copy full source and compile the application binary
5751
COPY Cargo.toml Cargo.lock ./
5852
COPY minikv ./minikv
5953
COPY minikv-core ./minikv-core
6054
COPY config ./config
6155

62-
# Build release binary
63-
# RUSTFLAGS for correctness: deny unused, warn on unsafe
56+
# Enforce strict compilation rules.
6457
ENV RUSTFLAGS="-D warnings -D unsafe_code"
6558

59+
# Build release binary and strip symbols.
6660
RUN cargo build --release --locked \
6761
&& strip target/release/minikv
6862

6963
# -----------------------------------------------------------------------------
70-
# Stage 4: Distroless image runtime
64+
# Stage 4: runtime
65+
# Distroless base image containing only required runtime components.
7166
# -----------------------------------------------------------------------------
7267
FROM gcr.io/distroless/cc-debian12:nonroot AS runtime
7368

74-
# Metadata
7569
LABEL org.opencontainers.image.title="minikv"
76-
LABEL org.opencontainers.image.description="Tiny distributed key value store in pure Rust"
70+
LABEL org.opencontainers.image.description="Distributed key value store in Rust"
7771
LABEL org.opencontainers.image.source="https://github.com/ekkolon/minikv"
7872
LABEL org.opencontainers.image.licenses="MIT"
7973

80-
# Copy the stripped binary from builder
74+
# Copy compiled binary.
8175
COPY --from=builder /build/target/release/minikv /usr/local/bin/minikv
8276

83-
# Copy nginx config (used by operators, not the binary itself)
77+
# Copy nginx reference configuration (for operators).
8478
COPY --from=builder /build/config/nginx-volume.conf /etc/minikv/nginx-volume.conf
8579

86-
# Data directory for LevelDB - must be mounted as a volume in production
87-
# The nonroot user (uid=65532) must own this path
80+
# Working directory for the metadata database.
81+
# This path must be mounted as a volume in production.
8882
WORKDIR /data
8983

90-
# Expose the default server port
91-
# Override with: minikv server --port <port>
84+
# Default server port. Can be overridden via CLI flag.
9285
EXPOSE 3000
9386

94-
# Run as nonroot (distroless nonroot image sets this by default)
95-
# UID 65532 - no shell, no sudo, no privilege escalation possible
87+
# Run as non-root user (UID 65532).
9688
USER nonroot
9789

98-
# Default entrypoint - subcommand must be passed at runtime:
90+
# Entry point. Subcommand must be provided at runtime, for example:
9991
# docker run minikv server --port 3000 --db /data --volumes ...
10092
# docker run minikv rebuild ...
10193
# docker run minikv rebalance ...
10294
ENTRYPOINT ["/usr/local/bin/minikv"]
10395

104-
# No default CMD - operator must provide subcommand explicitly.
105-
# This prevents accidental runs with wrong configuration.
96+
# No default CMD. A subcommand must be specified explicitly.

config/nginx-frontend.conf

Lines changed: 44 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
# =============================================================================
21
# X-Accel-Redirect reverse proxy for minikv
32
#
4-
# DNS RESOLUTION NOTE:
5-
# nginx resolves upstream hostnames at *startup* by default. If the upstream
6-
# (coordinator, volume servers) is not yet in DNS, nginx refuses to start.
3+
# DNS resolution
74
#
8-
# To overcome this, we use `resolver` + a variable for every upstream.
9-
# When the upstream is stored in a variable, nginx defers DNS resolution
10-
# to *request time*, so startup succeeds even if backends aren't running yet.
5+
# By default, nginx resolves upstream hostnames at startup. If an upstream
6+
# service (coordinator or volume server) is not yet resolvable, nginx fails
7+
# to start.
118
#
12-
# Docker's internal DNS resolver is always at 127.0.0.11.
13-
# =============================================================================
9+
# To avoid this, upstreams are stored in variables and a `resolver` is
10+
# configured. When `proxy_pass` references a variable, DNS resolution
11+
# happens at request time instead of startup time.
12+
#
13+
# In Docker environments, the internal DNS resolver is available at
14+
# 127.0.0.11.
1415

1516
worker_processes auto;
1617
error_log /dev/stderr warn;
@@ -28,34 +29,30 @@ http {
2829
server_tokens off;
2930
default_type application/octet-stream;
3031

31-
# Docker's internal DNS — required for runtime upstream resolution.
32-
# `valid=5s` re-resolves every 5 seconds so container restarts are
33-
# picked up quickly without reloading nginx.
32+
# Docker internal DNS for runtime upstream resolution.
33+
# `valid=5s` forces periodic re-resolution so container restarts
34+
# are detected without reloading nginx.
3435
resolver 127.0.0.11 valid=5s ipv6=off;
3536

3637
server {
3738
listen 8080 default_server;
3839
server_name _;
3940

40-
# ------------------------------------------------------------------
41-
# Coordinator upstream as a variable — defers DNS to request time.
42-
# Service name matches docker-compose: "minikv"
43-
# ------------------------------------------------------------------
41+
# Coordinator upstream stored in a variable to defer DNS resolution
42+
# to request time. Service name matches docker-compose ("minikv").
4443
set $coordinator_upstream "minikv:3000";
4544

46-
# ------------------------------------------------------------------
47-
# Main proxy: all client requests go to the coordinator.
45+
# Main proxy. All client requests are forwarded to the coordinator.
4846
#
49-
# On GET/HEAD the coordinator returns:
50-
# X-Accel-Redirect: /accel/volume1:8080/sv09/a2/38/...
51-
# Content-Type: image/jpeg
52-
# Content-Blake3: <hash>
53-
# Key-Balance: balanced
47+
# For GET and HEAD, the coordinator responds with:
48+
# X-Accel-Redirect: /accel/<volume>/<object-path>
49+
# Content-Type
50+
# Content-Blake3
51+
# Key-Balance
5452
#
55-
# nginx intercepts X-Accel-Redirect and performs an internal
56-
# subrequest, streaming the object body to the client with the
57-
# coordinator's headers intact.
58-
# ------------------------------------------------------------------
53+
# nginx intercepts X-Accel-Redirect and performs an internal subrequest.
54+
# The object body is streamed from the volume server while preserving
55+
# coordinator-provided metadata headers.
5956
location / {
6057
proxy_pass http://$coordinator_upstream;
6158

@@ -64,10 +61,10 @@ http {
6461
proxy_set_header X-Real-IP $remote_addr;
6562
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
6663

67-
# Disable request buffering — required for streaming PUT uploads.
64+
# Disable request buffering to allow streaming PUT uploads.
6865
proxy_request_buffering off;
6966

70-
# Disable response buffering stream GET bodies directly.
67+
# Disable response buffering to stream GET responses directly.
7168
proxy_buffering off;
7269

7370
# Pass all coordinator metadata headers through to client.
@@ -77,23 +74,21 @@ http {
7774
proxy_pass_header Key-Volumes;
7875
}
7976

80-
# ------------------------------------------------------------------
8177
# Internal X-Accel-Redirect handler.
8278
#
8379
# URI format: /accel/<volume-host:port>/<object-path>
84-
# Example: /accel/volume1:8080/sv09/a2/38/bXlib...
80+
# Example: /accel/volume1:8080/sv09/a2/38/...
8581
#
86-
# `internal` makes this location unreachable by direct client
87-
# requests — only X-Accel-Redirect from the coordinator can
88-
# trigger it. Direct requests return 404.
82+
# The `internal` directive prevents direct client access. Only
83+
# X-Accel-Redirect responses from the coordinator can trigger this
84+
# location. Direct requests return 404.
8985
#
90-
# The upstream is captured into a variable ($vol_upstream) so
91-
# DNS resolution is deferred to request time (same pattern as above).
92-
# ------------------------------------------------------------------
86+
# The captured upstream is stored in a variable to defer DNS
87+
# resolution to request time.
9388
location ~ ^/accel/([^/]+)/(.*)$ {
9489
internal;
9590

96-
# Capture volume host:port and path into variables for runtime DNS.
91+
# Capture volume host:port and object path into variables.
9792
set $vol_upstream $1;
9893
set $vol_path $2;
9994

@@ -102,26 +97,22 @@ http {
10297
# Do not forward client request headers to volume servers.
10398
proxy_pass_request_headers off;
10499

105-
# ---------------------------------------------------------------
106-
# Content-Type injection via variable persistence.
100+
# Content-Type handling.
107101
#
108-
# The coordinator sets X-Content-Type on its response.
109-
# nginx stores this as $upstream_http_x_content_type — a variable
110-
# that persists across the X-Accel-Redirect internal redirect
111-
# (same ngx_http_request_t context).
102+
# The coordinator provides X-Content-Type in its response. nginx
103+
# exposes this as $upstream_http_x_content_type. This variable
104+
# persists across the internal X-Accel-Redirect.
112105
#
113-
# If the coordinator has no stored Content-Type for this object
114-
# (object was PUT without a Content-Type header, or rebuilt from
115-
# volume data), $upstream_http_x_content_type will be empty.
116-
# In that case we fall back to application/octet-stream rather
117-
# than emitting an empty Content-Type header.
106+
# If no Content-Type metadata exists (for example, the object was
107+
# uploaded without one or reconstructed from volume data), the
108+
# variable is empty. In that case, application/octet-stream is used.
118109
#
119-
# Objects can be re-PUT with Content-Type to populate the field.
120-
# ---------------------------------------------------------------
110+
# Objects may be re-uploaded with a Content-Type header to set
111+
# the stored metadata.
121112
proxy_hide_header Content-Type;
122113

123-
# Resolve effective Content-Type: coordinator metadata wins,
124-
# fall back to octet-stream when metadata is absent.
114+
# Coordinator metadata takes precedence. Fall back to
115+
# application/octet-stream when absent.
125116
set $effective_ct $upstream_http_x_content_type;
126117
if ($effective_ct = "") {
127118
set $effective_ct "application/octet-stream";

config/nginx-volume.conf

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
# Volume server configuration for minikv
22
#
3-
# Requires: nginx-mod-http-dav-ext (installed via apk in Dockerfile.volume)
4-
# Module path on Alpine 3.19: /usr/lib/nginx/modules/ngx_http_dav_ext_module.so
3+
# Requires the nginx DAV extension module:
4+
# nginx-mod-http-dav-ext
55
#
6-
# All volume containers listen on 8080 internally.
7-
# docker-compose maps volume1 => 8001, volume2 => 8002, volume3 => 8003 on the host.
6+
# Alpine 3.19 module path:
7+
# /usr/lib/nginx/modules/ngx_http_dav_ext_module.so
88
#
9-
# daemon off is passed via CMD in Dockerfile.volume, not here, to avoid
10-
# the duplicate-directive fatal error from some nginx base images.
9+
# Each volume container listens on port 8080 internally.
10+
# docker-compose maps:
11+
# volume1 -> 8001
12+
# volume2 -> 8002
13+
# volume3 -> 8003
14+
#
15+
# `daemon off` is set via CMD in Dockerfile.volume to avoid duplicate
16+
# directive errors in certain nginx base images.
1117

1218
load_module /usr/lib/nginx/modules/ngx_http_dav_ext_module.so;
1319

@@ -43,13 +49,14 @@ http {
4349
location / {
4450
disable_symlinks off;
4551

52+
# Enable object writes and deletions via WebDAV.
4653
dav_methods PUT DELETE;
4754
dav_access group:rw all:r;
4855

49-
# Auto-creates parent shard directories on first PUT.
56+
# Automatically create shard directory hierarchy on write.
5057
create_full_put_path on;
5158

52-
# JSON directory listing — required by the rebuild subcommand.
59+
# Expose JSON directory listings for rebuild operations.
5360
autoindex on;
5461
autoindex_format json;
5562
}

0 commit comments

Comments
 (0)