SSD Nodes Learn 🎉 VPS $5.50/மாதம் முதல்
கல்வி வழிகாட்டிகள் Matt Connorஆல் Matt Connor · புதுப்பிக்கப்பட்டது 2026-08-13

Database-ஐ Docker-ல் இயக்குவது பாதுகாப்பானதா?

Postgres, MySQL, MongoDB போன்றவற்றை Docker-ல் இயக்குவது production-க்கு ஏற்றது. Volumes, upgrades, backups மற்றும் memory limits ஆகியவற்றைச் சரியாகக் கையாள்வது அவசியம்.

Database-ஐ Docker-ல் இயக்க வேண்டுமா அல்லது host-ல் இயக்க வேண்டுமா?

Database-ஐ Docker-ல் இயக்குங்கள். ஒரு VPS-ல் ஒரு application stack-ஐ இயக்கும்போது, container-ஆக உள்ள PostgreSQL, MySQL, MongoDB அல்லது Redis ஆகியவை சாதாரணமான production தேர்வுகள் ஆகும். இதைப் பற்றிய விவாதங்கள் பெரும்பாலும் தவறான கோணத்திலேயே அமைகின்றன. Container என்பது Linux namespaces மற்றும் cgroups-ஆல் சூழப்பட்ட ஒரு process மட்டுமே; இது virtual machine அல்ல. எனவே, database-க்கும் disk-க்கும் இடையே hypervisor எதுவும் இல்லை. Bind mount அல்லது local named volume-ஐப் பயன்படுத்தும்போது, தரவுகள் நேரடியாக host filesystem-ல் எழுதப்படுகின்றன; இது package install மூலம் இயங்கும் database பயன்படுத்தும் அதே முறைதான்.

இதன் உண்மையான சவால் செயல்பாட்டு ரீதியானது (operational). இந்த அமைப்பு சிறப்பாகச் செயல்படுமா அல்லது சிக்கலாகுமா என்பதை நான்கு விஷயங்கள் தீர்மானிக்கின்றன: தரவுகள் எங்கே சேமிக்கப்படுகின்றன, அந்த directory-ன் உரிமையாளர் யார், major version upgrade எப்படிச் செய்யப்படுகிறது, மற்றும் நீங்கள் எப்போதாவது backup-ஐ restore செய்து பார்த்திருக்கிறீர்களா என்பது. இவற்றைச் சரியாகச் செய்துவிட்டால், container என்பது ஒரு சிறிய தொழில்நுட்ப விவரம் மட்டுமே. இவற்றைத் தவறவிட்டால், நீங்கள் container-ஐக் குறை சொல்ல நேரிடும்.

எந்தவொரு server database-க்கும் இதுவே பொருந்தும். கீழே உள்ள உதாரணங்கள் PostgreSQL, MySQL, MongoDB மற்றும் Redis ஆகியவற்றைப் பயன்படுத்துகின்றன. அந்தந்த product-க்குரிய முக்கிய வேறுபாடுகள் தேவைப்படும் இடங்களில் குறிப்பிடப்பட்டுள்ளன.

ஒரு container உண்மையில் எதை மாற்றுகிறது

நீங்கள் ஒரு volume-ஐ mount செய்யும் வரை, storage path மாறுவதில்லை. அதே kernel, அதே page cache, அதே filesystem தான் பயன்படுத்தப்படுகிறது.

செயல்திறனில் ஒரு முக்கியமான சிக்கல் உள்ளது; அது நீங்கள் எதையும் mount செய்யாதபோது நிகழ்கிறது. Volume இல்லையென்றால், தரவு அடைவு (data directory) container-ன் writable layer-ல் அமையும். இது image-க்கு மேலே அடுக்கப்பட்ட ஒரு overlay filesystem ஆகும். அங்கு செய்யப்படும் எழுதும் செயல்பாடுகள் (writes) மெதுவானவை, மேலும் container நீக்கப்படும்போது அந்த முழு layer-ம் அழிந்துவிடும். "இன்று காலை எனது database காலியாக இருந்தது" என்ற புகாருக்கு இதுவே காரணம்.

உண்மையில் மாறுபவை:

  • வாழ்க்கைச் சுழற்சி (Lifecycle). docker compose down கட்டளை container-ஐ அழித்துவிடும். Volume-ல் இல்லாத அனைத்தும் அதனுடன் சேர்ந்து அழிந்துவிடும்.
  • பதிப்பு (Version). Image tag தான் பதிப்பு. ஒரு database container-க்குள் apt upgrade என்ற கட்டளை இருக்காது, அது அடுத்த docker compose pull-க்கு பிறகு நிலைத்திருக்காது.
  • நினைவகக் கணக்கீடு (Memory accounting). Cgroup வரம்பு என்பது kernel-ஆல் செயல்படுத்தப்படும் ஒரு கடினமான தடுப்புச் சுவர்; அது இருப்பதை database அறியாது.
  • பயனர் (User). செயல்முறை (process) container-க்குள் ஒரு எண் சார்ந்த பயனர் அடையாளத்துடன் (numeric user id) இயங்குகிறது. இது உங்கள் host-ல் எதையும் கொண்டிருக்காமல் இருக்கலாம்.

தரவு எங்கு சேமிக்கப்படுகிறது என்பது அனைத்தையும் தீர்மானிக்கிறது

இதற்கு இரண்டு சிறந்த வழிகளும், ஒரு பொதுவான தவறும் உள்ளன.

  • ஒரு named volume: pgdata:/var/lib/postgresql/data. Docker இந்த directory-ஐ /var/lib/docker/volumes/<project>_pgdata/_data-ல் உருவாக்குகிறது, மேலும் image entrypoint முதல்முறை இயங்கும்போது அதற்கான உரிமையை (ownership) அமைக்கிறது. இதுவே இயல்பான (default) தேர்வாகும்.
  • ஒரு bind mount: /srv/appname/pg:/var/lib/postgresql/data. பாதையை நீங்களே தேர்வு செய்வதால், அதற்கான அனுமதிகளை (permissions) நீங்களே கையாள வேண்டும்.
  • mount எதுவும் செய்யாதிருத்தல். மேலே உள்ளதைப் பார்க்கவும். தரவு container-க்கு உள்ளேயே இருக்கும்.

இதன் முழுமையான சாதக பாதகங்கள் ஒரு தனி தலைப்பாகும், bind mounts மற்றும் named volumes ஒப்பீடு அதை விளக்குகிறது. ஒரு database-க்கு சுருக்கமான அறிவுரை: host பாதையை நீங்கள் குறிப்பாகத் தெரிந்து வைத்திருக்க வேண்டிய அவசியம் இல்லையெனில், named volume-ஐப் பயன்படுத்தவும். ஒருவேளை bind mount-ஐப் பயன்படுத்தினால், அதை git clean அணுகக்கூடிய project directory-க்குள் வைக்காமல், /srv/appname/pg போன்ற நிலையான இடத்தில் வைக்கவும்.

ஒரு முக்கிய கட்டுப்பாடு: NFS (network file system) அல்லது அதன் locking மற்றும் fsync செயல்பாட்டை நீங்கள் சோதிக்காத எந்தவொரு network mount-லும் database தரவு directory-ஐ வைக்க வேண்டாம். ஒரு வெற்றிகரமான fsync என்பது தரவு நிலையான சேமிப்பகத்தில் (stable storage) பதிவாகிவிட்டது என்று database கருதுகிறது. இந்த அனுமானம் தவறாகும்போது, சில வாரங்களுக்குப் பிறகு தரவு சிதைவு (corruption) ஏற்படும்.

Volume பெயர் தொலைந்து போவதற்கு முன்பே அதை நிலைநிறுத்துங்கள் (Pin)

Compose ஒரு volume-க்கு <project>_<volume> என்று பெயரிடுகிறது, மேலும் project பெயர் இயல்பாகவே directory பெயராக அமைகிறது. எனவே, ஒரு volume-ன் அடையாளம் directory பெயரைச் சார்ந்துள்ளது; மக்கள் எந்தவித யோசனையுமின்றி மாற்றக்கூடிய ஒரு விஷயம் இது.

/srv/app-ஐ /srv/app-old-க்கு நகர்த்தினால், அல்லது compose file-ல் உள்ள pgdata key-ஐ மறுபெயரிட்டால், அடுத்தமுறை இயங்கும் docker compose up -d ஒரு புதிய காலி volume-ஐ உருவாக்கும். Postgres அதில் ஒரு புதிய cluster-ஐ initialize செய்யும். Container ஆரோக்கியமாக இருக்கும், application தொடங்கும், ஆனால் அனைத்து table-களும் அழிந்திருக்கும். பழைய volume இன்னும் பழைய பெயரிலேயே disk-ல் இருப்பதுதான் இதில் உள்ள ஒரே நல்ல செய்தி.

docker volume ls
docker volume inspect app_pgdata

இது நடக்காமல் இருக்க பெயர்களை நிலைநிறுத்துங்கள் (Pin). Project பெயர் மற்றும் volume பெயரைத் தெளிவாகக் குறிப்பிடுங்கள்:

name: myapp

services:
  db:
    image: postgres:17
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:
    name: myapp_pgdata

ஏற்கனவே ஒரு stray volume-ல் உங்கள் தரவு இருந்தால், database-ஐ நிறுத்திவிட்டு அதை நகலெடுங்கள்:

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

Database இயங்கிக்கொண்டிருக்கும்போது நகலெடுத்தால், எழுதப்பட்டுக்கொண்டிருந்த கோப்புகள் சிதைந்த நிலையில் (torn copy) கிடைக்கும். எனவே முதலில் அதை நிறுத்துங்கள்.

தரவு அடைவின் (data directory) உரிமையாளர் யார்

அதிகாரப்பூர்வமான Postgres, MySQL மற்றும் MongoDB images, அவற்றின் server-ஐ ஒரு சலுகையற்ற (unprivileged) user id-ல் இயக்குகின்றன, இது பொதுவாக 999 ஆகும். Container root பயனராகத் தொடங்கும்போது, entrypoint தரவு அடைவின் உரிமையை அந்தப் பயனருக்கு மாற்றிவிட்டு, பின்னர் தனது சலுகைகளைக் குறைத்துக்கொள்ளும். இதனால்தான் ஒரு காலியான bind mount பொதுவாக முதல் முயற்சியிலேயே வேலை செய்கிறது.

நீங்கள் compose கோப்பில் user:-ஐ அமைக்கும் தருணத்தில் இது செயலிழக்கும், ஏனெனில் அப்போது எதையும் சரிசெய்ய entrypoint-க்கு எந்தச் சலுகையும் இருக்காது. 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 இயங்கும்போது, lock கோப்பில் தோல்வியடையும்:

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.

இதற்கான தீர்வு, host அடைவின் உரிமையை (chown) ஒரு பெயருக்கு மாற்றாமல், அதன் எண் அடையாளத்திற்கு (numeric id) மாற்றுவதாகும்:

sudo chown -R 999:999 /srv/appname/pg
sudo chmod 700 /srv/appname/pg
ls -ldn /srv/appname/pg

ls -ldn பெயர்களுக்குப் பதிலாக எண்களைக் காட்டும், அது 999 999-ஐக் காட்ட வேண்டும். உங்கள் host-ல் உள்ள postgres என்ற கணக்கும், image-க்குள் உள்ள postgres என்ற கணக்கும் ஒன்றுடன் ஒன்று தொடர்புடையவை அல்ல: kernel எண்களை மட்டுமே ஒப்பிடும், பெயர்கள் ஒவ்வொரு பக்கத்திலும் தனித்தனியாகவே பார்க்கப்படும். PUID மற்றும் PGID எவ்வாறு host பயனர்களை container-க்குள் இணைக்கின்றன என்பது அந்த மேப்பிங் முறையை விரிவாக விளக்குகிறது. Rootless Docker அல்லது user namespace remapping-ன் கீழ் இந்த எண்கள் மீண்டும் மாறும், எனவே 999 என்று கருதுவதற்குப் பதிலாக, இயங்கும் container-லிருந்து அந்த id-களைப் பெற்றுக்கொள்ளுங்கள்.

Named volumes-ஐப் பயன்படுத்தினால், முதல்முறை இயக்கும்போதே இந்தச் சிக்கல் நீங்கிவிடும், ஏனெனில் Docker ஒரு காலியான அடைவை உருவாக்கி, entrypoint அதற்கு உரிமையாளராகிவிடும்.

மேம்படுத்தல்கள்: image tag மாற்றத்தின் மூலம் ஒரு package-ஐ மேம்படுத்துதல்

Host-ல், apt upgrade கட்டளையானது உங்களை ஒரு minor version-க்கு நகர்த்தும். உங்கள் distribution தானாகவே database major version-ஐ மாற்றாது. நீங்கள் ஒரு major version-க்கு மாற விரும்பினால், இரண்டு தொகுப்பு binaries-களையும் ஒரே நேரத்தில் நிறுவ முடியும்; இதுதான் pg_upgrade-க்குத் தேவையானதாகும்.

Container-ல் tag என்பதுதான் version, எனவே ஒரு மேம்படுத்தல் என்பது ஒரு வரியை மாற்றுவதாகும். இது minor மேம்படுத்தல்களை எளிதாக்குகிறது, ஆனால் major மேம்படுத்தல்கள் ஒரு முறையான செயல்முறையாகும்.

postgres:16 என்பதை postgres:17 என மாற்றி, docker compose up -d கட்டளையை இயக்கினால், container உடனடியாக வெளியேறும்:

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.

எந்த பாதிப்பும் ஏற்படாது. புதிய binaries, பழைய disk-ல் உள்ள catalog layout-ஐ வாசிக்க மறுக்கும், ஏனெனில் major versions-க்கு இடையே அது மாறுகிறது. tag-ஐ மீண்டும் postgres:16 என மாற்றினால், அது மீண்டும் இயங்கும். இந்த rollback வசதியே containers வழங்கும் உண்மையான மேம்படுத்தல் நன்மையாகும்.

இதற்கான அங்கீகரிக்கப்பட்ட வழி dump மற்றும் restore ஆகும். PostgreSQL-ல், புதிய client மூலம் dump எடுப்பது சிறந்தது. எனவே, compose network-ல் இன்னும் இயங்கிக்கொண்டிருக்கும் பழைய server-க்கு எதிராக புதிய image-லிருந்து அதை இயக்கவும்:

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

கோப்பின் அளவு குறைந்தது சில பத்து kilobytes இருக்க வேண்டும் மற்றும் அது PostgreSQL database cluster dump complete என்ற வரியுடன் முடிய வேண்டும். சில நூறு bytes மட்டுமே இருந்தால், dump தோல்வியடைந்துள்ளது என்று அர்த்தம்; அப்போது volume-ஐ நீக்க வேண்டாம். அந்தச் சரிபார்ப்பிற்குப் பிறகு மட்டுமே இதைச் செய்யவும்:

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

பிற engines-ன் செயல்பாடுகள் மாறுபடும்:

  • MySQL 8 தொடங்கும்போதே அதன் data dictionary-ஐ மேம்படுத்திக்கொள்ளும், எனவே minor tag மாற்றம் பொதுவாக ஒரு restart மட்டுமே. Release series-க்கு இடையே மாறும்போது release notes-ஐப் படிக்கவும், எப்படியிருந்தாலும் முதலில் dump எடுக்கவும்.
  • MariaDB-ல் புதிய version-ல் server தொடங்கிய பிறகு mariadb-upgrade இயக்கப்பட வேண்டும் என்று எதிர்பார்க்கிறது.
  • MongoDB-ஐ ஒரு நேரத்தில் ஒரு major version மட்டுமே மேம்படுத்த முடியும். ஒவ்வொரு படிக்குப் பிறகும், அடுத்த கட்டத்திற்குச் செல்லும் முன் feature compatibility version-ஐ அமைக்க வேண்டும். ஒரு version-ஐத் தவிர்த்தால், mongod தொடங்க மறுக்கும் மற்றும் logs-ல் featureCompatibilityVersion-ஐக் குறிப்பிடும் UPGRADE PROBLEM வரியைக் காட்டும். MongoDB 7.0 முதல், இந்த கட்டளைக்கு ஒரு தெளிவான உறுதிப்படுத்தல் flag தேவை: db.adminCommand({ setFeatureCompatibilityVersion: "8.0", confirm: true }).
  • Redis பழைய snapshot கோப்புகளைச் சரியாக ஏற்றிவிடும், ஆனால் புதியவற்றை ஏற்காது. எனவே, மேம்படுத்தல் என்பது ஒரு restart ஆகும், மேலும் downgrade செய்யும்போது தரவை ஏற்ற முடியாமல் போகலாம்.

பொதுவான விதி: container ஒரு downgrade-ஐ எளிதாக்குகிறது, ஆனால் மேம்படுத்தலை எளிதாக்குவதில்லை.

எனது database container ஏன் 137 என்ற குறியீட்டுடன் வெளியேறுகிறது?

ஏனெனில் kernel-ன் out of memory (OOM) killer அதை நிறுத்திவிட்டது. 137 என்பது 128 மற்றும் signal 9 ஆகியவற்றின் கூடுதல் ஆகும்.

docker compose ps
docker inspect myapp-db-1 | grep -i oomkilled
journalctl -k | tail -n 20

docker compose ps கட்டளை Exited (137)-ஐக் காட்டுகிறது, inspect வரியில் "OOMKilled": true என்று உள்ளது, மேலும் kernel log-ல் இதனுடன் தொடர்புடைய பதிவு உள்ளது:

Memory cgroup out of memory: Killed process 4711 (postgres) total-vm:2170416kB

இதற்கான செயல்முறை இதுதான், இது பலரை ஆச்சரியப்படுத்தும். PostgreSQL மற்றும் MySQL ஆகியவை host-ல் உள்ள மொத்த நினைவகத்தின் அடிப்படையில் தங்கள் buffer அளவைத் தீர்மானிக்கின்றன. ஒரு cgroup வரம்பு அந்த எண்ணை அவற்றுக்காக மாற்றுவதில்லை. 16 GB host-ல் 2 GB வரம்பு இருக்கும்போது, database தனக்கு 16 GB இருப்பதாகக் கருதி திட்டமிடுகிறது, இதனால் host-ல் எந்த அழுத்தமும் ஏற்படுவதற்கு முன்பே cgroup அதை நிறுத்திவிடுகிறது. எனவே, நினைவக வரம்பு மட்டும் போதாது. database-க்கு அதன் வரம்பை நீங்கள் தெரிவிக்க வேண்டும்:

  • PostgreSQL: shared_buffers-ஐ அமைக்கவும், work_mem-ல் கவனம் செலுத்தவும். work_mem என்பது ஒவ்வொரு connection-ன் ஒவ்வொரு sort செயல்பாட்டிற்கும் ஒதுக்கப்படும், எனவே அதிகப்படியான மதிப்பு மற்றும் ஐம்பது connection-கள் சேரும்போது, தொடக்கத்திலல்லாமல் சுமையின் போது container செயலிழக்க இதுவே பொதுவான காரணமாகிறது.
  • MySQL மற்றும் MariaDB: innodb_buffer_pool_size-ஐ அமைக்கவும், இதன் default மதிப்பு 128M ஆகும். container-ல் innodb_dedicated_server-ஐ off செய்யவும், ஏனெனில் கணினியின் நினைவகத்தைக் கண்டறிந்து தன்னைத்தானே அளவிடுவதுதான் அதன் வேலை.
  • MongoDB: host நினைவகத்திலிருந்து தானாகக் கணிப்பதற்குப் பதிலாக, WiredTiger cache அளவை நேரடியாக அமைக்கவும்.
  • Redis: maxmemory-ன் default மதிப்பு வரம்பற்றது, எனவே cgroup அதை நிறுத்தும் வரை Redis வளர்ந்துகொண்டே இருக்கும். maxmemory-ஐ container வரம்பிற்குச் சற்று குறைவாக அமைக்கவும் மற்றும் பொருத்தமான maxmemory-policy-ஐத் தேர்ந்தெடுக்கவும்.

Postgres இந்த நிகழ்வைத் தனது பக்கத்திலிருந்தும் தெரிவிக்கும், log-ல் நீங்கள் காணக்கூடிய வரிகள் இவை:

LOG:  server process (PID 123) was terminated by signal 9: Killed
LOG:  terminating any other active sessions due to crash of another server process

ஒரு backend நிறுத்தப்படுவது மற்ற அனைத்து backend-களையும் restart செய்யத் தூண்டுகிறது, ஏனெனில் shared memory இப்போது சீரற்றதாக இருக்கலாம். இது உங்கள் application-க்கு ஒரு connection storm-ஐ உருவாக்கும், இது ஒரு சாதாரண நிகழ்வல்ல. Docker Compose-ல் நினைவக வரம்புகளை அமைத்தல் என்பது இதற்கான syntax மற்றும் mem_limit மற்றும் deploy.resources வடிவத்திற்கு இடையிலான வித்தியாசத்தை விளக்குகிறது.

இவை எதுவும் host-ல் மறைந்துவிடாது. அவை இடம் மாறுகின்றன. cgroup இல்லையென்றால், database அந்த கணினியில் உள்ள மற்ற அனைத்துடனும் போட்டியிடும், மேலும் host OOM killer ஒரு மதிப்பெண் அடிப்படையில் ஒரு victim-ஐத் தேர்ந்தெடுக்கும், அது sshd-ஆகக்கூட இருக்கலாம். host OOM-ஆல் நீங்கள் வெளியேற்றப்படுவதை விட, database-ஐ முன்கூட்டியே நிறுத்தும் ஒரு வரம்பு நிர்வாகத்திற்கு எளிதானது.

Backups: உள்ளே dump செய்யுங்கள், வெளியே backup எடுங்கள்

இயங்கிக்கொண்டிருக்கும் database-ன் data directory-ஐ அப்படியே நகலெடுப்பதன் மூலம் backup எடுக்காதீர்கள். server தரவுகளை எழுதிக்கொண்டிருக்கும்போது எடுக்கப்படும் file-level நகல், 'torn copy' எனப்படும் முழுமையற்ற நகலாக இருக்கும்; இதை நீங்கள் restore செய்ய முயலும்போதுதான் அறிவீர்கள்.

இதற்கு இரண்டு முறையான வழிகள் உள்ளன: database இயங்கும்போது அதன் சொந்த கருவியைப் பயன்படுத்தி dump எடுத்து அந்த dump-ஐ backup செய்வது, அல்லது container-ஐ நிறுத்திவிட்டு volume-ஐ 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 கட்டளையுடன் terminal-ஐ இணைக்கக்கூடும்; அவ்வாறு இணைந்தால், terminal layer வெளியீட்டு ஓட்டத்தில் (output stream) carriage returns-ஐச் சேர்க்கும். இதனால் text dump-ஐ restore செய்யும்போது விசித்திரமான பிழைகள் ஏற்படும், binary dump முற்றிலும் சிதைந்துவிடும். இது backup எடுக்கும்போது அமைதியாகத் தோல்வியடைந்து, ஒரு மாதம் கழித்து restore செய்யும்போது பெரிய சிக்கலை உண்டாக்கும்.

--single-transaction, முழு server-ஐயும் lock செய்யாமல் InnoDB tables-ன் சீரான snapshot-ஐ mysqldump-க்கு வழங்குகிறது.

இந்தக் கட்டளைகள் ஒவ்வொன்றும் ஒரு கோப்பை மட்டுமே உருவாக்குகின்றன. இவை backup அமைப்பு அல்ல: இதில் retention கிடையாது, off-box நகல் கிடையாது, சரிபார்ப்பும் (verification) கிடையாது. இந்த மூன்றையும் செய்யும் ஒரு கருவியிடம் dump directory-ஐ ஒப்படையுங்கள்; அதற்காகத்தான் restic backups from a VPS உள்ளது. /var/lib/docker/volumes-ஐ அல்ல, /srv/backups-ஐ backup எடுங்கள்.

பிறகு restore செய்து பாருங்கள், ஏனெனில் நீங்கள் ஒருமுறை கூட restore செய்யாத backup, backup-ஆகவே கருதப்படாது:

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 உங்கள் application-ன் tables-ஐப் பட்டியலிட வேண்டும். முடிவு காலியாக இருந்தாலோ அல்லது Did not find any relations. என்று வந்தாலோ, dump நீங்கள் நினைத்தது போல இல்லை என்று அர்த்தம். முடித்தவுடன் restore_test-ஐ நீக்கிவிடுங்கள்.

அனைத்தையும் நீக்கும் கட்டளை

docker compose down -v.

எளிமையான down கட்டளையானது containers மற்றும் network-ஐ நீக்கும். -v கட்டளையானது, அந்த compose கோப்பில் குறிப்பிடப்பட்டுள்ள அனைத்து named volumes மற்றும் அந்த containers-உடன் இணைக்கப்பட்டுள்ள அனைத்து anonymous volumes-ஐயும் நீக்கிவிடும். இதற்கு எந்த உறுதிப்படுத்தலும் (prompt) கேட்கப்படாது, இதைத் திரும்பப் பெறவும் (undo) முடியாது. சுய-வழங்கி (self-hosted) தரவுத்தளங்கள் அழிக்கப்படுவதற்கு இதுவே பொதுவான வழியாகும். பெரும்பாலும், ஏதோ ஒரு சிக்கலைத் தீர்க்க முயற்சிக்கும்போது, இணையதள மன்றங்களில் கொடுக்கப்பட்ட ஆலோசனையைப் பின்பற்றி இதை இயக்குவதால் இத்தகைய இழப்பு ஏற்படுகிறது.

பாதிப்பின் அளவைக் குறைக்க நான்கு வழிமுறைகள் உள்ளன:

  • தரவுத்தள volume-ஐ external: true என அறிவிக்கவும். Compose தனது கட்டுப்பாட்டில் இல்லாத volume-ஐ நீக்காது, எனவே -v கட்டளையால் அதை அணுக முடியாது. இதை docker volume create myapp_pgdata கட்டளையைப் பயன்படுத்தி ஒருமுறை உருவாக்கிக்கொள்ளலாம்.
  • வழக்கமான மறுதொடக்கங்களுக்கு (routine restarts) docker compose stop மற்றும் docker compose start கட்டளைகளைப் பயன்படுத்தவும். Compose-ல் down மற்றும் stop இடையிலான வேறுபாடு ஒவ்வொன்றும் எதை நீக்கும் என்பதை விளக்குகிறது.
  • தரவுத்தள dump கோப்புகளை, compose நிர்வகிக்கும் volumes-க்கு வெளியே உள்ள host path-ல் சேமித்து வைக்கவும்.
  • நீங்கள் முக்கியமாகக் கருதும் தரவுகளைக் கொண்ட stack-ல், சிக்கலைத் தீர்க்கும் மன்றங்களில் கொடுக்கப்படும் -v கட்டளையை ஒருபோதும் நகலெடுத்து இயக்க வேண்டாம்.

Database port-ஐ பொதுவெளியில் வெளியிட வேண்டாம்

இந்த வரி உங்கள் database-ஐ பொது இணையத்தில் வைக்கிறது:

    ports:
      - "5432:5432"

இது அனைத்து interface-களிலும் பிணைக்கப்படுகிறது (bind). Docker ஒரு port-ஐ வெளியிடும்போது, உங்கள் firewall-ன் input விதிகள் பார்ப்பதற்கு முன்பே packet-ன் இலக்கை மாற்றிவிடுகிறது. ufw விதிகள் input chain-ல் இருப்பதால், ufw deny 5432 எந்தப் பயனும் தராது. Docker published ports ஏன் ufw-ஐத் தவிர்க்கின்றன என்பது chain traversal-ஐ விளக்குகிறது.

ஒரே compose project-ல் உள்ள ஒரு application, compose network-ல் உள்ள service name மூலம் database-ஐ அணுகும். எனவே, அதற்கு port-ஐ வெளியிட வேண்டிய அவசியமில்லை. அந்த block-ஐ நீக்கிவிடவும். host-ல் உள்ள ஒரு client-க்கு அணுகல் தேவைப்பட்டால், loopback-ல் மட்டும் பிணைக்கவும்:

    ports:
      - "127.0.0.1:5432:5432"

எது உண்மையில் listening நிலையில் உள்ளது என்பதைச் சரிபார்க்கவும்:

sudo ss -ltnp | grep 5432

127.0.0.1:5432 என்பது நீங்கள் எதிர்பார்க்கும் நிலை. 0.0.0.0:5432 என்பது உங்கள் கடவுச்சொல்லை யார் வேண்டுமானாலும் முயற்சி செய்யலாம் என்று அர்த்தம்.

எதை எங்கே இயக்குவது

ஒரு VPS-ல் ஒரு application. Container. ஒரு குறிப்பிட்ட பெயரிடப்பட்ட volume, published port கிடையாது, database அமைப்புகளுக்கு ஏற்றவாறு memory limit, மற்றும் restic மூலம் சேகரிக்கப்படும் nightly dump. VPS-ல் சுத்தமான Docker நிறுவல் என்பதிலிருந்து தொடங்கி, stack-ஐ ஒரே compose file-ல் வைத்து commit செய்யவும். இதன் நன்மை உண்மையானது: database version என்பது git-ல் சரிபார்க்கக்கூடிய ஒரு வரியாக மாறுகிறது.

பல சேவைகளை இயக்கும் ஒரு host. Containers, ஒவ்வொரு application-க்கும் ஒரு தனி database, அனைத்திற்கும் சேர்த்து ஒரு shared server அல்ல. Shared server ஒவ்வொரு application-ஐயும் ஒரே upgrade கால அட்டவணையுடன் பிணைக்கிறது; ஒரு runaway query அனைவரின் சேவையையும் முடக்கக்கூடும். ஒவ்வொரு container-க்கும் தனித்தனி memory limit வழங்கவும், அப்போதுதான் ஒரு தவறான query அந்த application-க்குள்ளேயே கட்டுப்படுத்தப்படும். பல சிறிய Postgres instances-க்கு சற்று கூடுதல் disk தேவைப்படும், ஆனால் ஒருங்கிணைப்பு மிகக் குறைவு.

Database-தான் தயாரிப்பு. அதை vendor-ன் package repository-லிருந்து host-ல் இயக்கவும் அல்லது managed service-க்கு பணம் செலுத்தவும். pg_upgrade-க்கு ஒரே நேரத்தில் இரண்டு major version binaries தேவைப்படும், இது packages மூலம் கிடைக்கும், ஆனால் single-version image-ல் கிடைக்காது. Database-க்கு சொந்தமான machine மற்றும் disk இருக்கும்போது, Replication மற்றும் WAL (write ahead log) archiving மூலம் point in time recovery செய்வது எளிது. அதிகாலை 03:00 மணிக்கு உங்களை எழுப்பும் system-க்கு, சலிப்பான ஆனால் பாதுகாப்பான வழியைத் தேர்ந்தெடுக்கவும்.

Application சிறியது. Server database-ஐ பயன்படுத்தாமல் இருக்க பரிசீலிக்கவும். ஒரு VPS-ல் இயங்கும் single-writer web application-க்கு VPS-ல் production-ல் SQLite பயன்படுத்துவது சிறந்தது. இதில் backup என்பது ஒரே ஒரு file, மற்றும் upgrade என்பது ஒரு library version மட்டுமே.

FAQ

Docker-ல் production database-ஐ இயக்குவது பாதுகாப்பானதா?

ஆம், ஒரே server-ல் இயங்கும் application stack-க்கு இது பாதுகாப்பானது. ஒரு container என்பது namespaces மற்றும் cgroups-ஆல் சூழப்பட்ட ஒரு Linux process ஆகும். எனவே, volume mount செய்யப்படும்போது, ஒரு package மூலம் install செய்ததைப் போலவே database-ம் host filesystem-ல் தரவுகளை எழுதும். இதில் உள்ள அபாயங்கள் வேகத்தை விட செயல்பாட்டு ரீதியானவை: பெயரிடப்படாத volume, தவறான user id-ல் உள்ள bind mount, நீங்கள் ஒருபோதும் சோதிக்காத restore, மற்றும் docker compose down -v. இந்த நான்கையும் சரிசெய்தால் container பாதுகாப்பாக இருக்கும். Database-தான் முதன்மையான பணிச்சுமை (workload) என்றும், உங்களுக்கு pg_upgrade, replication அல்லது point in time recovery தேவைப்படும்போதும் host install-க்கு மாறவும்.

Database தரவுகளுக்கு bind mount அல்லது named volume இதில் எதைப் பயன்படுத்த வேண்டும்?

Host path-ஐ நீங்கள் தெரிந்துகொள்ள வேண்டிய அவசியம் இல்லையென்றால், named volume-ஐப் பயன்படுத்தவும். Docker அந்த directory-ஐ உருவாக்கும், image entrypoint முதல் தொடக்கத்திலேயே ownership-ஐ அமைத்துவிடும், எனவே அனுமதி (permission) தொடர்பான சிக்கல்கள் வராது. Volume-ஐ ஒரு குறிப்பிட்ட name: மூலம் இணைக்கவும் அல்லது அதை external: true எனக் குறிப்பிடவும், இல்லையெனில் project directory-ன் பெயரை மாற்றும்போது, அது அமைதியாக ஒரு புதிய காலி volume-ஐ உருவாக்கி, database-ஐ காலியாக்கிவிடும். Image இயங்கும் numeric user id-க்கு (அதிகாரப்பூர்வ Postgres, MySQL மற்றும் MongoDB images-க்கு இது 999) host directory-ஐ chown செய்தால் bind mount பயன்படுத்தலாம். இதை ls -ldn மூலம் சரிபார்க்கவும், ஏனெனில் ls -l அந்த எண்ணிற்கான உங்கள் host-ன் பெயரை மட்டுமே காட்டும், அந்தப் பெயர் container-க்குள் அர்த்தமற்றது.

docker compose down -v எதை நீக்கும்?

இது ஒரு சாதாரண down போலவே containers மற்றும் network-ஐ நீக்கும், மேலும் -v அந்த compose file-ல் அறிவிக்கப்பட்ட அனைத்து named volumes மற்றும் அந்த containers-உடன் இணைக்கப்பட்ட அனைத்து anonymous volumes-ஐயும் நீக்கும். இதில் database-ம் அடங்கும். இதற்கு உறுதிப்படுத்தல் (confirmation) கேட்கப்படாது, தரவுகளை மீட்கவும் முடியாது. external: true எனக் குறிக்கப்பட்ட volumes நீக்கப்படாது, இதனால்தான் database volume-ஐ external எனக் குறிப்பிடுவது முக்கியம். வழக்கமான restart-க்கு docker compose stop மற்றும் docker compose start ஆகியவற்றைப் பயன்படுத்தவும்.

Docker-ல் PostgreSQL-ஐ புதிய major version-க்கு எப்படி upgrade செய்வது?

Dump மற்றும் restore செய்யவும். postgres:16-ஐ postgres:17 என மாற்றி restart செய்தால், DETAIL வரியுடன் FATAL: database files are incompatible with server பிழை வரும், ஏனெனில் புதிய binaries பழைய catalog layout-ஐப் படிக்காது. எதற்கும் பாதிப்பு ஏற்படாது: பழைய tag-ஐ மீண்டும் மாற்றினால் அது இயங்கும். இயங்கும் பழைய container-க்கு எதிராக புதிய version-ன் client-ஐப் பயன்படுத்தி pg_dumpall எடுக்கவும், கோப்பு PostgreSQL database cluster dump complete-ல் முடிவடைகிறதா என்பதை உறுதிப்படுத்தவும், பின்னர் புதிய tag-ஐ காலி volume-ல் கொண்டு வந்து dump-ஐ load செய்யவும். ஒரே major version-க்குள் நடக்கும் minor upgrades-க்கு pull மற்றும் restart மட்டுமே போதுமானது.

எனது database container ஏன் code 137-உடன் வெளியேறுகிறது?

137 என்பது 128 மற்றும் signal 9-ன் கூட்டுத்தொகை, எனவே ஏதோ ஒன்று process-ஐ நேரடியாகக் கொன்றுவிட்டது. docker inspect <container> | grep -i oomkilled-ஐ இயக்கவும்; true என்ற மதிப்பு இருந்தால், container அதன் cgroup memory limit-ஐ எட்டிவிட்டது என்று அர்த்தம். PostgreSQL மற்றும் MySQL ஆகியவை host-ன் மொத்த memory-ஐப் படிப்பதும், container-ன் limit-ஐக் கவனிக்காமல் இருப்பதும் இதற்குப் பொதுவான காரணம்; எனவே அவை 2 GB-க்குள் இயங்கும்போது 16 GB-க்குத் திட்டமிடுகின்றன. நீங்கள் container-க்குக் கொடுத்த limit-க்கு ஏற்ப shared_buffers மற்றும் work_mem அல்லது innodb_buffer_pool_size-ஐ அமைக்கவும். Kernel எந்த process-ஐத் தேர்ந்தெடுத்தது என்பதை உறுதிப்படுத்த journalctl -k-ல் உள்ள Memory cgroup out of memory வரியைச் சரிபார்க்கவும்.