-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile
More file actions
237 lines (200 loc) · 7.84 KB
/
Dockerfile
File metadata and controls
237 lines (200 loc) · 7.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# Generic Modular NFS Server for Kubernetes - Alpine Linux (Minimal/Optimized)
# A lightweight, configurable NFS server for containerized environments
# OPTIMIZED VERSION: Reduced image size by removing unnecessary packages
# Build arguments for supply chain attestation
ARG BUILD_DATE
ARG VCS_REF
ARG VERSION=1.0.2
FROM alpine:3.22
# Enhanced metadata for supply chain attestation
LABEL maintainer="contact@pocketlabs.cc" \
description="Minimal lightweight NFS server for Kubernetes with dynamic configuration" \
version="${VERSION}" \
org.opencontainers.image.title="Generic NFS Server (Minimal)" \
org.opencontainers.image.description="Minimal lightweight NFS server for Kubernetes with dynamic configuration" \
org.opencontainers.image.version="${VERSION}" \
org.opencontainers.image.authors="contact@pocketlabs.cc" \
org.opencontainers.image.vendor="Pocket Labs" \
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.source="https://github.com/boyroywax/nfs-server" \
org.opencontainers.image.documentation="https://github.com/boyroywax/nfs-server/blob/main/README.md" \
org.opencontainers.image.url="https://hub.docker.com/r/boyroywax/nfs-server" \
org.opencontainers.image.created="${BUILD_DATE}" \
org.opencontainers.image.revision="${VCS_REF}" \
org.label-schema.schema-version="1.0" \
org.label-schema.build-date="${BUILD_DATE}" \
org.label-schema.vcs-ref="${VCS_REF}" \
org.label-schema.vcs-url="https://github.com/boyroywax/nfs-server" \
org.label-schema.version="${VERSION}"
# Security: Update package index and install ONLY essential packages
# Optimization: Install nfs-utils without Python dependency (--no-scripts flag)
# This removes Python dependency which saves ~30MB
RUN apk update && apk upgrade && \
apk add --no-cache \
'openssl>=3.5.4-r0' \
'expat>=2.7.2-r0' \
nfs-utils \
rpcbind \
# Install only essential mount utilities (not full util-linux)
mount \
umount \
blkid \
findmnt \
&& rm -rf /var/cache/apk/* \
&& rm -rf /tmp/* \
# Remove Python-based NFS utilities that are not needed for basic operation
&& rm -f /usr/sbin/nfsiostat \
&& rm -f /usr/sbin/nfsdclddb \
&& rm -f /usr/sbin/nfsdclnts
# Security: Create dedicated non-root user and group for NFS operations
RUN addgroup -g 1001 -S nfsgroup && \
adduser -D -u 1001 -G nfsgroup -s /bin/sh -h /home/nfsuser nfsuser
# Create necessary directories for NFS serving with proper ownership
RUN mkdir -p /nfsshare/data \
/var/lib/nfs \
/var/lib/nfs/statd \
/var/lib/nfs/v4recovery \
/run/rpc_pipefs \
/etc/exports.d \
/home/nfsuser \
&& chown -R nfsuser:nfsgroup /nfsshare/data \
&& chown -R nfsuser:nfsgroup /home/nfsuser \
&& chmod 755 /nfsshare/data \
&& chmod 750 /home/nfsuser
# Create dynamic exports configuration script (POSIX compliant - no bash required)
RUN cat > /usr/local/bin/configure-exports.sh << 'EOF'
#!/bin/sh
set -e
# Configuration with sensible defaults
SHARE_NAME=${SHARE_NAME:-"default-share"}
EXPORT_PATH=${EXPORT_PATH:-"/nfsshare/data"}
NFS_OPTIONS=${NFS_OPTIONS:-"rw,sync,no_subtree_check,no_root_squash,insecure"}
CLIENT_CIDR=${CLIENT_CIDR:-"*"}
echo "=== NFS Server Configuration ==="
echo "Share Name: ${SHARE_NAME}"
echo "Export Path: ${EXPORT_PATH}"
echo "Client CIDR: ${CLIENT_CIDR}"
echo "NFS Options: ${NFS_OPTIONS}"
echo "================================"
# Ensure export directory exists
mkdir -p "${EXPORT_PATH}"
chown -R nfsuser:nfsgroup "${EXPORT_PATH}"
# Create exports file with proper handling of multiple CIDRs
echo "# NFS exports for ${SHARE_NAME}" > /etc/exports
# Split CLIENT_CIDR by comma and create separate entries for each
# POSIX compliant version without bash arrays
echo "$CLIENT_CIDR" | tr ',' '\n' | while IFS= read -r cidr; do
# Trim whitespace
cidr=$(echo "$cidr" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if [ -n "$cidr" ]; then
echo "${EXPORT_PATH} ${cidr}(${NFS_OPTIONS})" >> /etc/exports
fi
done
# Log final configuration
echo "Active NFS Exports:"
cat /etc/exports
echo ""
EOF
RUN chmod +x /usr/local/bin/configure-exports.sh
# Create startup script (POSIX compliant - no bash required)
RUN cat > /usr/local/bin/start-nfs.sh << 'EOF'
#!/bin/sh
set -e
# Check if running as root (required for NFS services)
if [ "$(id -u)" != "0" ]; then
echo "WARNING: NFS server requires root privileges"
echo "Container should be run with --user root or appropriate capabilities"
echo "Attempting to continue with limited functionality..."
fi
SHARE_NAME=${SHARE_NAME:-"default-share"}
echo "Starting NFS server for share: ${SHARE_NAME}"
echo ""
# Configure exports based on environment variables
/usr/local/bin/configure-exports.sh
# Ensure data directory exists and has correct permissions
mkdir -p /nfsshare/data
if [ "$(id -u)" = "0" ]; then
chown -R nfsuser:nfsgroup /nfsshare/data
fi
# Start rpcbind (requires root)
echo "Starting rpcbind service..."
if [ "$(id -u)" = "0" ]; then
rpcbind -w -f &
RPCBIND_PID=$!
# Wait for rpcbind to be ready
sleep 2
# Start statd
echo "Starting NFS state daemon..."
rpc.statd --no-notify &
STATD_PID=$!
# Start mountd
echo "Starting NFS mount daemon..."
rpc.mountd --port 20048 &
MOUNTD_PID=$!
# Export filesystems
echo "Activating NFS exports..."
exportfs -ra
# Start NFS daemon
echo "Starting NFS kernel daemon..."
rpc.nfsd -V 3 -V 4 8
else
echo "ERROR: Root privileges required for NFS services"
echo "Please run container with --user root or --privileged flag"
exit 1
fi
# Function to handle graceful shutdown
shutdown() {
echo ""
echo "Received shutdown signal, stopping NFS server for share: ${SHARE_NAME}..."
if [ "$(id -u)" = "0" ]; then
exportfs -ua 2>/dev/null || true
rpc.nfsd 0 2>/dev/null || true
kill $MOUNTD_PID $STATD_PID $RPCBIND_PID 2>/dev/null || true
fi
echo "NFS server stopped gracefully"
exit 0
}
# Set up signal handlers for graceful shutdown
trap shutdown TERM INT
echo ""
echo "✅ NFS server for share '${SHARE_NAME}' started successfully!"
echo "📁 Export path: ${EXPORT_PATH}"
echo "🌐 Available exports:"
showmount -e localhost 2>/dev/null || echo " (exports will be visible once fully initialized)"
echo ""
echo "🔄 Monitoring NFS server health..."
# Keep the container running and monitor health
while true; do
sleep 30
# Simple health check - if we can list exports, NFS is working
if ! showmount -e localhost > /dev/null 2>&1; then
echo "❌ NFS server health check failed, container will restart..."
exit 1
fi
done
EOF
RUN chmod +x /usr/local/bin/start-nfs.sh
# Security: Remove unnecessary files and clean up
RUN rm -rf /var/cache/apk/* \
&& rm -rf /tmp/* \
&& rm -rf /root/.cache \
&& find /var/log -type f -delete
# Note: NFS requires root privileges for rpc.nfsd and other services
# However, we set a non-root user as default for security scanning
# The entrypoint script will escalate to root when needed
WORKDIR /home/nfsuser
# Set non-root user as default (Docker Scout requirement)
# The startup script will handle privilege escalation for NFS services
USER nfsuser
# Expose standard NFS ports
EXPOSE 2049/tcp 20048/tcp 111/tcp 111/udp 32765/tcp 32766/tcp
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
CMD showmount -e localhost | grep -q "/nfsshare/data" || exit 1
# Default environment variables (can be overridden)
ENV SHARE_NAME=default-share \
EXPORT_PATH=/nfsshare/data \
NFS_OPTIONS=rw,sync,no_subtree_check,no_root_squash,insecure \
CLIENT_CIDR=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
# Start NFS server
ENTRYPOINT ["/usr/local/bin/start-nfs.sh"]