డేటాబేస్ Docker లో నడపాలా లేదా హోస్ట్ మెషీన్ లోనా?
Postgres, MySQL, MongoDB వంటి డేటాబేస్లను Docker కంటైనర్లలో నడపడం సురక్షితమేనా? వాల్యూమ్స్, వెర్షన్ అప్గ్రేడ్లు మరియు బ్యాకప్ నిర్వహణలో తీసుకోవాల్సిన జాగ్రత్తల గురించి తెలుసుకోండి.
డేటాబేస్ Docker లో నడపాలా లేదా హోస్ట్ (host) పై నడపాలా?
డేటాబేస్ను Docker లోనే నడపండి. ఒక VPS పై ఒక అప్లికేషన్ స్టాక్ కోసం, కంటైనరైజ్డ్ PostgreSQL, MySQL, MongoDB లేదా Redis వాడటం సాధారణ ప్రొడక్షన్ ఎంపిక. దీనిపై జరిగే వాదనలు సాధారణంగా తప్పుదోవ పట్టిస్తాయి. కంటైనర్ అనేది Linux ప్రాసెస్ మాత్రమే, దీని చుట్టూ namespaces మరియు cgroups ఉంటాయి; ఇది వర్చువల్ మెషీన్ కాదు, కాబట్టి డేటాబేస్కు మరియు డిస్క్కు మధ్య ఎటువంటి hypervisor ఉండదు. Bind mount లేదా local named volume వాడినప్పుడు, రీడ్ మరియు రైట్ ఆపరేషన్లు నేరుగా హోస్ట్ ఫైల్సిస్టమ్పైనే జరుగుతాయి, ఇది ప్యాకేజీ ఇన్స్టాలేషన్ వాడే పద్ధతికి సమానం.
నిజమైన సవాలు నిర్వహణకు సంబంధించినది. ఈ సెటప్ బాగుంటుందా లేదా విపత్తుగా మారుతుందా అనేది నాలుగు అంశాలపై ఆధారపడి ఉంటుంది: డేటా ఎక్కడ నిల్వ చేయబడింది, ఆ డైరెక్టరీకి యజమాని ఎవరు, మేజర్ వెర్షన్ అప్గ్రేడ్ ప్రక్రియ ఎలా ఉంటుంది, మరియు మీరు ఎప్పుడైనా బ్యాకప్ను రీస్టోర్ చేశారా? వీటిని సరిగ్గా నిర్వహిస్తే, కంటైనర్ అనేది ఒక చిన్న విషయం మాత్రమే. వీటిని విస్మరిస్తే, మీరు కంటైనర్నే నిందించాల్సి వస్తుంది.
ఏ సర్వర్ డేటాబేస్ కైనా ఇదే నిర్ణయం వర్తిస్తుంది. కింద ఉన్న ఉదాహరణలు PostgreSQL, MySQL, MongoDB మరియు Redis లపై ఆధారపడి ఉంటాయి. ఉత్పత్తికి సంబంధించిన ప్రత్యేక వ్యత్యాసాలు అవసరమైన చోట పేర్కొనబడ్డాయి.
కంటైనర్ వాస్తవానికి దేనిని మారుస్తుంది
మీరు ఒక స్టోరేజ్ పాత్ను మౌంట్ చేసినంత వరకు, అది మారదు. ఒకే కెర్నల్, ఒకే పేజీ కాష్, ఒకే ఫైల్సిస్టమ్ ఉంటాయి.
ఇక్కడ ఒక ముఖ్యమైన పనితీరు సమస్య ఉంది, అదే మీరు దేనినీ మౌంట్ చేయని సందర్భం. వాల్యూమ్ లేకపోతే, డేటా డైరెక్టరీ కంటైనర్ యొక్క రైటబుల్ లేయర్లోకి వెళ్తుంది, ఇది ఇమేజ్ పైన అమర్చబడిన ఒక overlay ఫైల్సిస్టమ్. అక్కడ జరిగే రైట్ ఆపరేషన్లు నెమ్మదిగా ఉంటాయి, మరియు కంటైనర్ను తొలగించినప్పుడు ఆ లేయర్ మొత్తం తొలగించబడుతుంది. "ఈ రోజు ఉదయానికి నా డేటాబేస్ ఖాళీగా ఉంది" అనే సమస్యకు ఇదే కారణం.
వాస్తవానికి మారేవి ఇవే:
- లైఫ్ సైకిల్.
docker compose downకంటైనర్ను నాశనం చేస్తుంది. వాల్యూమ్లో లేని ఏదైనా దానితో పాటే పోతుంది. - వెర్షన్. ఇమేజ్ ట్యాగ్ అనేది వెర్షన్ను సూచిస్తుంది. డేటాబేస్ కంటైనర్ లోపల ఎటువంటి
apt upgradeఉండదు, అది తదుపరిdocker compose pullవరకు నిలవదు. - మెమరీ అకౌంటింగ్. cgroup పరిమితి అనేది కెర్నల్ ద్వారా విధించబడే ఒక కఠినమైన గోడ, ఇది అక్కడ ఉందని డేటాబేస్కు తెలియదు.
- యూజర్. ప్రాసెస్ కంటైనర్ లోపల ఒక సంఖ్యాపరమైన యూజర్ ఐడి (numeric user id) గా నడుస్తుంది, దీనికి మీ హోస్ట్ మెషీన్పై ఎటువంటి యాజమాన్యం ఉండకపోవచ్చు.
డేటా ఎక్కడ నిల్వ చేయాలనేదే అన్నింటినీ నిర్ణయిస్తుంది
దీనికి రెండు మంచి మార్గాలు ఉన్నాయి మరియు ఒక సాధారణ పొరపాటు ఉంది.
- Named volume:
pgdata:/var/lib/postgresql/data. Docker ఈ డైరెక్టరీని/var/lib/docker/volumes/<project>_pgdata/_dataవద్ద సృష్టిస్తుంది, మరియు మొదటిసారి రన్ చేసినప్పుడు image entrypoint దీనికి యాజమాన్య హక్కులను (ownership) సెట్ చేస్తుంది. ఇదే డిఫాల్ట్ పద్ధతి. - Bind mount:
/srv/appname/pg:/var/lib/postgresql/data. పాత్ను మీరే ఎంచుకుంటారు కాబట్టి, పర్మిషన్ల సమస్యలను మీరే పరిష్కరించుకోవాలి. - మౌంట్ ఏదీ లేకపోవడం. పైన పేర్కొన్నది చూడండి. డేటా కంటైనర్ లోపలే ఉంటుంది.
దీనిలోని పూర్తి లాభనష్టాలు ఒక ప్రత్యేక అంశం, మరియు bind mounts మరియు named volumes మధ్య వ్యత్యాసం దీనిని వివరిస్తుంది. డేటాబేస్ కోసం క్లుప్తంగా చెప్పాలంటే: హోస్ట్ పాత్ గురించి మీకు ప్రత్యేక కారణం ఉంటే తప్ప named volume నే వాడండి. ఒకవేళ bind mount వాడాల్సి వస్తే, దానిని git clean అందుకోగల ప్రాజెక్ట్ డైరెక్టరీలో కాకుండా, /srv/appname/pg వంటి స్థిరమైన ప్రదేశంలో ఉంచండి.
ఒక కఠినమైన పరిమితి: డేటాబేస్ డేటా డైరెక్టరీని NFS (network file system) పై లేదా లాకింగ్ మరియు fsync ప్రవర్తనను మీరు పరీక్షించని ఏ నెట్వర్క్ మౌంట్పైన ఉంచవద్దు. ఒక విజయవంతమైన fsync అంటే డేటా స్థిరమైన స్టోరేజ్లో భద్రపరచబడిందని డేటాబేస్లు భావిస్తాయి. ఆ అంచనా తప్పైనప్పుడు, కొన్ని వారాల తర్వాత డేటా కరప్షన్ సమస్యలు బయటపడతాయి.
వాల్యూమ్ కనిపించకుండా పోకముందే దాని పేరును స్థిరపరచండి (Pin)
Compose ఒక వాల్యూమ్కు <project>_<volume> అని పేరు పెడుతుంది, మరియు ప్రాజెక్ట్ పేరు డిఫాల్ట్గా డైరెక్టరీ పేరును తీసుకుంటుంది. కాబట్టి వాల్యూమ్ గుర్తింపు అనేది డైరెక్టరీ పేరుపై ఆధారపడి ఉంటుంది, దీనిని ఎవరైనా ఆలోచించకుండా మార్చే అవకాశం ఉంది.
మీరు /srv/app ను /srv/app-old కి తరలించినా, లేదా compose ఫైల్లోని pgdata కీని పేరు మార్చినా, తదుపరి docker compose up -d కమాండ్ సరికొత్త ఖాళీ వాల్యూమ్ను సృష్టిస్తుంది. Postgres అందులో కొత్త క్లస్టర్ను ప్రారంభిస్తుంది. కంటైనర్ హెల్తీగా ఉంటుంది, అప్లికేషన్ ప్రారంభమవుతుంది, కానీ పాత టేబుల్స్ అన్నీ పోతాయి. పాత వాల్యూమ్ పాత పేరుతో డిస్క్లోనే ఉండటం ఒక మంచి విషయం.
docker volume ls
docker volume inspect app_pgdataఇలా జరగకుండా ఉండటానికి పేర్లను స్థిరపరచండి. ప్రాజెక్ట్ పేరును మరియు వాల్యూమ్ పేరును స్పష్టంగా సెట్ చేయండి:
name: myapp
services:
db:
image: postgres:17
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
name: myapp_pgdataఒకవేళ మీ డేటా ఇప్పటికే వేరే వాల్యూమ్లో ఉంటే, డేటాబేస్ను ఆపివేసి దానిని కాపీ చేయండి:
docker compose stop db
docker run --rm -v app_pgdata:/from -v myapp_pgdata:/to alpine sh -c 'cp -a /from/. /to/'
docker compose start dbడేటాబేస్ రన్ అవుతున్నప్పుడు కాపీ చేస్తే, అప్పటికే రాయబడుతున్న ఫైల్స్ పాడైపోయే (torn copy) అవకాశం ఉంది. కాబట్టి ముందుగా దానిని ఆపివేయండి.
డేటా డైరెక్టరీకి యజమాని ఎవరు
అధికారిక Postgres, MySQL మరియు MongoDB ఇమేజ్లు వాటి సర్వర్ను సాధారణంగా 999 అనే unprivileged user idతో నడుపుతాయి. కంటైనర్ rootగా ప్రారంభమైనప్పుడు, entrypoint ఆ డేటా డైరెక్టరీ యాజమాన్యాన్ని ఆ యూజర్కు మారుస్తుంది, ఆపై privilegesను వదులుకుంటుంది. అందుకే ఖాళీ bind mount సాధారణంగా మొదటి ప్రయత్నంలోనే పనిచేస్తుంది.
మీరు compose ఫైల్లో user: సెట్ చేసిన క్షణమే ఇది విఫలమవుతుంది, ఎందుకంటే అప్పుడు entrypointకు దేనినైనా సరిచేయడానికి ఎటువంటి privilege ఉండదు. Postgres దీనిని నేరుగా ఇలా చెబుతుంది:
initdb: error: could not change permissions of directory "/var/lib/postgresql/data": Operation not permittedతప్పు modeతో ఉన్న డేటా డైరెక్టరీ వేరే సందేశాన్ని ఇస్తుంది, మరియు ఈ సమస్యను గుర్తించడం ముఖ్యం ఎందుకంటే దీనికి పరిష్కారం chmod, chown కాదు:
FATAL: data directory "/var/lib/postgresql/data" has invalid permissions
DETAIL: Permissions should be u=rwx (0700) or u=rwx,g=rx (0750).root యాజమాన్యంలో ఉన్న bind mountపై MongoDB లాక్ ఫైల్ వద్ద విఫలమవుతుంది:
Unable to create/open the lock file: /data/db/mongod.lock (Permission denied). Ensure the user executing mongod is the owner of the lock file and has the appropriate permissions.దీనికి పరిష్కారం హోస్ట్ డైరెక్టరీని పేరుకు కాకుండా, numeric idకి chown చేయడం:
sudo chown -R 999:999 /srv/appname/pg
sudo chmod 700 /srv/appname/pg
ls -ldn /srv/appname/pgls -ldn పేర్లకు బదులుగా సంఖ్యలను ప్రింట్ చేస్తుంది, మరియు అది 999 999ని చూపాలి. మీ హోస్ట్లోని postgres అనే ఖాతా మరియు ఇమేజ్ లోపల ఉన్న postgres అనే ఖాతాకు సంబంధం లేదు: kernel సంఖ్యలను పోల్చి చూస్తుంది, మరియు పేర్లు ప్రతి వైపు విడిగా వెతకబడతాయి. PUID మరియు PGID హోస్ట్ యూజర్లను కంటైనర్లోకి ఎలా మ్యాప్ చేస్తాయి అనే అంశం ఈ మ్యాపింగ్ను వివరంగా వివరిస్తుంది. Rootless Docker లేదా user namespace remapping కింద సంఖ్యలు మళ్ళీ మారతాయి, కాబట్టి 999 అని ఊహించుకునే బదులు నడుస్తున్న కంటైనర్ నుండి idsను చదవండి.
Named volumes వాడినప్పుడు ఈ విభాగం మొత్తం మొదటి రన్లోనే అవసరం లేకుండా పోతుంది, ఎందుకంటే Docker ఒక ఖాళీ డైరెక్టరీని సృష్టిస్తుంది మరియు entrypoint దానికి యజమానిగా మారుతుంది.
అప్గ్రేడ్లు: ఇమేజ్ ట్యాగ్ మార్పు ద్వారా ప్యాకేజీ అప్గ్రేడ్
హోస్ట్లో, apt upgrade మిమ్మల్ని మైనర్ వెర్షన్ అప్గ్రేడ్కు తీసుకెళ్తుంది. మీ డిస్ట్రిబ్యూషన్ మీ అనుమతి లేకుండా డేటాబేస్ మేజర్ వెర్షన్ను మార్చదు. మీరు మేజర్ వెర్షన్ మార్చాలని నిర్ణయించుకున్నప్పుడు, రెండు రకాల బైనరీలను ఒకేసారి ఇన్స్టాల్ చేయవచ్చు; pg_upgrade కు ఇదే అవసరం.
కంటైనర్లో ట్యాగ్ అంటేనే వెర్షన్, కాబట్టి అప్గ్రేడ్ చేయడం అంటే ఒక లైన్ను ఎడిట్ చేయడం మాత్రమే. దీనివల్ల మైనర్ అప్గ్రేడ్లు చాలా సులభం అవుతాయి, కానీ మేజర్ అప్గ్రేడ్లు ఒక ప్రత్యేక ప్రక్రియగా మారుతాయి.
postgres:16 ను postgres:17 కి మార్చి, docker compose up -d రన్ చేయండి. అప్పుడు కంటైనర్ వెంటనే ఆగిపోతుంది:
PostgreSQL Database directory appears to contain a database; Skipping initialization
FATAL: database files are incompatible with server
DETAIL: The data directory was initialized by PostgreSQL version 16, which is not compatible with this version 17.ఏమీ పాడవదు. కొత్త బైనరీలు పాత ఆన్-డిస్క్ క్యాటలాగ్ లేఅవుట్ను చదవడానికి నిరాకరిస్తాయి, ఎందుకంటే మేజర్ వెర్షన్ల మధ్య అది మారుతుంది. ట్యాగ్ను తిరిగి postgres:16 కి మారిస్తే అది మళ్ళీ ప్రారంభమవుతుంది. కంటైనర్లు ఇచ్చే నిజమైన అప్గ్రేడ్ ప్రయోజనం ఇదే: సులభమైన రోల్బ్యాక్.
అధికారికంగా సిఫార్సు చేయబడిన మార్గం dump మరియు restore. కొత్త క్లయింట్ ద్వారా dump తీసుకోవడం PostgreSQL కు ఇష్టం, కాబట్టి కంపోజ్ నెట్వర్క్లో ఇంకా నడుస్తున్న పాత సర్వర్పై కొత్త ఇమేజ్ నుండి దీన్ని రన్ చేయండి:
docker run --rm --network myapp_default -e PGPASSWORD="$POSTGRES_PASSWORD" \
postgres:17 pg_dumpall -h db -U postgres > /srv/backups/all.sql
ls -lh /srv/backups/all.sql
tail -n 2 /srv/backups/all.sqlఫైల్ కనీసం పదుల కొద్దీ కిలోబైట్ల పరిమాణంలో ఉండాలి మరియు చివరి లైన్ PostgreSQL database cluster dump complete అని ఉండాలి. కొన్ని వందల బైట్ల ఫైల్ ఉంటే, dump విఫలమైందని అర్థం; అప్పుడు వాల్యూమ్ను డిలీట్ చేస్తే డేటా పోతుంది. ఆ తనిఖీ తర్వాత మాత్రమే:
docker compose down
docker volume rm myapp_pgdata
# edit the compose file: image: postgres:17
docker compose up -d db
docker compose exec -T db psql -U postgres -f /dev/stdin < /srv/backups/all.sqlఇతర ఇంజిన్ల పరిస్థితి భిన్నంగా ఉంటుంది:
- MySQL 8 స్టార్టప్ సమయంలోనే తన డేటా డిక్షనరీని అప్గ్రేడ్ చేసుకుంటుంది, కాబట్టి మైనర్ ట్యాగ్ మార్పు సాధారణంగా ఒక రీస్టార్ట్తో సరిపోతుంది. రిలీజ్ సిరీస్ల మధ్య మారే ముందు రిలీజ్ నోట్స్ చదవండి, ఏది ఏమైనా ముందుగా dump తీసుకోండి.
- MariaDB కొత్త వెర్షన్లో సర్వర్ ప్రారంభమైన తర్వాత
mariadb-upgradeరన్ చేయాలని ఆశిస్తుంది. - MongoDB ని ఒకసారికి ఒక మేజర్ వెర్షన్ చొప్పున మాత్రమే అప్గ్రేడ్ చేయాలి. ప్రతి దశ తర్వాత, తదుపరి వెర్షన్కు వెళ్లే ముందు feature compatibility version ను సెట్ చేయాలి. ఒక వెర్షన్ను దాటవేస్తే,
mongodప్రారంభం కావడానికి నిరాకరిస్తుంది మరియుfeatureCompatibilityVersionని పేర్కొంటూUPGRADE PROBLEMలైన్ను లాగ్ చేస్తుంది. MongoDB 7.0 నుండి, ఈ కమాండ్కు స్పష్టమైన నిర్ధారణ ఫ్లాగ్ అవసరం:db.adminCommand({ setFeatureCompatibilityVersion: "8.0", confirm: true }). - Redis పాత స్నాప్షాట్ ఫైళ్లను సులభంగా లోడ్ చేస్తుంది కానీ కొత్త వాటిని కాదు. కాబట్టి అప్గ్రేడ్ అంటే కేవలం రీస్టార్ట్, కానీ డౌన్గ్రేడ్ చేసేటప్పుడు డేటా లోడ్ కాకపోవచ్చు.
సాధారణ నియమం: కంటైనర్ డౌన్గ్రేడ్ను సులభతరం చేస్తుంది, కానీ అప్గ్రేడ్ను సులభతరం చేయదు.
నా డేటాబేస్ కంటైనర్ ఎందుకు 137 కోడ్తో నిలిచిపోతోంది?
ఎందుకంటే కెర్నల్ యొక్క out of memory (OOM) కిల్లర్ దానిని నిలిపివేసింది. 137 అనేది 128 మరియు సిగ్నల్ 9 ల మొత్తం.
docker compose ps
docker inspect myapp-db-1 | grep -i oomkilled
journalctl -k | tail -n 20docker compose ps కమాండ్ Exited (137) ని చూపుతుంది, inspect లైన్ "OOMKilled": true అని ఉంటుంది, మరియు కెర్నల్ లాగ్లో దీనికి సరిపోయే ఎంట్రీ ఉంటుంది:
Memory cgroup out of memory: Killed process 4711 (postgres) total-vm:2170416kBదీని వెనుక ఉన్న విధానం ఇది, ఇది చాలా మందిని ఆశ్చర్యపరుస్తుంది. PostgreSQL మరియు MySQL తమ బఫర్ల పరిమాణాన్ని హోస్ట్ రిపోర్ట్ చేసే మొత్తం మెమరీ ఆధారంగా నిర్ణయించుకుంటాయి. cgroup పరిమితి ఆ సంఖ్యను వాటి కోసం మార్చదు. 16 GB హోస్ట్లో 2 GB పరిమితి ఉన్నప్పుడు, డేటాబేస్ తనకు 16 GB ఉన్నట్లుగా ప్లాన్ చేసుకుంటుంది, హోస్ట్ ఒత్తిడిలో లేకపోయినా cgroup దానిని నిలిపివేస్తుంది. కాబట్టి కేవలం మెమరీ పరిమితి సరిపోదు. మీరు డేటాబేస్కు అందుబాటులో ఉన్న మెమరీని కూడా తెలియజేయాలి:
- PostgreSQL:
shared_buffersని సెట్ చేయండి, మరియుwork_memపట్ల జాగ్రత్త వహించండి.work_memఅనేది ప్రతి కనెక్షన్కు, ప్రతి సార్టింగ్ ఆపరేషన్కు కేటాయించబడుతుంది, కాబట్టి యాభై కనెక్షన్లకు ఎక్కువ విలువను కేటాయించడం వల్ల, స్టార్టప్ సమయంలో కాకుండా లోడ్ పెరిగినప్పుడు కంటైనర్ ఆగిపోవడానికి సాధారణ కారణం అవుతుంది. - MySQL మరియు MariaDB:
innodb_buffer_pool_sizeని సెట్ చేయండి, దీని డిఫాల్ట్ విలువ 128M. కంటైనర్లోinnodb_dedicated_serverని ఆఫ్ చేయండి, ఎందుకంటే మెషిన్ మెమరీని బట్టి తన పరిమాణాన్ని తానే నిర్ణయించుకోవడం దీని పని. - MongoDB: WiredTiger కాష్ పరిమాణాన్ని హోస్ట్ మెమరీని బట్టి ఊహించనివ్వకుండా, నేరుగా సెట్ చేయండి.
- Redis:
maxmemoryడిఫాల్ట్గా అపరిమితంగా ఉంటుంది, కాబట్టి cgroup ఆపే వరకు Redis పెరుగుతూనే ఉంటుంది.maxmemoryని కంటైనర్ పరిమితి కంటే తక్కువగా సెట్ చేయండి మరియు తగినmaxmemory-policyని ఎంచుకోండి.
Postgres కూడా ఈ సంఘటనను తన వైపు నుండి రిపోర్ట్ చేస్తుంది, లాగ్లో మీకు ఈ క్రింది రెండు లైన్లు కనిపిస్తాయి:
LOG: server process (PID 123) was terminated by signal 9: Killed
LOG: terminating any other active sessions due to crash of another server processఒక బ్యాకెండ్ నిలిపివేయబడటం వల్ల, షేర్డ్ మెమరీ అస్థిరంగా మారే అవకాశం ఉన్నందున మిగిలిన అన్ని బ్యాకెండ్లు రీస్టార్ట్ అవుతాయి. ఇది మీ అప్లికేషన్కు కనెక్షన్ల వరదను (connection storm) కలిగిస్తుంది, ఇది సాధారణ సంఘటన కాదు. Docker Compose లో మెమరీ పరిమితులను సెట్ చేయడం అనే విభాగం దీని సింటాక్స్ మరియు mem_limit కి, deploy.resources ఫార్మాట్కు మధ్య ఉన్న తేడాలను వివరిస్తుంది.
ఇవేవీ హోస్ట్లో మాయం కావు. అవి కేవలం మారుతాయి. cgroup లేకపోతే, డేటాబేస్ బాక్స్లోని మిగిలిన అన్నింటితో పోటీ పడుతుంది, అప్పుడు హోస్ట్ OOM కిల్లర్ స్కోరు ఆధారంగా ఒక బాధితుడిని ఎంచుకుంటుంది, అది sshd కూడా కావచ్చు. హోస్ట్ OOM వల్ల మీరు లాక్ అవుట్ అయ్యే ప్రమాదం కంటే, డేటాబేస్ను నిలిపివేసే పరిమితిని నిర్వహించడం సులభం.
బ్యాకప్లు: లోపల డంప్ చేయండి, బయట బ్యాకప్ చేయండి
నడుస్తున్న డేటాబేస్ను దాని డేటా డైరెక్టరీని కాపీ చేయడం ద్వారా బ్యాకప్ చేయవద్దు. సర్వర్ డేటాను రాస్తున్నప్పుడు ఫైల్-స్థాయి కాపీని తీసుకుంటే అది అసంపూర్ణంగా (torn copy) ఉంటుంది, ఇది మీరు డేటాను పునరుద్ధరించేటప్పుడు (restore) తెలుస్తుంది.
రెండు సరైన పద్ధతులు ఉన్నాయి: డేటాబేస్ నడుస్తున్నప్పుడు దాని స్వంత టూల్తో డంప్ తీసి ఆ డంప్ను బ్యాకప్ చేయడం, లేదా కంటైనర్ను ఆపివేసి వాల్యూమ్ను కోల్డ్ కాపీ (cold copy) చేయడం.
docker compose exec -T db pg_dump -U postgres -Fc appdb > /srv/backups/appdb.dump
docker compose exec -T db mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" --single-transaction --all-databases > /srv/backups/mysql.sql
docker compose exec -T db mongodump --archive --gzip --db appdb > /srv/backups/appdb.archive.gz
docker compose exec -T redis redis-cli BGSAVE-T చాలా ముఖ్యం. ఇది లేకపోతే, docker compose exec కమాండ్కు టెర్మినల్ను అటాచ్ చేయవచ్చు, దీనివల్ల టెర్మినల్ లేయర్ అవుట్పుట్ స్ట్రీమ్కు క్యారేజ్ రిటర్న్లను జోడిస్తుంది. అప్పుడు టెక్స్ట్ డంప్ వింతైన లోపాలతో పునరుద్ధరించబడుతుంది మరియు బైనరీ డంప్ పూర్తిగా పాడవుతుంది. ఇది బ్యాకప్ సమయంలో నిశ్శబ్దంగా విఫలమవుతుంది, కానీ ఒక నెల తర్వాత పునరుద్ధరించేటప్పుడు పెద్ద సమస్యగా మారుతుంది.
--single-transaction అనేది మొత్తం సర్వర్ను లాక్ చేయకుండానే InnoDB టేబుల్స్ యొక్క స్థిరమైన స్నాప్షాట్ను mysqldump కి అందిస్తుంది.
ఈ కమాండ్లు ఒక్కో ఫైల్ను మాత్రమే రాస్తాయి. ఇవి బ్యాకప్ సిస్టమ్ కాదు: ఇందులో రిటెన్షన్ (retention), బాహ్య కాపీ (off-box copy), మరియు వెరిఫికేషన్ ఉండవు. ఈ డంప్ డైరెక్టరీని ఈ మూడు పనులను చేసే ఒక టూల్కు అప్పగించండి, దీని కోసమే restic backups from a VPS ఉపయోగపడుతుంది. /var/lib/docker/volumes ని కాదు, /srv/backups ని బ్యాకప్ చేయండి.
తర్వాత పునరుద్ధరణను (restore) పరీక్షించండి, ఎందుకంటే మీరు ఎప్పుడూ పునరుద్ధరించని బ్యాకప్ అసలు బ్యాకపే కాదు:
docker compose exec -T db createdb -U postgres restore_test
docker compose exec -T db pg_restore -U postgres -d restore_test < /srv/backups/appdb.dump
docker compose exec -T db psql -U postgres -d restore_test -c '\dt'\dt మీ అప్లికేషన్ యొక్క టేబుల్స్ను చూపించాలి. ఫలితం ఖాళీగా ఉన్నా, లేదా Did not find any relations. అని వచ్చినా, డంప్ మీరు అనుకున్నట్లుగా లేదని అర్థం. పని పూర్తయ్యాక restore_test ని తొలగించండి.
అన్నింటినీ తొలగించే కమాండ్
docker compose down -v.
సాధారణ down కంటైనర్లను మరియు నెట్వర్క్ను తొలగిస్తుంది. -v ఆ compose ఫైల్లో పేర్కొన్న ప్రతి named volume ను, మరియు ఆ కంటైనర్లకు అనుసంధానించబడిన ప్రతి anonymous volume ను కూడా తొలగిస్తుంది. దీనికి ఎటువంటి నిర్ధారణ (prompt) అడగదు మరియు దీనిని వెనక్కి తీసుకోవడం (undo) సాధ్యం కాదు. self-hosted డేటాబేస్ తొలగిపోవడానికి ఇది అత్యంత సాధారణ కారణం. సంబంధం లేని ఏదైనా సమస్యను పరిష్కరించేటప్పుడు, ఫోరమ్లో ఎవరైనా దీనిని రన్ చేయమని చెప్పడం వల్ల ఇది తరచుగా జరుగుతుంది.
ప్రమాద తీవ్రతను తగ్గించడానికి నాలుగు మార్గాలు ఉన్నాయి:
- డేటాబేస్ వాల్యూమ్ను
external: trueగా ప్రకటించండి. Compose తన ఆధీనంలో లేని వాల్యూమ్ను తొలగించదు, కాబట్టి-vదానిని ఏమీ చేయలేదు. మీరు దీనినిdocker volume create myapp_pgdataతో ఒకసారి సృష్టించుకోవాలి. - సాధారణ రీస్టార్ట్ల కోసం
docker compose stopమరియుdocker compose startఉపయోగించండి. Compose లో down మరియు stop మధ్య తేడా ప్రతి ఒక్కటి దేనిని తొలగిస్తుందో వివరిస్తుంది. - Compose నిర్వహించే ప్రతి వాల్యూమ్ వెలుపల, హోస్ట్ పాత్లో డేటాబేస్ డంప్లను ఉంచండి.
- మీకు ముఖ్యమైన డేటా ఉన్న స్టాక్లో, ట్రబుల్షూటింగ్ సమాధానాల నుంచి వచ్చే
-vకమాండ్ను ఎప్పుడూ కాపీ-పేస్ట్ చేయవద్దు.
డేటాబేస్ పోర్ట్ను పబ్లిక్ చేయవద్దు
ఈ లైన్ మీ డేటాబేస్ను పబ్లిక్ ఇంటర్నెట్కు బహిర్గతం చేస్తుంది:
ports:
- "5432:5432"ఇది ప్రతి నెట్వర్క్ ఇంటర్ఫేస్కు బైండ్ అవుతుంది. Docker ఒక పోర్ట్ను పబ్లిక్ చేసినప్పుడు, మీ ఫైర్వాల్ ఇన్పుట్ రూల్స్ చూడకముందే అది ప్యాకెట్ యొక్క డెస్టినేషన్ను మారుస్తుంది. ufw రూల్స్ ఇన్పుట్ చైన్లో ఉంటాయి కాబట్టి, ufw deny 5432 ఏమాత్రం పనిచేయదు. Docker పబ్లిష్ చేసిన పోర్ట్లు ufw ను ఎందుకు దాటవేస్తాయి అనే అంశం చైన్ ట్రావర్సల్ను వివరిస్తుంది.
ఒకే compose ప్రాజెక్ట్లోని అప్లికేషన్, compose నెట్వర్క్ ద్వారా సర్వీస్ పేరుతోనే డేటాబేస్ను చేరుకోగలదు, కాబట్టి దానికి పబ్లిష్ చేసిన పోర్ట్ అవసరం లేదు. ఆ బ్లాక్ను తొలగించండి. ఒకవేళ మీకు హోస్ట్ మెషీన్ నుండి క్లయింట్ యాక్సెస్ కావాలంటే, loopback కు మాత్రమే బైండ్ చేయండి:
ports:
- "127.0.0.1:5432:5432"ప్రస్తుతం ఏది వింటోందో (listening) తనిఖీ చేయండి:
sudo ss -ltnp | grep 5432127.0.0.1:5432 అనేది మీరు ఆశించే ఫలితం. 0.0.0.0:5432 అంటే ఎవరైనా మీ పాస్వర్డ్ను ప్రయత్నించే అవకాశం ఉందని అర్థం.
ఎక్కడ ఏమి రన్ చేయాలి
ఒక VPSలో ఒక అప్లికేషన్. కంటైనర్ వాడండి. పేరు నిర్ణయించిన (pinned name) వాల్యూమ్ను ఉపయోగించండి, పోర్ట్ను పబ్లిష్ చేయకండి, డేటాబేస్ సెట్టింగ్లకు అనుగుణంగా మెమరీ పరిమితిని విధించండి, మరియు ప్రతిరోజూ రాత్రి ఒక dump ఫైల్ను హోస్ట్ పాత్లోకి తీసుకోండి, దానిని restic సేకరిస్తుంది. VPSలో క్లీన్ Docker ఇన్స్టాలేషన్ తో ప్రారంభించి, మొత్తం stackను ఒకే compose ఫైల్లో ఉంచి gitలో commit చేయండి. దీనివల్ల డేటాబేస్ వెర్షన్ gitలో రివ్యూ చేయదగిన లైన్గా మారుతుంది, ఇది చాలా ఉపయోగకరం.
అనేక సేవలు నడిచే హోస్ట్. కంటైనర్లను వాడండి, ప్రతి అప్లికేషన్కు ఒక ప్రత్యేక డేటాబేస్ ఉండాలి, అన్నింటికీ కలిపి ఒకే షేర్డ్ సర్వర్ ఉండకూడదు. షేర్డ్ సర్వర్ వల్ల అన్ని అప్లికేషన్లు ఒకే అప్గ్రేడ్ షెడ్యూల్కు కట్టుబడి ఉండాల్సి వస్తుంది, ఒకే ఒక తప్పు క్వెరీ వల్ల అన్ని సేవలు ఆగిపోయే ప్రమాదం ఉంది. ప్రతి కంటైనర్కు మెమరీ పరిమితిని సెట్ చేయండి, తద్వారా ఒక చెడు క్వెరీ ఆ అప్లికేషన్కే పరిమితం అవుతుంది. చిన్న చిన్న Postgres ఇన్స్టాన్సులను వాడటం వల్ల డిస్క్ స్పేస్ కొంచెం ఎక్కువ ఖర్చయినా, నిర్వహణ చాలా సులభం అవుతుంది.
డేటాబేసే ప్రధాన ఉత్పత్తి. దీనిని వెండర్ ప్యాకేజీ రిపోజిటరీ నుండి హోస్ట్పై రన్ చేయండి లేదా మేనేజ్డ్ సర్వీస్ను ఎంచుకోండి. pg_upgrade కి ఒకే సమయంలో రెండు ప్రధాన వెర్షన్ల బైనరీలు అవసరం కావచ్చు, ఇది ప్యాకేజీల ద్వారా సాధ్యమవుతుంది కానీ సింగిల్-వెర్షన్ ఇమేజ్లో సాధ్యం కాదు. డేటాబేస్ నేరుగా మెషీన్ మరియు డిస్క్లను నియంత్రిస్తున్నప్పుడు, WAL (write ahead log) ఆర్కైవింగ్తో రెప్లికేషన్ మరియు పాయింట్-ఇన్-టైమ్ రికవరీ సులభం అవుతాయి. రాత్రి 03:00 గంటలకు మీకు అలర్ట్ వచ్చే అవకాశం ఉన్న సిస్టమ్ కోసం ఎప్పుడూ నమ్మదగిన, సాధారణ పద్ధతినే ఎంచుకోండి.
అప్లికేషన్ చిన్నది. సర్వర్ డేటాబేస్ లేకుండా రన్ చేయడం గురించి ఆలోచించండి. ఒక VPSలో సింగిల్-రైటర్ వెబ్ అప్లికేషన్ కోసం VPSలో SQLite వాడటం తరచుగా మంచిది. ఇందులో బ్యాకప్ అంటే ఒకే ఒక ఫైల్, మరియు అప్గ్రేడ్ అంటే కేవలం లైబ్రరీ వెర్షన్ను మార్చడమే.
FAQ
ప్రొడక్షన్ డేటాబేస్ను Dockerలో రన్ చేయడం సురక్షితమేనా?
అవును, ఒకే సర్వర్ అప్లికేషన్ స్టాక్ కోసం ఇది సురక్షితమే. కంటైనర్ అనేది Linux namespaces మరియు cgroups కలిగి ఉన్న ఒక ప్రాసెస్ మాత్రమే. వాల్యూమ్ మౌంట్ చేసినప్పుడు, డేటాబేస్ నేరుగా హోస్ట్ ఫైల్సిస్టమ్లోనే డేటాను రాస్తుంది, కాబట్టి ప్యాకేజీ ద్వారా ఇన్స్టాల్ చేసిన దానితో దీనికి పెద్ద తేడా ఉండదు. ఇక్కడ రిస్క్ అనేది వేగం కంటే నిర్వహణకు సంబంధించింది: పేరు ఖచ్చితంగా లేని వాల్యూమ్, తప్పు యూజర్ ఐడి (UID) కలిగి ఉన్న bind mount, మరియు మీరు ఎప్పుడూ పరీక్షించని restore ప్రక్రియ, అలాగే docker compose down -v వంటివి సమస్యలను కలిగిస్తాయి. ఈ నాలుగు అంశాలను సరిచేసుకుంటే కంటైనర్ సురక్షితంగా ఉంటుంది. డేటాబేస్ మీ ప్రధాన వర్క్లోడ్ అయ్యి, మీకు pg_upgrade, రెప్లికేషన్ లేదా పాయింట్-ఇన్-టైమ్ రికవరీ అవసరమైనప్పుడు మాత్రం హోస్ట్ ఇన్స్టాలేషన్కు మారడం మంచిది.
డేటాబేస్ డేటా కోసం bind mount వాడాలా లేక named volume వాడాలా?
హోస్ట్ పాత్ గురించి ప్రత్యేక కారణం లేకపోతే named volume వాడటమే ఉత్తమం. Docker డైరెక్టరీని సృష్టిస్తుంది మరియు ఇమేజ్ ఎంట్రీపాయింట్ మొదటిసారి స్టార్ట్ అయినప్పుడు ownership ను సెట్ చేస్తుంది, కాబట్టి పర్మిషన్ సమస్యలు రావు. వాల్యూమ్ను ఖచ్చితమైన name: తో పిన్ చేయండి లేదా external: true గా మార్క్ చేయండి, లేకపోతే ప్రాజెక్ట్ డైరెక్టరీ పేరు మార్చినప్పుడు పాత డేటాబేస్ పోయి కొత్త ఖాళీ వాల్యూమ్ తయారవుతుంది. ఒకవేళ bind mount వాడాలంటే, హోస్ట్ డైరెక్టరీని ఇమేజ్ రన్ అయ్యే numeric user id కి chown చేయాలి (అధికారిక Postgres, MySQL మరియు MongoDB ఇమేజ్లకు ఇది 999). దీన్ని ls -ldn తో సరిచూసుకోండి, ఎందుకంటే ls -l మీ హోస్ట్ లోని పేరును చూపిస్తుంది, కానీ ఆ పేరు కంటైనర్ లోపల అర్థరహితం.
docker compose down -v దేనిని తొలగిస్తుంది?
ఇది సాధారణ down లాగానే కంటైనర్లు మరియు నెట్వర్క్ను తొలగిస్తుంది, అయితే -v అదనంగా ఆ compose ఫైల్లో పేర్కొన్న ప్రతి named volume ను మరియు ఆ కంటైనర్లకు అటాచ్ అయిన ప్రతి anonymous volume ను తొలగిస్తుంది. ఇందులో డేటాబేస్ కూడా ఉంటుంది. దీనికి ఎటువంటి కన్ఫర్మేషన్ అడగదు మరియు డేటాను తిరిగి పొందడం సాధ్యం కాదు. external: true అని మార్క్ చేసిన వాల్యూమ్లు తొలగించబడవు, అందుకే డేటాబేస్ వాల్యూమ్ను external గా మార్క్ చేయడం మంచిది. సాధారణ రీస్టార్ట్ కోసం docker compose stop మరియు docker compose start వాడండి.
Dockerలో PostgreSQL ను కొత్త మేజర్ వెర్షన్కు ఎలా అప్గ్రేడ్ చేయాలి?
Dump మరియు restore పద్ధతిని వాడాలి. postgres:16 ను postgres:17 కి మార్చి రీస్టార్ట్ చేస్తే, DETAIL లైన్తో కూడిన FATAL: database files are incompatible with server ఎర్రర్ వస్తుంది, ఎందుకంటే కొత్త బైనరీలు పాత క్యాటలాగ్ లేఅవుట్ను చదవలేవు. ఏమీ పాడవదు: పాత ట్యాగ్ను తిరిగి సెట్ చేస్తే అది మళ్ళీ స్టార్ట్ అవుతుంది. రన్ అవుతున్న పాత కంటైనర్పై కొత్త వెర్షన్ క్లయింట్ను ఉపయోగించి pg_dumpall తీసుకోండి, ఫైల్ PostgreSQL database cluster dump complete తో ముగిసిందో లేదో సరిచూసుకోండి, ఆపై కొత్త ట్యాగ్ను ఖాళీ వాల్యూమ్పై రన్ చేసి dump ను లోడ్ చేయండి. ఒకే మేజర్ వెర్షన్ లోపల చిన్న అప్గ్రేడ్ల కోసం కేవలం pull మరియు restart సరిపోతాయి.
నా డేటాబేస్ కంటైనర్ 137 కోడ్తో ఎందుకు ఆగిపోతుంది?
137 అంటే 128 ప్లస్ సిగ్నల్ 9, అంటే ఏదో ఒక కారణం చేత ప్రాసెస్ బలవంతంగా ఆపివేయబడింది. docker inspect <container> | grep -i oomkilled రన్ చేయండి; true విలువ వస్తే కంటైనర్ దాని cgroup మెమరీ పరిమితిని దాటిందని అర్థం. సాధారణంగా PostgreSQL మరియు MySQL హోస్ట్ యొక్క మొత్తం మెమరీని చూస్తాయి కానీ కంటైనర్ పరిమితిని చూడవు, కాబట్టి అవి 2 GB మెమరీ ఉన్నా 16 GB కోసం ప్లాన్ చేస్తాయి. కంటైనర్కు మీరు ఇచ్చిన పరిమితికి అనుగుణంగా shared_buffers మరియు work_mem, లేదా innodb_buffer_pool_size సెట్ చేయండి. కెర్నల్ ఏ ప్రాసెస్ను తొలగించిందో తెలుసుకోవడానికి journalctl -k లోని Memory cgroup out of memory లైన్ను తనిఖీ చేయండి.