diff --git a/docs/tutorial.rst b/docs/tutorial.rst index db83e22..3e4cd1f 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -6,7 +6,7 @@ Tutorial ======== -This tutorial shows how zrepl can be used to implement a ZFS-based pull backup. +This tutorial shows how zrepl can be used to implement a ZFS-based push backup. We assume the following scenario: * Production server ``prod`` with filesystems to back up: @@ -17,12 +17,12 @@ We assume the following scenario: * Backup server ``backups`` with - * Filesystem ``storage/zrepl/pull/prod`` + children dedicated to backups of ``prod`` + * Filesystem ``storage/zrepl/sink/prod`` + children dedicated to backups of ``prod`` Our backup solution should fulfill the following requirements: * Periodically snapshot the filesystems on ``prod`` *every 10 minutes* -* Incrementally replicate these snapshots to ``storage/zrepl/pull/prod/*`` on ``backups`` +* Incrementally replicate these snapshots to ``storage/zrepl/sink/prod/*`` on ``backups`` * Keep only very few snapshots on ``prod`` to save disk space * Keep a fading history (24 hourly, 30 daily, 6 monthly) of snapshots on ``backups`` @@ -31,74 +31,70 @@ Analysis We can model this situation as two jobs: -* A **source job** on ``prod`` +* A **push job** on ``prod`` * Creates the snapshots - * Keeps a short history of snapshots to enable incremental replication to ``backups`` - * Accepts connections from ``backups`` + * Keeps a short history of local snapshots to enable incremental replication to ``backups`` + * Connects to the ``zrepl daemon`` process on ``backups`` + * Pushes snapshots ``backups`` + * Prunes snapshots on ``backups`` after replication is complete -* A **pull job** on ``backups`` +* A **sink job** on ``backups`` - * Connects to the ``zrepl daemon`` process on ``prod`` - * Pulls the snapshots to ``storage/zrepl/pull/prod/*`` - * Fades out snapshots in ``storage/zrepl/pull/prod/*`` as they age - - -Why doesn't the **pull job** create the snapshots before pulling? - -As is the case with all distributed systems, the link between ``prod`` and ``backups`` might be down for an hour or two. -We do not want to sacrifice our required backup resolution of 10 minute intervals for a temporary connection outage. - -When the link comes up again, ``backups`` will catch up with the snapshots taken by ``prod`` in the meantime, without a gap in our backup history. + * Accepts connections & responds to requests from ``prod`` + * Limits client ``prod`` access to filesystem sub-tree ``storage/zrepl/sink/prod`` Install zrepl ------------- Follow the :ref:`OS-specific installation instructions ` and come back here. -Configure server ``backups`` ----------------------------- - -We define a **pull job** named ``pull_prod`` in ``/etc/zrepl/zrepl.yml`` or ``/usr/local/etc/zrepl/zrepl.yml`` on host ``backups`` : :: - - jobs: - - name: pull_prod - type: pull - connect: - type: tcp - address: "192.168.2.20:2342" - root_fs: "storage/zrepl/pull/prod" - interval: 10m - pruning: - keep_sender: - - type: not_replicated - - type: last_n - count: 10 - keep_receiver: - - type: grid - grid: 1x1h(keep=all) | 24x1h | 30x1d | 6x30d - regex: "^zrepl_" - interval: 10m - -The ``connect`` section instructs the zrepl daemon to use plain TCP transport. -Check out the :ref:`transports ` section for alternatives that support encryption. - -.. _tutorial-configure-prod: - -Configure server ``prod`` +Generate TLS Certificates ------------------------- -We define a corresponding **source job** named ``source_backups`` in ``/etc/zrepl/zrepl.yml`` or ``/usr/local/etc/zrepl/zrepl.yml`` on host ``prod`` : :: +We use the `TLS client authentication transport ` to protect our data on the wire. +To get things going quickly, we skip setting up a CA and generate two self-signed certificates as described :ref:`here `. +Again, for convenience, We generate the key pairs on our local machine and distribute them using ssh: + +.. code-block:: bash + :emphasize-lines: 6,13 + + openssl req -x509 -sha256 -nodes \ + -newkey rsa:4096 \ + -days 365 \ + -keyout backups.key \ + -out backups.crt + # ... and use "backups" as Common Name (CN) + + openssl req -x509 -sha256 -nodes \ + -newkey rsa:4096 \ + -days 365 \ + -keyout prod.key \ + -out prod.crt + # ... and use "prod" as Common Name (CN) + + ssh root@backups "mkdir /etc/zrepl" + scp backups.key backups.crt prod.crt root@backups:/etc/zrepl + + ssh root@prod "mkdir /etc/zrepl" + scp prod.key prod.crt backups.crt root@prod:/etc/zrepl + + +Configure server ``prod`` +---------------------------- + +We define a **push job** named ``prod_to_backups`` in ``/etc/zrepl/zrepl.yml`` on host ``prod`` : :: jobs: - - name: source_backups - type: source - serve: - type: tcp - listen: ":2342" - clients: { - "192.168.2.10" : "backups" - } + - name: prod_to_backups + type: push + connect: + type: tls + address: "backups.example.com:8888" + ca: /etc/zrepl/backups.crt + cert: /etc/zrepl/prod.crt + key: /etc/zrepl/prod.key + server_cn: "backups" filesystems: { "zroot/var/db:": true, "zroot/usr/home<": true, @@ -108,39 +104,69 @@ We define a corresponding **source job** named ``source_backups`` in ``/etc/zrep type: periodic prefix: zrepl_ interval: 10m + pruning: + keep_sender: + - type: not_replicated + - type: last_n + count: 10 + keep_receiver: + - type: grid + grid: 1x1h(keep=all) | 24x1h | 30x1d | 6x30d + regex: "^zrepl_" +.. _tutorial-configure-prod: + +Configure server ``prod`` +------------------------- + +We define a corresponding **sink job** named ``sink`` in ``/etc/zrepl/zrepl.yml`` on host ``prod`` : :: + + jobs: + - name: sink + type: sink + serve: + type: tls + listen: ":8888" + ca: "/etc/zrepl/prod.crt" + cert: "/etc/zrepl/backups.crt" + key: "/etc/zrepl/backups.key" + client_cns: + - "prod" + root_fs: "storage/zrepl/sink" -The ``serve`` section whitelists ``backups``'s IP address ``192.168.2.10`` and assigns it the client identity ``backups`` which will show up in the logs. -Again, check the :ref:`docs for encrypted transports `. Apply Configuration Changes --------------------------- -We need to restart the zrepl daemon on **both** ``prod`` and ``backups``. -This is :ref:`OS-specific `. +We use ``zrepl configcheck`` before to catch any configuration errors: no output indicates that everything is fine. +If that is the case, restart the zrepl daemon on **both** ``prod`` and ``backups`` using ``service zrepl restart`` or ``systemctl restart zrepl``. + Watch it Work ------------- Run ``zrepl status`` on ``prod`` to monitor the replication and pruning activity. - -Additionally, you can check the detailed structured logs of the `zrepl daemon` process and use GNU *watch* to view the snapshots present on both machines. +To re-trigger replication (snapshots are separate!), use ``zrepl signal wakeup prod_to_backups`` on ``prod``. If you like tmux, here is a handy script that works on FreeBSD: :: pkg install gnu-watch tmux - tmux new-window - tmux split-window "tail -f /var/log/zrepl.log" - tmux split-window "gnu-watch 'zfs list -t snapshot -o name,creation -s creation | grep zrepl_'" - tmux select-layout tiled + tmux new -s zrepl -d + tmux split-window -t zrepl "tail -f /var/log/messages" + tmux split-window -t zrepl "gnu-watch 'zfs list -t snapshot -o name,creation -s creation | grep zrepl_'" + tmux split-window -t zrepl "zrepl status" + tmux select-layout -t zrepl tiled + tmux attach -t zrepl The Linux equivalent might look like this: :: # make sure tmux is installed & let's assume you use systemd + journald - tmux new-window - tmux split-window "journalctl -f -u zrepl.service" - tmux split-window "watch 'zfs list -t snapshot -o name,creation -s creation | grep zrepl_'" - tmux select-layout tiled + tmux new -s zrepl -d + tmux split-window -t zrepl "journalctl -f -u zrepl.service" + tmux split-window -t zrepl "watch 'zfs list -t snapshot -o name,creation -s creation | grep zrepl_'" + tmux split-window -t zrepl "zrepl status" + tmux select-layout -t zrepl tiled + tmux attach -t zrepl Summary -------