Αποστολέας Θέμα: Σύστημα εκκίνησης Runit, γρήγορο, ελαφρύ, εύκολο και supervised  (Αναγνώστηκε 354 φορές)

linuxer

  • Administrator
  • *****
  • Μηνύματα: 35
  • Systemd kills Linux Freedom - Move to Artix Linux
    • Προφίλ
    • LINUXER

Runit init - μία σύντομη αναφορά στο supervision

Τι είναι το process supervision ή στα Ελληνικά, εποπτεία των διεργασιών:

Η εποπτεία των υπηρεσιών, είναι είδος διοίκησης των υπηρεσιών του λειτουργικού συστήματος, βάση της οποίας δημιουργείται μία κύρια (master) διεργασία, η οποία είναι ο κηδεμόνας των διεργασιών που πραγματοποιούν οι υπηρεσίες, και η οποία παραμένει να εκτελείται συνεχώς.

Τα οφέλη σε σύγκριση με τον παραδοσιακό τρόπο εκτέλεσης και μηχανισμών εκκίνησης, όπως για παράδειγμα το System V init, περιλαμβάνουν:

  • Την ικανότητα επανεκκίνησης υπηρεσιών που έχουν αποτύχει για κάποιο λόγο
  • Το γεγονός ότι δεν απαιτείται η χρήση των αρχείων pid (Process ID files)
  • Ξεκάθαρη κατάσταση εργασιών
  • Αξιόπιστη καταγραφή (logging), διότι η κύρια διεργασία μπορεί και καταγράφει τα stdout/stderr της υπηρεσίας και να δημιουργηθεί εγγραφή
  • Γρηγορότερη ταυτόχρονη (concurrent) εκτέλεση και ικανότητα εκκίνησης και παύσης των υπηρεσιών

Υλοποίηση:

  • daemontools
  • daemontools-encore
  • Eye: Μια υλοποίηση με Ruby
  • Finit: Γρήγορο, επεκτάσιμο σύστημα εκκίνησης για Linux
  • God: Μια υλοποίηση με Ruby
  • immortal: Μια υλοποίηση με Go
  • PM2: Διαχειριστής Διεργασιών για Node.js
  • Initng
  • launchd
  • minit: Ένα μικτό, αλλα πλήρες σε δυνατότητες, ολοκληρωμένο σύστημα εκκίνησης για Linux
  • Monit
  • OpenRC: Σε πειραματικό στάδιο εξέλιξης
  • runit
  • Supervisor: Μια υλοποίηση με Python
  • s6: Low-level διεργασία και εποπτεία διεργασιών
  • Systemd

Runit σύστημα εκκίνησης, οφέλη και χαρακτηριστικά

Τα επιπλέον οφέλη του Runit έναντι των υπόλοιπων συστημάτων εκκίνησης, είναι:

  • Η φορητότητα
  • Η ευκολία στο πακετάρισμα
  • Μικρό μέγεθος κώδικα

Ιστορία

Δυστυχώς δεν υπάρχουν επίσημα καταγεγραμμένα στοιχεία, για αυτό παραθέτω αυτά τα οποία, γνωρίζω:

Το Runit αρχικά σχεδιάστηκε και αναπτύχθηκε από τον Gerrit Pape και υποστηρίζεται από τους Denys Vlasenco (BusyBox maintainer) & Dmitry Bogatov (Debian maintainer).

Η πρώτη ιστορικά διανομή που το χρησιμοποίησε ήταν η Annvix, αλλά η διανομή που το αξιοποίησε, επί της ουσίας και διαδόθηκε, είναι το Void Linux.
Πλέον διατίθεται και στα Artix Linux, Project Trident, Antix και στο Dragora Linux που είναι και το μοναδικό Libre Linux (εγκεκριμένο από το FSF) της παρέας.
Υπάρχουν και άλλες διανομές που το αξιοποιούν, οι οποίες όμως ακόμη δεν το έχουν ανακοινώσει επίσημα.

Σχεδιασμός

Το Runit εστιάζει στον μικρού μεγέθους, αρθρωτό και φορητό πηγαίο κώδικα.

Το Runit διαιρείται σε τρία στάδια:

  • Αρχικοποίηση συστήματος
  • Εποπτεία υπηρεσιών
  • Σταμάτημα ή επανεκκίνηση συστήματος

Σε αντίθεση με το πρώτο και το τρίτο στάδιο που πρέπει να γίνει η προσαρμογή τους στο συγκεκριμένο λειτουργικό σύστημα στο οποίο εκτελούνται, το δεύτερο στάδιο είναι φορητό ανάμεσα σε όλα τα λειτουργικά συστήματα POSIX.

Τα τρία στάδια μπορούν να διαμορφώνοντας τρία 3 εκτελέσιμα αρχεία δέσμης εντολών, τα οποία ονομάζονται 1, 2 & 3 αντίστοιχα. (το ctrlaltdel είναι ένα πρόσθετο στάδιο υπηρεσίας)



Στάδιο 1:
Το runit εκτελεί το αρχείο /etc/runit/1 και το περιμένει να τελειώσει.
Το πρώτο στάδιο εκκίνησης του συστήματος, γίνεται σε αυτό το στάδιο.
Το /etc/runit/1 έχει τον πλήρη έλεγχο του /dev/console και παρέχει έτσι την δυνατότητα εκκίνησης τερματικού ανάγκης σε περίπτωση που η αρχική εκτέλεση οριστικοποίησης του συστήματος, αποτύχει.
Οι υπηρεσίες σε αυτό το στάδιο, δεν ξεκινούν ταυτόχρονα, λόγω εξαρτήσεων.

Στάδιο 2:
Το runit ξεκινά την εκτέλεση του αρχείου /etc/runit/2, το οποίο δεν επιστρέφει καμία τιμή (ολοκληρώνει την λειτουργία του), εκτός αν γίνει τερματισμός ή επανεκκίνηση του λειτουργικού συστήματος.
Εάν αποτύχει να εκτελεστεί (crash), θα επανεκκινήσει αυτόματα.
Κανονικά το αρχείο /etc/runit/2, εκτελεί το αρχείο runsvdir.
Στο στάδιο 2, η runit προαιρετικά, διαχειρίζεται το σήμα διακοπής INT (αίτημα πληκτρολογίου ctrl-alt-del).

Στάδιο 3:
Όταν η runit λάβει εντολή παύσης ή επανεκκίνησης, ή όταν το στάδιο 2 επιστρέψει χωρίς σφάλματα (ολοκληρωθεί η λειτουργία του), τότε αναλαμβάνει τον τερματισμό του Σταδίου 2, εάν ακόμα αυτό εκτελείται και εκτελεί το αρχείο /etc/runit/3.
Οι εργασίες του συστήματος, όπως ο τερματισμός (shutdown), η παύση (halt) και η επανεκκίνηση (reboot) εκτελούνται σε αυτό το στάδιο.

Αξιοποίηση
Το Runit μπορεί να αντικαταστήσει το σύστημα εκκίνησης του λειτουργικού, ή μπορεί να χρησιμοποιηθεί σαν επόπτης υπηρεσιών άλλου συστήματος εκκίνησης (init) αρκεί να είναι η διεργασία-κηδεμόνας στο PID1 και η οποία εκτελεί τις διεργασίες που καθορίζονται από στο αρχείο inittab.

Τρόπος χρήσης

Το Runit διαφοροποιείται ανάμεσα στο Void και Artix, σε ότι αφορά την οργάνωση των φακέλων (τοποθεσία), των υπηρεσιών (για λοιπές λεπτομέρειες, στα Wikis των διανομών κάτω στις πηγές).

Ο τρόπος χρήσης όμως, είναι κοινός, ως εντολές.

Στην περίπτωση του άρθρου αυτού, ο συγγραφέας χρησιμοποιεί το Artix Linux, οπότε λάβετε υπόψη σας, την διαφοροποίηση του /var/service/* (Void Linux) έναντι του /run/runit/service/* (Artix Linux)

<service_name> είναι το όνομα της υπηρεσίας, π.χ. clamd

Πρόσθεση/αφαίρεση υπηρεσίας:

Για Artix Linux
Κώδικας
 # ln -s /etc/runit/sv/<service_name> /run/runit/service 
 # unlink /run/runit/service/<service_name>
Για Void Linux
Κώδικας
 # ln -s /etc/sv/<service_name> /var/service/
 # rm /var/service/<service_name>

Εκκίνηση/επανεκκίνηση υπηρεσίας (Artix Linux/Void Linux):
Κώδικας
 # sv up <service_name>
 # sv restart <service_name>

Τερματισμός υπηρεσίας (Artix Linux/Void Linux):
Κώδικας
 # sv down <service_name>

Κατάλογος ενεργών υπηρεσιών:

Για Artix Linux
Κώδικας
 # sv status /run/runit/service/*

Για Void Linux
Κώδικας
 # sv status /var/service/*

Επίπεδα υπηρεσιών (Runlevels)

Εξ' ορισμού στο Runit υπάρχουν δύο επίπεδα υπηρεσιών, το default και το single

Η εναλλαγή των επιπέδων η οποία τα έχει ως αποτέλεσμα τον τερματισμό των υπηρεσιών του τρέχοντος επιπέδου και την εκκίνηση του άλλου, γίνεται με την εντολή
Κώδικας
 # runsvchdir runlevel

Υπάρχει η δυνατότητα πρόσθεσης επιπέδων υπηρεσιών, όπως και στο OpenRC με την αντίστοιχη λογική, δηλαδή ποιες υπηρεσίες θα ενεργοποιούνται σε εκείνο το επίπεδο.

Για να γίνει αυτό, δημιουργούμε ένα νέο επίπεδο υπηρεσιών, με την εντολή
Κώδικας
 # runsvchdir <runlevel_name>

Κατά συνέπεια οι παραπάνω εντολές πρόσθεσης υπηρεσίας (linked), για παράδειγμα στο Artix Linux θα είναι
Κώδικας
 # ln -s /etc/runit/sv/service /etc/runit/runsvdir/<runlevel_name>@@
(δείτε και στα Wikis του Runit & των διανομών, για περισσότερη σχετική πληροφόρηση)

Παραδείγματα γραφής υπηρεσιών για Runit

Οι υπηρεσίες στο Runit, έχουν σαν χαρακτηριστικό γνώρισμα το όνομα του εκτελέσιμου αρχείου run, το οποίο δημιουργείται μέσα σε ένα φάκελο με την ονομασία του service


Clamd υπηρεσία για Runit
Κώδικας
 #!/bin/sh
 exec clamd --foreground=true

Teamviewer υπηρεσία για Runit
Κώδικας
 #!/bin/sh
 exec teamviewer daemon enable

Είναι όλα τόσο απλά στο Runit?

Η απάντηση είναι ότι είναι σαφέστατα πιο εύκολη η δημιουργία υπηρεσιών στο Runit, σε σχέση με το OpenRC, το s6 και άλλα init systems.

Ας δούμε ένα μεγαλύτερο παράδειγμα όμως, δηλαδή πως μπορεί να παραμετροποιηθεί μία υπηρεσία, όπως το zramen (δεν θα επεξηγηθεί το αρχείο δέσμης εντολήν του ιδίου, αλλά μόνο της υπηρεσίας, θα μπει όμως ως παράθεση, για μελέτη).

Το εκτελέσιμο αρχείο δέσμης /usr/bin/zramen
Κώδικας
 #!/bin/bash

 # ----------------------------------------------------------------------------
 # zramen: manage zram swap space
 # ----------------------------------------------------------------------------

 # ==============================================================================
 # constants {{{

 # use this compression algorithm for zram by default
 readonly COMP_ALGORITHM='lz4'
 readonly ZRAM_COMP_ALGORITHM="${ZRAM_COMP_ALGORITHM:-$COMP_ALGORITHM}"

 # give zram swap device highest priority
 readonly PRIORITY=32767
 readonly ZRAM_PRIORITY="${ZRAM_PRIORITY:-$PRIORITY}"

 # allocate this percentage of memory for zram by default
 readonly SIZE=25
 readonly ZRAM_SIZE="${ZRAM_SIZE:-$SIZE}"

 # set the maximum number of compression streams for zram
 readonly STREAMS=$(nproc)
 readonly ZRAM_STREAMS="${ZRAM_STREAMS:-$STREAMS}"

 # zramen version number
 readonly VERSION=0.2.1

 # set TMPDIR to work directory for mktemp
 readonly WORK_DIR='/var/run/zramen'
 TMPDIR="$WORK_DIR"

 # end constants }}}
 # ==============================================================================
 # usage {{{

 _usage() {
 read -r -d '' _usage_string <<EOF
 Usage:
    zramen [-h|--help] <command>
    zramen [-a|--algorithm <algo>]
         [-n|--num <uint>]
         [-s|--size <uint>]
         [-p|--priority <int>]
         make
    zramen toss

  Options:
    -h, --help       Show this help text
    -v, --version    Show program version
    -a, --algorithm  Compression algorithm for zram (Default: $ZRAM_COMP_ALGORITHM)
    -n, --num        Number of compression streams for zram (Default: $ZRAM_STREAMS)
    -p, --priority   Priority of zram swap device (Default: $ZRAM_PRIORITY)
    -s, --size       Percentage of memory to allocate for zram (Default: $ZRAM_SIZE)

  Commands:
    make        Make zram swap device
    toss        Remove zram swap device

  Algorithm
    Run zramctl --help to see a list of acceptable algorithms:
    | lzo
    | lzo-rle
    | lz4
    | lz4hc
    | zstd
    | deflate
    | 842

  Num
    Number of zram compression streams; try one per core

  Priority
    Must be an integer <= 32767; higher number means higher zram priority

  Size
    Percentage of memory to allocate for zram; try <= 50
  EOF
  echo "$_usage_string"
  }

  _POSITIONAL=()

  while [[ $# -gt 0 ]]; do
    case "$1" in
      -h|--help)
        _usage
        exit 0
        ;;
      -v|--version)
        echo "$VERSION"
        exit 0
        ;;
      -a|--algorithm)
        _algorithm="$2"
        shift
        shift
        ;;
      -n|--num)
        _streams="$2"
        # shift past argument and value
        shift
        shift
        ;;
      -p|--priority)
        _priority="$2"
        shift
        shift
        ;;
      -s|--size)
        _size="$2"
        shift
        shift
        ;;
      -*)
        # unknown option
        _usage
        exit 1
        ;;
      make|toss)
        _POSITIONAL+=("$1")
        shift
        ;;
      *)
        # unknown command
        _usage
        exit 1
        ;;
    esac
  done

  if ! [[ "${#_POSITIONAL[@]}" == '1' ]]; then
    _usage
    exit 1
  fi

  # restore positional params
  set -- "${_POSITIONAL[@]}"

  # end usage }}}
  # ==============================================================================

  # sanitize compression algorithm input
  _algorithm="${_algorithm:-$ZRAM_COMP_ALGORITHM}"
  case "$_algorithm" in
    # proper algo chosen, no action necessary
    lzo|lzo-rle|lz4|lz4hc|zstd|deflate|842)
      ;;
    # improper algo chosen, reset to default
    *)
      _algorithm="$COMP_ALGORITHM"
      ;;
  esac

  # sanitize priority input
  _priority=${_priority:-$ZRAM_PRIORITY}
  [[ $_priority -le 32767 ]] \
    || _priority=32767

  # sanitize size input
  _size=${_size:-$ZRAM_SIZE}
  [[ $_size -gt 0 ]] \
    || _size=$SIZE
  [[ $_size -le 100 ]] \
    || _size=100

  # sanitize streams input
  _streams=${_streams:-$ZRAM_STREAMS}
  # number of CPUs requested must be 1+
  [[ $_streams -gt 0 ]] \
    || _streams=1
  # number of CPUs requested must not exceed CPUs available
  [[ $_streams -le $STREAMS ]] \
    || _streams=$STREAMS

  INFO() {
    echo "zramen#info: $*"
  }

  WARN() {
    echo "zramen#warn: $*"
  }

  ERRO() {
    echo "zramen#erro: $*"
    exit 1
  }

  calc() {
    # truncate to whole number
    printf '%.f' "$(bc --mathlib <<< "$@")"
  }

  make() {
    local _mem_total
    local _mem_to_alloc
    local _zram_dev

    _mem_total=$(grep 'MemTotal:' /proc/meminfo | awk '{print $2}')
    _mem_to_alloc=$(calc "$_mem_total * 1024 * ($_size / 100)")

    if ! [[ -d '/sys/module/zram' ]]; then
      INFO 'Attempting to find zram module - not part of kernel'
      modprobe --dry-run zram 2>/dev/null \
      || ERRO 'Sorry, could not find zram module'
     # loop to handle zram initialization problems
      for ((i=0; i < 10; i++)); do
        [[ -d '/sys/module/zram' ]] \
          && break
        modprobe zram
        sleep 1
      done
      INFO 'zram module successfully loaded'
    else
      INFO 'zram module already loaded'
    fi

    for ((i=0; i < 10; i++)); do
      INFO 'Attempting to initialize free device'
      _tmp="$(mktemp)"
    # return name of first free device
      zramctl \
        --algorithm "$_algorithm" \
        --find \
        --size "$_mem_to_alloc" \
        --streams "$_streams" &> \
        "$_tmp"
      read -r _output < "$_tmp"
      rm -f "$_tmp"
      unset _tmp
      case "$_output" in
      *'failed to reset: Device or resource busy'*)
        sleep 1
        ;;
      *'zramctl: no free zram device found'*)
        WARN 'zramctl could not find free device'
        INFO 'Attempting zram hot add'
        ! [[ -f '/sys/class/zram-control/hot_add' ]] \
          && ERRO 'Sorry, this kernel does not support zram hot add'
        read -r _hot_add < /sys/class/zram-control/hot_add
        INFO "Hot added new zram swap device: /dev/zram$_hot_add"
        ;;
      /dev/zram*)
        [[ -b "$_output" ]] \
          || continue
        _zram_dev="$_output"
        break
        ;;
      esac
    done

  if [[ -b "$_zram_dev" ]]; then
    INFO "Successfully initialized zram swap device: $_zram_dev"
    mkdir -p "$WORK_DIR/zram"
    mkswap "$_zram_dev" --label "$(basename "$_zram_dev")" &> /dev/null \
      && swapon --discard --priority $_priority "$_zram_dev" \
      && ln --symbolic "$_zram_dev" "$WORK_DIR/zram/"
    else
      WARN 'Could not get free zram device'
    fi
  }

  toss() {
    for zram in "$WORK_DIR/zram"/*; do
      ! [[ -b $zram ]] \
      && continue
      INFO "Removing zram swap device: /dev/$(basename "$zram")"
      swapoff "$zram" \
        && zramctl --reset "$(basename "$zram")" \
        && rm "$zram" \
        && INFO "Removed zram swap device: /dev/$(basename "$zram")"
    done
    [[ -d "$WORK_DIR" ]] \
      && rm -rf "$WORK_DIR"
  }

  main() {
    if ! [[ "$UID" == '0' ]]; then
      echo 'Sorry, requires root privileges'
      exit 1
    fi
    [[ -d "$WORK_DIR" ]] \
    || mkdir -p "$WORK_DIR"
    if [[ "$1" == 'make' ]]; then
      make
    elif [[ "$1" == 'toss' ]]; then
      toss
    else
      # unknown command
      _usage
      exit 1
    fi
  }

  main "$1"

  # vim: set filetype=sh foldmethod=marker foldlevel=0 nowrap:
Το αρχείο παραμετροποίησης του zramen/conf (καθορίζεται ως αρχείο από τις παραμέτρους του zramen, και απλά εδώ μπορεί κατά βούληση να μεταβάλλει κανείς τον τρόπο συμπίεσης, μέγεθος κλπ, από τα προκαθορισμένα)
Κώδικας
 #export ZRAM_COMP_ALGORITHM='lz4'
 #export ZRAM_PRIORITY=32767
 #export ZRAM_SIZE=25
 #export ZRAM_STREAMS=1

Το αρχείο εκκίνησης της υπηρεσίας του zramen/run
Κώδικας
 #!/bin/sh
 [ -r ./conf ] && . ./conf
 zramen make
 exec pause

Το αρχείο τερματισμού της υπηρεσίας του zramen/finish
Κώδικας
 #!/bin/sh
 zramen toss

Ο λόγος ύπαρξης των run & finish, είναι ότι επειδή πρόκειται για υπηρεσία τύπου mount (όπως άλλωστε ξεκάθαρα φαίνεται στον πηγαίο κώδικα αλλά επειδή και από την φύση του το swap θέλει mounting/unmounting με τις εντολές swapon/swapoff και άρα είναι onetime script σε εκτέλεση) και έτσι πρέπει να στείλει το αντίστοιχο σήμα επιστροφής όταν τερματίσει, στον επόπτη εργασιών.

Άδεια Χρήσης Runit

To runit είναι ελεύθερο λογισμικό και η άδεια χρήσης του είναι παρόμοια με την three-clause BSD. http://smarden.org/runit/faq.html (αντίγραφο της άδειας του, υπάρχει ως συνημμένο αρχείο στο τέλος του άρθρου)

Καλό διάβασμα!


Πηγές άρθρου:
Runit Init System
Runit Init Benefits
Artix Linux Runit Wiki
Void Linux Runit Wiki
Wikipedia Process Supervidion
Wikipedia Runit Init
zramen-runit source code
zramen-runit πακέτο (AUR)
teamviewer-runit πακέτο (AUR)
rsv, runit service manager για Artix Linux(AUR)
vsv, runit service manager για Void Linux

Άδεια χρήσης λογισμικού:
« Τελευταία τροποποίηση: Αύγουστος 23, 2020, 12:53:56 μμ από linuxer »
friendly
0
funny
0
informative
0
agree
0
disagree
0
pwnt
0
like
2
dislike
0
No reactions
No reactions
No reactions
No reactions
No reactions
No reactions
Members reacted like:
herco,akounadis,
No reactions

akounadis

  • Newbie
  • *
  • Μηνύματα: 2
    • Προφίλ
Απ: Σύστημα εκκίνησης Runit, γρήγορο, ελαφρύ, εύκολο και supervised
« Απάντηση #1 στις: Αύγουστος 14, 2020, 06:53:19 μμ »
Αρχικά καλώς σας βρήκα και καλή αρχή με μια δυναμική στο μέλλον που θα είναι αντάξια σ´ αυτό που εκπροσωπεί το GNU/Linux!
Θεωρούμε νέος μιας και τόσα χρόνια είχα "παρασυρθεί" στο systemd.

Ενδιαφέρον το άρθρο και οι βιβλιογραφικες αναφορές - βιβλιογραφικές παραπομπές!

Ευχαριστώ πολύ,

Καλή αρχή να έχουμε!
friendly
0
funny
0
informative
0
agree
0
disagree
0
pwnt
0
like
1
dislike
0
No reactions
No reactions
No reactions
No reactions
No reactions
No reactions
Members reacted like:
linuxer,
No reactions

linuxer

  • Administrator
  • *****
  • Μηνύματα: 35
  • Systemd kills Linux Freedom - Move to Artix Linux
    • Προφίλ
    • LINUXER
Απ: Σύστημα εκκίνησης Runit, γρήγορο, ελαφρύ, εύκολο και supervised
« Απάντηση #2 στις: Αύγουστος 14, 2020, 07:08:28 μμ »
Καλώς ήρθες στον χώρο μας.

Ευχαριστούμε πολύ για την θετική κριτική.

Ευχόμαστε, το μέλλον να είναι ευοίωνο, για όλους όσους αγαπάμε την ελευθερία και το δικαίωμα επιλογής, δηλαδή αυτοί που ακόμα κρατάμε τις αρχές του GNU και του αυθεντικού FSF (Stallman).

Καλή μας αρχή και καλή μας πορεία!

friendly
0
funny
0
informative
0
agree
0
disagree
0
pwnt
0
like
1
dislike
0
No reactions
No reactions
No reactions
No reactions
No reactions
No reactions
Members reacted like:
akounadis,
No reactions

Tags:
 


Powered by EzPortal