Rigel: Difference between revisions

From Personal wiki
(→‎repo: add archzfs)
(→‎LXC host: add lxc explanation)
 
(9 intermediate revisions by the same user not shown)
Line 1: Line 1:
Server that runs all applications and manages all data. It does not run the router.
Server that runs all applications and manages all data. It does not run the router.


== regular.py ==
== LXC host ==
Python script to coordinate recurring automation tasks. It reads a config file regular.csv and executes commands inside LXC containers at specified times and time intervals.
'''LXC containers''' are a type of virtualization environment made possible by namespace isolation of processes. Any program within a container still runs on the same (linux) kernel but knows about a different init process than the original of the host. Also, it cannot see other processes on the host's process tree, only processes in its namespace, somewhat like a subtree. LXC enables isolation of different resources and is mainly used here for network and data access controls.


=== regular.csv ===
The rigel server manages isolated LXC containers [[Lada]], [[Perun]] and [[Osm]]. Some mechanisms used across all of them are described below:
"<code>;</code>"-delimited CSV file, header line is "<code>id;runatstart;interval;start;depends;lxc_name;username;command</code>". Each subsequent line specifies a command and how and when it has to be run. <code>lxc_name</code> specifies the LXC container under which to run, <code>username</code> the user within that container and <code>command</code> the exact command, which cannot have spaces in its arguments (<code>true '1 2' 3</code> will evaluate to <code>"true" "'1" "2'" "3"</code>):<syntaxhighlight lang="shell">
$ sudo lxc-attach -n {lxc_name} -- sudo -u {username} -- {command.split(' ')}
</syntaxhighlight><code>start</code> is a 4-digit string in <code>%H%M</code> format at which time the command should be excecuted, and <code>interval</code> is a number of hours specifying how much hours after <code>start</code> the command should be run again, e.g. 24, 12 or 8 for one, two and three runs a day respectively. The <code>depends</code> column specifies whether the task is a parent task (empty <code>depends</code>) or a child task. Children tasks will be executed exactly after their parent, specified by<code>depends</code> containing the <code>id</code> of the parent, finishes execution. The parent must be in a line above the child's, and the child's <code>runatstart</code>, <code>interval</code> and <code>start</code> values are ignored and can be empty. If multiple children depend on the same parent, they will be run in the order they are listed in the .csv file from top to bottom. The <code>runatstart</code> column is a boolean (only checked for ==1) specifying whether the parent task should also be run at program startup if 1 and else the <code>start</code>+n*<code>interval</code> time will be awaited.


Contents:
=== Mounted filesystems ===
To make filesystems accessible, the directory <code>/mnt/{lxc_general}/{lxc_name}/mounts</code> is <code>--rbind mount</code>ed inside the container. It then has subdirectories that automatically show up in the lxc's <code>/mnt.</code> A filesystem is mounted in <code>/mnt/{lxc_general}/{lxc_name}/mounts/{dir}</code> and then becomes accessible in the container under <code>/mnt/{dir}</code>. This two-layered mount makes mounting filesystems independent of rebooting the container: mounts are no longer specified as lxc config lines (only the toplevel <code>lxc.mount.entry=/mnt/{lxc_general}/{lxc_name}/mounts/ mnt/ none rw,rbind 0 0</code>). Note that Lada uses a <code>mnt_mounts</code> and a <code>www_mounts</code> that map to <code>/mnt</code> and <code>/var/www/html/data</code>, for also accessing webserver contents directly.


==== sponsorblock ====
=== Modularity ===
<code>rsync</code>s the 1GB-sized <code>spnosorTimes.csv</code> through <code>[[perun]]</code> lxc container. Re-<code>mount</code>s the youtube filesystem to be sure updates are propagated through, and repeats <code>rsync+remount</code> a second time to smooth out network errors. Then runs the python script <code>/home/user/addcsv.py</code> to read the <code>.csv</code> file and load it into the [[Lada#RAMdb|ram-based database]]. There was a C program before to filter out some data columns, which reduced the actual data by about 5x, but It is discontinued because it liked to crash with a malformed csv input, which would happen sometimes if the network was unstable. Instead, the whole file is read line-by-line in python and a few error checks are implemented, allowing it to fail gracefully. The python script then enforces the key-constraint as it is different from the one in the source csv, namely: key(line_uuid) for the csv becomes key(start,end,video_id) for the database. This means some lines will be thrown away, and some side-effects, like updating of already-existing lines being inconsistent/non-idempotent, and slight rounding errors due to the floating-point types of durations should be expected. Consult the script itself for details.
The containers are modular in design: their mountpoints are managed by the host and therefore they can run on a different host than rigel. For example, in the offline offsite backup environment. This also means that they may run in a degraded environment: not all filesystems will always be available (e.g. for family pictures as a website, only lada≈8GB+the pictures in terms of storage are needed, and the multi-terabyte youtube archive will probably not be connected).
==== repo ====
<code>rsync</code>s from archlinux, archzfs and artix servers every 12 hours. See [[Lada#Arch and artix package mirror|repository]] for using it.


==== lectures ====
Additionally to its <code>/mnt/{lxc_general}/{lxc_name}/rootfs</code> which stores its root filesystem, each container also stores some files in <code>/mnt/{lxc_general}/{lxc_name}</code> to keep track of some mount and filesystem metadata that makes running on different hosts easier.
Uses <code>feed2exec</code> python module to fetch RSS feeds of ETHZ video lectures and extract links to the video files and their upload dates. Then download links with <code>wget</code> into files named by date, e.g. "<code>%Y-%m-%d.mp4</code>". All specified in <code>/home/user/updatefeeds.sh</code> and run in [[perun]] lxc container.


==== git ====
==== Systemd units ====
Daily synchronization of select repositories for source code. See <code>/mnt/software/git_clone.sh</code> in [[perun]] lxc container.
A simple heuristic to check for the is just whether a particular filesystem in mounted. In <code>systemd</code> unit files that depend on a filesystem being connected, the clause<syntaxhighlight lang="bash">
AssertPathIsMountPoint=/mnt/{dir}
</syntaxhighlight>is added.


==== stats ====
This mechanism is mostly used by Lada that runs webserver components and cannot run some component if its filesystem is missing. In Perun, because it is mainly a downloading container, no custom <code>systemd</code> services are needed because no (custom) daemons are necessary for downloading data.
Hourly synchronization through <code>ssh</code> from [[nyx]]. Extracts data as json with:<syntaxhighlight lang="shell">
 
==== open.sh ====
For each container, a script that is always run before <code>lxc-start</code>ing the container.
 
* It uses the contents of <code>/etc/hostname</code> of the host to determine which environment it is running in (e.g. <code>==rigel</code> -> full environment) and therefore whether to run <code>[[Rigel#mounts.sh|mounts.sh]]</code>, <code>backup_mounts.sh</code> or <code>other_mounts.sh</code>.
* It sets up container-specific networking <u>if needed</u>, e.g. Lada's port forwarding with <code>iptables</code> :<syntaxhighlight lang="bash">
in_iface=eth0
for port in 80 443 8080 7000;do
iptables -t nat -A POSTROUTING -o lxcbr0 -p tcp --dport $port -d {lxc_ip} -j SNAT --to-source {lxcbr0_host_gateway}
iptables -A PREROUTING -t nat -i "${in_iface}" -p tcp --dport $port -j DNAT --to 10.0.3.2:$port
iptables -A FORWARD -p tcp -d {lxc_ip} --dport $port -j ACCEPT
done
</syntaxhighlight>
 
==== mounts.sh ====
This is a script called by <code>open.sh</code> (see above) for each container before starting it. It has hardcoded mountpoints for all needed <code>{dir}</code>s, but also reads the file <code>mount.json</code> to resolve from which host path it should take the corresponding dir. This allows for configurability of where filesystems are (in <code>mount.json</code>) and which filesystems to actually mount (with different <code>mounts.sh</code> versions: <code>backup_mounts.sh</code>, <code>other_mounts.sh</code>).
 
The file <code>mount.json</code> is common to all containers and each container only keeps a symlink to a cental location. This does not affect <code>mounts.sh</code> because it only reads it, but edits to it need only to be made once.
 
== cron jobs ==
Use the script <code>./runtask.sh {name}</code> to lookup said task in <code>tasks</code>. Any possible task has a name that determines the executable file, the logfile, and the lockfile. Each task can have a language of either <code>sh</code> or <code>py</code>, with py execute <code>python3 {name}.py</code> and with sh <code>./{name}.sh</code>. Then, each task has an environment to be run in: an lxc container or <code>rigel</code> direclty. In this way, <code>runtask.sh</code> provides a standard framework to manage logs and locking (each task never runs multiple copies of itself) and have all tasks described by only their name.
 
To execute multiple tasks at one, just use <code>./runtask.sh {name1} {name2} {name3} [...]</code>. This is used for multiple different tasks that download something from the internet. Instead of scheduling them each offset by some guessed interval<syntaxhighlight lang="bash">
04 03 * * * /home/user/runtask.sh yt
04 04 * * * /home/user/runtask.sh repos
54 04 * * * /home/user/runtask.sh rsseth
16 05 * * * /home/user/runtask.sh yttmp
</syntaxhighlight>Just schedule the start of the chain:<syntaxhighlight lang="bash">
04 03 * * * /home/user/runtask.sh yt repos rsseth yttmp
</syntaxhighlight>Some concrete tasks described below, see [[Perun]] for more.
 
==== spball ====
Sponsorblock all: <code>rsync</code>s the 1GB-sized <code>sponsorTimes.csv</code> through <code>[[perun]]</code> lxc container. Then runs the python script <code>/home/user/addcsv.py</code> in [[lada]] to read the <code>.csv</code> file and load it into the [[Lada#RAMdb|ram-based database]]. There was a C program before to filter out some data columns, which reduced the actual data by about 5x, but It is discontinued because it liked to crash with <code>sponsorTimes.csv</code>'s malformed csv (stray newlines as if they were just quotable characters, I hope that's not valid csv). Instead, the whole file is read line-by-line in python and a few error checks are implemented, allowing it to fail somewhat gracefully. The python script then enforces the key-constraint as it is different from the one in the source csv, namely: key(line_uuid) for the csv becomes key(start,end,video_id) for the database. This means some lines will be thrown away, and some side-effects, like updating of already-existing lines being inconsistent/non-idempotent, and slight rounding errors due to the floating-point types of durations should be expected. Consult the script itself for details.
 
==== bwusage ====
Quarter-hourly synchronization through <code>ssh</code> from [[nyx]]. Extracts data as json with:<syntaxhighlight lang="shell">
ssh nyx vnstat -i usb0 --json f
ssh nyx vnstat -i usb0 --json f
</syntaxhighlight>The <code>.json</code> file is then modified though, see [[Lada#Stats|prepending to make it Javascript]].
</syntaxhighlight>The <code>.json</code> file is then converted to multiple files to summarize and sum on time, also see [[Lada#Stats|prepending to make it Javascript]].
 
== osm.py ==
Python script that manages the [[Osm#renderd|rendering daemon]], pre-rendering of cached low-zoom tiles and database data updates in [[osm]] lxc container. The rendering daemon does keep a lot of data in RAM though and this manages to crash the server by memory starvation after about 12-24h of rendering, low-zoom tiles for caching for example. This script monitors available RAM and will kill <code>renderd</code> if it gets too low. Then it also resumes pre-rendering tiles for caching. At 00:30 it stops all rendering anyway and runs <code>/home/renderaccount/update.py</code>, see [[Osm#Data_upades]] and resumes rendering when the script exits. This is to allow most resources to be available to <code>osm2pgsql</code> during import.


PLANNED: maybe periodically, once every 2-3 days, also restart the database and make a zfs snapshot for backup, of an offline database to allow restoring. It is possible to make a snapshot but the database needs to be manually shutdown before:<syntaxhighlight lang="shell-session">
== ramusage.py ==
$ sudo /root/createsp.py ps1a dbp
Python script that monitors RAM usagfe and attempts to restart the <code>renderd</code> daemon. Now that [[Osm#Tirex|Tirex]] is in use, it should not have a memory leak.
</syntaxhighlight>This specific command, to make the next <code>sp[a-z][a-z]</code> snapshot for exactly the <code>ps1a/dbp</code> dataset, is allowed passwordless in <code>visudo</code>.

Latest revision as of 21:42, 7 December 2023

Server that runs all applications and manages all data. It does not run the router.

LXC host

LXC containers are a type of virtualization environment made possible by namespace isolation of processes. Any program within a container still runs on the same (linux) kernel but knows about a different init process than the original of the host. Also, it cannot see other processes on the host's process tree, only processes in its namespace, somewhat like a subtree. LXC enables isolation of different resources and is mainly used here for network and data access controls.

The rigel server manages isolated LXC containers Lada, Perun and Osm. Some mechanisms used across all of them are described below:

Mounted filesystems

To make filesystems accessible, the directory /mnt/{lxc_general}/{lxc_name}/mounts is --rbind mounted inside the container. It then has subdirectories that automatically show up in the lxc's /mnt. A filesystem is mounted in /mnt/{lxc_general}/{lxc_name}/mounts/{dir} and then becomes accessible in the container under /mnt/{dir}. This two-layered mount makes mounting filesystems independent of rebooting the container: mounts are no longer specified as lxc config lines (only the toplevel lxc.mount.entry=/mnt/{lxc_general}/{lxc_name}/mounts/ mnt/ none rw,rbind 0 0). Note that Lada uses a mnt_mounts and a www_mounts that map to /mnt and /var/www/html/data, for also accessing webserver contents directly.

Modularity

The containers are modular in design: their mountpoints are managed by the host and therefore they can run on a different host than rigel. For example, in the offline offsite backup environment. This also means that they may run in a degraded environment: not all filesystems will always be available (e.g. for family pictures as a website, only lada≈8GB+the pictures in terms of storage are needed, and the multi-terabyte youtube archive will probably not be connected).

Additionally to its /mnt/{lxc_general}/{lxc_name}/rootfs which stores its root filesystem, each container also stores some files in /mnt/{lxc_general}/{lxc_name} to keep track of some mount and filesystem metadata that makes running on different hosts easier.

Systemd units

A simple heuristic to check for the is just whether a particular filesystem in mounted. In systemd unit files that depend on a filesystem being connected, the clause

AssertPathIsMountPoint=/mnt/{dir}

is added.

This mechanism is mostly used by Lada that runs webserver components and cannot run some component if its filesystem is missing. In Perun, because it is mainly a downloading container, no custom systemd services are needed because no (custom) daemons are necessary for downloading data.

open.sh

For each container, a script that is always run before lxc-starting the container.

  • It uses the contents of /etc/hostname of the host to determine which environment it is running in (e.g. ==rigel -> full environment) and therefore whether to run mounts.sh, backup_mounts.sh or other_mounts.sh.
  • It sets up container-specific networking if needed, e.g. Lada's port forwarding with iptables :
    in_iface=eth0
    for port in 80 443 8080 7000;do
    	iptables -t nat -A POSTROUTING -o lxcbr0 -p tcp --dport $port -d {lxc_ip} -j SNAT --to-source {lxcbr0_host_gateway}
    	iptables -A PREROUTING -t nat -i "${in_iface}" -p tcp --dport $port -j DNAT --to 10.0.3.2:$port
    	iptables -A FORWARD -p tcp -d {lxc_ip} --dport $port -j ACCEPT
    done

mounts.sh

This is a script called by open.sh (see above) for each container before starting it. It has hardcoded mountpoints for all needed {dir}s, but also reads the file mount.json to resolve from which host path it should take the corresponding dir. This allows for configurability of where filesystems are (in mount.json) and which filesystems to actually mount (with different mounts.sh versions: backup_mounts.sh, other_mounts.sh).

The file mount.json is common to all containers and each container only keeps a symlink to a cental location. This does not affect mounts.sh because it only reads it, but edits to it need only to be made once.

cron jobs

Use the script ./runtask.sh {name} to lookup said task in tasks. Any possible task has a name that determines the executable file, the logfile, and the lockfile. Each task can have a language of either sh or py, with py execute python3 {name}.py and with sh ./{name}.sh. Then, each task has an environment to be run in: an lxc container or rigel direclty. In this way, runtask.sh provides a standard framework to manage logs and locking (each task never runs multiple copies of itself) and have all tasks described by only their name.

To execute multiple tasks at one, just use ./runtask.sh {name1} {name2} {name3} [...]. This is used for multiple different tasks that download something from the internet. Instead of scheduling them each offset by some guessed interval

04 03 * * * /home/user/runtask.sh yt
04 04 * * * /home/user/runtask.sh repos
54 04 * * * /home/user/runtask.sh rsseth
16 05 * * * /home/user/runtask.sh yttmp

Just schedule the start of the chain:

04 03 * * * /home/user/runtask.sh yt repos rsseth yttmp

Some concrete tasks described below, see Perun for more.

spball

Sponsorblock all: rsyncs the 1GB-sized sponsorTimes.csv through perun lxc container. Then runs the python script /home/user/addcsv.py in lada to read the .csv file and load it into the ram-based database. There was a C program before to filter out some data columns, which reduced the actual data by about 5x, but It is discontinued because it liked to crash with sponsorTimes.csv's malformed csv (stray newlines as if they were just quotable characters, I hope that's not valid csv). Instead, the whole file is read line-by-line in python and a few error checks are implemented, allowing it to fail somewhat gracefully. The python script then enforces the key-constraint as it is different from the one in the source csv, namely: key(line_uuid) for the csv becomes key(start,end,video_id) for the database. This means some lines will be thrown away, and some side-effects, like updating of already-existing lines being inconsistent/non-idempotent, and slight rounding errors due to the floating-point types of durations should be expected. Consult the script itself for details.

bwusage

Quarter-hourly synchronization through ssh from nyx. Extracts data as json with:

ssh nyx vnstat -i usb0 --json f

The .json file is then converted to multiple files to summarize and sum on time, also see prepending to make it Javascript.

ramusage.py

Python script that monitors RAM usagfe and attempts to restart the renderd daemon. Now that Tirex is in use, it should not have a memory leak.