Om du vill kunna hantera webbapplikationer i utveckling och produktion på ett effektivt sätt måste du förstå miljövariabler.
Detta har inte alltid varit fallet. För bara några år sedan var det knappt någon som konfigurerade sina Rails-appar med hjälp av miljövariabler. Men sedan kom Heroku.
Heroku introducerade utvecklare till 12-faktors-app-strategin. I deras manifest för 12-faktorsappar beskriver de många av sina bästa metoder för att skapa appar som är lätta att distribuera. Avsnittet om miljövariabler har varit särskilt inflytelserikt.
Tolvfaktorsappen lagrar konfigurationen i miljövariabler (ofta förkortat env vars eller env). Env vars är lätta att ändra mellan distributioner utan att ändra någon kod; till skillnad från konfigurationsfiler finns det liten chans att de kontrolleras in i kodrepo av misstag; och till skillnad från anpassade konfigurationsfiler, eller andra konfigurationsmekanismer som Java System Properties, är de en språk- och OS-agnostisk standard.
Mer Rubyister använder miljövariabler än någonsin. Men ofta är det på ett kargo-felaktigt sätt. Vi använder dessa saker utan att riktigt förstå hur de fungerar.
Detta inlägg kommer att visa dig hur miljövariabler verkligen fungerar – och kanske ännu viktigare, hur de INTE fungerar. Vi kommer också att utforska några av de vanligaste sätten att hantera miljövariabler i dina Rails-appar. Nu sätter vi igång!
NOTAT: Du kan läsa om att säkra miljövariabler här.
- Varje process har sin egen uppsättning miljövariabler
- Miljövariabler dör med sin process
- En process får sina miljövariabler från sin förälder
- Föräldrar kan anpassa de miljövariabler som skickas till deras barn
- Barn kan inte ställa in sina föräldrars miljövariabler
- Förändringar i miljön synkroniseras inte mellan processer som körs
- Ditt skal är bara ett användargränssnitt för systemet med miljövariabler.
- Miljövariabler är INTE samma sak som skalvariabler
- Hantering av miljövariabler i praktiken
- Figaro
- Dotenv
- Secrets.yml?
- Plain old Linux
Varje process har sin egen uppsättning miljövariabler
Varje program du kör på din server har minst en process. Den processen får sin egen uppsättning miljövariabler. När den väl har dem kan ingenting utanför den processen ändra dem.
Ett förståeligt misstag som nybörjare gör är att tro att miljövariablerna på något sätt är servergemensamma. Tjänster som Heroku får det verkligen att se ut som om inställningen av miljövariablerna motsvarar att redigera en konfigurationsfil på disken. Men miljövariabler är inte alls som konfigurationsfiler.
Varje program du kör på din server får sin egen uppsättning miljövariabler i det ögonblick du startar det.
Varje process har sin egen miljö.
Miljövariabler dör med sin process
Har du någonsin ställt in en miljövariabel, startat om och upptäckt att den var borta? Eftersom miljövariabler tillhör processer betyder det att när processen avslutas försvinner din miljövariabel.
Du kan se detta genom att ställa in en miljövariabel i en IRB-session, stänga den och försöka komma åt variabeln i en andra irb-session.
När en process avslutas försvinner dess miljövariabler
Detta är samma princip som gör att du förlorar miljövariabler när servern startas om eller när du avslutar ditt skal. Om du vill att de ska bestå över sessioner måste du lagra dem i någon form av konfigurationsfil som .bashrc
.
En process får sina miljövariabler från sin förälder
Alla processer har en förälder. Det beror på att varje program måste startas av något annat program.
Om du använder ditt bash-skal för att starta vim är vims förälder skalet. Om din Rails-app använder imagemagick för att identifiera en bild så är identify
programmets förälder din Rails-app.
Barnprocesser ärver env vars från sin förälder
I exemplet nedan ställer jag in värdet på miljövariabeln $MARCO i min IRB-process. Sedan använder jag back-ticks för att skicka ut och eka värdet på variabeln.
Då IRB är överordnad process till skalet som jag just skapade, får den en kopia av miljövariabeln $MARCO.
Miljövariabler som sätts i Ruby ärvs av barnprocesser
Föräldrar kan anpassa de miljövariabler som skickas till deras barn
Som standard får ett barn kopior av alla miljövariabler som dess förälder har. Men föräldern har kontroll över detta.
Från kommandoraden kan du använda env-programmet. Och i bash finns det en speciell syntax för att ställa in env-vars på barnet utan att ställa in dem på föräldern.
Använd env-kommandot för att ställa in miljövariabler för ett barn utan att ställa in dem på föräldern
Om du shellar ut från Ruby kan du också ge anpassade miljövariabler till den underordnade processen utan att skräpa ner din ENV-hash. Använd bara följande syntax med metoden system
:
Hur man skickar anpassade miljövariabler till Rubys systemmetod
Barn kan inte ställa in sina föräldrars miljövariabler
Då barn bara får kopior av föräldrarnas miljövariabler har ändringar som görs av barnet ingen effekt på föräldern.
Miljövariabler ”överförs genom värde” inte ”genom referens”
Här använder vi back-tick-syntaxen för att shell out och försöka ställa in en miljövariabel. Variabeln kommer att ställas in för barnet, men det nya värdet bubblar inte upp till föräldern.
Barnprocesser kan inte ändra sina föräldrars env vars
Förändringar i miljön synkroniseras inte mellan processer som körs
I exemplet nedan kör jag två kopior av IRB sida vid sida. Att lägga till en variabel i miljön i den ena IRB-sessionen har ingen effekt på den andra IRB-sessionen.
Att lägga till en miljövariabel i en process ändrar inte den för andra processer
Ditt skal är bara ett användargränssnitt för systemet med miljövariabler.
Systemet i sig självt är en del av OS-kärnan. Det innebär att skalet inte har någon magisk makt över miljövariabler. Det måste följa samma regler som alla andra program du kör.
Miljövariabler är INTE samma sak som skalvariabler
Ett av de största missförstånden sker på grund av att skal tillhandahåller sina egna ”lokala” system för skalvariabler. Syntaxen för att använda lokala variabler är ofta densamma som för miljövariabler. Och nybörjare förväxlar ofta de två.
Men lokala variabler kopieras inte till barnen.
Miljövariabler är inte samma sak som skalvariabler
Låt oss ta en titt på ett exempel. Först sätter jag en lokal skalvariabel som heter MARCO. Eftersom detta är en lokal variabel kopieras den inte till några underprocesser. När jag försöker skriva ut den via Ruby fungerar det följaktligen inte.
Nästan använder jag kommandot export för att omvandla den lokala variabeln till en miljövariabel. Nu kopieras den till varje ny process som skalet skapar. Nu är miljövariabeln tillgänglig för Ruby.
Lokala variabler är inte tillgängliga för underordnade processer. Export konverterar den lokala variabeln till en miljövariabel.
Hantering av miljövariabler i praktiken
Hur fungerar allt detta i verkligheten? Låt oss ta ett exempel:
Antag att du har två Rails-program som körs på en enda dator. Du använder Honeybadger för att övervaka dessa appar för undantag. Men du har stött på ett problem.
Du vill lagra din Honeybadger API-nyckel i miljövariabeln $HONEYBADGER_API_KEY. Men dina två appar har två olika API-nycklar.
Hur kan en miljövariabel ha två olika värden?
Härmed hoppas jag att du vet svaret. Eftersom env-variabler är per process, och mina två rail-appar körs i olika processer finns det ingen anledning till varför de inte kan ha varsitt eget värde för $HONEYBADGER_API_KEY.
Nu är den enda frågan hur det ska ställas in. Lyckligtvis finns det några gems som gör detta riktigt enkelt.
Figaro
När du installerar Figaro-gemsen i din Rails-app kommer alla värden som du skriver in i config/application.yml att laddas in i ruby ENV hash vid start.
Du installerar bara gemsen:
# Gemfilegem "figaro"
Och börja lägga till objekt i application.yml. Det är mycket viktigt att du lägger till den här filen i din .gitignore, så att du inte av misstag begår dina hemligheter.
# config/application.ymlHONEYBADGER_API_KEY: 12345
Dotenv
Dotenv-gemen är mycket lik Figaro, förutom att den laddar in miljövariabler från .env, och den använder inte YAML.
Installera bara pärlan:
# Gemfilegem 'dotenv-rails'
Och lägg till dina konfigurationsvärden i .env – och se till att du git ignorerar filen så att du inte av misstag publicerar den på github.
HONEYBADGER_API_KEY=12345
Du kan sedan komma åt värdena i din Ruby ENV hash
ENV
Du kan också köra kommandon i skalet med din fördefinierade uppsättning env-vars så här:
dotenv ./my_script.sh
Secrets.yml?
Ledsen. Secrets.yml – även om det är coolt – ställer inte in miljövariabler. Så det är inte riktigt en ersättning för pärlor som Figaro och dotenv.
Plain old Linux
Det är också möjligt att upprätthålla unika uppsättningar av miljövariabler per app med hjälp av grundläggande Linuxkommandon. Ett tillvägagångssätt är att låta varje app som körs på din server ägas av en annan användare. Du kan sedan använda användarens .bashrc för att lagra applikationsspecifika värden.