[{"data":1,"prerenderedAt":642},["ShallowReactive",2],{"post-document:\u002Fdevops\u002Fdocker\u002F2026\u002F08\u002F17\u002Fdocker-01-core-concepts\u002F":3},{"id":4,"title":5,"body":6,"categories":624,"date":627,"description":628,"extension":629,"image":630,"key_concepts":630,"last_modified_at":630,"legacyPath":631,"meta":632,"navigation":143,"part":634,"path":635,"published":143,"robots":630,"seo":636,"series":637,"stem":638,"strengths":630,"summary":630,"tags":639,"tradeoffs":630,"__hash__":641},"posts\u002Fposts\u002FCI-CD-Docker\u002FDocker\u002F2026-08-17-docker-01-core-concepts.md","Docker 기초 1편: Dockerfile, Image와 Container",{"type":7,"value":8,"toc":608},"minimark",[9,14,18,21,24,27,38,41,44,47,50,56,59,62,68,71,74,77,80,83,89,92,95,98,101,105,108,114,118,123,184,187,190,193,196,199,202,205,208,211,217,220,224,229,233,236,263,266,272,275,278,283,286,289,293,296,311,314,320,323,329,332,338,341,347,351,395,398,404,408,411,416,432,436,448,452,464,467,486,492,496,499,502,505,511,514,517,536,542,546,549,555,558,564,567,571,574,580,583,586,592,595,598,601,604],[10,11,13],"h2",{"id":12},"_1-docker가-왜-필요할까","1. Docker가 왜 필요할까?",[15,16,17],"p",{},"뭐.. 개발은 내 컴퓨터에서만 하고, 사용도 내 컴퓨터에서만 한다면 사실 이 게시물을 읽을 필요가 없다.",[15,19,20],{},"그런데 아시다시피 개발을 하면 배포를 해야한다.",[15,22,23],{},"여기서부터 문제는 시작된다.",[15,25,26],{},"내가 뭐 SpringBoot 프로젝트를 한다고 치자",[28,29,35],"pre",{"className":30,"code":32,"language":33,"meta":34},[31],"language-text","Java 21\nMySQL 8\n특정 환경변수\n특정 라이브러리\n","text","",[36,37,32],"code",{"__ignoreMap":34},[15,39,40],{},"내 컴퓨터는 세팅이 잘 되어있어서 내가 만들어놓은 프로젝트가 잘 돌아갈 것이다.\n(근데 당연한 소리다. 내 컴퓨터에서 돌아가지도 않는데 개발을 어캐함???? ㅋㅋㅋㅋ)",[15,42,43],{},"그렇지만 내 개발을 서버에 올릴 떄는 이야기가 달라진다.",[15,45,46],{},"내가 올려야 할 서버는 내 컴퓨터와 사양과 환경이 같을까? 그렇리는 없다.",[15,48,49],{},"일례로 서버 환경이",[28,51,54],{"className":52,"code":53,"language":33,"meta":34},[31],"Java 17\nMySQL 5\n환경변수 없음\n라이브러리 버전 다름\n",[36,55,53],{"__ignoreMap":34},[15,57,58],{},"뭐 이렇다고 치면",[15,60,61],{},"실행이 될리가 없다. 애초에 개발에 사용된 환경과 서버에서 사용된 환경이 다르니까.",[63,64,65],"blockquote",{},[15,66,67],{},"이럴 때 하는 말이 하나있다. \"내 컴에서는 되던데?\"",[15,69,70],{},"(아무런 도움이 되지 않는 말이다..ㅋㅋ)",[15,72,73],{},"아무튼 그렇다면 문제를 어떻게 해결해야겠는가?",[15,75,76],{},"애플리케이션과 실행 환경을 같이 묶어서 실행하면 되는 것이다.",[15,78,79],{},"Docker가 이 문제를 해결해준다.",[15,81,82],{},"일단 실행환경과 코드를 묶어서 이미지로 만들어주고",[28,84,87],{"className":85,"code":86,"language":33,"meta":34},[31],"Spring Boot Application\n        +\nJava Runtime\n        +\nLibrary\n        +\n설정\n        ↓\nDocker Image\n",[36,88,86],{"__ignoreMap":34},[15,90,91],{},"서버에서는",[15,93,94],{},"도커 이미지를 바탕으로",[15,96,97],{},"돌려서",[15,99,100],{},"Container를 돌리는 것이다.",[10,102,104],{"id":103},"_2-docker의-가장-중요한-개념","2. Docker의 가장 중요한 개념",[15,106,107],{},"Docker를 처음 공부한다면 아래 흐름을 먼저 외우는 게 좋다.",[28,109,112],{"className":110,"code":111,"language":33,"meta":34},[31],"Dockerfile\n->\ndocker build\n->\nImage\n->\ndocker run\n->\nContainer\n",[36,113,111],{"__ignoreMap":34},[10,115,117],{"id":116},"_3-dockerfile","3. Dockerfile",[63,119,120],{},[15,121,122],{},"Dockerfile은 Docker Image를 만드는 설계도",[28,124,128],{"className":125,"code":126,"language":127,"meta":34,"style":34},"language-dockerfile shiki shiki-themes github-light github-dark","FROM eclipse-temurin:21-jre\n\nWORKDIR \u002Fapp\n\nCOPY build\u002Flibs\u002Fapp.jar app.jar\n\nEXPOSE 8080\n\nENTRYPOINT [\"java\", \"-jar\", \"app.jar\"]\n","dockerfile",[36,129,130,138,145,151,156,162,167,173,178],{"__ignoreMap":34},[131,132,135],"span",{"class":133,"line":134},"line",1,[131,136,137],{},"FROM eclipse-temurin:21-jre\n",[131,139,141],{"class":133,"line":140},2,[131,142,144],{"emptyLinePlaceholder":143},true,"\n",[131,146,148],{"class":133,"line":147},3,[131,149,150],{},"WORKDIR \u002Fapp\n",[131,152,154],{"class":133,"line":153},4,[131,155,144],{"emptyLinePlaceholder":143},[131,157,159],{"class":133,"line":158},5,[131,160,161],{},"COPY build\u002Flibs\u002Fapp.jar app.jar\n",[131,163,165],{"class":133,"line":164},6,[131,166,144],{"emptyLinePlaceholder":143},[131,168,170],{"class":133,"line":169},7,[131,171,172],{},"EXPOSE 8080\n",[131,174,176],{"class":133,"line":175},8,[131,177,144],{"emptyLinePlaceholder":143},[131,179,181],{"class":133,"line":180},9,[131,182,183],{},"ENTRYPOINT [\"java\", \"-jar\", \"app.jar\"]\n",[15,185,186],{},"하나씩 보면:",[15,188,189],{},"FROM eclipse-temurin:21-jre",[15,191,192],{},"Java 21이 설치된 환경을 기반으로 사용",[15,194,195],{},"WORKDIR \u002Fapp",[15,197,198],{},"Container 내부의 작업 위치를 \u002Fapp으로 저장한다.",[15,200,201],{},"COPY build\u002Flibs\u002Fapp.jar app.jar",[15,203,204],{},"내 컴퓨통에 있는 jar 파일을 Container 이미지 내부로 복사한다.",[15,206,207],{},"EXPOSE 8080",[15,209,210],{},"이 애플리케이션이 8080 Port",[15,212,213,214],{},"ENTRYPOINT ",[131,215,216],{},"\"java\", \"-jar\", \"app.jar\"",[15,218,219],{},"Container가 시작할 떄 실행할 명령",[221,222,223],"h4",{"id":223},"요약",[63,225,226],{},[15,227,228],{},"이 어플리케이션을 실행하기 위해 어떤 환경을 만들고, 어떤 파일을 넣고, 어떤 명령으로 실행할지 선언하는 파일",[10,230,232],{"id":231},"_4-docker-image","4. Docker Image",[15,234,235],{},"Dockerfile을 이용해서 Image를 만든다.",[28,237,241],{"className":238,"code":239,"language":240,"meta":34,"style":34},"language-bash shiki shiki-themes github-light github-dark","docker build -t myapp:1.0 .\n","bash",[36,242,243],{"__ignoreMap":34},[131,244,245,249,253,257,260],{"class":133,"line":134},[131,246,248],{"class":247},"sScJk","docker",[131,250,252],{"class":251},"sZZnC"," build",[131,254,256],{"class":255},"sj4cs"," -t",[131,258,259],{"class":251}," myapp:1.0",[131,261,262],{"class":251}," .\n",[15,264,265],{},"그러면",[28,267,270],{"className":268,"code":269,"language":33,"meta":34},[31],"Dockerfile\n->\ndocker build\n->\nmyapp:1.0\n",[36,271,269],{"__ignoreMap":34},[15,273,274],{},"이라는 Image가 만들어진다.",[15,276,277],{},"Image는 쉽게 말하면",[63,279,280],{},[15,281,282],{},"어플리케이션 실행에 필요한 환경을 포함한 환경 패키지",[15,284,285],{},"라고 보면 된다.",[15,287,288],{},"여기서 중요한 점은 Image 자체는 실행중인 프로그램이 아니라는 것.",[10,290,292],{"id":291},"_5-docker-container","5. Docker Container",[15,294,295],{},"Image를 실제로 실행하면 Container가 된다.",[28,297,299],{"className":238,"code":298,"language":240,"meta":34,"style":34},"docker run myapp:1.0\n",[36,300,301],{"__ignoreMap":34},[131,302,303,305,308],{"class":133,"line":134},[131,304,248],{"class":247},[131,306,307],{"class":251}," run",[131,309,310],{"class":251}," myapp:1.0\n",[15,312,313],{},"구조는",[28,315,318],{"className":316,"code":317,"language":33,"meta":34},[31],"Image\nmyapp:1.0\n-> docker run\ncontainer\n",[36,319,317],{"__ignoreMap":34},[15,321,322],{},"이게 비유하면",[28,324,327],{"className":325,"code":326,"language":33,"meta":34},[31],"Java class\n-> new\nobject\n",[36,328,326],{"__ignoreMap":34},[15,330,331],{},"Docker에서는",[28,333,336],{"className":334,"code":335,"language":33,"meta":34},[31],"Docker Image\n-> docker run\nContainer\n",[36,337,335],{"__ignoreMap":34},[15,339,340],{},"(마치 OOP의 느낌, 클래스로 여러 개의 인스턴스를 만드는 것을 생각하면 쉽게 생각될 듯 하다. )",[28,342,345],{"className":343,"code":344,"language":33,"meta":34},[31],"             myapp:1.0\n                 │\n        ┌────────┼────────┐\n        ↓        ↓        ↓\nContainer A Container B Container C\n",[36,346,344],{"__ignoreMap":34},[10,348,350],{"id":349},"_6-image와-container의-차이","6. Image와 Container의 차이",[352,353,354,367],"table",{},[355,356,357],"thead",{},[358,359,360,364],"tr",{},[361,362,363],"th",{},"개념",[361,365,366],{},"의미",[368,369,370,379,387],"tbody",{},[358,371,372,376],{},[373,374,375],"td",{},"Dockerfile",[373,377,378],{},"Image 만드는 설계도",[358,380,381,384],{},[373,382,383],{},"Image",[373,385,386],{},"실행 가능한 패키지",[358,388,389,392],{},[373,390,391],{},"Container",[373,393,394],{},"Image가 실제 실행된 상태",[15,396,397],{},"비유하자면",[28,399,402],{"className":400,"code":401,"language":33,"meta":34},[31],"Dockerfile\n= 붕어빵 틀을 만드는 설계\n\nImage\n= 붕어빵 틀\n\nContainer\n= 실제 만들어진 붕어빵\n",[36,403,401],{"__ignoreMap":34},[10,405,407],{"id":406},"_7-docker-명령어-기본-흐름","7. Docker 명령어 기본 흐름",[15,409,410],{},"Docker를 사용하면 보통 이런 순서",[412,413,415],"h3",{"id":414},"image-만들기","Image 만들기",[28,417,418],{"className":238,"code":239,"language":240,"meta":34,"style":34},[36,419,420],{"__ignoreMap":34},[131,421,422,424,426,428,430],{"class":133,"line":134},[131,423,248],{"class":247},[131,425,252],{"class":251},[131,427,256],{"class":255},[131,429,259],{"class":251},[131,431,262],{"class":251},[412,433,435],{"id":434},"image-확인","Image 확인",[28,437,439],{"className":238,"code":438,"language":240,"meta":34,"style":34},"docker images\n",[36,440,441],{"__ignoreMap":34},[131,442,443,445],{"class":133,"line":134},[131,444,248],{"class":247},[131,446,447],{"class":251}," images\n",[412,449,451],{"id":450},"container-확인","Container 확인",[28,453,454],{"className":238,"code":298,"language":240,"meta":34,"style":34},[36,455,456],{"__ignoreMap":34},[131,457,458,460,462],{"class":133,"line":134},[131,459,248],{"class":247},[131,461,307],{"class":251},[131,463,310],{"class":251},[15,465,466],{},"-> web_server라면 Port도 연결해야함",[28,468,470],{"className":238,"code":469,"language":240,"meta":34,"style":34},"docker run -p 8080:8080 myapp:1.0\n",[36,471,472],{"__ignoreMap":34},[131,473,474,476,478,481,484],{"class":133,"line":134},[131,475,248],{"class":247},[131,477,307],{"class":251},[131,479,480],{"class":255}," -p",[131,482,483],{"class":251}," 8080:8080",[131,485,310],{"class":251},[28,487,490],{"className":488,"code":489,"language":33,"meta":34},[31],"내 컴퓨터 8080\n      ↓\nContainer 8080\n",[36,491,489],{"__ignoreMap":34},[10,493,495],{"id":494},"_8-근데-왜-port-mapping을-해야할까","8. 근데 왜 PORT mapping을 해야할까?",[15,497,498],{},"Container는 외부와 분리된 환경이므로 내 컴퓨터의 내부 포트와 연결해야 한다.",[15,500,501],{},"예를 들어 Spring Boot가 Container 안에서: localhost:8080",[15,503,504],{},"으로 실행된다. 그렇다고 내 컴퓨터의 8080과 자동으로 연결되는 것은 아님",[15,506,507,510],{},[36,508,509],{},"docker run -p 8080:8080 myapp"," 처럼 연결",[15,512,513],{},"형식은: -p HostPort:ContainerPort",[15,515,516],{},"예를 들어:",[28,518,520],{"className":238,"code":519,"language":240,"meta":34,"style":34},"docker run -p 9000:8080 myapp\n",[36,521,522],{"__ignoreMap":34},[131,523,524,526,528,530,533],{"class":133,"line":134},[131,525,248],{"class":247},[131,527,307],{"class":251},[131,529,480],{"class":255},[131,531,532],{"class":251}," 9000:8080",[131,534,535],{"class":251}," myapp\n",[28,537,540],{"className":538,"code":539,"language":33,"meta":34},[31],"Browser\n\nlocalhost:9000\n-> Host 9000\n-> Container 8080\n-> Spring Boot\n",[36,541,539],{"__ignoreMap":34},[10,543,545],{"id":544},"_9-container는-격리된-환경","9. Container는 격리된 환경",[15,547,548],{},"Docker의 중요한 특징이다. 컨테이너끼리 격리되어있다.\n(추후에 namespace 개념에서 한 번 더 나오므로 잘 기억하자)",[28,550,553],{"className":551,"code":552,"language":33,"meta":34},[31],"Container A\nJava 17\n\nContainer B\nJava 21\n\nContainer C\nPython 3.13\n",[36,554,552],{"__ignoreMap":34},[15,556,557],{},"를 같은 컴퓨터에서 동시에 실행이 가능하다.",[28,559,562],{"className":560,"code":561,"language":33,"meta":34},[31],"Host Operating System\n        │\n        ├── Container A\n        │     Java 17\n        │\n        ├── Container B\n        │     Java 21\n        │\n        └── Container C\n              Python\n",[36,563,561],{"__ignoreMap":34},[15,565,566],{},"이런 식으로 격리되어 있어서 프로젝트마다 분리해서 사용하기가 쉽다.",[10,568,570],{"id":569},"_10-근데-이러면-vmvirtual-machine하고-뭐가-다른거임","10. 근데 이러면 VM(Virtual Machine)하고 뭐가 다른거임?",[15,572,573],{},"일단 VM부터 살펴보도록하자.",[28,575,578],{"className":576,"code":577,"language":33,"meta":34},[31],"Hardware\n   ↓\nHost OS\n   ↓\nHypervisor\n   ↓\nGuest OS\n   ↓\nApplication\n",[36,579,577],{"__ignoreMap":34},[15,581,582],{},"VM은 기본적으로 기본 OS 위에 가상 OS를 띄우는 방식으로 굴러간다.",[15,584,585],{},"그러나 Docker의 경우에는",[28,587,590],{"className":588,"code":589,"language":33,"meta":34},[31],"Hardware\n   ↓\nHost OS\n   ↓\nDocker Engine\n   ↓\nContainer\n   ↓\nApplication\n",[36,591,589],{"__ignoreMap":34},[15,593,594],{},"Docker Container는 VM처럼 OS 전체를 하나 더 띄우지 않는다.",[15,596,597],{},"Host OS의 Kernel을 공유",[15,599,600],{},"시작이 빠르고\n용량이 작고\n리소스를 덜 사용하는",[15,602,603],{},"장점이 있다.",[605,606,607],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":34,"searchDepth":140,"depth":140,"links":609},[610,611,612,613,614,615,616,621,622,623],{"id":12,"depth":140,"text":13},{"id":103,"depth":140,"text":104},{"id":116,"depth":140,"text":117},{"id":231,"depth":140,"text":232},{"id":291,"depth":140,"text":292},{"id":349,"depth":140,"text":350},{"id":406,"depth":140,"text":407,"children":617},[618,619,620],{"id":414,"depth":147,"text":415},{"id":434,"depth":147,"text":435},{"id":450,"depth":147,"text":451},{"id":494,"depth":140,"text":495},{"id":544,"depth":140,"text":545},{"id":569,"depth":140,"text":570},[625,626],"DevOps","Docker","2026-08-17 12:00:00 +0900","Docker가 필요한 이유와 Dockerfile, Image, Container, 기본 명령어, Port Mapping과 격리 개념을 정리한다.","md",null,"\u002Fdevops\u002Fdocker\u002F2026\u002F08\u002F17\u002Fdocker-01-core-concepts\u002F",{"layout":633},"post","1","\u002Fposts\u002Fci-cd-docker\u002Fdocker\u002F2026-08-17-docker-01-core-concepts",{"title":5,"description":628},"Docker 기초","posts\u002FCI-CD-Docker\u002FDocker\u002F2026-08-17-docker-01-core-concepts",[626,375,383,391,640],"Port Mapping","bb71jEqK3CopERdreuOz6BbC4xTF83HJJ_36ANpky4s",1788744787482]