mirror of
https://github.com/rustfs/rustfs.git
synced 2026-01-17 01:30:33 +00:00
feat: Add comprehensive Docker build pipeline for multi-architecture images
This commit is contained in:
300
.github/workflows/docker.yml
vendored
Normal file
300
.github/workflows/docker.yml
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
name: Build and Push Docker Images
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
push_to_registry:
|
||||
description: 'Push images to registry'
|
||||
required: false
|
||||
default: 'true'
|
||||
type: boolean
|
||||
|
||||
env:
|
||||
REGISTRY_IMAGE_DOCKERHUB: rustfs/rustfs
|
||||
REGISTRY_IMAGE_GHCR: ghcr.io/${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
# Skip duplicate job runs
|
||||
skip-check:
|
||||
permissions:
|
||||
actions: write
|
||||
contents: read
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
should_skip: ${{ steps.skip_check.outputs.should_skip }}
|
||||
steps:
|
||||
- id: skip_check
|
||||
uses: fkirc/skip-duplicate-actions@v5
|
||||
with:
|
||||
concurrent_skipping: 'same_content_newer'
|
||||
cancel_others: true
|
||||
paths_ignore: '["*.md", "docs/**"]'
|
||||
|
||||
# Build RustFS binary for different platforms
|
||||
build-binary:
|
||||
needs: skip-check
|
||||
if: needs.skip-check.outputs.should_skip != 'true'
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- target: x86_64-unknown-linux-musl
|
||||
os: ubuntu-latest
|
||||
arch: amd64
|
||||
- target: aarch64-unknown-linux-musl
|
||||
os: ubuntu-latest
|
||||
arch: arm64
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust toolchain
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Install cross-compilation dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y musl-tools
|
||||
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-musl" ]; then
|
||||
sudo apt-get install -y gcc-aarch64-linux-gnu
|
||||
fi
|
||||
|
||||
- name: Install protoc
|
||||
uses: arduino/setup-protoc@v3
|
||||
with:
|
||||
version: "31.1"
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install flatc
|
||||
uses: Nugine/setup-flatc@v1
|
||||
with:
|
||||
version: "25.2.10"
|
||||
|
||||
- name: Cache cargo dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-cargo-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cargo-${{ matrix.target }}-
|
||||
${{ runner.os }}-cargo-
|
||||
|
||||
- name: Build RustFS binary
|
||||
run: |
|
||||
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=aarch64-linux-gnu-gcc
|
||||
cargo build --release --target ${{ matrix.target }} --bin rustfs
|
||||
|
||||
- name: Upload binary artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: rustfs-${{ matrix.arch }}
|
||||
path: target/${{ matrix.target }}/release/rustfs
|
||||
retention-days: 1
|
||||
|
||||
# Build and push Docker images
|
||||
build-images:
|
||||
needs: [skip-check, build-binary]
|
||||
if: needs.skip-check.outputs.should_skip != 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
matrix:
|
||||
image-type: [production, ubuntu, rockylinux, devenv]
|
||||
platform: [linux/amd64, linux/arm64]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download binary artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./artifacts
|
||||
|
||||
- name: Setup binary files
|
||||
run: |
|
||||
mkdir -p target/x86_64-unknown-linux-musl/release
|
||||
mkdir -p target/aarch64-unknown-linux-musl/release
|
||||
cp artifacts/rustfs-amd64/rustfs target/x86_64-unknown-linux-musl/release/
|
||||
cp artifacts/rustfs-arm64/rustfs target/aarch64-unknown-linux-musl/release/
|
||||
chmod +x target/*/release/rustfs
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/'))
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/'))
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set Dockerfile and context
|
||||
id: dockerfile
|
||||
run: |
|
||||
case "${{ matrix.image-type }}" in
|
||||
production)
|
||||
echo "dockerfile=Dockerfile" >> $GITHUB_OUTPUT
|
||||
echo "context=." >> $GITHUB_OUTPUT
|
||||
echo "suffix=" >> $GITHUB_OUTPUT
|
||||
;;
|
||||
ubuntu)
|
||||
echo "dockerfile=.docker/Dockerfile.ubuntu22.04" >> $GITHUB_OUTPUT
|
||||
echo "context=." >> $GITHUB_OUTPUT
|
||||
echo "suffix=-ubuntu22.04" >> $GITHUB_OUTPUT
|
||||
;;
|
||||
rockylinux)
|
||||
echo "dockerfile=.docker/Dockerfile.rockylinux9.3" >> $GITHUB_OUTPUT
|
||||
echo "context=." >> $GITHUB_OUTPUT
|
||||
echo "suffix=-rockylinux9.3" >> $GITHUB_OUTPUT
|
||||
;;
|
||||
devenv)
|
||||
echo "dockerfile=.docker/Dockerfile.devenv" >> $GITHUB_OUTPUT
|
||||
echo "context=." >> $GITHUB_OUTPUT
|
||||
echo "suffix=-devenv" >> $GITHUB_OUTPUT
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
${{ env.REGISTRY_IMAGE_DOCKERHUB }}
|
||||
${{ env.REGISTRY_IMAGE_GHCR }}
|
||||
tags: |
|
||||
type=ref,event=branch,suffix=${{ steps.dockerfile.outputs.suffix }}
|
||||
type=ref,event=pr,suffix=${{ steps.dockerfile.outputs.suffix }}
|
||||
type=semver,pattern={{version}},suffix=${{ steps.dockerfile.outputs.suffix }}
|
||||
type=semver,pattern={{major}}.{{minor}},suffix=${{ steps.dockerfile.outputs.suffix }}
|
||||
type=semver,pattern={{major}},suffix=${{ steps.dockerfile.outputs.suffix }}
|
||||
type=raw,value=latest,suffix=${{ steps.dockerfile.outputs.suffix }},enable={{is_default_branch}}
|
||||
flavor: |
|
||||
latest=false
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: ${{ steps.dockerfile.outputs.context }}
|
||||
file: ${{ steps.dockerfile.outputs.dockerfile }}
|
||||
platforms: ${{ matrix.platform }}
|
||||
push: ${{ github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha,scope=${{ matrix.image-type }}-${{ matrix.platform }}
|
||||
cache-to: type=gha,mode=max,scope=${{ matrix.image-type }}-${{ matrix.platform }}
|
||||
build-args: |
|
||||
BUILDTIME=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}
|
||||
VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}
|
||||
REVISION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }}
|
||||
|
||||
# Create multi-arch manifests
|
||||
create-manifest:
|
||||
needs: [skip-check, build-images]
|
||||
if: needs.skip-check.outputs.should_skip != 'true' && github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/'))
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
image-type: [production, ubuntu, rockylinux, devenv]
|
||||
steps:
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set image suffix
|
||||
id: suffix
|
||||
run: |
|
||||
case "${{ matrix.image-type }}" in
|
||||
production) echo "suffix=" >> $GITHUB_OUTPUT ;;
|
||||
ubuntu) echo "suffix=-ubuntu22.04" >> $GITHUB_OUTPUT ;;
|
||||
rockylinux) echo "suffix=-rockylinux9.3" >> $GITHUB_OUTPUT ;;
|
||||
devenv) echo "suffix=-devenv" >> $GITHUB_OUTPUT ;;
|
||||
esac
|
||||
|
||||
- name: Create and push manifest
|
||||
run: |
|
||||
# Set tag based on ref
|
||||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
TAG=${GITHUB_REF#refs/tags/}
|
||||
else
|
||||
TAG="main"
|
||||
fi
|
||||
|
||||
SUFFIX="${{ steps.suffix.outputs.suffix }}"
|
||||
|
||||
# Docker Hub manifest
|
||||
docker buildx imagetools create -t ${REGISTRY_IMAGE_DOCKERHUB}:${TAG}${SUFFIX} \
|
||||
${REGISTRY_IMAGE_DOCKERHUB}:${TAG}${SUFFIX}-linux-amd64 \
|
||||
${REGISTRY_IMAGE_DOCKERHUB}:${TAG}${SUFFIX}-linux-arm64
|
||||
|
||||
# GitHub Container Registry manifest
|
||||
docker buildx imagetools create -t ${REGISTRY_IMAGE_GHCR}:${TAG}${SUFFIX} \
|
||||
${REGISTRY_IMAGE_GHCR}:${TAG}${SUFFIX}-linux-amd64 \
|
||||
${REGISTRY_IMAGE_GHCR}:${TAG}${SUFFIX}-linux-arm64
|
||||
|
||||
# Create latest tag for main branch
|
||||
if [[ $GITHUB_REF == refs/heads/main ]]; then
|
||||
docker buildx imagetools create -t ${REGISTRY_IMAGE_DOCKERHUB}:latest${SUFFIX} \
|
||||
${REGISTRY_IMAGE_DOCKERHUB}:${TAG}${SUFFIX}-linux-amd64 \
|
||||
${REGISTRY_IMAGE_DOCKERHUB}:${TAG}${SUFFIX}-linux-arm64
|
||||
|
||||
docker buildx imagetools create -t ${REGISTRY_IMAGE_GHCR}:latest${SUFFIX} \
|
||||
${REGISTRY_IMAGE_GHCR}:${TAG}${SUFFIX}-linux-amd64 \
|
||||
${REGISTRY_IMAGE_GHCR}:${TAG}${SUFFIX}-linux-arm64
|
||||
fi
|
||||
|
||||
# Security scanning
|
||||
security-scan:
|
||||
needs: [skip-check, build-images]
|
||||
if: needs.skip-check.outputs.should_skip != 'true'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
image-type: [production]
|
||||
steps:
|
||||
- name: Run Trivy vulnerability scanner
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
image-ref: ${{ env.REGISTRY_IMAGE_GHCR }}:main
|
||||
format: 'sarif'
|
||||
output: 'trivy-results.sarif'
|
||||
|
||||
- name: Upload Trivy scan results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
if: always()
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
119
Dockerfile.multi-stage
Normal file
119
Dockerfile.multi-stage
Normal file
@@ -0,0 +1,119 @@
|
||||
# Multi-stage Dockerfile for RustFS
|
||||
# Supports cross-compilation for amd64 and arm64 architectures
|
||||
ARG TARGETPLATFORM
|
||||
ARG BUILDPLATFORM
|
||||
|
||||
# Build stage
|
||||
FROM --platform=$BUILDPLATFORM rust:1.85-bookworm AS builder
|
||||
|
||||
# Install required build dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
wget \
|
||||
git \
|
||||
curl \
|
||||
unzip \
|
||||
gcc \
|
||||
pkg-config \
|
||||
libssl-dev \
|
||||
lld \
|
||||
musl-tools \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install cross-compilation tools for ARM64
|
||||
RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
|
||||
apt-get update && \
|
||||
apt-get install -y gcc-aarch64-linux-gnu && \
|
||||
rm -rf /var/lib/apt/lists/*; \
|
||||
fi
|
||||
|
||||
# Install protoc
|
||||
RUN wget https://github.com/protocolbuffers/protobuf/releases/download/v31.1/protoc-31.1-linux-x86_64.zip \
|
||||
&& unzip protoc-31.1-linux-x86_64.zip -d protoc3 \
|
||||
&& mv protoc3/bin/* /usr/local/bin/ && chmod +x /usr/local/bin/protoc \
|
||||
&& mv protoc3/include/* /usr/local/include/ && rm -rf protoc-31.1-linux-x86_64.zip protoc3
|
||||
|
||||
# Install flatc
|
||||
RUN wget https://github.com/google/flatbuffers/releases/download/v25.2.10/Linux.flatc.binary.g++-13.zip \
|
||||
&& unzip Linux.flatc.binary.g++-13.zip \
|
||||
&& mv flatc /usr/local/bin/ && chmod +x /usr/local/bin/flatc && rm -rf Linux.flatc.binary.g++-13.zip
|
||||
|
||||
# Set up Rust targets based on platform
|
||||
RUN case "$TARGETPLATFORM" in \
|
||||
"linux/amd64") rustup target add x86_64-unknown-linux-musl ;; \
|
||||
"linux/arm64") rustup target add aarch64-unknown-linux-musl ;; \
|
||||
*) echo "Unsupported platform: $TARGETPLATFORM" && exit 1 ;; \
|
||||
esac
|
||||
|
||||
# Set up environment for cross-compilation
|
||||
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=aarch64-linux-gnu-gcc
|
||||
|
||||
WORKDIR /usr/src/rustfs
|
||||
|
||||
# Copy Cargo files for dependency caching
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
COPY */Cargo.toml ./*/
|
||||
|
||||
# Create dummy main.rs files for dependency compilation
|
||||
RUN find . -name "Cargo.toml" -not -path "./Cargo.toml" | \
|
||||
xargs -I {} dirname {} | \
|
||||
xargs -I {} sh -c 'mkdir -p {}/src && echo "fn main() {}" > {}/src/main.rs'
|
||||
|
||||
# Build dependencies only (cache layer)
|
||||
RUN case "$TARGETPLATFORM" in \
|
||||
"linux/amd64") cargo build --release --target x86_64-unknown-linux-musl ;; \
|
||||
"linux/arm64") cargo build --release --target aarch64-unknown-linux-musl ;; \
|
||||
esac
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Generate protobuf code
|
||||
RUN cargo run --bin gproto
|
||||
|
||||
# Build the actual application
|
||||
RUN case "$TARGETPLATFORM" in \
|
||||
"linux/amd64") \
|
||||
cargo build --release --target x86_64-unknown-linux-musl --bin rustfs && \
|
||||
cp target/x86_64-unknown-linux-musl/release/rustfs /usr/local/bin/rustfs \
|
||||
;; \
|
||||
"linux/arm64") \
|
||||
cargo build --release --target aarch64-unknown-linux-musl --bin rustfs && \
|
||||
cp target/aarch64-unknown-linux-musl/release/rustfs /usr/local/bin/rustfs \
|
||||
;; \
|
||||
esac
|
||||
|
||||
# Runtime stage - minimal Alpine image
|
||||
FROM alpine:latest
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apk add --no-cache \
|
||||
ca-certificates \
|
||||
tzdata \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
# Create rustfs user and group
|
||||
RUN addgroup -g 1000 rustfs && \
|
||||
adduser -D -s /bin/sh -u 1000 -G rustfs rustfs
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Create data directories
|
||||
RUN mkdir -p /data/rustfs{0,1,2,3} && \
|
||||
chown -R rustfs:rustfs /data /app
|
||||
|
||||
# Copy binary from builder stage
|
||||
COPY --from=builder /usr/local/bin/rustfs /app/rustfs
|
||||
RUN chmod +x /app/rustfs
|
||||
|
||||
# Switch to non-root user
|
||||
USER rustfs
|
||||
|
||||
# Expose ports
|
||||
EXPOSE 9000 9001
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:9000/health || exit 1
|
||||
|
||||
# Set default command
|
||||
CMD ["/app/rustfs"]
|
||||
221
docker-compose.yml
Normal file
221
docker-compose.yml
Normal file
@@ -0,0 +1,221 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# RustFS main service
|
||||
rustfs:
|
||||
image: rustfs/rustfs:latest
|
||||
container_name: rustfs-server
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.multi-stage
|
||||
args:
|
||||
TARGETPLATFORM: linux/amd64
|
||||
ports:
|
||||
- "9000:9000" # S3 API port
|
||||
- "9001:9001" # Console port
|
||||
environment:
|
||||
- RUSTFS_VOLUMES=/data/rustfs0,/data/rustfs1,/data/rustfs2,/data/rustfs3
|
||||
- RUSTFS_ADDRESS=0.0.0.0:9000
|
||||
- RUSTFS_CONSOLE_ENABLE=true
|
||||
- RUSTFS_CONSOLE_ADDRESS=0.0.0.0:9001
|
||||
- RUSTFS_ACCESS_KEY=rustfsadmin
|
||||
- RUSTFS_SECRET_KEY=rustfsadmin
|
||||
- RUSTFS_LOG_LEVEL=info
|
||||
- RUSTFS_OBS_ENDPOINT=http://otel-collector:4317
|
||||
volumes:
|
||||
- rustfs_data_0:/data/rustfs0
|
||||
- rustfs_data_1:/data/rustfs1
|
||||
- rustfs_data_2:/data/rustfs2
|
||||
- rustfs_data_3:/data/rustfs3
|
||||
- ./logs:/app/logs
|
||||
networks:
|
||||
- rustfs-network
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
depends_on:
|
||||
- otel-collector
|
||||
|
||||
# Development environment
|
||||
rustfs-dev:
|
||||
image: rustfs/rustfs:devenv
|
||||
container_name: rustfs-dev
|
||||
build:
|
||||
context: .
|
||||
dockerfile: .docker/Dockerfile.devenv
|
||||
ports:
|
||||
- "9010:9000"
|
||||
- "9011:9001"
|
||||
environment:
|
||||
- RUSTFS_VOLUMES=/data/rustfs0,/data/rustfs1
|
||||
- RUSTFS_ADDRESS=0.0.0.0:9000
|
||||
- RUSTFS_CONSOLE_ENABLE=true
|
||||
- RUSTFS_CONSOLE_ADDRESS=0.0.0.0:9001
|
||||
- RUSTFS_ACCESS_KEY=devadmin
|
||||
- RUSTFS_SECRET_KEY=devadmin
|
||||
- RUSTFS_LOG_LEVEL=debug
|
||||
volumes:
|
||||
- .:/root/s3-rustfs
|
||||
- rustfs_dev_data:/data
|
||||
networks:
|
||||
- rustfs-network
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- dev
|
||||
|
||||
# OpenTelemetry Collector
|
||||
otel-collector:
|
||||
image: otel/opentelemetry-collector-contrib:latest
|
||||
container_name: otel-collector
|
||||
command:
|
||||
- --config=/etc/otelcol-contrib/otel-collector.yml
|
||||
volumes:
|
||||
- ./.docker/observability/otel-collector.yml:/etc/otelcol-contrib/otel-collector.yml:ro
|
||||
ports:
|
||||
- "4317:4317" # OTLP gRPC receiver
|
||||
- "4318:4318" # OTLP HTTP receiver
|
||||
- "8888:8888" # Prometheus metrics
|
||||
- "8889:8889" # Prometheus exporter metrics
|
||||
networks:
|
||||
- rustfs-network
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- observability
|
||||
|
||||
# Jaeger for tracing
|
||||
jaeger:
|
||||
image: jaegertracing/all-in-one:latest
|
||||
container_name: jaeger
|
||||
ports:
|
||||
- "16686:16686" # Jaeger UI
|
||||
- "14250:14250" # Jaeger gRPC
|
||||
environment:
|
||||
- COLLECTOR_OTLP_ENABLED=true
|
||||
networks:
|
||||
- rustfs-network
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- observability
|
||||
|
||||
# Prometheus for metrics
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: prometheus
|
||||
ports:
|
||||
- "9090:9090"
|
||||
volumes:
|
||||
- ./.docker/observability/prometheus.yml:/etc/prometheus/prometheus.yml:ro
|
||||
- prometheus_data:/prometheus
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
- '--web.console.libraries=/etc/prometheus/console_libraries'
|
||||
- '--web.console.templates=/etc/prometheus/consoles'
|
||||
- '--storage.tsdb.retention.time=200h'
|
||||
- '--web.enable-lifecycle'
|
||||
networks:
|
||||
- rustfs-network
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- observability
|
||||
|
||||
# Grafana for visualization
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: grafana
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_USER=admin
|
||||
- GF_SECURITY_ADMIN_PASSWORD=admin
|
||||
volumes:
|
||||
- grafana_data:/var/lib/grafana
|
||||
- ./.docker/observability/grafana/provisioning:/etc/grafana/provisioning:ro
|
||||
- ./.docker/observability/grafana/dashboards:/var/lib/grafana/dashboards:ro
|
||||
networks:
|
||||
- rustfs-network
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- observability
|
||||
|
||||
# MinIO for S3 API testing
|
||||
minio:
|
||||
image: minio/minio:latest
|
||||
container_name: minio-test
|
||||
ports:
|
||||
- "9020:9000"
|
||||
- "9021:9001"
|
||||
environment:
|
||||
- MINIO_ROOT_USER=minioadmin
|
||||
- MINIO_ROOT_PASSWORD=minioadmin
|
||||
volumes:
|
||||
- minio_data:/data
|
||||
command: server /data --console-address ":9001"
|
||||
networks:
|
||||
- rustfs-network
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- testing
|
||||
|
||||
# Redis for caching (optional)
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: redis
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- rustfs-network
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- cache
|
||||
|
||||
# NGINX reverse proxy (optional)
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: nginx-proxy
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./.docker/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./.docker/nginx/ssl:/etc/nginx/ssl:ro
|
||||
networks:
|
||||
- rustfs-network
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- proxy
|
||||
depends_on:
|
||||
- rustfs
|
||||
|
||||
networks:
|
||||
rustfs-network:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.20.0.0/16
|
||||
|
||||
volumes:
|
||||
rustfs_data_0:
|
||||
driver: local
|
||||
rustfs_data_1:
|
||||
driver: local
|
||||
rustfs_data_2:
|
||||
driver: local
|
||||
rustfs_data_3:
|
||||
driver: local
|
||||
rustfs_dev_data:
|
||||
driver: local
|
||||
prometheus_data:
|
||||
driver: local
|
||||
grafana_data:
|
||||
driver: local
|
||||
minio_data:
|
||||
driver: local
|
||||
redis_data:
|
||||
driver: local
|
||||
426
docs/docker-build.md
Normal file
426
docs/docker-build.md
Normal file
@@ -0,0 +1,426 @@
|
||||
# RustFS Docker Build and Deployment Guide
|
||||
|
||||
This document describes how to build and deploy RustFS using Docker, including the automated GitHub Actions workflow for building and pushing images to Docker Hub and GitHub Container Registry.
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Using Pre-built Images
|
||||
|
||||
```bash
|
||||
# Pull and run the latest RustFS image
|
||||
docker run -d \
|
||||
--name rustfs \
|
||||
-p 9000:9000 \
|
||||
-p 9001:9001 \
|
||||
-v rustfs_data:/data \
|
||||
-e RUSTFS_VOLUMES=/data/rustfs0,/data/rustfs1,/data/rustfs2,/data/rustfs3 \
|
||||
-e RUSTFS_ACCESS_KEY=rustfsadmin \
|
||||
-e RUSTFS_SECRET_KEY=rustfsadmin \
|
||||
-e RUSTFS_CONSOLE_ENABLE=true \
|
||||
rustfs/rustfs:latest
|
||||
```
|
||||
|
||||
### Using Docker Compose
|
||||
|
||||
```bash
|
||||
# Basic deployment
|
||||
docker-compose up -d
|
||||
|
||||
# Development environment
|
||||
docker-compose --profile dev up -d
|
||||
|
||||
# With observability stack
|
||||
docker-compose --profile observability up -d
|
||||
|
||||
# Full stack with all services
|
||||
docker-compose --profile dev --profile observability --profile testing up -d
|
||||
```
|
||||
|
||||
## 📦 Available Images
|
||||
|
||||
Our GitHub Actions workflow builds multiple image variants:
|
||||
|
||||
### Image Registries
|
||||
|
||||
- **Docker Hub**: `rustfs/rustfs`
|
||||
- **GitHub Container Registry**: `ghcr.io/rustfs/s3-rustfs`
|
||||
|
||||
### Image Variants
|
||||
|
||||
| Variant | Tag Suffix | Description | Use Case |
|
||||
|---------|------------|-------------|----------|
|
||||
| Production | *(none)* | Minimal Alpine-based runtime | Production deployment |
|
||||
| Ubuntu | `-ubuntu22.04` | Ubuntu 22.04 based build environment | Development/Testing |
|
||||
| Rocky Linux | `-rockylinux9.3` | Rocky Linux 9.3 based build environment | Enterprise environments |
|
||||
| Development | `-devenv` | Full development environment | Development/Debugging |
|
||||
|
||||
### Supported Architectures
|
||||
|
||||
All images support multi-architecture:
|
||||
- `linux/amd64` (x86_64)
|
||||
- `linux/arm64` (aarch64)
|
||||
|
||||
### Tag Examples
|
||||
|
||||
```bash
|
||||
# Latest production image
|
||||
rustfs/rustfs:latest
|
||||
rustfs/rustfs:main
|
||||
|
||||
# Specific version
|
||||
rustfs/rustfs:v1.0.0
|
||||
rustfs/rustfs:v1.0.0-ubuntu22.04
|
||||
|
||||
# Development environment
|
||||
rustfs/rustfs:latest-devenv
|
||||
rustfs/rustfs:main-devenv
|
||||
```
|
||||
|
||||
## 🔧 GitHub Actions Workflow
|
||||
|
||||
The Docker build workflow (`.github/workflows/docker.yml`) automatically:
|
||||
|
||||
1. **Builds cross-platform binaries** for `amd64` and `arm64`
|
||||
2. **Creates Docker images** for all variants
|
||||
3. **Pushes to registries** (Docker Hub and GitHub Container Registry)
|
||||
4. **Creates multi-arch manifests** for seamless platform selection
|
||||
5. **Performs security scanning** using Trivy
|
||||
|
||||
### Workflow Triggers
|
||||
|
||||
- **Push to main branch**: Builds and pushes `main` and `latest` tags
|
||||
- **Tag push** (`v*`): Builds and pushes version tags
|
||||
- **Pull requests**: Builds images without pushing
|
||||
- **Manual trigger**: Workflow dispatch with options
|
||||
|
||||
### Required Secrets
|
||||
|
||||
Configure these secrets in your GitHub repository:
|
||||
|
||||
```bash
|
||||
# Docker Hub credentials
|
||||
DOCKERHUB_USERNAME=your-dockerhub-username
|
||||
DOCKERHUB_TOKEN=your-dockerhub-access-token
|
||||
|
||||
# GitHub token is automatically available
|
||||
GITHUB_TOKEN=automatically-provided
|
||||
```
|
||||
|
||||
## 🏗️ Building Locally
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Docker with BuildKit enabled
|
||||
- Docker Compose (optional)
|
||||
|
||||
### Build Commands
|
||||
|
||||
```bash
|
||||
# Build production image for local platform
|
||||
docker build -t rustfs:local .
|
||||
|
||||
# Build multi-stage production image
|
||||
docker build -f Dockerfile.multi-stage -t rustfs:multi-stage .
|
||||
|
||||
# Build specific variant
|
||||
docker build -f .docker/Dockerfile.ubuntu22.04 -t rustfs:ubuntu .
|
||||
|
||||
# Build for specific platform
|
||||
docker build --platform linux/amd64 -t rustfs:amd64 .
|
||||
docker build --platform linux/arm64 -t rustfs:arm64 .
|
||||
|
||||
# Build multi-platform image
|
||||
docker buildx build --platform linux/amd64,linux/arm64 -t rustfs:multi .
|
||||
```
|
||||
|
||||
### Build with Docker Compose
|
||||
|
||||
```bash
|
||||
# Build all services
|
||||
docker-compose build
|
||||
|
||||
# Build specific service
|
||||
docker-compose build rustfs
|
||||
|
||||
# Build development environment
|
||||
docker-compose build rustfs-dev
|
||||
```
|
||||
|
||||
## 🚀 Deployment Options
|
||||
|
||||
### 1. Single Container
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name rustfs \
|
||||
--restart unless-stopped \
|
||||
-p 9000:9000 \
|
||||
-p 9001:9001 \
|
||||
-v /data/rustfs:/data \
|
||||
-e RUSTFS_VOLUMES=/data/rustfs0,/data/rustfs1,/data/rustfs2,/data/rustfs3 \
|
||||
-e RUSTFS_ADDRESS=0.0.0.0:9000 \
|
||||
-e RUSTFS_CONSOLE_ENABLE=true \
|
||||
-e RUSTFS_CONSOLE_ADDRESS=0.0.0.0:9001 \
|
||||
-e RUSTFS_ACCESS_KEY=rustfsadmin \
|
||||
-e RUSTFS_SECRET_KEY=rustfsadmin \
|
||||
rustfs/rustfs:latest
|
||||
```
|
||||
|
||||
### 2. Docker Compose Profiles
|
||||
|
||||
```bash
|
||||
# Production deployment
|
||||
docker-compose up -d
|
||||
|
||||
# Development with debugging
|
||||
docker-compose --profile dev up -d
|
||||
|
||||
# With monitoring stack
|
||||
docker-compose --profile observability up -d
|
||||
|
||||
# Complete testing environment
|
||||
docker-compose --profile dev --profile observability --profile testing up -d
|
||||
```
|
||||
|
||||
### 3. Kubernetes Deployment
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: rustfs
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: rustfs
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: rustfs
|
||||
spec:
|
||||
containers:
|
||||
- name: rustfs
|
||||
image: rustfs/rustfs:latest
|
||||
ports:
|
||||
- containerPort: 9000
|
||||
- containerPort: 9001
|
||||
env:
|
||||
- name: RUSTFS_VOLUMES
|
||||
value: "/data/rustfs0,/data/rustfs1,/data/rustfs2,/data/rustfs3"
|
||||
- name: RUSTFS_ADDRESS
|
||||
value: "0.0.0.0:9000"
|
||||
- name: RUSTFS_CONSOLE_ENABLE
|
||||
value: "true"
|
||||
- name: RUSTFS_CONSOLE_ADDRESS
|
||||
value: "0.0.0.0:9001"
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: rustfs-data
|
||||
```
|
||||
|
||||
## ⚙️ Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `RUSTFS_VOLUMES` | Comma-separated list of data volumes | Required |
|
||||
| `RUSTFS_ADDRESS` | Server bind address | `0.0.0.0:9000` |
|
||||
| `RUSTFS_CONSOLE_ENABLE` | Enable web console | `false` |
|
||||
| `RUSTFS_CONSOLE_ADDRESS` | Console bind address | `0.0.0.0:9001` |
|
||||
| `RUSTFS_ACCESS_KEY` | S3 access key | `rustfsadmin` |
|
||||
| `RUSTFS_SECRET_KEY` | S3 secret key | `rustfsadmin` |
|
||||
| `RUSTFS_LOG_LEVEL` | Log level | `info` |
|
||||
| `RUSTFS_OBS_ENDPOINT` | Observability endpoint | `""` |
|
||||
| `RUSTFS_TLS_PATH` | TLS certificates path | `""` |
|
||||
|
||||
### Volume Mounts
|
||||
|
||||
- **Data volumes**: `/data/rustfs{0,1,2,3}` - RustFS data storage
|
||||
- **Logs**: `/app/logs` - Application logs
|
||||
- **Config**: `/etc/rustfs/` - Configuration files
|
||||
- **TLS**: `/etc/ssl/rustfs/` - TLS certificates
|
||||
|
||||
### Ports
|
||||
|
||||
- **9000**: S3 API endpoint
|
||||
- **9001**: Web console (if enabled)
|
||||
- **9002**: Admin API (if enabled)
|
||||
- **50051**: gRPC API (if enabled)
|
||||
|
||||
## 🔍 Monitoring and Observability
|
||||
|
||||
### Health Checks
|
||||
|
||||
The Docker images include built-in health checks:
|
||||
|
||||
```bash
|
||||
# Check container health
|
||||
docker ps --filter "name=rustfs" --format "table {{.Names}}\t{{.Status}}"
|
||||
|
||||
# View health check logs
|
||||
docker inspect rustfs --format='{{json .State.Health}}'
|
||||
```
|
||||
|
||||
### Metrics and Tracing
|
||||
|
||||
When using the observability profile:
|
||||
|
||||
- **Prometheus**: http://localhost:9090
|
||||
- **Grafana**: http://localhost:3000 (admin/admin)
|
||||
- **Jaeger**: http://localhost:16686
|
||||
- **OpenTelemetry Collector**: http://localhost:8888/metrics
|
||||
|
||||
### Log Collection
|
||||
|
||||
```bash
|
||||
# View container logs
|
||||
docker logs rustfs -f
|
||||
|
||||
# Export logs
|
||||
docker logs rustfs > rustfs.log 2>&1
|
||||
```
|
||||
|
||||
## 🛠️ Development
|
||||
|
||||
### Development Environment
|
||||
|
||||
```bash
|
||||
# Start development container
|
||||
docker-compose --profile dev up -d rustfs-dev
|
||||
|
||||
# Access development container
|
||||
docker exec -it rustfs-dev bash
|
||||
|
||||
# Mount source code for live development
|
||||
docker run -it --rm \
|
||||
-v $(pwd):/root/s3-rustfs \
|
||||
-p 9000:9000 \
|
||||
rustfs/rustfs:devenv \
|
||||
bash
|
||||
```
|
||||
|
||||
### Building from Source in Container
|
||||
|
||||
```bash
|
||||
# Use development image for building
|
||||
docker run --rm \
|
||||
-v $(pwd):/root/s3-rustfs \
|
||||
-w /root/s3-rustfs \
|
||||
rustfs/rustfs:ubuntu22.04 \
|
||||
cargo build --release --bin rustfs
|
||||
```
|
||||
|
||||
## 🔐 Security
|
||||
|
||||
### Security Scanning
|
||||
|
||||
The workflow includes Trivy security scanning:
|
||||
|
||||
```bash
|
||||
# Run security scan locally
|
||||
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v $HOME/Library/Caches:/root/.cache/ \
|
||||
aquasec/trivy:latest image rustfs/rustfs:latest
|
||||
```
|
||||
|
||||
### Security Best Practices
|
||||
|
||||
1. **Use non-root user**: Images run as `rustfs` user (UID 1000)
|
||||
2. **Minimal base images**: Alpine Linux for production
|
||||
3. **Security updates**: Regular base image updates
|
||||
4. **Secret management**: Use Docker secrets or environment files
|
||||
5. **Network security**: Use Docker networks and proper firewall rules
|
||||
|
||||
## 📝 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Build failures**: Check build logs and ensure all dependencies are installed
|
||||
2. **Permission issues**: Ensure proper volume permissions for UID 1000
|
||||
3. **Network connectivity**: Verify port mappings and network configuration
|
||||
4. **Resource limits**: Ensure sufficient memory and CPU for compilation
|
||||
|
||||
### Debug Commands
|
||||
|
||||
```bash
|
||||
# Check container status
|
||||
docker ps -a
|
||||
|
||||
# View container logs
|
||||
docker logs rustfs --tail 100
|
||||
|
||||
# Access container shell
|
||||
docker exec -it rustfs sh
|
||||
|
||||
# Check resource usage
|
||||
docker stats rustfs
|
||||
|
||||
# Inspect container configuration
|
||||
docker inspect rustfs
|
||||
```
|
||||
|
||||
## 🔄 CI/CD Integration
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
The provided workflow can be customized:
|
||||
|
||||
```yaml
|
||||
# Override image names
|
||||
env:
|
||||
REGISTRY_IMAGE_DOCKERHUB: myorg/rustfs
|
||||
REGISTRY_IMAGE_GHCR: ghcr.io/myorg/rustfs
|
||||
```
|
||||
|
||||
### GitLab CI
|
||||
|
||||
```yaml
|
||||
build:
|
||||
stage: build
|
||||
image: docker:latest
|
||||
services:
|
||||
- docker:dind
|
||||
script:
|
||||
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
|
||||
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
```
|
||||
|
||||
### Jenkins Pipeline
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
script {
|
||||
docker.build("rustfs:${env.BUILD_ID}")
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Push') {
|
||||
steps {
|
||||
script {
|
||||
docker.withRegistry('https://registry.hub.docker.com', 'dockerhub-credentials') {
|
||||
docker.image("rustfs:${env.BUILD_ID}").push()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📚 Additional Resources
|
||||
|
||||
- [Docker Official Documentation](https://docs.docker.com/)
|
||||
- [Docker Compose Reference](https://docs.docker.com/compose/)
|
||||
- [GitHub Actions Documentation](https://docs.github.com/en/actions)
|
||||
- [RustFS Configuration Guide](../README.md)
|
||||
- [Kubernetes Deployment Guide](./kubernetes.md)
|
||||
Reference in New Issue
Block a user