sandcastle-ng

Scripts for the deployment of Sandcastle (GNU Taler)
Log | Files | Refs | README

README.md (13237B)


      1 # Introduction
      2 
      3 The sandcastle is a containerized deployment of GNU Taler
      4 
      5 It uses podman to build an image and run a single container that
      6 has systemd running inside.
      7 
      8 
      9 # Prerequisites
     10 
     11 You need (on your host system):
     12 
     13 * podman
     14 * bash
     15 * Python 3.10 or newer
     16 
     17 The sandcastle-ng container exposes the GNU Taler APIs and Web interfaces
     18 through Unix domain sockets.
     19 
     20 Some of these services expect to be accessed via a certain hostname,
     21 so it is recommended that you set up the following domain names:
     22 
     23 * `exchange.$MYDOMAIN` for taler-exchange
     24 * `backend.$MYDOMAIN` for taler-merchant
     25 * `bank.$MYDOMAIN` for libeufin-bank
     26 * `landing.$MYDOMAIN` for the demo landing page
     27 * `shop.$MYDOMAIN` for the demo blog shop page
     28 * `donations.$MYDOMAIN` for the demo donations page
     29 * `paivana.$MYDOMAIN` for the demo Paivana paywall
     30 
     31 Your host system should reverse-proxy HTTP(s) traffic to the respective service
     32 socket.
     33 
     34 
     35 # Upgrading Component Versions
     36 
     37 `packages.toml` is the single source of truth for package repositories, tags,
     38 Debian paths, dependencies, enabled state, and builders.  It uses the same
     39 `[repositories]` and `[packages]` layout as
     40 `taler-deployment/packaging/ng/packages.toml`.
     41 
     42 Run `./sandcastle-upgrade` to update package tags in `packages.toml` to the
     43 latest upstream tag of the respective repository.
     44 
     45 By default only production tags (`vX.Y.Z`, `deb-vX.Y.Z-R`) are considered.
     46 Pass `--dev` to also consider dev tags (`vX.Y.Z-dev.N`).
     47 Pass `--dry` to only show what would change.
     48 Individual components can be given as arguments, e.g.
     49 
     50     ./sandcastle-upgrade --dev taler-exchange gnunet
     51 
     52 Packages whose configured tag is not a supported version tag are left alone.
     53 Use `./sandcastle-upgrade --dry` to show available updates without changing the
     54 configuration.
     55 
     56 
     57 # Building the Container Image
     58 
     59 1. Set the package's `tag` in `packages.toml` to the git tag you want to build.
     60 
     61 2. Run `./sandcastle-build` to build the Taler container.  The resulting container
     62    will be tagged as `taler-base-all`.
     63 
     64    Package builds are incremental.  Built Debian packages and their build keys
     65    are kept below `packages/`, while downloaded build data is kept below
     66    `cache/`.  A component is rebuilt when its resolved package configuration,
     67    build logic, builder image, or one of its package dependencies changes.
     68    Unrelated packages remain untouched.  Failed builds are not recorded as
     69    current, so they are retried on the next invocation.
     70 
     71    Packages using the `pnpm-workspace` builder are grouped by repository and
     72    tag.  Each group clones and bootstraps the monorepo once, performs one
     73    filtered pnpm install and build for all selected workspace dependency
     74    closures, and then creates the individual Debian packages from the prebuilt
     75    artifacts.
     76 
     77    Apt, pnpm, Gradle, Cargo, npm, Go, and pip caches are shared between package
     78    containers.  Source checkouts and package build trees remain fresh.
     79 
     80    Use `./sandcastle-build --no-cache` to rebuild the package builder, every
     81    component package, and the final image without cached image layers.  Shared
     82    dependency and compiler caches are retained.
     83 
     84    By default `sandcastle-build` builds from the `Dockerfile`
     85    in the same directory as the script.
     86    Anyhow you can pass a different container file like this:
     87 
     88        ./sandcastle-build nightly.Dockerfile
     89 
     90 
     91 # Configuring the Deployment
     92 
     93 If you just want to play around with the Taler services inside the container,
     94 or want to get an integration development environment,
     95 there is a nice preset, see below.
     96 Thus in these cases no configuration is required
     97 and you can skip to "Running the Deployment" below.
     98 
     99 For Taler developers, it is recommended that for each sandcastle deployment,
    100 you clone the sandcastle-ng.git repository
    101 (https://git.taler.net/sandcastle-ng.git) and create a branch with
    102 deployment-specific changes.
    103 
    104 Currently there is not much configuration.
    105 
    106 The main adjustments to be made are:
    107 
    108 * scripts/demo/setup-sandcastle.sh has the currency on top of the file
    109 * Services use Unix sockets below `sockets/` by default.  Set
    110   `SANDCASTLE_SOCKET_DIR` to choose a different host directory.
    111 
    112 To make adjustments for an environment without changing the
    113 ``setup-sandcastle.sh`` script, you can use an override file
    114 ``overrides/$YOUR_ENVIRONMENT``.  This is a bash script that is sourced at the
    115 beginning of ``setup-sandcastle.sh`` and can be used to customize
    116 environment-specific settings such as hostnames.
    117 
    118 In order to choose an override,
    119 set the ``SANDCASTLE_OVERRIDE_NAME`` environment variable
    120 before running `./sandcastle-run`:
    121 
    122     SANDCASTLE_OVERRIDE_NAME=$YOUR_ENVIRONMENT ./sandcastle-run
    123 
    124 
    125 The following variables are typically adjusted in an override file:
    126 
    127 * ``CURRENCY``: Currency of the deployment
    128 * ``MYDOMAIN``: Parent domain name for ``{bank,exchange,backend}`` services.
    129 * ``EXTERNAL_PORT``: The host port the services will be available on.
    130 * ``EXTERNAL_IP``: The host IP the services will be available on.
    131   For security reasons this defaults to localhost (127.0.0.1).
    132 * ``USE_INSECURE_SANDBOX_PASSWORDS``:
    133     If set to `1`, use password `sandbox` for all services instead of random ones.
    134     WARNING! Use only when listening to localhost!
    135 * ``PAIVANA_DESTINATION``: Upstream website that the Paivana paywall
    136   protects.  Defaults to `https://www.taler.net/`.  Note that this is an
    137   *external* server that the container proxies to, it is not served by the
    138   sandcastle itself.
    139 * ``ENABLE_KYC``: Set to `1` to enable KYC; it is disabled by default.
    140 * ``ENABLE_TURNSTILE``: Set to `0` to omit the Drupal Turnstile setup; it is
    141   enabled by default.
    142 
    143 
    144 # Running the Deployment
    145 
    146 Run ``./sandcastle-run`` to run the single container.
    147 The container will be named `taler-sandcastle`.
    148 Wait until everything has been set up:
    149 
    150     ./sandcastle-wait
    151 
    152 While provisioning is running, this follows the output of
    153 ``setup-sandcastle.service`` inside the container.  It exits successfully once
    154 provisioning has completed, or with a non-zero status if provisioning fails.
    155 After a successful deployment, the landing host serves the Sandcastle version,
    156 component versions, and deployment time at ``/metrics/sandcastle-status``.
    157 
    158 Note that ``./sandcastle-run`` is just a wrapper around ``podman run``.
    159 If required, you can pass addtional arguments to ``./sandcastle-run``.
    160 These will be passed on to ``podman run``. Example:
    161 
    162     ./sandcastle-run --log-level=debug
    163 
    164 The running container exposes these services through bind-mounted Unix sockets:
    165 
    166 | Service | Socket |
    167 | --- | --- |
    168 | Bank | `bank.sock` |
    169 | Exchange | `exchange.sock` |
    170 | Merchant backend | `merchant-backend.sock` |
    171 | Landing page | `landing.sock` |
    172 | Blog shop | `blog.sock` |
    173 | Donations | `donations.sock` |
    174 | Challenger | `challenger.sock` |
    175 | Auditor | `auditor.sock` |
    176 | Donau | `donau.sock` |
    177 | Drupal | `drupal.sock` |
    178 | Paivana | `paivana.sock` |
    179 
    180 Exchange, Merchant, the Blog and Donations demos, Auditor, Donau, and Paivana
    181 are exposed directly through their native listener or packaged systemd socket
    182 activation.  Caddy owns the bank socket to bridge libeufin-bank's internal TCP
    183 listener, the landing socket to add the Sandcastle status endpoint, the
    184 Challenger socket to serve the insecure demo challenges, and the Drupal socket
    185 because it is Drupal's HTTP server.
    186 
    187 For example, query the Exchange and merchant configuration endpoints with:
    188 
    189     curl --unix-socket ./sockets/exchange.sock http://localhost/config
    190     curl --unix-socket ./sockets/merchant-backend.sock http://localhost/config
    191 
    192 The socket directory defaults to `./sockets`, relative to the repository, and
    193 can be changed when starting the deployment:
    194 
    195     SANDCASTLE_SOCKET_DIR=/run/taler-sandcastle ./sandcastle-run
    196 
    197 Missing socket directories are created with mode `1777`, and the sockets have
    198 mode `0666`, so a host reverse proxy running as a different user can connect to
    199 them.  A pre-existing custom directory must allow the relevant container
    200 service users to create sockets.  The bind mount uses Podman's shared SELinux
    201 label; deployments with a confined host reverse proxy may additionally need
    202 an appropriate local SELinux policy.
    203 
    204 libeufin-bank does not yet support Unix sockets, so it listens on localhost
    205 inside the container and Caddy exposes it through `bank.sock`.
    206 
    207 The shared bank Caddy configuration redirects `/` to `/webui/` while preserving
    208 query parameters. The demo links use language entry paths such as `/de/` and
    209 `/de_CH/`, which redirect to `/webui/?lang=de` and
    210 `/webui/?lang=de_CH`. The path language replaces an existing `lang` parameter;
    211 other query parameters are retained. These temporary redirects apply to GET
    212 and HEAD requests through both the bank socket and HTTP/HTTPS ingress.
    213 
    214 Overrides that define `EXTERNAL_PORT`, such as `taler.localhost`, continue to
    215 publish that single Caddy ingress port for local integration testing.
    216 
    217 When starting sandcastle like
    218 
    219     SANDCASTLE_OVERRIDE_NAME=taler.localhost ./sandcastle-run
    220 
    221 the services will be available as
    222 
    223  - http://taler.localhost:4321
    224  - http://bank.taler.localhost:4321
    225  - http://shop.taler.localhost:4321
    226  - http://donations.taler.localhost:4321
    227  - http://backend.taler.localhost:4321  - the merchant backend
    228  - http://exchange.taler.localhost:4321
    229  - http://auditor.taler.localhost:4321
    230  - http://challenger.taler.localhost:4321
    231  - http://paivana.taler.localhost:4321/en/  - www.taler.net behind a Taler paywall
    232    (use the ``/en/`` entry point, as www.taler.net redirects ``/`` to its own domain)
    233 
    234 This gives a nice environment for integration testing.
    235 
    236 
    237 # Running the Unit Tests
    238 
    239 Run the Python unit-test suite from the repository root:
    240 
    241     python3 -m unittest discover -s tests -v
    242 
    243 
    244 # Stopping the deployment
    245 
    246 For stopping the deployment simply run
    247 
    248 ```
    249 ./sandcastle-stop
    250 ```
    251 
    252 which is just a shortcut for ``podman stop taler-sandcastle``.
    253 
    254 
    255 # Watching Logs
    256 
    257 Run ``./sandcastle-logs`` to watch the logs within the container.
    258 You can pass addtional arguments to ``./sandcastle-logs``,
    259 which will be passed on to ``journalctl`` in the container.  Example:
    260 
    261     ./sandcastle-logs --output=cat
    262 
    263 
    264 # Poking Around
    265 
    266 You can poke around in a running sandcastle instance by running
    267 
    268 ```
    269 podman exec -it taler-sandcastle /bin/bash
    270 ```
    271 
    272 Or, as a shortcut:
    273 
    274 ```
    275 ./sandcastle-enter
    276 ```
    277 
    278 This will drop you into a shell inside the running container,
    279 where you have access to systemd, journalctl, etc.
    280 
    281 
    282 # Data Storage
    283 
    284 All persistent data is stored in a podman volume called
    285 _talerdata_.  You can see where it is in your filesystem
    286 by running ``podman volume inspect talerdata``.
    287 
    288 That volume also contains the postgres database files.
    289 
    290 ## Cleaning the Data Storage
    291 
    292 For cleaning the data storage run
    293 
    294     ./sandcastle-plow
    295 
    296 and for cleaning also the persistent storage run
    297 
    298     ./sandcastle-plow all
    299 
    300 
    301 # Provisioning Details
    302 
    303 The whole deployment is configured by a script
    304 mounted into the container as ``/provision/setup-sandcastle.sh``.
    305 This script will be run as a oneshot systemd service and will disable itself after
    306 the first success.
    307 
    308 To troubleshoot, run ``journalctl -u setup-sandcastle.service``.
    309 
    310 There are different setup scripts in the ``scripts/$SANDCASTLE_SETUP_NAME``
    311 folders. Specifically:
    312 
    313 * ``none`` does no setup at all
    314 * ``demo`` set up the usual Taler demo
    315 * TBD: ``regio`` is a currency conversion setup
    316 
    317 By default, ``demo`` is used.
    318 To mount a different provision script,
    319 set ``$SANDCASTLE_SETUP_NAME`` when running ``./sandcastle-run``,
    320 like this
    321 
    322     SANDCASTLE_SETUP_NAME=none ./sandcastle-run
    323 
    324 
    325 You can always manually run any of the provisioning script inside the container as
    326 ``/scripts/$SANDCASTLE_SETUP_NAME/setup-sandcastle.sh``.
    327 
    328 # Importing / exporting
    329 
    330 To migrate a sandcastle deployment, export / import can be used.
    331 
    332 ```
    333 # Requires taler-sandcastle to be running.
    334 # Export the sandcastle data to ./exported/
    335 ./sandcastle-export
    336 
    337 # Other host:
    338 # Request an import
    339 touch exported/import-request
    340 # Now the deployment script will pick up the data to import
    341 ./sandcastle-run
    342 ```
    343 
    344 # Neat Things That Already Work
    345 
    346 * Rebulding the base image is incremental, since we use layers.  If the tag
    347   of the exchange is changed, only the exchange and components that depend
    348   on it are rebuilt.
    349 * Inside the container, the service names resolve to localhost,
    350   and on localhost a reverse proxy with locally signed certificates
    351   ensures that services can talk to each other *within* the container
    352   by using their *public* base URL.
    353 
    354 
    355 # Future Extensions
    356 
    357 * Better way to access logs, better way to expose errors during provisioning
    358 * The Dockerfile should introduce nightly tags for debian packages it builds.
    359   Currently it just uses the latest defined version, which is confusing.
    360 * Deploy the Taler woocommerce plugin, wordpress plugin, Joomla plugin
    361 * Do self-tests of the deployment using the wallet CLI
    362 * Running the auditor
    363 * Running a currency conversion setup with multiple libeufin-bank instances
    364 * Instead of requiring the reverse proxy to handle TLS,
    365   the sandcastle container itself could do TLS termination with caddy.
    366 * To improve performance, allow connecting to an external database
    367 * Make it easy to import and export the persistent data
    368 * Extra tooling to checkpoint images/containers to revert to a previous
    369   state quickly.