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 작성 흐름
- 베이지 이미지를 선택한다.
- 어떤 기술 스택인지 결정 ex) Python, Node, PHP, Ubuntu
- 작업 디렉토리를 설정한다.
- WORKDIR /app
- 의존성 파일을 복사한다.
- COPY requirements.txt .
- 패키지를 설치한다.
- RUN pip install -r requirements.txt
- 소스코드를 복사한다.
- COPY . .
- 포트를 문서화 한다.
- EXPOSE 5000
- 실행 명령을 지정한다.
- CMD [“python”, “app.py”]
Dockerfile 과 Docker Compose 의 차이?
- Dockerfile
- 하나의 이미지를 어떻게 만들지 정의한다. - 개별 부품을 만드는법
- Docker Compose
- 여러 컨테이너를 어떻게 함께 실행할지 정의한다. - 부품들을 조립해서 함께 실행하는법