Dockerfile에 대한 학습 기록

Dockerfile

도커 파일은 쉽게말하면 컨테이너를 어떤 환경에서 만들지를 적어두는 설계도 같은 텍스트 파일이다.

  • Dockerfile = 컨테이너 제작 설명서
  • Docker image = 설명서로 만든 완성품
  • Docker container = 완성품을 실제로 실행한 상태

도커파일의 필요성

실습환경을 똑같이 재현할수있다.

  • 누구나 같은 이미지로
  • 같은 버전의 패키지와 설정으로
  • 같은 실습 환경을 만들수있다.

즉 “내 컴퓨터에서는 안된다” 라는 문제를 줄일수있다. < CTF 문제를 풀때 큰 장점


환경을 빠르게 만들거나 지울 수 있다.

  • DVWA
  • WebGoat
  • Burp Suite 연동 웹앱

이런 환경들은 직접 설치해서 사용하기 꺼려지는데 이럴때 Docker를 쓰면 환경 생성이나 삭제 실습에 용이하다는 장점이있다.


웹 보안 공부 - 실무연계

실무에서 AppSec, DevSecOps, 클라우드 보안까지 연결된다면 Docker 이해는 거의 필수에 가깝다.
단순하게 실습에서만 용이한것이 아닌 현업 웹 서비스 구조를 이해하는데도 도움이 된다.


Dockerfile 없이도 Docker 쓸수있는데 왜 Dockerfile을 쓸까

컨테이너를 그냥 실행해서 안에서 여러가지 설치가 가능하다. 하지만 무슨 작업을 했는지 기록이 잘 안남고,
다른 사람이 똑같이 만들기 어렵고, 다시 만들 때 수작업으로 반복해야하며 실수 가능성이 크다.

Dockerfile 사용

  • 코드로 설정이 기록.
  • 재현 가능.
  • 버전 관리 가능.
  • 상태 그대로 공유 가능.

Dockerfile의 기본 구조

1
2
3
4
5
6
FROM python:3.11-slim
WORKDIR /app
COPY . /app
RUN pip install flask
EXPOSE 5000
CMD ["python", "app.py"]

이를 분석해보면

  • FROM python:3.11-slim
    • 파이썬 3.11이 설치된 가벼운 이미지를 기반으로 시작
  • WORKDIR /app
    • 작업 디렉터리를 /app으로 설정
  • COPY . /app
    • 현재 폴더 파일들을 컨테이너 안 /app으로 복사
  • RUN pip install flask
    • Flask 설치
  • EXPOSE 5000
    • 컨테이너가 5000 포트를 사용한다고 문서화
  • CMD [“python”, “app.py”]
    • 컨테이너 시작 시 python app.py 실행

Dockerfile 핵심 명령어

FROM

1
FROM ubuntu:22.04
  • 어떤 베이스 이미지에서 시작할지를 정한다.

WORKDIR

1
WORKDIR /app
  • 이후 명령이 실행될 기본 디렉토리를 지정한다. 리눅스의 cd /app 와 비슷

COPY

1
COPY . /app
  • 호스트의 파일을 컨테이너 이미지 안으로 복사한다.

RUN

1
2
RUN apt-get update && apt-get install -y curl
RUN pip install -r requirements.txt
  • 이미지를 빌드할때 실행하는 명령어이다.

CMD

1
CMD ["python", "app.py"]
  • 컨테이너가 시작될때 기본으로 실행할 명령이다.
  • RUN - 빌드 / CMD - 실행

EXPOSE

1
EXPOSE 80
  • 컨테이너가 80의 포트를 사용한다고 표시하는것이다.
    1
    
    docker run -p 8080:80 myweb
    
  • 실제로 접속을 위해선 실행할때 포트 매핑이 필요하다. / My computer(8080) → 컨테이너(80) 연결

ENV

1
ENV APP_ENV=development
  • 환경변수를 설정한다. / 민감정보는 Dockerfile에 직접 박는건 좋지않다.

USER

1
USER appuser
  • 이후 명령 또는 실행 프로세스를 특정 사용자로 수행한다.

Dockerfile의 동작

Dockerfile은 위에서 아래로 읽힌다. 각 줄은 보통 레이어(Layer)를 만든다.

1
2
3
4
FROM ubuntu:22.04
RUN apt-get update
RUN apt-get install -y nginx
COPY . /app
  • 각 단계가 하나의 레이어처럼 쌓인다.

빌드 & 실행

빌드는 도커파일이 있는 폴더에서

1
docker build -t myapp .
  • 현재 폴더(.)의 Dockerfile로 이미지를 생성한다.
  • 이름을 myapp으로 설정한다.

실행

1
docker run -p 5000:5000 myapp
  • myapp 이미지를 실행한다.
  • 호스트 5000 포트와 컨테이너 5000 포트가 연결된다.

백그라운드 실행

1
docker run -d -p 5000:5000 myapp
  • -d는 detached 모드이다.

컨테이너 목록 확인

1
docker ps

중지

1
docker stop <컨테이너ID>

Flask 취약

예를 들어 Flask 앱을 만든다고 했을때

app.py

1
2
3
4
5
6
7
8
9
from flask import Flask
app = Flask(__name__)

@app.route("/")
def home():
    return "Hello, Web Security!"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

requirements.txt

1
flask

Dockerfile

1
2
3
4
5
6
7
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt /app
RUN pip install --no-cache-dir -r requirements.txt
COPY . /app
EXPOSE 5000
CMD ["python", "app.py"]

이렇게 하게되면

1
2
docker build -t flask-lab .
docker run -p 5000:5000 flask-lab

브라우저에서 접속이 가능하다. COPY requirements.txt 를 먼저하는 이유는 의존성 설치 캐시를 잘 활용하기 위함이다.
소스코드만 바뀌면 pip install 을 매번 다시 안해도된다.


Dockerfile 작성 흐름

  1. 베이지 이미지를 선택한다.
    • 어떤 기술 스택인지 결정 ex) Python, Node, PHP, Ubuntu
  2. 작업 디렉토리를 설정한다.
  3. WORKDIR /app
  4. 의존성 파일을 복사한다.
  5. COPY requirements.txt .
  6. 패키지를 설치한다.
  7. RUN pip install -r requirements.txt
  8. 소스코드를 복사한다.
  9. COPY . .
  10. 포트를 문서화 한다.
  11. EXPOSE 5000
  12. 실행 명령을 지정한다.
  13. CMD [“python”, “app.py”]

Dockerfile 과 Docker Compose 의 차이?

  • Dockerfile
    • 하나의 이미지를 어떻게 만들지 정의한다. - 개별 부품을 만드는법
  • Docker Compose
    • 여러 컨테이너를 어떻게 함께 실행할지 정의한다. - 부품들을 조립해서 함께 실행하는법