mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-28 07:57:01 +00:00
feat: enhance entrypoint and Dockerfiles for flexible volume and permission management (#260)
* feat: enhance entrypoint and Dockerfiles for flexible volume and permission management\n\n- Support batch mount and permission fix in entrypoint.sh\n- Add coreutils/shadow (alpine) and coreutils/passwd (ubuntu) for UID/GID/ownership\n- Use ENTRYPOINT for unified startup\n- Make local dev and prod Dockerfile behavior consistent\n- Improve security and user experience\n\nBREAKING CHANGE: entrypoint.sh and Dockerfile now require additional packages for permission management, and support batch volume mount via RUSTFS_VOLUMES. * chore: update Dockerfile comments to English only * fix(entrypoint): improve local/remote volume detection and permission logic in entrypoint.sh * Update entrypoint.sh Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update entrypoint.sh Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Dockerfile Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
+11
-15
@@ -4,8 +4,7 @@
|
|||||||
FROM alpine:3.22 AS build
|
FROM alpine:3.22 AS build
|
||||||
|
|
||||||
# Build arguments for platform and release
|
# Build arguments for platform and release
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETARCH
|
||||||
ARG BUILDPLATFORM
|
|
||||||
ARG RELEASE=latest
|
ARG RELEASE=latest
|
||||||
|
|
||||||
# Install minimal dependencies for downloading and extracting
|
# Install minimal dependencies for downloading and extracting
|
||||||
@@ -14,18 +13,14 @@ RUN apk add --no-cache ca-certificates curl unzip
|
|||||||
# Create build directory
|
# Create build directory
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
# Map TARGETPLATFORM to architecture
|
# Detect architecture and download corresponding binary
|
||||||
RUN case "${TARGETPLATFORM}" in \
|
RUN case "${TARGETARCH}" in \
|
||||||
"linux/amd64") ARCH="x86_64" ;; \
|
amd64) ARCH="x86_64" ;; \
|
||||||
"linux/arm64") ARCH="aarch64" ;; \
|
arm64) ARCH="aarch64" ;; \
|
||||||
*) echo "Unsupported platform: ${TARGETPLATFORM}" >&2 && exit 1 ;; \
|
*) echo "Unsupported architecture: ${TARGETARCH}" >&2 && exit 1 ;; \
|
||||||
esac && \
|
esac && \
|
||||||
echo "ARCH=${ARCH}" > /build/arch.env
|
|
||||||
|
|
||||||
# Download and extract RustFS binary
|
|
||||||
RUN . /build/arch.env && \
|
|
||||||
BASE_URL="https://dl.rustfs.com/artifacts/rustfs/release" && \
|
BASE_URL="https://dl.rustfs.com/artifacts/rustfs/release" && \
|
||||||
PACKAGE_NAME="rustfs-linux-${ARCH}-${RELEASE}.zip" && \
|
PACKAGE_NAME="rustfs-linux-${ARCH}-${RELEASE#v}.zip" && \
|
||||||
DOWNLOAD_URL="${BASE_URL}/${PACKAGE_NAME}" && \
|
DOWNLOAD_URL="${BASE_URL}/${PACKAGE_NAME}" && \
|
||||||
echo "Downloading ${PACKAGE_NAME} from ${DOWNLOAD_URL}" >&2 && \
|
echo "Downloading ${PACKAGE_NAME} from ${DOWNLOAD_URL}" >&2 && \
|
||||||
curl -f -L "${DOWNLOAD_URL}" -o rustfs.zip && \
|
curl -f -L "${DOWNLOAD_URL}" -o rustfs.zip && \
|
||||||
@@ -56,7 +51,7 @@ LABEL name="RustFS" \
|
|||||||
# Install runtime dependencies
|
# Install runtime dependencies
|
||||||
RUN echo "https://dl-cdn.alpinelinux.org/alpine/v3.20/community" >> /etc/apk/repositories && \
|
RUN echo "https://dl-cdn.alpinelinux.org/alpine/v3.20/community" >> /etc/apk/repositories && \
|
||||||
apk update && \
|
apk update && \
|
||||||
apk add --no-cache ca-certificates bash gosu && \
|
apk add --no-cache ca-certificates bash gosu coreutils shadow && \
|
||||||
addgroup -g 1000 rustfs && \
|
addgroup -g 1000 rustfs && \
|
||||||
adduser -u 1000 -G rustfs -s /bin/bash -D rustfs
|
adduser -u 1000 -G rustfs -s /bin/bash -D rustfs
|
||||||
|
|
||||||
@@ -74,7 +69,7 @@ RUN chmod +x /usr/bin/rustfs /entrypoint.sh && \
|
|||||||
chmod 700 /data /logs
|
chmod 700 /data /logs
|
||||||
|
|
||||||
# Environment variables (credentials should be set via environment or secrets)
|
# Environment variables (credentials should be set via environment or secrets)
|
||||||
ENV RUSTFS_ADDRESS=":9000" \
|
ENV RUSTFS_ADDRESS=:9000 \
|
||||||
RUSTFS_ACCESS_KEY=rustfsadmin \
|
RUSTFS_ACCESS_KEY=rustfsadmin \
|
||||||
RUSTFS_SECRET_KEY=rustfsadmin \
|
RUSTFS_SECRET_KEY=rustfsadmin \
|
||||||
RUSTFS_CONSOLE_ENABLE=true \
|
RUSTFS_CONSOLE_ENABLE=true \
|
||||||
@@ -91,4 +86,5 @@ VOLUME ["/data", "/logs"]
|
|||||||
|
|
||||||
# Set entry point
|
# Set entry point
|
||||||
ENTRYPOINT ["/entrypoint.sh"]
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
CMD ["/usr/bin/rustfs"]
|
CMD ["/usr/bin/rustfs"]
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -112,6 +112,8 @@ RUN apt-get update && apt-get install -y \
|
|||||||
ca-certificates \
|
ca-certificates \
|
||||||
tzdata \
|
tzdata \
|
||||||
wget \
|
wget \
|
||||||
|
coreutils \
|
||||||
|
passwd \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Create rustfs user and group
|
# Create rustfs user and group
|
||||||
@@ -128,6 +130,10 @@ RUN mkdir -p /data/rustfs{0,1,2,3} && \
|
|||||||
COPY --from=builder /usr/local/bin/rustfs /app/rustfs
|
COPY --from=builder /usr/local/bin/rustfs /app/rustfs
|
||||||
RUN chmod +x /app/rustfs && chown rustfs:rustfs /app/rustfs
|
RUN chmod +x /app/rustfs && chown rustfs:rustfs /app/rustfs
|
||||||
|
|
||||||
|
# Copy entrypoint script
|
||||||
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
# Switch to non-root user
|
# Switch to non-root user
|
||||||
USER rustfs
|
USER rustfs
|
||||||
|
|
||||||
@@ -142,9 +148,9 @@ ENV RUSTFS_ACCESS_KEY=rustfsadmin \
|
|||||||
RUSTFS_VOLUMES=/data \
|
RUSTFS_VOLUMES=/data \
|
||||||
RUST_LOG=warn
|
RUST_LOG=warn
|
||||||
|
|
||||||
|
|
||||||
# Volume for data
|
# Volume for data
|
||||||
VOLUME ["/data"]
|
VOLUME ["/data"]
|
||||||
|
|
||||||
# Set default command
|
# Set entrypoint and default command
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
CMD ["/app/rustfs"]
|
CMD ["/app/rustfs"]
|
||||||
|
|||||||
+95
-42
@@ -1,51 +1,104 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Function to adjust rustfs user/group to match mounted directory ownership
|
APP_USER=rustfs
|
||||||
fix_permissions() {
|
APP_GROUP=rustfs
|
||||||
local dir="$1"
|
APP_UID=${PUID:-1000}
|
||||||
local user="rustfs"
|
APP_GID=${PGID:-1000}
|
||||||
local group="rustfs"
|
|
||||||
|
|
||||||
# Skip if directory doesn't exist or isn't mounted
|
# Parse RUSTFS_VOLUMES into array (support space, comma, tab as separator)
|
||||||
if [ ! -d "$dir" ]; then
|
VOLUME_RAW="${RUSTFS_VOLUMES:-/data}"
|
||||||
echo "Directory $dir does not exist, creating it"
|
# Replace comma and tab with space, then split
|
||||||
mkdir -p "$dir"
|
VOLUME_RAW=$(echo "$VOLUME_RAW" | tr ',\t' ' ')
|
||||||
chown "$user:$group" "$dir"
|
read -ra ALL_VOLUMES <<< "$VOLUME_RAW"
|
||||||
chmod 700 "$dir"
|
|
||||||
return
|
# Only keep local volumes (start with /, not http/https)
|
||||||
|
LOCAL_VOLUMES=()
|
||||||
|
for vol in "${ALL_VOLUMES[@]}"; do
|
||||||
|
if [[ "$vol" =~ ^/ ]] && [[ ! "$vol" =~ ^https?:// ]]; then
|
||||||
|
# Not a URL (http/https), just a local path
|
||||||
|
LOCAL_VOLUMES+=("$vol")
|
||||||
|
fi
|
||||||
|
# If it's a URL (http/https), skip
|
||||||
|
# If it's an empty string, skip
|
||||||
|
# If it's a local path, keep
|
||||||
|
# (We don't support other protocols here)
|
||||||
|
done
|
||||||
|
|
||||||
|
# Always ensure /logs is included for permission fix
|
||||||
|
include_logs=1
|
||||||
|
for vol in "${LOCAL_VOLUMES[@]}"; do
|
||||||
|
if [ "$vol" = "/logs" ]; then
|
||||||
|
include_logs=0
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ $include_logs -eq 1 ]; then
|
||||||
|
LOCAL_VOLUMES+=("/logs")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Try to update rustfs UID/GID if needed (requires root and shadow tools)
|
||||||
|
update_user_group_ids() {
|
||||||
|
local uid="$1"
|
||||||
|
local gid="$2"
|
||||||
|
local user="$3"
|
||||||
|
local group="$4"
|
||||||
|
local updated=0
|
||||||
|
if [ "$(id -u "$user")" != "$uid" ]; then
|
||||||
|
if command -v usermod >/dev/null 2>&1; then
|
||||||
|
echo "🔧 Updating UID of $user to $uid"
|
||||||
|
usermod -u "$uid" "$user"
|
||||||
|
updated=1
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
# Get directory ownership
|
if [ "$(id -g "$group")" != "$gid" ]; then
|
||||||
local dir_uid=$(stat -c %u "$dir")
|
if command -v groupmod >/dev/null 2>&1; then
|
||||||
local dir_gid=$(stat -c %g "$dir")
|
echo "🔧 Updating GID of $group to $gid"
|
||||||
|
groupmod -g "$gid" "$group"
|
||||||
# If directory is owned by root or inaccessible, skip adjustment
|
updated=1
|
||||||
if [ "$dir_uid" = "0" ] || [ "$dir_gid" = "0" ]; then
|
|
||||||
echo "Warning: Directory $dir is owned by root, skipping UID/GID adjustment"
|
|
||||||
chown "$user:$group" "$dir"
|
|
||||||
chmod 700 "$dir"
|
|
||||||
return
|
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
# Adjust rustfs user/group to match directory ownership
|
return $updated
|
||||||
if [ "$dir_uid" != "$(id -u $user)" ]; then
|
|
||||||
echo "Adjusting UID of $user to $dir_uid for $dir"
|
|
||||||
usermod -u "$dir_uid" "$user"
|
|
||||||
fi
|
|
||||||
if [ "$dir_gid" != "$(id -g $group)" ]; then
|
|
||||||
echo "Adjusting GID of $group to $dir_gid for $dir"
|
|
||||||
groupmod -g "$dir_gid" "$group"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Ensure permissions are correct
|
|
||||||
chown "$user:$group" "$dir"
|
|
||||||
chmod 700 "$dir"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Fix permissions for /data and /logs
|
echo "📦 Initializing mount directories: ${LOCAL_VOLUMES[*]}"
|
||||||
fix_permissions "/data"
|
|
||||||
fix_permissions "/logs"
|
|
||||||
|
|
||||||
# Run RustFS as the rustfs user
|
for vol in "${LOCAL_VOLUMES[@]}"; do
|
||||||
exec gosu rustfs:rustfs "$@"
|
if [ ! -d "$vol" ]; then
|
||||||
|
echo "📁 Creating directory: $vol"
|
||||||
|
mkdir -p "$vol"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Alpine busybox stat does not support -c, coreutils is required
|
||||||
|
dir_uid=$(stat -c '%u' "$vol")
|
||||||
|
dir_gid=$(stat -c '%g' "$vol")
|
||||||
|
|
||||||
|
if [ "$dir_uid" != "$APP_UID" ] || [ "$dir_gid" != "$APP_GID" ]; then
|
||||||
|
if [[ "$SKIP_CHOWN" != "true" ]]; then
|
||||||
|
# Prefer to update rustfs user/group UID/GID
|
||||||
|
update_user_group_ids "$dir_uid" "$dir_gid" "$APP_USER" "$APP_GROUP" || \
|
||||||
|
{
|
||||||
|
echo "🔧 Fixing ownership for: $vol → $APP_USER:$APP_GROUP"
|
||||||
|
if [[ -n "$CHOWN_RECURSION_DEPTH" ]]; then
|
||||||
|
echo "🔧 Applying ownership fix with recursion depth: $CHOWN_RECURSION_DEPTH"
|
||||||
|
find "$vol" -mindepth 0 -maxdepth "$CHOWN_RECURSION_DEPTH" -exec chown "$APP_USER:$APP_GROUP" {} \;
|
||||||
|
else
|
||||||
|
echo "🔧 Applying ownership fix recursively (full depth)"
|
||||||
|
chown -R "$APP_USER:$APP_GROUP" "$vol"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
else
|
||||||
|
echo "⚠️ SKIP_CHOWN is enabled. Skipping ownership fix for: $vol"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
chmod 700 "$vol"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Warn if default credentials are used
|
||||||
|
if [[ "$RUSTFS_ACCESS_KEY" == "rustfsadmin" || "$RUSTFS_SECRET_KEY" == "rustfsadmin" ]]; then
|
||||||
|
echo "⚠️ WARNING: Using default RUSTFS_ACCESS_KEY or RUSTFS_SECRET_KEY"
|
||||||
|
echo "⚠️ It is strongly recommended to override these values in production!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "🚀 Starting application: $*"
|
||||||
|
exec gosu "$APP_USER" "$@"
|
||||||
|
|||||||
Reference in New Issue
Block a user