Dies ist ein Template für den Skripte-Unterbereich InhaltPerlSkripteWeb.

Zuverläassiges laden von FastCGI? Scripten bei lighttpd

Name

include_fcgi.pl

Aufgabe

Ich sehe mich immer wieder damit konfrontiert einen lighttpd Server mit mehreren FastCGI? Scripten auf zu setzen.

Der gebräuchliche Ansatz hier ist es ein Programm wie spawn-fcgi zu benutzen, das als Deamon mit lighttpd kommuniziert. Die Vorteile sind da dass die Scripte nicht die selben Benutzer Rechte haben müssen wie der Server, dass der Server unabhängig von den Scripten neu gestartet werden kann und die Scripte gut überwacht werden können (z.B. Neustart bei Updates vom Script)

Der Nachteil ist aber, das bei einem Fehler im Deamon kein Script mehr Erreichbar da die Kommunikation von allen Scripten über ein Socket abläuft (wobei es egal ist ob es ein FileSocket? oder NetSocket? ist). Dies führt zudem unter Last manchmal dazu, dass Aktionen verzögert werden, weil das Socket gerade von einem Anderen benutzt wird. Besonders langsame und nicht sehr durchsatzstarke Systeme kommen hier schnell an ihre Grenzen.

Es ist natürlich möglich mehrere Deamons zu starten, die nur wenige Scripte verwalten. Der Konfigurationsaufwand steigt dabei aber. (und damit auch wie Wahrscheinlichkeit Fehler zu machen)

Einfacher ist es , so finde ich, beim Start des Servers alle FastCGI?-Scripte zu suchen und mit jeweils einem Socket zu versehen und die Verwaltung direkt dem lighttpd-Server zu überlassen. Dieser hat die Fähigkeit beendete FastCGI?-Scripte neu zu starten oder mehrere Scriptinstanzen auf einem Socket zu verwalten. Die fehlenden Updatemöglichkeiten lassen sich ohne großen Aufwand im Script selber implementieren und sogar besser lösen als es über ein externes Programm möglich wäre. Dabei laufen die Scripte natürlich mit den selben Rechten wie der Server. Aber dafür entfällt ein Programm das gepflegt und aktuell gehalten werden muss und kann es zu keinen Engpässen beim Datentransfer kommen. Gerade auf langsamen Maschinen ist das ein Vorteil. Außerdem kommt es nicht zu Störungen zwischen verschiedenen Scripten, wie es bei machen Implementation von FastCGI?-Deamons vorkommt.

Es ist natürlich mühsam von Hand die FastCGI?-Sripte in die Konfiguration einzutragen und auf Tippfehler zu achten und die für jedes umbenannte oder neue Script wiederholen zu müssen. Das kann besonders nervig werden, wenn man einen neuen Server einrichtet. Darum schrieb ich dieses Script. Die Lighttpd-Konfiguartion kennt die Option "include_shell" die wird benutzt um über Scripte eine Konfiguration zu generieren. Ich nutze sie um ein Perlscript auszuführen, das FastCGI? Scripte nach gewissen Kategorien sucht und die passende Konfiguration erstellt. Das erlaubt es durch einfaches einbinden dieses Scriptes alle FastCGI? Scripte beim Serverstart zu finden und zu laden. Das beschleunigt und vereinfacht das einrichten eines Servers mit FastCGI? Scripten enorm.

Aufruf mit Parametern

Einbetten in die lighttpd Konfiguration: include_shell "/usr/local/lib/lighttpd/include_fcgi.pl"

Optionen, die an das Script übergeben werden können:
  --config_file => Pfad zur lighttpd.conf
                   wenn der wert nicht gesetzt ist versucht das Script eine Konfiguration zu finden

  --suffix      => Dateiendung für FastCGIs
                   wenn nichts gesetzt, dann wird jede gefundene ausführbare Datei als FastCGI erkannt.

  --bin_path    => Suchpfad für FastCGIs
                   wenn es kein absoluter Pfad ist, dann wird "document_root" als Basispfad genommen

  --max_process => Maximale Anzahl der Prozesse die ein CGI-Script parallel haben darf
                   Default ist 1

  --add         => Zusätzliche Argumente

  --tmp         => Verzeichnis in welche die Socket der FastCGIs abgelegt werden
                   wenn nichts gesetzt nimmt das Scipt den "restbesten" (siehe "tempdir" in File::Spec)

Skript

<pre> =#!/usr/bin/perl
use strict;
use warnings;
use File::Find;
use File::Spec;
use Getopt::Long qw(:config pass_through);

#map{ print STDERR "$_ => $ENV{$_}\n" }keys(%ENV);
#----------------------------------------------------------------------#
# configuartions

# main config file of lighttpd
# needed to determin "username" "groupname" and "document_root"
my @conf=qw();

# temp dir
my $tmp=File::Spec->tmpdir();

# seach only here for perl scrips
my $bin_path= 'fcgi-bin';

# file suffix
my @suffix = qw();

# max processes of the script allowed
my $max_process=1;

# additional options
my $add='';

my @defult_confs=qw(/etc/lighttpd.conf /etc/lighttpd/lighttpd.conf /usr/lib/lighttpd/lighttpd.conf /usr/local/lib/lighttpd/lighttpd.conf);
#----------------------------------------------------------------------#
# script

GetOptions (
  "config_file=s" => \@conf,
  "suffix=s"      => \@suffix,
  "bin_path=s"    => \$bin_path,
  "max_process=i" => \$max_process,
  "add=s"         =>\$add,
  "tmp=s"         =>\$tmp,
) || exit;

#find a config file if no defined.
# ( CWD is set to conf path )
if(!@conf)
{
  my $first='';
  for(@defult_confs)
  { $first=$_ and last if(-f $_) };

  find(sub{
      if($File::Find::name=~/\.conf$/)
      {
        my $fname=(File::Spec->splitpath())[2];
        if($fname=~/lighttpd\.conf/)
        {
          if($first)
          { unshift(@conf,$File::Find::name); }
          else
          { $first=$File::Find::name; }
        }
        elsif($fname=~/lighttpd\.conf/)
        { unshift(@conf,$File::Find::name); }
        elsif($File::Find::name=~/lighttpd/)
        { push(@conf,$File::Find::name); }
      }
    },File::Spec->rel2abs('.'));

  unshift(@conf,$first) if($first);
}

# read config to find doc-root user and group
my $usr='';
my $grp='';
my $base='';
{
  OUTER:for(@conf)
  {
    open(my $fh, '<', $_) or exit;
    while(my $l=<$fh>)
    {
      $base=$1 if($l=~m!^\s*server.document-root\s*=\s*"([^"]+)"!s);
      $usr=$1  if($l=~m!^\s*server.username\s*=\s*"([^"]+)"!s);
      $grp=$1  if($l=~m!^\s*server.groupname\s*=\s*"([^"]+)"!s);
      last OUTER if($base && $usr && $grp);
    }
    close($fh);
  }
}
exit unless($base && -d $base && $usr && $grp);

# get ids for user and group
my $uid = getpwnam($usr);
my $gid = getgrnam($grp);
exit unless(defined($uid) && defined($gid));

# find files
# files have to be executable by process
my %files=();
find(sub{
    if(!@suffix || grep{$File::Find::name=~/\Q$_\E$/}@suffix)
    {
      my $fname=$File::Find::name;
      my $rname=File::Spec->abs2rel($fname,$base);
      $rname=~s!\\!/!gs;
      $rname="/$rname";
      my ($fperm,$fuid,$fgid)=(stat($fname))[2,4,5];
      $fperm &= 07777;
      if(-f $fname && (($fuid == $uid && $fperm & 00100) || ($fgid == $gid && $fperm & 00010) || $fperm & 00001) )
      { $files{$fname}=$rname; }
    }
  },File::Spec->rel2abs($base,$bin_path));
exit unless(%files);

# load mod_fastcgi
print qq#server.modules += ( "mod_fastcgi" )\n#;

# for each found script create a configuration.
my $cnt=0;
while(my($f,$n)=each(%files))
{
  my $tmp_file=File::Spec->join($tmp,"fastpl.$cnt.socket");
  print <<"EOC";
fastcgi.server += ( "$n" =>
  ((
    "bin-path" => "$f",
    "socket" => "$tmp_file",
    "max_process" => $max_process,
    "bin-copy-environment" => (
      "PATH", "SHELL", "USER"
    ),
    "broken-scriptfilename" => "enable"
$add
  ))
)
EOC
  $cnt++;
}= </pre>

Ergänzungen, Kommentare

Kommentare werden am besten in folgender Form vorgenommen, damit sie im Inhaltsverzeichnis angezeigt werden (natürlich ohne das <verbatim>):
---### Main.??? - 14 Jul 2003 - Betreff

UtilPerlSkripteSubForm edit

Titel Zuverläassiges laden von FastCGI? Scripten bei lighttpd
Autor ToPeGoe?
Bereich PerlSkripteWeb
Topic revision: 2011-01-21, ToPeGroe
 
Bitte die NutzungsBedingungen beachten.
Bei Vorschlägen, Anfragen oder Problemen mit dem PerlCommunityWiki bitten wir um WebBottomBarExample">Rückmeldung.