snapshot of https://github.com/seaweedfs/seaweedfs.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
This commit is contained in:
44
docker/Dockerfile.e2e
Normal file
44
docker/Dockerfile.e2e
Normal file
@@ -0,0 +1,44 @@
|
||||
FROM ubuntu:22.04
|
||||
|
||||
LABEL author="Chris Lu"
|
||||
|
||||
# Note: This e2e test image intentionally runs as root for simplicity and compatibility.
|
||||
# Production images (Dockerfile.go_build) use proper user isolation with su-exec.
|
||||
# For testing purposes, running as root avoids permission complexities and dependency
|
||||
# on Alpine-specific tools like su-exec (not available in Ubuntu repos).
|
||||
|
||||
# apt-install prefers Azure's mirror, which archive.ubuntu.com is slow enough from
|
||||
# GitHub-hosted runners to justify, and falls through to archive.ubuntu.com when
|
||||
# Azure is unreachable - which it periodically is, and Acquire::Retries against a
|
||||
# single mirror just retries a dead host. Images built FROM this one install
|
||||
# through it for the same reason.
|
||||
COPY apt-install /usr/local/bin/apt-install
|
||||
RUN chmod +x /usr/local/bin/apt-install && \
|
||||
apt-install curl fio fuse ca-certificates && \
|
||||
rm -rf /tmp/* /var/tmp/*
|
||||
|
||||
RUN mkdir -p /etc/seaweedfs /data/filerldb2
|
||||
|
||||
COPY ./weed /usr/bin/
|
||||
COPY ./filer.toml /etc/seaweedfs/filer.toml
|
||||
COPY ./entrypoint_e2e.sh /entrypoint.sh
|
||||
|
||||
# volume server grpc port
|
||||
EXPOSE 18080
|
||||
# volume server http port
|
||||
EXPOSE 8080
|
||||
# filer server grpc port
|
||||
EXPOSE 18888
|
||||
# filer server http port
|
||||
EXPOSE 8888
|
||||
# master server shared grpc port
|
||||
EXPOSE 19333
|
||||
# master server shared http port
|
||||
EXPOSE 9333
|
||||
|
||||
VOLUME /data
|
||||
WORKDIR /data
|
||||
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
132
docker/Dockerfile.foundationdb_large
Normal file
132
docker/Dockerfile.foundationdb_large
Normal file
@@ -0,0 +1,132 @@
|
||||
FROM golang:1.26 AS builder
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y build-essential wget ca-certificates && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ARG FDB_VERSION=7.4.5
|
||||
ENV FDB_VERSION=${FDB_VERSION}
|
||||
ARG TARGETARCH
|
||||
|
||||
# Install FoundationDB client libraries with SHA256 checksum verification
|
||||
# Known SHA256 checksums for FoundationDB client packages (verified 2025-01-19)
|
||||
# To add checksums for new versions: run docker/get_fdb_checksum.sh <version> <arch>
|
||||
RUN cd /tmp && \
|
||||
case "${TARGETARCH}" in \
|
||||
"amd64") FDB_ARCH="amd64"; PACKAGE_ARCH="amd64" ;; \
|
||||
"arm64") FDB_ARCH="arm64"; PACKAGE_ARCH="aarch64" ;; \
|
||||
*) echo "Unsupported architecture: ${TARGETARCH}" >&2; exit 1 ;; \
|
||||
esac && \
|
||||
case "${FDB_VERSION}_${FDB_ARCH}" in \
|
||||
"7.4.5_amd64") \
|
||||
EXPECTED_SHA256="eea6b98cf386a0848655b2e196d18633662a7440a7ee061c10e32153c7e7e112" ;; \
|
||||
"7.4.5_arm64") \
|
||||
EXPECTED_SHA256="f2176b86b7e1b561c3632b4e6e7efb82e3b8f57c2ff0d0ac4671e742867508aa" ;; \
|
||||
"7.3.43_amd64") \
|
||||
EXPECTED_SHA256="c3fa0a59c7355b914a1455dac909238d5ea3b6c6bc7b530af8597e6487c1651a" ;; \
|
||||
"7.3.43_arm64") \
|
||||
echo "ERROR: FoundationDB ${FDB_VERSION} does not publish arm64 client packages." >&2; \
|
||||
echo "Please upgrade to 7.4.5+ when targeting arm64." >&2; \
|
||||
exit 1 ;; \
|
||||
*) \
|
||||
echo "ERROR: No checksum available for FDB version ${FDB_VERSION} on ${FDB_ARCH}" >&2; \
|
||||
echo "This is a security requirement. To add verification:" >&2; \
|
||||
echo " 1. Run: docker/get_fdb_checksum.sh ${FDB_VERSION} ${FDB_ARCH}" >&2; \
|
||||
echo " 2. Add the checksum to this Dockerfile" >&2; \
|
||||
echo "Refusing to proceed without checksum verification." >&2; \
|
||||
exit 1 ;; \
|
||||
esac && \
|
||||
PACKAGE="foundationdb-clients_${FDB_VERSION}-1_${PACKAGE_ARCH}.deb" && \
|
||||
wget --timeout=30 --tries=3 https://github.com/apple/foundationdb/releases/download/${FDB_VERSION}/${PACKAGE} && \
|
||||
echo "${EXPECTED_SHA256} ${PACKAGE}" | sha256sum -c - || \
|
||||
(echo "ERROR: Checksum verification failed for FoundationDB ${FDB_VERSION} (${FDB_ARCH})" >&2; \
|
||||
echo "Expected: ${EXPECTED_SHA256}" >&2; \
|
||||
echo "This indicates either a corrupted download or potential tampering." >&2; \
|
||||
exit 1) && \
|
||||
dpkg -i ${PACKAGE} && \
|
||||
rm ${PACKAGE}
|
||||
|
||||
# Set up FoundationDB environment variables for CGO
|
||||
ENV CGO_CFLAGS="-I/usr/include/foundationdb"
|
||||
ENV CGO_LDFLAGS="-lfdb_c"
|
||||
|
||||
# build SeaweedFS sources; prefer local context but fall back to git clone if context only has docker files
|
||||
ARG SOURCE_REF=master
|
||||
WORKDIR /go/src/github.com/seaweedfs/seaweedfs
|
||||
COPY . .
|
||||
RUN set -euo pipefail && \
|
||||
if [ ! -d weed ]; then \
|
||||
echo "Local build context does not include SeaweedFS sources; cloning ${SOURCE_REF}" >&2; \
|
||||
mkdir -p /tmp/local-context && cp -a /go/src/github.com/seaweedfs/seaweedfs/. /tmp/local-context && \
|
||||
cd / && rm -rf /go/src/github.com/seaweedfs/seaweedfs && \
|
||||
git clone --depth 1 --branch ${SOURCE_REF} https://github.com/seaweedfs/seaweedfs /go/src/github.com/seaweedfs/seaweedfs && \
|
||||
cp -a /tmp/local-context/. /go/src/github.com/seaweedfs/seaweedfs/docker/ && \
|
||||
rm -rf /tmp/local-context && \
|
||||
cd /go/src/github.com/seaweedfs/seaweedfs; \
|
||||
fi && \
|
||||
cd weed \
|
||||
&& COMMIT_SHA=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown") \
|
||||
&& export LDFLAGS="-X github.com/seaweedfs/seaweedfs/weed/util/version.COMMIT=${COMMIT_SHA}" \
|
||||
&& go install -tags "5BytesOffset foundationdb" -ldflags "${LDFLAGS}"
|
||||
|
||||
|
||||
FROM debian:bookworm-slim AS final
|
||||
LABEL author="Chris Lu"
|
||||
|
||||
# Install runtime dependencies first
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
curl \
|
||||
fuse \
|
||||
wget && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Reuse FoundationDB artifacts installed during the build stage
|
||||
COPY --from=builder /usr/lib/libfdb_c* /usr/lib/
|
||||
COPY --from=builder /usr/lib/foundationdb /usr/lib/foundationdb
|
||||
COPY --from=builder /usr/bin/fdb* /usr/bin/
|
||||
RUN ldconfig
|
||||
|
||||
# Copy SeaweedFS binary and configuration
|
||||
COPY --from=builder /go/bin/weed /usr/bin/
|
||||
RUN mkdir -p /etc/seaweedfs
|
||||
COPY --from=builder /go/src/github.com/seaweedfs/seaweedfs/docker/filer_foundationdb.toml /etc/seaweedfs/filer.toml
|
||||
COPY --from=builder /go/src/github.com/seaweedfs/seaweedfs/docker/entrypoint.sh /entrypoint.sh
|
||||
|
||||
# Create non-root user
|
||||
RUN groupadd -g 1000 seaweed && \
|
||||
useradd -u 1000 -g seaweed -s /bin/bash -m seaweed
|
||||
|
||||
# volume server gprc port
|
||||
EXPOSE 18080
|
||||
# volume server http port
|
||||
EXPOSE 8080
|
||||
# filer server gprc port
|
||||
EXPOSE 18888
|
||||
# filer server http port
|
||||
EXPOSE 8888
|
||||
# master server shared gprc port
|
||||
EXPOSE 19333
|
||||
# master server shared http port
|
||||
EXPOSE 9333
|
||||
# s3 server http port
|
||||
EXPOSE 8333
|
||||
# webdav server http port
|
||||
EXPOSE 7333
|
||||
|
||||
# Create data directory and set proper ownership for seaweed user
|
||||
RUN mkdir -p /data && \
|
||||
chown -R seaweed:seaweed /data && \
|
||||
chown -R seaweed:seaweed /etc/seaweedfs && \
|
||||
chmod 755 /entrypoint.sh
|
||||
|
||||
VOLUME /data
|
||||
|
||||
WORKDIR /data
|
||||
|
||||
# Switch to non-root user
|
||||
USER seaweed
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
||||
120
docker/Dockerfile.go_build
Normal file
120
docker/Dockerfile.go_build
Normal file
@@ -0,0 +1,120 @@
|
||||
# Pin the builder to the host arch and cross-compile the (CGO-free) Go binary,
|
||||
# so arm64/arm/386 targets skip QEMU emulation of the whole compile.
|
||||
FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS builder
|
||||
RUN apk add git g++ fuse
|
||||
RUN mkdir -p /go/src/github.com/seaweedfs/
|
||||
ARG BRANCH=${BRANCH:-master}
|
||||
# Clone with full history and all tags to ensure all commits are available
|
||||
RUN git clone --no-single-branch --tags https://github.com/seaweedfs/seaweedfs /go/src/github.com/seaweedfs/seaweedfs
|
||||
ARG TAGS
|
||||
RUN cd /go/src/github.com/seaweedfs/seaweedfs && \
|
||||
(git checkout $BRANCH || \
|
||||
(echo "Checkout failed, fetching all history..." && \
|
||||
git fetch --all --tags --prune && \
|
||||
git checkout $BRANCH) || \
|
||||
(echo "ERROR: Branch/commit $BRANCH not found in repository" && \
|
||||
echo "Available branches:" && git branch -a && exit 1))
|
||||
ARG TARGETOS TARGETARCH TARGETVARIANT
|
||||
RUN cd /go/src/github.com/seaweedfs/seaweedfs/weed \
|
||||
&& export LDFLAGS="-X github.com/seaweedfs/seaweedfs/weed/util/version.COMMIT=$(git rev-parse --short HEAD)" \
|
||||
&& export GOOS=$TARGETOS GOARCH=$TARGETARCH \
|
||||
&& case "$TARGETARCH" in arm) export GOARM="${TARGETVARIANT#v}";; esac \
|
||||
&& CGO_ENABLED=0 go build -tags "$TAGS" -ldflags "-extldflags -static ${LDFLAGS}" -o /go/bin/weed .
|
||||
|
||||
# Rust volume server: use pre-built binary from CI when available (placed in
|
||||
# weed-volume-prebuilt/ by the build-rust-binaries job), otherwise compile
|
||||
# from source. Pre-building avoids a multi-hour QEMU-emulated cargo build
|
||||
# for non-native architectures.
|
||||
FROM alpine:3.23 as rust_builder
|
||||
ARG TARGETARCH
|
||||
ARG TAGS
|
||||
COPY weed-volume-prebuilt/ /prebuilt/
|
||||
COPY weed-worker-prebuilt/ /prebuilt-worker/
|
||||
COPY --from=builder /go/src/github.com/seaweedfs/seaweedfs/seaweed-volume /build/seaweed-volume
|
||||
COPY --from=builder /go/src/github.com/seaweedfs/seaweedfs/weed /build/weed
|
||||
WORKDIR /build/seaweed-volume
|
||||
RUN if [ -f "/prebuilt/weed-volume-${TARGETARCH}" ]; then \
|
||||
echo "Using pre-built Rust binary for ${TARGETARCH}" && \
|
||||
cp "/prebuilt/weed-volume-${TARGETARCH}" /weed-volume; \
|
||||
elif [ "$TARGETARCH" = "amd64" ] || [ "$TARGETARCH" = "arm64" ]; then \
|
||||
apk add --no-cache musl-dev openssl-dev protobuf-dev git rust cargo; \
|
||||
if [ "$TAGS" = "5BytesOffset" ]; then \
|
||||
cargo build --release; \
|
||||
else \
|
||||
cargo build --release --no-default-features; \
|
||||
fi && \
|
||||
cp target/release/weed-volume /weed-volume; \
|
||||
else \
|
||||
echo "Skipping Rust build for $TARGETARCH (unsupported)" && \
|
||||
touch /weed-volume; \
|
||||
fi
|
||||
# The Rust maintenance worker is taken pre-built or not at all: the lance jobs
|
||||
# it carries pull in arrow and datafusion, a far larger dependency tree than
|
||||
# the image build can carry, so an architecture CI did not build for gets the
|
||||
# same empty placeholder the entrypoint refuses to exec.
|
||||
RUN if [ -f "/prebuilt-worker/weed-worker-${TARGETARCH}" ]; then \
|
||||
echo "Using pre-built Rust worker for ${TARGETARCH}" && \
|
||||
cp "/prebuilt-worker/weed-worker-${TARGETARCH}" /weed-worker; \
|
||||
else \
|
||||
echo "No pre-built Rust worker for ${TARGETARCH}" && \
|
||||
touch /weed-worker; \
|
||||
fi
|
||||
|
||||
# Pre-built binaries arrive via GitHub Actions artifacts, which drop the
|
||||
# executable bit, so the copied file is 0644 and exec fails with "Permission
|
||||
# denied". Restore it (no-op for the empty placeholders, which stay size 0).
|
||||
RUN chmod 0755 /weed-volume /weed-worker
|
||||
|
||||
FROM alpine AS final
|
||||
LABEL author="Chris Lu"
|
||||
COPY --from=builder /go/bin/weed /usr/bin/
|
||||
# Copy Rust volume server binary (real binary on amd64/arm64, empty placeholder on other platforms)
|
||||
COPY --from=rust_builder /weed-volume /usr/bin/weed-volume
|
||||
# Same for the Rust maintenance worker, which serves Lance table buckets
|
||||
COPY --from=rust_builder /weed-worker /usr/bin/weed-worker
|
||||
RUN mkdir -p /etc/seaweedfs
|
||||
COPY --from=builder /go/src/github.com/seaweedfs/seaweedfs/docker/filer.toml /etc/seaweedfs/filer.toml
|
||||
COPY --from=builder /go/src/github.com/seaweedfs/seaweedfs/docker/entrypoint.sh /entrypoint.sh
|
||||
|
||||
# FIPS 140-3 mode is ON by default (Go 1.24+)
|
||||
# To disable: docker run -e GODEBUG=fips140=off ...
|
||||
|
||||
# Install dependencies and create non-root user
|
||||
RUN apk upgrade --no-cache && \
|
||||
apk add --no-cache fuse curl su-exec libgcc libcrypto3 libssl3 && \
|
||||
addgroup -g 1000 seaweed && \
|
||||
adduser -D -u 1000 -G seaweed seaweed
|
||||
|
||||
# volume server gprc port
|
||||
EXPOSE 18080
|
||||
# volume server http port
|
||||
EXPOSE 8080
|
||||
# filer server gprc port
|
||||
EXPOSE 18888
|
||||
# filer server http port
|
||||
EXPOSE 8888
|
||||
# master server shared gprc port
|
||||
EXPOSE 19333
|
||||
# master server shared http port
|
||||
EXPOSE 9333
|
||||
# s3 server http port
|
||||
EXPOSE 8333
|
||||
# webdav server http port
|
||||
EXPOSE 7333
|
||||
|
||||
# Create data directory and set proper ownership for seaweed user
|
||||
RUN mkdir -p /data/filerldb2 && \
|
||||
chown -R seaweed:seaweed /data && \
|
||||
chown -R seaweed:seaweed /etc/seaweedfs && \
|
||||
chmod 755 /entrypoint.sh
|
||||
|
||||
VOLUME /data
|
||||
WORKDIR /data
|
||||
|
||||
# Entrypoint will handle permission fixes and user switching
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
# Default to a complete single-process cluster (master+volume+filer+S3+admin)
|
||||
# so the image is usable out of the box — including in environments like
|
||||
# GitHub Actions service containers that cannot pass arguments to the entrypoint.
|
||||
# Override with any other subcommand at `docker run` / compose time.
|
||||
CMD ["mini", "-dir=/data"]
|
||||
47
docker/Dockerfile.local
Normal file
47
docker/Dockerfile.local
Normal file
@@ -0,0 +1,47 @@
|
||||
FROM alpine AS final
|
||||
LABEL author="Chris Lu"
|
||||
COPY ./weed /usr/bin/weed
|
||||
RUN chmod +x /usr/bin/weed && ls -la /usr/bin/weed
|
||||
RUN mkdir -p /etc/seaweedfs
|
||||
COPY ./filer.toml /etc/seaweedfs/filer.toml
|
||||
COPY ./entrypoint.sh /entrypoint.sh
|
||||
|
||||
# Install dependencies and create non-root user
|
||||
RUN apk upgrade --no-cache && \
|
||||
apk add --no-cache fuse curl su-exec && \
|
||||
addgroup -g 1000 seaweed && \
|
||||
adduser -D -u 1000 -G seaweed seaweed
|
||||
|
||||
# volume server grpc port
|
||||
EXPOSE 18080
|
||||
# volume server http port
|
||||
EXPOSE 8080
|
||||
# filer server grpc port
|
||||
EXPOSE 18888
|
||||
# filer server http port
|
||||
EXPOSE 8888
|
||||
# master server shared grpc port
|
||||
EXPOSE 19333
|
||||
# master server shared http port
|
||||
EXPOSE 9333
|
||||
# s3 server http port
|
||||
EXPOSE 8333
|
||||
# webdav server http port
|
||||
EXPOSE 7333
|
||||
|
||||
# Create data directory and set proper ownership for seaweed user
|
||||
RUN mkdir -p /data/filerldb2 && \
|
||||
chown -R seaweed:seaweed /data && \
|
||||
chown -R seaweed:seaweed /etc/seaweedfs && \
|
||||
chmod 755 /entrypoint.sh
|
||||
|
||||
VOLUME /data
|
||||
WORKDIR /data
|
||||
|
||||
# Entrypoint will handle permission fixes and user switching
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
# Default to a complete single-process cluster (master+volume+filer+S3+admin)
|
||||
# so the image is usable out of the box — including in environments like
|
||||
# GitHub Actions service containers that cannot pass arguments to the entrypoint.
|
||||
# Override with any other subcommand at `docker run` / compose time.
|
||||
CMD ["mini", "-dir=/data"]
|
||||
17
docker/Dockerfile.rocksdb_dev_env
Normal file
17
docker/Dockerfile.rocksdb_dev_env
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM golang:1.26 AS builder
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential libsnappy-dev zlib1g-dev libbz2-dev libgflags-dev liblz4-dev libzstd-dev
|
||||
|
||||
ARG ROCKSDB_VERSION=v10.10.1
|
||||
ENV ROCKSDB_VERSION=${ROCKSDB_VERSION}
|
||||
|
||||
# build RocksDB
|
||||
RUN cd /tmp && \
|
||||
git clone https://github.com/facebook/rocksdb.git /tmp/rocksdb --depth 1 --single-branch --branch $ROCKSDB_VERSION && \
|
||||
cd rocksdb && \
|
||||
PORTABLE=1 make -j"$(nproc)" static_lib && \
|
||||
make install-static
|
||||
|
||||
ENV CGO_CFLAGS="-I/tmp/rocksdb/include"
|
||||
ENV CGO_LDFLAGS="-L/tmp/rocksdb -lrocksdb -lstdc++ -lm -lz -lbz2 -lsnappy -llz4 -lzstd"
|
||||
75
docker/Dockerfile.rocksdb_large
Normal file
75
docker/Dockerfile.rocksdb_large
Normal file
@@ -0,0 +1,75 @@
|
||||
FROM golang:1.26 AS builder
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential libsnappy-dev zlib1g-dev libbz2-dev libgflags-dev liblz4-dev libzstd-dev
|
||||
|
||||
ARG ROCKSDB_VERSION=v10.10.1
|
||||
ENV ROCKSDB_VERSION=${ROCKSDB_VERSION}
|
||||
|
||||
# build RocksDB
|
||||
RUN cd /tmp && \
|
||||
git clone https://github.com/facebook/rocksdb.git /tmp/rocksdb --depth 1 --single-branch --branch $ROCKSDB_VERSION && \
|
||||
cd rocksdb && \
|
||||
PORTABLE=1 make -j"$(nproc)" static_lib && \
|
||||
make install-static
|
||||
|
||||
ENV CGO_CFLAGS="-I/tmp/rocksdb/include"
|
||||
ENV CGO_LDFLAGS="-L/tmp/rocksdb -lrocksdb -lstdc++ -lm -lz -lbz2 -lsnappy -llz4 -lzstd"
|
||||
|
||||
# build SeaweedFS
|
||||
RUN mkdir -p /go/src/github.com/seaweedfs/
|
||||
RUN git clone https://github.com/seaweedfs/seaweedfs /go/src/github.com/seaweedfs/seaweedfs
|
||||
ARG BRANCH=master
|
||||
RUN cd /go/src/github.com/seaweedfs/seaweedfs && git checkout $BRANCH
|
||||
RUN cd /go/src/github.com/seaweedfs/seaweedfs/weed \
|
||||
&& export LDFLAGS="-X github.com/seaweedfs/seaweedfs/weed/util/version.COMMIT=$(git rev-parse --short HEAD)" \
|
||||
&& go install -tags "5BytesOffset rocksdb" -ldflags "-extldflags -static ${LDFLAGS}"
|
||||
|
||||
|
||||
FROM alpine AS final
|
||||
LABEL author="Chris Lu"
|
||||
COPY --from=builder /go/bin/weed /usr/bin/
|
||||
RUN mkdir -p /etc/seaweedfs
|
||||
COPY --from=builder /go/src/github.com/seaweedfs/seaweedfs/docker/filer_rocksdb.toml /etc/seaweedfs/filer.toml
|
||||
COPY --from=builder /go/src/github.com/seaweedfs/seaweedfs/docker/entrypoint.sh /entrypoint.sh
|
||||
|
||||
# Install dependencies and create non-root user
|
||||
RUN apk upgrade --no-cache && \
|
||||
apk add --no-cache fuse snappy gflags curl su-exec && \
|
||||
addgroup -g 1000 seaweed && \
|
||||
adduser -D -u 1000 -G seaweed seaweed
|
||||
|
||||
# volume server gprc port
|
||||
EXPOSE 18080
|
||||
# volume server http port
|
||||
EXPOSE 8080
|
||||
# filer server gprc port
|
||||
EXPOSE 18888
|
||||
# filer server http port
|
||||
EXPOSE 8888
|
||||
# master server shared gprc port
|
||||
EXPOSE 19333
|
||||
# master server shared http port
|
||||
EXPOSE 9333
|
||||
# s3 server http port
|
||||
EXPOSE 8333
|
||||
# webdav server http port
|
||||
EXPOSE 7333
|
||||
|
||||
# Create data directory and set proper ownership for seaweed user
|
||||
RUN mkdir -p /data/filer_rocksdb && \
|
||||
chown -R seaweed:seaweed /data && \
|
||||
chown -R seaweed:seaweed /etc/seaweedfs && \
|
||||
chmod 755 /entrypoint.sh
|
||||
|
||||
VOLUME /data
|
||||
|
||||
WORKDIR /data
|
||||
|
||||
# Entrypoint will handle permission fixes and user switching
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
# Default to a complete single-process cluster (master+volume+filer+S3+admin)
|
||||
# so the image is usable out of the box — including in environments like
|
||||
# GitHub Actions service containers that cannot pass arguments to the entrypoint.
|
||||
# Override with any other subcommand at `docker run` / compose time.
|
||||
CMD ["mini", "-dir=/data"]
|
||||
53
docker/Dockerfile.rocksdb_large_local
Normal file
53
docker/Dockerfile.rocksdb_large_local
Normal file
@@ -0,0 +1,53 @@
|
||||
FROM chrislusf/rocksdb_dev_env as builder
|
||||
|
||||
# build SeaweedFS
|
||||
RUN mkdir -p /go/src/github.com/seaweedfs/
|
||||
ADD . /go/src/github.com/seaweedfs/seaweedfs
|
||||
RUN ls -al /go/src/github.com/seaweedfs/ && \
|
||||
cd /go/src/github.com/seaweedfs/seaweedfs/weed \
|
||||
&& export LDFLAGS="-X github.com/seaweedfs/seaweedfs/weed/util/version.COMMIT=$(git rev-parse --short HEAD)" \
|
||||
&& go install -tags "5BytesOffset rocksdb" -ldflags "-extldflags -static ${LDFLAGS}"
|
||||
|
||||
|
||||
FROM alpine AS final
|
||||
LABEL author="Chris Lu"
|
||||
COPY --from=builder /go/bin/weed /usr/bin/
|
||||
RUN mkdir -p /etc/seaweedfs
|
||||
COPY --from=builder /go/src/github.com/seaweedfs/seaweedfs/docker/filer_rocksdb.toml /etc/seaweedfs/filer.toml
|
||||
COPY --from=builder /go/src/github.com/seaweedfs/seaweedfs/docker/entrypoint.sh /entrypoint.sh
|
||||
|
||||
# Install dependencies and create non-root user
|
||||
RUN apk upgrade --no-cache && \
|
||||
apk add --no-cache fuse snappy gflags curl tmux su-exec && \
|
||||
addgroup -g 1000 seaweed && \
|
||||
adduser -D -u 1000 -G seaweed seaweed
|
||||
|
||||
# volume server gprc port
|
||||
EXPOSE 18080
|
||||
# volume server http port
|
||||
EXPOSE 8080
|
||||
# filer server gprc port
|
||||
EXPOSE 18888
|
||||
# filer server http port
|
||||
EXPOSE 8888
|
||||
# master server shared gprc port
|
||||
EXPOSE 19333
|
||||
# master server shared http port
|
||||
EXPOSE 9333
|
||||
# s3 server http port
|
||||
EXPOSE 8333
|
||||
# webdav server http port
|
||||
EXPOSE 7333
|
||||
|
||||
# Create data directory and set proper ownership for seaweed user
|
||||
RUN mkdir -p /data/filer_rocksdb && \
|
||||
chown -R seaweed:seaweed /data && \
|
||||
chown -R seaweed:seaweed /etc/seaweedfs && \
|
||||
chmod 755 /entrypoint.sh
|
||||
|
||||
VOLUME /data
|
||||
|
||||
WORKDIR /data
|
||||
|
||||
# Entrypoint will handle permission fixes and user switching
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
31
docker/Dockerfile.s3tests
Normal file
31
docker/Dockerfile.s3tests
Normal file
@@ -0,0 +1,31 @@
|
||||
FROM ubuntu:20.04
|
||||
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||
git \
|
||||
sudo \
|
||||
debianutils \
|
||||
python3-pip \
|
||||
python3-virtualenv \
|
||||
python3-dev \
|
||||
libevent-dev \
|
||||
libffi-dev \
|
||||
libxml2-dev \
|
||||
libxslt-dev \
|
||||
zlib1g-dev && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
git clone https://github.com/ceph/s3-tests.git /opt/s3-tests
|
||||
|
||||
WORKDIR /opt/s3-tests
|
||||
RUN ./bootstrap
|
||||
|
||||
ENV \
|
||||
NOSETESTS_EXCLUDE="" \
|
||||
NOSETESTS_ATTR="" \
|
||||
NOSETESTS_OPTIONS="" \
|
||||
S3TEST_CONF="/s3tests.conf"
|
||||
|
||||
ENTRYPOINT ["/bin/bash", "-c"]
|
||||
CMD ["sleep 30 && exec ./virtualenv/bin/nosetests ${NOSETESTS_OPTIONS-} ${NOSETESTS_ATTR:+-a $NOSETESTS_ATTR} ${NOSETESTS_EXCLUDE:+-e $NOSETESTS_EXCLUDE}"]
|
||||
23
docker/Dockerfile.tarantool.dev_env
Normal file
23
docker/Dockerfile.tarantool.dev_env
Normal file
@@ -0,0 +1,23 @@
|
||||
FROM tarantool/tarantool:3.3.1 AS builder
|
||||
|
||||
# install dependencies
|
||||
RUN apt update && \
|
||||
apt install -y git unzip cmake tt=2.7.0
|
||||
|
||||
# init tt dir structure, create dir for app, create symlink
|
||||
RUN tt init && \
|
||||
mkdir app && \
|
||||
ln -sfn ${PWD}/app/ ${PWD}/instances.enabled/app
|
||||
|
||||
# copy cluster configs
|
||||
COPY tarantool /opt/tarantool/app
|
||||
|
||||
# build app
|
||||
RUN tt build app
|
||||
|
||||
# the base image's default healthcheck assumes a single-instance layout and
|
||||
# checks a control socket path that doesn't exist for this multi-instance
|
||||
# app, so it never reports healthy; check instance status instead.
|
||||
HEALTHCHECK --interval=5s --timeout=3s --start-period=15s --retries=6 \
|
||||
CMD tt status app | awk 'NR>2{if ($2!="RUNNING") exit 1} END{if (NR<=2) exit 1}'
|
||||
|
||||
146
docker/Makefile
Normal file
146
docker/Makefile
Normal file
@@ -0,0 +1,146 @@
|
||||
all: gen
|
||||
|
||||
.PHONY : gen
|
||||
|
||||
gen: dev
|
||||
|
||||
cgo ?= 0
|
||||
ldflags_extra ?= -extldflags -static
|
||||
|
||||
binary:
|
||||
export SWCOMMIT=$(shell git rev-parse --short HEAD)
|
||||
export SWLDFLAGS="-X github.com/seaweedfs/seaweedfs/weed/util/version.COMMIT=$(SWCOMMIT)"
|
||||
cd ../weed && CGO_ENABLED=$(cgo) GOOS=linux go build $(options) -tags "$(tags)" -ldflags "-s -w $(ldflags_extra) $(SWLDFLAGS)" -o weed_binary && mv weed_binary ../docker/weed
|
||||
cd ../other/mq_client_example/agent_pub_record && CGO_ENABLED=$(cgo) GOOS=linux go build && mv agent_pub_record ../../../docker/
|
||||
cd ../other/mq_client_example/agent_sub_record && CGO_ENABLED=$(cgo) GOOS=linux go build && mv agent_sub_record ../../../docker/
|
||||
|
||||
# Race detector requires CGO and dynamic linking - don't use -static
|
||||
binary_race: options = -race
|
||||
binary_race: cgo = 1
|
||||
binary_race: ldflags_extra =
|
||||
binary_race: binary
|
||||
|
||||
build: binary
|
||||
docker build --no-cache -t chrislusf/seaweedfs:local -f Dockerfile.local .
|
||||
|
||||
build_e2e: binary_race
|
||||
docker buildx build \
|
||||
--cache-from=type=local,src=/tmp/.buildx-cache \
|
||||
--cache-to=type=local,dest=/tmp/.buildx-cache-new,mode=max \
|
||||
--load \
|
||||
-t chrislusf/seaweedfs:e2e \
|
||||
-f Dockerfile.e2e .
|
||||
# Move cache to avoid growing cache size
|
||||
rm -rf /tmp/.buildx-cache || true
|
||||
mv /tmp/.buildx-cache-new /tmp/.buildx-cache || true
|
||||
|
||||
go_build: # make go_build tags=elastic,ydb,gocdk,hdfs,5BytesOffset,tarantool
|
||||
docker build --build-arg TAGS=$(tags) --no-cache -t chrislusf/seaweedfs:go_build -f Dockerfile.go_build .
|
||||
|
||||
go_build_large_disk:
|
||||
docker build --build-arg TAGS=large_disk --no-cache -t chrislusf/seaweedfs:large_disk -f Dockerfile.go_build .
|
||||
|
||||
build_rocksdb_dev_env:
|
||||
docker build --no-cache -t chrislusf/rocksdb_dev_env -f Dockerfile.rocksdb_dev_env .
|
||||
|
||||
build_rocksdb_local: build_rocksdb_dev_env
|
||||
cd .. ; docker build --no-cache -t chrislusf/seaweedfs:rocksdb_local -f docker/Dockerfile.rocksdb_large_local .
|
||||
|
||||
build_rocksdb:
|
||||
docker build --no-cache -t chrislusf/seaweedfs:rocksdb -f Dockerfile.rocksdb_large .
|
||||
|
||||
build_tarantool_dev_env:
|
||||
docker build --no-cache -t chrislusf/tarantool_dev_env -f Dockerfile.tarantool.dev_env .
|
||||
|
||||
s3tests_build:
|
||||
docker build --no-cache -t chrislusf/ceph-s3-tests:local -f Dockerfile.s3tests .
|
||||
|
||||
dev: build
|
||||
docker compose -f compose/local-dev-compose.yml -p seaweedfs up
|
||||
|
||||
dev_race: binary_race
|
||||
docker compose -f compose/local-dev-compose.yml -p seaweedfs up
|
||||
|
||||
dev_tls: build certstrap
|
||||
ENV_FILE="tls.env" docker compose -f compose/local-dev-compose.yml -p seaweedfs up
|
||||
|
||||
dev_mount: build
|
||||
docker compose -f compose/local-mount-compose.yml -p seaweedfs up
|
||||
|
||||
run_image: build
|
||||
docker run --rm -ti --device /dev/fuse --cap-add SYS_ADMIN --entrypoint /bin/sh chrislusf/seaweedfs:local
|
||||
|
||||
profile_mount: build
|
||||
docker compose -f compose/local-mount-profile-compose.yml -p seaweedfs up
|
||||
|
||||
k8s: build
|
||||
docker compose -f compose/local-k8s-compose.yml -p seaweedfs up
|
||||
|
||||
dev_registry: build
|
||||
docker compose -f compose/local-registry-compose.yml -p seaweedfs up
|
||||
|
||||
dev_replicate:
|
||||
docker build --build-arg TAGS=gocdk --no-cache -t chrislusf/seaweedfs:local -f Dockerfile.go_build .
|
||||
docker compose -f compose/local-replicate-compose.yml -p seaweedfs up
|
||||
|
||||
dev_auditlog: build
|
||||
docker compose -f compose/local-auditlog-compose.yml -p seaweedfs up
|
||||
|
||||
dev_nextcloud: build
|
||||
docker compose -f compose/local-nextcloud-compose.yml -p seaweedfs up
|
||||
|
||||
cluster: build
|
||||
docker compose -f compose/local-cluster-compose.yml -p seaweedfs up
|
||||
|
||||
2clusters: build
|
||||
docker compose -f compose/local-clusters-compose.yml -p seaweedfs up
|
||||
|
||||
2mount: build
|
||||
docker compose -f compose/local-sync-mount-compose.yml -p seaweedfs up
|
||||
|
||||
filer_backup: build
|
||||
docker compose -f compose/local-filer-backup-compose.yml -p seaweedfs up
|
||||
|
||||
hashicorp_raft: build
|
||||
docker compose -f compose/local-hashicorp-raft-compose.yml -p seaweedfs up
|
||||
|
||||
s3tests: build s3tests_build
|
||||
docker compose -f compose/local-s3tests-compose.yml -p seaweedfs up
|
||||
|
||||
brokers: build
|
||||
docker compose -f compose/local-brokers-compose.yml -p seaweedfs up
|
||||
|
||||
agent: build
|
||||
docker compose -f compose/local-mq-test.yml -p seaweedfs up
|
||||
|
||||
filer_etcd: build
|
||||
docker stack deploy -c compose/swarm-etcd.yml fs
|
||||
|
||||
test_etcd: build
|
||||
docker compose -f compose/test-etcd-filer.yml -p seaweedfs up
|
||||
|
||||
test_ydb: tags = ydb
|
||||
test_ydb: build
|
||||
docker compose -f compose/test-ydb-filer.yml -p seaweedfs up
|
||||
|
||||
test_tarantool: tags = tarantool
|
||||
test_tarantool: build_tarantool_dev_env build
|
||||
docker compose -f compose/test-tarantool-filer.yml -p seaweedfs up
|
||||
|
||||
test_keycloak_s3: build
|
||||
docker compose -f compose/test-keycloak-s3.yml -p seaweedfs up
|
||||
|
||||
clean:
|
||||
rm ./weed
|
||||
|
||||
certstrap:
|
||||
go install -v github.com/square/certstrap@latest
|
||||
certstrap --depot-path compose/tls init --curve P-256 --passphrase "" --common-name "SeaweedFS CA" || true
|
||||
certstrap --depot-path compose/tls request-cert --ou "SeaweedFS" --curve P-256 --passphrase "" --domain localhost --common-name volume01.dev || true
|
||||
certstrap --depot-path compose/tls request-cert --ou "SeaweedFS" --curve P-256 --passphrase "" --common-name master01.dev || true
|
||||
certstrap --depot-path compose/tls request-cert --ou "SeaweedFS" --curve P-256 --passphrase "" --common-name filer01.dev || true
|
||||
certstrap --depot-path compose/tls request-cert --ou "SeaweedFS" --curve P-256 --passphrase "" --common-name client01.dev || true
|
||||
certstrap --depot-path compose/tls sign --CA "SeaweedFS CA" volume01.dev || true
|
||||
certstrap --depot-path compose/tls sign --CA "SeaweedFS CA" master01.dev || true
|
||||
certstrap --depot-path compose/tls sign --CA "SeaweedFS CA" filer01.dev || true
|
||||
certstrap --depot-path compose/tls sign --CA "SeaweedFS CA" client01.dev || true
|
||||
104
docker/README.md
Normal file
104
docker/README.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Docker
|
||||
|
||||
## Compose V2
|
||||
SeaweedFS now uses the `v2` syntax `docker compose`
|
||||
|
||||
If you rely on using Docker Compose as docker-compose (with a hyphen), you can set up Compose V2 to act as a drop-in replacement of the previous docker-compose. Refer to the [Installing Compose](https://docs.docker.com/compose/install/) section for detailed instructions on upgrading.
|
||||
|
||||
Confirm your system has docker compose v2 with a version check
|
||||
```bash
|
||||
$ docker compose version
|
||||
Docker Compose version v2.10.2
|
||||
```
|
||||
|
||||
## Try it out
|
||||
|
||||
```bash
|
||||
|
||||
wget https://raw.githubusercontent.com/seaweedfs/seaweedfs/master/docker/seaweedfs-compose.yml
|
||||
|
||||
docker compose -f seaweedfs-compose.yml -p seaweedfs up
|
||||
|
||||
```
|
||||
|
||||
## Try latest tip
|
||||
|
||||
```bash
|
||||
|
||||
wget https://raw.githubusercontent.com/seaweedfs/seaweedfs/master/docker/seaweedfs-dev-compose.yml
|
||||
|
||||
docker compose -f seaweedfs-dev-compose.yml -p seaweedfs up
|
||||
|
||||
```
|
||||
|
||||
## Verify an image signature
|
||||
|
||||
Every image CI pushes to `chrislusf/seaweedfs` and `ghcr.io/chrislusf/seaweedfs` is signed with [cosign](https://docs.sigstore.dev/cosign/verifying/verify/), keyless, by the GitHub Actions workflow that built it, so there is no key to fetch or pin. The signature is attached to the image digest and covers the multi-arch index and each platform image in it; `latest` is the release image under another tag and verifies the same way. Images published before September 2026 predate signing.
|
||||
|
||||
```bash
|
||||
cosign verify \
|
||||
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
|
||||
--certificate-identity-regexp '^https://github.com/seaweedfs/seaweedfs/\.github/workflows/container_release_unified\.yml@' \
|
||||
chrislusf/seaweedfs:latest
|
||||
```
|
||||
|
||||
cosign prints the digest it verified. Deploy by that digest, or let an admission controller resolve the tag, so what runs is what was checked.
|
||||
|
||||
The identity is `https://github.com/seaweedfs/seaweedfs/.github/workflows/<workflow>@<ref>`. The ref is `refs/tags/<version>` for a release and `refs/heads/master` when a variant was republished by hand. The workflow is `container_release_unified.yml` for the release images, `container_dev.yml` for `dev`, `container_latest.yml` for a `latest` rebuilt by hand, `container_release_foundationdb.yml` for the `_large_disk_foundationdb` release image, and `container_foundationdb_version.yml` or `container_rocksdb_version.yml` for the per-version builds. The regexp above accepts release images only; `container_[a-z_]+\.yml@` accepts everything this repository publishes, `dev` included.
|
||||
|
||||
The same check as a Kyverno policy, release images only:
|
||||
|
||||
```yaml
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: verify-seaweedfs-images
|
||||
spec:
|
||||
validationFailureAction: Enforce
|
||||
webhookTimeoutSeconds: 30
|
||||
rules:
|
||||
- name: signed-by-the-release-workflow
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Pod
|
||||
verifyImages:
|
||||
- imageReferences:
|
||||
- "docker.io/chrislusf/seaweedfs:*"
|
||||
- "ghcr.io/chrislusf/seaweedfs:*"
|
||||
attestors:
|
||||
- entries:
|
||||
- keyless:
|
||||
issuer: https://token.actions.githubusercontent.com
|
||||
subject: https://github.com/seaweedfs/seaweedfs/.github/workflows/container_release_unified.yml@refs/tags/*
|
||||
```
|
||||
|
||||
## Local Development
|
||||
|
||||
```bash
|
||||
cd $GOPATH/src/github.com/seaweedfs/seaweedfs/docker
|
||||
make
|
||||
```
|
||||
|
||||
### S3 cmd
|
||||
|
||||
list
|
||||
```
|
||||
s3cmd --no-ssl --host=127.0.0.1:8333 ls s3://
|
||||
```
|
||||
|
||||
## Build and push a multiarch build
|
||||
|
||||
Make sure that `docker buildx` is supported (might be an experimental docker feature)
|
||||
```bash
|
||||
BUILDER=$(docker buildx create --driver docker-container --use)
|
||||
docker buildx build --pull --push --platform linux/386,linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 . -t chrislusf/seaweedfs
|
||||
docker buildx stop $BUILDER
|
||||
```
|
||||
|
||||
## Minio debugging
|
||||
```
|
||||
mc config host add local http://127.0.0.1:9000 some_access_key1 some_secret_key1
|
||||
mc admin trace --all --verbose local
|
||||
```
|
||||
18
docker/admin_integration/Dockerfile.local
Normal file
18
docker/admin_integration/Dockerfile.local
Normal file
@@ -0,0 +1,18 @@
|
||||
FROM alpine:latest
|
||||
|
||||
# Install required packages
|
||||
RUN apk add --no-cache \
|
||||
ca-certificates \
|
||||
fuse \
|
||||
curl \
|
||||
jq
|
||||
|
||||
# Copy our locally built binary
|
||||
COPY weed-local /usr/bin/weed
|
||||
RUN chmod +x /usr/bin/weed
|
||||
|
||||
# Create working directory
|
||||
WORKDIR /data
|
||||
|
||||
# Default command
|
||||
ENTRYPOINT ["/usr/bin/weed"]
|
||||
438
docker/admin_integration/EC-TESTING-README.md
Normal file
438
docker/admin_integration/EC-TESTING-README.md
Normal file
@@ -0,0 +1,438 @@
|
||||
# SeaweedFS EC Worker Testing Environment
|
||||
|
||||
This Docker Compose setup provides a comprehensive testing environment for SeaweedFS Erasure Coding (EC) workers using **official SeaweedFS commands**.
|
||||
|
||||
## 📂 Directory Structure
|
||||
|
||||
The testing environment is located in `docker/admin_integration/` and includes:
|
||||
|
||||
```
|
||||
docker/admin_integration/
|
||||
├── Makefile # Main management interface
|
||||
├── docker-compose-ec-test.yml # Docker compose configuration
|
||||
├── EC-TESTING-README.md # This documentation
|
||||
└── run-ec-test.sh # Quick start script
|
||||
```
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
The testing environment uses **official SeaweedFS commands** and includes:
|
||||
|
||||
- **1 Master Server** (port 9333) - Coordinates the cluster with 50MB volume size limit
|
||||
- **6 Volume Servers** (ports 8080-8085) - Distributed across 2 data centers and 3 racks for diversity
|
||||
- **1 Filer** (port 8888) - Provides file system interface
|
||||
- **1 Admin Server** (port 23646) - Detects volumes needing EC and manages workers using official `admin` command
|
||||
- **3 EC Workers** - Execute erasure coding tasks using official `worker` command with task-specific working directories
|
||||
- **1 Load Generator** - Continuously writes and deletes files using SeaweedFS shell commands
|
||||
- **1 Monitor** - Tracks cluster health and EC progress using shell scripts
|
||||
|
||||
## ✨ New Features
|
||||
|
||||
### **Task-Specific Working Directories**
|
||||
Each worker now creates dedicated subdirectories for different task types:
|
||||
- `/work/erasure_coding/` - For EC encoding tasks
|
||||
- `/work/vacuum/` - For vacuum cleanup tasks
|
||||
- `/work/balance/` - For volume balancing tasks
|
||||
|
||||
This provides:
|
||||
- **Organization**: Each task type gets isolated working space
|
||||
- **Debugging**: Easy to find files/logs related to specific task types
|
||||
- **Cleanup**: Can clean up task-specific artifacts easily
|
||||
- **Concurrent Safety**: Different task types won't interfere with each other's files
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Docker and Docker Compose installed
|
||||
- GNU Make installed
|
||||
- At least 4GB RAM available for containers
|
||||
- Ports 8080-8085, 8888, 9333, 23646 available
|
||||
|
||||
### Start the Environment
|
||||
|
||||
```bash
|
||||
# Navigate to the admin integration directory
|
||||
cd docker/admin_integration/
|
||||
|
||||
# Show available commands
|
||||
make help
|
||||
|
||||
# Start the complete testing environment
|
||||
make start
|
||||
```
|
||||
|
||||
The `make start` command will:
|
||||
1. Start all services using official SeaweedFS images
|
||||
2. Configure workers with task-specific working directories
|
||||
3. Wait for services to be ready
|
||||
4. Display monitoring URLs and run health checks
|
||||
|
||||
### Alternative Commands
|
||||
|
||||
```bash
|
||||
# Quick start aliases
|
||||
make up # Same as 'make start'
|
||||
|
||||
# Development mode (higher load for faster testing)
|
||||
make dev-start
|
||||
|
||||
# Build images without starting
|
||||
make build
|
||||
```
|
||||
|
||||
## 📋 Available Make Targets
|
||||
|
||||
Run `make help` to see all available targets:
|
||||
|
||||
### **🚀 Main Operations**
|
||||
- `make start` - Start the complete EC testing environment
|
||||
- `make stop` - Stop all services
|
||||
- `make restart` - Restart all services
|
||||
- `make clean` - Complete cleanup (containers, volumes, images)
|
||||
|
||||
### **📊 Monitoring & Status**
|
||||
- `make health` - Check health of all services
|
||||
- `make status` - Show status of all containers
|
||||
- `make urls` - Display all monitoring URLs
|
||||
- `make monitor` - Open monitor dashboard in browser
|
||||
- `make monitor-status` - Show monitor status via API
|
||||
- `make volume-status` - Show volume status from master
|
||||
- `make admin-status` - Show admin server status
|
||||
- `make cluster-status` - Show complete cluster status
|
||||
|
||||
### **📋 Logs Management**
|
||||
- `make logs` - Show logs from all services
|
||||
- `make logs-admin` - Show admin server logs
|
||||
- `make logs-workers` - Show all worker logs
|
||||
- `make logs-worker1/2/3` - Show specific worker logs
|
||||
- `make logs-load` - Show load generator logs
|
||||
- `make logs-monitor` - Show monitor logs
|
||||
- `make backup-logs` - Backup all logs to files
|
||||
|
||||
### **⚖️ Scaling & Testing**
|
||||
- `make scale-workers WORKERS=5` - Scale workers to 5 instances
|
||||
- `make scale-load RATE=25` - Increase load generation rate
|
||||
- `make test-ec` - Run focused EC test scenario
|
||||
|
||||
### **🔧 Development & Debug**
|
||||
- `make shell-admin` - Open shell in admin container
|
||||
- `make shell-worker1` - Open shell in worker container
|
||||
- `make debug` - Show debug information
|
||||
- `make troubleshoot` - Run troubleshooting checks
|
||||
|
||||
## 📊 Monitoring URLs
|
||||
|
||||
| Service | URL | Description |
|
||||
|---------|-----|-------------|
|
||||
| Master UI | http://localhost:9333 | Cluster status and topology |
|
||||
| Filer | http://localhost:8888 | File operations |
|
||||
| Admin Server | http://localhost:23646/ | Task management |
|
||||
| Monitor | http://localhost:9999/status | Complete cluster monitoring |
|
||||
| Volume Servers | http://localhost:8080-8085/status | Individual volume server stats |
|
||||
|
||||
Quick access: `make urls` or `make monitor`
|
||||
|
||||
## 🔄 How EC Testing Works
|
||||
|
||||
### 1. Continuous Load Generation
|
||||
- **Write Rate**: 10 files/second (1-5MB each)
|
||||
- **Delete Rate**: 2 files/second
|
||||
- **Target**: Fill volumes to 50MB limit quickly
|
||||
|
||||
### 2. Volume Detection
|
||||
- Admin server scans master every 30 seconds
|
||||
- Identifies volumes >40MB (80% of 50MB limit)
|
||||
- Queues EC tasks for eligible volumes
|
||||
|
||||
### 3. EC Worker Assignment
|
||||
- **Worker 1**: EC specialist (max 2 concurrent tasks)
|
||||
- **Worker 2**: EC + Vacuum hybrid (max 2 concurrent tasks)
|
||||
- **Worker 3**: EC + Vacuum hybrid (max 1 concurrent task)
|
||||
|
||||
### 4. Comprehensive EC Process
|
||||
Each EC task follows 6 phases:
|
||||
1. **Copy Volume Data** (5-15%) - Stream .dat/.idx files locally
|
||||
2. **Mark Read-Only** (20-25%) - Ensure data consistency
|
||||
3. **Local Encoding** (30-60%) - Create 14 shards (10+4 Reed-Solomon)
|
||||
4. **Calculate Placement** (65-70%) - Smart rack-aware distribution
|
||||
5. **Distribute Shards** (75-90%) - Upload to optimal servers
|
||||
6. **Verify & Cleanup** (95-100%) - Validate and clean temporary files
|
||||
|
||||
### 5. Real-Time Monitoring
|
||||
- Volume analysis and EC candidate detection
|
||||
- Worker health and task progress
|
||||
- No data loss verification
|
||||
- Performance metrics
|
||||
|
||||
## 📋 Key Features Tested
|
||||
|
||||
### ✅ EC Implementation Features
|
||||
- [x] Local volume data copying with progress tracking
|
||||
- [x] Local Reed-Solomon encoding (10+4 shards)
|
||||
- [x] Intelligent shard placement with rack awareness
|
||||
- [x] Load balancing across available servers
|
||||
- [x] Backup server selection for redundancy
|
||||
- [x] Detailed step-by-step progress tracking
|
||||
- [x] Comprehensive error handling and recovery
|
||||
|
||||
### ✅ Infrastructure Features
|
||||
- [x] Multi-datacenter topology (dc1, dc2)
|
||||
- [x] Rack diversity (rack1, rack2, rack3)
|
||||
- [x] Volume size limits (50MB)
|
||||
- [x] Worker capability matching
|
||||
- [x] Health monitoring and alerting
|
||||
- [x] Continuous workload simulation
|
||||
|
||||
## 🛠️ Common Usage Patterns
|
||||
|
||||
### Basic Testing Workflow
|
||||
```bash
|
||||
# Start environment
|
||||
make start
|
||||
|
||||
# Watch progress
|
||||
make monitor-status
|
||||
|
||||
# Check for EC candidates
|
||||
make volume-status
|
||||
|
||||
# View worker activity
|
||||
make logs-workers
|
||||
|
||||
# Stop when done
|
||||
make stop
|
||||
```
|
||||
|
||||
### High-Load Testing
|
||||
```bash
|
||||
# Start with higher load
|
||||
make dev-start
|
||||
|
||||
# Scale up workers and load
|
||||
make scale-workers WORKERS=5
|
||||
make scale-load RATE=50
|
||||
|
||||
# Monitor intensive EC activity
|
||||
make logs-admin
|
||||
```
|
||||
|
||||
### Debugging Issues
|
||||
```bash
|
||||
# Check port conflicts and system state
|
||||
make troubleshoot
|
||||
|
||||
# View specific service logs
|
||||
make logs-admin
|
||||
make logs-worker1
|
||||
|
||||
# Get shell access for debugging
|
||||
make shell-admin
|
||||
make shell-worker1
|
||||
|
||||
# Check detailed status
|
||||
make debug
|
||||
```
|
||||
|
||||
### Development Iteration
|
||||
```bash
|
||||
# Quick restart after code changes
|
||||
make restart
|
||||
|
||||
# Rebuild and restart
|
||||
make clean
|
||||
make start
|
||||
|
||||
# Monitor specific components
|
||||
make logs-monitor
|
||||
```
|
||||
|
||||
## 📈 Expected Results
|
||||
|
||||
### Successful EC Testing Shows:
|
||||
1. **Volume Growth**: Steady increase in volume sizes toward 50MB limit
|
||||
2. **EC Detection**: Admin server identifies volumes >40MB for EC
|
||||
3. **Task Assignment**: Workers receive and execute EC tasks
|
||||
4. **Shard Distribution**: 14 shards distributed across 6 volume servers
|
||||
5. **No Data Loss**: All files remain accessible during and after EC
|
||||
6. **Performance**: EC tasks complete within estimated timeframes
|
||||
|
||||
### Sample Monitor Output:
|
||||
```bash
|
||||
# Check current status
|
||||
make monitor-status
|
||||
|
||||
# Output example:
|
||||
{
|
||||
"monitor": {
|
||||
"uptime": "15m30s",
|
||||
"master_addr": "master:9333",
|
||||
"admin_addr": "admin:9900"
|
||||
},
|
||||
"stats": {
|
||||
"VolumeCount": 12,
|
||||
"ECTasksDetected": 3,
|
||||
"WorkersActive": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
You can customize the environment by setting variables:
|
||||
|
||||
```bash
|
||||
# High load testing
|
||||
WRITE_RATE=25 DELETE_RATE=5 make start
|
||||
|
||||
# Extended test duration
|
||||
TEST_DURATION=7200 make start # 2 hours
|
||||
```
|
||||
|
||||
### Scaling Examples
|
||||
|
||||
```bash
|
||||
# Scale workers
|
||||
make scale-workers WORKERS=6
|
||||
|
||||
# Increase load generation
|
||||
make scale-load RATE=30
|
||||
|
||||
# Combined scaling
|
||||
make scale-workers WORKERS=4
|
||||
make scale-load RATE=40
|
||||
```
|
||||
|
||||
## 🧹 Cleanup Options
|
||||
|
||||
```bash
|
||||
# Stop services only
|
||||
make stop
|
||||
|
||||
# Remove containers but keep volumes
|
||||
make down
|
||||
|
||||
# Remove data volumes only
|
||||
make clean-volumes
|
||||
|
||||
# Remove built images only
|
||||
make clean-images
|
||||
|
||||
# Complete cleanup (everything)
|
||||
make clean
|
||||
```
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Quick Diagnostics
|
||||
```bash
|
||||
# Run complete troubleshooting
|
||||
make troubleshoot
|
||||
|
||||
# Check specific components
|
||||
make health
|
||||
make debug
|
||||
make status
|
||||
```
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Services not starting:**
|
||||
```bash
|
||||
# Check port availability
|
||||
make troubleshoot
|
||||
|
||||
# View startup logs
|
||||
make logs-master
|
||||
make logs-admin
|
||||
```
|
||||
|
||||
**No EC tasks being created:**
|
||||
```bash
|
||||
# Check volume status
|
||||
make volume-status
|
||||
|
||||
# Increase load to fill volumes faster
|
||||
make scale-load RATE=30
|
||||
|
||||
# Check admin detection
|
||||
make logs-admin
|
||||
```
|
||||
|
||||
**Workers not responding:**
|
||||
```bash
|
||||
# Check worker registration
|
||||
make admin-status
|
||||
|
||||
# View worker logs
|
||||
make logs-workers
|
||||
|
||||
# Restart workers
|
||||
make restart
|
||||
```
|
||||
|
||||
### Performance Tuning
|
||||
|
||||
**For faster testing:**
|
||||
```bash
|
||||
make dev-start # Higher default load
|
||||
make scale-load RATE=50 # Very high load
|
||||
```
|
||||
|
||||
**For stress testing:**
|
||||
```bash
|
||||
make scale-workers WORKERS=8
|
||||
make scale-load RATE=100
|
||||
```
|
||||
|
||||
## 📚 Technical Details
|
||||
|
||||
### Network Architecture
|
||||
- Custom bridge network (172.20.0.0/16)
|
||||
- Service discovery via container names
|
||||
- Health checks for all services
|
||||
|
||||
### Storage Layout
|
||||
- Each volume server: max 100 volumes
|
||||
- Data centers: dc1, dc2
|
||||
- Racks: rack1, rack2, rack3
|
||||
- Volume limit: 50MB per volume
|
||||
|
||||
### EC Algorithm
|
||||
- Reed-Solomon RS(10,4)
|
||||
- 10 data shards + 4 parity shards
|
||||
- Rack-aware distribution
|
||||
- Backup server redundancy
|
||||
|
||||
### Make Integration
|
||||
- Color-coded output for better readability
|
||||
- Comprehensive help system (`make help`)
|
||||
- Parallel execution support
|
||||
- Error handling and cleanup
|
||||
- Cross-platform compatibility
|
||||
|
||||
## 🎯 Quick Reference
|
||||
|
||||
```bash
|
||||
# Essential commands
|
||||
make help # Show all available targets
|
||||
make start # Start complete environment
|
||||
make health # Check all services
|
||||
make monitor # Open dashboard
|
||||
make logs-admin # View admin activity
|
||||
make clean # Complete cleanup
|
||||
|
||||
# Monitoring
|
||||
make volume-status # Check for EC candidates
|
||||
make admin-status # Check task queue
|
||||
make monitor-status # Full cluster status
|
||||
|
||||
# Scaling & Testing
|
||||
make test-ec # Run focused EC test
|
||||
make scale-load RATE=X # Increase load
|
||||
make troubleshoot # Diagnose issues
|
||||
```
|
||||
|
||||
This environment provides a realistic testing scenario for SeaweedFS EC workers with actual data operations, comprehensive monitoring, and easy management through Make targets.
|
||||
346
docker/admin_integration/Makefile
Normal file
346
docker/admin_integration/Makefile
Normal file
@@ -0,0 +1,346 @@
|
||||
# SeaweedFS Admin Integration Test Makefile
|
||||
# Tests the admin server and worker functionality using official weed commands
|
||||
|
||||
.PHONY: help build build-and-restart restart-workers start stop restart logs clean status test admin-ui worker-logs master-logs admin-logs vacuum-test vacuum-demo vacuum-status vacuum-data vacuum-data-high vacuum-data-low vacuum-continuous vacuum-clean vacuum-help
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
COMPOSE_FILE := docker-compose-ec-test.yml
|
||||
PROJECT_NAME := admin_integration
|
||||
|
||||
build: ## Build SeaweedFS with latest changes and create Docker image
|
||||
@echo "🔨 Building SeaweedFS with latest changes..."
|
||||
@echo "1️⃣ Generating admin templates..."
|
||||
@cd ../../ && make admin-generate
|
||||
@echo "2️⃣ Building Docker image with latest changes..."
|
||||
@cd ../ && make build
|
||||
@echo "3️⃣ Copying binary for local docker-compose..."
|
||||
@cp ../weed ./weed-local
|
||||
@echo "✅ Build complete! Updated image: chrislusf/seaweedfs:local"
|
||||
@echo "💡 Run 'make restart' to apply changes to running services"
|
||||
|
||||
build-and-restart: build ## Build with latest changes and restart services
|
||||
@echo "🔄 Recreating services with new image..."
|
||||
@echo "1️⃣ Recreating admin server with new image..."
|
||||
@docker-compose -f $(COMPOSE_FILE) up -d admin
|
||||
@sleep 5
|
||||
@echo "2️⃣ Recreating workers to reconnect..."
|
||||
@docker-compose -f $(COMPOSE_FILE) up -d worker1 worker2 worker3
|
||||
@echo "✅ All services recreated with latest changes!"
|
||||
@echo "🌐 Admin UI: http://localhost:23646/"
|
||||
@echo "💡 Workers will reconnect to the new admin server"
|
||||
|
||||
restart-workers: ## Restart all workers to reconnect to admin server
|
||||
@echo "🔄 Restarting workers to reconnect to admin server..."
|
||||
@docker-compose -f $(COMPOSE_FILE) restart worker1 worker2 worker3
|
||||
@echo "✅ Workers restarted and will reconnect to admin server"
|
||||
|
||||
help: ## Show this help message
|
||||
@echo "SeaweedFS Admin Integration Test"
|
||||
@echo "================================"
|
||||
@echo "Tests admin server task distribution to workers using official weed commands"
|
||||
@echo ""
|
||||
@echo "🏗️ Cluster Management:"
|
||||
@grep -E '^(start|stop|restart|clean|status|build):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " %-18s %s\n", $$1, $$2}'
|
||||
@echo ""
|
||||
@echo "🧪 Testing:"
|
||||
@grep -E '^(test|demo|validate|quick-test):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " %-18s %s\n", $$1, $$2}'
|
||||
@echo ""
|
||||
@echo "🗑️ Vacuum Testing:"
|
||||
@grep -E '^vacuum-.*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " %-18s %s\n", $$1, $$2}'
|
||||
@echo ""
|
||||
@echo "📜 Monitoring:"
|
||||
@grep -E '^(logs|admin-logs|worker-logs|master-logs|admin-ui):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " %-18s %s\n", $$1, $$2}'
|
||||
@echo ""
|
||||
@echo "🚀 Quick Start:"
|
||||
@echo " make start # Start cluster"
|
||||
@echo " make vacuum-test # Test vacuum tasks"
|
||||
@echo " make vacuum-help # Vacuum testing guide"
|
||||
@echo ""
|
||||
@echo "💡 For detailed vacuum testing: make vacuum-help"
|
||||
|
||||
start: ## Start the complete SeaweedFS cluster with admin and workers
|
||||
@echo "🚀 Starting SeaweedFS cluster with admin and workers..."
|
||||
@docker-compose -f $(COMPOSE_FILE) up -d
|
||||
@echo "✅ Cluster started!"
|
||||
@echo ""
|
||||
@echo "📊 Access points:"
|
||||
@echo " • Admin UI: http://localhost:23646/"
|
||||
@echo " • Master UI: http://localhost:9333/"
|
||||
@echo " • Filer: http://localhost:8888/"
|
||||
@echo ""
|
||||
@echo "📈 Services starting up..."
|
||||
@echo " • Master server: ✓"
|
||||
@echo " • Volume servers: Starting (6 servers)..."
|
||||
@echo " • Filer: Starting..."
|
||||
@echo " • Admin server: Starting..."
|
||||
@echo " • Workers: Starting (3 workers)..."
|
||||
@echo ""
|
||||
@echo "⏳ Use 'make status' to check startup progress"
|
||||
@echo "💡 Use 'make logs' to watch the startup process"
|
||||
|
||||
start-staged: ## Start services in proper order with delays
|
||||
@echo "🚀 Starting SeaweedFS cluster in stages..."
|
||||
@echo ""
|
||||
@echo "Stage 1: Starting Master server..."
|
||||
@docker-compose -f $(COMPOSE_FILE) up -d master
|
||||
@sleep 10
|
||||
@echo ""
|
||||
@echo "Stage 2: Starting Volume servers..."
|
||||
@docker-compose -f $(COMPOSE_FILE) up -d volume1 volume2 volume3 volume4 volume5 volume6
|
||||
@sleep 15
|
||||
@echo ""
|
||||
@echo "Stage 3: Starting Filer..."
|
||||
@docker-compose -f $(COMPOSE_FILE) up -d filer
|
||||
@sleep 10
|
||||
@echo ""
|
||||
@echo "Stage 4: Starting Admin server..."
|
||||
@docker-compose -f $(COMPOSE_FILE) up -d admin
|
||||
@sleep 15
|
||||
@echo ""
|
||||
@echo "Stage 5: Starting Workers..."
|
||||
@docker-compose -f $(COMPOSE_FILE) up -d worker1 worker2 worker3
|
||||
@sleep 10
|
||||
@echo ""
|
||||
@echo "Stage 6: Starting Load generator and Monitor..."
|
||||
@docker-compose -f $(COMPOSE_FILE) up -d load_generator monitor
|
||||
@echo ""
|
||||
@echo "✅ All services started!"
|
||||
@echo ""
|
||||
@echo "📊 Access points:"
|
||||
@echo " • Admin UI: http://localhost:23646/"
|
||||
@echo " • Master UI: http://localhost:9333/"
|
||||
@echo " • Filer: http://localhost:8888/"
|
||||
@echo ""
|
||||
@echo "⏳ Services are initializing... Use 'make status' to check progress"
|
||||
|
||||
stop: ## Stop all services
|
||||
@echo "🛑 Stopping SeaweedFS cluster..."
|
||||
@docker-compose -f $(COMPOSE_FILE) down
|
||||
@echo "✅ Cluster stopped"
|
||||
|
||||
restart: stop start ## Restart the entire cluster
|
||||
|
||||
clean: ## Stop and remove all containers, networks, and volumes
|
||||
@echo "🧹 Cleaning up SeaweedFS test environment..."
|
||||
@docker-compose -f $(COMPOSE_FILE) down -v --remove-orphans
|
||||
@docker system prune -f
|
||||
@rm -rf data/
|
||||
@echo "✅ Environment cleaned"
|
||||
|
||||
status: ## Check the status of all services
|
||||
@echo "📊 SeaweedFS Cluster Status"
|
||||
@echo "=========================="
|
||||
@docker-compose -f $(COMPOSE_FILE) ps
|
||||
@echo ""
|
||||
@echo "📋 Service Health:"
|
||||
@echo "Master:"
|
||||
@curl -s http://localhost:9333/cluster/status | jq '.IsLeader' 2>/dev/null || echo " ❌ Master not ready"
|
||||
@echo "Admin:"
|
||||
@curl -s http://localhost:23646/ | grep -q "Admin" && echo " ✅ Admin ready" || echo " ❌ Admin not ready"
|
||||
|
||||
logs: ## Show logs from all services
|
||||
@echo "📜 Following logs from all services..."
|
||||
@echo "💡 Press Ctrl+C to stop following logs"
|
||||
@docker-compose -f $(COMPOSE_FILE) logs -f
|
||||
|
||||
admin-logs: ## Show logs from admin server only
|
||||
@echo "📜 Admin server logs:"
|
||||
@docker-compose -f $(COMPOSE_FILE) logs -f admin
|
||||
|
||||
worker-logs: ## Show logs from all workers
|
||||
@echo "📜 Worker logs:"
|
||||
@docker-compose -f $(COMPOSE_FILE) logs -f worker1 worker2 worker3
|
||||
|
||||
master-logs: ## Show logs from master server
|
||||
@echo "📜 Master server logs:"
|
||||
@docker-compose -f $(COMPOSE_FILE) logs -f master
|
||||
|
||||
admin-ui: ## Open admin UI in browser (macOS)
|
||||
@echo "🌐 Opening admin UI in browser..."
|
||||
@open http://localhost:23646/ || echo "💡 Manually open: http://localhost:23646/"
|
||||
|
||||
test: ## Run integration test to verify task assignment and completion
|
||||
@echo "🧪 Running Admin-Worker Integration Test"
|
||||
@echo "========================================"
|
||||
@echo ""
|
||||
@echo "1️⃣ Checking cluster health..."
|
||||
@sleep 5
|
||||
@curl -s http://localhost:9333/cluster/status | jq '.IsLeader' > /dev/null && echo "✅ Master healthy" || echo "❌ Master not ready"
|
||||
@curl -s http://localhost:23646/ | grep -q "Admin" && echo "✅ Admin healthy" || echo "❌ Admin not ready"
|
||||
@echo ""
|
||||
@echo "2️⃣ Checking worker registration..."
|
||||
@sleep 10
|
||||
@echo "💡 Check admin UI for connected workers: http://localhost:23646/"
|
||||
@echo ""
|
||||
@echo "3️⃣ Generating load to trigger EC tasks..."
|
||||
@echo "📝 Creating test files to fill volumes..."
|
||||
@echo "Creating large files with random data to trigger EC (targeting ~60MB total to exceed 50MB limit)..."
|
||||
@for i in {1..12}; do \
|
||||
echo "Creating 5MB random file $$i..."; \
|
||||
docker run --rm --network admin_integration_seaweed_net -v /tmp:/tmp --entrypoint sh chrislusf/seaweedfs:local -c "dd if=/dev/urandom of=/tmp/largefile$$i.dat bs=1M count=5 2>/dev/null && weed upload -master=master:9333 /tmp/largefile$$i.dat && rm /tmp/largefile$$i.dat"; \
|
||||
sleep 3; \
|
||||
done
|
||||
@echo ""
|
||||
@echo "4️⃣ Waiting for volumes to process large files and reach 50MB limit..."
|
||||
@echo "This may take a few minutes as we're uploading 60MB of data..."
|
||||
@sleep 60
|
||||
@echo ""
|
||||
@echo "5️⃣ Checking for EC task creation and assignment..."
|
||||
@echo "💡 Monitor the admin UI to see:"
|
||||
@echo " • Tasks being created for volumes needing EC"
|
||||
@echo " • Workers picking up tasks"
|
||||
@echo " • Task progress (pending → running → completed)"
|
||||
@echo " • EC shards being distributed"
|
||||
@echo ""
|
||||
@echo "✅ Integration test setup complete!"
|
||||
@echo "📊 Monitor progress at: http://localhost:23646/"
|
||||
|
||||
quick-test: ## Quick verification that core services are running
|
||||
@echo "⚡ Quick Health Check"
|
||||
@echo "===================="
|
||||
@echo "Master: $$(curl -s http://localhost:9333/cluster/status | jq -r '.IsLeader // "not ready"')"
|
||||
@echo "Admin: $$(curl -s http://localhost:23646/ | grep -q "Admin" && echo "ready" || echo "not ready")"
|
||||
@echo "Workers: $$(docker-compose -f $(COMPOSE_FILE) ps worker1 worker2 worker3 | grep -c Up) running"
|
||||
|
||||
validate: ## Validate integration test configuration
|
||||
@echo "🔍 Validating Integration Test Configuration"
|
||||
@echo "==========================================="
|
||||
@chmod +x test-integration.sh
|
||||
@./test-integration.sh
|
||||
|
||||
demo: start ## Start cluster and run demonstration
|
||||
@echo "🎭 SeaweedFS Admin-Worker Demo"
|
||||
@echo "============================="
|
||||
@echo ""
|
||||
@echo "⏳ Waiting for services to start..."
|
||||
@sleep 45
|
||||
@echo ""
|
||||
@echo "🎯 Demo Overview:"
|
||||
@echo " • 1 Master server (coordinates cluster)"
|
||||
@echo " • 6 Volume servers (50MB volume limit)"
|
||||
@echo " • 1 Admin server (task management)"
|
||||
@echo " • 3 Workers (execute EC tasks)"
|
||||
@echo " • Load generator (creates files continuously)"
|
||||
@echo ""
|
||||
@echo "📊 Watch the process:"
|
||||
@echo " 1. Visit: http://localhost:23646/"
|
||||
@echo " 2. Observe workers connecting"
|
||||
@echo " 3. Watch tasks being created and assigned"
|
||||
@echo " 4. See tasks progress from pending → completed"
|
||||
@echo ""
|
||||
@echo "🔄 The demo will:"
|
||||
@echo " • Fill volumes to 50MB limit"
|
||||
@echo " • Admin detects volumes needing EC"
|
||||
@echo " • Workers receive and execute EC tasks"
|
||||
@echo " • Tasks complete with shard distribution"
|
||||
@echo ""
|
||||
@echo "💡 Use 'make worker-logs' to see worker activity"
|
||||
@echo "💡 Use 'make admin-logs' to see admin task management"
|
||||
|
||||
# Vacuum Testing Targets
|
||||
vacuum-test: ## Create test data with garbage and verify vacuum detection
|
||||
@echo "🧪 SeaweedFS Vacuum Task Testing"
|
||||
@echo "================================"
|
||||
@echo ""
|
||||
@echo "1️⃣ Checking cluster health..."
|
||||
@curl -s http://localhost:9333/cluster/status | jq '.IsLeader' > /dev/null && echo "✅ Master ready" || (echo "❌ Master not ready. Run 'make start' first." && exit 1)
|
||||
@curl -s http://localhost:23646/ | grep -q "Admin" && echo "✅ Admin ready" || (echo "❌ Admin not ready. Run 'make start' first." && exit 1)
|
||||
@echo ""
|
||||
@echo "2️⃣ Creating test data with garbage..."
|
||||
@docker-compose -f $(COMPOSE_FILE) exec vacuum-tester go run create_vacuum_test_data.go -files=25 -delete=0.5 -size=200
|
||||
@echo ""
|
||||
@echo "3️⃣ Configuration Instructions:"
|
||||
@echo " Visit: http://localhost:23646/maintenance/config/vacuum"
|
||||
@echo " Set for testing:"
|
||||
@echo " • Enable Vacuum Tasks: ✅ Checked"
|
||||
@echo " • Garbage Threshold: 0.20 (20%)"
|
||||
@echo " • Scan Interval: [30] [Seconds]"
|
||||
@echo " • Min Volume Age: [0] [Minutes]"
|
||||
@echo " • Max Concurrent: 2"
|
||||
@echo ""
|
||||
@echo "4️⃣ Monitor vacuum tasks at: http://localhost:23646/maintenance"
|
||||
@echo ""
|
||||
@echo "💡 Use 'make vacuum-status' to check volume garbage ratios"
|
||||
|
||||
vacuum-demo: ## Run automated vacuum testing demonstration
|
||||
@echo "🎭 Vacuum Task Demo"
|
||||
@echo "=================="
|
||||
@echo ""
|
||||
@echo "⚠️ This demo requires user interaction for configuration"
|
||||
@echo "💡 Make sure cluster is running with 'make start'"
|
||||
@echo ""
|
||||
@docker-compose -f $(COMPOSE_FILE) exec vacuum-tester sh -c "chmod +x demo_vacuum_testing.sh && ./demo_vacuum_testing.sh"
|
||||
|
||||
vacuum-status: ## Check current volume status and garbage ratios
|
||||
@echo "📊 Current Volume Status"
|
||||
@echo "======================="
|
||||
@docker-compose -f $(COMPOSE_FILE) exec vacuum-tester sh -c "chmod +x check_volumes.sh && ./check_volumes.sh"
|
||||
|
||||
vacuum-data: ## Create test data with configurable parameters
|
||||
@echo "📁 Creating vacuum test data..."
|
||||
@echo "Usage: make vacuum-data [FILES=20] [DELETE=0.4] [SIZE=100]"
|
||||
@echo ""
|
||||
@docker-compose -f $(COMPOSE_FILE) exec vacuum-tester go run create_vacuum_test_data.go \
|
||||
-files=$${FILES:-20} \
|
||||
-delete=$${DELETE:-0.4} \
|
||||
-size=$${SIZE:-100}
|
||||
|
||||
vacuum-data-high: ## Create high garbage ratio test data (should trigger vacuum)
|
||||
@echo "📁 Creating high garbage test data (70% garbage)..."
|
||||
@docker-compose -f $(COMPOSE_FILE) exec vacuum-tester go run create_vacuum_test_data.go -files=30 -delete=0.7 -size=150
|
||||
|
||||
vacuum-data-low: ## Create low garbage ratio test data (should NOT trigger vacuum)
|
||||
@echo "📁 Creating low garbage test data (15% garbage)..."
|
||||
@docker-compose -f $(COMPOSE_FILE) exec vacuum-tester go run create_vacuum_test_data.go -files=30 -delete=0.15 -size=150
|
||||
|
||||
vacuum-continuous: ## Generate garbage continuously for testing
|
||||
@echo "🔄 Generating continuous garbage for vacuum testing..."
|
||||
@echo "Creating 5 rounds of test data with 30-second intervals..."
|
||||
@for i in {1..5}; do \
|
||||
echo "Round $$i: Creating garbage..."; \
|
||||
docker-compose -f $(COMPOSE_FILE) exec vacuum-tester go run create_vacuum_test_data.go -files=10 -delete=0.6 -size=100; \
|
||||
echo "Waiting 30 seconds..."; \
|
||||
sleep 30; \
|
||||
done
|
||||
@echo "✅ Continuous test complete. Check vacuum task activity!"
|
||||
|
||||
vacuum-clean: ## Clean up vacuum test data (removes all volumes!)
|
||||
@echo "🧹 Cleaning up vacuum test data..."
|
||||
@echo "⚠️ WARNING: This will delete ALL volumes!"
|
||||
@read -p "Are you sure? (y/N): " confirm && [ "$$confirm" = "y" ] || exit 1
|
||||
@echo "Stopping cluster..."
|
||||
@docker-compose -f $(COMPOSE_FILE) down
|
||||
@echo "Removing volume data..."
|
||||
@rm -rf data/volume*/
|
||||
@echo "Restarting cluster..."
|
||||
@docker-compose -f $(COMPOSE_FILE) up -d
|
||||
@echo "✅ Clean up complete. Fresh volumes ready for testing."
|
||||
|
||||
vacuum-help: ## Show vacuum testing help and examples
|
||||
@echo "🧪 Vacuum Testing Commands (Docker-based)"
|
||||
@echo "=========================================="
|
||||
@echo ""
|
||||
@echo "Quick Start:"
|
||||
@echo " make start # Start SeaweedFS cluster with vacuum-tester"
|
||||
@echo " make vacuum-test # Create test data and instructions"
|
||||
@echo " make vacuum-status # Check volume status"
|
||||
@echo ""
|
||||
@echo "Data Generation:"
|
||||
@echo " make vacuum-data-high # High garbage (should trigger)"
|
||||
@echo " make vacuum-data-low # Low garbage (should NOT trigger)"
|
||||
@echo " make vacuum-continuous # Continuous garbage generation"
|
||||
@echo ""
|
||||
@echo "Monitoring:"
|
||||
@echo " make vacuum-status # Quick volume status check"
|
||||
@echo " make vacuum-demo # Full guided demonstration"
|
||||
@echo ""
|
||||
@echo "Configuration:"
|
||||
@echo " Visit: http://localhost:23646/maintenance/config/vacuum"
|
||||
@echo " Monitor: http://localhost:23646/maintenance"
|
||||
@echo ""
|
||||
@echo "Custom Parameters:"
|
||||
@echo " make vacuum-data FILES=50 DELETE=0.8 SIZE=200"
|
||||
@echo ""
|
||||
@echo "💡 All commands now run inside Docker containers"
|
||||
@echo "Documentation:"
|
||||
@echo " See: VACUUM_TEST_README.md for complete guide"
|
||||
32
docker/admin_integration/check_volumes.sh
Executable file
32
docker/admin_integration/check_volumes.sh
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "📊 Quick Volume Status Check"
|
||||
echo "============================"
|
||||
echo ""
|
||||
|
||||
# Check if master is running
|
||||
MASTER_URL="${MASTER_HOST:-master:9333}"
|
||||
if ! curl -s http://$MASTER_URL/cluster/status > /dev/null; then
|
||||
echo "❌ Master server not available at $MASTER_URL"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🔍 Fetching volume status from master..."
|
||||
curl -s "http://$MASTER_URL/vol/status" | jq -r '
|
||||
if .Volumes and .Volumes.DataCenters then
|
||||
.Volumes.DataCenters | to_entries[] | .value | to_entries[] | .value | to_entries[] | .value | if . then .[] else empty end |
|
||||
"Volume \(.Id):
|
||||
Size: \(.Size | if . < 1024 then "\(.) B" elif . < 1048576 then "\(. / 1024 | floor) KB" elif . < 1073741824 then "\(. / 1048576 * 100 | floor / 100) MB" else "\(. / 1073741824 * 100 | floor / 100) GB" end)
|
||||
Files: \(.FileCount) active, \(.DeleteCount) deleted
|
||||
Garbage: \(.DeletedByteCount | if . < 1024 then "\(.) B" elif . < 1048576 then "\(. / 1024 | floor) KB" elif . < 1073741824 then "\(. / 1048576 * 100 | floor / 100) MB" else "\(. / 1073741824 * 100 | floor / 100) GB" end) (\(if .Size > 0 then (.DeletedByteCount / .Size * 100 | floor) else 0 end)%)
|
||||
Status: \(if (.DeletedByteCount / .Size * 100) > 30 then "🎯 NEEDS VACUUM" else "✅ OK" end)
|
||||
"
|
||||
else
|
||||
"No volumes found"
|
||||
end'
|
||||
|
||||
echo ""
|
||||
echo "💡 Legend:"
|
||||
echo " 🎯 NEEDS VACUUM: >30% garbage ratio"
|
||||
echo " ✅ OK: <30% garbage ratio"
|
||||
echo ""
|
||||
280
docker/admin_integration/create_vacuum_test_data.go
Normal file
280
docker/admin_integration/create_vacuum_test_data.go
Normal file
@@ -0,0 +1,280 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
master = flag.String("master", "master:9333", "SeaweedFS master server address")
|
||||
fileCount = flag.Int("files", 20, "Number of files to create")
|
||||
deleteRatio = flag.Float64("delete", 0.4, "Ratio of files to delete (0.0-1.0)")
|
||||
fileSizeKB = flag.Int("size", 100, "Size of each file in KB")
|
||||
)
|
||||
|
||||
type AssignResult struct {
|
||||
Fid string `json:"fid"`
|
||||
Url string `json:"url"`
|
||||
PublicUrl string `json:"publicUrl"`
|
||||
Count int `json:"count"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
fmt.Println("🧪 Creating fake data for vacuum task testing...")
|
||||
fmt.Printf("Master: %s\n", *master)
|
||||
fmt.Printf("Files to create: %d\n", *fileCount)
|
||||
fmt.Printf("Delete ratio: %.1f%%\n", *deleteRatio*100)
|
||||
fmt.Printf("File size: %d KB\n", *fileSizeKB)
|
||||
fmt.Println()
|
||||
|
||||
if *fileCount == 0 {
|
||||
// Just check volume status
|
||||
fmt.Println("📊 Checking volume status...")
|
||||
checkVolumeStatus()
|
||||
return
|
||||
}
|
||||
|
||||
// Step 1: Create test files
|
||||
fmt.Println("📁 Step 1: Creating test files...")
|
||||
fids := createTestFiles()
|
||||
|
||||
// Step 2: Delete some files to create garbage
|
||||
fmt.Println("🗑️ Step 2: Deleting files to create garbage...")
|
||||
deleteFiles(fids)
|
||||
|
||||
// Step 3: Check volume status
|
||||
fmt.Println("📊 Step 3: Checking volume status...")
|
||||
checkVolumeStatus()
|
||||
|
||||
// Step 4: Configure vacuum for testing
|
||||
fmt.Println("⚙️ Step 4: Instructions for testing...")
|
||||
printTestingInstructions()
|
||||
}
|
||||
|
||||
func createTestFiles() []string {
|
||||
var fids []string
|
||||
|
||||
for i := 0; i < *fileCount; i++ {
|
||||
// Generate random file content
|
||||
fileData := make([]byte, *fileSizeKB*1024)
|
||||
rand.Read(fileData)
|
||||
|
||||
// Get file ID assignment
|
||||
assign, err := assignFileId()
|
||||
if err != nil {
|
||||
log.Printf("Failed to assign file ID for file %d: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Upload file
|
||||
err = uploadFile(assign, fileData, fmt.Sprintf("test_file_%d.dat", i))
|
||||
if err != nil {
|
||||
log.Printf("Failed to upload file %d: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
fids = append(fids, assign.Fid)
|
||||
|
||||
if (i+1)%5 == 0 {
|
||||
fmt.Printf(" Created %d/%d files...\n", i+1, *fileCount)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("✅ Created %d files successfully\n\n", len(fids))
|
||||
return fids
|
||||
}
|
||||
|
||||
func deleteFiles(fids []string) {
|
||||
deleteCount := int(float64(len(fids)) * *deleteRatio)
|
||||
|
||||
for i := 0; i < deleteCount; i++ {
|
||||
err := deleteFile(fids[i])
|
||||
if err != nil {
|
||||
log.Printf("Failed to delete file %s: %v", fids[i], err)
|
||||
continue
|
||||
}
|
||||
|
||||
if (i+1)%5 == 0 {
|
||||
fmt.Printf(" Deleted %d/%d files...\n", i+1, deleteCount)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("✅ Deleted %d files (%.1f%% of total)\n\n", deleteCount, *deleteRatio*100)
|
||||
}
|
||||
|
||||
func assignFileId() (*AssignResult, error) {
|
||||
resp, err := http.Get(fmt.Sprintf("http://%s/dir/assign", *master))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result AssignResult
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.Error != "" {
|
||||
return nil, fmt.Errorf("assignment error: %s", result.Error)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func uploadFile(assign *AssignResult, data []byte, filename string) error {
|
||||
url := fmt.Sprintf("http://%s/%s", assign.Url, assign.Fid)
|
||||
|
||||
body := &bytes.Buffer{}
|
||||
body.Write(data)
|
||||
|
||||
req, err := http.NewRequest("POST", url, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/octet-stream")
|
||||
if filename != "" {
|
||||
req.Header.Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 30 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
return fmt.Errorf("upload failed with status %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteFile(fid string) error {
|
||||
url := fmt.Sprintf("http://%s/%s", *master, fid)
|
||||
|
||||
req, err := http.NewRequest("DELETE", url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 10 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkVolumeStatus() {
|
||||
// Get volume list from master
|
||||
resp, err := http.Get(fmt.Sprintf("http://%s/vol/status", *master))
|
||||
if err != nil {
|
||||
log.Printf("Failed to get volume status: %v", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var volumes map[string]interface{}
|
||||
err = json.NewDecoder(resp.Body).Decode(&volumes)
|
||||
if err != nil {
|
||||
log.Printf("Failed to decode volume status: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("📊 Volume Status Summary:")
|
||||
|
||||
if vols, ok := volumes["Volumes"].([]interface{}); ok {
|
||||
for _, vol := range vols {
|
||||
if v, ok := vol.(map[string]interface{}); ok {
|
||||
id := int(v["Id"].(float64))
|
||||
size := uint64(v["Size"].(float64))
|
||||
fileCount := int(v["FileCount"].(float64))
|
||||
deleteCount := int(v["DeleteCount"].(float64))
|
||||
deletedBytes := uint64(v["DeletedByteCount"].(float64))
|
||||
|
||||
garbageRatio := 0.0
|
||||
if size > 0 {
|
||||
garbageRatio = float64(deletedBytes) / float64(size) * 100
|
||||
}
|
||||
|
||||
fmt.Printf(" Volume %d:\n", id)
|
||||
fmt.Printf(" Size: %s\n", formatBytes(size))
|
||||
fmt.Printf(" Files: %d (active), %d (deleted)\n", fileCount, deleteCount)
|
||||
fmt.Printf(" Garbage: %s (%.1f%%)\n", formatBytes(deletedBytes), garbageRatio)
|
||||
|
||||
if garbageRatio > 30 {
|
||||
fmt.Printf(" 🎯 This volume should trigger vacuum (>30%% garbage)\n")
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func formatBytes(bytes uint64) string {
|
||||
if bytes < 1024 {
|
||||
return fmt.Sprintf("%d B", bytes)
|
||||
} else if bytes < 1024*1024 {
|
||||
return fmt.Sprintf("%.1f KB", float64(bytes)/1024)
|
||||
} else if bytes < 1024*1024*1024 {
|
||||
return fmt.Sprintf("%.1f MB", float64(bytes)/(1024*1024))
|
||||
} else {
|
||||
return fmt.Sprintf("%.1f GB", float64(bytes)/(1024*1024*1024))
|
||||
}
|
||||
}
|
||||
|
||||
func printTestingInstructions() {
|
||||
fmt.Println("🧪 Testing Instructions:")
|
||||
fmt.Println()
|
||||
fmt.Println("1. Configure Vacuum for Testing:")
|
||||
fmt.Println(" Visit: http://localhost:23646/maintenance/config/vacuum")
|
||||
fmt.Println(" Set:")
|
||||
fmt.Printf(" - Garbage Percentage Threshold: 20 (20%% - lower than default 30)\n")
|
||||
fmt.Printf(" - Scan Interval: [30] [Seconds] (faster than default)\n")
|
||||
fmt.Printf(" - Min Volume Age: [0] [Minutes] (no age requirement)\n")
|
||||
fmt.Printf(" - Max Concurrent: 2\n")
|
||||
fmt.Printf(" - Min Interval: 1m (faster repeat)\n")
|
||||
fmt.Println()
|
||||
|
||||
fmt.Println("2. Monitor Vacuum Tasks:")
|
||||
fmt.Println(" Visit: http://localhost:23646/maintenance")
|
||||
fmt.Println(" Watch for vacuum tasks to appear in the queue")
|
||||
fmt.Println()
|
||||
|
||||
fmt.Println("3. Manual Vacuum (Optional):")
|
||||
fmt.Println(" curl -X POST 'http://localhost:9333/vol/vacuum?garbageThreshold=0.20'")
|
||||
fmt.Println(" (Note: Master API still uses 0.0-1.0 decimal format)")
|
||||
fmt.Println()
|
||||
|
||||
fmt.Println("4. Check Logs:")
|
||||
fmt.Println(" Look for messages like:")
|
||||
fmt.Println(" - 'Vacuum detector found X volumes needing vacuum'")
|
||||
fmt.Println(" - 'Applied vacuum configuration'")
|
||||
fmt.Println(" - 'Worker executing task: vacuum'")
|
||||
fmt.Println()
|
||||
|
||||
fmt.Println("5. Verify Results:")
|
||||
fmt.Println(" Re-run this script with -files=0 to check volume status")
|
||||
fmt.Println(" Garbage ratios should decrease after vacuum operations")
|
||||
fmt.Println()
|
||||
|
||||
fmt.Printf("🚀 Quick test command:\n")
|
||||
fmt.Printf(" go run create_vacuum_test_data.go -files=0\n")
|
||||
fmt.Println()
|
||||
}
|
||||
105
docker/admin_integration/demo_vacuum_testing.sh
Executable file
105
docker/admin_integration/demo_vacuum_testing.sh
Executable file
@@ -0,0 +1,105 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "🧪 SeaweedFS Vacuum Task Testing Demo"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
# Check if SeaweedFS is running
|
||||
echo "📋 Checking SeaweedFS status..."
|
||||
MASTER_URL="${MASTER_HOST:-master:9333}"
|
||||
ADMIN_URL="${ADMIN_HOST:-admin:23646}"
|
||||
|
||||
if ! curl -s http://$MASTER_URL/cluster/status > /dev/null; then
|
||||
echo "❌ SeaweedFS master not running at $MASTER_URL"
|
||||
echo " Please ensure Docker cluster is running: make start"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! curl -s http://volume1:8080/status > /dev/null; then
|
||||
echo "❌ SeaweedFS volume servers not running"
|
||||
echo " Please ensure Docker cluster is running: make start"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! curl -s http://$ADMIN_URL/ > /dev/null; then
|
||||
echo "❌ SeaweedFS admin server not running at $ADMIN_URL"
|
||||
echo " Please ensure Docker cluster is running: make start"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ All SeaweedFS components are running"
|
||||
echo ""
|
||||
|
||||
# Phase 1: Create test data
|
||||
echo "📁 Phase 1: Creating test data with garbage..."
|
||||
go run create_vacuum_test_data.go -master=$MASTER_URL -files=15 -delete=0.5 -size=150
|
||||
echo ""
|
||||
|
||||
# Phase 2: Check initial status
|
||||
echo "📊 Phase 2: Checking initial volume status..."
|
||||
go run create_vacuum_test_data.go -master=$MASTER_URL -files=0
|
||||
echo ""
|
||||
|
||||
# Phase 3: Configure vacuum
|
||||
echo "⚙️ Phase 3: Vacuum configuration instructions..."
|
||||
echo " 1. Visit: http://localhost:23646/maintenance/config/vacuum"
|
||||
echo " 2. Set these values for testing:"
|
||||
echo " - Enable Vacuum Tasks: ✅ Checked"
|
||||
echo " - Garbage Threshold: 0.30"
|
||||
echo " - Scan Interval: [30] [Seconds]"
|
||||
echo " - Min Volume Age: [0] [Minutes]"
|
||||
echo " - Max Concurrent: 2"
|
||||
echo " 3. Click 'Save Configuration'"
|
||||
echo ""
|
||||
|
||||
read -p " Press ENTER after configuring vacuum settings..."
|
||||
echo ""
|
||||
|
||||
# Phase 4: Monitor tasks
|
||||
echo "🎯 Phase 4: Monitoring vacuum tasks..."
|
||||
echo " Visit: http://localhost:23646/maintenance"
|
||||
echo " You should see vacuum tasks appear within 30 seconds"
|
||||
echo ""
|
||||
|
||||
echo " Waiting 60 seconds for vacuum detection and execution..."
|
||||
for i in {60..1}; do
|
||||
printf "\r Countdown: %02d seconds" $i
|
||||
sleep 1
|
||||
done
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
# Phase 5: Check results
|
||||
echo "📈 Phase 5: Checking results after vacuum..."
|
||||
go run create_vacuum_test_data.go -master=$MASTER_URL -files=0
|
||||
echo ""
|
||||
|
||||
# Phase 6: Create more garbage for continuous testing
|
||||
echo "🔄 Phase 6: Creating additional garbage for continuous testing..."
|
||||
echo " Running 3 rounds of garbage creation..."
|
||||
|
||||
for round in {1..3}; do
|
||||
echo " Round $round: Creating garbage..."
|
||||
go run create_vacuum_test_data.go -master=$MASTER_URL -files=8 -delete=0.6 -size=100
|
||||
echo " Waiting 30 seconds before next round..."
|
||||
sleep 30
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "📊 Final volume status:"
|
||||
go run create_vacuum_test_data.go -master=$MASTER_URL -files=0
|
||||
echo ""
|
||||
|
||||
echo "🎉 Demo Complete!"
|
||||
echo ""
|
||||
echo "🔍 Things to check:"
|
||||
echo " 1. Maintenance Queue: http://localhost:23646/maintenance"
|
||||
echo " 2. Volume Status: http://localhost:9333/vol/status"
|
||||
echo " 3. Admin Dashboard: http://localhost:23646"
|
||||
echo ""
|
||||
echo "💡 Next Steps:"
|
||||
echo " - Try different garbage thresholds (0.10, 0.50, 0.80)"
|
||||
echo " - Adjust scan intervals (10s, 1m, 5m)"
|
||||
echo " - Monitor logs for vacuum operations"
|
||||
echo " - Test with multiple volumes"
|
||||
echo ""
|
||||
240
docker/admin_integration/docker-compose-ec-test.yml
Normal file
240
docker/admin_integration/docker-compose-ec-test.yml
Normal file
@@ -0,0 +1,240 @@
|
||||
name: admin_integration
|
||||
|
||||
networks:
|
||||
seaweed_net:
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
master:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- "9333:9333"
|
||||
- "19333:19333"
|
||||
command: "master -ip=master -mdir=/data -volumeSizeLimitMB=50"
|
||||
environment:
|
||||
- WEED_MASTER_VOLUME_GROWTH_COPY_1=1
|
||||
- WEED_MASTER_VOLUME_GROWTH_COPY_2=2
|
||||
- WEED_MASTER_VOLUME_GROWTH_COPY_OTHER=1
|
||||
volumes:
|
||||
- ./data/master:/data
|
||||
networks:
|
||||
- seaweed_net
|
||||
|
||||
volume1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- "8080:8080"
|
||||
- "18080:18080"
|
||||
command: "volume -master=master:9333 -ip=volume1 -dir=/data -max=10"
|
||||
depends_on:
|
||||
- master
|
||||
volumes:
|
||||
- ./data/volume1:/data
|
||||
networks:
|
||||
- seaweed_net
|
||||
|
||||
volume2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- "8081:8080"
|
||||
- "18081:18080"
|
||||
command: "volume -master=master:9333 -ip=volume2 -dir=/data -max=10"
|
||||
depends_on:
|
||||
- master
|
||||
volumes:
|
||||
- ./data/volume2:/data
|
||||
networks:
|
||||
- seaweed_net
|
||||
|
||||
volume3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- "8082:8080"
|
||||
- "18082:18080"
|
||||
command: "volume -master=master:9333 -ip=volume3 -dir=/data -max=10"
|
||||
depends_on:
|
||||
- master
|
||||
volumes:
|
||||
- ./data/volume3:/data
|
||||
networks:
|
||||
- seaweed_net
|
||||
|
||||
volume4:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- "8083:8080"
|
||||
- "18083:18080"
|
||||
command: "volume -master=master:9333 -ip=volume4 -dir=/data -max=10"
|
||||
depends_on:
|
||||
- master
|
||||
volumes:
|
||||
- ./data/volume4:/data
|
||||
networks:
|
||||
- seaweed_net
|
||||
|
||||
volume5:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- "8084:8080"
|
||||
- "18084:18080"
|
||||
command: "volume -master=master:9333 -ip=volume5 -dir=/data -max=10"
|
||||
depends_on:
|
||||
- master
|
||||
volumes:
|
||||
- ./data/volume5:/data
|
||||
networks:
|
||||
- seaweed_net
|
||||
|
||||
volume6:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- "8085:8080"
|
||||
- "18085:18080"
|
||||
command: "volume -master=master:9333 -ip=volume6 -dir=/data -max=10"
|
||||
depends_on:
|
||||
- master
|
||||
volumes:
|
||||
- ./data/volume6:/data
|
||||
networks:
|
||||
- seaweed_net
|
||||
|
||||
filer:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- "8888:8888"
|
||||
- "18888:18888"
|
||||
command: "filer -master=master:9333 -ip=filer"
|
||||
depends_on:
|
||||
- master
|
||||
volumes:
|
||||
- ./data/filer:/data
|
||||
networks:
|
||||
- seaweed_net
|
||||
|
||||
admin:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- "23646:23646" # HTTP admin interface (default port)
|
||||
- "33646:33646" # gRPC worker communication (23646 + 10000)
|
||||
command: "-v=2 admin -port=23646 -masters=master:9333 -dataDir=/data"
|
||||
depends_on:
|
||||
- master
|
||||
- filer
|
||||
volumes:
|
||||
- ./data/admin:/data
|
||||
networks:
|
||||
- seaweed_net
|
||||
|
||||
worker1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
command: "-v=2 worker -admin=admin:23646 -capabilities=erasure_coding,vacuum -maxConcurrent=2"
|
||||
depends_on:
|
||||
- admin
|
||||
volumes:
|
||||
- ./data/worker1:/data
|
||||
networks:
|
||||
- seaweed_net
|
||||
environment:
|
||||
- WORKER_ID=worker-1
|
||||
|
||||
worker2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
command: "-v=2 worker -admin=admin:23646 -capabilities=erasure_coding,vacuum -maxConcurrent=2"
|
||||
depends_on:
|
||||
- admin
|
||||
volumes:
|
||||
- ./data/worker2:/data
|
||||
networks:
|
||||
- seaweed_net
|
||||
environment:
|
||||
- WORKER_ID=worker-2
|
||||
|
||||
worker3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
command: "-v=2 worker -admin=admin:23646 -capabilities=erasure_coding,vacuum -maxConcurrent=2"
|
||||
depends_on:
|
||||
- admin
|
||||
volumes:
|
||||
- ./data/worker3:/data
|
||||
networks:
|
||||
- seaweed_net
|
||||
environment:
|
||||
- WORKER_ID=worker-3
|
||||
|
||||
load_generator:
|
||||
image: chrislusf/seaweedfs:local
|
||||
entrypoint: ["/bin/sh"]
|
||||
command: >
|
||||
-c "
|
||||
echo 'Starting load generator...';
|
||||
sleep 30;
|
||||
echo 'Generating continuous load with 50MB volume limit...';
|
||||
while true; do
|
||||
echo 'Writing test files...';
|
||||
echo 'Test file content at $(date)' | /usr/bin/weed upload -server=master:9333;
|
||||
sleep 5;
|
||||
echo 'Deleting some files...';
|
||||
/usr/bin/weed shell -master=master:9333 <<< 'fs.rm /test_file_*' || true;
|
||||
sleep 10;
|
||||
done
|
||||
"
|
||||
depends_on:
|
||||
- master
|
||||
- filer
|
||||
- admin
|
||||
networks:
|
||||
- seaweed_net
|
||||
|
||||
monitor:
|
||||
image: alpine:latest
|
||||
entrypoint: ["/bin/sh"]
|
||||
command: >
|
||||
-c "
|
||||
apk add --no-cache curl jq;
|
||||
echo 'Starting cluster monitor...';
|
||||
sleep 30;
|
||||
while true; do
|
||||
echo '=== Cluster Status $(date) ===';
|
||||
echo 'Master status:';
|
||||
curl -s http://master:9333/cluster/status | jq '.IsLeader, .Peers' || echo 'Master not ready';
|
||||
echo;
|
||||
echo 'Admin status:';
|
||||
curl -s http://admin:23646/ | grep -o 'Admin.*Interface' || echo 'Admin not ready';
|
||||
echo;
|
||||
echo 'Volume count by server:';
|
||||
curl -s http://master:9333/vol/status | jq '.Volumes | length' || echo 'Volumes not ready';
|
||||
echo;
|
||||
sleep 60;
|
||||
done
|
||||
"
|
||||
depends_on:
|
||||
- master
|
||||
- admin
|
||||
- filer
|
||||
networks:
|
||||
- seaweed_net
|
||||
|
||||
vacuum-tester:
|
||||
image: chrislusf/seaweedfs:local
|
||||
entrypoint: ["/bin/sh"]
|
||||
command: >
|
||||
-c "
|
||||
echo 'Installing dependencies for vacuum testing...';
|
||||
apk add --no-cache jq curl go bash;
|
||||
echo 'Vacuum tester ready...';
|
||||
echo 'Use: docker-compose exec vacuum-tester sh';
|
||||
echo 'Available commands: go, weed, curl, jq, bash, sh';
|
||||
sleep infinity
|
||||
"
|
||||
depends_on:
|
||||
- master
|
||||
- admin
|
||||
- filer
|
||||
volumes:
|
||||
- .:/testing
|
||||
working_dir: /testing
|
||||
networks:
|
||||
- seaweed_net
|
||||
environment:
|
||||
- MASTER_HOST=master:9333
|
||||
- ADMIN_HOST=admin:23646
|
||||
73
docker/admin_integration/test-integration.sh
Executable file
73
docker/admin_integration/test-integration.sh
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
echo "🧪 Testing SeaweedFS Admin-Worker Integration"
|
||||
echo "============================================="
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
echo -e "${BLUE}1. Validating docker-compose configuration...${NC}"
|
||||
if docker-compose -f docker-compose-ec-test.yml config > /dev/null; then
|
||||
echo -e "${GREEN}✅ Docker compose configuration is valid${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ Docker compose configuration is invalid${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}2. Checking if required ports are available...${NC}"
|
||||
for port in 9333 8080 8081 8082 8083 8084 8085 8888 23646; do
|
||||
if lsof -i :$port > /dev/null 2>&1; then
|
||||
echo -e "${YELLOW}⚠️ Port $port is in use${NC}"
|
||||
else
|
||||
echo -e "${GREEN}✅ Port $port is available${NC}"
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "${BLUE}3. Testing worker command syntax...${NC}"
|
||||
# Test that the worker command in docker-compose has correct syntax
|
||||
if docker-compose -f docker-compose-ec-test.yml config | grep -q "workingDir=/work"; then
|
||||
echo -e "${GREEN}✅ Worker working directory option is properly configured${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ Worker working directory option is missing${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}4. Verifying admin server configuration...${NC}"
|
||||
if docker-compose -f docker-compose-ec-test.yml config | grep -q "admin:23646"; then
|
||||
echo -e "${GREEN}✅ Admin server port configuration is correct${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ Admin server port configuration is incorrect${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}5. Checking service dependencies...${NC}"
|
||||
if docker-compose -f docker-compose-ec-test.yml config | grep -q "depends_on"; then
|
||||
echo -e "${GREEN}✅ Service dependencies are configured${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ Service dependencies may not be configured${NC}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}🎉 Integration test configuration is ready!${NC}"
|
||||
echo ""
|
||||
echo -e "${BLUE}To start the integration test:${NC}"
|
||||
echo " make start # Start all services"
|
||||
echo " make health # Check service health"
|
||||
echo " make logs # View logs"
|
||||
echo " make stop # Stop all services"
|
||||
echo ""
|
||||
echo -e "${BLUE}Key features verified:${NC}"
|
||||
echo " ✅ Official SeaweedFS images are used"
|
||||
echo " ✅ Worker working directories are configured"
|
||||
echo " ✅ Admin-worker communication on correct ports"
|
||||
echo " ✅ Task-specific directories will be created"
|
||||
echo " ✅ Load generator will trigger EC tasks"
|
||||
echo " ✅ Monitor will track progress"
|
||||
25
docker/apt-install
Executable file
25
docker/apt-install
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
# Install packages, falling through to the next Ubuntu mirror when one is
|
||||
# unreachable. See docker/Dockerfile.e2e.
|
||||
set -e
|
||||
|
||||
# Every rewrite starts from the pristine list, so a mirror that just failed does
|
||||
# not become the pattern the next rewrite has to match.
|
||||
[ -f /etc/apt/sources.list.orig ] || cp /etc/apt/sources.list /etc/apt/sources.list.orig
|
||||
|
||||
for mirror in azure.archive.ubuntu.com archive.ubuntu.com; do
|
||||
# Any archive host, so this works whether the pristine list came from the
|
||||
# base image (archive.ubuntu.com) or a CI runner (azure.archive.ubuntu.com).
|
||||
sed "s|http://[a-z0-9.]*archive\.ubuntu\.com/ubuntu|http://$mirror/ubuntu|g; s|http://security\.ubuntu\.com/ubuntu|http://$mirror/ubuntu|g" \
|
||||
/etc/apt/sources.list.orig > /etc/apt/sources.list
|
||||
if apt-get -o Acquire::Retries=3 -o Acquire::http::Timeout=15 update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get -o Acquire::Retries=3 -o Acquire::http::Timeout=15 install -y \
|
||||
--no-install-recommends --no-install-suggests "$@"; then
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
exit 0
|
||||
fi
|
||||
echo "apt: $mirror unreachable, trying the next mirror" >&2
|
||||
done
|
||||
|
||||
exit 1
|
||||
0
docker/compose/dev.env
Normal file
0
docker/compose/dev.env
Normal file
61
docker/compose/e2e-mount.yml
Normal file
61
docker/compose/e2e-mount.yml
Normal file
@@ -0,0 +1,61 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
master:
|
||||
image: chrislusf/seaweedfs:e2e
|
||||
command: "-v=4 master -ip=master -ip.bind=0.0.0.0 -raftBootstrap"
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "--fail", "-I", "http://localhost:9333/cluster/healthz" ]
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 30
|
||||
start_period: 10s
|
||||
|
||||
volume:
|
||||
image: chrislusf/seaweedfs:e2e
|
||||
command: "-v=4 volume -master=master:9333 -ip=volume -ip.bind=0.0.0.0 -preStopSeconds=1"
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "--fail", "-I", "http://localhost:8080/healthz" ]
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 15
|
||||
start_period: 5s
|
||||
depends_on:
|
||||
master:
|
||||
condition: service_healthy
|
||||
|
||||
filer:
|
||||
image: chrislusf/seaweedfs:e2e
|
||||
command: "-v=4 filer -master=master:9333 -ip=filer -ip.bind=0.0.0.0"
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "--fail", "-I", "http://localhost:8888" ]
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 15
|
||||
start_period: 5s
|
||||
depends_on:
|
||||
volume:
|
||||
condition: service_healthy
|
||||
|
||||
mount:
|
||||
image: chrislusf/seaweedfs:e2e
|
||||
command: "-v=4 mount -filer=filer:8888 -filer.path=/ -dirAutoCreate -dir=/mnt/seaweedfs"
|
||||
cap_add:
|
||||
- SYS_ADMIN
|
||||
devices:
|
||||
- /dev/fuse
|
||||
security_opt:
|
||||
- apparmor:unconfined
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 4096m
|
||||
healthcheck:
|
||||
test: [ "CMD", "mountpoint", "-q", "--", "/mnt/seaweedfs" ]
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 15
|
||||
start_period: 10s
|
||||
depends_on:
|
||||
filer:
|
||||
condition: service_healthy
|
||||
8
docker/compose/fluent.conf
Normal file
8
docker/compose/fluent.conf
Normal file
@@ -0,0 +1,8 @@
|
||||
<source>
|
||||
@type forward
|
||||
port 24224
|
||||
</source>
|
||||
|
||||
<match **>
|
||||
@type stdout # Output logs to container's stdout (visible via `docker logs`)
|
||||
</match>
|
||||
4
docker/compose/fluent.json
Normal file
4
docker/compose/fluent.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"fluent_port": 24224,
|
||||
"fluent_host": "fluent"
|
||||
}
|
||||
38
docker/compose/local-auditlog-compose.yml
Normal file
38
docker/compose/local-auditlog-compose.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
s3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8333:8333
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
- 8084:8080
|
||||
- 18084:18080
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
- 8000:8000
|
||||
command: "server -ip=s3 -filer -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8000 -s3.auditLogConfig=/etc/seaweedfs/fluent.json -volume.max=0 -master.volumeSizeLimitMB=8 -volume.preStopSeconds=1"
|
||||
volumes:
|
||||
- ./fluent.json:/etc/seaweedfs/fluent.json
|
||||
- ./s3.json:/etc/seaweedfs/s3.json
|
||||
depends_on:
|
||||
- fluent
|
||||
fluent:
|
||||
image: fluent/fluentd:v1.17
|
||||
volumes:
|
||||
- ./fluent.conf:/fluentd/etc/fluent.conf
|
||||
ports:
|
||||
- 24224:24224
|
||||
#s3tests:
|
||||
# image: chrislusf/ceph-s3-tests:local
|
||||
# volumes:
|
||||
# - ./s3tests.conf:/opt/s3-tests/s3tests.conf
|
||||
# environment:
|
||||
# S3TEST_CONF: "s3tests.conf"
|
||||
# NOSETESTS_OPTIONS: "--verbose --logging-level=ERROR --with-xunit --failure-detail s3tests_boto3.functional.test_s3"
|
||||
# NOSETESTS_ATTR: "!tagging,!fails_on_aws,!encryption,!bucket-policy,!versioning,!fails_on_rgw,!bucket-policy,!fails_with_subdomain,!policy_status,!object-lock,!lifecycle,!cors,!user-policy"
|
||||
# NOSETESTS_EXCLUDE: "(get_bucket_encryption|put_bucket_encryption|bucket_list_delimiter_basic|bucket_listv2_delimiter_basic|bucket_listv2_encoding_basic|bucket_list_encoding_basic|bucket_list_delimiter_prefix|bucket_listv2_delimiter_prefix_ends_with_delimiter|bucket_list_delimiter_prefix_ends_with_delimiter|bucket_list_delimiter_alt|bucket_listv2_delimiter_alt|bucket_list_delimiter_prefix_underscore|bucket_list_delimiter_percentage|bucket_listv2_delimiter_percentage|bucket_list_delimiter_whitespace|bucket_listv2_delimiter_whitespace|bucket_list_delimiter_dot|bucket_listv2_delimiter_dot|bucket_list_delimiter_unreadable|bucket_listv2_delimiter_unreadable|bucket_listv2_fetchowner_defaultempty|bucket_listv2_fetchowner_empty|bucket_list_prefix_delimiter_alt|bucket_listv2_prefix_delimiter_alt|bucket_list_prefix_delimiter_prefix_not_exist|bucket_listv2_prefix_delimiter_prefix_not_exist|bucket_list_prefix_delimiter_delimiter_not_exist|bucket_listv2_prefix_delimiter_delimiter_not_exist|bucket_list_prefix_delimiter_prefix_delimiter_not_exist|bucket_listv2_prefix_delimiter_prefix_delimiter_not_exist|bucket_list_maxkeys_none|bucket_listv2_maxkeys_none|bucket_list_maxkeys_invalid|bucket_listv2_continuationtoken_empty|bucket_list_return_data|bucket_list_objects_anonymous|bucket_listv2_objects_anonymous|bucket_notexist|bucketv2_notexist|bucket_delete_nonempty|bucket_concurrent_set_canned_acl|object_write_to_nonexist_bucket|object_requestid_matches_header_on_error|object_set_get_metadata_none_to_good|object_set_get_metadata_none_to_empty|object_set_get_metadata_overwrite_to_empty|post_object_anonymous_request|post_object_authenticated_request|post_object_authenticated_no_content_type|post_object_authenticated_request_bad_access_key|post_object_set_success_code|post_object_set_invalid_success_code|post_object_upload_larger_than_chunk|post_object_set_key_from_filename|post_object_ignored_header|post_object_case_insensitive_condition_fields|post_object_escaped_field_values|post_object_success_redirect_action|post_object_invalid_signature|post_object_invalid_access_key|post_object_missing_policy_condition|post_object_user_specified_header|post_object_request_missing_policy_specified_field|post_object_expired_policy|post_object_invalid_request_field_value|get_object_ifunmodifiedsince_good|put_object_ifmatch_failed|object_raw_get_bucket_gone|object_delete_key_bucket_gone|object_raw_get_bucket_acl|object_raw_get_object_acl|object_raw_response_headers|object_raw_authenticated_bucket_gone|object_raw_get_x_amz_expires_out_max_range|object_raw_get_x_amz_expires_out_positive_range|object_anon_put_write_access|object_raw_put_authenticated_expired|bucket_create_exists|bucket_create_naming_bad_short_one|bucket_create_naming_bad_short_two|bucket_get_location|bucket_acl_default|bucket_acl_canned|bucket_acl_canned_publicreadwrite|bucket_acl_canned_authenticatedread|object_acl_default|object_acl_canned_during_create|object_acl_canned|object_acl_canned_publicreadwrite|object_acl_canned_authenticatedread|object_acl_canned_bucketownerread|object_acl_canned_bucketownerfullcontrol|object_acl_full_control_verify_attributes|bucket_acl_canned_private_to_private|bucket_acl_grant_nonexist_user|bucket_acl_no_grants|bucket_acl_grant_email_not_exist|bucket_acl_revoke_all|bucket_recreate_not_overriding|object_copy_verify_contenttype|object_copy_to_itself_with_metadata|object_copy_not_owned_bucket|object_copy_not_owned_object_bucket|object_copy_retaining_metadata|object_copy_replacing_metadata|multipart_upload_empty|multipart_copy_invalid_range|multipart_copy_special_names|multipart_upload_resend_part|multipart_upload_size_too_small|abort_multipart_upload_not_found|multipart_upload_missing_part|multipart_upload_incorrect_etag|100_continue|ranged_request_invalid_range|ranged_request_empty_object|access_bucket)"
|
||||
# depends_on:
|
||||
# - s3
|
||||
# - fluent
|
||||
127
docker/compose/local-brokers-compose.yml
Normal file
127
docker/compose/local-brokers-compose.yml
Normal file
@@ -0,0 +1,127 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
master0:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
command: "-v=0 master -volumeSizeLimitMB 100 -resumeState=false -ip=master0 -port=9333 -peers=master0:9333,master1:9334,master2:9335 -mdir=/tmp"
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 1
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_2: 2
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 1
|
||||
master1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9334:9334
|
||||
- 19334:19334
|
||||
command: "-v=0 master -volumeSizeLimitMB 100 -resumeState=false -ip=master1 -port=9334 -peers=master0:9333,master1:9334,master2:9335 -mdir=/tmp"
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 1
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_2: 2
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 1
|
||||
master2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9335:9335
|
||||
- 19335:19335
|
||||
command: "-v=0 master -volumeSizeLimitMB 100 -resumeState=false -ip=master2 -port=9335 -peers=master0:9333,master1:9334,master2:9335 -mdir=/tmp"
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 1
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_2: 2
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 1
|
||||
volume1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: 'volume -dataCenter=dc1 -rack=v1 -master="master0:9333,master1:9334,master2:9335" -port=8080 -ip=volume1 -publicUrl=localhost:8080 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
volume2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8082:8082
|
||||
- 18082:18082
|
||||
command: 'volume -dataCenter=dc2 -rack=v2 -master="master0:9333,master1:9334,master2:9335" -port=8082 -ip=volume2 -publicUrl=localhost:8082 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
volume3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8083:8083
|
||||
- 18083:18083
|
||||
command: 'volume -dataCenter=dc3 -rack=v3 -master="master0:9333,master1:9334,master2:9335" -port=8083 -ip=volume3 -publicUrl=localhost:8083 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
filer1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
command: 'filer -defaultReplicaPlacement=100 -iam -master="master0:9333,master1:9334,master2:9335" -port=8888 -ip=filer1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
- volume1
|
||||
- volume2
|
||||
filer2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8889:8889
|
||||
- 18889:18889
|
||||
command: 'filer -defaultReplicaPlacement=100 -iam -master="master0:9333,master1:9334,master2:9335" -port=8889 -ip=filer2'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
- volume1
|
||||
- volume2
|
||||
- filer1
|
||||
broker1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 17777:17777
|
||||
command: 'mq.broker -master="master0:9333,master1:9334,master2:9335" -port=17777 -ip=broker1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
- volume1
|
||||
- volume2
|
||||
- filer1
|
||||
- filer2
|
||||
broker2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 17778:17778
|
||||
command: 'mq.broker -master="master0:9333,master1:9334,master2:9335" -port=17778 -ip=broker2'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
- volume1
|
||||
- volume2
|
||||
- filer1
|
||||
- filer2
|
||||
broker3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 17779:17779
|
||||
command: 'mq.broker -master="master0:9333,master1:9334,master2:9335" -port=17779 -ip=broker3'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
- volume1
|
||||
- volume2
|
||||
- filer1
|
||||
- filer2
|
||||
88
docker/compose/local-cluster-compose.yml
Normal file
88
docker/compose/local-cluster-compose.yml
Normal file
@@ -0,0 +1,88 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
master0:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
command: "-v=1 master -volumeSizeLimitMB 100 -resumeState=false -ip=master0 -port=9333 -peers=master0:9333,master1:9334,master2:9335 -mdir=/tmp"
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 1
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_2: 2
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 1
|
||||
master1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9334:9334
|
||||
- 19334:19334
|
||||
command: "-v=1 master -volumeSizeLimitMB 100 -resumeState=false -ip=master1 -port=9334 -peers=master0:9333,master1:9334,master2:9335 -mdir=/tmp"
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 1
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_2: 2
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 1
|
||||
master2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9335:9335
|
||||
- 19335:19335
|
||||
command: "-v=1 master -volumeSizeLimitMB 100 -resumeState=false -ip=master2 -port=9335 -peers=master0:9333,master1:9334,master2:9335 -mdir=/tmp"
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 1
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_2: 2
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 1
|
||||
volume1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: 'volume -dataCenter=dc1 -rack=v1 -master="master0:9333,master1:9334,master2:9335" -port=8080 -ip=volume1 -publicUrl=localhost:8080 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
volume2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8082:8082
|
||||
- 18082:18082
|
||||
command: 'volume -dataCenter=dc2 -rack=v2 -master="master0:9333,master1:9334,master2:9335" -port=8082 -ip=volume2 -publicUrl=localhost:8082 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
volume3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8083:8083
|
||||
- 18083:18083
|
||||
command: 'volume -dataCenter=dc3 -rack=v3 -master="master0:9333,master1:9334,master2:9335" -port=8083 -ip=volume3 -publicUrl=localhost:8083 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
filer:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
- 8111:8111
|
||||
command: 'filer -defaultReplicaPlacement=100 -iam -master="master0:9333,master1:9334,master2:9335"'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
- volume1
|
||||
- volume2
|
||||
s3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8333:8333
|
||||
command: '-v=9 s3 -filer="filer:8888"'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
- volume1
|
||||
- volume2
|
||||
- filer
|
||||
28
docker/compose/local-clusters-compose.yml
Normal file
28
docker/compose/local-clusters-compose.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
server1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
- 8084:8080
|
||||
- 18084:18080
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
command: "server -ip=server1 -filer -volume.max=0 -master.volumeSizeLimitMB=100 -volume.preStopSeconds=1"
|
||||
volumes:
|
||||
- ./master-cloud.toml:/etc/seaweedfs/master.toml
|
||||
depends_on:
|
||||
- server2
|
||||
server2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9334:9333
|
||||
- 19334:19333
|
||||
- 8085:8080
|
||||
- 18085:18080
|
||||
- 8889:8888
|
||||
- 18889:18888
|
||||
- 8334:8333
|
||||
command: "server -ip=server2 -filer -s3 -volume.max=0 -master.volumeSizeLimitMB=100 -volume.preStopSeconds=1"
|
||||
80
docker/compose/local-dev-compose.yml
Normal file
80
docker/compose/local-dev-compose.yml
Normal file
@@ -0,0 +1,80 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
master:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
command: "-v=1 master -ip=master -volumeSizeLimitMB=10"
|
||||
volumes:
|
||||
- ./tls:/etc/seaweedfs/tls
|
||||
env_file:
|
||||
- ${ENV_FILE:-dev.env}
|
||||
volume:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: "-v=1 volume -master=master:9333 -port=8080 -ip=volume -preStopSeconds=1 -max=10000"
|
||||
depends_on:
|
||||
- master
|
||||
volumes:
|
||||
- ./tls:/etc/seaweedfs/tls
|
||||
env_file:
|
||||
- ${ENV_FILE:-dev.env}
|
||||
filer:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
command: '-v=1 filer -ip.bind=0.0.0.0 -master="master:9333"'
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
volumes:
|
||||
- ./tls:/etc/seaweedfs/tls
|
||||
env_file:
|
||||
- ${ENV_FILE:-dev.env}
|
||||
|
||||
iam:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8111:8111
|
||||
command: '-v=1 iam -filer="filer:8888" -master="master:9333"'
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
- filer
|
||||
volumes:
|
||||
- ./tls:/etc/seaweedfs/tls
|
||||
|
||||
s3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8333:8333
|
||||
command: '-v=1 s3 -filer="filer:8888" -ip.bind=s3'
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
- filer
|
||||
volumes:
|
||||
- ./tls:/etc/seaweedfs/tls
|
||||
env_file:
|
||||
- ${ENV_FILE:-dev.env}
|
||||
|
||||
mount:
|
||||
image: chrislusf/seaweedfs:local
|
||||
privileged: true
|
||||
cap_add:
|
||||
- SYS_ADMIN
|
||||
mem_limit: 4096m
|
||||
command: '-v=4 mount -filer="filer:8888" -dirAutoCreate -dir=/mnt/seaweedfs -cacheCapacityMB=100 -concurrentWriters=128'
|
||||
volumes:
|
||||
- ./tls:/etc/seaweedfs/tls
|
||||
env_file:
|
||||
- ${ENV_FILE:-dev.env}
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
- filer
|
||||
54
docker/compose/local-filer-backup-compose.yml
Normal file
54
docker/compose/local-filer-backup-compose.yml
Normal file
@@ -0,0 +1,54 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
server-left:
|
||||
image: chrislusf/seaweedfs:local
|
||||
command: "-v=0 server -ip=server-left -filer -filer.maxMB 5 -s3 -s3.config=/etc/seaweedfs/s3.json -volume.max=0 -master.volumeSizeLimitMB=100 -volume.preStopSeconds=1"
|
||||
volumes:
|
||||
- ./s3.json:/etc/seaweedfs/s3.json
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "--fail", "-I", "http://localhost:9333/cluster/healthz" ]
|
||||
interval: 3s
|
||||
start_period: 15s
|
||||
timeout: 30s
|
||||
server-right:
|
||||
image: chrislusf/seaweedfs:local
|
||||
command: "-v=0 server -ip=server-right -filer -filer.maxMB 64 -s3 -s3.config=/etc/seaweedfs/s3.json -volume.max=0 -master.volumeSizeLimitMB=100 -volume.preStopSeconds=1"
|
||||
volumes:
|
||||
- ./s3.json:/etc/seaweedfs/s3.json
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "--fail", "-I", "http://localhost:9333/cluster/healthz" ]
|
||||
interval: 3s
|
||||
start_period: 15s
|
||||
timeout: 30s
|
||||
filer-backup:
|
||||
image: chrislusf/seaweedfs:local
|
||||
command: "-v=0 filer.backup -debug -doDeleteFiles=False -filer server-left:8888"
|
||||
volumes:
|
||||
- ./replication.toml:/etc/seaweedfs/replication.toml
|
||||
environment:
|
||||
WEED_SINK_LOCAL_INCREMENTAL_ENABLED: "false"
|
||||
WEED_SINK_S3_ENABLED: "true"
|
||||
WEED_SINK_S3_BUCKET: "backup"
|
||||
WEED_SINK_S3_ENDPOINT: "http://server-right:8333"
|
||||
WEED_SINK_S3_DIRECTORY: "/"
|
||||
WEED_SINK_S3_AWS_ACCESS_KEY_ID: "some_access_key1"
|
||||
WEED_SINK_S3_AWS_SECRET_ACCESS_KEY: "some_secret_key1"
|
||||
WEED_SINK_S3_S3_DISABLE_CONTENT_MD5_VALIDATION: "false"
|
||||
WEED_SINK_S3_UPLOADER_PART_SIZE_MB: "5"
|
||||
WEED_SINK_S3_KEEP_PART_SIZE: "false"
|
||||
depends_on:
|
||||
server-left:
|
||||
condition: service_healthy
|
||||
server-right:
|
||||
condition: service_healthy
|
||||
minio-warp:
|
||||
image: minio/warp
|
||||
command: 'mixed --duration 5s --obj.size=6mb --md5 --objects 10 --concurrent 2'
|
||||
restart: on-failure
|
||||
environment:
|
||||
WARP_HOST: "server-left:8333"
|
||||
WARP_ACCESS_KEY: "some_access_key1"
|
||||
WARP_SECRET_KEY: "some_secret_key1"
|
||||
depends_on:
|
||||
- filer-backup
|
||||
89
docker/compose/local-hashicorp-raft-compose.yml
Normal file
89
docker/compose/local-hashicorp-raft-compose.yml
Normal file
@@ -0,0 +1,89 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
master0:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
command: "-v=4 master -volumeSizeLimitMB 100 -raftHashicorp -electionTimeout 1s -ip=master0 -port=9333 -peers=master1:9334,master2:9335 -mdir=/data"
|
||||
volumes:
|
||||
- ./master/0:/data
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 1
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_2: 2
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 1
|
||||
master1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9334:9334
|
||||
- 19334:19334
|
||||
command: "-v=4 master -volumeSizeLimitMB 100 -raftHashicorp -electionTimeout 1s -ip=master1 -port=9334 -peers=master0:9333,master2:9335 -mdir=/data"
|
||||
volumes:
|
||||
- ./master/1:/data
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 1
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_2: 2
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 1
|
||||
master2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9335:9335
|
||||
- 19335:19335
|
||||
command: "-v=4 master -volumeSizeLimitMB 100 -raftHashicorp -electionTimeout 1s -ip=master2 -port=9335 -peers=master0:9333,master1:9334 -mdir=/data"
|
||||
volumes:
|
||||
- ./master/2:/data
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 1
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_2: 2
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 1
|
||||
volume1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: 'volume -dataCenter=dc1 -rack=v1 -master="master0:9333,master1:9334,master2:9335" -port=8080 -ip=volume1 -publicUrl=localhost:8080 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
volume2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8082:8082
|
||||
- 18082:18082
|
||||
command: 'volume -dataCenter=dc2 -rack=v2 -master="master0:9333,master1:9334,master2:9335" -port=8082 -ip=volume2 -publicUrl=localhost:8082 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
volume3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8083:8083
|
||||
- 18083:18083
|
||||
command: 'volume -dataCenter=dc3 -rack=v3 -master="master0:9333,master1:9334,master2:9335" -port=8083 -ip=volume3 -publicUrl=localhost:8083 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
filer:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
- 8111:8111
|
||||
command: 'filer -defaultReplicaPlacement=100 -iam -master="master0:9333,master1:9334,master2:9335"'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- volume1
|
||||
- volume2
|
||||
s3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8333:8333
|
||||
command: '-v=9 s3 -ip.bind="s3" -filer="filer:8888"'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- volume1
|
||||
- volume2
|
||||
- filer
|
||||
94
docker/compose/local-k8s-compose.yml
Normal file
94
docker/compose/local-k8s-compose.yml
Normal file
@@ -0,0 +1,94 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
master:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
command: "master -ip=master"
|
||||
volume:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: "volume -master=master:9333 -port=8080 -ip=volume"
|
||||
depends_on:
|
||||
- master
|
||||
mysql:
|
||||
image: percona/percona-server:5.7
|
||||
ports:
|
||||
- 3306:3306
|
||||
volumes:
|
||||
- ./seaweedfs.sql:/docker-entrypoint-initdb.d/seaweedfs.sql
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=secret
|
||||
- MYSQL_DATABASE=seaweedfs
|
||||
- MYSQL_PASSWORD=secret
|
||||
- MYSQL_USER=seaweedfs
|
||||
filer:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
environment:
|
||||
- WEED_MYSQL_HOSTNAME=mysql
|
||||
- WEED_MYSQL_PORT=3306
|
||||
- WEED_MYSQL_DATABASE=seaweedfs
|
||||
- WEED_MYSQL_USERNAME=seaweedfs
|
||||
- WEED_MYSQL_PASSWORD=secret
|
||||
- WEED_MYSQL_ENABLED=true
|
||||
- WEED_MYSQL_CONNECTION_MAX_IDLE=5
|
||||
- WEED_MYSQL_CONNECTION_MAX_OPEN=75
|
||||
# "refresh" connection every 10 minutes, eliminating mysql closing "old" connections
|
||||
- WEED_MYSQL_CONNECTION_MAX_LIFETIME_SECONDS=600
|
||||
# enable usage of memsql as filer backend
|
||||
- WEED_MYSQL_INTERPOLATEPARAMS=true
|
||||
- WEED_LEVELDB2_ENABLED=false
|
||||
command: '-v 9 filer -master="master:9333"'
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
- mysql
|
||||
ingress:
|
||||
image: jwilder/nginx-proxy:alpine
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./nginx/proxy.conf:/etc/nginx/proxy.conf
|
||||
s3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8333:8333
|
||||
command: '-v 9 s3 -filer="filer:8888"'
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
- filer
|
||||
environment:
|
||||
- VIRTUAL_HOST=ingress
|
||||
- VIRTUAL_PORT=8333
|
||||
registry:
|
||||
image: registry:2
|
||||
environment:
|
||||
REGISTRY_HTTP_ADDR: "0.0.0.0:5001" # seaweedfs s3
|
||||
REGISTRY_LOG_LEVEL: "debug"
|
||||
REGISTRY_STORAGE: "s3"
|
||||
REGISTRY_STORAGE_S3_REGION: "us-east-1"
|
||||
REGISTRY_STORAGE_S3_REGIONENDPOINT: "http://ingress"
|
||||
REGISTRY_STORAGE_S3_BUCKET: "registry"
|
||||
REGISTRY_STORAGE_S3_ACCESSKEY: "some_access_key1"
|
||||
REGISTRY_STORAGE_S3_SECRETKEY: "some_secret_key1"
|
||||
REGISTRY_STORAGE_S3_V4AUTH: "true"
|
||||
REGISTRY_STORAGE_S3_SECURE: "false"
|
||||
REGISTRY_STORAGE_S3_SKIPVERIFY: "true"
|
||||
REGISTRY_STORAGE_S3_ROOTDIRECTORY: "/"
|
||||
REGISTRY_STORAGE_DELETE_ENABLED: "true"
|
||||
REGISTRY_STORAGE_REDIRECT_DISABLE: "true"
|
||||
REGISTRY_VALIDATION_DISABLED: "true"
|
||||
ports:
|
||||
- 5001:5001
|
||||
depends_on:
|
||||
- s3
|
||||
- ingress
|
||||
50
docker/compose/local-minio-gateway-compose.yml
Normal file
50
docker/compose/local-minio-gateway-compose.yml
Normal file
@@ -0,0 +1,50 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
master:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
command: "master -ip=master -volumeSizeLimitMB=100"
|
||||
volume:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: "volume -master=master:9333 -port=8080 -ip=volume -max=0 -preStopSeconds=1"
|
||||
depends_on:
|
||||
- master
|
||||
s3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
- 8333:8333
|
||||
command: '-v 1 filer -master="master:9333" -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8333'
|
||||
volumes:
|
||||
- ./s3.json:/etc/seaweedfs/s3.json
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
minio-gateway-s3:
|
||||
image: minio/minio
|
||||
ports:
|
||||
- 9000:9000
|
||||
command: 'minio gateway s3 http://s3:8333'
|
||||
restart: on-failure
|
||||
environment:
|
||||
MINIO_ACCESS_KEY: "some_access_key1"
|
||||
MINIO_SECRET_KEY: "some_secret_key1"
|
||||
depends_on:
|
||||
- s3
|
||||
minio-warp:
|
||||
image: minio/warp
|
||||
command: 'mixed --duration=5m --obj.size=3mb --autoterm'
|
||||
restart: on-failure
|
||||
environment:
|
||||
WARP_HOST: "minio-gateway-s3:9000"
|
||||
WARP_ACCESS_KEY: "some_access_key1"
|
||||
WARP_SECRET_KEY: "some_secret_key1"
|
||||
depends_on:
|
||||
- minio-gateway-s3
|
||||
46
docker/compose/local-mount-compose.yml
Normal file
46
docker/compose/local-mount-compose.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
master:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
command: "master -ip=master"
|
||||
volume:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 7455:8080
|
||||
- 9325:9325
|
||||
command: 'volume -master="master:9333" -port=8080 -metricsPort=9325 -preStopSeconds=1 -publicUrl=localhost:7455'
|
||||
depends_on:
|
||||
- master
|
||||
filer:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
- 9326:9326
|
||||
command: 'filer -master="master:9333" -metricsPort=9326'
|
||||
tty: true
|
||||
stdin_open: true
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
mount_1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
privileged: true
|
||||
entrypoint: '/bin/sh -c "mkdir -p t1 && mkdir -p cache/t1 && weed -v=4 mount -filer=filer:8888 -cacheDir=./cache/t1 -dir=./t1 -filer.path=/c1 -volumeServerAccess=filerProxy"'
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
- filer
|
||||
mount_2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
privileged: true
|
||||
entrypoint: '/bin/sh -c "mkdir -p t2 && mkdir -p cache/t2 && weed -v=4 mount -filer=filer:8888 -cacheDir=./cache/t2 -dir=./t2 -filer.path=/c1"'
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
- filer
|
||||
- mount_1
|
||||
47
docker/compose/local-mount-profile-compose.yml
Normal file
47
docker/compose/local-mount-profile-compose.yml
Normal file
@@ -0,0 +1,47 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
master:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
command: "master -ip=master"
|
||||
volume:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 7455:8080
|
||||
- 9325:9325
|
||||
volumes:
|
||||
- /Volumes/mobile_disk/99:/data
|
||||
command: 'volume -master="master:9333" -port=8080 -metricsPort=9325 -preStopSeconds=1 -publicUrl=localhost:7455'
|
||||
depends_on:
|
||||
- master
|
||||
filer:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
- 9326:9326
|
||||
volumes:
|
||||
- /Volumes/mobile_disk/99:/data
|
||||
command: 'filer -master="master:9333" -metricsPort=9326'
|
||||
tty: true
|
||||
stdin_open: true
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
mount:
|
||||
image: chrislusf/seaweedfs:local
|
||||
privileged: true
|
||||
cap_add:
|
||||
- SYS_ADMIN
|
||||
devices:
|
||||
- fuse
|
||||
volumes:
|
||||
- /Volumes/mobile_disk/99:/data
|
||||
entrypoint: '/bin/sh -c "mkdir -p t1 && weed -v=4 mount -filer=filer:8888 -dir=./t1 -cacheCapacityMB=0 -memprofile=/data/mount.mem.pprof"'
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
- filer
|
||||
32
docker/compose/local-mq-test.yml
Normal file
32
docker/compose/local-mq-test.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
services:
|
||||
server:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
command: "server -ip=server -filer -volume.max=0 -master.volumeSizeLimitMB=8 -volume.preStopSeconds=1"
|
||||
healthcheck:
|
||||
test: curl -f http://localhost:8888/healthz
|
||||
mq_broker:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 17777:17777
|
||||
command: "mq.broker -master=server:9333 -ip=mq_broker"
|
||||
depends_on:
|
||||
server:
|
||||
condition: service_healthy
|
||||
mq_agent:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 16777:16777
|
||||
command: "mq.agent -broker=mq_broker:17777 -port=16777"
|
||||
depends_on:
|
||||
- mq_broker
|
||||
mq_client:
|
||||
image: chrislusf/seaweedfs:local
|
||||
# run a custom command instead of entrypoint
|
||||
command: "ls -al"
|
||||
depends_on:
|
||||
- mq_agent
|
||||
44
docker/compose/local-nextcloud-compose.yml
Normal file
44
docker/compose/local-nextcloud-compose.yml
Normal file
@@ -0,0 +1,44 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
master:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
command: "master -ip=master"
|
||||
volume:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: "volume -master=master:9333 -port=8080 -ip=volume"
|
||||
depends_on:
|
||||
- master
|
||||
s3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
- 8333:8333
|
||||
command: '-v 9 filer -master="master:9333" -s3'
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
nextcloud:
|
||||
image: nextcloud:23.0.5-apache
|
||||
environment:
|
||||
- OBJECTSTORE_S3_HOST=s3
|
||||
- OBJECTSTORE_S3_BUCKET=nextcloud
|
||||
- OBJECTSTORE_S3_KEY=some_access_key1
|
||||
- OBJECTSTORE_S3_SECRET=some_secret_key1
|
||||
- OBJECTSTORE_S3_PORT=8333
|
||||
- OBJECTSTORE_S3_SSL=false
|
||||
- OBJECTSTORE_S3_USEPATH_STYLE=true
|
||||
- SQLITE_DATABASE=nextcloud
|
||||
- NEXTCLOUD_ADMIN_USER=admin
|
||||
- NEXTCLOUD_ADMIN_PASSWORD=admin
|
||||
ports:
|
||||
- 80:80
|
||||
depends_on:
|
||||
- s3
|
||||
85
docker/compose/local-registry-compose.yml
Normal file
85
docker/compose/local-registry-compose.yml
Normal file
@@ -0,0 +1,85 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
master:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
command: "master -ip=master -volumeSizeLimitMB=100"
|
||||
volume:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: "volume -master=master:9333 -port=8080 -ip=volume -max=0 -preStopSeconds=1"
|
||||
depends_on:
|
||||
- master
|
||||
s3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
- 8333:8333
|
||||
command: '-v 9 filer -master="master:9333" -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8333'
|
||||
volumes:
|
||||
- ./s3.json:/etc/seaweedfs/s3.json
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
minio:
|
||||
image: minio/minio
|
||||
ports:
|
||||
- 9000:9000
|
||||
command: 'minio server /data'
|
||||
environment:
|
||||
MINIO_ACCESS_KEY: "some_access_key1"
|
||||
MINIO_SECRET_KEY: "some_secret_key1"
|
||||
depends_on:
|
||||
- master
|
||||
registry1:
|
||||
image: registry:2
|
||||
environment:
|
||||
REGISTRY_HTTP_ADDR: "0.0.0.0:5001" # seaweedfs s3
|
||||
REGISTRY_LOG_LEVEL: "debug"
|
||||
REGISTRY_STORAGE: "s3"
|
||||
REGISTRY_STORAGE_S3_REGION: "us-east-1"
|
||||
REGISTRY_STORAGE_S3_REGIONENDPOINT: "http://s3:8333"
|
||||
REGISTRY_STORAGE_S3_BUCKET: "registry"
|
||||
REGISTRY_STORAGE_S3_ACCESSKEY: "some_access_key1"
|
||||
REGISTRY_STORAGE_S3_SECRETKEY: "some_secret_key1"
|
||||
REGISTRY_STORAGE_S3_V4AUTH: "true"
|
||||
REGISTRY_STORAGE_S3_SECURE: "false"
|
||||
REGISTRY_STORAGE_S3_SKIPVERIFY: "true"
|
||||
REGISTRY_STORAGE_S3_ROOTDIRECTORY: "/"
|
||||
REGISTRY_STORAGE_DELETE_ENABLED: "true"
|
||||
REGISTRY_STORAGE_REDIRECT_DISABLE: "true"
|
||||
REGISTRY_VALIDATION_DISABLED: "true"
|
||||
ports:
|
||||
- 5001:5001
|
||||
depends_on:
|
||||
- s3
|
||||
- minio
|
||||
registry2:
|
||||
image: registry:2
|
||||
environment:
|
||||
REGISTRY_HTTP_ADDR: "0.0.0.0:5002" # minio
|
||||
REGISTRY_LOG_LEVEL: "debug"
|
||||
REGISTRY_STORAGE: "s3"
|
||||
REGISTRY_STORAGE_S3_REGION: "us-east-1"
|
||||
REGISTRY_STORAGE_S3_REGIONENDPOINT: "http://minio:9000"
|
||||
REGISTRY_STORAGE_S3_BUCKET: "registry"
|
||||
REGISTRY_STORAGE_S3_ACCESSKEY: "some_access_key1"
|
||||
REGISTRY_STORAGE_S3_SECRETKEY: "some_secret_key1"
|
||||
REGISTRY_STORAGE_S3_V4AUTH: "true"
|
||||
REGISTRY_STORAGE_S3_SECURE: "false"
|
||||
REGISTRY_STORAGE_S3_SKIPVERIFY: "true"
|
||||
REGISTRY_STORAGE_S3_ROOTDIRECTORY: "/"
|
||||
REGISTRY_STORAGE_DELETE_ENABLED: "true"
|
||||
REGISTRY_STORAGE_REDIRECT_DISABLE: "true"
|
||||
REGISTRY_VALIDATION_DISABLED: "true"
|
||||
ports:
|
||||
- 5002:5002
|
||||
depends_on:
|
||||
- s3
|
||||
- minio
|
||||
61
docker/compose/local-replicate-compose.yml
Normal file
61
docker/compose/local-replicate-compose.yml
Normal file
@@ -0,0 +1,61 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
master:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
command: "master -ip=master"
|
||||
volume:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: "volume -master=master:9333 -port=8080 -ip=volume -preStopSeconds=1"
|
||||
depends_on:
|
||||
- master
|
||||
filer:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
command: '-v=9 filer -master="master:9333"'
|
||||
restart: on-failure
|
||||
volumes:
|
||||
- ./notification.toml:/etc/seaweedfs/notification.toml
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
- rabbitmq
|
||||
- replicate
|
||||
environment:
|
||||
RABBIT_SERVER_URL: "amqp://guest:guest@rabbitmq:5672/"
|
||||
replicate:
|
||||
image: chrislusf/seaweedfs:local
|
||||
command: '-v=9 filer.replicate'
|
||||
restart: on-failure
|
||||
volumes:
|
||||
- ./notification.toml:/etc/seaweedfs/notification.toml
|
||||
- ./replication.toml:/etc/seaweedfs/replication.toml
|
||||
depends_on:
|
||||
- rabbitmq
|
||||
environment:
|
||||
RABBIT_SERVER_URL: "amqp://guest:guest@rabbitmq:5672/"
|
||||
s3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8333:8333
|
||||
command: 's3 -filer="filer:8888"'
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
- filer
|
||||
rabbitmq:
|
||||
image: rabbitmq:3.8.10-management-alpine
|
||||
ports:
|
||||
- 5672:5672
|
||||
- 15671:15671
|
||||
- 15672:15672
|
||||
environment:
|
||||
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS: "-rabbit log_levels [{connection,error},{queue,debug}]"
|
||||
45
docker/compose/local-s3tests-compose.yml
Normal file
45
docker/compose/local-s3tests-compose.yml
Normal file
@@ -0,0 +1,45 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
master:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
command: "master -ip=master -volumeSizeLimitMB=16"
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 1
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 1
|
||||
volume:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: "volume -master=master:9333 -port=8080 -ip=volume -preStopSeconds=1"
|
||||
depends_on:
|
||||
- master
|
||||
s3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
- 8000:8000
|
||||
command: 'filer -master="master:9333" -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8000 -s3.allowDeleteBucketNotEmpty=false'
|
||||
volumes:
|
||||
- ./s3.json:/etc/seaweedfs/s3.json
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
s3tests:
|
||||
image: chrislusf/ceph-s3-tests:local
|
||||
volumes:
|
||||
- ./s3tests.conf:/opt/s3-tests/s3tests.conf
|
||||
environment:
|
||||
S3TEST_CONF: "s3tests.conf"
|
||||
NOSETESTS_OPTIONS: "--verbose --logging-level=ERROR --with-xunit --failure-detail s3tests_boto3.functional.test_s3"
|
||||
NOSETESTS_ATTR: "!fails_on_aws,!encryption,!bucket-policy,!versioning,!fails_on_rgw,!bucket-policy,!fails_with_subdomain,!policy_status,!object-lock,!lifecycle,!cors,!user-policy"
|
||||
NOSETESTS_EXCLUDE: "(post_object_tags_anonymous_request|get_obj_tagging|set_bucket_tagging|post_object_tags_authenticated_request|put_max_tags|put_modify_tags|test_put_obj_with_tags|get_bucket_encryption|delete_bucket_encryption|put_bucket_encryption|bucket_list_delimiter_basic|bucket_listv2_delimiter_basic|bucket_listv2_encoding_basic|bucket_list_encoding_basic|bucket_list_delimiter_prefix|bucket_listv2_delimiter_prefix_ends_with_delimiter|bucket_list_delimiter_prefix_ends_with_delimiter|bucket_list_delimiter_alt|bucket_listv2_delimiter_alt|bucket_list_delimiter_prefix_underscore|bucket_list_delimiter_percentage|bucket_listv2_delimiter_percentage|bucket_list_delimiter_whitespace|bucket_listv2_delimiter_whitespace|bucket_list_delimiter_dot|bucket_listv2_delimiter_dot|bucket_list_delimiter_unreadable|bucket_listv2_delimiter_unreadable|bucket_listv2_fetchowner_defaultempty|bucket_listv2_fetchowner_empty|bucket_list_prefix_delimiter_alt|bucket_listv2_prefix_delimiter_alt|bucket_list_prefix_delimiter_prefix_not_exist|bucket_listv2_prefix_delimiter_prefix_not_exist|bucket_list_prefix_delimiter_delimiter_not_exist|bucket_listv2_prefix_delimiter_delimiter_not_exist|bucket_list_prefix_delimiter_prefix_delimiter_not_exist|bucket_listv2_prefix_delimiter_prefix_delimiter_not_exist|bucket_list_maxkeys_none|bucket_listv2_maxkeys_none|bucket_list_maxkeys_invalid|bucket_listv2_continuationtoken_empty|bucket_list_return_data|bucket_list_objects_anonymous|bucket_listv2_objects_anonymous|bucket_concurrent_set_canned_acl|object_write_to_nonexist_bucket|object_requestid_matches_header_on_error|object_set_get_metadata_none_to_good|object_set_get_metadata_none_to_empty|object_set_get_metadata_overwrite_to_empty|post_object_anonymous_request|post_object_authenticated_request|post_object_authenticated_no_content_type|post_object_authenticated_request_bad_access_key|post_object_set_success_code|post_object_set_invalid_success_code|post_object_upload_larger_than_chunk|post_object_set_key_from_filename|post_object_ignored_header|post_object_case_insensitive_condition_fields|post_object_escaped_field_values|post_object_success_redirect_action|post_object_invalid_signature|post_object_invalid_access_key|post_object_missing_policy_condition|post_object_user_specified_header|post_object_request_missing_policy_specified_field|post_object_expired_policy|post_object_invalid_request_field_value|get_object_ifunmodifiedsince_good|put_object_ifmatch_failed|object_raw_get_bucket_gone|object_delete_key_bucket_gone|object_raw_get_bucket_acl|object_raw_get_object_acl|object_raw_response_headers|object_raw_authenticated_bucket_gone|object_raw_get_x_amz_expires_out_max_range|object_raw_get_x_amz_expires_out_positive_range|object_anon_put_write_access|object_raw_put_authenticated_expired|bucket_create_exists|bucket_create_naming_bad_short_one|bucket_create_naming_bad_short_two|bucket_get_location|bucket_acl_default|bucket_acl_canned|bucket_acl_canned_publicreadwrite|bucket_acl_canned_authenticatedread|object_acl_default|object_acl_canned_during_create|object_acl_canned|object_acl_canned_publicreadwrite|object_acl_canned_authenticatedread|object_acl_canned_bucketownerread|object_acl_canned_bucketownerfullcontrol|object_acl_full_control_verify_attributes|bucket_acl_canned_private_to_private|bucket_acl_grant_nonexist_user|bucket_acl_no_grants|bucket_acl_grant_email_not_exist|bucket_acl_revoke_all|bucket_recreate_not_overriding|object_copy_verify_contenttype|object_copy_to_itself_with_metadata|object_copy_not_owned_bucket|object_copy_not_owned_object_bucket|object_copy_retaining_metadata|object_copy_replacing_metadata|multipart_upload_empty|multipart_copy_invalid_range|multipart_copy_special_names|multipart_upload_resend_part|multipart_upload_size_too_small|abort_multipart_upload_not_found|multipart_upload_missing_part|100_continue|ranged_request_invalid_range|ranged_request_empty_object|access_bucket|list_multipart_upload_owner|multipart_upload_small)"
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
- s3
|
||||
56
docker/compose/local-sync-mount-compose.yml
Normal file
56
docker/compose/local-sync-mount-compose.yml
Normal file
@@ -0,0 +1,56 @@
|
||||
version: '3.9'
|
||||
services:
|
||||
node1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
command: "server -master -volume -filer"
|
||||
ports:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "--fail", "-I", "http://localhost:9333/cluster/healthz" ]
|
||||
interval: 1s
|
||||
start_period: 10s
|
||||
timeout: 30s
|
||||
mount1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
privileged: true
|
||||
command: "mount -filer=node1:8888 -dir=/mnt -dirAutoCreate"
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "--fail", "-I", "http://node1:8888/" ]
|
||||
interval: 1s
|
||||
start_period: 10s
|
||||
timeout: 30s
|
||||
depends_on:
|
||||
node1:
|
||||
condition: service_healthy
|
||||
node2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 7888:8888
|
||||
- 17888:18888
|
||||
command: "server -master -volume -filer"
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "--fail", "-I", "http://localhost:9333/cluster/healthz" ]
|
||||
interval: 1s
|
||||
start_period: 10s
|
||||
timeout: 30s
|
||||
mount2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
privileged: true
|
||||
command: "mount -filer=node2:8888 -dir=/mnt -dirAutoCreate"
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "--fail", "-I", "http://node2:8888/" ]
|
||||
interval: 1s
|
||||
start_period: 10s
|
||||
timeout: 30s
|
||||
depends_on:
|
||||
node2:
|
||||
condition: service_healthy
|
||||
sync:
|
||||
image: chrislusf/seaweedfs:local
|
||||
command: "-v=4 filer.sync -a=node1:8888 -b=node2:8888 -a.debug -b.debug"
|
||||
depends_on:
|
||||
mount1:
|
||||
condition: service_healthy
|
||||
mount2:
|
||||
condition: service_healthy
|
||||
34
docker/compose/master-cloud.toml
Normal file
34
docker/compose/master-cloud.toml
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
# Put this file to one of the location, with descending priority
|
||||
# ./master.toml
|
||||
# $HOME/.seaweedfs/master.toml
|
||||
# /etc/seaweedfs/master.toml
|
||||
# this file is read by master
|
||||
|
||||
[master.maintenance]
|
||||
# periodically run these scripts are the same as running them from 'weed shell'
|
||||
# Scripts are skipped while an admin server is connected.
|
||||
scripts = """
|
||||
lock
|
||||
ec.encode -fullPercent=95 -quietFor=1h
|
||||
ec.rebuild -apply
|
||||
ec.balance -apply
|
||||
volume.balance -apply
|
||||
volume.fix.replication -apply
|
||||
unlock
|
||||
"""
|
||||
sleep_minutes = 17 # sleep minutes between each script execution
|
||||
|
||||
# configurations for tiered cloud storage
|
||||
# old volumes are transparently moved to cloud for cost efficiency
|
||||
[storage.backend]
|
||||
[storage.backend.s3.default]
|
||||
enabled = true
|
||||
aws_access_key_id = "any" # if empty, loads from the shared credentials file (~/.aws/credentials).
|
||||
aws_secret_access_key = "any" # if empty, loads from the shared credentials file (~/.aws/credentials).
|
||||
region = "us-east-2"
|
||||
bucket = "volume_bucket" # an existing bucket
|
||||
endpoint = "http://server2:8333"
|
||||
storage_class = "STANDARD_IA"
|
||||
# upload_concurrency = 5 # concurrent multipart part uploads per volume (volume.tier.upload -concurrent overrides)
|
||||
# download_concurrency = 5 # concurrent multipart part downloads per volume (volume.tier.download -concurrent overrides)
|
||||
17
docker/compose/notification.toml
Normal file
17
docker/compose/notification.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[notification.log]
|
||||
# this is only for debugging purpose and does not work with "weed filer.replicate"
|
||||
enabled = false
|
||||
|
||||
|
||||
[notification.gocdk_pub_sub]
|
||||
# The Go Cloud Development Kit (https://gocloud.dev).
|
||||
# PubSub API (https://godoc.org/gocloud.dev/pubsub).
|
||||
# Supports AWS SNS/SQS, Azure Service Bus, Google PubSub, NATS and RabbitMQ.
|
||||
enabled = true
|
||||
# This URL will Dial the RabbitMQ server at the URL in the environment
|
||||
# variable RABBIT_SERVER_URL and open the exchange "myexchange".
|
||||
# The exchange must have already been created by some other means, like
|
||||
# the RabbitMQ management plugin. Сreate myexchange of type fanout and myqueue then
|
||||
# create binding myexchange => myqueue
|
||||
topic_url = "rabbit://swexchange"
|
||||
sub_url = "rabbit://swqueue"
|
||||
11
docker/compose/replication.toml
Normal file
11
docker/compose/replication.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[source.filer]
|
||||
enabled = true
|
||||
grpcAddress = "filer:18888"
|
||||
# all files under this directory tree are replicated.
|
||||
# this is not a directory on your hard drive, but on your filer.
|
||||
# i.e., all files with this "prefix" are sent to notification message queue.
|
||||
directory = "/buckets"
|
||||
|
||||
[sink.local_incremental]
|
||||
enabled = true
|
||||
directory = "/data"
|
||||
115
docker/compose/s3.json
Normal file
115
docker/compose/s3.json
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"identities": [
|
||||
{
|
||||
"name": "anonymous",
|
||||
"actions": [
|
||||
"Read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "some_admin_user",
|
||||
"credentials": [
|
||||
{
|
||||
"accessKey": "some_access_key1",
|
||||
"secretKey": "some_secret_key1"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
"Admin",
|
||||
"Read",
|
||||
"List",
|
||||
"Tagging",
|
||||
"Write"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "s3_tests",
|
||||
"credentials": [
|
||||
{
|
||||
"accessKey": "ABCDEFGHIJKLMNOPQRST",
|
||||
"secretKey": "abcdefghijklmnopqrstuvwxyzabcdefghijklmn"
|
||||
},
|
||||
{
|
||||
"accessKey": "0555b35654ad1656d804",
|
||||
"secretKey": "h7GhxuBLTrlhVUyxSPUKUV8r/2EI4ngqJxD7iBdBYLhwluN30JaT3Q=="
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
"Admin",
|
||||
"Read",
|
||||
"List",
|
||||
"Tagging",
|
||||
"Write"
|
||||
],
|
||||
"account": {
|
||||
"id": "testid"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "s3_tests_alt",
|
||||
"credentials": [
|
||||
{
|
||||
"accessKey": "NOPQRSTUVWXYZABCDEFG",
|
||||
"secretKey": "nopqrstuvwxyzabcdefghijklmnabcdefghijklm"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
"Admin",
|
||||
"Read",
|
||||
"List",
|
||||
"Tagging",
|
||||
"Write"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "s3_tests_tenant",
|
||||
"credentials": [
|
||||
{
|
||||
"accessKey": "HIJKLMNOPQRSTUVWXYZA",
|
||||
"secretKey": "opqrstuvwxyzabcdefghijklmnopqrstuvwxyzab"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
"Admin",
|
||||
"Read",
|
||||
"List",
|
||||
"Tagging",
|
||||
"Write"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "some_read_only_user",
|
||||
"credentials": [
|
||||
{
|
||||
"accessKey": "some_access_key2",
|
||||
"secretKey": "some_secret_key2"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
"Read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "some_normal_user",
|
||||
"credentials": [
|
||||
{
|
||||
"accessKey": "some_access_key3",
|
||||
"secretKey": "some_secret_key3"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
"Read",
|
||||
"List",
|
||||
"Tagging",
|
||||
"Write"
|
||||
]
|
||||
}
|
||||
],
|
||||
"accounts": [
|
||||
{
|
||||
"id" : "testid",
|
||||
"displayName": "M. Tester",
|
||||
"emailAddress": "tester@ceph.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
53
docker/compose/s3_static_users_example.json
Normal file
53
docker/compose/s3_static_users_example.json
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"identities": [
|
||||
{
|
||||
"name": "admin",
|
||||
"credentials": [
|
||||
{
|
||||
"accessKey": "AKIAIOSFODNN7EXAMPLE",
|
||||
"secretKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
"Admin",
|
||||
"Read",
|
||||
"List",
|
||||
"Tagging",
|
||||
"Write"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "steward",
|
||||
"credentials": [
|
||||
{
|
||||
"accessKey": "steward-key",
|
||||
"secretKey": "steward-secret"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
"Read",
|
||||
"List",
|
||||
"Write"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "le001",
|
||||
"credentials": [
|
||||
{
|
||||
"accessKey": "le001-key",
|
||||
"secretKey": "le001-secret"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
"Read",
|
||||
"List"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "anonymous",
|
||||
"actions": [
|
||||
"Read"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
103
docker/compose/s3tests.conf
Normal file
103
docker/compose/s3tests.conf
Normal file
@@ -0,0 +1,103 @@
|
||||
[DEFAULT]
|
||||
## this section is just used for host, port and bucket_prefix
|
||||
|
||||
# host set for rgw in vstart.sh
|
||||
host = 127.0.0.1
|
||||
|
||||
# port set for rgw in vstart.sh
|
||||
port = 8000
|
||||
|
||||
## say "False" to disable TLS
|
||||
is_secure = False
|
||||
|
||||
[fixtures]
|
||||
## all the buckets created will start with this prefix;
|
||||
## {random} will be filled with random characters to pad
|
||||
## the prefix to 30 characters long, and avoid collisions
|
||||
bucket prefix = yournamehere-{random}-
|
||||
|
||||
[s3 main]
|
||||
# main display_name set in vstart.sh
|
||||
display_name = M. Tester
|
||||
|
||||
# main user_idname set in vstart.sh
|
||||
user_id = testid
|
||||
|
||||
# main email set in vstart.sh
|
||||
email = tester@ceph.com
|
||||
|
||||
# zonegroup api_name for bucket location
|
||||
api_name = default
|
||||
|
||||
## main AWS access key
|
||||
access_key = 0555b35654ad1656d804
|
||||
|
||||
## main AWS secret key
|
||||
secret_key = h7GhxuBLTrlhVUyxSPUKUV8r/2EI4ngqJxD7iBdBYLhwluN30JaT3Q==
|
||||
|
||||
## replace with key id obtained when secret is created, or delete if KMS not tested
|
||||
#kms_keyid = 01234567-89ab-cdef-0123-456789abcdef
|
||||
|
||||
[s3 alt]
|
||||
# alt display_name set in vstart.sh
|
||||
display_name = john.doe
|
||||
## alt email set in vstart.sh
|
||||
email = john.doe@example.com
|
||||
|
||||
# alt user_id set in vstart.sh
|
||||
user_id = 56789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234
|
||||
|
||||
# alt AWS access key set in vstart.sh
|
||||
access_key = NOPQRSTUVWXYZABCDEFG
|
||||
|
||||
# alt AWS secret key set in vstart.sh
|
||||
secret_key = nopqrstuvwxyzabcdefghijklmnabcdefghijklm
|
||||
|
||||
[s3 tenant]
|
||||
# tenant display_name set in vstart.sh
|
||||
display_name = testx$tenanteduser
|
||||
|
||||
# tenant user_id set in vstart.sh
|
||||
user_id = 9876543210abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
||||
|
||||
# tenant AWS secret key set in vstart.sh
|
||||
access_key = HIJKLMNOPQRSTUVWXYZA
|
||||
|
||||
# tenant AWS secret key set in vstart.sh
|
||||
secret_key = opqrstuvwxyzabcdefghijklmnopqrstuvwxyzab
|
||||
|
||||
# tenant email set in vstart.sh
|
||||
email = tenanteduser@example.com
|
||||
|
||||
# tenant name
|
||||
tenant = testx
|
||||
|
||||
[iam]
|
||||
#used for iam operations in sts-tests
|
||||
#email from vstart.sh
|
||||
email = s3@example.com
|
||||
|
||||
#user_id from vstart.sh
|
||||
user_id = 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
||||
|
||||
#access_key from vstart.sh
|
||||
access_key = ABCDEFGHIJKLMNOPQRST
|
||||
|
||||
#secret_key from vstart.sh
|
||||
secret_key = abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
|
||||
|
||||
#display_name from vstart.sh
|
||||
display_name = youruseridhere
|
||||
|
||||
[iam root]
|
||||
access_key = AAAAAAAAAAAAAAAAAAaa
|
||||
secret_key = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
user_id = RGW11111111111111111
|
||||
email = account1@ceph.com
|
||||
|
||||
# iam account root user in a different account than [iam root]
|
||||
[iam alt root]
|
||||
access_key = BBBBBBBBBBBBBBBBBBbb
|
||||
secret_key = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
user_id = RGW22222222222222222
|
||||
email = account2@ceph.com
|
||||
82
docker/compose/swarm-etcd.yml
Normal file
82
docker/compose/swarm-etcd.yml
Normal file
@@ -0,0 +1,82 @@
|
||||
# 2021-01-30 16:25:30
|
||||
services:
|
||||
|
||||
etcd:
|
||||
image: gasparekatapy/etcd
|
||||
networks:
|
||||
- net
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: 3
|
||||
|
||||
master:
|
||||
image: chrislusf/seaweedfs:local
|
||||
environment:
|
||||
WEED_MASTER_FILER_DEFAULT: "filer:8888"
|
||||
WEED_MASTER_SEQUENCER_TYPE: "raft"
|
||||
ports:
|
||||
- "9333:9333"
|
||||
- "19333:19333"
|
||||
networks:
|
||||
- net
|
||||
command:
|
||||
- 'master'
|
||||
- '-resumeState=true'
|
||||
- '-ip=master'
|
||||
- '-port=9333'
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: 1
|
||||
|
||||
filer:
|
||||
image: chrislusf/seaweedfs:local
|
||||
environment:
|
||||
WEED_LEVELDB2_ENABLED: "false"
|
||||
WEED_ETCD_ENABLED: "true"
|
||||
WEED_ETCD_SERVERS: "etcd:2379"
|
||||
ports:
|
||||
- target: 8888
|
||||
published: 8888
|
||||
protocol: tcp
|
||||
mode: host
|
||||
- target: 18888
|
||||
published: 18888
|
||||
protocol: tcp
|
||||
mode: host
|
||||
networks:
|
||||
- net
|
||||
command:
|
||||
- 'filer'
|
||||
- '-ip=filer'
|
||||
- '-port=8888'
|
||||
- '-port.readonly=28888'
|
||||
- '-master=master:9333'
|
||||
- '-disableDirListing=true'
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: 1
|
||||
|
||||
volume:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- target: 8080
|
||||
published: 8080
|
||||
protocol: tcp
|
||||
mode: host
|
||||
- target: 18080
|
||||
published: 18080
|
||||
protocol: tcp
|
||||
mode: host
|
||||
networks:
|
||||
- net
|
||||
command:
|
||||
- 'volume'
|
||||
- '-master=master:9333'
|
||||
- '-port=8080'
|
||||
deploy:
|
||||
mode: global
|
||||
|
||||
###########################################################################
|
||||
|
||||
networks:
|
||||
net:
|
||||
62
docker/compose/test-etcd-filer.yml
Normal file
62
docker/compose/test-etcd-filer.yml
Normal file
@@ -0,0 +1,62 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
etcd:
|
||||
image: quay.io/coreos/etcd:v3.5.4
|
||||
command: "etcd --advertise-client-urls http://etcd:2379 --listen-client-urls http://0.0.0.0:2379"
|
||||
ports:
|
||||
- 2379:2379
|
||||
master:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
command: "master -ip=master -volumeSizeLimitMB=100"
|
||||
volume:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: "volume -master=master:9333 -port=8080 -ip=volume -max=0 -preStopSeconds=1"
|
||||
depends_on:
|
||||
- master
|
||||
s3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
- 8333:8333
|
||||
command: '-v 9 filer -master="master:9333" -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8333'
|
||||
environment:
|
||||
WEED_LEVELDB2_ENABLED: 'false'
|
||||
WEED_ETCD_ENABLED: 'true'
|
||||
WEED_ETCD_KEY_PREFIX: 'seaweedfs.'
|
||||
WEED_ETCD_SERVERS: "http://etcd:2379"
|
||||
volumes:
|
||||
- ./s3.json:/etc/seaweedfs/s3.json
|
||||
depends_on:
|
||||
- etcd
|
||||
- master
|
||||
- volume
|
||||
registry:
|
||||
image: registry:2
|
||||
environment:
|
||||
REGISTRY_HTTP_ADDR: "0.0.0.0:5001" # seaweedfs s3
|
||||
REGISTRY_LOG_LEVEL: "debug"
|
||||
REGISTRY_STORAGE: "s3"
|
||||
REGISTRY_STORAGE_S3_REGION: "us-east-1"
|
||||
REGISTRY_STORAGE_S3_REGIONENDPOINT: "http://s3:8333"
|
||||
REGISTRY_STORAGE_S3_BUCKET: "registry"
|
||||
REGISTRY_STORAGE_S3_ACCESSKEY: "some_access_key1"
|
||||
REGISTRY_STORAGE_S3_SECRETKEY: "some_secret_key1"
|
||||
REGISTRY_STORAGE_S3_V4AUTH: "true"
|
||||
REGISTRY_STORAGE_S3_SECURE: "false"
|
||||
REGISTRY_STORAGE_S3_SKIPVERIFY: "true"
|
||||
REGISTRY_STORAGE_S3_ROOTDIRECTORY: "/"
|
||||
REGISTRY_STORAGE_DELETE_ENABLED: "true"
|
||||
REGISTRY_STORAGE_REDIRECT_DISABLE: "true"
|
||||
REGISTRY_VALIDATION_DISABLED: "true"
|
||||
ports:
|
||||
- 5001:5001
|
||||
depends_on:
|
||||
- s3
|
||||
260
docker/compose/test-git-on-mount.sh
Executable file
260
docker/compose/test-git-on-mount.sh
Executable file
@@ -0,0 +1,260 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Integration test: git clone & pull on a SeaweedFS FUSE mount.
|
||||
#
|
||||
# Verifies that the mount correctly supports git's file operations by:
|
||||
# 1. Creating a bare repo on the mount (acts as a remote)
|
||||
# 2. Cloning it, making commits, and pushing back to the mount
|
||||
# 3. Cloning from the mount into a working directory also on the mount
|
||||
# 4. Pushing additional commits to the bare repo
|
||||
# 5. Checking out an older revision in the on-mount clone
|
||||
# 6. Running git pull to fast-forward with real changes
|
||||
# 7. Verifying file content integrity at each step
|
||||
#
|
||||
# Usage:
|
||||
# bash test-git-on-mount.sh /path/to/mount/point
|
||||
#
|
||||
# The mount must already be running. All test artifacts are created under
|
||||
# <mount>/git-test-<pid> and cleaned up on exit (unless TEST_KEEP=1).
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
MOUNT_DIR="${1:?Usage: $0 <mount-dir>}"
|
||||
TEST_DIR="$MOUNT_DIR/git-test-$$"
|
||||
LOCAL_DIR=$(mktemp -d)
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
cleanup() {
|
||||
if [[ "${TEST_KEEP:-}" == "1" ]]; then
|
||||
echo "TEST_KEEP=1 — leaving artifacts:"
|
||||
echo " mount: $TEST_DIR"
|
||||
echo " local: $LOCAL_DIR"
|
||||
else
|
||||
rm -rf "$TEST_DIR" 2>/dev/null || true
|
||||
rm -rf "$LOCAL_DIR" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# --- helpers ---------------------------------------------------------------
|
||||
|
||||
pass() { PASS=$((PASS + 1)); echo " PASS: $1"; }
|
||||
fail() { FAIL=$((FAIL + 1)); echo " FAIL: $1"; }
|
||||
|
||||
assert_file_contains() {
|
||||
local file=$1 expected=$2 label=$3
|
||||
if [[ -f "$file" ]] && grep -qF "$expected" "$file" 2>/dev/null; then
|
||||
pass "$label"
|
||||
else
|
||||
fail "$label (expected '$expected' in $file)"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_file_exists() {
|
||||
local file=$1 label=$2
|
||||
if [[ -f "$file" ]]; then
|
||||
pass "$label"
|
||||
else
|
||||
fail "$label ($file not found)"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_file_not_exists() {
|
||||
local file=$1 label=$2
|
||||
if [[ ! -f "$file" ]]; then
|
||||
pass "$label"
|
||||
else
|
||||
fail "$label ($file should not exist)"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_eq() {
|
||||
local actual=$1 expected=$2 label=$3
|
||||
if [[ "$actual" == "$expected" ]]; then
|
||||
pass "$label"
|
||||
else
|
||||
fail "$label (expected '$expected', got '$actual')"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- setup -----------------------------------------------------------------
|
||||
|
||||
echo "========================================"
|
||||
echo " Git-on-mount integration test"
|
||||
echo "========================================"
|
||||
echo "Mount: $MOUNT_DIR"
|
||||
echo "Test: $TEST_DIR"
|
||||
echo "Local: $LOCAL_DIR"
|
||||
echo ""
|
||||
|
||||
if ! mountpoint -q "$MOUNT_DIR" 2>/dev/null && [[ ! -d "$MOUNT_DIR" ]]; then
|
||||
echo "ERROR: $MOUNT_DIR is not a valid directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$TEST_DIR"
|
||||
|
||||
# --- Phase 1: Create bare repo on mount -----------------------------------
|
||||
|
||||
echo "--- Phase 1: Create bare repo on mount ---"
|
||||
|
||||
BARE_REPO="$TEST_DIR/repo.git"
|
||||
git init --bare "$BARE_REPO" >/dev/null 2>&1
|
||||
pass "bare repo created on mount"
|
||||
|
||||
# --- Phase 2: Clone locally, make initial commits, push -------------------
|
||||
|
||||
echo "--- Phase 2: Clone locally, make initial commits, push ---"
|
||||
|
||||
LOCAL_CLONE="$LOCAL_DIR/clone1"
|
||||
git clone "$BARE_REPO" "$LOCAL_CLONE" >/dev/null 2>&1
|
||||
cd "$LOCAL_CLONE"
|
||||
git config user.email "test@seaweedfs.test"
|
||||
git config user.name "SeaweedFS Test"
|
||||
|
||||
# Commit 1: initial files
|
||||
echo "hello world" > README.md
|
||||
mkdir -p src
|
||||
echo 'package main; import "fmt"; func main() { fmt.Println("v1") }' > src/main.go
|
||||
git add -A && git commit -m "initial commit" >/dev/null 2>&1
|
||||
COMMIT1=$(git rev-parse HEAD)
|
||||
|
||||
# Commit 2: add more files
|
||||
mkdir -p data
|
||||
for i in $(seq 1 20); do
|
||||
printf "file-%03d: %s\n" "$i" "$(head -c 64 /dev/urandom | base64)" > "data/file-$(printf '%03d' $i).txt"
|
||||
done
|
||||
git add -A && git commit -m "add data files" >/dev/null 2>&1
|
||||
COMMIT2=$(git rev-parse HEAD)
|
||||
|
||||
# Commit 3: modify and add
|
||||
echo 'package main; import "fmt"; func main() { fmt.Println("v2") }' > src/main.go
|
||||
echo "# Updated readme" >> README.md
|
||||
mkdir -p docs
|
||||
echo "documentation content" > docs/guide.md
|
||||
git add -A && git commit -m "update src and add docs" >/dev/null 2>&1
|
||||
COMMIT3=$(git rev-parse HEAD)
|
||||
|
||||
git push origin master >/dev/null 2>&1 || git push origin main >/dev/null 2>&1
|
||||
BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
pass "3 commits pushed to mount bare repo (branch=$BRANCH)"
|
||||
|
||||
# --- Phase 3: Clone from mount bare repo to mount working dir -------------
|
||||
|
||||
echo "--- Phase 3: Clone from mount bare repo to on-mount working dir ---"
|
||||
|
||||
MOUNT_CLONE="$TEST_DIR/working"
|
||||
git clone "$BARE_REPO" "$MOUNT_CLONE" >/dev/null 2>&1
|
||||
|
||||
# Verify clone integrity
|
||||
assert_file_exists "$MOUNT_CLONE/README.md" "README.md exists after clone"
|
||||
assert_file_contains "$MOUNT_CLONE/README.md" "# Updated readme" "README.md has latest content"
|
||||
assert_file_contains "$MOUNT_CLONE/src/main.go" 'v2' "src/main.go has v2"
|
||||
assert_file_exists "$MOUNT_CLONE/docs/guide.md" "docs/guide.md exists"
|
||||
assert_file_exists "$MOUNT_CLONE/data/file-001.txt" "data files exist"
|
||||
assert_file_exists "$MOUNT_CLONE/data/file-020.txt" "data/file-020.txt exists"
|
||||
|
||||
CLONE_HEAD=$(cd "$MOUNT_CLONE" && git rev-parse HEAD)
|
||||
assert_eq "$CLONE_HEAD" "$COMMIT3" "on-mount clone HEAD matches commit 3"
|
||||
|
||||
# Count files
|
||||
FILE_COUNT=$(find "$MOUNT_CLONE/data" -name '*.txt' | wc -l | tr -d ' ')
|
||||
assert_eq "$FILE_COUNT" "20" "data/ has 20 files"
|
||||
|
||||
# --- Phase 4: Push more commits from local clone --------------------------
|
||||
|
||||
echo "--- Phase 4: Push more commits from local clone ---"
|
||||
|
||||
cd "$LOCAL_CLONE"
|
||||
|
||||
# Commit 4: larger changes
|
||||
for i in $(seq 21 50); do
|
||||
printf "file-%03d: %s\n" "$i" "$(head -c 128 /dev/urandom | base64)" > "data/file-$(printf '%03d' $i).txt"
|
||||
done
|
||||
echo 'package main; import "fmt"; func main() { fmt.Println("v3") }' > src/main.go
|
||||
git add -A && git commit -m "expand data and update to v3" >/dev/null 2>&1
|
||||
COMMIT4=$(git rev-parse HEAD)
|
||||
|
||||
# Commit 5: rename and delete
|
||||
git mv docs/guide.md docs/manual.md
|
||||
git rm data/file-001.txt >/dev/null 2>&1
|
||||
git commit -m "rename guide, remove file-001" >/dev/null 2>&1
|
||||
COMMIT5=$(git rev-parse HEAD)
|
||||
|
||||
git push origin "$BRANCH" >/dev/null 2>&1
|
||||
pass "2 more commits pushed (5 total)"
|
||||
|
||||
# --- Phase 5: Checkout older revision in on-mount clone -------------------
|
||||
|
||||
echo "--- Phase 5: Checkout older revision in on-mount clone ---"
|
||||
|
||||
cd "$MOUNT_CLONE"
|
||||
git checkout "$COMMIT2" >/dev/null 2>&1
|
||||
|
||||
# Verify we're at commit 2 state
|
||||
DETACHED_HEAD=$(git rev-parse HEAD)
|
||||
assert_eq "$DETACHED_HEAD" "$COMMIT2" "on-mount clone at commit 2 (detached)"
|
||||
assert_file_not_exists "$MOUNT_CLONE/docs/guide.md" "docs/guide.md not in commit 2"
|
||||
assert_file_contains "$MOUNT_CLONE/src/main.go" 'v1' "src/main.go has v1 at commit 2"
|
||||
|
||||
# --- Phase 6: Return to branch and pull -----------------------------------
|
||||
|
||||
echo "--- Phase 6: Return to branch and pull with real changes ---"
|
||||
|
||||
cd "$MOUNT_CLONE"
|
||||
git checkout "$BRANCH" >/dev/null 2>&1
|
||||
# At this point the on-mount clone is at commit 3, remote is at commit 5
|
||||
OLD_HEAD=$(git rev-parse HEAD)
|
||||
assert_eq "$OLD_HEAD" "$COMMIT3" "on-mount clone at commit 3 before pull"
|
||||
|
||||
git pull >/dev/null 2>&1
|
||||
NEW_HEAD=$(git rev-parse HEAD)
|
||||
assert_eq "$NEW_HEAD" "$COMMIT5" "HEAD matches commit 5 after pull"
|
||||
|
||||
# Verify commit 5 state
|
||||
assert_file_contains "$MOUNT_CLONE/src/main.go" 'v3' "src/main.go has v3 after pull"
|
||||
assert_file_exists "$MOUNT_CLONE/docs/manual.md" "docs/manual.md exists (renamed)"
|
||||
assert_file_not_exists "$MOUNT_CLONE/docs/guide.md" "docs/guide.md gone (renamed)"
|
||||
assert_file_not_exists "$MOUNT_CLONE/data/file-001.txt" "data/file-001.txt removed"
|
||||
assert_file_exists "$MOUNT_CLONE/data/file-050.txt" "data/file-050.txt exists"
|
||||
|
||||
FINAL_COUNT=$(find "$MOUNT_CLONE/data" -name '*.txt' | wc -l | tr -d ' ')
|
||||
assert_eq "$FINAL_COUNT" "49" "data/ has 49 files (50 added, 1 removed)"
|
||||
|
||||
# --- Phase 7: Verify git log integrity -----------------------------------
|
||||
|
||||
echo "--- Phase 7: Verify git log integrity ---"
|
||||
|
||||
cd "$MOUNT_CLONE"
|
||||
GIT_LOG=$(git log --format=%s)
|
||||
LOG_COUNT=$(echo "$GIT_LOG" | wc -l | tr -d ' ')
|
||||
assert_eq "$LOG_COUNT" "5" "git log shows 5 commits"
|
||||
|
||||
# Verify commit messages
|
||||
echo "$GIT_LOG" | grep -qF "initial commit" && pass "commit 1 message in log" || fail "commit 1 message missing"
|
||||
echo "$GIT_LOG" | grep -qF "expand data" && pass "commit 4 message in log" || fail "commit 4 message missing"
|
||||
echo "$GIT_LOG" | grep -qF "rename guide" && pass "commit 5 message in log" || fail "commit 5 message missing"
|
||||
|
||||
# --- Phase 8: Verify git status is clean ----------------------------------
|
||||
|
||||
echo "--- Phase 8: Verify git status is clean ---"
|
||||
|
||||
cd "$MOUNT_CLONE"
|
||||
STATUS=$(git status --porcelain)
|
||||
if [[ -z "$STATUS" ]]; then
|
||||
pass "git status is clean"
|
||||
else
|
||||
fail "git status has changes: $STATUS"
|
||||
fi
|
||||
|
||||
# --- Results ---------------------------------------------------------------
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo " Results: $PASS passed, $FAIL failed"
|
||||
echo "========================================"
|
||||
|
||||
if [[ "$FAIL" -gt 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
46
docker/compose/test-keycloak-s3.yml
Normal file
46
docker/compose/test-keycloak-s3.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
services:
|
||||
keycloak:
|
||||
image: quay.io/keycloak/keycloak:26.0.7
|
||||
command: ["start-dev", "--import-realm"]
|
||||
environment:
|
||||
KC_BOOTSTRAP_ADMIN_USERNAME: admin
|
||||
KC_BOOTSTRAP_ADMIN_PASSWORD: admin
|
||||
KC_HTTP_ENABLED: "true"
|
||||
KC_HOSTNAME: "http://keycloak:8080"
|
||||
KC_HOSTNAME_STRICT: "false"
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- ../../test/s3/iam/seaweedfs-test-realm.json:/opt/keycloak/data/import/seaweedfs-test-realm.json:ro
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "exec 3<>/dev/tcp/localhost/8080"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 60s
|
||||
|
||||
s3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
command:
|
||||
- -v=9
|
||||
- server
|
||||
- -ip=s3
|
||||
- -filer
|
||||
- -master.volumeSizeLimitMB=16
|
||||
- -volume
|
||||
- -volume.max=0
|
||||
- -volume.preStopSeconds=1
|
||||
- -s3
|
||||
- -s3.port=8333
|
||||
- -s3.config=/etc/seaweedfs/s3_config.json
|
||||
- -s3.iam.config=/etc/seaweedfs/iam_config.json
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 1
|
||||
volumes:
|
||||
- ../../test/s3/iam/test_config.json:/etc/seaweedfs/s3_config.json:ro
|
||||
- ../../test/s3/iam/iam_config_docker.json:/etc/seaweedfs/iam_config.json:ro
|
||||
ports:
|
||||
- "8333:8333"
|
||||
depends_on:
|
||||
keycloak:
|
||||
condition: service_healthy
|
||||
30
docker/compose/test-tarantool-filer.yml
Normal file
30
docker/compose/test-tarantool-filer.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
tarantool:
|
||||
image: chrislusf/tarantool_dev_env
|
||||
entrypoint: "tt start app -i"
|
||||
environment:
|
||||
APP_USER_PASSWORD: "app"
|
||||
CLIENT_USER_PASSWORD: "client"
|
||||
REPLICATOR_USER_PASSWORD: "replicator"
|
||||
STORAGE_USER_PASSWORD: "storage"
|
||||
network_mode: "host"
|
||||
ports:
|
||||
- "3303:3303"
|
||||
|
||||
s3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
command: "server -ip=127.0.0.1 -filer -master.volumeSizeLimitMB=16 -volume.max=0 -volume -volume.preStopSeconds=1 -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8000 -s3.allowDeleteBucketNotEmpty=false"
|
||||
volumes:
|
||||
- ./s3.json:/etc/seaweedfs/s3.json
|
||||
environment:
|
||||
WEED_LEVELDB2_ENABLED: "false"
|
||||
WEED_TARANTOOL_ENABLED: "true"
|
||||
WEED_TARANTOOL_ADDRESS: "127.0.0.1:3303"
|
||||
WEED_TARANTOOL_USER: "client"
|
||||
WEED_TARANTOOL_PASSWORD: "client"
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 1
|
||||
network_mode: "host"
|
||||
depends_on:
|
||||
- tarantool
|
||||
35
docker/compose/test-ydb-filer.yml
Normal file
35
docker/compose/test-ydb-filer.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
ydb:
|
||||
image: cr.yandex/yc/yandex-docker-local-ydb
|
||||
ports:
|
||||
- 2135:2135
|
||||
- 8765:8765
|
||||
- 2136:2136
|
||||
environment:
|
||||
- YDB_DEFAULT_LOG_LEVEL=DEBUG
|
||||
- GRPC_TLS_PORT=2135
|
||||
- GRPC_PORT=2136
|
||||
- MON_PORT=8765
|
||||
s3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
- 8888:8888
|
||||
- 8000:8000
|
||||
- 18888:18888
|
||||
command: "server -ip=s3 -filer -master.volumeSizeLimitMB=16 -volume.max=0 -volume -volume.preStopSeconds=1 -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8000 -s3.allowDeleteBucketNotEmpty=false"
|
||||
volumes:
|
||||
- ./s3.json:/etc/seaweedfs/s3.json
|
||||
environment:
|
||||
WEED_LEVELDB2_ENABLED: "false"
|
||||
WEED_YDB_ENABLED: "true"
|
||||
WEED_YDB_DSN: "grpc://ydb:2136/?database=local"
|
||||
WEED_YDB_PREFIX: "seaweedfs"
|
||||
YDB_ANONYMOUS_CREDENTIALS: 1
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 1
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 1
|
||||
depends_on:
|
||||
- ydb
|
||||
20
docker/compose/tls.env
Normal file
20
docker/compose/tls.env
Normal file
@@ -0,0 +1,20 @@
|
||||
WEED_GRPC_CA=/etc/seaweedfs/tls/SeaweedFS_CA.crt
|
||||
WEED_GRPC_ALLOWED_WILDCARD_DOMAIN=".dev"
|
||||
WEED_GRPC_MASTER_CERT=/etc/seaweedfs/tls/master01.dev.crt
|
||||
WEED_GRPC_MASTER_KEY=/etc/seaweedfs/tls/master01.dev.key
|
||||
WEED_GRPC_VOLUME_CERT=/etc/seaweedfs/tls/volume01.dev.crt
|
||||
WEED_GRPC_VOLUME_KEY=/etc/seaweedfs/tls/volume01.dev.key
|
||||
WEED_GRPC_FILER_CERT=/etc/seaweedfs/tls/filer01.dev.crt
|
||||
WEED_GRPC_FILER_KEY=/etc/seaweedfs/tls/filer01.dev.key
|
||||
WEED_GRPC_CLIENT_CERT=/etc/seaweedfs/tls/client01.dev.crt
|
||||
WEED_GRPC_CLIENT_KEY=/etc/seaweedfs/tls/client01.dev.key
|
||||
WEED_GRPC_MASTER_ALLOWED_COMMONNAMES="volume01.dev,master01.dev,filer01.dev,client01.dev"
|
||||
WEED_GRPC_VOLUME_ALLOWED_COMMONNAMES="volume01.dev,master01.dev,filer01.dev,client01.dev"
|
||||
WEED_GRPC_FILER_ALLOWED_COMMONNAMES="volume01.dev,master01.dev,filer01.dev,client01.dev"
|
||||
WEED_GRPC_CLIENT_ALLOWED_COMMONNAMES="volume01.dev,master01.dev,filer01.dev,client01.dev"
|
||||
WEED_HTTPS_CLIENT_ENABLE=true
|
||||
WEED_HTTPS_VOLUME_CERT=/etc/seaweedfs/tls/volume01.dev.crt
|
||||
WEED_HTTPS_VOLUME_KEY=/etc/seaweedfs/tls/volume01.dev.key
|
||||
WEED_HTTPS_VOLUME_CA=/etc/seaweedfs/tls/SeaweedFS_CA.crt
|
||||
#GRPC_GO_LOG_SEVERITY_LEVEL=info
|
||||
#GRPC_GO_LOG_VERBOSITY_LEVEL=2
|
||||
37
docker/compose/userstore.json
Normal file
37
docker/compose/userstore.json
Normal file
@@ -0,0 +1,37 @@
|
||||
[
|
||||
{
|
||||
"Username": "admin",
|
||||
"Password": "myadminpassword",
|
||||
"PublicKeys": [
|
||||
],
|
||||
"HomeDir": "/",
|
||||
"Permissions": {
|
||||
"/": ["*"]
|
||||
},
|
||||
"Uid": 0,
|
||||
"Gid": 0
|
||||
},
|
||||
{
|
||||
"Username": "user1",
|
||||
"Password": "myuser1password",
|
||||
"PublicKeys": [""],
|
||||
"HomeDir": "/user1",
|
||||
"Permissions": {
|
||||
"/user1": ["*"],
|
||||
"/public": ["read", "list","write"]
|
||||
},
|
||||
"Uid": 1111,
|
||||
"Gid": 1111
|
||||
},
|
||||
{
|
||||
"Username": "readonly",
|
||||
"Password": "myreadonlypassword",
|
||||
"PublicKeys": [],
|
||||
"HomeDir": "/public",
|
||||
"Permissions": {
|
||||
"/public": ["read", "list"]
|
||||
},
|
||||
"Uid": 1112,
|
||||
"Gid": 1112
|
||||
}
|
||||
]
|
||||
142
docker/entrypoint.sh
Executable file
142
docker/entrypoint.sh
Executable file
@@ -0,0 +1,142 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Enable FIPS 140-3 mode by default (Go 1.24+)
|
||||
# To disable: docker run -e GODEBUG=fips140=off ...
|
||||
export GODEBUG="${GODEBUG:+$GODEBUG,}fips140=on"
|
||||
|
||||
# Fix permissions for mounted volumes
|
||||
# If /data is mounted from host, it might have different ownership
|
||||
# Fix this by ensuring seaweed user owns the directory
|
||||
if [ "$(id -u)" = "0" ]; then
|
||||
# Running as root, check and fix permissions if needed
|
||||
SEAWEED_UID=$(id -u seaweed)
|
||||
SEAWEED_GID=$(id -g seaweed)
|
||||
|
||||
# Verify seaweed user and group exist
|
||||
if [ -z "$SEAWEED_UID" ] || [ -z "$SEAWEED_GID" ]; then
|
||||
echo "Error: 'seaweed' user or group not found. Cannot fix permissions." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DATA_UID=$(stat -c '%u' /data 2>/dev/null)
|
||||
DATA_GID=$(stat -c '%g' /data 2>/dev/null)
|
||||
|
||||
# Only run chown -R if ownership doesn't already match (avoids expensive
|
||||
# recursive chown on subsequent starts, and is a no-op on OpenShift when
|
||||
# fsGroup has already set correct ownership on the PVC).
|
||||
if [ "$DATA_UID" != "$SEAWEED_UID" ] || [ "$DATA_GID" != "$SEAWEED_GID" ]; then
|
||||
echo "Fixing /data ownership for seaweed user (uid=$SEAWEED_UID, gid=$SEAWEED_GID)"
|
||||
if ! chown -R seaweed:seaweed /data; then
|
||||
echo "Warning: Failed to change ownership of /data. This may cause permission errors." >&2
|
||||
echo "If /data is read-only or has mount issues, the application may fail to start." >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
# Use su-exec to drop privileges and run as seaweed user
|
||||
exec su-exec seaweed "$0" "$@"
|
||||
fi
|
||||
|
||||
isArgPassed() {
|
||||
# Match both `-flag` and `--flag` (and their `=value` forms): the Go fla9
|
||||
# library accepts both, and users may pick either form on the CLI.
|
||||
arg="$1"
|
||||
argWithEqualSign="$1="
|
||||
argDouble="-$1"
|
||||
argDoubleWithEqualSign="-$1="
|
||||
shift
|
||||
while [ $# -gt 0 ]; do
|
||||
passedArg="$1"
|
||||
shift
|
||||
case $passedArg in
|
||||
"$arg"|"$argDouble")
|
||||
return 0
|
||||
;;
|
||||
"$argWithEqualSign"*|"$argDoubleWithEqualSign"*)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
|
||||
'master')
|
||||
ARGS="-mdir=/data -volumeSizeLimitMB=1024"
|
||||
shift
|
||||
exec /usr/bin/weed -logtostderr=true master $ARGS $@
|
||||
;;
|
||||
|
||||
'volume')
|
||||
ARGS="-dir=/data -max=0"
|
||||
if isArgPassed "-max" "$@"; then
|
||||
ARGS="-dir=/data"
|
||||
fi
|
||||
shift
|
||||
exec /usr/bin/weed -logtostderr=true volume $ARGS $@
|
||||
;;
|
||||
|
||||
'volume-rust')
|
||||
ARGS="-dir /data -max 0"
|
||||
if isArgPassed "-max" "$@"; then
|
||||
ARGS="-dir /data"
|
||||
fi
|
||||
shift
|
||||
if [ ! -s /usr/bin/weed-volume ]; then
|
||||
echo "Error: Rust volume server is not available on this platform ($(uname -m))." >&2
|
||||
echo "Use 'volume' for the Go volume server instead." >&2
|
||||
exit 1
|
||||
fi
|
||||
exec /usr/bin/weed-volume $ARGS $@
|
||||
;;
|
||||
|
||||
'worker-rust')
|
||||
shift
|
||||
if [ ! -s /usr/bin/weed-worker ]; then
|
||||
echo "Error: Rust maintenance worker is not available on this platform ($(uname -m))." >&2
|
||||
echo "Use 'worker' for the Go maintenance worker instead." >&2
|
||||
exit 1
|
||||
fi
|
||||
exec /usr/bin/weed-worker "$@"
|
||||
;;
|
||||
|
||||
'server')
|
||||
ARGS="-dir=/data -volume.max=0 -master.volumeSizeLimitMB=1024"
|
||||
if isArgPassed "-volume.max" "$@"; then
|
||||
ARGS="-dir=/data -master.volumeSizeLimitMB=1024"
|
||||
fi
|
||||
shift
|
||||
exec /usr/bin/weed -logtostderr=true server $ARGS $@
|
||||
;;
|
||||
|
||||
'mini')
|
||||
ARGS="-dir=/data"
|
||||
if isArgPassed "-dir" "$@"; then
|
||||
ARGS=""
|
||||
fi
|
||||
shift
|
||||
exec /usr/bin/weed -logtostderr=true mini $ARGS $@
|
||||
;;
|
||||
|
||||
'filer')
|
||||
ARGS=""
|
||||
shift
|
||||
exec /usr/bin/weed -logtostderr=true filer $ARGS $@
|
||||
;;
|
||||
|
||||
's3')
|
||||
ARGS="-domainName=$S3_DOMAIN_NAME -key.file=$S3_KEY_FILE -cert.file=$S3_CERT_FILE"
|
||||
shift
|
||||
exec /usr/bin/weed -logtostderr=true s3 $ARGS $@
|
||||
;;
|
||||
|
||||
'shell')
|
||||
ARGS="-cluster=$SHELL_CLUSTER -filer=$SHELL_FILER -filerGroup=$SHELL_FILER_GROUP -master=$SHELL_MASTER -options=$SHELL_OPTIONS"
|
||||
shift
|
||||
exec echo "$@" | /usr/bin/weed -logtostderr=true shell $ARGS
|
||||
;;
|
||||
|
||||
*)
|
||||
exec /usr/bin/weed $@
|
||||
;;
|
||||
esac
|
||||
86
docker/entrypoint_e2e.sh
Executable file
86
docker/entrypoint_e2e.sh
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Simplified entrypoint for e2e testing
|
||||
#
|
||||
# This script intentionally runs as root for e2e test environments to:
|
||||
# 1. Simplify test setup and avoid permission-related test failures
|
||||
# 2. Eliminate dependency on Alpine-specific tools (su-exec) since we use Ubuntu base
|
||||
# 3. Focus testing on application logic rather than container security
|
||||
#
|
||||
# IMPORTANT: Production deployments should use Dockerfile.go_build with proper
|
||||
# user isolation via su-exec. This simplified approach is ONLY for testing.
|
||||
|
||||
isArgPassed() {
|
||||
arg="$1"
|
||||
argWithEqualSign="$1="
|
||||
shift
|
||||
while [ $# -gt 0 ]; do
|
||||
passedArg="$1"
|
||||
shift
|
||||
case $passedArg in
|
||||
"$arg")
|
||||
return 0
|
||||
;;
|
||||
"$argWithEqualSign"*)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
|
||||
'master')
|
||||
ARGS="-mdir=/data -volumeSizeLimitMB=1024"
|
||||
shift
|
||||
exec /usr/bin/weed -logtostderr=true master $ARGS "$@"
|
||||
;;
|
||||
|
||||
'volume')
|
||||
ARGS="-dir=/data -max=0"
|
||||
if isArgPassed "-max" "$@"; then
|
||||
ARGS="-dir=/data"
|
||||
fi
|
||||
shift
|
||||
exec /usr/bin/weed -logtostderr=true volume $ARGS "$@"
|
||||
;;
|
||||
|
||||
'server')
|
||||
ARGS="-dir=/data -volume.max=0 -master.volumeSizeLimitMB=1024"
|
||||
if isArgPassed "-volume.max" "$@"; then
|
||||
ARGS="-dir=/data -master.volumeSizeLimitMB=1024"
|
||||
fi
|
||||
shift
|
||||
exec /usr/bin/weed -logtostderr=true server $ARGS "$@"
|
||||
;;
|
||||
|
||||
'filer')
|
||||
ARGS=""
|
||||
shift
|
||||
exec /usr/bin/weed -logtostderr=true filer $ARGS "$@"
|
||||
;;
|
||||
|
||||
's3')
|
||||
ARGS="-domainName=$S3_DOMAIN_NAME -key.file=$S3_KEY_FILE -cert.file=$S3_CERT_FILE"
|
||||
shift
|
||||
exec /usr/bin/weed -logtostderr=true s3 $ARGS "$@"
|
||||
;;
|
||||
|
||||
'mount')
|
||||
shift
|
||||
exec /usr/bin/weed -logtostderr=true mount "$@"
|
||||
;;
|
||||
|
||||
'shell')
|
||||
ARGS="-cluster=$SHELL_CLUSTER -filer=$SHELL_FILER -filerGroup=$SHELL_FILER_GROUP -master=$SHELL_MASTER -options=$SHELL_OPTIONS"
|
||||
shift
|
||||
exec echo "$@" | /usr/bin/weed -logtostderr=true shell $ARGS
|
||||
;;
|
||||
|
||||
*)
|
||||
exec /usr/bin/weed "$@"
|
||||
;;
|
||||
esac
|
||||
|
||||
3
docker/filer.toml
Normal file
3
docker/filer.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
[leveldb2]
|
||||
enabled = true
|
||||
dir = "/data/filerldb2"
|
||||
19
docker/filer_foundationdb.toml
Normal file
19
docker/filer_foundationdb.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[filer.options]
|
||||
# with http DELETE, by default the filer would check whether a folder is empty.
|
||||
# recursive_delete will delete all sub folders and files, similar to "rm -Rf"
|
||||
recursive_delete = false
|
||||
|
||||
####################################################
|
||||
# FoundationDB store
|
||||
####################################################
|
||||
[foundationdb]
|
||||
enabled = true
|
||||
cluster_file = "/etc/foundationdb/fdb.cluster"
|
||||
api_version = 740
|
||||
# Optional: timeout for FDB operations (default: 10s)
|
||||
# timeout = "10s"
|
||||
# Optional: max retry delay for retryable errors (default: 1s)
|
||||
# max_retry_delay = "1s"
|
||||
# Optional: directory prefix for storing SeaweedFS data (default: "seaweedfs")
|
||||
# directory_prefix = "seaweedfs"
|
||||
|
||||
3
docker/filer_rocksdb.toml
Normal file
3
docker/filer_rocksdb.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
[rocksdb]
|
||||
enabled = true
|
||||
dir = "/data/filer_rocksdb"
|
||||
61
docker/get_fdb_checksum.sh
Executable file
61
docker/get_fdb_checksum.sh
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/bin/bash
|
||||
# Helper script to get SHA256 checksum for FoundationDB client package
|
||||
# Usage: ./get_fdb_checksum.sh <version> [arch]
|
||||
# Example: ./get_fdb_checksum.sh 7.4.5 amd64
|
||||
# Example: ./get_fdb_checksum.sh 7.4.5 arm64
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [ $# -lt 1 ] || [ $# -gt 2 ]; then
|
||||
echo "Usage: $0 <fdb_version> [arch]" >&2
|
||||
echo "Example: $0 7.4.5" >&2
|
||||
echo "Example: $0 7.4.5 arm64" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FDB_VERSION="$1"
|
||||
FDB_ARCH="${2:-amd64}"
|
||||
|
||||
case "$FDB_ARCH" in
|
||||
"amd64")
|
||||
CANONICAL_ARCH="amd64"
|
||||
PACKAGE_ARCH="amd64"
|
||||
;;
|
||||
"arm64"|"aarch64")
|
||||
CANONICAL_ARCH="arm64"
|
||||
PACKAGE_ARCH="aarch64"
|
||||
;;
|
||||
*)
|
||||
echo "Error: Architecture must be 'amd64', 'arm64', or 'aarch64'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
PACKAGE="foundationdb-clients_${FDB_VERSION}-1_${PACKAGE_ARCH}.deb"
|
||||
URL="https://github.com/apple/foundationdb/releases/download/${FDB_VERSION}/${PACKAGE}"
|
||||
|
||||
echo "Downloading FoundationDB ${FDB_VERSION} client package for ${FDB_ARCH}..."
|
||||
echo "URL: ${URL}"
|
||||
echo ""
|
||||
|
||||
# Download to temp directory
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
trap 'rm -rf "${TEMP_DIR}"' EXIT
|
||||
|
||||
cd "${TEMP_DIR}"
|
||||
if wget --timeout=30 --tries=3 -q "${URL}"; then
|
||||
CHECKSUM=$(sha256sum "${PACKAGE}" | awk '{print $1}')
|
||||
echo "✓ Download successful"
|
||||
echo ""
|
||||
echo "SHA256 Checksum:"
|
||||
echo "${CHECKSUM}"
|
||||
echo ""
|
||||
echo "Add this to Dockerfile.foundationdb_large:"
|
||||
echo " \"${FDB_VERSION}_${CANONICAL_ARCH}\") \\"
|
||||
echo " EXPECTED_SHA256=\"${CHECKSUM}\" ;; \\"
|
||||
else
|
||||
echo "✗ Failed to download package from ${URL}" >&2
|
||||
echo "Please verify the version number, architecture, and URL" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
30
docker/nginx/proxy.conf
Normal file
30
docker/nginx/proxy.conf
Normal file
@@ -0,0 +1,30 @@
|
||||
# HTTP 1.1 support
|
||||
proxy_http_version 1.1;
|
||||
#proxy_buffering off;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $proxy_connection;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
|
||||
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
|
||||
|
||||
# Mitigate httpoxy attack (see README for details)
|
||||
proxy_set_header Proxy "";
|
||||
|
||||
# aws default max_concurrent_requests 10
|
||||
# aws default multipart_threshold 8MB
|
||||
proxy_buffering on; # GET buffering or “X-Accel-Buffering” enables or disables buffering of a response;
|
||||
proxy_buffers 64 1m; # buffers used for reading a response from the proxied server, for a single connection
|
||||
proxy_buffer_size 8k; # maximum size of the data that nginx can receive from the server at a time is set
|
||||
proxy_busy_buffers_size 2m;
|
||||
|
||||
proxy_request_buffering on; # PUT buffering
|
||||
client_body_buffer_size 64m; # buffer size for reading client request body
|
||||
client_max_body_size 64m;
|
||||
|
||||
proxy_next_upstream error timeout non_idempotent http_500; # PUT request should be passed to the next server:
|
||||
proxy_connect_timeout 200ms;
|
||||
proxy_read_timeout 3s; #timeout is set only between two successive read operations
|
||||
proxy_send_timeout 3s; #timeout is set only between two successive write operations
|
||||
18
docker/prometheus/prometheus.yml
Normal file
18
docker/prometheus/prometheus.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
global:
|
||||
scrape_interval: 30s
|
||||
scrape_timeout: 10s
|
||||
|
||||
scrape_configs:
|
||||
- job_name: services
|
||||
metrics_path: /metrics
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'prometheus:9090'
|
||||
- 'master:9324'
|
||||
- 'volume:9325'
|
||||
- 'filer:9326'
|
||||
- 's3:9327'
|
||||
# A plugin worker publishes its own metrics when started with
|
||||
# -metricsPort (Go) or --metrics-port (Rust). 9328 continues the
|
||||
# series, since 9327 is already the S3 gateway's.
|
||||
# - 'worker:9328'
|
||||
59
docker/seaweedfs-compose.yml
Normal file
59
docker/seaweedfs-compose.yml
Normal file
@@ -0,0 +1,59 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
master:
|
||||
image: chrislusf/seaweedfs # use a remote image
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
- 9324:9324
|
||||
command: 'master -ip=master -ip.bind=0.0.0.0 -metricsPort=9324'
|
||||
volume:
|
||||
image: chrislusf/seaweedfs # use a remote image
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
- 9325:9325
|
||||
command: 'volume -ip=volume -master="master:9333" -ip.bind=0.0.0.0 -port=8080 -metricsPort=9325'
|
||||
depends_on:
|
||||
- master
|
||||
filer:
|
||||
image: chrislusf/seaweedfs # use a remote image
|
||||
ports:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
- 9326:9326
|
||||
command: 'filer -ip=filer -master="master:9333" -ip.bind=0.0.0.0 -metricsPort=9326'
|
||||
tty: true
|
||||
stdin_open: true
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
s3:
|
||||
image: chrislusf/seaweedfs # use a remote image
|
||||
ports:
|
||||
- 8333:8333
|
||||
- 9327:9327
|
||||
command: 's3 -filer="filer:8888" -ip.bind=0.0.0.0 -metricsPort=9327'
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
- filer
|
||||
webdav:
|
||||
image: chrislusf/seaweedfs # use a remote image
|
||||
ports:
|
||||
- 7333:7333
|
||||
command: 'webdav -filer="filer:8888"'
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
- filer
|
||||
prometheus:
|
||||
image: prom/prometheus:v2.21.0
|
||||
ports:
|
||||
- 9000:9090
|
||||
volumes:
|
||||
- ./prometheus:/etc/prometheus
|
||||
command: '--web.enable-lifecycle --config.file=/etc/prometheus/prometheus.yml'
|
||||
depends_on:
|
||||
- s3
|
||||
53
docker/seaweedfs-dev-compose.yml
Normal file
53
docker/seaweedfs-dev-compose.yml
Normal file
@@ -0,0 +1,53 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
master:
|
||||
image: chrislusf/seaweedfs:dev # use a remote dev image
|
||||
ports:
|
||||
- 9333:9333
|
||||
- 19333:19333
|
||||
command: 'master -ip=master -ip.bind=0.0.0.0'
|
||||
volume:
|
||||
image: chrislusf/seaweedfs:dev # use a remote dev image
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: 'volume -ip=volume -master="master:9333" -ip.bind=0.0.0.0 -port=8080'
|
||||
depends_on:
|
||||
- master
|
||||
filer:
|
||||
image: chrislusf/seaweedfs:dev # use a remote dev image
|
||||
ports:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
command: 'filer -ip=filer -master="master:9333" -ip.bind=0.0.0.0'
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
s3:
|
||||
image: chrislusf/seaweedfs:dev # use a remote dev image
|
||||
ports:
|
||||
- 8333:8333
|
||||
command: 's3 -filer="filer:8888" -ip.bind=0.0.0.0'
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
- filer
|
||||
webdav:
|
||||
image: chrislusf/seaweedfs:dev # use a remote dev image
|
||||
ports:
|
||||
- 7333:7333
|
||||
command: 'webdav -filer="filer:8888"'
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
- filer
|
||||
admin:
|
||||
image: chrislusf/seaweedfs:dev # use a remote dev image
|
||||
ports:
|
||||
- 23646:23646
|
||||
command: 'admin -master=master:9333'
|
||||
depends_on:
|
||||
- master
|
||||
- volume
|
||||
- filer
|
||||
12
docker/seaweedfs.sql
Normal file
12
docker/seaweedfs.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
CREATE DATABASE IF NOT EXISTS seaweedfs;
|
||||
CREATE USER IF NOT EXISTS 'seaweedfs'@'%' IDENTIFIED BY 'secret';
|
||||
GRANT ALL PRIVILEGES ON seaweedfs.* TO 'seaweedfs'@'%';
|
||||
FLUSH PRIVILEGES;
|
||||
USE seaweedfs;
|
||||
CREATE TABLE IF NOT EXISTS `filemeta` (
|
||||
`dirhash` BIGINT NOT NULL COMMENT 'first 64 bits of MD5 hash value of directory field',
|
||||
`name` VARCHAR(766) NOT NULL COMMENT 'directory or file name',
|
||||
`directory` TEXT NOT NULL COMMENT 'full path to parent directory',
|
||||
`meta` LONGBLOB,
|
||||
PRIMARY KEY (`dirhash`, `name`)
|
||||
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
34
docker/security.toml.example
Normal file
34
docker/security.toml.example
Normal file
@@ -0,0 +1,34 @@
|
||||
# Put this file to one of the location, with descending priority
|
||||
# ./security.toml
|
||||
# $HOME/.seaweedfs/security.toml
|
||||
# /etc/seaweedfs/security.toml
|
||||
# this file is read by master, volume server, filer, and worker
|
||||
|
||||
# comma separated origins allowed to make requests to the filer and s3 gateway.
|
||||
# enter in this format: https://domain.com, or http://localhost:port
|
||||
[cors.allowed_origins]
|
||||
values = "*"
|
||||
|
||||
# this jwt signing key is read by master and volume server, and it is used for write operations:
|
||||
# - the Master server generates the JWT, which can be used to write a certain file on a volume server
|
||||
# - the Volume server validates the JWT on writing
|
||||
# the jwt defaults to expire after 10 seconds.
|
||||
# [jwt.signing]
|
||||
# key = "V1JJVEVTRUNSRVRFWEFNUExFMTIzNDU2Nzg5MDEy" # Example: WRITESECRETEXAMPLE123456789012
|
||||
# this jwt signing key is read by master and volume server, and it is used for read operations:
|
||||
# - the Master server generates the JWT, which can be used to read a certain file on a volume server
|
||||
# - the Volume server validates the JWT on reading
|
||||
# [jwt.signing.read]
|
||||
# key = "UkVBRFNFQ1JFVUVYQU1QTEUxMjM0NTY3ODkwMTI=" # Example: READSECRETEXAMPLE123456789012
|
||||
# If this JWT key is configured, Filer only accepts writes over HTTP if they are signed with this JWT:
|
||||
# - f.e. the S3 API Shim generates the JWT
|
||||
# - the Filer server validates the JWT on writing
|
||||
# the jwt defaults to expire after 10 seconds.
|
||||
# [jwt.filer_signing]
|
||||
# key = "RklMRVJXUklURVNFQ1JFVEVYQU1QTEUxMjM0NTY3OA==" # Example: FILERWRITESECRETEXAMPLE12345678
|
||||
# If this JWT key is configured, Filer only accepts reads over HTTP if they are signed with this JWT:
|
||||
# - f.e. the S3 API Shim generates the JWT
|
||||
# - the Filer server validates the JWT on reading
|
||||
# the jwt defaults to expire after 10 seconds.
|
||||
# [jwt.filer_signing.read]
|
||||
# key = "RklMRVJSRUFEU0VDUkVURVhBTVBMRTEyMzQ1Njc4OQ==" # Example: FILERREADSECRETEXAMPLE123456789
|
||||
14
docker/tarantool/app-scm-1.rockspec
Normal file
14
docker/tarantool/app-scm-1.rockspec
Normal file
@@ -0,0 +1,14 @@
|
||||
package = 'app'
|
||||
version = 'scm-1'
|
||||
source = {
|
||||
url = '/dev/null',
|
||||
}
|
||||
dependencies = {
|
||||
'crud == 1.5.2-1',
|
||||
'expirationd == 1.6.0-1',
|
||||
'metrics-export-role == 0.3.0-1',
|
||||
'vshard == 0.1.32-1'
|
||||
}
|
||||
build = {
|
||||
type = 'none';
|
||||
}
|
||||
145
docker/tarantool/config.yaml
Normal file
145
docker/tarantool/config.yaml
Normal file
@@ -0,0 +1,145 @@
|
||||
config:
|
||||
context:
|
||||
app_user_password:
|
||||
from: env
|
||||
env: APP_USER_PASSWORD
|
||||
client_user_password:
|
||||
from: env
|
||||
env: CLIENT_USER_PASSWORD
|
||||
replicator_user_password:
|
||||
from: env
|
||||
env: REPLICATOR_USER_PASSWORD
|
||||
storage_user_password:
|
||||
from: env
|
||||
env: STORAGE_USER_PASSWORD
|
||||
|
||||
credentials:
|
||||
roles:
|
||||
crud-role:
|
||||
privileges:
|
||||
- permissions: [ "execute" ]
|
||||
lua_call: [ "crud.delete", "crud.get", "crud.upsert" ]
|
||||
users:
|
||||
app:
|
||||
password: '{{ context.app_user_password }}'
|
||||
roles: [ public, crud-role ]
|
||||
client:
|
||||
password: '{{ context.client_user_password }}'
|
||||
roles: [ super ]
|
||||
replicator:
|
||||
password: '{{ context.replicator_user_password }}'
|
||||
roles: [ replication ]
|
||||
storage:
|
||||
password: '{{ context.storage_user_password }}'
|
||||
roles: [ sharding ]
|
||||
|
||||
iproto:
|
||||
advertise:
|
||||
peer:
|
||||
login: replicator
|
||||
sharding:
|
||||
login: storage
|
||||
|
||||
sharding:
|
||||
bucket_count: 10000
|
||||
|
||||
metrics:
|
||||
include: [ all ]
|
||||
exclude: [ vinyl ]
|
||||
labels:
|
||||
alias: '{{ instance_name }}'
|
||||
|
||||
|
||||
groups:
|
||||
storages:
|
||||
roles:
|
||||
- roles.crud-storage
|
||||
- roles.expirationd
|
||||
- roles.metrics-export
|
||||
roles_cfg:
|
||||
roles.expirationd:
|
||||
cfg:
|
||||
metrics: true
|
||||
filer_metadata_task:
|
||||
space: filer_metadata
|
||||
is_expired: filer_metadata.is_expired
|
||||
options:
|
||||
atomic_iteration: true
|
||||
force: true
|
||||
index: 'expire_at_idx'
|
||||
iterator_type: GT
|
||||
start_key:
|
||||
- 0
|
||||
tuples_per_iteration: 10000
|
||||
app:
|
||||
module: storage
|
||||
sharding:
|
||||
roles: [ storage ]
|
||||
replication:
|
||||
failover: election
|
||||
database:
|
||||
use_mvcc_engine: true
|
||||
replicasets:
|
||||
storage-001:
|
||||
instances:
|
||||
storage-001-a:
|
||||
roles_cfg:
|
||||
roles.metrics-export:
|
||||
http:
|
||||
- listen: '0.0.0.0:8081'
|
||||
endpoints:
|
||||
- path: /metrics/prometheus/
|
||||
format: prometheus
|
||||
- path: /metrics/json
|
||||
format: json
|
||||
iproto:
|
||||
listen:
|
||||
- uri: 127.0.0.1:3301
|
||||
advertise:
|
||||
client: 127.0.0.1:3301
|
||||
storage-001-b:
|
||||
roles_cfg:
|
||||
roles.metrics-export:
|
||||
http:
|
||||
- listen: '0.0.0.0:8082'
|
||||
endpoints:
|
||||
- path: /metrics/prometheus/
|
||||
format: prometheus
|
||||
- path: /metrics/json
|
||||
format: json
|
||||
iproto:
|
||||
listen:
|
||||
- uri: 127.0.0.1:3302
|
||||
advertise:
|
||||
client: 127.0.0.1:3302
|
||||
routers:
|
||||
roles:
|
||||
- roles.crud-router
|
||||
- roles.metrics-export
|
||||
roles_cfg:
|
||||
roles.crud-router:
|
||||
stats: true
|
||||
stats_driver: metrics
|
||||
stats_quantiles: true
|
||||
app:
|
||||
module: router
|
||||
sharding:
|
||||
roles: [ router ]
|
||||
replicasets:
|
||||
router-001:
|
||||
instances:
|
||||
router-001-a:
|
||||
roles_cfg:
|
||||
roles.metrics-export:
|
||||
http:
|
||||
- listen: '0.0.0.0:8083'
|
||||
endpoints:
|
||||
- path: /metrics/prometheus/
|
||||
format: prometheus
|
||||
- path: /metrics/json
|
||||
format: json
|
||||
iproto:
|
||||
listen:
|
||||
- uri: 127.0.0.1:3303
|
||||
advertise:
|
||||
client: 127.0.0.1:3303
|
||||
7
docker/tarantool/instances.yaml
Normal file
7
docker/tarantool/instances.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
storage-001-a:
|
||||
|
||||
storage-001-b:
|
||||
|
||||
router-001-a:
|
||||
|
||||
77
docker/tarantool/router.lua
Normal file
77
docker/tarantool/router.lua
Normal file
@@ -0,0 +1,77 @@
|
||||
local vshard = require('vshard')
|
||||
local log = require('log')
|
||||
|
||||
-- Bootstrap the vshard router.
|
||||
while true do
|
||||
local ok, err = vshard.router.bootstrap({
|
||||
if_not_bootstrapped = true,
|
||||
})
|
||||
if ok then
|
||||
break
|
||||
end
|
||||
log.info(('Router bootstrap error: %s'):format(err))
|
||||
end
|
||||
|
||||
-- functions for filer_metadata space
|
||||
local filer_metadata = {
|
||||
delete_by_directory_idx = function(directory)
|
||||
-- find all storages
|
||||
local storages = require('vshard').router.routeall()
|
||||
-- on each storage
|
||||
for _, storage in pairs(storages) do
|
||||
-- call local function
|
||||
local result, err = storage:callrw('filer_metadata.delete_by_directory_idx', { directory })
|
||||
-- check for error
|
||||
if err then
|
||||
error("Failed to call function on storage: " .. tostring(err))
|
||||
end
|
||||
end
|
||||
-- return
|
||||
return true
|
||||
end,
|
||||
find_by_directory_idx_and_name = function(dirPath, startFileName, includeStartFile, limit)
|
||||
-- init results
|
||||
local results = {}
|
||||
-- find all storages
|
||||
local storages = require('vshard').router.routeall()
|
||||
-- on each storage
|
||||
for _, storage in pairs(storages) do
|
||||
-- call local function
|
||||
local result, err = storage:callro('filer_metadata.find_by_directory_idx_and_name', {
|
||||
dirPath,
|
||||
startFileName,
|
||||
includeStartFile,
|
||||
limit
|
||||
})
|
||||
-- check for error
|
||||
if err then
|
||||
error("Failed to call function on storage: " .. tostring(err))
|
||||
end
|
||||
-- add to results
|
||||
for _, tuple in ipairs(result) do
|
||||
table.insert(results, tuple)
|
||||
end
|
||||
end
|
||||
-- sort
|
||||
table.sort(results, function(a, b) return a[3] < b[3] end)
|
||||
-- apply limit
|
||||
if #results > limit then
|
||||
local limitedResults = {}
|
||||
for i = 1, limit do
|
||||
table.insert(limitedResults, results[i])
|
||||
end
|
||||
results = limitedResults
|
||||
end
|
||||
-- return
|
||||
return results
|
||||
end,
|
||||
}
|
||||
|
||||
rawset(_G, 'filer_metadata', filer_metadata)
|
||||
|
||||
-- register functions for filer_metadata space, set grants
|
||||
for name, _ in pairs(filer_metadata) do
|
||||
box.schema.func.create('filer_metadata.' .. name, { if_not_exists = true })
|
||||
box.schema.user.grant('app', 'execute', 'function', 'filer_metadata.' .. name, { if_not_exists = true })
|
||||
box.schema.user.grant('client', 'execute', 'function', 'filer_metadata.' .. name, { if_not_exists = true })
|
||||
end
|
||||
97
docker/tarantool/storage.lua
Normal file
97
docker/tarantool/storage.lua
Normal file
@@ -0,0 +1,97 @@
|
||||
box.watch('box.status', function()
|
||||
if box.info.ro then
|
||||
return
|
||||
end
|
||||
|
||||
-- ====================================
|
||||
-- key_value space
|
||||
-- ====================================
|
||||
box.schema.create_space('key_value', {
|
||||
format = {
|
||||
{ name = 'key', type = 'string' },
|
||||
{ name = 'bucket_id', type = 'unsigned' },
|
||||
{ name = 'value', type = 'string' }
|
||||
},
|
||||
if_not_exists = true
|
||||
})
|
||||
|
||||
-- create key_value space indexes
|
||||
box.space.key_value:create_index('id', {type = 'tree', parts = { 'key' }, unique = true, if_not_exists = true})
|
||||
box.space.key_value:create_index('bucket_id', { type = 'tree', parts = { 'bucket_id' }, unique = false, if_not_exists = true })
|
||||
|
||||
-- ====================================
|
||||
-- filer_metadata space
|
||||
-- ====================================
|
||||
box.schema.create_space('filer_metadata', {
|
||||
format = {
|
||||
{ name = 'directory', type = 'string' },
|
||||
{ name = 'bucket_id', type = 'unsigned' },
|
||||
{ name = 'name', type = 'string' },
|
||||
{ name = 'expire_at', type = 'unsigned' },
|
||||
{ name = 'data', type = 'string' }
|
||||
},
|
||||
if_not_exists = true
|
||||
})
|
||||
|
||||
-- create filer_metadata space indexes
|
||||
box.space.filer_metadata:create_index('id', {type = 'tree', parts = { 'directory', 'name' }, unique = true, if_not_exists = true})
|
||||
box.space.filer_metadata:create_index('bucket_id', { type = 'tree', parts = { 'bucket_id' }, unique = false, if_not_exists = true })
|
||||
box.space.filer_metadata:create_index('directory_idx', { type = 'tree', parts = { 'directory' }, unique = false, if_not_exists = true })
|
||||
box.space.filer_metadata:create_index('name_idx', { type = 'tree', parts = { 'name' }, unique = false, if_not_exists = true })
|
||||
box.space.filer_metadata:create_index('expire_at_idx', { type = 'tree', parts = { 'expire_at' }, unique = false, if_not_exists = true})
|
||||
end)
|
||||
|
||||
-- functions for filer_metadata space
|
||||
local filer_metadata = {
|
||||
delete_by_directory_idx = function(directory)
|
||||
local space = box.space.filer_metadata
|
||||
local index = space.index.directory_idx
|
||||
-- for each found directory
|
||||
for _, tuple in index:pairs({ directory }, { iterator = 'EQ' }) do
|
||||
space:delete({ tuple[1], tuple[3] })
|
||||
end
|
||||
return true
|
||||
end,
|
||||
find_by_directory_idx_and_name = function(dirPath, startFileName, includeStartFile, limit)
|
||||
local space = box.space.filer_metadata
|
||||
local directory_idx = space.index.directory_idx
|
||||
-- choose filter name function
|
||||
local filter_filename_func
|
||||
if includeStartFile then
|
||||
filter_filename_func = function(value) return value >= startFileName end
|
||||
else
|
||||
filter_filename_func = function(value) return value > startFileName end
|
||||
end
|
||||
-- init results
|
||||
local results = {}
|
||||
-- for each found directory
|
||||
for _, tuple in directory_idx:pairs({ dirPath }, { iterator = 'EQ' }) do
|
||||
-- filter by name
|
||||
if filter_filename_func(tuple[3]) then
|
||||
table.insert(results, tuple)
|
||||
end
|
||||
end
|
||||
-- sort
|
||||
table.sort(results, function(a, b) return a[3] < b[3] end)
|
||||
-- apply limit
|
||||
if #results > limit then
|
||||
local limitedResults = {}
|
||||
for i = 1, limit do
|
||||
table.insert(limitedResults, results[i])
|
||||
end
|
||||
results = limitedResults
|
||||
end
|
||||
-- return
|
||||
return results
|
||||
end,
|
||||
is_expired = function(args, tuple)
|
||||
return (tuple[4] > 0) and (require('fiber').time() > tuple[4])
|
||||
end
|
||||
}
|
||||
|
||||
-- register functions for filer_metadata space, set grants
|
||||
rawset(_G, 'filer_metadata', filer_metadata)
|
||||
for name, _ in pairs(filer_metadata) do
|
||||
box.schema.func.create('filer_metadata.' .. name, { setuid = true, if_not_exists = true })
|
||||
box.schema.user.grant('storage', 'execute', 'function', 'filer_metadata.' .. name, { if_not_exists = true })
|
||||
end
|
||||
274
docker/test.py
Executable file
274
docker/test.py
Executable file
@@ -0,0 +1,274 @@
|
||||
#!/usr/bin/env python3
|
||||
# /// script
|
||||
# requires-python = ">=3.12"
|
||||
# dependencies = [
|
||||
# "boto3",
|
||||
# ]
|
||||
# ///
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import random
|
||||
import string
|
||||
import subprocess
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
|
||||
import boto3
|
||||
|
||||
REGION_NAME = "us-east-1"
|
||||
|
||||
|
||||
class Actions(str, Enum):
|
||||
Get = "Get"
|
||||
Put = "Put"
|
||||
List = "List"
|
||||
|
||||
|
||||
def get_user_dir(bucket_name, user, with_bucket=True):
|
||||
if with_bucket:
|
||||
return f"{bucket_name}/user-id-{user}"
|
||||
|
||||
return f"user-id-{user}"
|
||||
|
||||
|
||||
def create_power_user():
|
||||
power_user_key = "power_user_key"
|
||||
power_user_secret = "power_user_secret"
|
||||
command = f"s3.configure -apply -user poweruser -access_key {power_user_key} -secret_key {power_user_secret} -actions Admin"
|
||||
print("Creating Power User...")
|
||||
subprocess.run(
|
||||
["docker", "exec", "-i", "seaweedfs-master-1", "weed", "shell"],
|
||||
input=command,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
print(
|
||||
f"Power User created with key: {power_user_key} and secret: {power_user_secret}"
|
||||
)
|
||||
return power_user_key, power_user_secret
|
||||
|
||||
|
||||
def create_bucket(s3_client, bucket_name):
|
||||
print(f"Creating Bucket {bucket_name}...")
|
||||
s3_client.create_bucket(Bucket=bucket_name)
|
||||
print(f"Bucket {bucket_name} created.")
|
||||
|
||||
|
||||
def upload_file(s3_client, bucket_name, user, file_path, custom_remote_path=None):
|
||||
user_dir = get_user_dir(bucket_name, user, with_bucket=False)
|
||||
if custom_remote_path:
|
||||
remote_path = custom_remote_path
|
||||
else:
|
||||
remote_path = f"{user_dir}/{str(Path(file_path).name)}"
|
||||
|
||||
print(f"Uploading {file_path} for {user}... on {user_dir}")
|
||||
|
||||
s3_client.upload_file(file_path, bucket_name, remote_path)
|
||||
print(f"File {file_path} uploaded for {user}.")
|
||||
|
||||
|
||||
def create_user(iam_client, user):
|
||||
print(f"Creating user {user}...")
|
||||
response = iam_client.create_access_key(UserName=user)
|
||||
print(
|
||||
f"User {user} created with access key: {response['AccessKey']['AccessKeyId']}"
|
||||
)
|
||||
return response
|
||||
|
||||
|
||||
def list_files(s3_client, bucket_name, path=None):
|
||||
if path is None:
|
||||
path = ""
|
||||
print(f"Listing files of s3://{bucket_name}/{path}...")
|
||||
try:
|
||||
response = s3_client.list_objects_v2(Bucket=bucket_name, Prefix=path)
|
||||
if "Contents" in response:
|
||||
for obj in response["Contents"]:
|
||||
print(f"\t - {obj['Key']}")
|
||||
else:
|
||||
print("No files found.")
|
||||
except Exception as e:
|
||||
print(f"Error listing files: {e}")
|
||||
|
||||
|
||||
def create_policy_for_user(
|
||||
iam_client, user, bucket_name, actions=[Actions.Get, Actions.List]
|
||||
):
|
||||
print(f"Creating policy for {user} on {bucket_name}...")
|
||||
policy_document = {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [f"s3:{action.value}*" for action in actions],
|
||||
"Resource": [
|
||||
f"arn:aws:s3:::{get_user_dir(bucket_name, user)}/*",
|
||||
],
|
||||
}
|
||||
],
|
||||
}
|
||||
policy_name = f"{user}-{bucket_name}-full-access"
|
||||
|
||||
policy_json = json.dumps(policy_document)
|
||||
filepath = f"/tmp/{policy_name}.json"
|
||||
with open(filepath, "w") as f:
|
||||
f.write(json.dumps(policy_document, indent=2))
|
||||
|
||||
iam_client.put_user_policy(
|
||||
PolicyName=policy_name, PolicyDocument=policy_json, UserName=user
|
||||
)
|
||||
print(f"Policy for {user} on {bucket_name} created.")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="SeaweedFS S3 Test Script")
|
||||
parser.add_argument(
|
||||
"--s3-url", default="http://127.0.0.1:8333", help="S3 endpoint URL"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--iam-url", default="http://127.0.0.1:8111", help="IAM endpoint URL"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
bucket_name = (
|
||||
f"test-bucket-{''.join(random.choices(string.digits + 'abcdef', k=8))}"
|
||||
)
|
||||
sentinel_file = "/tmp/SENTINEL"
|
||||
with open(sentinel_file, "w") as f:
|
||||
f.write("Hello World")
|
||||
print(f"SENTINEL file created at {sentinel_file}")
|
||||
|
||||
power_user_key, power_user_secret = create_power_user()
|
||||
|
||||
admin_s3_client = get_s3_client(args, power_user_key, power_user_secret)
|
||||
iam_client = get_iam_client(args, power_user_key, power_user_secret)
|
||||
|
||||
create_bucket(admin_s3_client, bucket_name)
|
||||
upload_file(admin_s3_client, bucket_name, "Alice", sentinel_file)
|
||||
upload_file(admin_s3_client, bucket_name, "Bob", sentinel_file)
|
||||
list_files(admin_s3_client, bucket_name)
|
||||
|
||||
alice_user_info = create_user(iam_client, "Alice")
|
||||
bob_user_info = create_user(iam_client, "Bob")
|
||||
|
||||
alice_key = alice_user_info["AccessKey"]["AccessKeyId"]
|
||||
alice_secret = alice_user_info["AccessKey"]["SecretAccessKey"]
|
||||
bob_key = bob_user_info["AccessKey"]["AccessKeyId"]
|
||||
bob_secret = bob_user_info["AccessKey"]["SecretAccessKey"]
|
||||
|
||||
# Make sure Admin can read any files
|
||||
list_files(admin_s3_client, bucket_name)
|
||||
list_files(
|
||||
admin_s3_client,
|
||||
bucket_name,
|
||||
get_user_dir(bucket_name, "Alice", with_bucket=False),
|
||||
)
|
||||
list_files(
|
||||
admin_s3_client,
|
||||
bucket_name,
|
||||
get_user_dir(bucket_name, "Bob", with_bucket=False),
|
||||
)
|
||||
|
||||
# Create read policy for Alice and Bob
|
||||
create_policy_for_user(iam_client, "Alice", bucket_name)
|
||||
create_policy_for_user(iam_client, "Bob", bucket_name)
|
||||
|
||||
alice_s3_client = get_s3_client(args, alice_key, alice_secret)
|
||||
|
||||
# Make sure Alice can read her files
|
||||
list_files(
|
||||
alice_s3_client,
|
||||
bucket_name,
|
||||
get_user_dir(bucket_name, "Alice", with_bucket=False) + "/",
|
||||
)
|
||||
|
||||
# Make sure Bob can read his files
|
||||
bob_s3_client = get_s3_client(args, bob_key, bob_secret)
|
||||
list_files(
|
||||
bob_s3_client,
|
||||
bucket_name,
|
||||
get_user_dir(bucket_name, "Bob", with_bucket=False) + "/",
|
||||
)
|
||||
|
||||
# Update policy to include write
|
||||
create_policy_for_user(iam_client, "Alice", bucket_name, actions=[Actions.Put, Actions.Get, Actions.List]) # fmt: off
|
||||
create_policy_for_user(iam_client, "Bob", bucket_name, actions=[Actions.Put, Actions.Get, Actions.List]) # fmt: off
|
||||
|
||||
print("############################# Make sure Alice can write her files")
|
||||
upload_file(
|
||||
alice_s3_client,
|
||||
bucket_name,
|
||||
"Alice",
|
||||
sentinel_file,
|
||||
custom_remote_path=f"{get_user_dir(bucket_name, 'Alice', with_bucket=False)}/SENTINEL_by_Alice",
|
||||
)
|
||||
|
||||
|
||||
print("############################# Make sure Bob can write his files")
|
||||
upload_file(
|
||||
bob_s3_client,
|
||||
bucket_name,
|
||||
"Bob",
|
||||
sentinel_file,
|
||||
custom_remote_path=f"{get_user_dir(bucket_name, 'Bob', with_bucket=False)}/SENTINEL_by_Bob",
|
||||
)
|
||||
|
||||
|
||||
print("############################# Make sure Alice can read her new files")
|
||||
list_files(
|
||||
alice_s3_client,
|
||||
bucket_name,
|
||||
get_user_dir(bucket_name, "Alice", with_bucket=False) + "/",
|
||||
)
|
||||
|
||||
|
||||
print("############################# Make sure Bob can read his new files")
|
||||
list_files(
|
||||
bob_s3_client,
|
||||
bucket_name,
|
||||
get_user_dir(bucket_name, "Bob", with_bucket=False) + "/",
|
||||
)
|
||||
|
||||
|
||||
print("############################# Make sure Bob cannot read Alice's files")
|
||||
list_files(
|
||||
bob_s3_client,
|
||||
bucket_name,
|
||||
get_user_dir(bucket_name, "Alice", with_bucket=False) + "/",
|
||||
)
|
||||
|
||||
print("############################# Make sure Alice cannot read Bob's files")
|
||||
|
||||
list_files(
|
||||
alice_s3_client,
|
||||
bucket_name,
|
||||
get_user_dir(bucket_name, "Bob", with_bucket=False) + "/",
|
||||
)
|
||||
|
||||
|
||||
|
||||
def get_iam_client(args, access_key, secret_key):
|
||||
iam_client = boto3.client(
|
||||
"iam",
|
||||
endpoint_url=args.iam_url,
|
||||
region_name=REGION_NAME,
|
||||
aws_access_key_id=access_key,
|
||||
aws_secret_access_key=secret_key,
|
||||
)
|
||||
return iam_client
|
||||
|
||||
|
||||
def get_s3_client(args, access_key, secret_key):
|
||||
s3_client = boto3.client(
|
||||
"s3",
|
||||
endpoint_url=args.s3_url,
|
||||
region_name=REGION_NAME,
|
||||
aws_access_key_id=access_key,
|
||||
aws_secret_access_key=secret_key,
|
||||
)
|
||||
return s3_client
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
0
docker/weed-volume-prebuilt/.gitkeep
Normal file
0
docker/weed-volume-prebuilt/.gitkeep
Normal file
0
docker/weed-worker-prebuilt/.gitkeep
Normal file
0
docker/weed-worker-prebuilt/.gitkeep
Normal file
Reference in New Issue
Block a user