Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 4.x 👀 #7

Merged
merged 2 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions 4/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
FROM debian:bookworm-slim

RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
# mfscli (and cgi) are Python-based
python3 \
# mfsmount needs "fusermount"
fuse \
; \
rm -rf /var/lib/apt/lists/*; \
# allow running mfsmount as non-root
grep '^#user_allow_other$' /etc/fuse.conf; \
sed -ri 's/^#user_allow_other$/user_allow_other/' /etc/fuse.conf; \
grep '^user_allow_other$' /etc/fuse.conf

RUN set -eux; \
groupadd \
--gid 9400 \
--system \
mfs \
; \
useradd \
--comment 'MooseFS' \
--gid mfs \
--home-dir /var/lib/mfs \
--no-create-home \
--system \
--uid 9400 \
mfs \
; \
mkdir /var/lib/mfs; \
chown mfs:mfs /var/lib/mfs; \
id mfs

# https://github.com/moosefs/moosefs/releases
ENV MOOSEFS_VERSION 4.56.6

RUN set -eux; \
savedAptMark="$(apt-mark showmanual)"; \
apt-get update; \
apt-get install -y --no-install-recommends \
ca-certificates \
wget \
\
dpkg-dev \
file \
gcc \
libc6-dev \
libfuse-dev \
libpcap-dev \
make \
pkg-config \
zlib1g-dev \
; \
rm -rf /var/lib/apt/lists/*; \
\
wget -O moosefs.tgz "https://github.com/moosefs/moosefs/archive/v${MOOSEFS_VERSION}.tar.gz"; \
mkdir /usr/local/src/moosefs; \
tar --extract \
--file moosefs.tgz \
--directory /usr/local/src/moosefs \
--strip-components 1 \
; \
rm moosefs.tgz; \
\
( \
cd /usr/local/src/moosefs; \
gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \
./configure \
--build="$gnuArch" \
--disable-static \
--enable-option-checking=fatal \
--localstatedir=/var/lib \
--sysconfdir=/etc \
--with-default-group=mfs \
--with-default-user=mfs \
; \
); \
make -C /usr/local/src/moosefs -j "$(nproc)"; \
make -C /usr/local/src/moosefs install; \
ldconfig; \
rm -rf /usr/local/src/moosefs; \
\
# prep the default configuration so things generally work Out-of-the-Box
chown -R mfs:mfs /etc/mfs; \
for sample in /etc/mfs/*.sample; do \
cfg="${sample%.sample}"; \
[ -s "$cfg" ] || cp -avT "$sample" "$cfg"; \
done; \
cp -avT /etc/mfs /etc/mfs.sample; \
rm -v /etc/mfs.sample/*.sample; \
cp -avT /var/lib/mfs /var/lib/mfs.sample; \
cp -avT /var/lib/mfs/metadata.mfs.empty /var/lib/mfs/metadata.mfs; \
\
# allow us to run as an arbitrary user but still modify configuration
chmod 777 /etc/mfs; \
chmod 1777 /var/lib/mfs; \
\
apt-mark auto '.*' > /dev/null; \
apt-mark manual $savedAptMark > /dev/null; \
find /usr/local -type f -executable -exec ldd '{}' ';' \
| awk '/=>/ { so = $(NF-1); if (index(so, "/usr/local/") == 1) { next }; gsub("^/(usr/)?", "", so); print so }' \
| sort -u \
| xargs -r dpkg-query --search 2>/dev/null \
| cut -d: -f1 \
| sort -u \
| xargs -r apt-mark manual \
; \
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
\
mfsmount --version; \
mfscli -v; \
mfschunkserver -v; \
mfsmaster -v; \
mfschunktool -v; \
mfsmetalogger -v

RUN set -eux; \
# prep a scratch space with appropriate permissions to be able to do quick prototyping Out-of-the-Box
mkdir /mnt/mfs; \
chown mfs:mfs /mnt/mfs

# without this, the Python-based mfscli "-f" flag refuses to use UTF-8 box-drawing characters
ENV LANG=C.UTF-8

COPY docker-entrypoint.sh docker-chunkservers.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["bash"]
142 changes: 142 additions & 0 deletions 4/docker-chunkservers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#!/usr/bin/env bash
set -Eeuo pipefail

chunkservers="${MFS_CHUNKSERVERS:?set MFS_CHUNKSERVERS to the base directory of all chunkservers}"
cd "$chunkservers"

temp="$(mktemp -d)"
trap "$(printf 'rm -rf %q' "$temp")" EXIT

# if "ALLOW_STARTING_WITH_INVALID_DISKS" isn't set, let's change the default from 0 to 1
# (otherwise, a chunkserver with invalid disks stops ALL our chunkservers from starting)
: "${MFSCHUNKSERVER_ALLOW_STARTING_WITH_INVALID_DISKS:=1}"
export MFSCHUNKSERVER_ALLOW_STARTING_WITH_INVALID_DISKS

copy_etc() {
local dir="$1"; shift
cp -aT /etc/mfs "$dir"
find "$dir" -type f -exec sed -ri "s!/etc/mfs!$dir!g" '{}' +
}

declare -A pids=() cfgs=()

all_still_up() {
local name pid cfg
for name in "${!pids[@]}"; do
pid="${pids["$name"]}"
if [ ! -d "/proc/$pid" ]; then
if cfg="${cfgs["$name"]:-}" && [ -n "$cfg" ] && [ ! -s "$cfg" ]; then
# if a process is dead, and we had a config file but it's now empty or gone, we should ignore this process (was probably a removed drive/server)
unset pids["$name"] cfgs["$name"]
continue
fi
return 1
fi
done
if [ "${#pids[@]}" -eq 0 ]; then
# if we've emptied the full list of processes, we're not "up" anymore :)
return 1
fi
return 0
}
any_still_up() {
local pid
for pid in "${pids[@]}"; do
if [ -d "/proc/$pid" ]; then
return 0
fi
done
return 1
}
kill_all() {
local pid
for pid in "${pids[@]}"; do
if [ -d "/proc/$pid" ]; then
# try to make sure the process is still running before signalling it to avoid "pid X doesn't exist" over and over again if one is hung and we're trying to stop
kill "$@" "$pid"
fi
done
}
end_session() {
while any_still_up; do
kill_all
sleep 1
# TODO timeout?
done
exit "$@"
}
hup_all() {
if any_still_up; then
kill_all -HUP
fi
}
trap 'end_session 0' ABRT ALRM INT KILL PIPE QUIT STOP TERM USR1 USR2
trap 'end_session 1' ERR
trap 'hup_all' HUP

# backwards compatibility
for cfg in */mfshdd.cfg; do
[ -f "$cfg" ] || continue
dir="$(dirname "$cfg")"
new="$dir-mfshdd.cfg"
if [ ! -f "$new" ]; then
mv -vT "$cfg" "$new"
fi
done

# auto-detect and prepare new chunkservers
for chunks in */chunks/; do
chunks="${chunks%/}"
[ -d "$chunks" ] || continue
dir="$(dirname "$chunks")"
cfg="$dir-mfshdd.cfg"
if [ ! -s "$cfg" ]; then
readlink -ve "$chunks" >> "$cfg"
fi
done

port='9422'
for cfg in *-mfshdd.cfg; do
[ -f "$cfg" ] || continue

base="${cfg%-mfshdd.cfg}"
name="$(basename "$base")"
dir="$(dirname "$base")"

var="$dir/.var-lib-mfs-$name"
if [ ! -d "$var" ]; then
if [ -d "$dir/$name/var-lib-mfs" ]; then
# backwards compatibility
mv -vT "$dir/$name/var-lib-mfs" "$var"
else
# pre-seed our new state directory with the standard "empty" contents
cp -aT /var/lib/mfs "$var"
chmod 755 "$var" || :
fi
fi

copy_etc "$temp/$name"

sed -r "s!/etc/mfs!$temp/$name!g" /usr/local/bin/docker-entrypoint.sh > "$temp/$name/entrypoint.sh"
chmod +x "$temp/$name/entrypoint.sh"

cfg="$(readlink -ve "$cfg")"
var="$(readlink -ve "$var")"
MFSCHUNKSERVER_CSSERV_LISTEN_PORT="$port" \
MFSCHUNKSERVER_SYSLOG_IDENT="$name" \
MFSCHUNKSERVER_HDD_CONF_FILENAME="$cfg" \
MFSCHUNKSERVER_DATA_PATH="$var" \
"$temp/$name/entrypoint.sh" \
mfschunkserver -func "$temp/$name/mfschunkserver.cfg" &
pid="$!"
pids["$name"]="$pid"
cfgs["$name"]="$cfg"

(( port++ )) || :
all_still_up || end_session 1
done

while any_still_up; do
all_still_up || end_session 1
sleep 5
done
34 changes: 34 additions & 0 deletions 4/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/usr/bin/env bash
set -Eeuo pipefail

# see http://stackoverflow.com/a/2705678/433558
sed_escape_lhs() {
sed -e 's/[]\/$*.^|[]/\\&/g' <<<"$*"
}
sed_escape_rhs() {
sed -e 's/[\/&]/\\&/g' <<<"$*"
}

# magic with environment variables
for cfg in \
/etc/mfs/mfschunkserver.cfg \
/etc/mfs/mfsmaster.cfg \
/etc/mfs/mfsmetalogger.cfg \
; do
base="$(basename "$cfg" '.cfg')" # "mfsmaster", etc
base="${base^^}_" # "MFSMASTER_"
eval 'envs=( "${!'"$base"'@}" )' # envs=( "${!MFSMASTER_@}" )
for env in "${envs[@]}"; do
var="${env#$base}" # "HDD_CONF_FILENAME"
val="${!env}" # "/mnt/mfs/mfshdd.cfg"
sedVar="$(sed_escape_lhs "$var")"
sedVal="$(sed_escape_rhs "$val")"
sed -ri -e 's/^([[:space:]]*#)?[[:space:]]*('"$sedVar"')[[:space:]]*=.*$/\2 = '"$sedVal"'/' "$cfg"
if ! grep -qE "^$sedVar =" "$cfg"; then
echo >&2 "warning: $var ($env) was not found in '$cfg' (so might be a typo!)"
{ echo; echo "$var = $val"; } >> "$cfg"
fi
done
done

exec "$@"
Loading