sandcastle-ng

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

README.md (12802B)


      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 Overrides that define `EXTERNAL_PORT`, such as `taler.localhost`, continue to
    208 publish that single Caddy ingress port for local integration testing.
    209 
    210 When starting sandcastle like
    211 
    212     SANDCASTLE_OVERRIDE_NAME=taler.localhost ./sandcastle-run
    213 
    214 the services will be available as
    215 
    216  - http://taler.localhost:4321
    217  - http://bank.taler.localhost:4321
    218  - http://shop.taler.localhost:4321
    219  - http://donations.taler.localhost:4321
    220  - http://backend.taler.localhost:4321  - the merchant backend
    221  - http://exchange.taler.localhost:4321
    222  - http://auditor.taler.localhost:4321
    223  - http://challenger.taler.localhost:4321
    224  - http://paivana.taler.localhost:4321/en/  - www.taler.net behind a Taler paywall
    225    (use the ``/en/`` entry point, as www.taler.net redirects ``/`` to its own domain)
    226 
    227 This gives a nice environment for integration testing.
    228 
    229 
    230 # Running the Unit Tests
    231 
    232 Run the Python unit-test suite from the repository root:
    233 
    234     python3 -m unittest discover -s tests -v
    235 
    236 
    237 # Stopping the deployment
    238 
    239 For stopping the deployment simply run
    240 
    241 ```
    242 ./sandcastle-stop
    243 ```
    244 
    245 which is just a shortcut for ``podman stop taler-sandcastle``.
    246 
    247 
    248 # Watching Logs
    249 
    250 Run ``./sandcastle-logs`` to watch the logs within the container.
    251 You can pass addtional arguments to ``./sandcastle-logs``,
    252 which will be passed on to ``journalctl`` in the container.  Example:
    253 
    254     ./sandcastle-logs --output=cat
    255 
    256 
    257 # Poking Around
    258 
    259 You can poke around in a running sandcastle instance by running
    260 
    261 ```
    262 podman exec -it taler-sandcastle /bin/bash
    263 ```
    264 
    265 Or, as a shortcut:
    266 
    267 ```
    268 ./sandcastle-enter
    269 ```
    270 
    271 This will drop you into a shell inside the running container,
    272 where you have access to systemd, journalctl, etc.
    273 
    274 
    275 # Data Storage
    276 
    277 All persistent data is stored in a podman volume called
    278 _talerdata_.  You can see where it is in your filesystem
    279 by running ``podman volume inspect talerdata``.
    280 
    281 That volume also contains the postgres database files.
    282 
    283 ## Cleaning the Data Storage
    284 
    285 For cleaning the data storage run
    286 
    287     ./sandcastle-plow
    288 
    289 and for cleaning also the persistent storage run
    290 
    291     ./sandcastle-plow all
    292 
    293 
    294 # Provisioning Details
    295 
    296 The whole deployment is configured by a script
    297 mounted into the container as ``/provision/setup-sandcastle.sh``.
    298 This script will be run as a oneshot systemd service and will disable itself after
    299 the first success.
    300 
    301 To troubleshoot, run ``journalctl -u setup-sandcastle.service``.
    302 
    303 There are different setup scripts in the ``scripts/$SANDCASTLE_SETUP_NAME``
    304 folders. Specifically:
    305 
    306 * ``none`` does no setup at all
    307 * ``demo`` set up the usual Taler demo
    308 * TBD: ``regio`` is a currency conversion setup
    309 
    310 By default, ``demo`` is used.
    311 To mount a different provision script,
    312 set ``$SANDCASTLE_SETUP_NAME`` when running ``./sandcastle-run``,
    313 like this
    314 
    315     SANDCASTLE_SETUP_NAME=none ./sandcastle-run
    316 
    317 
    318 You can always manually run any of the provisioning script inside the container as
    319 ``/scripts/$SANDCASTLE_SETUP_NAME/setup-sandcastle.sh``.
    320 
    321 # Importing / exporting
    322 
    323 To migrate a sandcastle deployment, export / import can be used.
    324 
    325 ```
    326 # Requires taler-sandcastle to be running.
    327 # Export the sandcastle data to ./exported/
    328 ./sandcastle-export
    329 
    330 # Other host:
    331 # Request an import
    332 touch exported/import-request
    333 # Now the deployment script will pick up the data to import
    334 ./sandcastle-run
    335 ```
    336 
    337 # Neat Things That Already Work
    338 
    339 * Rebulding the base image is incremental, since we use layers.  If the tag
    340   of the exchange is changed, only the exchange and components that depend
    341   on it are rebuilt.
    342 * Inside the container, the service names resolve to localhost,
    343   and on localhost a reverse proxy with locally signed certificates
    344   ensures that services can talk to each other *within* the container
    345   by using their *public* base URL.
    346 
    347 
    348 # Future Extensions
    349 
    350 * Better way to access logs, better way to expose errors during provisioning
    351 * The Dockerfile should introduce nightly tags for debian packages it builds.
    352   Currently it just uses the latest defined version, which is confusing.
    353 * Deploy the Taler woocommerce plugin, wordpress plugin, Joomla plugin
    354 * Do self-tests of the deployment using the wallet CLI
    355 * Running the auditor
    356 * Running a currency conversion setup with multiple libeufin-bank instances
    357 * Instead of requiring the reverse proxy to handle TLS,
    358   the sandcastle container itself could do TLS termination with caddy.
    359 * To improve performance, allow connecting to an external database
    360 * Make it easy to import and export the persistent data
    361 * Extra tooling to checkpoint images/containers to revert to a previous
    362   state quickly.