diff --git a/docker/stacks/archmirror/docker-compose.yml b/docker/stacks/archmirror/docker-compose.yml new file mode 100644 index 0000000..6626dba --- /dev/null +++ b/docker/stacks/archmirror/docker-compose.yml @@ -0,0 +1,44 @@ +services: + rsync-mirror: + build: + context: ./rsync + dockerfile: Dockerfile + environment: + - MIRROR_URL=${MIRROR_URL} + - SYNC_SCHEDULE=${SYNC_SCHEDULE} + - TZ=${TZ} + - RSYNC_EXTRA_OPTIONS=${RSYNC_EXTRA_OPTIONS} + volumes: + - ${ARCHLINUX_VOLUME_PATH:-./archlinux}:/archlinux + restart: unless-stopped + healthcheck: + test: ["CMD", "ps", "aux", "|", "grep", "[s]upercronic"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + + nginx-server: + build: + context: ./nginx + dockerfile: Dockerfile + ports: + - "${HTTP_PORT:-8080}:80" + volumes: + - ${ARCHLINUX_VOLUME_PATH:-./archlinux}:/usr/share/nginx/html/archlinux:ro + environment: + - NGINX_WORKERS=${NGINX_WORKERS} + depends_on: + rsync-mirror: + condition: service_healthy + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost/"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 15s + +networks: + default: + name: archlinux-mirror-net diff --git a/docker/stacks/archmirror/nginx/Dockerfile b/docker/stacks/archmirror/nginx/Dockerfile new file mode 100644 index 0000000..9e620af --- /dev/null +++ b/docker/stacks/archmirror/nginx/Dockerfile @@ -0,0 +1,3 @@ +FROM nginx:alpine + +COPY nginx.conf /etc/nginx/nginx.conf diff --git a/docker/stacks/archmirror/nginx/nginx.conf b/docker/stacks/archmirror/nginx/nginx.conf new file mode 100644 index 0000000..67edde7 --- /dev/null +++ b/docker/stacks/archmirror/nginx/nginx.conf @@ -0,0 +1,30 @@ +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + sendfile on; + gzip on; + + server { + listen 80; + root /usr/share/nginx/html; + + location /archlinux/ { + alias /usr/share/nginx/html/archlinux/; + autoindex on; + } + + location = / { + return 301 /archlinux/; + } + + location /health { + return 200 "OK\n"; + add_header Content-Type text/plain; + } + } +} diff --git a/docker/stacks/archmirror/rsync/Dockerfile b/docker/stacks/archmirror/rsync/Dockerfile new file mode 100644 index 0000000..d32f584 --- /dev/null +++ b/docker/stacks/archmirror/rsync/Dockerfile @@ -0,0 +1,24 @@ +FROM alpine:latest AS builder + +RUN apk add --no-cache curl \ + && curl -fsSLO https://github.com/aptible/supercronic/releases/download/v0.2.29/supercronic-linux-amd64 \ + && echo "cd48d45c4b10f3f0bfdd3a57d054cd05ac96812b supercronic-linux-amd64" | sha1sum -c - \ + && chmod +x supercronic-linux-amd64 + +FROM alpine:latest + +RUN apk add --no-cache rsync flock \ + && rm -rf /var/cache/apk/* + +COPY --from=builder /supercronic-linux-amd64 /usr/local/bin/supercronic + +RUN mkdir -p /archlinux /var/log /var/lock + +COPY sync.sh /usr/local/bin/sync.sh +COPY crontab /etc/crontab + +RUN chmod +x /usr/local/bin/sync.sh + +WORKDIR /archlinux + +CMD ["supercronic", "/etc/crontab"] \ No newline at end of file diff --git a/docker/stacks/archmirror/rsync/crontab b/docker/stacks/archmirror/rsync/crontab new file mode 100644 index 0000000..f576687 --- /dev/null +++ b/docker/stacks/archmirror/rsync/crontab @@ -0,0 +1,2 @@ +0 */6 * * * /usr/bin/flock -n /var/lock/archlinux-sync.lock /usr/local/bin/sync.sh +* * * * * [ ! -f /var/lock/initial-sync-done ] && /usr/bin/flock -n /var/lock/archlinux-sync.lock /usr/local/bin/sync.sh && touch /var/lock/initial-sync-done diff --git a/docker/stacks/archmirror/rsync/sync.sh b/docker/stacks/archmirror/rsync/sync.sh new file mode 100644 index 0000000..f208ae6 --- /dev/null +++ b/docker/stacks/archmirror/rsync/sync.sh @@ -0,0 +1,32 @@ +#!/bin/sh +set -e + +TARGET_DIR="/archlinux" +MAX_RETRIES=3 + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >&2 +} + +if [ -z "$MIRROR_URL" ]; then + log "ERROR: MIRROR_URL not set" + exit 1 +fi + +mkdir -p "$TARGET_DIR" +for i in $(seq 1 $MAX_RETRIES); do + log "Sync attempt $i/$MAX_RETRIES from $MIRROR_URL" + + if rsync --timeout=7200 \ + -rlptH --safe-links --delete-delay --delay-updates \ + ${RSYNC_EXTRA_OPTIONS:-} \ + "$MIRROR_URL/" "$TARGET_DIR/"; then + log "Sync completed successfully" + exit 0 + fi + + [ $i -lt $MAX_RETRIES ] && sleep $((i * 300)) +done + +log "All sync attempts failed" +exit 1 diff --git a/docker/stacks/archmirror/stack.env b/docker/stacks/archmirror/stack.env new file mode 100644 index 0000000..5e1ded6 --- /dev/null +++ b/docker/stacks/archmirror/stack.env @@ -0,0 +1,14 @@ +# Mirror Configuration +MIRROR_URL= +SYNC_SCHEDULE=0 */6 * * * +RSYNC_EXTRA_OPTIONS=--info=progress2 + +# HTTP Configuration +HTTP_PORT=8080 +NGINX_WORKERS=auto + +# Path Configuration +ARCHLINUX_VOLUME_PATH= + +# Basic Configuration +TZ=UTC \ No newline at end of file