SSD Nodes Learn RAM 8GB — $66/tahun
Panduan Matt ConnorOleh Matt Connor · Dikemas kini 2026-08-01

Had Memori Docker Compose untuk Elak OOM

Tetapkan had memori dan CPU dalam Docker Compose supaya satu bekas tidak menjatuhkan VPS. Bandingkan deploy.resources, mem_limit, swap dan kod keluar 137.

Kesan had memori Docker Compose

Had memori Docker Compose ialah had keras yang ditetapkan oleh kernel Linux pada cgroup (kumpulan kawalan, iaitu ciri kernel yang mengukur sumber untuk sekumpulan proses) satu bekas. Tetapkan deploy.resources.limits.memory pada sesuatu perkhidmatan, dan bekas itu tidak boleh menggunakan memori melebihi nilai yang anda tulis. Apabila cuba melebihinya, kernel akan menghentikan proses dalam bekas tersebut, dan bekas biasanya keluar dengan kod 137.

Hal ini paling penting pada VPS, kerana jumlah RAM adalah tetap dan tiada memori hos tambahan untuk digunakan. Satu bekas yang mengalami kebocoran memori atau menjalankan pertanyaan yang bermasalah boleh menggunakan setiap halaman memori yang tersedia pada pelayan 8GB. Kernel kemudian menghentikan proses yang dianggap paling bermasalah, yang sering kali merupakan pangkalan data atau sesi SSH anda, bukannya bekas yang menyebabkan masalah. Had menukarkan gangguan keseluruhan pelayan kepada satu perkhidmatan yang boleh dimulakan semula.

services:
  app:
    image: ghcr.io/example/app:1.4
    deploy:
      resources:
        limits:
          cpus: "1.5"
          memory: 1g
        reservations:
          memory: 256m

Gunakan tetapan tersebut dan sahkan bahawa had itu aktif:

docker compose up -d
docker stats --no-stream

Lajur MEM USAGE / LIMIT sepatutnya memaparkan sesuatu seperti 142MiB / 1GiB. Jika lajur had menunjukkan keseluruhan RAM hos, tetapan itu tidak diterapkan dan panduan seterusnya tidak akan membantu sehingga tetapan tersebut diterapkan. Jika fail compose masih baharu bagi anda, asas Docker Compose untuk VPS menerangkan susun atur fail yang menjadi asas kepada panduan ini.

deploy.resources.limits atau mem_limit: yang manakah terpakai

Dua ejaan wujud untuk idea yang sama. Oleh itu, perkara ini mengelirukan.

mem_limit, mem_reservation, memswap_limit, cpus dan cpu_shares ialah kunci perkhidmatan peringkat teratas yang diwarisi daripada format fail Compose lama. deploy.resources berasal daripada skema Swarm dan kini merupakan sebahagian daripada Compose Specification, iaitu format yang dibaca oleh docker compose pada masa ini.

Kedua-duanya berfungsi pada satu hos. Compose V2, iaitu pemalam docker compose, menggunakan deploy.resources.limits dan deploy.resources.reservations apabila anda menjalankan docker compose up, tanpa sebarang kelompok Swarm. Bahagian deploy yang hanya digunakan oleh Swarm ialah kunci lain: mode, placement, update_config dan endpoint_mode mempunyai makna untuk docker stack deploy dan diabaikan oleh docker compose up. Oleh itu, nasihat umum bahawa "deploy memerlukan Swarm" adalah salah untuk subseksyen resources. Jika nasihat itu diikuti, perkhidmatan anda tidak mempunyai had langsung.

Pilih satu ejaan bagi setiap projek. Menulis mem_limit: 512m dan deploy.resources.limits.memory: 1g pada perkhidmatan yang sama menghasilkan fail yang sukar difahami dengan sekali pandang. Daripada meneka nombor yang digunakan, tanya daemon:

docker inspect --format '{{.HostConfig.Memory}} {{.HostConfig.MemoryReservation}} {{.HostConfig.NanoCpus}}' app-1

Nilai memori adalah dalam bait, jadi 1g memaparkan 1073741824. CPU dinyatakan dalam nano CPU, jadi 1.5 memaparkan 1500000000. Nilai 0 dalam mana-mana medan bermaksud tiada had ditetapkan. Had memori minimum yang diterima oleh Docker ialah 6m. Jika nilainya lebih rendah, kontena tidak dapat dimulakan.

Perkara yang berlaku apabila bekas mencapai had

Bekas tidak menjadi perlahan. Bekas terhenti.

Apabila proses meminta halaman memori dan cgroup sudah mencapai memory.max, kernel terlebih dahulu mendapatkan semula apa yang boleh digunakan dalam cgroup itu: cache halaman bersih, kemudian halaman yang boleh ditukar ke ruang swap. Jika proses mendapatkan semula memori tidak membebaskan ruang yang mencukupi, pembunuh OOM (kehabisan memori) cgroup memilih satu proses dalam bekas dan menghantar SIGKILL kepadanya. Menamatkan PID 1 bekas akan menamatkan bekas itu. Kod keluar 137 hanyalah 128 ditambah isyarat 9, jadi 137 ialah tanda bagi mana-mana SIGKILL, bukan bukti bahawa OOM berlaku.

docker compose ps -a
docker inspect --format '{{.State.OOMKilled}} {{.State.ExitCode}}' app-1

true 137 ialah penamatan oleh OOM. false 137 bermaksud sesuatu yang lain menghantar SIGKILL, dan punca lazimnya ialah docker compose stop mencapai tempoh kelonggaran sepuluh saat kerana aplikasi mengabaikan SIGTERM. Perbezaan ini menjimatkan masa berjam-jam kerana kedua-dua masalah itu tiada kaitan.

Dua lagi tempat merekodkan peristiwa ini. Pantau daemon secara langsung:

docker events --filter event=oom

Kemudian baca log kernel, iaitu rekod yang kekal selepas mula semula:

sudo dmesg -T | grep -i -E 'memory cgroup out of memory|killed process'

Penamatan oleh cgroup mencetak baris yang bermula dengan Memory cgroup out of memory: Killed process 24713 (node). Baris tanpa awalan Memory cgroup ialah OOM hos, yang bermaksud mesin itu sendiri kehabisan RAM. Inilah kegagalan yang sepatutnya dicegah oleh had. Jika anda melihatnya, jumlah had anda terlalu tinggi atau sesetengah perkhidmatan langsung tiada had.

Dengan restart: unless-stopped, gelung OOM mudah tersembunyi kerana perkhidmatan kelihatan aktif dalam docker compose ps sesaat selepas terhenti. Semak lajur uptime dan bilangan mula semula. Padankan had itu dengan healthcheck yang melaporkan aplikasi sebagai tidak sihat supaya bekas yang terus terhenti dapat dilihat tanpa perlu anda memantaunya.

Reservation ialah petunjuk, had ialah peraturan

reservations.memory (mem_reservation yang lebih lama) ialah paras bawah lembut. Docker menerangkannya sebagai had lembut yang diaktifkan apabila daemon mengesan persaingan sumber atau memori rendah pada hos. Ia tidak pernah menghalang container daripada melebihinya dan tidak pernah menjamin memori itu tersedia apabila container memintanya. Ia hanya mempengaruhi kernel supaya terlebih dahulu menuntut semula memori daripada container yang melebihi reservation.

Oleh itu, reservation tidak melindungi apa-apa dengan sendirinya. Gunakannya untuk menandakan perkhidmatan yang perlu diberi keutamaan apabila sumber terhad, dan bergantung pada limit untuk keselamatan. Pastikan reservation lebih rendah daripada limit, atau container tidak akan bermula: Docker menolak konfigurasi dengan Minimum memory limit can not be less than memory reservation limit.

Swap secara tepat

Kebanyakan imej VPS disediakan tanpa fail swap. Jalankan swapon --show dan free -h. Jika jumlah swap ialah sifar, semua tetapan berkaitan swap di bawah tidak berkesan, dan had memori anda hanyalah had RAM.

memswap_limit bukan jumlah swap. Nilai itu ialah jumlah memori dan swap. Dengan mem_limit: 1g dan memswap_limit: 2g, kontena mendapat 1GB RAM dan 1GB swap. Menetapkan kedua-dua nilai kepada nilai yang sama menyebabkan kontena tidak mempunyai swap. Menetapkan mem_limit dan membiarkan memswap_limit tidak ditetapkan membolehkan kontena menggunakan swap sehingga saiz had memorinya sekali lagi.

Ubuntu 24.04 dan Debian 13 menggunakan cgroup v2 secara lalai. Dalam versi ini, swap ialah pembilang berasingan (memory.swap.max) dan fungsi ini beroperasi tanpa persediaan tambahan. Mesej lama Your kernel does not support swap limit capabilities berasal daripada hos cgroup v1 yang dibut tanpa swapaccount=1. Pada hos tersebut, had memori masih berkuat kuasa, manakala bahagian swap diabaikan.

Jelaskan manfaat swap dengan tepat. Swap menyebabkan pembunuhan proses OOM menjadi lebih lambat, bukan kurang berkemungkinan berlaku, kerana proses yang mengalami kebocoran memori akan memenuhi swap sama seperti memenuhi RAM. Sementara itu, kontena yang menggunakan swap secara berlebihan pada storan VPS dikongsi akan memperlahankan setiap perkhidmatan lain pada pelayan tersebut. Untuk apa-apa yang sensitif terhadap kependaman, had yang betul tanpa swap akan gagal dengan lebih cepat dan lebih boleh dijangka.

Mengapa penggunaan memori kelihatan lebih tinggi daripada keadaan sebenar

Angka MEM USAGE dalam docker stats merangkumi cache halaman. Oleh itu, kontena yang membaca fail besar akan meningkat hingga menghampiri hadnya dan kekal pada tahap itu. Keadaan ini normal dan bukan kebocoran, kerana cache bersih akan dituntut semula sebelum pembunuh OOM dipanggil. Perkhidmatan seperti pelayan media Jellyfin yang dihoskan sendiri akan kelihatan sentiasa hampir dengan hadnya atas sebab ini.

Pisahkan angka tersebut kepada cache dan set kerja sebenar dari dalam kontena:

docker compose exec app grep -E '^(anon|file) ' /sys/fs/cgroup/memory.stat
docker compose exec app cat /sys/fs/cgroup/memory.events

anon ialah memori tanpa nama, iaitu set kerja yang tidak boleh digugurkan. file ialah cache halaman, yang boleh dituntut semula. Tetapkan had berdasarkan anon ditambah margin, bukan berdasarkan jumlah keseluruhan. Fail memory.events mengesahkan keadaan ini dengan jelas: pembilang oom_kill yang lebih besar daripada sifar bermakna kernel telah mematikan sesuatu dalam kontena ini sejak kontena bermula, manakala pembilang max yang meningkat bermakna kontena sedang ditahan pada hadnya sekarang. Kedua-dua arahan memerlukan shell dan coreutils dalam imej. Oleh itu, arahan tersebut gagal pada imej distroless atau scratch.

Had saiz pada VPS 8GB

Mulakan dengan hos, bukan aplikasi. Pada VPS 8GB, peruntukkan kira-kira 1GB untuk kernel, daemon Docker, sshd, journald dan shell log masuk anda. Ini meninggalkan kira-kira 7GB untuk diagihkan, dan jumlah had semua kontena hendaklah kekal di bawah nilai tersebut. Peruntukan berlebihan mungkin berfungsi sehingga dua perkhidmatan mencapai penggunaan puncak pada masa yang sama.

Pembahagian yang sesuai pada mesin 8GB:

  • Proksi songsang: had 128m. Proses ini kecil, dan had yang ketat seperti ini akan mengesan pemuatan semula konfigurasi yang tidak terkawal dengan segera.
  • PostgreSQL: had 2g, dengan shared_buffers ditetapkan kepada kira-kira 512MB dalam konfigurasi pangkalan data.
  • Kontena aplikasi: had 1g.
  • Pekerja latar belakang: had 512m.
  • Perkhidmatan media atau fail: had 2g, yang sebahagian besarnya akan digunakan sebagai cache halaman.

Jangan salin nombor tersebut ke dalam tindanan anda sendiri. Jalankan perkhidmatan di bawah beban sebenar selama sehari, pantau docker stats, catat nilai anon puncak bagi setiap kontena dan tambahkan kira-kira separuh daripada nilai tersebut sebagai ruang lebihan. Had yang ditetapkan terlalu ketat lebih buruk daripada tiada had, kerana had itu akan menghentikan perkhidmatan yang sihat semasa lonjakan trafik biasa.

Satu perangkap perlu diberi perhatian khusus. Kebanyakan runtime tidak mengetahui had tersebut melainkan anda memberitahunya. PostgreSQL akan menetapkan saiz shared_buffers dan work_mem melebihi had kontenanya, lalu prosesnya dihentikan. JVM (mesin maya Java) memerlukan -XX:MaxRAMPercentage=75 untuk menetapkan saiz heap berdasarkan had cgroup, bukan berdasarkan RAM hos. Node.js memerlukan --max-old-space-size dalam megabait, yang ditetapkan di bawah had kontena; jika tidak, pemungut sampahnya membenarkan heap berkembang sehingga kernel mengambil tindakan. cgroup tidak berunding. Ia menghentikan proses.

Had CPU berkelakuan dengan cara yang sama sekali berbeza

cpus: "1.5" bermaksud 150% daripada satu teras, yang dikuatkuasakan sebagai kuota CFS (completely fair scheduler). Container mendapat 150ms masa CPU dalam setiap tempoh 100ms, yang dikongsi oleh semua threadnya. Apabila masa itu habis digunakan, kernel memaksanya menunggu sehingga tempoh seterusnya.

Itulah perbezaan pentingnya. Container yang melebihi had memorinya akan dihentikan. Container yang melebihi had CPU akan dihadkan dan terus berjalan dengan lebih perlahan. Oleh itu, had CPU selamat untuk ditetapkan secara agresif, manakala had memori memerlukan ruang lebihan.

cpu_shares ialah alat yang berbeza: pemberat relatif yang hanya penting apabila CPU benar-benar tepu. Dua container dengan shares sebanyak 1024 dan 512 membahagikan teras yang sibuk pada nisbah kira-kira dua kepada satu. Pada sistem yang tidak sibuk, kedua-duanya tidak dihadkan. Gunakan shares untuk menyusun keutamaan perkhidmatan, dan gunakan cpus apabila anda memerlukan had sebenar, contohnya untuk menghalang kerja transkod malam daripada menggunakan semua sumber CPU sehingga pelayan web anda terjejas.

FAQ

Adakah deploy.resources.limits berfungsi tanpa Docker Swarm?

Ya. Compose V2 menggunakan deploy.resources.limits dan deploy.resources.reservations apabila anda menjalankan docker compose up pada hos tunggal. Sahkan dengan docker inspect --format '{{.HostConfig.Memory}}' <container>, yang mencetak had dalam bait dan mencetak 0 apabila tiada had digunakan. Kekunci dalam deploy yang benar-benar memerlukan Swarm ialah mode, placement, update_config dan endpoint_mode.

Apakah maksud kod keluar 137 dalam Docker Compose?

Maksudnya proses utama menerima SIGKILL, kerana 137 ialah 128 ditambah isyarat 9. Pembunuh OOM kernel ialah punca yang lazim, tetapi tamat masa penutupan menghasilkan kod yang sama apabila aplikasi mengabaikan SIGTERM. Jalankan docker inspect --format '{{.State.OOMKilled}} {{.State.ExitCode}}' <container> untuk membezakan kedua-duanya. true 137 ialah pembunuhan akibat memori, manakala false 137 bukan.

Patutkah saya menetapkan mem_limit atau deploy.resources.limits.memory?

Kedua-duanya berfungsi dengan docker compose. deploy.resources.limits.memory ialah bentuk semasa Compose Specification dan merupakan pilihan lalai yang lebih baik untuk fail baharu. Kekalkan mem_limit jika bahagian lain fail anda sudah menggunakan kekunci peringkat atas yang lebih lama. Menetapkan kedua-duanya pada satu perkhidmatan hanya menyukarkan pembacaan fail, jadi pilih satu dan sahkan hasilnya dengan docker inspect.

Mengapakah kontena saya menggunakan had memori sepenuhnya tanpa dihentikan?

Angka penggunaan dalam docker stats termasuk cache halaman, yang akan dibuang oleh kernel apabila berlaku tekanan, bukannya mencetuskan pembunuhan OOM. Jalankan docker compose exec <service> grep -E '^(anon|file) ' /sys/fs/cgroup/memory.stat dan baca nilai anon, iaitu set kerja yang tidak boleh dituntut semula. Nilai file yang tinggi bersebelahan nilai anon yang rendah menunjukkan kontena sedang melakukan input dan output cakera, bukan kontena yang hampir dihentikan.

Berapakah RAM yang patut saya biarkan tidak diperuntukkan pada VPS 8GB?

Biarkan kira-kira 1GB untuk kernel, daemon Docker, sshd, journald dan shell anda sendiri. Kemudian kekalkan jumlah semua had kontena di bawah baki 7GB. Pantau nilai puncak anon bagi setiap kontena di bawah beban sebenar selama sehari sebelum anda menetapkan nilai, dan anggap jumlah itu sebagai belanjawan, bukan sasaran yang perlu diisi.