This is an old revision of the document!
Webhosting bij NPO ICT, generiek deel
Bij NPO ICT bestaan twee hosting clusters. Het zgn Applicatie Cluster (appcluster) is een omgeving ingericht die is toegespitst op het hosten van willekeurige Java, PHP en Ruby on Rails web-applicaties. Het Webservices Cluster (webcluster) is toegespitst op het hosten van high-volume sites. Hier worden alleen statische websites (“platte html”) specifieke door NPO ICT geaccepteerde PHP applicaties gehost.
Het app- en het webcluster zijn volgens dezelfde structuur opgebouwd. Dit document beschrijft het gemeenschappelijke stuk in de inrichting van het appcluster en het webcluster. Daarnaast zijn er de zusterdocumenten Appcluster Hosting en Webcluster Hosting die de specifieke eigenschappen van beide clusters beschrijven.
Inleiding
Bij NPO ICT zijn twee omgevingen ingericht, die samen een aantal webhostingmogelijkheden bieden. Het zgn Applicatie Cluster (appcluster) is een omgeving ingericht die is toegespitst op het hosten van willekeurige Java, PHP en Ruby on Rails web-applicaties. In deze omgeving hanteert NPO ICT geen acceptatiecriteria en zullen wij dus proberen om elke site te hosten. Het Webservices Cluster (webcluster) is toegespitst op het hosten van high-volume sites. Hier worden alleen statische websites (“platte html”) specifieke door NPO ICT geaccepteerde applicaties gehost. In het webcluster wordt gestreefd naar 24×7 beschikbaarheid, dus de sites die daar draaien zijn per definitie gebouwd met behulp van High Availability technieken. In het appcluster is dit optioneel, maar veel voorkomend en vaak ook gewenst.
Naast het app- en het webcluster is er ook een testcluster beschikbaar. Dit testcluster is op dezelfde manier opgezet als de productieclusters en kan gebruikt worden als testomgeving voor zowel het app- als het webcluster, maar kent geen uptime-garanties.
Beide omgevingen zijn server clusters bestaande uit twee loadbalancers, een aantal web-, applicatie- en database servers. Alle data bevindt zich op centrale, betrouwbare storage servers. Niet alleen is uw data daar veilig, maar dit zorgt er ook voor dat uw omgeving bijzonder flexibel is. Een database server kan a la minute een applicatieserver worden mocht dat nodig zijn. Of, als u al uw diensten op 1 server draaide en uw sites worden populair kan er zeer snel een tweede server bijgeschakeld worden om de last te verdelen.
De hardware, het OS, de web-, applicatie- en databaseservers worden beheerd door NPO ICT, wat garant staat voor een stabiele, veilige omgeving. In het appcluster kunt u uw eigen applicaties zelf beheren, uitbesteden aan NPO ICT of aan een derde partij. In het webcluster worden de applicaties uitsluitend beheerd door NPO ICT, waarbij NPO ICT delen van het beheer kan delegeren aan derden. (b.v. de makers van een applicatie)
Vragen? Deze kunnen gericht worden aan de NPO ICT Servicedesk servicedesk@omroep.nl
Standaard Software
Alle omgevingen zijn zoveel mogelijk gebaseerd op open source software componenten: Linux, Apache, MySQL, PHP, Tomcat, Ruby, Rails, etcetera. Wij zijn namelijk overtuigd van de kracht van open source en bij NPO ICT is zeer kennis aanwezig van de gebruikte open source componenten.
| Component | Versie | Opmerkingen |
|---|---|---|
| OS | Scientific Linux 6, 64 bit | Scientific Linux is gebaseerd op Redhat Enterprise Linux. Vergelijkbaar met CentOS 6 kijk op hun website |
| HA-Loadbalancer | Keepalived-1.2.x | Loadbalancing wordt verzorgd door Keepalived dmv Direct Routing. We draaien de loadbalancers in een master-slave configuratie, waarin de slave het overneemt als de master er mee ophoudt. Het loadbalancen gebeurt op basis van direct routing, wat betekent dat retour verkeer niet door de loadbalancers heen hoeft, waardoor deze grote aantallen verkeer kunnen verwerken. |
| Statische webserver / front-Proxy | Apache-2.4.x + mod_worker of Nginx | Deze front-proxies kunnen statische data (html, plaatjes, .css, .js etc.) snel en efficient uitserveren; vele malen sneller en efficienter dan een 'backend' applicatieserver. Daarnaast zorgen ze voor loadbalancing en failover tussen 2 of meer applicatieservers In geval van java sites kan de proxy ook caching verzorgen. Php, jsp en railsapplicaties worden geproxied naar een applicatieserver. |
| Dynamische webserver voor PHP sites | Apache-2.4.x + mod_prefork of php-fpm | PHP sites draaien onder apache-2.4 Wij geven er de voorkeur aan om de PHP webservers achter een proxy te zetten, waarbij de proxy de statische content zelf kan uitserveren. |
| PHP | php(-fpm)5.6 of nieuwer | Voor PHP kunnen wij deze modules leveren |
| Database | MySQL(tegenwoordig MariaDB) of Postgresql | |
| postfix-2.5.x | Mail versturen en ontvangen kan via verschillende methoden. |
Extra software in het appcluster
In het appcluster is naast de gewone LAMP stack ook Java, Ruby on Rails en Zope hosting mogelijk. Daartoe zijn de volgende software componenten beschikbaar:
| Component | Versie | Opmerkingen |
|---|---|---|
| Java | jre-1.6.x (default) of jre-1.7.x (indien gewenst) | Liefst gebruiken we alleen de runtime environment (jre). In sommige gevallen kunnen we ook een jdk aanbieden |
| Servlet container | Tomcat-6.x | |
| Ruby on Rails | ruby-1.8.x + rubygems-1.3.x + passenger-2.x.y | |
| Overig | - | Andere tools als ImageMagick, ffmpeg e.d. zijn op aanvraag beschikbaar |
In overleg met NPO ICT kunnen eventueel extra ondersteunende pakketten geinstalleerd worden. Indien dit geen open source is, dient u zelf zorg te dragen voor een eventuele licentie.
Opbouw van de omgevingen
Het hart van de omgeving is de storage server. Hier ligt alle data van alle andere servers opgeslagen. De lokale disken van de andere servers bevatten alleen het OS. Het voordeel van deze opzet is dat als er een server uit mocht vallen, deze zeer snel te vervangen is door een reserveserver. Omdat er geen data op de uitgevallen server staat, hoeft er geen restore uitgevoerd te worden en kan de reserverserver zeer snel weer online zijn. De storage server zelf is o.a. geselecteerd op z'n betrouwbaarheid, zodat de kans dat deze uitvalt zeer gering is.
Middels NFS over een prive netwerk is de storage server gekoppeld aan de frontproxy-, applicatie- en database servers. Deze servers zijn op hun beurt via een publiek netwerk (en een tussenliggende router) aan het internet verbonden. Op de router gebeurt afscherming, zodat alleen http verkeer (webserving) en ssh verkeer (uploaden bestanden) tussen het internet en de servers mogelijk is. Daarnaast vindt op de hosts zelf ook afscherming plaats, zodat er geen ongeoorloofd verkeer tussen verschillende servers in hetzelfde cluster mogelijk is.
In onderstaand overzicht zijn 4 servers getekend, in werkelijkheid zijn dit er in het appcluster nu bijna 30. Het geheel van alle servers tezamen vormt het hosting cluster.
Instanties
Een belangrijk concept in het cluster is dat van een “instantie”. Een instantie is de combinatie van een proces en resources behorende bij zo'n proces (met name storage en een eigen IP adres) Bekendste voorbeeld is een database instantie. Daar heb je dus het database proces en de on-disk data files waar het database proces op werkt. Maar, ook van andere diensten kan je een instantie hebben. Denk aan een webserver instantie. Een proces (“apache”) in combinatie met storage (o.a. de documentroot van een website) waar dat proces wat mee doet.
Dit concept is zo belangrijk, omdat de individuele nodes (servers) in het cluster “instantie agnostisch” zijn opgezet. Dwz er is geen binding tussen een node en een instantie. Een instantie kan draaien op node A, maar net zo goed op node B. (bedenk dat de storage van een instantie niet op de lokale disken van een node ligt, maar op de gesharede disken van de fileserver)
Sterker nog, er kunnen meerdere instanties van hetzelfde type (webservers, database servers) draaien op dezelfde node. Bijvoorbeeld, in het appcluster hebben we een node aangewezen als plekje waar normaliter alle shared databases moeten draaien. Op dit moment draaien daar 4 database instanties op. Als we hardware zouden hebben met heel veel CPU en geheugen, dan zou niets ons letten om alle instanties van het hele cluster op die ene superkrachtige node te draaien.
Dit kan omdat we ervoor zorgen dat een instantie nooit “unieke” resources van een node in kan pikken. Bijvoorbeeld: apache laten we nooit binden aan het 0.0.0.0 adres, maar alleen maar een een specifiek, bij die instantie behorend ip adres. Net zo voor databases. Die willen vaak graag een socket in /tmp aanmaken. Dat gaat mooi niet door, want zo'n socket kan maar 1x aangemaakt worden. In de start/stop scripts zorgen we er dus voor dat zo'n socket niet in de globale /tmp directory aangemaakt wordt, maar in een directory behorende bij de instantie.
Tegelijkertijd hebben we onze eigen versies van de normale start/stop scripts (dwz de scripts die je normaal in /etc/init.d vindt); onze versies doen extra zaken. Waaronder het dynamisch opbrengen van het IP adres behorende bij een instantie, op de node waar je op dat moment de instantie opstart. Bij het afluiten van de instantie wordt het IP adres ook weer verwijderd.
De grap nu van die instanties is dat het dus heel makkelijk is om een individuele node even tijdelijk uit de running te halen. Simpel alle instanties die op die node draaien even “overhupsen” naar een andere node. Stoppen aan de ene kant, weer opstarten aan de andere kant en de dienst draait weer verder. Dit kan binnen seconden geregeld zijn. Hiermee is het mogelijk om b.v. nodes voorzien van kernel of OS upgrades, zonder dat de diensten die aan de buitenwereld geleverd worden down gebracht hoeven te worden.
De Frontproxy-, Applicatie- en Database servers
Al het webverkeer wordt afgehandeld door de frontproxies. Dit zijn webservers die java hosting als een intermediair tussen de buitenwereld en de applicatieservers fungeren. De voornaamste reden hiervoor is caching: alle requests die uit de cache geserveerd kunnen worden hoeven niet door een applicatieserver afgehandeld te worden, wat +/- een factor 100 (!) in performance kan schelen. (een frontproxy kan maximaal +/- 5000 hits/sec afhandelen, een tomcat applicatieserver +/- 50)
Alle requests die de frontproxy niet zelf af kan handelen worden over het prive netwerk doorgestuurd naar de juiste applicatieserver. De applicatieserver op zijn beurt kan weer database requests naar een database server sturen.
Bij php hosting is er geen sprake van een aparte applicatieserver. Daar verzorgt de webserver zelf het afhandelen van php bestanden. Echter, het blijkt dat php serving ook verbetert als dat achter een proxy gestopt wordt. In die zin krijgt de php-enabled server dus een rol als een applicatieserver.
Ondertussen is alle file access die hierbij nodig is via NFS naar de storage server (bijvoorbeeld voor een database server die z'n datafiles moet raadplegen). Om het NFS verkeer te minimaliseren zijn alle cluster nodes uitgerust met veel geheugen, zodat de meeste file access vanuit het geheugen gedaan kan worden en niet via NFS hoeft.
De Uploadserver
Een speciale rol is weggelegd voor de upload server. Dit is het enige systeem waarop ingelogged kan worden en vanaf waar nieuwe applicaties geplaatst kunnen worden.
Omdat de storage gedeeld is tussen alle systemen, kunnen bestanden die via de upload server geplaatst worden, door de applicatieservers gelezen worden. Andersom kunnen logfiles die door de applicatieservers gemaakt worden vanaf de upload server gelezen worden.
Indien applicatieontwikkelaars of andere partijen zelf applicaties willen kunnen plaatsen krijgt men een account op de upload server. Het grote publiek heeft geen toegang tot dit systeem. Shell toegang tot de overige servers is alleen voor de beheerders van NPO ICT weggelegd. Wel kan vanaf de upload server door bv applicatieontwikkelaars een sql connectie tot een database server opgezet worden.
Filesysteem layout: /e en /d
Alles dat te maken heeft met de diensten draaien is
op het filesysteem te vinden onder de directory genaamd “/e”.
Daar is voor elk type dienst een subdirectory, met daaronder alle instanties
van die dienst, en daar weer onder de zaken die nodig zijn voor die dienst.
Oftwel: alle paden zien er uit als
/e/<dienst>/<instantie-naam>/<instantie specifieke zaken>
Onder /e staan veel symlinks die allemaal naar een directory onder /d wijzen. Die /d directories zijn puur voor intern gebruik Dwz het is niet de bedoeling dat een padnaam beginnend met /d ooit naar buiten gecommuniceerd wordt of ergens in configuratie opgenomen wordt. De bedoeling van de split tussen /e en /d is dat systeembeheerders makkelijk data naar andere filesystemen kunnen schuiven, zonder dat er enige configuratie in de draaiende applicatie aangepast moet worden. Wat wellicht verwarrend is, is dat het “locate” commando wel padnamen met /d oplepelt. Dat is wellicht misleidend en men moet zelf bedenken wat het bijbehorende /e pad is. Ook php en diverse ftp clients willen graag symlinks dereferencen, waardoor in die hoek ook nog wel eens /d paden zichtbaar willen zijn. Wees hier bedacht op.
De reden dat voor deze “rare” opzet gekozen is, is dat alles in een cluster draait. Het idee is dat dan alle storage centraal op 1 storage server komt te liggen, die gedeeld wordt door alle cluster nodes. In zo'n cluster opzet is het handig als elke dienst op elke willekeurige cluster node kan draaien en als er ook b.v. meerdere instanties van een dienst (zeg meerdere database instances) op dezelfde clusternode kunnen draaien. De gekozen filesysteem indeling maakt dit mogelijk.
Omdat het opzet van het cluster wat onorthodox is (met de gedeelde storage)
is de filesysteem layout ook wat onorthodox.
Alles in het cluster dat te maken heeft met de diensten die er draaien is
op het filesysteem te vinden onder de directory genaamd “/e”.
Daar is voor elk type dienst een subdirectory, met daaronder alle instanties
van die dienst, en daar weer onder de zaken die nodig zijn voor die dienst.
Oftwel: alle paden zien er uit als
/e/<dienst>/<instantie-naam>/<instantie specifieke zaken>
-
/e/ha
Hier staan de loadbalancer / keepalived instanties. Deze komen altijd voor in paartjes (instantieA en instantieB), die onderling voor een highly available service zorgen. De actieve node fungeert als loadbalancer om requests te distribueren over meerdere webservers.
-
/e/fp Hieronder staan alle frontproxy / webserver instanties. Normaal
gesproken zal voor elke omroep 1 set frontproxies draaien, maar het kunnen er ook meer zijn (bv voor een https server) of geen als die omroep van de shared frontproxy gebruik maakt. Als een dienst geloadbalanced wordt, dan staan er hier een aantal instanties naast elkaar, genaamd …a, …b, …c enz.
-
/e/as Hieronder staan alle applicatie server instanties.
Een omroep kan ervoor kiezen om al z'n applicaties binnen dezelfde applicatie server instantie te draaien, maar er zijn ook andere mogelijkheden. Zo kunnen er verschillende instanties gebruikt worden als delen van een site op verschillende nodes draaien, of als men de website en het cms wil scheiden (bv MMBase editwizards in een aparte instantie).
-
/e/ap Hieronder staan alle applicaties (webapps en php-sites)
Binnen de applicatieserver wordt naar deze directory verwezen; het idee is dat een applicatie niet gebonden is aan een specifieke applicatieserver, maar relatief eenvoudig tussen verschillende applicatieservers moet kunnen verhuizen mocht dat nodig zijn. In geval van php hosting is er normaliter een 1 op 1 relatie tussen de naam van een vhost (b.v. www.site.nl) en de naam onder /e/ap (dwz /e/ap/www.site.nl)
-
/e/db Hieronder staan alle database instanties.
Normaal wordt er 1 database instantie per omroep aangehouden, waarbinnen dan alle databases voor die omroep aangemaakt worden. In sommige gevallen kan hier van afgeweken worden, bijvoorbeeld als voor een omroep zowel een postgresql als een mysql database nodig is, of als men over meerdere database nodes wil kunnen beschikken.
-
/e/ml Hieronder staan alle mailserver instanties.
Voor de diverse intanties zijn de volgende directories van belang:
-
/e/{ha,fp,as,db,ml}/<instance>/{log,OLDlog} De (gearchiveerde)
logfiles van een server instance.
-
/e/{ha,fp,as,db,ml}/<instance>/conf De configuratie van de
instance in kwestie
-
/e/{ha,fp,as,db,ml}/<instance>/rc De start/stop scripts van de
instance in kwestie.
-
/e/{ha,fp,as,db,ml}/<instance>/data De data behorende bij
een instantie. Denk bijvoorbeeld aan de datafiles van een database of aan de queueing directory van een mailserver.
-
/e/{ha,fp,as,db,ml}/<instance>/tmp Temp directory. Kan
door de instance gebruikt worden als scrath dir.
Voor applicaties ligt het iets anders; php applicaties hebben een iets andere directory structuur dan java applicaties.
PHP applicaties hebben de volgende structuur onder /e/ap/<applicatienaam>
-
pages
(php applicaties) De document root van een php website. Deze is standaard php-enabled; maar -niet- schrijfbaar voor de webserver. Files hebben standaard als groep 'cw<naampje>'; zodat verschillende uploaders (bijvoorbeeld een omroep samen met een externe webbouwer) schrijfrechten hebben op de files. Belangrijk daarvoor is dat files mode 0664 hebben, en directories 2775. Dit valt prima te bereiken door een 'umask 002' in je .profile neer te zetten.
-
data
De plek waar een applicatie z'n persistente data kan wegschrijven. Deze directory wordt direct via de proxy-webserver uitgeserveerd worden onder www.applicatienaam.nl/data. Het zelfde rechtenverhaal gaat hier ook op, behalve dan dat de bestanden en directories allemaal lid zijn van een 'dw<naampje>'-groep. Hierin zitten dezelfde mensen als in het 'cw<naampje>'-groepje, maar de webservers die data weg mogen schrijven zijn hier ook aan toegevoegd.
-
config
Hier kunnen config bestanden geplaatst worden. Deze directory zit in het php include path. Bijvoorbeelde de database parameters zijn hier altijd terug te vinden, maar ook allerlei php-code valt hier te plaatsen die niet in de docomentroot hoeft te staan (denk aan generieke classes, libraries, etcetera). Ook deze directory is niet schrijfbaar voor de webserver. Wat betreft de rechten geldt hier hetzelfde als oncer /pages.
-
tmp
Scratch directory van een applicatie
Tot slot hebben we nog
-
/home/omroep/<accountnaam>
De unix home directory van het upload-account genaamd <accountnaam>. Dit is de plek waar je binnenkomt als je inlogt. Als dit upload account bedoeld is voor het uploaden van applicatie X, dan zal er in de home directory vaak een verwijzing (symlink) naar applicatiedirectory X, dwz /e/ap/X gemaakt worden.
Filesysteem layout: /local en /software
De systemen zijn ingericht als zgn “netboot clients”. Dat betekent o.a. dat er een /local en een /software directory is. Dit is de manier waarop NPO ICT z'n zelfgecompilede software distribueert; hieronder is het relevante stukje uit de netboot documentatie geknipt:
———begin knip hier———
In onze setup gebruiken we de directories /local en
/software om onze software in te zetten. Door slim gebruik te
maken van symlinks kunnen we hier heel eenvoudig de versies van de
gebruikte software veranderen. De software benader je uiteindelijk door
/local/bin en evt. /local/sbin in je PATH te
hebben.
Stel je hebt een software pakket “foo” met versie nummer 2.71. Dan wordt
de software neergezet onder /software/foo-2.71. Stel dat “foo”
bestaat uit 2 executables bar en baz met bij horende
manpages, dan krijg je zo'n structuur:
/software/foo-2.71/bin/bar /software/foo-2.71/bin/baz /software/foo-2.71/man/man3/bar /software/foo-2.71/man/man3/baz
Om dit te benaderen moeten er nu in /local/bin en in
/local/man/man3 wat symlinkjes gezet worden. Deze worden niet
direct naar /software/foo-2.71/… gelinked maar deze lopen via
een extra symlinkje in /local. Dit extra linkje ziet er zo uit:
/local/foo -> /software/foo-2.71
En de rest van de linkjes onder /local zo:
/local/bin/bar -> /local/foo/bin/bar /local/bin/baz -> /local/foo/bin/baz /local/man/man3/bar -> /local/foo/man/man3/bar /local/man/man3/baz -> /local/foo/man/man3/bar
Dit schept een werkend geheel. En nu het slimme stuk. Er komt een
belangrijke nieuwe versie van “foo” uit, versie 3.14. En je wilt hier
naar upgraden. Deze versie zet je weer onder /software neer, en
wel zo:
/software/foo-3.14/bin/bar /software/foo-3.14/bin/baz /software/foo-3.14/man/man3/bar /software/foo-3.14/man/man3/baz
Het actief maken is nu een simpele kwestie van het vervangen van een enkele symlink:
/local/foo -> /software/foo-2.71
door:
/local/foo -> /software/foo-3.14
———einde knip hier———
Concreet betekent dit dat bv de mysql software staat onder /local/mysql, maar dat een mysql instantie leeft onder /e/db/…
Zelfde voor apache met /local/apache en /e/fp/…
Om te zien welke versies actief zijn, kan men ls -l /local doen, dat
geeft een lijst met symlinks naar de exacte versies onder /software.
Om niet eindeloos je $PATH aan te hoeven passen is er ook nog de /local/bin directory, deze heeft voor elk geinstalleerd pakket (dat zelf onder /local/pakket leeft) een setje symlinks onder /local/bin en /local/man staan naar /local/pakket/bin.
Bijvoorbeeld, het mysql dump tool staat in /local/mysql/bin/mysqldump. Maar, wij hebben ook een symlink /local/bin/mysqldump naar /local/mysql/bin/mysqldump. Het nut hiervan is dat alleen /local/bin in je $PATH hoeft te staan, om bij alle geinstalleerde pakketten te kunnen.
Read-only vs Read-write filesystemen
In onze omgeving maken wij onderscheid tussen read-only en read-write filesystemen. Voor de read-only filesystemen geldt dat deze vanaf de web, applicatie en database servers niet gewijzigd kunnen worden. Deze filesystemen worden gebruikt om de executeerbare delen en de configuratie van applicaties op te slaan.
In onze omgeving is het zo dat alle web-app en pages directories op read-only filesystemen liggen. Verder ligt alle configuratie (frontproxy, database, applicatieserver) op een read-only filesysteem. De read-write filesystemen worden alleen gebruikt voor logfiles, temp-directories en databases.
De reden hiervoor is dat als een site gehacked wordt, het voor de hacker onmogelijk is om b.v. jsp of php files te wijzigen. Concreet houdt dit in dat bij een geslaagde hack poging de applicatie zichzelf niet kan wijzigen (op instigatie van de hacker), en dat het dus bijzonder moeilijk zal zijn om b.v. aan de database inhoud te komen. Overigens is er bij ons nog nooit een geslaagde hackpoging geweest.
Dit houdt in dat het voor applicaties dus niet mogelijk is om self-modifying code te gebruiken (bv een jsp die een nieuwe versie van zichzelf neerzet). In het geval van MMBase houdt dit in dat er niet via het web-interface nieuwe delen van MMBase geinstalleerd kunnen worden (want de applicatieserver mag niet schrijven in z'n web-app directory) Zelfs als u bijvoorbeeld “chmod 777” (= unix speak voor world writable) op een jsp bestand zou doen, dan nog is het niet te wijzigen vanaf een applicatieserver. Dit willen we dan ook ten zeerste afraden.
De enige plek vanaf waar naar de read-only filesystemen geschreven mag worden is de upload server. Da's ook nodig, anders zouden er b.v. nooit nieuwe jsp bestanden geplaatst kunnen worden.
Naamgeving
De policy voor naamgeving is als volgt: (ingewikkeld? Vertel ons wat u wilt en wij regelen het zonder u te vermoeien met onderstaande details)
-
Websites
Elke omroep is geheel vrij een naam voor de website te kiezen. Elke applicatie kan onder een andere naam draaien (bv “www.groente.nl” vs “www.fruit.nl”), een gedeelde naam (bv “www.plantaardig.nl/groente vs www.plantaardig.nl/fruit”) of onder de default naam “sites.omroep.nl” (bv sites.omroep.nl/groente) De naam die u kiest, is de naam die in de locatiebalk van de webserver zichbaar is en de naam die extern bekend gemaakt wordt. Alle naamgeving die hieronder nog staat is alleen maar intern, en niet extern zichtbaar. In de testomgeving hebben wij liefst dat applicaties draaien onder “testsites.omroep.nl/<applicatie>”, maar indien gewenst kunnen er ook (lange!) namen als “<omroep>-<applicatie>test.omroep.nl” aangemaakt worden (bv degezondeomroep-groentetest.omroep.nl)
-
Frontproxies
Deze worden genoemd naar de omroep waar ze bij horen,
gevolgd door een volgnummer. B.v. /e/fp/dgo01 zou de 1e frontproxy
van “De Gezonde Omroep” (DGO) zijn. De shared frontproxy heet <tt/shrd01/
De dns naam van een frontproxy wordt “<omroep>-sites.omroep.nl”.
(bv “degezondeomroep-sites.omroep.nl”). Deze naam wordt iha niet extern
genoemd, maar is alleen een “kapstok” om domeinnamen aan op te kunnen
hangen, dmv DNS CNAMES. (b.v. www.groente.nl is een CNAME naar
degezondeomroep-sites.omroep.nl; dmv een virtualhost constructie in de
frontproxy zorgen wij er dan voor dat www.groente.nl uitkomt bij de groente
applicatie)
-
Databases
Deze worden ook genoemd naar de omroep waar ze bij horen,
gevolgd door een volgnummer. In de naamgeving wordt geen onderscheid tussen
de verschillende types database (mysql of postgresql) aangehouden. B.v.
/e/db/dgo01 zou de eerste database instance van de gezonde omroep
zijn. De shared
database instances heten shrd01 (mysql) en shrd02 (postgresql)
Binnen de database instances kunnen voor de diverse applicaties diverse
databases aangemaakt worden. Als er een applicatie genaamd “groente” zou zijn, zou
de database die daarbij hoort “groentedb” heten en de database user die daarbij
hoort zou “groente' heten.
-
Applicatie Servers
Ook deze worden genoemd naar de omroep waar ze bij
horen, met een volgnummer. De tiende DGO applicatieserver zou
/e/as/dgo10 heten.
De naam van applicatieservers wordt generiek gehouden, omdat een
applicatieserver geen 1 op 1 relatie met een applicatie heeft.
-
Applicaties
Voor applicaties wordt bij voorkeur gepoogd om een 1 op 1 mapping tussen url en applicatienaam te hebben. Dwz als een website www.groentenenfruit.nl heet, dan is de applicatienaam ook /e/ap/www.groentenenfruit.nl In geval van java hosting wil het nog wel eens voorkomen dat er onder 1 url meerdere applicaties hangen (verschillende mountpoints in tomcat) In dat geval wordt gepoogd een min of meer descriptieve naam te gebruiken. Stel dat onder de groentenenfruit site nog een speciale shop module nodig is, dan zou deze op disk /e/ap/groentenenfruitshop kunnen heten en bereikbaar kunnen zind als www.groentenenfruit.nl/shop.
-
Upload Accountnamen
De upload accounts worden meestal genoemd naar de organisatie die de
uploads wil kunnen doen. Stel dat DGO het maken van z'n Groenten en Fruit
site geheeld uit zou besteden aan de “DeNeefjesCompany Ltd” dan zou het upload
account iets als “neefjes” kunnen heten; dit account zou vervolgens
schrijfrechten onder onder /e/ap/groentenenfruit/web-app krijgen
om daar de applicatie te plaatsen.
Als een omroep zelf z'n eigen applicaties plaatst, dan wordt de accountnaam
weer iets als “omroep+volgnummer”.
Users en Groups namen
In het web- app- en testcluster is i.h.a. een vrij stricte relatie tussen een usernaam en waar deze voor gebruikt wordt. B.v. een instantie die leeft onder /e/XX/YYYYYY draait bijna altijd onder het userid YYYYYYXX. Voorbeeld: de webserver instantie /e/fp/dmd1a draait onder als user dmd1afp, de postfix instantie /e/ml/dmd2b draait als dmd2bml.
Alle user accounts worden gecreeerd volgens het “all accounts are created equal” principe, wat inhoudt dat er nooit intrinsieke rechten aan een account hangen. De rechten volgen pas door het account toe te voegen aan specifieke groepen. Om dit af te dwingen worden accounts altijd gecreeerd met uid=gid (dit is unix terminologie, en betekent dat elk account in z'n eigen unieke groep geplaatst wordt). De naam van de groep is gelijk aan de naam van de user. Oftewel, als er een user X is met uid N, dan is z'n primary group-id ook N en de bijbehorende groepsnaam is weer X. Ook aan het uid hangen geen speciale rechten, da's gewoon het eerstvolgende vrije uid boven de 5000. Voorbeeld: de user “test1afp”. Deze heeft de volgende entry in /etc/passwd
test1afp:x:5000:5000:Test webserver:/e/fp/test1a:/sbin/nologin
Zie hoe het userid gelijk is aan het group-id (5000), dus in /etc/group komt de volgende regel voor:
test1afp:x:5000:
Als we nu rechten uit willen delen aan deze user, dan kan dat op basis van group-membership. Typisch voor een webserver is dat deze data moet kunnen wegschrijven en derhalve lid van een data writers (“dw”) group moet zijn:
dwtest:x:20000:test1afp,test1bfp,webtoko1
De groeps-id's hebben ook geen speciale betekenis; het eerste vrije uid boven de 20000. In de groeps namen zit wel enige codering, nl in de eerste twee letters:
-
rd - Reader
De groep voor users die ergens mogen lezen. Dit bestaat om ervoor te zorgen dat ongerelateerde entiteiten niet elkaars spullen mogen lezen. De readers omvat normaal gesproken alle user users die iets met een applicatie te maken hebben: webservers, applicatieservers, databases, uploaders en beheerders.
-
dw - Data writer
De groep voor users die data mogen plaatsen. Dit zijn de uploaders en de processen die zelf data wegschrijven (bv een webserver die ge-upload content ergens weg moet kunnen schrijven)
-
cw - Content Writer
De groep voor users die content (denk aan php code) mogen plaatsen. Dit zijn normaal gesproken alleen de uploaders.
Voorbeeld: stel dat er een applicatie <tt/foo/ is, bestaande uit een paar webservers en een paar uploaders, dan geeft dat aanleiding tot de volgende groepen:
rdfoo:x:20000:uploader1,uploader2,foo1afp,foo1bfp,beheerders dwfoo:x:20001:uploader1,uploader2,foo1afp,foo1bfp cwfoo:x:20002:uploader1,uploader2
File Permissies
Het probleem: afscherming en samen kunnen schrijven
Er zijn twee problemen die we op willen lossen:
-
Afscherming
Je wilt niet dat alles voor iedereen leesbaar is. De uploaders van de ene omroep moeten niet de code van een andere omroep kunnen zien.
-
Samen schrijven
Je wilt dat verschillende users dingen op het filesysteem met elkaar kunnen delen. Bijvoorbeeld meerdeer upload accounts die samen aan de code van 1 applicatie moeten kunnen werken, of meerdere geloadbalancede webservers die elk onder een gesharede /data spulletjes moeten kunnen wegschrijven. Ook wil je vaak dat zowel uploaders als webservers samen onder /data kunnens chrijven.
Oplossing voor Afscherming: Hekjes
Een hekje is een directory ergens bovenaan in een directory tree die niet world readable is, slechts group readable en dus alleen te passeren voor users die lid zijn van die groep.
Voorbeeld:
Beschouw de volgende groep:
readers:x:10000:uploader1,uploader2,webserver1,webserver2,beheerders
en deze directory:
/d/netapp/ro/00/ap/www.website.nl
Als we die directory nou owner root:readers, mode 750 geven dan is alles wat daaronder ligt niet meer te benaderen voor users die geen lid van de groep “readers” zijn. Onafhankelijk van de permissies daaronder!
Oplossing voor samen Schrijven: datawriters en contentwriters
Voor het schrijven roepen we ook 2 groepen in het leven: de datawriters en de contentwriters. Contentwriters zijn iha de users met een upload account, die vanuit de upload server de /pages (e.d.) directory mogen vullen. In de datawriters groep zitten de webservers en de uploaders samen. En dat geeft ze rechten om onder /data te schrijven.
Om dit goed te laten werken is het nodig dat zowel datawriters als contentwriters een umask 002 hanteren, zodat wat ze aanmaken default group writable is.
En om dat weer veilig te kunnen doen is het nodig dat ALLE users een uniek primary group ID hebben.
Dus, voorbeeld:
We hebben de users:
webserver1:x:5001:5001:Ik ben een webserver:/var/empty/home:/sbin/nologin webserver1:x:5002:5002:Ik ben een webserver:/var/empty/home:/sbin/nologin uploader1:x:5003:5003:Ik ben een uploader:/home/omroep/uploader1:/bin/bash uploader2:x:5004:5004:Ik ben een uploader:/home/omroep/uploader1:/bin/bash
Dan hebben we de groepen:
readers:x:10000:uploader1,uploader2,webserver1,webserver2,beheerders contentwriters:x:10001:uploader1,uploader2 datawriters:x:10002:uploader1,uploader2,webserver1,webserver2
En de permissies onder /e/ap/www.website.nl zouden dan zijn:
$ cd /e/ap/www.website.nl # ls -Lla . drwxr-x--- 2 root readers 4.0K Jan 14 23:12 . drwxrwxr-x 2 root contenwriters 4.0K Jan 14 23:12 pages drwxrwxr-x 2 root datawriters 4.0K Jan 14 23:12 data
Granulariteit van readers en content/data-writers
Readers
Laten we per omroep 1 readers groep aanmaken. Dat betekent dat als webtoko1 en webtoko2 allebei voor $omroep werken ze elkaars code kunnen lezen en de code die een omroep zelf opgehoest heeft. Maar, dat zou imo geen probleem moeten zijn.
Content/Data-writers
Je wilt niet dat webtoko1 en webtoko2 over elkaars code heen kunnen krassen. Ook wil je een asymmetrische relatie tussen $omroep en $webtoko, nl $omroep mag wel over de code van $webtoko heenkrassen, maar niet andersom. Dit is te regelen door per omroep-webtoko combinatie een groepje aan te maken:
readers:x:10000:omroep,webtoko1,webtoko2,webserver1,webserver2,beheerders contentwriters:x:10001:omroep toko1writers:x:10002:omroep,webtoko1 toko2writers:x:10003:omroep,webtoko2 datawriters:x:10004::omroep,webtoko1,webtoko2,webserver1,webserver2
Op die manier kan toko1 nog wel over de data van toko2 heenschrijven, maar dat konden ze toch al, als ze in dezelfde apache instantie draaien. (nl door het apache maar te laten doen)
$omroep dreigt wel lid van veel groepen te worden op die manier (net zoveel als dat ze gescheiden webtoko's in dienst hebben), dus die moeten wellicht van tijd tot tijd “newgrp toko1writers” intikken om over de code van toko1 heen te kunnen krassen.
Als tokoX nou maar 1 account heeft, en niet hoeft te delen met tokoY, dan kan het simpeler opgelost worden; nl tokoX geen lid te maken van enige contentwriter group en de pages directory owner tokoX. Dwz owner tokoX:contentwriters, mode 775.
Rechten goed houden met php
Bovenstaande rechtenstructuur is essentieel voor de juiste werking van een website. Wanneer er, bijvoorbeeld door de code van de website, wijzigingen in de rechten worden aangebracht kan hierdoor functionaliteit verloren gaan. Het is daarom belangrijk dat de code van de website de rechten niet veranderd wat helaas in php niet altijd voor de hand liggend is. De basis gedachte achter ons platform is: eea is zo opgezet dat de rechten vanzelf goed komen te staan. Wij zien dus het liefst dat er zo min mogelijk gebruik wordt gemaakt van chown/chmod en consorten. Voorwaarde is wel dat het zgn “umask” goed staat; dat moet op '002' staan. In onze web-, sshd- en ftpservers zorgen wij ervoor dat dat goed staat. In shell accounts adviseren wij om in een '.profile' een 'umask 002' op te nemen. Enige probleem geval zijn cronjobs. Cron draait met een verkeerd umask (022); indien er cronjobjes gebruikt worden die mogelijk files of directories zouden kunnen creeeren dan is het aan te raden om in het desbetreffende commando een umask op te nemen; bijvoorbeeld zoiets:
*/5 * * * * umask 002; doe_iets.php
Sommige php functies (b.v. mkdir) willen in sommige gevallen dat er permissies opgegeven worden. De mkdir functie werkt als volgt:
bool mkdir ( string $pathname [, int $mode = 0777 [, bool $recursive = false [, resource $context ]]] )
Dat houdt in dat als je recursive een directory aan wilt maken (“mkdir -p” zeg maar) je opeens verplicht bent om ook permissies op te geven. Gebruik in dat geval de default permissies (hier dus 0777) dat komt omdat de permissies die bij mkdir opgegeven worden, worden ge-bitmasked met je umask en op die manier toch de juiste rechten gebruikt worden.
Http Loadbalancing
Er zijn meerdere manieren om loadbalancing te implementeren, deze sectie beschrijft hoe wij dit het liefste doen, nl met twee gestapelde loadbalancers. De gedachte is dat we aan de buitenkant een paartje loadbalancers hebben, welke in master/slave configuratie draaien. Deze loadbalancers gebruiken keepalived met direct routing. Dat betekent dat de loadbalancers puur op IP niveau kijken en losse IP pakketjes doorsturen naar de te loadbalancen instanties.
Normaal zouden die te loadbalancen instanties een farm van webservers zijn die het eigenlijke werk doen, maar hier zit er een extra laag tussen, nl er wordt geloadbalanced over een farm(pje) van http proxies. En die proxies op hun beurt loadbalancen (mod-proxy-balancer igv apache) dan over de farm van (php enabled) webservers die het echte werk doen. In ascii art ziet dat er als volgt uit
Interweb
|
web1a....web1b Load balancers
/ \
/ \
xxx1afp xxx1bfp static, loadbalancing http proxies
|\ /|
| \ / |
| \/ |
| /\ |
| / \ |
|/ \|
xxx2afp xxx2bfp php nodes
Er is voor deze getrapte setup gekozen om de volgende redenen:
-
Aan webserving zitten twee kanten: enerzijds het spoonfeeden
(bitje voor bitje uitserveren, over een tergend traag internet lijntje)
van data naar je kijkers, anderzijds het uitrekenen (denk php) van hoe
een webpagina eruit moet zien.
Voor het uitrekenen (php) heb je hele “dure” webserver slots nodig;
bij apache is dat single threaded, ze hebben veel geheugen nodig etc.
Het spoonfeeden echter is een simpele taak, die heel goed threaded kan.
Normaal bij een php webserver zit je dus 90% van de tijd dure php slots
te gebruiken om data naar je kijkers te spoonfeeden. Rescources die
beter anders gebruikt zouden kunnen worden.
Door er een http proxy tussen te zetten ontkoppel je het rekenen van het
spoonfeeden. Het spoonfeeden gebeurt nu door de proxy, die daartoe
geoptimaliseerd is (threaded webserver, veel slots e.d.)
Het rekenen gebeurt door de geproxiede server. Omdat er tussen de proxy
en de reken-server een snelle connectie ligt, is daar geen sprake van
spoonfeeding en zijn de dure php slots alleen in gebruik op het moment
dat ze ook echt nodig zijn. In apache termen betekent dit dat je op de
php servers kan volstaan met>MaxClients 8, wat in normale
mensentermen betekent dat je heel veel apache instanties naast elkaar
zou kunnen gaan draaien zonder dat het geheugen volloopt.
-
Een aardige bijkomstigheid van het gebruik van apache als proxy is
dat deze ook alvast het domme werk kan doen, nl zelf de statische data uitserveren, zonder daar de php server mee te belasten.
-
Deze setup kan gebruikt worden voor het high-volume uitserveren
van statische websites. In dit geval zijn de proxies gewoon de eindpunten (ze proxyen zelf niks, omdat alles statische data is). Het schalen gaat hier door maar genoeg http proxies bij te schakelen. Stel dat er gekozen zou zijn voor een ongetrapt, simpeler alternatief, waarbij je de keepalived / DR loadbalancing gewoon niet zou doen (dwz direct aan de voorkant 1 proxy instantie, welke mbv keepalived in een master/slave config gedraaid wordt), dan zou dat prima werken voor groots php hosten, maar uiteindelijk zou je ene proxy server dan een choke point kunnen worden. Andersom, als de buitenkant een keepalived/DR loadbalancer zou zijn, die direct balanced over een aantal php nodes, dan heb je dus last van alle spoonfeeding issues zoals boven beschreven
-
De keepalived/DR loadbalancer kan meerdere IP adressen en meerdere
poorten aan. Dit kan bv gebruikt worden om op 1 website http en https verkeer vasn elkaar te scheiden, waarbij het https verkeer naar ssl enabled instanties gaat, terwijl voor http verkeer alle ssl overhead niet nodig is en deze dus door leaner and meaner instanties gedaan kan worden. Andersom kan het ook gebruikt worden om 1 shared loadbalancer neer te zetten, die gebruikt kan worden voor een aantal verschillende klanten/applicaties, die dan allemaal hun eigen webserver isntances hebben staan.
Naamgeving
Webservers leven altijd onder /e/fp.
De naam daaronder ziet eruit als xxxx[0-9][a-z], waarbij
de xxxx een tag is om aan te duiden van of voor wie deze
instantie is (bv een omroepnaam of een applicatienaam), daarna volgt een
cijfer, wat een volgnummer is. De N'e instance van klant xxxx.
Tenslotte volgt weer een letter om aan te geven dat iets geloadbalanced
is. Stel dat foo1 geloadbalanced zou worden over 3 instanties, dan zou
je deze onder /e/fp terugvinden als foo1a,
foo1b en foo1c.
Vaak zullen de a,b en c instanties onderling veel configuratie delen.
Om deze nu niet 3x te dupliceren is deze terug te vinden in een gedeelde
directory /e/fp/foo1 (dwz zonder volgletter).
Zowel de static proxies, als de php enabled servers zijn webservers en
leven dus beide onder /e/fp. Er is geen onderscheid in
naamgeving tussen proxies en php servers. In praktijk betekent dit vaak
dat een proxy en php server dezelfde prefix hebben (“foo”), maar een
ander volgnummertje (“foo1” tegenover “foo2”).
Het kan natuurlijk ook zo zijn dat 1 setje proxies (foo1[a-z])
loadbalanced over meerdere setjes php servers (foo2[a-z] voor
applicatie X en foo3[a-z] voor applicatie Y).
Wij streven ernaar om in het GECOS veld van de password file aan te
geven wat een webserver isntantie precies doet.
De user waar een webserver onder draait is z'n naam gevolgd door de
letters “fp”. B.v. foo1afp. En het adres waar die aan bindt
heeft meestal als DNS naam foo1afp.omroep.nl,
Shared vhost includes
de configuratie van apache virtual hosts leeft bij ons altijd in losse
.vhost files, welke door de webserver geinclude worden.
In een loadbalanced context moeten zowel de proxies als de php servers
weet hebben van de vhosts. Om nu niet alle informatie N maal te
dupliceren hebben we vsan elke vhost file slechts een kopie, die door
alle (proxies <em>en</em> php servers) webserver geinclude wordt.
In de vhost file wordt met Define's gespeeld om ervoor te zorgen dat
elke instantie alleen maar het stukje configuratie krijgt dat voor die
instantie van toepassing is.
Sessies
Niet alles is rozegeur en maneschijn, nl sessies zijn een probleem. Er is geen garantie dat een sessie altijd bij dezelfde php node terecht komt. Er zijn een aantal oplossingen:
-
route constructies gebruiken
We gaan er van uit dat sessie informatie in http cookies gestopt zit.
Als de cookies op een zodanige wijze gegenereerd kunnen worden dat het
duidelijk is door welke worker node dit gedaan is, dan zit er in de http
proxy functionaliteit om op basis van zo'n cookie het request naar de
juiste worker door te sturen.
Concreet betekent dat dat de cookiename statisch moet zijn (bv
PHPSESSIONID) en dat de waarde van de cookie eruit moet zien als
sessiadata.NODE_ID, waarbij het NODE_ID bepalend is voor naar
welke node een request doorgezet moet worden.
In een java tomcat context is dit tamelijk eenvoudig te doen door in de
tomcat server.xml een jvmRoute op te nemen:
<Engine name="Standalone" defaultHost="none" jvmRoute="NODE_x">
Dit zorgt ervoor dat er cookies JSESSIONID=sessiedata.NODE_x gezet worden. Vervolgens stellen we op de proxy in:
ProxyPass / balancer://cluster/ stickysession=JSESSIONID <Proxy balancer://cluster> BalancerMember http://node1 route=NODE_1 BalancerMember http://node2 route=NODE_2 BalancerMember http://node3 route=NODE_3 ... </Proxy>
En zo weet de proxy dat sessies met NODE_1 doorgestuurd moeten worden naar node1. Het probleem hierbij echter is dat dat bij php niet zo fijn werkt. Er is in php geen makkelijke manier (a la jvmRoute in tomcat) om php duidelijk te maken dat ie z'n sessie namen volgens een bepaalde syntax aan moet maken. Daarom hebben we een speciale truc verzonnen, waardoor door middel van een RewriteRule in de PHP-worker een cookie geset wordt (vaak iets als 'BALANCEID'), wat dan als stickysession gebruikt kan worden. Hierdoor komt uiteindelijk dan alsnog brafa elk request van 1 bezoeker op dezelfde PHP-worker terecht.
-
sessies in database opslaan
Aangezien de verschillende webserver nodes uiteindelijk weer aan dezelfde database refereren, kan de database goed gebruikt worden om sessie informatie in op te slaan.
-
sessies op het filesysteem opslaan
Dit zou in theorie kunnen, maar is in praktijk een slecht idee. De gedachte is dat de verschillende php nodes een shared filesysteem hebben. Dus, als node 1 op het filesysteem wat sessie info neerzet, dan kan node 2 dat weer oppikken. Probleem hierbij is dat we NFS gebruiken voor het filesysteem en dat NFS geen cache consistency biedt. Dat betekent dat op het moment dat node 1 iets weggeschreven heeft, dit niet meteen op node 2 bekend is.
-
sessies in memcache opslaan
We bieden inmiddels ook support voor memcache, een stukje geheugen dat op een eigen intern ip-adresje beschikbaar is voor alle php-workers.
Performancetips
-
statische content
Het komt natuurlijk best wel eens voor dat een site allemaal 'statische' content heeft staan onder /pages, en dan gaat het bovenstaande verhaal van de loadbalancing minder snel op. Daarom zorgen wij er standaard voor dat files met de extensies *.gif, *.html, *.htm, *.jpg, *.png, *.css, *.js, *.txt, *.swd, *.flv, *.xml, *.ico, *.pdf, *.gz, *.mp3 door de proxy uitgeserveerd worden. Hierbij is er wel een maar: het kan zijn dat een site speciale rewriterules heeft die botsen met deze constructie. In dat geval zullen we een custom oplossing moeten maken.
-
xml
Ook zien we vaak dat er XML gegenereerd wordt aan de hand van gegevens uit een database. Dat is natuurlijk helemaal geen probleem, maar wordt het vanzelf wel als 15.000 mensen tegelijkertijd diezelfde XML willen opvragen uit de database. Daarom adviseren wij om in dat geval de XML-file door middel van een cronjob, bijvoorbeeld elke minuut, te genereren en onder /data neer te laten zetten. Op deze manier wordt een vaak opgevraagde xml toch actueel gehouden, maar uitgeserveerd door de proxiende webserver. Dit scheelt heel erg in de performance.
-
caching
Er zijn nogal wat caching-mechanismes in omloop in de php-wereld; varierend van zelf bedachte dingen tot het gebruik van componenten als smarty en memcache. Wij supporten in ieder geval deze 2 mechanismes, en willen iedereen dan ook adviseren caching-vormen toe te passen op de applicaties.
Contactgegevens
-
NPO ICT, servicedesk@omroep.nl, tel 035-6773555.
-
Algemeen aanspreekpunt voor het beheer van de omgeving.
Dick Snippe, Dick.Snippe@tech.omroep.nl, Senior internetbeheerderGerwin Mast, Gerwin.Mast@omroep.nl, Teamleider Media-
Voor vragen mbt de opzet van de hosting omgeving.
-
- sterretje-cluster/cluster-hosting.1475745028.txt.gz
- Last modified: 2026/05/27 14:01
- (external edit)
