SSD Nodes Learn 🎉 VPS החל מ־$5.50/חודש
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-08-13

האם כדאי להריץ מסד נתונים בתוך Docker או על ה-host?

האם להריץ PostgreSQL, MySQL או Redis בתוך Docker? גלו את הסיכונים האמיתיים בניהול volumes, שדרוגי גרסאות, גיבויים והגבלות זיכרון בסביבות production מודרניות.

האם כדאי להריץ את מסד הנתונים בתוך Docker או על ה-host?

מומלץ להריץ את מסד הנתונים בתוך Docker. עבור stack של יישום בודד על שרת VPS, הרצה של PostgreSQL, MySQL, MongoDB או Redis בתוך מכולה (container) היא בחירה מקובלת בסביבות production, והוויכוחים בנושא זה לרוב אינם מתמקדים בנקודות הנכונות. מכולה היא תהליך Linux עם namespaces ו-cgroups, ולא מכונה וירטואלית, לכן אין hypervisor שחוצץ בין מסד הנתונים לבין הדיסק. באמצעות bind mount או local named volume, פעולות קריאה וכתיבה מתבצעות ישירות על מערכת הקבצים של ה-host, בדיוק כפי שהיה קורה בהתקנה רגילה של חבילה.

העלות האמיתית היא תפעולית. ארבעה גורמים קובעים אם הגדרה זו תהיה תקינה או שתוביל לאסון: היכן נשמר המידע, מי הבעלים של אותה תיקייה, כיצד מתבצע שדרוג גרסה מרכזי, והאם אי פעם ביצעת שחזור מגיבוי. אם תטפלו בנקודות אלו נכון, המכולה תהיה פרט טכני בלבד. אם תטפלו בהן בצורה שגויה, המכולה תהיה הגורם שעליו תטילו את האשמה.

זוהי אותה החלטה עבור כל מסד נתונים בשרת. הדוגמאות להלן משתמשות ב-PostgreSQL, MySQL, MongoDB ו-Redis, וההבדלים הספציפיים לכל מוצר מצוינים במקומות הרלוונטיים.

מה מכולה משנה בפועל

לא את נתיב האחסון, כל עוד אתם מבצעים mount לאחד. אותו kernel, אותו page cache, ואותה מערכת קבצים.

ישנו מכשול ביצועים אחד אמיתי, והוא המקרה שבו לא מבצעים mount לכלום. ללא volume, ספריית הנתונים נכנסת לשכבה הניתנת לכתיבה של המכולה, שהיא מערכת קבצים מסוג overlay המונחת על גבי ה-image. כתיבה לשם איטית יותר, והשכבה כולה נמחקת כאשר המכולה מוסרת. מכאן נובעת התופעה של "מסד הנתונים שלי היה ריק הבוקר".

מה משתנה באמת:

  • מחזור החיים. docker compose down משמיד את המכולה. כל מה שלא היה בתוך volume נעלם יחד איתה.
  • הגרסה. ה-image tag הוא הגרסה. אין apt upgrade בתוך מכולת מסד נתונים ששורד את ה-docker compose pull הבא.
  • ניהול זיכרון. מגבלת cgroup היא קיר קשיח שנאכף על ידי ה-kernel, ומסד הנתונים אינו מודע לקיומו.
  • המשתמש. התהליך רץ כ-numeric user id בתוך המכולה, שייתכן שאינו בעלים של דבר במערכת המארחת (host) שלכם.

מיקום הנתונים קובע הכל

קיימות שתי אפשרויות טובות וטעות אחת נפוצה.

  • כרך (volume) בעל שם: pgdata:/var/lib/postgresql/data. Docker יוצר את הספרייה ב-/var/lib/docker/volumes/<project>_pgdata/_data, ונקודת הכניסה (entrypoint) של ה-image מגדירה את הבעלות בהרצה הראשונה. זוהי ברירת המחדל המומלצת.
  • מיפוי ספרייה (bind mount): /srv/appname/pg:/var/lib/postgresql/data. אתה בוחר את הנתיב, ולכן האחריות לבעיות הרשאות היא עליך.
  • ללא מיפוי כלל. ראו לעיל. הנתונים נשמרים בתוך ה-container.

השיקולים המלאים הם נושא בפני עצמו, והמאמר bind mounts against named volumes מכסה אותם. עבור מסד נתונים, התשובה הקצרה היא: השתמשו ב-named volume אלא אם יש לכם סיבה ספציפית להכיר את נתיב ה-host. אם בכל זאת בחרתם ב-bind mount, מקמו אותו במיקום יציב כמו /srv/appname/pg ולא בתוך ספריית הפרויקט, שם git clean עלול לגשת אליו.

מגבלה אחת קשיחה: אל תמקמו ספריית נתונים של מסד נתונים על NFS (או כל מערכת קבצים מרושתת) שאת התנהגות ה-locking וה-fsync שלה לא בדקתם. מסדי נתונים מניחים שפעולת fsync מוצלחת משמעה שהבתים נכתבו לאחסון יציב. כאשר הנחה זו שגויה, נוצר שחיתות נתונים שמתגלה רק שבועות לאחר מכן.

קיבוע שם ה-volume לפני אובדן הנתונים

Docker Compose מעניק ל-volume שם המבוסס על <project>_<volume>, כאשר שם הפרויקט כברירת מחדל הוא שם הספרייה שבה הוא נמצא. לכן, הזהות של ה-volume תלויה בשם הספרייה, דבר שמשתמשים נוטים לשנות מבלי להקדיש לכך מחשבה.

העברה של /srv/app ל-/srv/app-old, או שינוי שם המפתח pgdata בקובץ ה-compose, יגרמו לכך שהפקודה docker compose up -d הבאה תיצור volume חדש וריק. Postgres יאתחל לתוכו cluster חדש. המכולה תהיה תקינה, היישום יעלה, אך כל הטבלאות ייעלמו. החדשות הטובות הן שה-volume הישן עדיין קיים על הדיסק תחת השם הקודם.

docker volume ls
docker volume inspect app_pgdata

קבעו את השמות באופן מפורש כדי למנוע מצב זה. הגדירו את שם הפרויקט ואת שם ה-volume במפורש:

name: myapp

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

volumes:
  pgdata:
    name: myapp_pgdata

אם הנתונים שלכם נמצאים ב-volume שנותר ללא שימוש, העתיקו אותם לאחר עצירת מסד הנתונים:

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

העתקה בזמן שמסד הנתונים פעיל תוביל לעותק פגום של קבצים שנכתבו באותו רגע. עצרו את השירות תחילה.

למי שייכת ספריית הנתונים

הדימויים הרשמיים של Postgres, MySQL ו-MongoDB מריצים את השרת שלהם כמשתמש ללא הרשאות מיוחדות, בדרך כלל עם ה-ID‏ 999. כאשר המכולה מתחילה כ-root, נקודת הכניסה (entrypoint) משנה את הבעלות על ספריית הנתונים למשתמש זה ואז מוותרת על ההרשאות. זו הסיבה ש-bind mount ריק עובד בדרך כלל בניסיון הראשון.

התהליך נכשל ברגע שמגדירים user: בקובץ ה-compose, כיוון שאז לנקודת הכניסה אין הרשאות לבצע שינויים. Postgres מדווח על כך ישירות:

initdb: error: could not change permissions of directory "/var/lib/postgresql/data": Operation not permitted

ספריית נתונים שקיימת עם הרשאות שגויות מציגה הודעה שונה, וכדאי להכיר אותה כי הפתרון הוא 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).

MongoDB על גבי bind mount בבעלות root נכשל בעת יצירת קובץ הנעילה (lock file):

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.

הפתרון הוא להריץ chown על ספריית המארח (host) לפי ה-ID המספרי, ולא לפי שם משתמש:

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

הפקודה ls -ldn מציגה מספרים במקום שמות, והיא אמורה להציג 999 999. החשבון שנקרא postgres במארח שלכם והחשבון שנקרא postgres בתוך המכולה אינם קשורים: ה-kernel משווה מספרים, והשמות נבדקים בנפרד בכל צד. המדריך כיצד PUID ו-PGID ממפים משתמשי מארח לתוך מכולה מסביר את המיפוי הזה כראוי. תחת Docker ללא root או מיפוי מחדש של מרחב שמות משתמש (user namespace), המספרים משתנים שוב, לכן מומלץ לקרוא את ה-IDs מהמכולה הרצה במקום להניח שמדובר ב-999.

שימוש ב-named volumes מבטל את הצורך בכל הסעיף הזה בהרצה הראשונה, כיוון ש-Docker יוצר ספרייה ריקה ונקודת הכניסה מקבלת עליה בעלות באופן אוטומטי.

שדרוגים: שדרוג חבילה מול שינוי תגית Image

במערכת ההפעלה המארחת, apt upgrade מעביר אתכם בין גרסאות משנה. ההפצה שלכם לא תקפיץ גרסה ראשית של מסד נתונים ללא ידיעתכם, וכאשר תבחרו לבצע קפיצה כזו, ניתן להתקין את שתי קבוצות הבינאריים בו-זמנית, וזה בדיוק מה ש-pg_upgrade דורש.

במכולה (container), התגית היא הגרסה, לכן שדרוג מסתכם בעריכת שורה אחת. זה הופך שדרוגי משנה לעניין טריוויאלי ושדרוגים ראשיים להליך מובנה.

שנו את 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 והיא תעלה שוב. ה-rollback הזה הוא היתרון האמיתי היחיד שקונטיינרים מעניקים לכם בשדרוגים.

הנתיב הנתמך הוא גיבוי (dump) ושחזור. PostgreSQL מעדיפה שהגיבוי יבוצע על ידי הלקוח החדש, לכן הריצו אותו מה-image החדש כנגד השרת הישן שעדיין רץ ברשת ה-compose:

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. קובץ של כמה מאות בתים בלבד מעיד על כך שהגיבוי נכשל ואתם עומדים למחוק 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

מנועים אחרים פועלים אחרת:

  • MySQL 8 משדרגת את מילון הנתונים שלה בעת העלייה, לכן הקפצת תגית משנה היא בדרך כלל רק הפעלה מחדש. קראו את הערות השחרור לפני קפיצה בין סדרות גרסאות, ובכל מקרה בצעו גיבוי תחילה.
  • MariaDB מצפה ש-mariadb-upgrade יורץ לאחר שהשרת עולה בגרסה החדשה.
  • MongoDB חייבת לעבור שדרוג גרסה ראשית אחת בכל פעם, ולאחר כל שלב עליכם להגדיר את גרסת תאימות התכונות (feature compatibility version) לפני שממשיכים. דילוג על גרסה גורם ל-mongod לסרב לעלות ולרשום שורת UPGRADE PROBLEM המציינת את featureCompatibilityVersion. החל מ-MongoDB 7.0 ואילך, הפקודה דורשת דגל אישור מפורש: db.adminCommand({ setFeatureCompatibilityVersion: "8.0", confirm: true }).
  • Redis טוענת קובצי snapshot ישנים ללא בעיה, אך לא קבצים חדשים יותר, לכן שדרוג הוא הפעלה מחדש, ושנמוך (downgrade) עלול להיכשל בטעינת הנתונים.

הכלל הכללי: קונטיינר הופך שנמוך לקל, אך לא הופך שדרוג לקל יותר.

מדוע מכולת מסד הנתונים שלי קורסת עם קוד 137?

הסיבה היא שה-OOM killer (מנגנון הריגת תהליכים עקב מחסור בזיכרון) של ה-kernel הרג את התהליך. הקוד 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 מכיל רשומה תואמת:

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

זהו המנגנון, והוא מפתיע משתמשים רבים. PostgreSQL ו-MySQL קובעים את גודל ה-buffers שלהם לפי הזיכרון הכולל שהמארח מדווח עליו. מגבלת 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 cache במפורש במקום לתת לו לנחש לפי זיכרון המארח.
  • Redis: הערך maxmemory הוא ללא הגבלה כברירת מחדל, לכן Redis יגדל עד שה-cgroup יעצור אותו. הגדירו את 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

הריגת backend אחד מאלצת את כל שאר ה-backends לבצע אתחול, כיוון שהזיכרון המשותף עלול להיות כעת במצב לא עקבי. זהו "מבול חיבורים" (connection storm) עבור היישום שלכם, ולא אירוע שקט. המדריך הגדרת מגבלות זיכרון ב-Docker Compose מכסה את התחביר ואת ההבדל בין mem_limit לבין הצורה deploy.resources.

שום דבר מזה לא נעלם במארח; הוא רק עובר מקום. ללא cgroup, מסד הנתונים מתחרה על משאבים עם כל שאר התהליכים במכונה, וה-OOM killer של המארח בוחר קורבן לפי ניקוד, מה שעלול להיות תהליך ה-sshd. מגבלה שהורגת את מסד הנתונים בצורה צפויה קלה יותר לניהול מאשר OOM של המארח שנועל אתכם מחוץ למערכת.

גיבויים: בצעו dump בפנים, גבו בחוץ

אל תגבו מסד נתונים פעיל על ידי העתקת ספריית הנתונים שלו. העתקה ברמת הקובץ בזמן שהשרת כותב נתונים יוצרת עותק פגום (torn copy), ואתם תגלו זאת רק ברגע השחזור.

ישנן שתי שיטות אמינות: ביצוע dump באמצעות הכלי הייעודי של מסד הנתונים בזמן שהוא רץ וגיבוי ה־dump, או עצירת המכולה והעתקת ה־volume במצב קר (cold).

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 עלול לחבר טרמינל לפקודה, ושכבת הטרמינל מוסיפה תווי ירידת שורה (carriage returns) לזרם הפלט. כתוצאה מכך, dump טקסטואלי ישוחזר עם שגיאות מוזרות, ו-dump בינארי פשוט יהיה מושחת. הכשל הזה מתרחש בשקט בזמן הגיבוי, ומתגלה בקול רעש גדול חודש לאחר מכן.

השימוש ב---single-transaction מעניק ל-mysqldump תמונת מצב (snapshot) עקבית של טבלאות InnoDB מבלי לנעול את השרת כולו.

פקודות אלו כותבות קובץ אחד בלבד בכל הרצה. הן אינן מהוות מערכת גיבוי: אין בהן ניהול תקופת שמירה (retention), אין העתקה מחוץ לשרת, ואין אימות. העבירו את ספריית ה-dump לכלי שמבצע את שלושת אלו, וזהו בדיוק הייעוד של גיבויי restic משרת VPS. גבו את /srv/backups, לא את /var/lib/docker/volumes.

לאחר מכן, בצעו שחזור, כיוון שגיבוי שמעולם לא שוחזר אינו נחשב לגיבוי:

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., מעידים על כך שה-dump אינו מה שחשבתם. מחקו את restore_test לאחר שתסיימו.

הפקודה שמוחקת הכול

docker compose down -v.

הפקודה down מסירה את המכולות ואת הרשת. הפקודה -v מסירה בנוסף כל volume בעל שם שהוגדר בקובץ ה-compose, וכל volume אנונימי שמחובר למכולות אלו. אין בקשת אישור ואין אפשרות לבטל את הפעולה. זו הדרך הנפוצה ביותר שבה מסד נתונים של שירות עצמי נמחק, וזה קורה בדרך כלל במהלך פתרון בעיות שאינן קשורות, כי תשובה בפורום הורתה להריץ אותה.

ארבעה דברים מצמצמים את טווח הנזק:

  • הגדירו את ה-volume של מסד הנתונים כ-external: true. ‏Compose לא יסיר volume שהוא לא הבעלים שלו, לכן -v לא יוכל להגיע אליו. יוצרים אותו פעם אחת באמצעות docker volume create myapp_pgdata.
  • השתמשו ב-docker compose stop וב-docker compose start לצורך אתחולים שגרתיים. המאמר down לעומת stop ב-Compose מפרט מה כל אחת מהן מסירה.
  • שמרו גיבויים (dumps) בנתיב על ה-host מחוץ לכל volume ש-Compose מנהל.
  • לעולם אל תדביקו -v מתוך תשובה בפורום לתוך stack שמכיל נתונים שחשובים לכם.

אל תפרסמו את פורט מסד הנתונים

השורה הבאה חושפת את מסד הנתונים שלכם לאינטרנט הציבורי:

    ports:
      - "5432:5432"

היא מבצעת bind לכל ממשקי הרשת. Docker מפרסם פורט על ידי כתיבה מחדש של יעד החבילה (packet) עוד לפני שחוקי ה-input של ה-firewall שלכם רואים אותה, ומכיוון שחוקי ufw יושבים בשרשרת ה-input, הפקודה ufw deny 5432 אינה עושה דבר. המאמר מדוע פורטים שמפורסמים על ידי Docker עוקפים את ufw מציג את מסלול המעבר בשרשראות ה-iptables.

יישום הנמצא באותו פרויקט compose ניגש למסד הנתונים לפי שם השירות ברשת ה-compose הפנימית, ולכן אין צורך בפורט מפורסם. מחקו את הבלוק. אם אתם זקוקים לגישה מלקוח הנמצא על ה-host, בצעו bind ל-loopback בלבד:

    ports:
      - "127.0.0.1:5432:5432"

בדקו מה באמת מאזין:

sudo ss -ltnp | grep 5432

הערך 127.0.0.1:5432 הוא מה שאתם רוצים לראות. הערך 0.0.0.0:5432 משמעו שכל אחד יכול לנסות לפרוץ את הסיסמה שלכם.

מה להריץ ואיפה

יישום אחד על VPS אחד. השתמשו ב-Container. הגדירו volume בעל שם קבוע, ללא חשיפת פורטים, עם הגבלת זיכרון שתואמת להגדרות מסד הנתונים, ועם גיבוי לילי לנתיב במערכת ההפעלה המארחת ש-restic אוסף. התחילו מ-התקנת Docker נקייה על VPS ושמרו את כל ה-stack בקובץ compose אחד שאתם מבצעים לו commit. היתרון משמעותי: גרסת מסד הנתונים הופכת לשורה הניתנת לסקירה ב-git.

שרת המריץ כמה שירותים. השתמשו ב-Containers, עם מסד נתונים נפרד לכל יישום, ולא בשרת אחד משותף לכולם. שרת משותף כובל את כל היישומים ללוח זמנים אחד של שדרוגים, ושאילתה בעייתית אחת עלולה להפיל את כל השירותים. הגבילו את הזיכרון לכל container בנפרד, כך ששאילתה חריגה תישאר מוגבלת ליישום שיצר אותה. כמה מופעי Postgres קטנים דורשים מעט יותר שטח דיסק, אך חוסכים משמעותית בתיאום וניהול.

מסד הנתונים הוא המוצר. הריצו אותו על השרת מתוך מאגר החבילות הרשמי של הספק, או השתמשו בשירות מנוהל. pg_upgrade דורש התקנה של שתי גרסאות major של הקבצים הבינאריים בו-זמנית, דבר שחבילות מאפשרות בעוד ש-image של גרסה יחידה לא. שכפול (replication) ושחזור לנקודת זמן (point in time recovery) באמצעות ארכוב WAL (write ahead log) קלים יותר כאשר מסד הנתונים מנהל את המכונה ואת הדיסקים שלה. בחרו בדרך השמרנית והיציבה עבור מערכת שעלולה להקפיץ אתכם מהמיטה ב-03:00.

היישום קטן. שקלו לא להריץ מסד נתונים שרת כלל. עבור יישום web עם כותב יחיד על VPS אחד, לעיתים קרובות עדיף להשתמש ב-SQLite בסביבת production על VPS, שם הגיבוי הוא קובץ אחד ונתיב השדרוג הוא גרסת ספרייה.

FAQ

האם בטוח להריץ מסד נתונים בסביבת Production בתוך Docker?

כן, עבור מחסנית יישומים בשרת בודד. מכולה היא תהליך Linux עם namespaces ו-cgroups סביבו, לכן עם volume ממופה, מסד הנתונים כותב לאותה מערכת קבצים מארחת שבה היה משתמש אילו הותקן מחבילה. הסיכונים הם תפעוליים ולא קשורים למהירות: volume ששמו לא קבוע, bind mount בבעלות מזהה משתמש שגוי, או שחזור שמעולם לא נבדק, ו-docker compose down -v. פתרו את ארבעת אלו והמכולה תהיה תקינה. עברו להתקנה ישירה על המארח כאשר מסד הנתונים הוא עומס העבודה העיקרי ואתם זקוקים ל-pg_upgrade, שכפול (replication) או שחזור לנקודת זמן מסוימת.

האם להשתמש ב-bind mount או ב-named volume עבור נתוני מסד הנתונים?

השתמשו ב-named volume אלא אם יש לכם סיבה ספציפית להכיר את הנתיב במארח. Docker יוצר את הספרייה ונקודת הכניסה (entrypoint) של ה-image מגדירה בעלות בהפעלה הראשונה, כך שבעיית הרשאות לעולם לא מופיעה. קבעו את ה-volume עם name: מפורש או סמנו אותו כ-external: true, אחרת שינוי שם ספריית הפרויקט ייצור בשקט volume חדש וריק ומסד נתונים ריק. bind mount הוא תקין אם מבצעים chown לספריית המארח למזהה המשתמש המספרי שבו ה-image רץ, שהוא 999 עבור ה-images הרשמיים של Postgres, MySQL ו-MongoDB. אמת זאת עם ls -ldn, כיוון ש-ls -l מציג את שם המשתמש במארח עבור מספר זה, ושם זה חסר משמעות בתוך המכולה.

מה docker compose down -v מוחק?

הוא מסיר את המכולות ואת הרשת כמו down רגיל, ו--v מסיר בנוסף כל named volume שהוצהר בקובץ ה-compose יחד עם כל anonymous volume שמחובר למכולות אלו. זה כולל את מסד הנתונים. אין הודעת אישור ואין אפשרות שחזור. volumes המסומנים כ-external: true אינם מוסרים, וזו הסיבה העיקרית לסמן volume של מסד נתונים כ-external. עבור הפעלה מחדש שגרתית השתמשו ב-docker compose stop וב-docker compose start במקום.

כיצד לשדרג PostgreSQL לגרסה ראשית חדשה ב-Docker?

בצעו dump ושחזור. שינוי postgres:16 ל-postgres:17 והפעלה מחדש יגרמו ל-FATAL: database files are incompatible with server עם שורת DETAIL המציינת את שתי הגרסאות, כיוון שהקבצים הבינאריים החדשים לא יקראו את מבנה הקטלוג הישן. דבר לא ניזוק: החזירו את ה-tag הישן והוא יעלה. בצעו pg_dumpall באמצעות ה-client של הגרסה החדשה מול המכולה הישנה שרצה, ודאו שהקובץ מסתיים ב-PostgreSQL database cluster dump complete, לאחר מכן העלו את ה-tag החדש על volume ריק וטענו את ה-dump. שדרוגים משניים בתוך גרסה ראשית דורשים רק pull והפעלה מחדש.

מדוע מכולת מסד הנתונים שלי יוצאת עם קוד 137?

137 הוא 128 ועוד אות 9, לכן משהו הרג את התהליך באופן מיידי. הריצו docker inspect <container> | grep -i oomkilled; ערך של true אומר שהמכולה הגיעה למגבלת הזיכרון של ה-cgroup שלה. הסיבה הרגילה היא ש-PostgreSQL ו-MySQL קוראים את סך הזיכרון מהמארח ולעולם לא רואים את המגבלה של המכולה, לכן הם מתכננים ל-16 GB בזמן שהם חיים בתוך 2 GB. הגדירו shared_buffers ו-work_mem, או innodb_buffer_pool_size, כדי להתאים למגבלה שהקציתם למכולה. בדקו את journalctl -k עבור שורת Memory cgroup out of memory התואמת כדי לאשר איזה תהליך ה-kernel בחר להרוג.