Files
Portabase.Agent/docker/Dockerfile
T
Charles Gauthereau 5d87fb2d7d feat(files): files sources with Archive, Snapshots and Sync methods
Back up and restore plain directories, alongside the database sources.

Files source and Archive (P0)
- `files` type: absolute path (not /), options.exclude and
  options.one_file_system; walk + tar.gz with symlinks kept as links,
  special files skipped, unreadable entries fail the run.
- Mirror restore: archive validated first, then everything not excluded
  is wiped (mount points and special files kept) and the archive is
  extracted, retrying without metadata on filesystems refusing chown/chmod.
- Windows-safe platform helpers; helm extraVolumes/extraVolumeMounts.

Universal rclone mapper (P1)
- rclone_target(storage) for s3, blob, gcs, drive, rclone and sftp; sftp
  goes through it; rclone obscure reads the password from stdin.

Snapshots, restic (P2)
- restic in the image; repository per source and channel, password
  derived from the master key (HKDF); stable host, bs:<row> tags,
  translated excludes; exit 3 fails and forgets the snapshot.
- Mirror restore with `restic restore --delete`; restore payload carries
  the encrypted channel; snapshot ids must be full ids.
- Engine in the ping and in scheduled task metadata.

One locked method per source (spec A)
- databases.json declares options.method (archive, snapshot, sync),
  reported in the ping for local sources only.
- Sync: rclone sync per channel onto <folder>/sync/<id>/current, refuses
  an empty source, reports transferred/deleted counters.

Local channel (spec B)
- Snapshots and Sync reach the dashboard's local storage through its
  append-only restic REST server and its WebDAV server.

Security
- Strict rclone config validation: one section, no duplicate keys, no
  command, credential or host-file keys, no quoted values, valid backend
  type, blocked backends.
- Scheduled task metadata (decrypted storages) is no longer logged.
2026-10-04 10:09:56 +02:00

211 lines
6.7 KiB
Docker

# =========================
# MySQL client tools
# =========================
FROM mysql:8.4 AS mysql-client-tools
RUN mkdir -p /mysql-exports/bin /mysql-exports/lib \
&& cp /usr/bin/mysqldump /mysql-exports/bin/ \
&& find /usr/lib -name "libmysqlclient.so.21*" -exec cp {} /mysql-exports/lib/ \;
# =========================
# Base image (shared)
# =========================
FROM rust:1.98 AS base
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y curl ca-certificates \
&& curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc -o /etc/apt/trusted.gpg.d/pgdg.asc \
&& echo "deb https://apt.postgresql.org/pub/repos/apt trixie-pgdg main" > /etc/apt/sources.list.d/pgdg.list
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
pkg-config \
libssl-dev \
tzdata \
redis-server \
ca-certificates \
libpq5 \
libedit2 \
libreadline8 \
libncurses6 \
zlib1g \
curl \
mariadb-client \
sqlite3 \
redis-tools \
valkey \
firebird3.0-utils \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
ENV DOTNET_ROOT=/usr/local/dotnet
RUN curl -sSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh \
&& chmod +x /tmp/dotnet-install.sh \
&& /tmp/dotnet-install.sh --channel 8.0 --install-dir /usr/local/dotnet \
&& rm /tmp/dotnet-install.sh \
&& /usr/local/dotnet/dotnet tool install --global microsoft.sqlpackage
ENV PATH="$PATH:/usr/local/dotnet:/root/.dotnet/tools"
RUN ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') \
&& curl -sSL "https://github.com/microsoft/go-sqlcmd/releases/latest/download/sqlcmd-linux-${ARCH}.tar.bz2" \
| tar -xjf - -C /usr/local/bin sqlcmd \
&& chmod +x /usr/local/bin/sqlcmd
# =========================
# rclone (all storage backends)
# =========================
ARG RCLONE_VERSION=1.75.1
RUN ARCH=$(dpkg --print-architecture) \
&& curl -fsSL -o /tmp/rclone.deb "https://downloads.rclone.org/v${RCLONE_VERSION}/rclone-v${RCLONE_VERSION}-linux-${ARCH}.deb" \
&& dpkg -i /tmp/rclone.deb \
&& rm /tmp/rclone.deb
# =========================
# restic (Snapshots mode)
# =========================
ARG RESTIC_VERSION=0.19.1
RUN ARCH=$(dpkg --print-architecture) \
&& curl -fsSL -o /tmp/restic.bz2 "https://github.com/restic/restic/releases/download/v${RESTIC_VERSION}/restic_${RESTIC_VERSION}_linux_${ARCH}.bz2" \
&& bzip2 -d /tmp/restic.bz2 \
&& install -m 0755 /tmp/restic /usr/local/bin/restic \
&& rm /tmp/restic \
&& restic version
ARG TARGETARCH
# =========================
# PostgreSQL client binaries (versions 12-18)
# =========================
RUN for v in 12 13 14 15 16 17 18; do \
mkdir -p /usr/lib/postgresql/$v/bin; \
done
COPY assets/tools/amd64/postgresql/ /tmp/pg-x64/
COPY assets/tools/arm64/postgresql/ /tmp/pg-arm/
RUN if [ "$TARGETARCH" = "amd64" ]; then \
for v in 12 13 14 15 16 17 18; do \
cp -r /tmp/pg-x64/postgresql-$v/bin/* /usr/lib/postgresql/$v/bin/; \
done; \
elif [ "$TARGETARCH" = "arm64" ]; then \
for v in 12 13 14 15 16 17 18; do \
cp -r /tmp/pg-arm/postgresql-$v/bin/* /usr/lib/postgresql/$v/bin/; \
done; \
fi && \
rm -rf /tmp/pg-x64 /tmp/pg-arm && \
chmod +x /usr/lib/postgresql/*/bin/*
# =========================
# MongoDB client binaries
# =========================
COPY assets/tools/${TARGETARCH}/mongodb/ /usr/local/mongodb/
RUN chmod +x /usr/local/mongodb/bin/*
# =========================
# MySQL real mysqldump binary
# =========================
COPY --from=mysql-client-tools /mysql-exports/bin/mysqldump /usr/local/bin/mysqldump
COPY --from=mysql-client-tools /mysql-exports/lib/ /usr/local/lib/
RUN chmod +x /usr/local/bin/mysqldump && ldconfig
WORKDIR /app
# =========================
# Development image
# =========================
FROM base AS dev
RUN cargo install cargo-watch
RUN cargo install grcov --locked
COPY Cargo.toml Cargo.lock ./
RUN mkdir src && echo "fn main() {}" > src/main.rs
RUN cargo build
RUN rm -rf src
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
CMD ["/entrypoint.sh"]
# =========================
# Builder (production)
# =========================
FROM base AS builder
COPY . .
RUN cargo build --release
RUN echo "APP_VERSION=$(cargo pkgid | awk -F# '{print $2}')" > /app/version.env
# =========================
# Runtime (production)
# =========================
FROM ubuntu:24.04 AS prod
RUN apt-get update && apt-get install -y curl ca-certificates \
&& curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc -o /etc/apt/trusted.gpg.d/pgdg.asc \
&& echo "deb https://apt.postgresql.org/pub/repos/apt noble-pgdg main" > /etc/apt/sources.list.d/pgdg.list
RUN apt-get update && apt-get install -y \
redis-server \
ca-certificates \
tzdata \
libpq5 \
libedit2 \
libreadline8 \
libncurses6 \
zlib1g \
curl \
bzip2 \
mariadb-client \
sqlite3 \
redis-tools \
valkey \
firebird3.0-utils \
&& rm -rf /var/lib/apt/lists/*
ARG RCLONE_VERSION=1.75.1
RUN ARCH=$(dpkg --print-architecture) \
&& curl -fsSL -o /tmp/rclone.deb "https://downloads.rclone.org/v${RCLONE_VERSION}/rclone-v${RCLONE_VERSION}-linux-${ARCH}.deb" \
&& dpkg -i /tmp/rclone.deb \
&& rm /tmp/rclone.deb
# =========================
# restic (Snapshots mode)
# =========================
ARG RESTIC_VERSION=0.19.1
RUN ARCH=$(dpkg --print-architecture) \
&& curl -fsSL -o /tmp/restic.bz2 "https://github.com/restic/restic/releases/download/v${RESTIC_VERSION}/restic_${RESTIC_VERSION}_linux_${ARCH}.bz2" \
&& bzip2 -d /tmp/restic.bz2 \
&& install -m 0755 /tmp/restic /usr/local/bin/restic \
&& rm /tmp/restic \
&& restic version
ENV DOTNET_ROOT=/usr/local/dotnet
RUN curl -sSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh \
&& chmod +x /tmp/dotnet-install.sh \
&& /tmp/dotnet-install.sh --channel 8.0 --runtime dotnet --install-dir /usr/local/dotnet \
&& rm /tmp/dotnet-install.sh
WORKDIR /app
RUN mkdir -p /config
COPY --from=builder /app/target/release/app /usr/local/bin/app
COPY --from=builder /app/version.env /app/version.env
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
COPY --from=base /usr/lib/postgresql/ /usr/lib/postgresql/
COPY --from=base /usr/local/mongodb/bin/ /usr/local/mongodb/bin/
COPY --from=base /root/.dotnet/tools/ /root/.dotnet/tools/
COPY --from=mysql-client-tools /mysql-exports/bin/mysqldump /usr/local/bin/mysqldump
COPY --from=mysql-client-tools /mysql-exports/lib/ /usr/local/lib/
RUN chmod +x /usr/local/bin/mysqldump && ldconfig
ENV PATH="$PATH:/usr/local/dotnet:/root/.dotnet/tools"
ENV APP_ENV=production
CMD ["/entrypoint.sh"]