Volymer — data som överlever containern
Hoppa till
Var vi är
Nu pratar API:et med databasen, hälsotestet håller ordning på startordningen, och hela systemet går
igång med docker compose up. Lisa lägger in tvåhundra testprodukter och går hem för dagen.
Nästa morgon kör hon docker compose down och docker compose up igen. Databasen är tom.
Det är inte en bugg. Den här delen förklarar varför, och hur man gör i stället — sista byggstenen innan Docker sitter.
Var en container skriver
I delen om Dockerfile såg vi att varje instruktion skapar ett lager. Det som inte sades då är att
alla de lagren är skrivskyddade.
När containern startar lägger Docker ett tunt skrivbart lager överst. Allt applikationen ändrar eller skapar hamnar där: nya rader i databasen, loggfiler, uppladdade bilder.
Varför datan försvann
Det skrivbara lagret tillhör containern, inte imagen.
docker compose down tar bort containrarna, och med dem det skrivbara lagret. Imagen är kvar och
koden är kvar — men allt Postgres hunnit skriva är borta.
Det är samma egenskap som gör containrar användbara. En container ska vara utbytbar: går den sönder kastar du den och startar en ny från samma image. Med samma konfiguration, omgivning och externa beroenden kan den nya containern utföra samma uppgift som den gamla.
Den garantin håller bara om containern inte bär på något unikt. Data som ska överleva måste därför bo någon annanstans.
Vad en volym är
En volym är lagring som lever utanför containern och som Docker hanterar separat.
Du pekar ut en katalog inuti containern, och allt som skrivs dit hamnar i stället i volymen. Applikationen märker ingenting — den skriver till en helt vanlig sökväg.
/var/lib/postgresql/data, som vanligt.katalogen är monteradMonteringspunktenDocker har kopplat just den sökvägen till en volym i stället för till det skrivbara lagret.skriver igenomVolymen `shop_db_data`Lever kvar även när containern tas bort.Var volymen faktiskt ligger
Docker kan tala om var en volym bor:
docker volume inspect min-vol \
--format '{{.Mountpoint}}'
/var/lib/docker/volumes/min-vol/_data
Sökvägen ser ut som en vanlig katalog, och på en Linux-server är den det. På macOS och Windows
finns den inte. Docker kör där i en liten Linux-maskin, och sökvägen gäller inuti den. Försöker du cd dit får
du No such file or directory.
Det är inte ett fel. Det är att volymen medvetet är Dockers område, inte ditt filsystem. Vill du åt innehållet gör du det genom en container:
docker run --rm -v min-vol:/d alpine ls -la /d
Volym vs image-lager
Två sorters lagring i samma container, och de beter sig tvärtom.
Image-lagren är skrivskyddade och byggs in vid docker build. De är samma för alla containrar
som startas ur imagen, och de följer med när imagen delas.
Volymen är skrivbar och skapas vid körning. Den är unik för den miljö den ligger i, och den följer aldrig med imagen.
Det förklarar Lisas morgon exakt: koden låg i ett image-lager och fanns kvar, medan produkterna låg i det skrivbara lagret och försvann.
Sökvägssyntaxen
I Compose-filen är det två rader plus en deklaration:
services:
db:
image: postgres:17-alpine
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
Raden under volumes: i tjänsten läses källa:mål — volymen db_data monteras på sökvägen
/var/lib/postgresql/data inuti containern.
Blocket längst ner är obligatoriskt. En namngiven volym måste deklareras på toppnivå innan en tjänst får använda den, annars vägrar Compose starta.
Nu överlever produkterna både down och up.
Named volume vs bind mount
Två varianter, och valet handlar om vem som äger katalogen.
./backend:/app
En mapp på din dator monteras in i containern. Du ser filerna i din editor, och ändringar slår igenom direkt.
Perfekt under utveckling: spara i editorn, och appen laddar om utan ombyggnad.
Beroende av att sökvägen finns — och av vilket operativsystem du kör.
db_data:/var/lib/postgresql/data
Docker äger lagringen och lägger den på en plats du normalt inte rör.
Rätt val för databasfiler och annat applikationen själv producerar.
Fungerar likadant på Linux, macOS och Windows, och är snabbare på de två sistnämnda.
Du känner igen dem på källan: börjar den med . eller / är det en sökväg på din dator, alltså en
bind mount. Är det ett vanligt namn är det en named volume.
Tumregeln är kort: bind mount för kod du redigerar, named volume för data appen skapar.
Vem som äger filerna i en volym
En ny named volume är tom och ägs av root:
docker run --rm -v min-vol:/d alpine \
stat -c 'uid=%u gid=%g' /d
uid=0 gid=0
Så länge containern kör som root märks det inte. Kör den som en annan användare, vilket produktionsdelen rekommenderar, kan den inte skriva i volymen. Felet blir Permission denied på en katalog som ser helt tom och normal ut.
Officiella databasimages löser det åt dig genom att sätta rättigheterna vid start. Din egen applikation gör det inte, och då är det ditt jobb.
En bind mount beter sig dessutom olika på olika värdar. Uppmätt på Docker Desktop för Mac visas
en fil som ägs av uid 501 som uid=0 inuti containern, och en container som kör som node får
skriva. På en Linux-server går värdens uid rakt igenom, och då uppstår rättighetsproblemet på
riktigt.
Det är den vanligaste orsaken till “det fungerar på min dator” i just det här sammanhanget.
Anonyma volymer
En tredje variant du inte skapar med flit men kommer att stöta på.
Skriver du bara ett mål utan källa — - /app/node_modules — skapar Docker en anonym volym med
ett slumpat namn.
Vissa images gör samma sak åt dig. postgres deklarerar själv en volym för sin datakatalog, vilket
gör att data kan överleva även utan att du bett om det — i en volym med ett genererat namn.
En ny container kopplas inte automatiskt till den volymen. Du kan hitta den med docker volume ls,
men en named volume är tydligare när data ska återanvändas medvetet.
Det är därför docker volume ls visar poster med långa hash-namn som du aldrig skapat.
down vs down -v
En bokstavs skillnad, och den ena raderar data.
docker compose down tar bort containrarna och nätverket. Namngivna volymer behålls.
docker compose down -v tar bort volymerna också, utan att fråga.
-v är utmärkt i en testmiljö när du vill börja om från tomma bordet, och farligt i alla andra —
särskilt i ett skript som “städar” innan varje körning.
En bind mount kan gömma undan det som redan finns.
Monterar du ./backend:/app läggs din mapp ovanpå /app i containern. Katalogen node_modules
som byggdes in i imagen blir då osynlig, eftersom din mapp saknar den.
Symtomet är Cannot find module på något du uttryckligen installerade i Dockerfile. Vanligaste
lösningen är en anonym volym som skyddar just den katalogen:
volumes:
- ./backend:/app
- /app/node_modulesprune vs down -v
Två sätt att städa, med olika räckvidd — och det ena är betydligt trubbigare.
docker compose down -v tar bort volymerna som hör till det här projektet. Räckvidden är
mappen du står i.
docker volume prune tar bort alla volymer på maskinen som ingen container använder just
nu. Räckvidden är hela din dator.
Den andra är farlig av ett skäl som inte syns: en volym från ett projekt du inte rört på en månad räknas som oanvänd, eftersom dess containrar är borta. Testdatan du sparade i mars försvinner när du städar efter ett helt annat projekt.
Kör docker volume ls först. Kommandot frågar en gång och rapporterar bara hur många byte som
frigjordes.
En volym är inte en säkerhetskopia
En lokal Docker-volym ligger där Docker Engine lagrar data. Det är ofta samma maskin, men lagringsdrivrutinen kan använda annan lagring.
Volymen skyddar mot att containern tas bort. Den skyddar inte mot diskhaveri, felaktig radering eller
data som blivit trasig — och down -v raderar den utan papperskorg.
Ska databasen kunna återställas behöver du en riktig dump, pg_dump för Postgres, som lagras någon
annanstans än på samma maskin.
Vad det här betyder i ditt arbete
Du kommer att skriva bind mounts för källkod i varje utvecklingsuppsättning, och named volumes för varje databas. De två raderna återkommer i så gott som varje Compose-fil du möter.
Det du felsöker är oftare Cannot find module efter en bind mount, eller en databas som tömts av en
down -v i ett skript. Båda ser ut som mystiska fel och är i själva verket den här delens två
fallgropar.
Volymdrivrutiner, nätverkslagring och backup-rutiner blir dina den dag data ska överleva mer än din egen laptop. I Kubernetes heter samma idé PersistentVolume, och den bygger på exakt samma uppdelning.
Vanliga nybörjarförväxlingar
En container sparar inte data av sig själv. Det skrivbara lagret försvinner med containern.
En volym är inte en del av imagen. Imagen delas; volymen stannar där den skapades.
docker compose down raderar inte namngivna volymer. Det gör down -v.
En bind mount lägger sig ovanpå målkatalogen och kan dölja filer som byggdes in i imagen.
En volym är ingen säkerhetskopia. Den skyddar inte mot förlust av lagringen.
Volymer du aldrig skapat är ofta anonyma volymer som imagen själv deklarerat.
Prova själv
Det här körs i slängbara containrar och rör ingenting du har.
docker volume create testvol
docker run --rm -v testvol:/data busybox \
sh -c "echo hej > /data/fil.txt"
--rm tar bort containern direkt när den avslutats — den finns alltså inte kvar. Starta nu en helt
ny container mot samma volym:
docker run --rm -v testvol:/data \
busybox cat /data/fil.txt
Du får tillbaka hej. Filen skrevs av en container som inte längre existerar, och den överlevde
ändå. Titta sedan på volymen:
docker volume ls
docker volume inspect testvol
Städa efter dig när du är klar:
docker volume rm testvol
Tre saker som kan förvirra: docker volume inspect visar en Mountpoint som ser ut som en vanlig
sökväg, men på macOS och Windows finns den inte på din disk. Den ligger inuti den Linux-maskin
Docker Desktop kör i bakgrunden. docker volume ls visar dessutom volymer med långa hash-namn som du
aldrig skapat; det är anonyma volymer från images som postgres. Och docker volume rm vägrar så
länge någon container använder volymen, vilket är avsiktligt.
- Imagens lager är skrivskyddade. Containern får ett tunt skrivbart lager som försvinner med containern.
- En volym flyttar en katalog ut ur containerns livscykel, så data överlever
downochup. - Named volume för data applikationen skapar; bind mount för kod du redigerar.
- Källan avslöjar vilken sort det är: en sökväg är bind mount, ett namn är named volume.
- Namngivna volymer måste deklareras i
volumes:-blocket på toppnivå. downbehåller volymerna,down -vraderar dem. Utan varning.
Du kör docker compose down och sedan up. Koden finns kvar men databasen är tom. Varför?
build. Databasens innehåll skrevs till containerns skrivbara lager, som togs bort tillsammans med containern. Utan volym finns det ingenstans för datan att ta vägen.Vad är skillnaden mellan ett image-lager och en volym?
docker build och följer med när imagen delas. Volymen är skrivbar, skapas vid körning, är unik för miljön och följer aldrig med imagen.Hur ser du på en rad i Compose-filen om det är en bind mount eller en named volume?
. eller / är det en sökväg på din dator, alltså en bind mount. Är det ett vanligt namn är det en named volume som Docker äger.När ska du välja en bind mount framför en named volume?
Du monterar ./backend:/app och får plötsligt Cannot find module för ett paket du installerade i Dockerfile. Vad hände?
/app i containern och dolde node_modules som byggdes in i imagen. Lägg till en anonym volym för /app/node_modules så skyddas den katalogen från att skrivas över.Räcker en volym som säkerhetskopia av databasen?
Snabb sammanfattning
- Imagens lager är skrivskyddade. Containern får ett tunt skrivbart lager ovanpå.
- Det skrivbara lagret tillhör containern och raderas med den. Därför tömdes databasen.
- Att containrar inte bär på något unikt är avsiktligt — det är vad som gör dem utbytbara.
- En volym är lagring utanför containern, monterad på en sökväg inuti den.
- Applikationen märker ingen skillnad. Den skriver till en vanlig katalog.
- Volymen är skrivbar och stannar i miljön; image-lagret är skrivskyddat och följer med imagen.
- Syntaxen är
källa:mål, och namngivna volymer måste deklareras på toppnivå. - Named volume för data appen skapar, bind mount för kod du redigerar.
- Anonyma volymer skapas av mål utan källa — och av images som
postgrespå egen hand. downbehåller volymerna.down -vraderar dem utan att fråga.- En bind mount lägger sig ovanpå målkatalogen och kan dölja inbyggda filer.
- En volym är ingen säkerhetskopia. Den skyddar inte mot förlust av lagringen.
Nästa del
Därmed har du de fyra delarna: containern, imagen, nätverket och lagringen. Det räcker för att köra ett riktigt system på din egen maskin.
Innan det blir någon annans maskin återstår en sak. Del 1.1 sköt upp fyra djup med orden “när imagen ska till produktion” — och i nästa del tar vi dem: hur bygget delas i två steg, vad som egentligen startar i containern, och varför en tagg inte räcker när något måste gå att återskapa.