[{"data":1,"prerenderedAt":562},["ShallowReactive",2],{"mdc--c33laq-key":3,"mdc--snhi2z-key":16,"mdc-m59l82-key":60,"mdc-8tqfjq-key":128,"mdc--87h6l0-key":137,"mdc-mbx6dt-key":206,"mdc--ha3p5u-key":218,"mdc--idy90j-key":292,"mdc--g5f0j6-key":348,"mdc-86ghl2-key":360,"mdc--ucyjlk-key":397,"mdc--k038u2-key":407},{"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","Most of what anyone types at a Docker prompt is one command with a handful of flags. This lesson is that command, and the reason each flag exists.",{"data":17,"body":18},{},{"type":6,"children":19},[20,34,46,51],{"type":9,"tag":21,"props":22,"children":24},"h2",{"id":23},"the-anatomy-of-docker-run",[25,27],{"type":14,"value":26},"The anatomy of ",{"type":9,"tag":28,"props":29,"children":31},"code",{"className":30},[],[32],{"type":14,"value":33},"docker run",{"type":9,"tag":35,"props":36,"children":40},"pre",{"className":37,"code":39,"language":14},[38],"language-text","docker run [OPTIONS] IMAGE [COMMAND] [ARGS...]\n",[41],{"type":9,"tag":28,"props":42,"children":44},{"__ignoreMap":43},"",[45],{"type":14,"value":39},{"type":9,"tag":10,"props":47,"children":48},{},[49],{"type":14,"value":50},"Everything before the image name is for Docker. Everything after it is for the process inside the container, replacing the image's default command.",{"type":9,"tag":35,"props":52,"children":55},{"className":53,"code":54,"language":14},[38],"docker run nginx                    # run nginx's default command\ndocker run nginx nginx -v           # run something else instead\ndocker run alpine echo hello        # alpine's default is a shell; override it\n",[56],{"type":9,"tag":28,"props":57,"children":58},{"__ignoreMap":43},[59],{"type":14,"value":54},{"data":61,"body":62},{},{"type":6,"children":63},[64,70,79],{"type":9,"tag":21,"props":65,"children":67},{"id":66},"foreground-background-and-interactive",[68],{"type":14,"value":69},"Foreground, background, and interactive",{"type":9,"tag":35,"props":71,"children":74},{"className":72,"code":73,"language":14},[38],"docker run nginx                    # attached: your terminal follows its output\ndocker run -d nginx                 # detached: prints an ID and returns\ndocker run -it alpine sh            # interactive shell\n",[75],{"type":9,"tag":28,"props":76,"children":77},{"__ignoreMap":43},[78],{"type":14,"value":73},{"type":9,"tag":10,"props":80,"children":81},{},[82,88,90,96,98,104,106,112,114,119,121,126],{"type":9,"tag":28,"props":83,"children":85},{"className":84},[],[86],{"type":14,"value":87},"-d",{"type":14,"value":89}," detaches. ",{"type":9,"tag":28,"props":91,"children":93},{"className":92},[],[94],{"type":14,"value":95},"-it",{"type":14,"value":97}," is two flags people always type together: ",{"type":9,"tag":28,"props":99,"children":101},{"className":100},[],[102],{"type":14,"value":103},"-i",{"type":14,"value":105}," keeps stdin open, ",{"type":9,"tag":28,"props":107,"children":109},{"className":108},[],[110],{"type":14,"value":111},"-t",{"type":14,"value":113}," allocates a pseudo-terminal. You need both for a usable shell — ",{"type":9,"tag":28,"props":115,"children":117},{"className":116},[],[118],{"type":14,"value":103},{"type":14,"value":120}," alone gives you no prompt and no line editing, ",{"type":9,"tag":28,"props":122,"children":124},{"className":123},[],[125],{"type":14,"value":111},{"type":14,"value":127}," alone gives you a prompt that ignores your typing.",{"data":129,"body":130},{},{"type":6,"children":131},[132],{"type":9,"tag":133,"props":134,"children":136},"terminal-teaser",{":lines":135},"[{\"cmd\":\"docker run -d --name web -p 8080:80 nginx\",\"out\":\"3f9a1c4e77b2\"},{\"cmd\":\"docker ps\",\"out\":\"CONTAINER ID   IMAGE   STATUS         PORTS                  NAMES\\n3f9a1c4e77b2   nginx   Up 4 seconds   0.0.0.0:8080->80/tcp   web\"},{\"cmd\":\"curl -s localhost:8080 | head -4\",\"out\":\"\u003C!DOCTYPE html>\\n\u003Chtml>\\n\u003Chead>\\n\u003Ctitle>Welcome to nginx!\u003C/title>\"}]",[],{"data":138,"body":139},{},{"type":6,"children":140},[141,153,172,177,186],{"type":9,"tag":21,"props":142,"children":144},{"id":143},"p-publishes-a-port",[145,151],{"type":9,"tag":28,"props":146,"children":148},{"className":147},[],[149],{"type":14,"value":150},"-p",{"type":14,"value":152}," publishes a port",{"type":9,"tag":10,"props":154,"children":155},{},[156,162,164,170],{"type":9,"tag":28,"props":157,"children":159},{"className":158},[],[160],{"type":14,"value":161},"-p 8080:80",{"type":14,"value":163}," means ",{"type":9,"tag":165,"props":166,"children":167},"strong",{},[168],{"type":14,"value":169},"host port 8080 forwards to container port 80",{"type":14,"value":171},". Host first, container second — get it backwards and you will publish port 80 on your machine into a container that has nothing listening on 8080.",{"type":9,"tag":10,"props":173,"children":174},{},[175],{"type":14,"value":176},"A container's ports are private to its network namespace by default. Publishing is what pokes a hole from the host into it, and it is the reason two containers can both listen on 80 while only one of them can claim host port 8080.",{"type":9,"tag":35,"props":178,"children":181},{"className":179,"code":180,"language":14},[38],"-p 8080:80              # host 8080 -> container 80, all interfaces\n-p 127.0.0.1:8080:80    # ...bound to loopback only\n-p 80                   # container 80 -> a random free host port\n-P                      # publish every EXPOSEd port to random host ports\n",[182],{"type":9,"tag":28,"props":183,"children":184},{"__ignoreMap":43},[185],{"type":14,"value":180},{"type":9,"tag":10,"props":187,"children":188},{},[189,191,196,198,204],{"type":14,"value":190},"The loopback form is worth a habit. ",{"type":9,"tag":28,"props":192,"children":194},{"className":193},[],[195],{"type":14,"value":161},{"type":14,"value":197}," binds ",{"type":9,"tag":28,"props":199,"children":201},{"className":200},[],[202],{"type":14,"value":203},"0.0.0.0",{"type":14,"value":205},", which on a machine with a public IP means the internet, and Docker's rules sit ahead of a naive host firewall — a detail the Intermediate course returns to.",{"data":207,"body":208},{},{"type":6,"children":209},[210],{"type":9,"tag":211,"props":212,"children":217},"quiz",{":answer":213,":options":214,"explanation":215,"question":216},"0","[\"The mapping is host-then-container, so Docker is forwarding host 3000 to container 8080, where nothing is listening\",\"Port 3000 is reserved and cannot be published\",\"The container needs `EXPOSE 3000` before it can be published\"]","The order is `-p HOST:CONTAINER`. You wanted `-p 3000:3000`. Nothing errors, because Docker has no way to know the container is not listening on 8080 — it happily forwards into silence.","A container serves on port 3000. You run it with `-p 3000:8080` and get connection refused on the host. Why?",[],{"data":219,"body":220},{},{"type":6,"children":221},[222,228,237,274],{"type":9,"tag":21,"props":223,"children":225},{"id":224},"naming-and-cleanup",[226],{"type":14,"value":227},"Naming and cleanup",{"type":9,"tag":35,"props":229,"children":232},{"className":230,"code":231,"language":14},[38],"docker run --name web nginx         # a name you can use instead of the ID\ndocker run --rm alpine echo hi      # delete the container when it exits\n",[233],{"type":9,"tag":28,"props":234,"children":235},{"__ignoreMap":43},[236],{"type":14,"value":231},{"type":9,"tag":10,"props":238,"children":239},{},[240,242,248,250,256,258,264,266,272],{"type":14,"value":241},"Without ",{"type":9,"tag":28,"props":243,"children":245},{"className":244},[],[246],{"type":14,"value":247},"--name",{"type":14,"value":249}," you get a generated one like ",{"type":9,"tag":28,"props":251,"children":253},{"className":252},[],[254],{"type":14,"value":255},"nostalgic_hopper",{"type":14,"value":257},". Names must be unique, which is why re-running a ",{"type":9,"tag":28,"props":259,"children":261},{"className":260},[],[262],{"type":14,"value":263},"--name web",{"type":14,"value":265}," command after a crash fails until you ",{"type":9,"tag":28,"props":267,"children":269},{"className":268},[],[270],{"type":14,"value":271},"docker rm web",{"type":14,"value":273},".",{"type":9,"tag":10,"props":275,"children":276},{},[277,283,285,290],{"type":9,"tag":28,"props":278,"children":280},{"className":279},[],[281],{"type":14,"value":282},"--rm",{"type":14,"value":284}," matters more than it looks. Every container you run and forget stays on disk, writable layer and all. A month of experimenting without ",{"type":9,"tag":28,"props":286,"children":288},{"className":287},[],[289],{"type":14,"value":282},{"type":14,"value":291}," is measured in gigabytes. Use it for anything one-shot; leave it off for anything you might want to inspect after it dies.",{"data":293,"body":294},{},{"type":6,"children":295},[296,302,311,330],{"type":9,"tag":21,"props":297,"children":299},{"id":298},"environment-and-the-working-directory",[300],{"type":14,"value":301},"Environment and the working directory",{"type":9,"tag":35,"props":303,"children":306},{"className":304,"code":305,"language":14},[38],"docker run -e LOG_LEVEL=debug myapp\ndocker run --env-file .env myapp\ndocker run -w /app -v \"$PWD:/app\" node:22 npm test\n",[307],{"type":9,"tag":28,"props":308,"children":309},{"__ignoreMap":43},[310],{"type":14,"value":305},{"type":9,"tag":10,"props":312,"children":313},{},[314,320,322,328],{"type":9,"tag":28,"props":315,"children":317},{"className":316},[],[318],{"type":14,"value":319},"-e",{"type":14,"value":321}," sets one variable, ",{"type":9,"tag":28,"props":323,"children":325},{"className":324},[],[326],{"type":14,"value":327},"--env-file",{"type":14,"value":329}," reads a file of them. Both are the normal way to configure a container, because the whole point of an image is that it is the same everywhere and the configuration is not.",{"type":9,"tag":10,"props":331,"children":332},{},[333,338,340,346],{"type":9,"tag":165,"props":334,"children":335},{},[336],{"type":14,"value":337},"Do not pass secrets this way if you can avoid it.",{"type":14,"value":339}," ",{"type":9,"tag":28,"props":341,"children":343},{"className":342},[],[344],{"type":14,"value":345},"docker inspect",{"type":14,"value":347}," shows every environment variable in plain text to anyone who can reach the daemon, and so does the API. The Intermediate and Advanced courses cover the alternatives.",{"data":349,"body":350},{},{"type":6,"children":351},[352],{"type":9,"tag":353,"props":354,"children":359},"fill-blank",{":answer":355,"hint":356,"placeholder":357,"prompt":358},"[\"docker run -d --name cache -p 6379:6379 redis\",\"docker run -d -p 6379:6379 --name cache redis\",\"docker run --name cache -d -p 6379:6379 redis\",\"docker run -d --name=cache -p 6379:6379 redis\"]","Three flags — detach, name, publish — then the image.","docker run ...","Run the `redis` image in the background, named `cache`, with container port 6379 published on host port 6379.",[],{"data":361,"body":362},{},{"type":6,"children":363},[364,370,379],{"type":9,"tag":21,"props":365,"children":367},{"id":366},"looking-at-what-is-running",[368],{"type":14,"value":369},"Looking at what is running",{"type":9,"tag":35,"props":371,"children":374},{"className":372,"code":373,"language":14},[38],"docker ps                  # running\ndocker ps -a               # every container, including exited\ndocker logs -f web         # follow the output\ndocker exec -it web sh     # a second process inside a running container\ndocker stop web            # SIGTERM, then SIGKILL after the grace period\ndocker rm web              # delete a stopped container\n",[375],{"type":9,"tag":28,"props":376,"children":377},{"__ignoreMap":43},[378],{"type":14,"value":373},{"type":9,"tag":10,"props":380,"children":381},{},[382,388,390,395],{"type":9,"tag":28,"props":383,"children":385},{"className":384},[],[386],{"type":14,"value":387},"docker exec",{"type":14,"value":389}," is the one people reach for constantly and the one worth understanding properly: it starts a ",{"type":9,"tag":165,"props":391,"children":392},{},[393],{"type":14,"value":394},"new process",{"type":14,"value":396}," inside an existing container's namespaces. It is not a way back into the original process, and anything it changes lives in the container's writable layer like any other write.",{"data":398,"body":399},{},{"type":6,"children":400},[401],{"type":9,"tag":211,"props":402,"children":406},{":answer":213,":options":403,"explanation":404,"question":405},"[\"`docker logs \u003Cname>` — a stopped container keeps its logs until it is removed\",\"`docker ps` — it lists containers that have exited\",\"`docker exec` into it and look around\"]","`docker ps` only shows running containers (you would need `-a`), and `docker exec` needs a running container to exec into. Logs outlive the process and are the first thing to read. `docker inspect --format '{{.State.ExitCode}}'` gives you the exit code alongside.","A container exits immediately with no output. Which command actually helps?",[],{"data":408,"body":409},{},{"type":6,"children":410},[411,557],{"type":9,"tag":412,"props":413,"children":415},"deep-dive",{"title":414},"Why your container exits straight away",[416,421,431,474,479,552],{"type":9,"tag":10,"props":417,"children":418},{},[419],{"type":14,"value":420},"The most common beginner surprise, and it is not a bug.",{"type":9,"tag":10,"props":422,"children":423},{},[424,429],{"type":9,"tag":165,"props":425,"children":426},{},[427],{"type":14,"value":428},"A container lives exactly as long as its main process.",{"type":14,"value":430}," When PID 1 exits, the container stops. There is no daemon, no supervisor, nothing keeping it alive.",{"type":9,"tag":10,"props":432,"children":433},{},[434,436,442,444,450,452,457,459,465,467,472],{"type":14,"value":435},"So ",{"type":9,"tag":28,"props":437,"children":439},{"className":438},[],[440],{"type":14,"value":441},"docker run ubuntu",{"type":14,"value":443}," starts, runs ",{"type":9,"tag":28,"props":445,"children":447},{"className":446},[],[448],{"type":14,"value":449},"bash",{"type":14,"value":451},", finds no terminal attached, ",{"type":9,"tag":28,"props":453,"children":455},{"className":454},[],[456],{"type":14,"value":449},{"type":14,"value":458}," reads end-of-file immediately and exits, and the container is gone. ",{"type":9,"tag":28,"props":460,"children":462},{"className":461},[],[463],{"type":14,"value":464},"docker run -it ubuntu",{"type":14,"value":466}," gives ",{"type":9,"tag":28,"props":468,"children":470},{"className":469},[],[471],{"type":14,"value":449},{"type":14,"value":473}," a terminal to read from, and it stays.",{"type":9,"tag":10,"props":475,"children":476},{},[477],{"type":14,"value":478},"The same rule explains other cases:",{"type":9,"tag":480,"props":481,"children":482},"ul",{},[483,508,534],{"type":9,"tag":484,"props":485,"children":486},"li",{},[487,499,500,506],{"type":9,"tag":165,"props":488,"children":489},{},[490,492,498],{"type":14,"value":491},"A backgrounded process in your ",{"type":9,"tag":28,"props":493,"children":495},{"className":494},[],[496],{"type":14,"value":497},"CMD",{"type":14,"value":273},{"type":14,"value":339},{"type":9,"tag":28,"props":501,"children":503},{"className":502},[],[504],{"type":14,"value":505},"CMD [\"sh\", \"-c\", \"myapp &\"]",{"type":14,"value":507}," starts the app, the shell has nothing left to do, PID 1 exits, everything dies.",{"type":9,"tag":484,"props":509,"children":510},{},[511,516,518,524,526,532],{"type":9,"tag":165,"props":512,"children":513},{},[514],{"type":14,"value":515},"A web server in daemon mode.",{"type":14,"value":517}," Every official image runs its server in the foreground on purpose — ",{"type":9,"tag":28,"props":519,"children":521},{"className":520},[],[522],{"type":14,"value":523},"nginx -g 'daemon off;'",{"type":14,"value":525},", ",{"type":9,"tag":28,"props":527,"children":529},{"className":528},[],[530],{"type":14,"value":531},"httpd-foreground",{"type":14,"value":533},". Configuring one to daemonise kills the container.",{"type":9,"tag":484,"props":535,"children":536},{},[537,542,544,550],{"type":9,"tag":165,"props":538,"children":539},{},[540],{"type":14,"value":541},"A crash you cannot see.",{"type":14,"value":543}," The process really did fail. ",{"type":9,"tag":28,"props":545,"children":547},{"className":546},[],[548],{"type":14,"value":549},"docker logs",{"type":14,"value":551}," and the exit code will say so.",{"type":9,"tag":10,"props":553,"children":554},{},[555],{"type":14,"value":556},"The rule to carry: the thing you want to keep running must be PID 1, and it must not fork into the background.",{"type":9,"tag":10,"props":558,"children":559},{},[560],{"type":14,"value":561},"Next up: images and registries — where the things you have been running come from.",1787908867614]