Script får V2's skygge-server på benene igen efter nedbrud

29. august 2019 kl. 05:086
Script får V2's skygge-server på benene igen efter nedbrud
Illustration: Version2.
Et script gør det muligt at gendanne Version2's skygge-server i skyen, hvis uheldet skulle være ude.
Artiklen er ældre end 30 dage
Manglende links i teksten kan sandsynligvis findes i bunden af artiklen.

En sky-server er en nem og billig måde at sætte en lille tjeneste i luften, især for os, der gør det i skygge-it og hjemmestrikkede løsninger.

Men ligesom alle andre slags computere kan serveren stå af. Vores server-instans hører hjemme hos Amazon, og hvis disk eller hukommelse går i stykker i datacenteret i Virginia på USA’s østkyst, er det hele væk.

Amazon stiller en ny instans til rådighed, hvis uheldet er ude, men den nye instans er ganske tom til at starte med, og jeg får også et nyt IP-nummer i den anledning.

Det tager tid at sætte det hele mekanikken op igen med håndarbejde. Og den tid har jeg måske ikke, den dag, hvor alt bare går galt i skyen.

Artiklen fortsætter efter annoncen

Løsningen er at skrive et script, som kan udrulle systemet i en ruf. Webtjenesten gemmer ikke noget på disk, så der er ingen behov for backup.

Hemmelige passwords

I sidste episode af denne fortælling løste vi problemet med Let’s Encrypt’s kortlivede SSL-certifikater, der skal fornyes hver tredje måned. Og det gik helt fint.

Vores problem består denne gang i at udrulle hele baduljen på frisk, blank sky. Kronologisk ser det således ud:

Vi har scripts liggende lokalt. Vi afvikler et lokal script, der beder os om passwordet til root i skyen - altså sky-serverens administrator-password. Det script kopierer en række scripts over på sky-serveren, samt webtjeneste-programmet.

Artiklen fortsætter efter annoncen

Dernæst afvikler vi - fra den lokale terminal - to scripts, der sætter det hele op på sky-serveren. Det første skal køre som root - administrator - på sky-serveren. Det andet skal kører som den almindelige bruger, der hedder ‘ec2-user.’

Det første, lokale script, ser ud som herunder. Vores linjer er lidt lange, og da Version2-cms’ets kodeformatering ikke har en rulleskakt - det er skrevet i backloggen - har vi knækket linjerne med backslash \, som i bash betyder: Kommandoen fortsætter på næste linje.

  1. # Udruller sky-app. Afvikles lokalt.
  2. # Indlæs password til skyen.
  3. echo -n Password:
  4. read -s PASSWORD
  5. HOST=ec2-user@ec2-18-223-114-109.us-east-2.compute.amazonaws.com
  6. WEBTJ_LOKAL=/mnt/c/Users/tan/Documents/webtjeneste
  7. WEBTJ_FJERN=/home/ec2-user/webtjeneste
  8. # Kopier udrul-script 1 og 2 til skyen.
  9. scp -i TaniasAWSNoegler.pem udrul-sky-1.sh $HOST:/home/ec2-user
  10. scp -i TaniasAWSNoegler.pem udrul-sky-2.sh $HOST:/home/ec2-user
  11. # Kopier webtjeneste til skyen.
  12. scp -i TaniasAWSNoegler.pem -r $WEBTJ_LOKAL $HOST:$WEBTJ_FJERN
  13. # Kopier script til certifikat-fornyelse til sky.
  14. scp -i TaniasAWSNoegler.pem cert-forny.sh $HOST:/home/ec2-user
  15. # Kopier script til start af webtjeneste til sky.
  16. scp -i TaniasAWSNoegler.pem genstart-tjeneste.sh \
  17. $HOST:/home/ec2-user
  18. # Gør scripts eksekverbare.
  19. ssh -i TaniasAWSNoegler.pem \
  20. ec2-user@ec2-18-223-114-109.us-east-2.compute.amazonaws.com 'echo \
  21. $PASSWORD | sudo chmod +x udrul-sky-1.sh'
  22. ssh -i TaniasAWSNoegler.pem \
  23. ec2-user@ec2-18-223-114-109.us-east-2.compute.amazonaws.com 'echo \
  24. $PASSWORD | sudo chmod +x udrul-sky-2.sh'
  25. # Kør udrul-sky-1.sh i skyen som root.
  26. ssh -i TaniasAWSNoegler.pem \
  27. ec2-user@ec2-18-223-114-109.us-east-2.compute.amazonaws.com 'echo \
  28. $PASSWORD | sudo -S /home/ec2-user/udrul-sky-1.sh'
  29. # Kør udrul-sky-2.sh i skyen som alm. bruger (ec2-user).
  30. ssh -i TaniasAWSNoegler.pem \
  31. ec2-user@ec2-18-223-114-109.us-east-2.compute.amazonaws.com \
  32. '/home/ec2-user/udrul-sky-2.sh'

Vi skal bruge root-passwordet til skyen, som jo giver administrator-adgang, og vi vil ikke have, at det ryger ned i bash’ history, der gemmer alle kommandoer.

Linjen read -s PASSWORD gør, at passwordet indlæses fra terminalen uden at skrive noget, ligesom når man anvender sudo-kommandoen. Det gemmes i variablen PASSWORD.

Vi starter med at kopiere vores to udrulnings-scripts over på sky-serveren med scp, der tager vores Amazon-nøgler som argument.

Så kopierer vi webtjeneste-programmet over, samt de to scripts, der henholdsvis fornyer certifikater og starter eller genstarter webtjenesten.

Nu skal vi gøre vores scripts eksekverbare på sky-serveren, og her skal vi bruge vores PASSWORD-variabel fra tidligere. Det er denne linje, det drejer sig om:

  1. # Gør scripts eksekverbart.
  2. ssh -i TaniasAWSNoegler.pem $HOST 'echo $PASSWORD | sudo chmod +x \
  3. udrul-sky-1.sh'

HOST-variablen satte vi øverst i scriptet, og nu udfører vi denne kommando på sky-serveren, som står inde mellem de to anførselstegn:

  1. echo $PASSWORD | sudo chmod +x udrul-sky-1.sh

Sudo-kommandoen vil efterspørge et password, og den klarer vi ved at skrive vores password med echo, og ‘pipe’ det over i sudo-kommandoen. Det gør det samme, som hvis jeg var logget ind på sky-serveren og skrev kommandoen i hånden. Passwordet bliver på denne måde heller ikke skrevet i en history-fil, hverken på sky eller lokalt, og når scriptet er afviklet, er variablen væk.

Spørgelystne kommandoer tier stille

Vi gør det samme med de to udrulnings-scripts udrul-sky-1 og 2, og etteren afvikler vi på skyen som root, og toeren som skyens almindelige bruger ec2-user.

  1. # Køres som root på sky-serveren.
  2. # Installer Java 11.
  3. curl -L \
  4. https://d3pxv6yz143wms.cloudfront.net/11.0.4.11.1/java-11-amazon-corretto-devel-11.0.4.11-1.x86_64.rpm \
  5. -o /tmp/java-11-amazon-corretto-devel-11.0.4.11-1.x86_64.rpm
  6. yum localinstall \
  7. /tmp/java-11-amazon-corretto-devel-11.0.4.11-1.x86_64.rpm -y
  8. # Installer Let’s Encrypt certbot-auto.
  9. wget https://dl.eff.org/certbot-auto
  10. mv certbot-auto /usr/local/bin/certbot-auto
  11. chown root /usr/local/bin/certbot-auto
  12. chmod 0755 /usr/local/bin/certbot-auto
  13. # Skab certifikater.
  14. /usr/local/bin/certbot-auto certonly --standalone --no-bootstrap \
  15. --preferred-challenges http -d v2emneord.ddnsfree.com \
  16. --non-interactive --agree-tos -m tan@ing.dk
  17. # Opsæt et cronjob som root, der fornyer certifikater hver
  18. # søndag kl. 00.00.
  19. echo "0 0 * * 0 /home/ec2-user/cert-forny.sh >> \
  20. /home/ec2-user/forny.log 2>&1" > cronfil
  21. crontab cronfil
  22. rm cronfil
  23. # Lav swapspace
  24. dd if=/dev/zero of=/swapspace bs=1M count=2000
  25. chmod 600 /swapspace
  26. mkswap /swapspace
  27. swapon /swapspace
  28. # Gør scripts eksekverbare.
  29. chmod +x /home/ec2-user/genstart-tjeneste.sh
  30. chmod +x /home/ec2-user/cert-forny.sh

Først installerer vi Java, og her benytter vi Amazons udgave af Java 11. Dernæst installerer vi Let’s Encrypts certbot-program, der skaber og fornyer SSL-certifikater. Hernæst opsætter vi et cronjob, der fornyer certifikaterne. Så skaber vi swapspace, da vores webtjeneste er lidt underforsynet med hukommelse, og til sidst gør vi de to scripts, der genstarter tjenesten og fornyer certifikater, eksekverbare.

Artiklen fortsætter efter annoncen

Alt i alt er det blot det samme, som vi gjorde i en tidligere artikel, men hvor nogle af kommandoerne er i udgaver, der ikke stiller spørgsmål undervejs, som vi også så det i sidste episode.

Når udrul-sky-1 er afviklet, er der kun en lille opgave tilbage. Det er at opsætte en cronjob, der genstarter tjenesten, efter at certifikatet er fornyet. Til allersidst starter vi tjenesten med scriptet genstart-tjeneste.sh. Det lille script, udrul-sky-2, ser sådan ud:

  1. # Køres som alm. bruger (ec2-user). Opsætter cronjob, der
  2. # genstarter tjenesten efter certifikat-fornyelse, og starter
  3. # tjenesten.
  4. echo "15 0 * * 0 /home/ec2-user/genstart-tjeneste.sh >> \
  5. /home/ec2-user/genstart.log 2>&1" > cronfil
  6. crontab cronfil
  7. rm cronfil
  8. /home/ec2-user/genstart-tjeneste.sh > genstart.log

Så er vi parat til den dag, hvor serveren brænder sammen eller ondskabsfulde typer hacker systemet.

Alt er godt - sådan da. For jeg vil også gerne flytte Version2’s job-robot over på serveren. Den moderne og gnidningsfri måde at gøre det på er med containere. Det kigger vi nærmere på i løbet af efteråret, så bliv på kanalen.

6 kommentarer.  Hop til debatten
Denne artikel er gratis...

...men det er dyrt at lave god journalistik. Derfor beder vi dig overveje at tegne abonnement på Version2.

Digitaliseringen buldrer derudaf, og it-folkene tegner fremtidens Danmark. Derfor er det vigtigere end nogensinde med et kvalificeret bud på, hvordan it bedst kan være med til at udvikle det danske samfund og erhvervsliv.

Og der har aldrig været mere akut brug for en kritisk vagthund, der råber op, når der tages forkerte it-beslutninger.

Den rolle har Version2 indtaget siden 2006 - og det bliver vi ved med.

Debatten
Log ind eller opret en bruger for at deltage i debatten.
settingsDebatindstillinger
7
31. august 2019 kl. 11:00

Udover alternativerne som er nævnt i andre kommentarer (Puppet, Ansible, osv.), kunne det også gøres med AWS services såsom CloudFormation. Dog er alle disse måske en anelse komplekse, hvis man ikke er erfaren udvikler, og bare skal have noget i luften ASAP.

Et lettere alternativ vil være EC2 user data scripts (hvis altså det er ligemeget at have en cross-cloud løsning):

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html

Ikke den bedste løsning, men den er til at forholde sig til, hvis man skal have noget kørende til små hobby projekter eller lignende. ?

5
29. august 2019 kl. 12:30

Jeg har skrevet det til tidligere indlæg om dette emne, men here goes again: brug en smartere webserver :-)

Caddy har super simpel konfigurationsfil, håndterer LetsEncrypt automatisk, og har alle de features du har behov for. Sæt den ind som en reverse proxy foran din Java applikation, og så slipper du for alt bøvlet med cronjob, Java keystore og så videre.

Hvis du vil lege med Docker til applikationen, kunne det være værd at kigge på Traefik – nok lidt overkill til emneords servicen, men det er et interessant projekt.

Og så i øvrigt +1 til forslagene om at du kigger på Puppet, Ansible (eller Chef eller...) til automatisering fremfor håndrullede scripts.

4
29. august 2019 kl. 12:14

Kort opsummering:

ansible er "avanceret scripting".. det er bygget til at være modulært - så man kan genbruge komponenter og "deles om opgaven " - så man får langt mere robust automatisering.. https://www.ansible.com/overview/how-ansible-works

Ovenstående scripting er hvad man gjorde "for mange mange år siden" - idag bør man benytte det man kalder system configuration værktøjer.. Puppet, Ansible, Terraform etc.. - netop fordi man så kan samarbejde om udfordringerne vha. moduler og dermed øge hastigheden og kvaliteten samtidigt.

Disse værktøjer bruges til VMs og fysiske maskiner.

Docker er bygget til at man bygger et image én gang (vha. en Dockerfile) - og så kan man føde med med en sti (volume) der mountes ind i imaget når servicen startes og man kan give den environment variable som koden inden i docker imaget kan bruge til at ændre hvordan den kører. Så har man altså alt det man skal bruge i en "statisk skal" - som derfor kan køre med f.ex. "Ubuntu-18.04 versioner af softwaren" - uanset hvilken VM eller fysisk server det kører på.

Docker er hvad man bruger i Kubernetes miljøer, hvor man så kan kombinere flere docker images (f.ex. nginx + phpfpm docker images) til at køre ens kode (hvor kubernetes sørger for at skalere op/ned og flytte rundt i tilfælde af servere der dør).

3
29. august 2019 kl. 12:09

... vil jeg lige anbefale den sudo-linie, der hedder

/etc/sudoers: %sshkeyonly ALL=(ALL) NOPASSWD: ALL

Den betyder, at hvis man logger ind på serveren med ssh-key (og det gør du jo), så bliver der ikke spurgt om password for sudo.

2
29. august 2019 kl. 11:30

Hej Thomas,

Det har jeg aldrig hørt om - jeg er jo blot en devops-nybegynder. Kan du fortælle, hvordan det er i forhold til Docker?

Mvh Tania/V2

1
29. august 2019 kl. 10:55

Det lyder som en perfekt opgave for Ansible? så måske en artikel om den fremgangsmåde, og evt. forskellene/værdien af det? Inden docker-løsningen kommer på banen.