summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Warner <antarus@gentoo.org>2022-06-22 16:58:03 -0700
committerAlec Warner <antarus@gentoo.org>2022-06-22 16:58:03 -0700
commitde8adc8e50b119abff3a9db4ed3a71d8b1187e1b (patch)
treebd7333c8d6271af7aeb086794fed48051f182788
parentAdd a docker container for rsync. (diff)
downloadrsync-service-de8adc8e50b119abff3a9db4ed3a71d8b1187e1b.tar.gz
rsync-service-de8adc8e50b119abff3a9db4ed3a71d8b1187e1b.tar.bz2
rsync-service-de8adc8e50b119abff3a9db4ed3a71d8b1187e1b.zip
Update this codebase.
maffblaster wants to use it, so fix a bunch of bugs. Signed-off-by: Alec Warner <antarus@gentoo.org>
-rw-r--r--Dockerfile22
-rwxr-xr-xrsyncd.conf20
-rwxr-xr-xwrap_rsync.sh71
3 files changed, 56 insertions, 57 deletions
diff --git a/Dockerfile b/Dockerfile
index 73a69da..7948ca8 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,36 +1,26 @@
-# Base Image
-FROM gentoo/stage3-amd64-hardened:latest AS base
-WORKDIR /
-
+# image is based on stage3-amd64
+FROM gentoo/stage3-amd64:latest
+COPY rsyncd.conf /opt/rsync/rsyncd.conf
COPY wrap_rsync.sh /opt/rsync/wrap_rsync.sh
-COPY ./rsync-mirror /etc/xinetd.d/rsync-mirror
# Normally I would advocate for ARG here and pass arguments to wrap_rsync.
# This would enable new docker builds with arguments like:
# docker build . --build_arg WAIT_TIME=30m -t gentoo/rsync
# However, ARG's cannot be passed to ENTRYPOINTs, so we set these as ENV instead.
-
# Mirror to get data from.
ENV SOURCE_MIRROR=rsync://turnstone.gentoo.org./gentoo-portage
# ENV SOURCE_MIRROR=rsync://rsync.us.gentoo.org/gentoo-portage
-
-# Possibly a stateful volume
+# Where to write the data in this container.
ENV DEST_DIR=/srv/gentoo
-# A memory-backed volume
-ENV TMP_DIR=/srv/ephemeral
-
# How long to wait between syncs; must be a valid argument to sleep
ENV WAIT_TIME=30m
-# Create TMP_DIR and DEST_DIR
-WORKDIR $TMP_DIR
+# This needs to exist in the container.
WORKDIR $DEST_DIR
# Expose Rsync port
EXPOSE 873
-# Stop xinetd; wrap_rsync will start it when the container is started.
-CMD /etc/init.d/xinetd stop
+CMD mount -t tmpfs -o size=2g,nr_inodes=2000000 tmpfs /srv/gentoo
-# Execute wrapper.
ENTRYPOINT /opt/rsync/wrap_rsync.sh
diff --git a/rsyncd.conf b/rsyncd.conf
new file mode 100755
index 0000000..bc9ccc0
--- /dev/null
+++ b/rsyncd.conf
@@ -0,0 +1,20 @@
+
+uid = nobody
+gid = nobody
+# We are in a container, who cares.
+use chroot = no
+# Let clients use as much as they want; CPU control is in a load balancer in front of us.
+max connections = 0
+
+motd file = ./rsyncd.motd
+# On GCP, the default log collector only collects syslog, so just toss logs in there.
+log file = /var/log/syslog
+transfer logging = yes
+log format = %t %a %m %f %b
+syslog facility = daemon
+timeout = 300
+
+[gentoo-portage]
+path = /srv/gentoo/serving
+comment = Gentoo Linux Portage tree mirror
+exclude = distfiles
diff --git a/wrap_rsync.sh b/wrap_rsync.sh
index fb420dc..60f7687 100755
--- a/wrap_rsync.sh
+++ b/wrap_rsync.sh
@@ -1,21 +1,23 @@
-#!/bin/bash
-
-set -x
+#!/bin/bash -x
# On container start, run an rsync to get a good copy of the tree.
-# Once we have a copy, start xinetd to start serving.
+# Then execute rsyncd; we will start serving once the sync completes.
# Then keep syncing in the background every 30m.
+# We keep the trees in a TMPFS, we need a million inodes and 1300MB of space.
+mount -t tmpfs -o size=1300m,nr_inodes=1000000 tmpfs "${DEST_DIR}"
+if [[ $? -ne 0 ]]; then
+ logger -t rsync "Init: Failed to create tmpfs: ${DEST_DIR}"
+ return 1
+fi
+
# Maintain 2 'partitions' of the tree.
# "serving" - This copy is served to users and is not mutated.
# "updating" - This copy is a shadow copy used for updates.
# Create the two partitions on startup.
-# We will swap between them at runtime.
PARTITION1=$(mktemp -d -p "${DEST_DIR}" XXXXXX)
PARTITION2=$(mktemp -d -p "${DEST_DIR}" XXXXXX)
-# Our stateful copy.
-UPDATES=${DEST_DIR}/stateful
# Function sync syncs dest ("${2}") from source ("${1}")
function sync() {
@@ -46,62 +48,49 @@ function sync() {
return 0
}
-# Init will update the stateful tree copy.
-# Then it will copy that to the stateless partition.
+# Function init does a first sync, to populate the serving partition and
+# setup symlinks, and begin serving data.
+# "${1}" is the serving partition. "${2}" is the update partition
function init() {
- sync "${UPDATING}" "${SOURCE_MIRROR}" # this is synchronous.
- sync "${UPDATING}" "${PARTITION1}"
+ sync "${1}" "${SOURCE_MIRROR}" # this is synchronous.
- # We serve out of ${TMP_DIR}/serving
- ln -s "${PARTITION1}" "${TMP_DIR}/serving"
- # The second partition will be for stateless updates.
- ln -s "${PARTITION2}" "${TMP_DIR}/update"
+ # We serve out of ${DEST_DIR}/serving
+ ln -s "${1}" "${DEST_DIR}/serving"
+ # Setup the update partition
+ ln -s "${2}" "${DEST_DIR}/update"
- # Then launch xinetd; it will detech into the background and serve.
- /etc/init.d/xinetd start
+ # Then launch rsyncd; it will detach into the background and serve from serving.
+ rsync --daemon --config="/opt/rsync/rsyncd.conf"
+ return 0
}
-# function update syncs the UPDATING partition (stateful.)
-# Then it syncs it into the ${TMP_DIR}/update partition (stateless.)
-# Then we swap the two stateless partitions (via symlinks swapping.)
+# Function update syncs the 'update' partition and, if successful, swaps the partitions.
function update() {
- update=$(readlink "${TMP_DIR}/update")
- # Try to update our stateful tree copy.
- if ! sync "${UPDATING}" "${SOURCE_MIRROR}"; then
+ update=$(readlink "${DEST_DIR}/update")
+ # If we fail to sync, just return false and avoid modifying the serving state.
+ if ! sync "${update}" "${SOURCE_MIRROR}"; then
return 1
fi
- # Try to update our stateless copy.
- if ! sync "${update}" "${UPDATING}"; then
- return 1
- fi
-
- # Quasi-atomic swap with symlinks.
# Save the previous serving partition
- old_serving=$(readlink "${TMP_DIR}/serving")
+ old_serving=$(readlink "${DEST_DIR}/serving")
# Point the serving symlink at the update partition; now freshly updated.
- mv -fT "${TMP_DIR}/update" "${TMP_DIR}/serving"
+ mv -fT "${DEST_DIR}/update" "${DEST_DIR}/serving"
# Point the update partition at the old serving partition.
- ln -sf "${old_serving}" "${TMP_DIR}/update"
-
- # Its plausible here that users may still be accessing the old_serving copy, so we don't delete it or anything.
-}
-
-function health() {
- /etc/init.d/xinetd status
+ ln -sf "${old_serving}" "${DEST_DIR}/update"
}
function serve() {
while true
do
+ # TODO(antarus): Add exponential backoff.
sleep "${WAIT_TIME}"
update
- # If xinetd died, just suicide and docker will restart us.
- health || exit 5
done
}
-init
+# Partition1 starts as "serving", partition2 as "update"
+init "${PARTITION1}" "${PARTITION2}"
if [[ $? -ne 0 ]]; then
exit 1
fi