[{"data":1,"prerenderedAt":702},["ShallowReactive",2],{"mdc--rupt5i-key":3,"mdc-jhqfge-key":16,"mdc-iug1w1-key":51,"mdc--izft3a-key":89,"mdc--ey0urt-key":295,"mdc--waw90t-key":306,"mdc--52ln26-key":373,"mdc--2cpuin-key":392,"mdc--78tr4d-key":438,"mdc--wivm4m-key":448,"mdc--h6d8lx-key":547,"mdc-dzfcjl-key":559},{"data":4,"body":5},{},{"type":6,"children":7},"root",[8],{"type":9,"tag":10,"props":11,"children":12},"element","p",{},[13],{"type":14,"value":15},"text","Two things you will do more than anything else once you actually depend on Docker: work out why a container is not behaving, and stop Docker eating the disk. Neither is difficult; both go faster if you know which command answers which question.",{"data":17,"body":18},{},{"type":6,"children":19},[20,27,40],{"type":9,"tag":21,"props":22,"children":24},"h2",{"id":23},"the-four-commands-that-answer-most-questions",[25],{"type":14,"value":26},"The four commands that answer most questions",{"type":9,"tag":28,"props":29,"children":33},"pre",{"className":30,"code":32,"language":14},[31],"language-text","docker logs -f --tail 100 web       # what did it print?\ndocker inspect web                  # how was it configured?\ndocker stats                        # what is it consuming, live?\ndocker events                       # what is the daemon doing right now?\n",[34],{"type":9,"tag":35,"props":36,"children":38},"code",{"__ignoreMap":37},"",[39],{"type":14,"value":32},{"type":9,"tag":10,"props":41,"children":42},{},[43,49],{"type":9,"tag":35,"props":44,"children":46},{"className":45},[],[47],{"type":14,"value":48},"inspect",{"type":14,"value":50}," returns a wall of JSON, which is why it takes a format string:",{"data":52,"body":53},{},{"type":6,"children":54},[55,60],{"type":9,"tag":56,"props":57,"children":59},"terminal-teaser",{":lines":58},"[{\"cmd\":\"docker inspect -f '{{.State.Status}} {{.State.ExitCode}}' web\",\"out\":\"exited 137\"},{\"cmd\":\"docker inspect -f '{{.State.OOMKilled}}' web\",\"out\":\"true\"},{\"cmd\":\"docker inspect -f '{{json .NetworkSettings.Networks}}' web\",\"out\":\"{\\\"appnet\\\":{\\\"IPAddress\\\":\\\"172.19.0.3\\\",\\\"Aliases\\\":[\\\"web\\\"]}}\"}]",[],{"type":9,"tag":10,"props":61,"children":62},{},[63,65,71,73,79,81,87],{"type":14,"value":64},"That first pair is a complete diagnosis. ",{"type":9,"tag":66,"props":67,"children":68},"strong",{},[69],{"type":14,"value":70},"Exit code 137 is 128 + 9",{"type":14,"value":72},", meaning the process was killed with ",{"type":9,"tag":35,"props":74,"children":76},{"className":75},[],[77],{"type":14,"value":78},"SIGKILL",{"type":14,"value":80},", and ",{"type":9,"tag":35,"props":82,"children":84},{"className":83},[],[85],{"type":14,"value":86},"OOMKilled: true",{"type":14,"value":88}," says the kernel did it for exceeding a memory limit. No log line, no stack trace — the process was not asked to stop, it was stopped.",{"data":90,"body":91},{},{"type":6,"children":92},[93,99,262],{"type":9,"tag":21,"props":94,"children":96},{"id":95},"reading-exit-codes",[97],{"type":14,"value":98},"Reading exit codes",{"type":9,"tag":100,"props":101,"children":102},"table",{},[103,122],{"type":9,"tag":104,"props":105,"children":106},"thead",{},[107],{"type":9,"tag":108,"props":109,"children":110},"tr",{},[111,117],{"type":9,"tag":112,"props":113,"children":114},"th",{},[115],{"type":14,"value":116},"Code",{"type":9,"tag":112,"props":118,"children":119},{},[120],{"type":14,"value":121},"Means",{"type":9,"tag":123,"props":124,"children":125},"tbody",{},[126,144,161,178,195,212,237],{"type":9,"tag":108,"props":127,"children":128},{},[129,139],{"type":9,"tag":130,"props":131,"children":132},"td",{},[133],{"type":9,"tag":35,"props":134,"children":136},{"className":135},[],[137],{"type":14,"value":138},"0",{"type":9,"tag":130,"props":140,"children":141},{},[142],{"type":14,"value":143},"clean exit",{"type":9,"tag":108,"props":145,"children":146},{},[147,156],{"type":9,"tag":130,"props":148,"children":149},{},[150],{"type":9,"tag":35,"props":151,"children":153},{"className":152},[],[154],{"type":14,"value":155},"1",{"type":9,"tag":130,"props":157,"children":158},{},[159],{"type":14,"value":160},"generic application error — read the logs",{"type":9,"tag":108,"props":162,"children":163},{},[164,173],{"type":9,"tag":130,"props":165,"children":166},{},[167],{"type":9,"tag":35,"props":168,"children":170},{"className":169},[],[171],{"type":14,"value":172},"125",{"type":9,"tag":130,"props":174,"children":175},{},[176],{"type":14,"value":177},"the daemon itself failed — usually a bad flag",{"type":9,"tag":108,"props":179,"children":180},{},[181,190],{"type":9,"tag":130,"props":182,"children":183},{},[184],{"type":9,"tag":35,"props":185,"children":187},{"className":186},[],[188],{"type":14,"value":189},"126",{"type":9,"tag":130,"props":191,"children":192},{},[193],{"type":14,"value":194},"the command was found but is not executable",{"type":9,"tag":108,"props":196,"children":197},{},[198,207],{"type":9,"tag":130,"props":199,"children":200},{},[201],{"type":9,"tag":35,"props":202,"children":204},{"className":203},[],[205],{"type":14,"value":206},"127",{"type":9,"tag":130,"props":208,"children":209},{},[210],{"type":14,"value":211},"command not found — wrong path, or missing in this base image",{"type":9,"tag":108,"props":213,"children":214},{},[215,224],{"type":9,"tag":130,"props":216,"children":217},{},[218],{"type":9,"tag":35,"props":219,"children":221},{"className":220},[],[222],{"type":14,"value":223},"137",{"type":9,"tag":130,"props":225,"children":226},{},[227,229,235],{"type":14,"value":228},"SIGKILL — an OOM kill, or a ",{"type":9,"tag":35,"props":230,"children":232},{"className":231},[],[233],{"type":14,"value":234},"stop",{"type":14,"value":236}," that timed out",{"type":9,"tag":108,"props":238,"children":239},{},[240,249],{"type":9,"tag":130,"props":241,"children":242},{},[243],{"type":9,"tag":35,"props":244,"children":246},{"className":245},[],[247],{"type":14,"value":248},"143",{"type":9,"tag":130,"props":250,"children":251},{},[252,254,260],{"type":14,"value":253},"SIGTERM — a clean ",{"type":9,"tag":35,"props":255,"children":257},{"className":256},[],[258],{"type":14,"value":259},"docker stop",{"type":14,"value":261}," the process honoured",{"type":9,"tag":10,"props":263,"children":264},{},[265,270,272,277,279,285,287,293],{"type":9,"tag":35,"props":266,"children":268},{"className":267},[],[269],{"type":14,"value":189},{"type":14,"value":271}," and ",{"type":9,"tag":35,"props":273,"children":275},{"className":274},[],[276],{"type":14,"value":206},{"type":14,"value":278}," are almost always an image problem rather than a code problem: a script without the executable bit, a shebang pointing at ",{"type":9,"tag":35,"props":280,"children":282},{"className":281},[],[283],{"type":14,"value":284},"/bin/bash",{"type":14,"value":286}," in an Alpine image that only has ",{"type":9,"tag":35,"props":288,"children":290},{"className":289},[],[291],{"type":14,"value":292},"/bin/sh",{"type":14,"value":294},", or a binary built for the wrong architecture.",{"data":296,"body":297},{},{"type":6,"children":298},[299],{"type":9,"tag":300,"props":301,"children":305},"quiz",{":answer":138,":options":302,"explanation":303,"question":304},"[\"It was SIGKILLed — most likely an out-of-memory kill against its own limit\",\"It called `exit(137)` deliberately\",\"The image is corrupt\"]","137 is 128 + 9, and signal 9 cannot be caught or handled — which is exactly why the logs just stop. Confirm with `docker inspect -f '{{.State.OOMKilled}}'`. Either the limit is too low or the workload leaks.","A container exits with code 137 and its logs end mid-request with no error. What happened?",[],{"data":307,"body":308},{},{"type":6,"children":309},[310,316,329,338,343,364],{"type":9,"tag":21,"props":311,"children":313},{"id":312},"when-the-container-will-not-start-at-all",[314],{"type":14,"value":315},"When the container will not start at all",{"type":9,"tag":10,"props":317,"children":318},{},[319,321,327],{"type":14,"value":320},"If it exits immediately and the logs are empty, you cannot ",{"type":9,"tag":35,"props":322,"children":324},{"className":323},[],[325],{"type":14,"value":326},"exec",{"type":14,"value":328}," into it — there is nothing running to join. Override the entrypoint and get a shell in the same image instead:",{"type":9,"tag":28,"props":330,"children":333},{"className":331,"code":332,"language":14},[31],"docker run --rm -it --entrypoint sh myapp\n",[334],{"type":9,"tag":35,"props":335,"children":336},{"__ignoreMap":37},[337],{"type":14,"value":332},{"type":9,"tag":10,"props":339,"children":340},{},[341],{"type":14,"value":342},"Now you are inside the image's filesystem and can check whether the file exists, whether it is executable, and what the environment actually looks like. Nine times out of ten it is a path.",{"type":9,"tag":10,"props":344,"children":345},{},[346,348,354,356,362],{"type":14,"value":347},"For an image with no shell at all — distroless, ",{"type":9,"tag":35,"props":349,"children":351},{"className":350},[],[352],{"type":14,"value":353},"scratch",{"type":14,"value":355}," — Docker Desktop ships ",{"type":9,"tag":35,"props":357,"children":359},{"className":358},[],[360],{"type":14,"value":361},"docker debug",{"type":14,"value":363},", which attaches a toolbox of debugging binaries to a running or stopped container without changing the image:",{"type":9,"tag":28,"props":365,"children":368},{"className":366,"code":367,"language":14},[31],"docker debug myapp\n",[369],{"type":9,"tag":35,"props":370,"children":371},{"__ignoreMap":37},[372],{"type":14,"value":367},{"data":374,"body":375},{},{"type":6,"children":376},[377,383],{"type":9,"tag":21,"props":378,"children":380},{"id":379},"where-the-disk-went",[381],{"type":14,"value":382},"Where the disk went",{"type":9,"tag":28,"props":384,"children":387},{"className":385,"code":386,"language":14},[31],"docker system df\n",[388],{"type":9,"tag":35,"props":389,"children":390},{"__ignoreMap":37},[391],{"type":14,"value":386},{"data":393,"body":394},{},{"type":6,"children":395},[396,400,405,414],{"type":9,"tag":56,"props":397,"children":399},{":lines":398},"[{\"cmd\":\"docker system df\",\"out\":\"TYPE            TOTAL   ACTIVE   SIZE      RECLAIMABLE\\nImages          47      6        12.4GB    9.87GB (79%)\\nContainers      31      4        1.2GB     1.1GB (91%)\\nLocal Volumes   22      3        8.9GB     7.2GB (80%)\\nBuild Cache     412     0        18.3GB    18.3GB (100%)\"}]",[],{"type":9,"tag":10,"props":401,"children":402},{},[403],{"type":14,"value":404},"Build cache is usually the biggest number and the one people forget exists. Forty gigabytes of it is unremarkable on a machine that builds regularly.",{"type":9,"tag":28,"props":406,"children":409},{"className":407,"code":408,"language":14},[31],"docker container prune          # stopped containers\ndocker image prune              # untagged images\ndocker image prune -a           # every image no container is using\ndocker builder prune            # build cache\ndocker builder prune --keep-storage 10GB   # keep a working set\n\ndocker system prune             # containers + networks + dangling images + cache\ndocker system prune -a --volumes   # everything. Including your data.\n",[410],{"type":9,"tag":35,"props":411,"children":412},{"__ignoreMap":37},[413],{"type":14,"value":408},{"type":9,"tag":10,"props":415,"children":416},{},[417,428,430,436],{"type":9,"tag":66,"props":418,"children":419},{},[420,426],{"type":9,"tag":35,"props":421,"children":423},{"className":422},[],[424],{"type":14,"value":425},"docker system prune -a --volumes",{"type":14,"value":427}," is the dangerous one.",{"type":14,"value":429}," It deletes every unused volume, and \"unused\" means \"no container currently references it\" — which includes the database volume of a stack you stopped for the weekend. Run ",{"type":9,"tag":35,"props":431,"children":433},{"className":432},[],[434],{"type":14,"value":435},"docker volume ls",{"type":14,"value":437}," first and know what you are agreeing to.",{"data":439,"body":440},{},{"type":6,"children":441},[442],{"type":9,"tag":300,"props":443,"children":447},{":answer":138,":options":444,"explanation":445,"question":446},"[\"`docker builder prune`\",\"`docker image prune -a`\",\"`docker system prune -a --volumes`\"]","Build cache is its own storage type with its own prune command. `image prune` does not touch it, and the `system prune -a --volumes` form would work but also deletes your volumes, which is a very expensive way to reclaim cache.","`docker system df` shows 18 GB of build cache. What reclaims it without touching images or volumes?",[],{"data":449,"body":450},{},{"type":6,"children":451},[452,458,486,499,510,531,536],{"type":9,"tag":21,"props":453,"children":455},{"id":454},"cap-the-logs-before-they-cap-you",[456],{"type":14,"value":457},"Cap the logs before they cap you",{"type":9,"tag":10,"props":459,"children":460},{},[461,463,468,470,476,478,484],{"type":14,"value":462},"The default logging driver writes JSON to disk ",{"type":9,"tag":66,"props":464,"children":465},{},[466],{"type":14,"value":467},"with no size limit",{"type":14,"value":469},". A chatty container will happily produce hundreds of gigabytes, and because the file is not in ",{"type":9,"tag":35,"props":471,"children":473},{"className":472},[],[474],{"type":14,"value":475},"/var/lib/docker/volumes",{"type":14,"value":477}," it does not show up in ",{"type":9,"tag":35,"props":479,"children":481},{"className":480},[],[482],{"type":14,"value":483},"docker system df",{"type":14,"value":485}," at all.",{"type":9,"tag":10,"props":487,"children":488},{},[489,491,497],{"type":14,"value":490},"Set a limit globally in ",{"type":9,"tag":35,"props":492,"children":494},{"className":493},[],[495],{"type":14,"value":496},"/etc/docker/daemon.json",{"type":14,"value":498},":",{"type":9,"tag":28,"props":500,"children":505},{"className":501,"code":503,"language":504,"meta":37},[502],"language-json","{\n  \"log-driver\": \"local\",\n  \"log-opts\": { \"max-size\": \"10m\", \"max-file\": \"3\" }\n}\n","json",[506],{"type":9,"tag":35,"props":507,"children":508},{"__ignoreMap":37},[509],{"type":14,"value":503},{"type":9,"tag":10,"props":511,"children":512},{},[513,515,521,523,529],{"type":14,"value":514},"The ",{"type":9,"tag":35,"props":516,"children":518},{"className":517},[],[519],{"type":14,"value":520},"local",{"type":14,"value":522}," driver is a better default than ",{"type":9,"tag":35,"props":524,"children":526},{"className":525},[],[527],{"type":14,"value":528},"json-file",{"type":14,"value":530},": it compresses, rotates, and is cheaper to write. Engine 29.5 also added custom attributes to it, so you can tag log entries at the driver level.",{"type":9,"tag":10,"props":532,"children":533},{},[534],{"type":14,"value":535},"Per service in Compose:",{"type":9,"tag":28,"props":537,"children":542},{"className":538,"code":540,"language":541,"meta":37},[539],"language-yaml","services:\n  api:\n    logging:\n      driver: local\n      options:\n        max-size: \"10m\"\n        max-file: \"3\"\n","yaml",[543],{"type":9,"tag":35,"props":544,"children":545},{"__ignoreMap":37},[546],{"type":14,"value":540},{"data":548,"body":549},{},{"type":6,"children":550},[551],{"type":9,"tag":552,"props":553,"children":558},"fill-blank",{":answer":554,"hint":555,"placeholder":556,"prompt":557},"[\"docker system df\",\"docker system df -v\"]","Three words, and the last one is the same as the Unix disk-free command.","docker system ...","Show how much disk space Docker is using, broken down by images, containers, volumes and build cache.",[],{"data":560,"body":561},{},{"type":6,"children":562},[563,691],{"type":9,"tag":564,"props":565,"children":567},"deep-dive",{"title":566},"A checklist for the four failures you will actually hit",[568,602,636,661,679],{"type":9,"tag":10,"props":569,"children":570},{},[571,576,578,584,586,592,594,600],{"type":9,"tag":66,"props":572,"children":573},{},[574],{"type":14,"value":575},"\"Connection refused\" to a container you just published.",{"type":14,"value":577}," Nearly always the process inside bound to ",{"type":9,"tag":35,"props":579,"children":581},{"className":580},[],[582],{"type":14,"value":583},"127.0.0.1",{"type":14,"value":585}," instead of ",{"type":9,"tag":35,"props":587,"children":589},{"className":588},[],[590],{"type":14,"value":591},"0.0.0.0",{"type":14,"value":593},". Inside a container, loopback means the container's own loopback, and nothing from outside can reach it. Configure the server to listen on all interfaces. If it is not that, check the ",{"type":9,"tag":35,"props":595,"children":597},{"className":596},[],[598],{"type":14,"value":599},"-p",{"type":14,"value":601}," order — host first.",{"type":9,"tag":10,"props":603,"children":604},{},[605,610,612,618,620,626,628,634],{"type":9,"tag":66,"props":606,"children":607},{},[608],{"type":14,"value":609},"\"No such file or directory\" for a file that is definitely there.",{"type":14,"value":611}," On Alpine, this is usually the ",{"type":9,"tag":613,"props":614,"children":615},"em",{},[616],{"type":14,"value":617},"dynamic linker",{"type":14,"value":619}," missing, not your file: a glibc-linked binary on musl. Check with ",{"type":9,"tag":35,"props":621,"children":623},{"className":622},[],[624],{"type":14,"value":625},"ldd",{"type":14,"value":627},". Use a ",{"type":9,"tag":35,"props":629,"children":631},{"className":630},[],[632],{"type":14,"value":633},"-slim",{"type":14,"value":635}," Debian base or build a static binary.",{"type":9,"tag":10,"props":637,"children":638},{},[639,644,646,652,654,659],{"type":9,"tag":66,"props":640,"children":641},{},[642],{"type":14,"value":643},"Works locally, fails in CI.",{"type":14,"value":645}," Architecture, most of the time — an image built on an ARM laptop and run on an x86 runner. ",{"type":9,"tag":35,"props":647,"children":649},{"className":648},[],[650],{"type":14,"value":651},"docker image inspect -f '{{.Architecture}}'",{"type":14,"value":653}," on both. Multi-platform builds are the fix, and they are a lesson in ",{"type":9,"tag":613,"props":655,"children":656},{},[657],{"type":14,"value":658},"Docker in Practice",{"type":14,"value":660},".",{"type":9,"tag":10,"props":662,"children":663},{},[664,669,671,677],{"type":9,"tag":66,"props":665,"children":666},{},[667],{"type":14,"value":668},"Permission denied on a bind-mounted file.",{"type":14,"value":670}," UIDs are numbers and do not map across the boundary. A container running as UID 1000 cannot write to a host directory owned by UID 501. Either run the container as the host's UID (",{"type":9,"tag":35,"props":672,"children":674},{"className":673},[],[675],{"type":14,"value":676},"--user \"$(id -u):$(id -g)\"",{"type":14,"value":678},") or use a named volume, where Docker owns the permissions and the question does not arise.",{"type":9,"tag":10,"props":680,"children":681},{},[682,684,689],{"type":14,"value":683},"The general habit worth taking from this course: when something is wrong, ask ",{"type":9,"tag":66,"props":685,"children":686},{},[687],{"type":14,"value":688},"which layer",{"type":14,"value":690}," — image, container, network, volume — before you start changing things. The commands above each answer one of those, and the answer is usually one command away.",{"type":9,"tag":10,"props":692,"children":693},{},[694,696,700],{"type":14,"value":695},"That is the whole of everyday Docker: run, build, store, connect, compose, debug. ",{"type":9,"tag":613,"props":697,"children":698},{},[699],{"type":14,"value":658},{"type":14,"value":701}," picks up from here with multi-stage builds, BuildKit's cache and secret mounts, multi-platform images, Bake, and the Compose features that make a real development loop.",1787908867655]