[Docker] 2. Dockerfile

김미숙's avatar
Jul 30, 2025
[Docker] 2. Dockerfile

✅ Dockerfile이란?

  • 도커 이미지를 만들기 위한 설정 파일(스크립트)
    • 이미지를 어떻게 만들 것인지 절차를 정의한 설계도
  • Dockerfile은 텍스트 기반의 명령어 모음 파일로, 우리가 원하는 환경이나 애플리케이션을 자동으로 이미지로 빌드할 수 있게 도와준다

🧱 대표적인 명령어

명령어
설명
FROM
어떤 이미지를 기반으로 만들 것인지 지정 (예: nginx, ubuntu, openjdk)
WORKDIR
작업 디렉토리를 설정 (이후 모든 명령은 이 경로 기준으로 실행됨)
COPY
호스트의 파일/디렉토리를 이미지 안으로 복사
ADD
COPY와 유사하지만 압축 해제 가능, URL도 가능
RUN
이미지 빌드 도중에 실행할 명령어 (예: apt install, npm install)
CMD
컨테이너가 실행될 때 실행할 명령어
ENTRYPOINT
CMD처럼 실행 명령을 지정하지만, 더 고정된 실행 환경을 원할 때 사용
ENV
환경변수 설정
EXPOSE
컨테이너가 사용하는 포트 명시 (실제 포트 개방은 아님)

✅ 요약

  • Dockerfile = 이미지 설계도
  • FROM으로 시작해서 CMDENTRYPOINT로 마무리
  • 이 파일을 docker build 명령으로 실행해 이미지 생성
 

실습 0 - Apache 실행

  • 설치만 하는 건 pull
    • docker pull nginx
  • 설치 포함 실행은 run
    • docker run -d -p 8000:80 nginx
    • docker run -dit -p 8080:80 httpd
      notion image
      notion image
      notion image
      notion image

Bind Mount

✅ Mount란?

  • 데이터를 컨테이너에 연결하는 방식 전체

✅ Mount 방식 2가지

방식
설명
Bind Mount
호스트의 특정 경로를 컨테이너 내부 경로와 연결
Volume
도커가 관리하는 독립된 저장소 (컨테이너 재시작해도 유지됨)

✅ Bind Mount란?

  • Mount 방식 중 하나
  • 호스트(내 컴퓨터)의 특정 디렉토리나 파일을 컨테이너 안에 연결(mount)하는 방법

✅ 특징

항목
설명
📂 위치
호스트의 직접 지정한 경로를 사용 (예: C:/workspace/project)
🔁 양방향 접근
컨테이너에서 수정한 파일이 호스트에도 반영되고, 반대로도 가능
🔧 주 용도
로컬 개발 시 코드 수정 사항을 바로 반영하고 테스트할 때
🔥 주의할 점
권한 관리나 OS별 경로 차이로 오류가 생길 수 있음
🗑 컨테이너 삭제 시
데이터는 사라지지 않음 (호스트에 있기 때문)

✅ Bind Mount가 필요한 이유?

  • 컨테이너 안에서 만든 파일이 컨테이너 삭제되면 사라짐 😢
    • 데이터를 영구적으로 유지하고 싶을 때
  • 컨테이너에서 직접 호스트의 코드, 설정 파일 등을 읽고 쓰고 싶을 때
  • 개발 중 컨테이너 안 파일을 즉시 반영하고 싶을 때 (예: hot reload)
 

실습1 - apache

  • ex01 폴더 내에 index.html 생성 후 apache의 index.html 위치 확인
    • notion image
      notion image
      notion image
  • ex01 폴더를 apache 웹 서버 폴더로 마운트
    • docker run -d -p 8000:80 -v c:/workspace/docker_lab/ex01:/usr/local/apache2/htdocs httpd
      → bash는 \ 인식 못함
      → 내가 생성한 폴더명 그대로 작성해야한다!
      docker_lab 을 docker-lab 라고 작성했더니 docker-lab 폴더를 생성하고 docker-lab 폴더를 마운트 함 : Windows 경로 지정 방식Docker 마운트 처리 방식의 차이에서 오는 현상
      🔍 왜 새로운 docker-lab 폴더가 만들어졌을까?
      -v c:/workspace/docker-lab/ex01:/usr/share/nginx/html
      이렇게 잘못된 경로를 입력했을 경우:
      👉 Windows에는 docker-lab 폴더가 없는데,
      Docker는:
      • "이 경로를 마운트하라고 했는데, 없네?"
      • 그러면 빈 디렉토리라도 만들어서 마운트해줘야겠다
        • → 그래서 docker-lab이라는 폴더를 새로 생성하고 마운트해버림
      ✅ 정리하면:
      상황
      결과
      호스트 경로가 정확할 때
      해당 폴더가 컨테이너에 마운트됨
      호스트 경로가 틀리거나 없음
      Docker가 빈 폴더를 새로 생성해서 마운트함
      🧩 경로를 지정할 땐 절대경로를 정확히 확인하고, bash는 슬래시(/), powershell은 백슬래시임(\)을 기억
  • 확인
    • notion image
      notion image
      notion image
       

실습 2 - Nginx

  • Nginx 실행 확인
    • docker run -d -p 8000:80 nginx
      notion image
      notion image
      notion image
      notion image
  • Nginx의 index.html 위치 확인
    • docker exec -it 7ec6 bash
      → index.html은 /usr/share/nginx/html 폴더에 위치함
      notion image
      notion image
  • c:/workspace/docker_lab/ex01 로 마운트
    • docker run -d -p 8000:80 -v c:/workspace/docker_lab/ex01:/usr/share/nginx/html nginx
notion image

Copy

💡
마운트 보다 Copy 가 더 편하다

Copy란?

  • Dockerfile에서 호스트 시스템의 파일이나 디렉토리를 도커 이미지에 복사하는 명령어

✅ 특징 요약

항목
설명
사용 위치
Dockerfile 내부
복사 대상
현재 Dockerfile 기준의 build context 내 파일만 가능
경로 끝 슬래시 /
생략해도 되고, 붙이면 "디렉토리로 복사" 의미가 더 명확함
비교 vs ADD
COPY는 복사만, ADD는 복사 + 압축 해제 기능 있음

🧠 참고

  • Dockerfile과 같은 디렉토리에서 빌드할 때만 복사 가능
    • 외부 경로(ex. ../)는 사용할 수 없다
       

실습 3 - apache

  • html 폴더 생성 후 index.html 파일 추가
    • <h1>ex03 test</h1>
  • Dockerfile 생성
    • 스크립트 작성해서 실행시킬 수 있음
    • 내가 원하는 이미지를 만들어내는 스크립트
    • 내 애플리케이션을 실행하기 위한 환경을 어떻게 만들지?를 정의한 설계도
    • 프로비저닝 - 완성품을 만들기 위한 준비과정 (서버가 만들어질 때 도커 파일을 읽어서 실행 후 만들어짐)
    • 이전에 작성한 Dockerfile
      # 기반 이미지 설정 # eclipse-temurin은 OpenJDK 공식 이미지 중 하나 # 21-jdk는 Java 21 버전의 JDK 환경 FROM eclipse-temurin:21-jdk # 작업 디렉토리 설정 # 이후 모든 명령은 /app 디렉토리 안에서 실행됨 # COPY, CMD, RUN 등 경로 기준이 /app이 됨 WORKDIR /app # 호스트의 JAR 파일 복사 # 현재 빌드 컨텍스트에서 build/libs/ 폴더에 있는 JAR 파일을 app.jar 이름으로 컨테이너에 복사 COPY build/libs/*.jar app.jar # 환경 변수 선언 # 추후 Java 실행 시 옵션을 커스터마이징할 수 있도록 환경변수 JAVA_OPTS 설정 # 예: -Xmx512m 같은 JVM 옵션을 런타임에 주입 가능 ENV JAVA_OPTS="" # 컨테이너 시작 시 실행할 명령어 설정 # 쉘에서 명령 실행: java $JAVA_OPTS -jar app.j # 실제 실행 -> java -jar app.jar ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
      ✅ 요약
      명령어
      설명
      FROM
      Java 21 JDK가 설치된 베이스 이미지 사용
      WORKDIR /app
      작업 디렉토리를 /app으로 설정
      COPY
      빌드된 .jar 파일을 이미지에 복사
      ENV
      JVM 옵션을 환경변수로 설정 (필요 시 확장 가능)
      ENTRYPOINT
      컨테이너 실행 시 Spring Boot 앱을 시작
      • JAR 파일 기반의 자바 서버 애플리케이션을 도커 이미지로 만들어 실행
      • 실행 흐름:
          1. Java 21 환경에서
          1. JAR 파일 복사하고
          1. java -jar 명령으로 실행
      FROM httpd COPY ./htdocs /usr/local/apache2/htdocs CMD ["httpd-foreground"]
      notion image
      🧱 Dockerfile 핵심 구조
      # 1. 베이스 이미지 설정 FROM node:18-alpine # 2. 작업 디렉토리 설정 WORKDIR /app # 3. 필요한 파일 복사 COPY package*.json ./ RUN npm install # 4. 소스 코드 복사 COPY . . # 5. 앱 실행 포트 지정 (옵션) EXPOSE 3000 # 6. 컨테이너 시작 시 실행될 명령어 CMD ["npm", "start"]
      🔍 각 명령어 설명
      명령어
      의미
      FROM
      어떤 이미지를 기반으로 만들 것인지 (ex: ubuntu, node, nginx 등)
      WORKDIR
      이후 명령어들이 실행될 작업 디렉토리 설정
      COPY
      호스트(내 컴퓨터) → 이미지로 파일 복사
      RUN
      이미지 빌드 과정에서 실행할 명령어 (예: RUN npm install)
      EXPOSE
      컨테이너가 사용하는 포트를 문서화 (실제 포트 개방 아님)
      CMD
      컨테이너가 실행될 때 자동으로 실행할 명령어
      📦 사용 흐름
      1. Dockerfile 작성
      1. docker build -t my-app .
        1. → Dockerfile 기반으로 이미지 생성
      1. docker run -p 8080:3000 my-app
        1. → 이미지로 컨테이너 실행
→ 기존 순수한 이미지에 docker build 명령어를 통해 이미지를 구워내면서 실행됨
  • Docker image build
    • docker build -t webserver .
      -t webserver: 생성될 이미지에 태그(tag)webserver라는 이름을 붙임
      .: 현재 디렉토리에 있는 Dockerfile을 기준으로 빌드
      notion image
  • 이미지 확인
    • docker images
      notion image
      notion image
       
  • 이미지로 컨테이너 실행
    • docker run -p 8080:80 webserver
      notion image
      notion image
  • 확인
    • notion image
 

실습 4 - Nginx

  • Nginx 실행해서 설정파일 확인
    • docker run -d -p 8080:80 nginx
      notion image
  • Nginx 설정파일 위치 확인
    • docker exec -it 1538 bash
      → 설정파일의 위치: /etc/nginx/
    • nginx.conf
      • 기본 nginx 설정파일
      • NGINX의 최상위 설정 파일(main config)
      • user nginx; worker_processes auto; error_log /var/log/nginx/error.log notice; pid /run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; include /etc/nginx/conf.d/*.conf; }
        include /etc/nginx/conf.d/*.conf; : etc/nginx/conf.d/ 경로에 있는 모든 .conf 파일을 읽는다 / 개별 서버 설정들을 불러오는 구조
        default.conf 같은 파일을 conf.d 폴더에 넣으면 자동으로 포함 됨
       
    • default.conf
      • NGINX에서 기본으로 제공하거나, 사용자가 정의하는 서버 블록(server block) 설정 파일
      • 보통 도메인이나 포트에 따라 요청을 처리하는 규칙을 여기에 정의
      • 위치: /etc/nginx/conf.d/default.conf
      • server { listen 80; listen [::]:80; server_name localhost; // -> 기본 도메인 이름 설정 (보통 개발 환경에서 사용) #access_log /var/log/nginx/host.access.log main; location / { root /usr/share/nginx/html; // -> 웹서버가 요청에 응답할 때 기준이 되는 디렉토리 (여기서는 html 파일들이 있는 경로) index index.html index.htm; // -> 루트 경로(/) 요청 시 우선적으로 찾을 기본 파일 리스트. 첫 번째로 index.html을 찾고 없으면 index.htm } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; // -> 에러 발생 시 보여줄 HTML 파일 지정 location = /50x.html { root /usr/share/nginx/html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} }
      • /usr/share/nginx/html : 웹서버 폴더 경로
      • index.html index.htm; : 해당 파일을 읽는다
      • 기존 설정파일을 복사한 후 내가 원하는 대로 설정한다
      •  
  • 설정파일 수정
    • conf.d 폴더 생성 후 default.conf 파일 만들어서 내용 복사 → 수정
    • server { listen 5000; listen [::]:5000; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
      → 포트를 8080에서 5000으로 수정
 
  • Dockerfile
    • FROM nginx COPY ./html/ /usr/share/nginx/html COPY ./conf.d/ /etc/nginx/conf.d CMD ["nginx", "-g", "daemon off;"]
      COPY ./html/ /usr/share/nginx/html: 로컬의 html/ 폴더에 있는 정적 파일들을 컨테이너 내부의 /usr/share/nginx/html 로 복사
      COPY ./conf.d/ /etc/nginx/conf.d: 로컬의 conf.d/ 폴더에 있는 설정 파일들 (default.conf 등)을 컨테이너의 /etc/nginx/conf.d 디렉토리로 덮어씌워서 기본 설정을 원하는 방식으로 커스터마이징
      CMD ["nginx", "-g", "daemon off;"]: nginx를 포그라운드 모드로 실행해서 컨테이너가 계속 살아있도록 설정
      🔧 daemon on vs daemon off 차이
      옵션
      의미
      사용 목적
      daemon on
      NGINX를 백그라운드에서 실행 (기본값)
      일반 리눅스 환경에서 NGINX를 서비스처럼 돌릴 때 사용
      daemon off
      NGINX를 포그라운드에서 실행
      Docker 컨테이너 내부에서 사용 (컨테이너 유지 목적)
      🚀 왜 Docker에서는 daemon off를 써야 할까?
      Docker는 기본적으로 포그라운드 프로세스가 없으면 컨테이너가 자동 종료됨
      그래서 nginx가 백그라운드에서 실행되면, Docker 입장에선 “앗? 실행 중인 게 없네?” 하고 바로 컨테이너를 꺼버린다
      👉 그래서 CMD ["nginx", "-g", "daemon off;"]포그라운드에서 nginx를 실행해야 컨테이너가 계속 살아있고 웹서버도 유지됨
      Docker 컨테이너는 반드시 하나의 포그라운드 프로세스를 실행하고 있어야 컨테이너가 계속 유지된다
      • Docker는 하나의 메인 프로세스(PID 1)를 기반으로 작동하며, 이 메인 프로세스가 종료되면 컨테이너도 즉시 종료
      • 백그라운드로 실행되면 "컨테이너 안에서 실행할 게 없다"고 판단해서 종료됨.
      ✅ 결론
      도커 컨테이너는 포그라운드 실행을 원칙으로 한다.
      (즉, 컨테이너 안에서 메인 프로세스가 계속 떠 있어야 한다.)
      notion image
  • 이미지 확인
    • docker images
      notion image
  • 이미지로 컨테이너 실행
    • docker run -p 5000:5000 nginxserver
notion image

Volume

✅ Volume이란?

  • Mount 방식 중 하나
  • 컨테이너의 데이터를 지속적으로 저장하거나 공유하기 위해 사용하는 저장 공간
  • 도커가 관리하는 컨테이너 외부 저장소로, 컨테이너가 삭제돼도 데이터는 남아있도록 해주는 중요한 기능
  • 컨테이너 데이터를 안전하게 보존하고, 재사용·공유·백업까지 쉽게 가능하게 해주는 핵심 기능

✅ 왜 Volume을 쓰나?

이유
설명
🎯 데이터 유지
컨테이너를 지우거나 재시작해도 데이터는 유지됨
🛡️ 안정성
도커가 관리하므로, 경로/권한 문제 없이 안정적으로 동작
📤 데이터 공유
여러 컨테이너가 동일한 볼륨을 공유 가능
🔄 백업·복원 용이
docker volume 명령으로 쉽게 백업하거나 이동 가능
🔍 호스트 디렉토리 의존 ↓
바인드 마운트보다 안전하고 독립적

📊 Bind Mount vs Volume

구분
Bind Mount
Volume
📍 저장 위치
호스트의 지정된 경로 (예: C:/myfolder)
Docker가 관리하는 경로 (예: /var/lib/docker/volumes/)
🛠️ 생성 방법
직접 경로 지정 (-v /host/path:/container/path)
이름 지정 또는 자동 생성 (-v myvolume:/container/path)
🔧 유연성
호스트 디렉토리를 자유롭게 지정 가능
Docker가 내부적으로 관리 (보안/관리 편리)
🔐 보안
보안 취약점 우려 있음 (호스트 파일 접근 가능)
상대적으로 안전 (Docker 내부 디렉토리 관리)
🔁 백업/이동성
직접 복사해야 함
docker volume 명령어로 백업/이동 쉬움
🧪 테스트 용도
개발 환경에서 코드 실시간 반영 등 유리
배포/운영 환경에서 데이터 유지에 유리
🔍 사용 명령
-v C:/code:/app
-v myvol:/data 혹은 docker volume create myvol

✅ 요약 정리

  • Bind Mount
    • 호스트의 특정 폴더를 그대로 컨테이너에 연결
    • 💡 실시간 코드 수정 등 개발 환경에 유리
  • Volume
    • Docker가 자체적으로 생성/관리하는 디렉토리
    • 💡 데이터 유지운영 환경에 적합
 
Share article

parangdajavous