1. Introduction
Docker와 Dockerfile이란?
최근 몇 년간 Docker는 개발 환경 및 애플리케이션 배포를 효율적으로 간소화하는 방법으로 빠르게 인기를 얻었습니다. Docker는 애플리케이션과 그 의존성을 “컨테이너”라는 단일 단위로 패키징하여, 서로 다른 환경에서도 일관되게 실행될 수 있게 합니다.
이러한 Docker 컨테이너를 만들기 위해서는 Dockerfile이라는 청사진이 필요합니다. Dockerfile은 기본 운영체제 이미지, 설치할 소프트웨어, 환경 변수 및 기타 설정 세부 정보를 정의하는 텍스트 파일입니다. 개발자는 이를 사용해 맞춤형 환경을 자동으로 빌드할 수 있습니다.
왜 Ubuntu를 베이스 이미지로 사용할까?
Dockerfile을 만들 때 가장 먼저 해야 할 일은 베이스 운영체제 이미지를 선택하는 것입니다. 다양한 옵션 중 Ubuntu는 가장 많이 사용되는 이미지 중 하나입니다. Ubuntu는 사용이 간편하고 방대한 패키지 생태계가 지원하는 유연한 환경 설정으로 알려진 Debian 기반 Linux 배포판입니다.
Ubuntu 기반 Dockerfile은 다음과 같은 장점을 제공합니다:
- 풍부한 공식 및 커뮤니티 문서 덕분에 학습 곡선이 낮음
- APT를 이용한 패키지 및 도구 설치가 쉬움
ubuntu:20.04,ubuntu:24.04와 같은 공식 경량·미니멀 이미지 제공
이 글의 목적 및 대상 독자
이 글은 키워드 “Dockerfile Ubuntu”에 초점을 맞추어, 초보자도 이해하기 쉬운 방식으로 Ubuntu 기반 Dockerfile을 만드는 방법을 설명합니다.
Dockerfile의 기본 구조부터 Ubuntu 환경을 구축하는 단계별 절차, Python과 같은 애플리케이션 환경 설정 예시, 흔히 발생하는 오류와 해결 방법까지 모두 다룹니다.
이 글은 다음과 같은 분들에게 권장됩니다:
- 처음으로 Dockerfile을 사용해 환경을 구축하고자 하는 분
- Ubuntu에서 재현 가능한 개발 환경을 만들고 싶은 개발자
- 트러블슈팅 기법을 포함해 이해도를 높이고 싶은 모든 분
2. Basic Structure of a Dockerfile
Dockerfile이란 무엇이며 그 역할은?
Dockerfile은 Docker 이미지를 만들기 위한 레시피와 같습니다. 어떤 베이스 운영체제를 사용할지, 어떤 소프트웨어를 설치할지, 환경을 어떻게 설정할지를 정의합니다.
이 파일을 기반으로 docker build 명령을 실행하면, 높은 재현성을 가진 개발 및 런타임 환경을 손쉽게 만들 수 있습니다.
Dockerfile 사용의 장점:
- 자동화된 환경 설정(수동 반복 작업 불필요)
- 팀 개발 시 환경 불일치 해소
- CI/CD 파이프라인에 손쉽게 통합
자주 사용되는 Dockerfile 명령어
Dockerfile은 여러 명령어(디렉티브)로 구성됩니다. 아래는 가장 많이 사용되는 명령어들 중 일부이며, 적절히 조합하면 Ubuntu 기반 Dockerfile을 만들 수 있습니다.
| Instruction | Description |
|---|---|
FROM | Specifies the base Docker image (e.g., FROM ubuntu:24.04) |
RUN | Executes shell commands, typically for installing packages |
COPY | Copies local files into the image |
ADD | Similar to COPY, but also supports URLs and archive extraction |
WORKDIR | Sets the working directory |
ENV | Defines environment variables |
CMD | Defines the default command executed at container startup (can be overridden) |
ENTRYPOINT | Defines a command that is always executed at container startup |
최소한의 Ubuntu 기반 Dockerfile 예시
아래는 Ubuntu를 베이스 이미지로 사용한 매우 기본적인 Dockerfile 예시입니다.
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y \
curl \
vim
CMD ["/bin/bash"]
이 Dockerfile은 Ubuntu 24.04를 베이스 이미지로 사용하고, curl과 vim 유틸리티를 설치한 뒤, 컨테이너가 시작될 때 Bash 쉘을 실행합니다.
적절한 Ubuntu 태그 선택하기
Ubuntu Docker 이미지는 공식 Docker Hub 저장소에 게시됩니다. ubuntu:latest를 지정하면 최신 버전을 사용하지만, 버전을 명시적으로 고정하는 것이 권장됩니다.
예시:
ubuntu:22.04(LTS: 장기 지원, 안정성 중심)ubuntu:24.04(최신 LTS, 최신 기능 중심)
안정성을 중시할지, 최신 기능을 중시할지에 따라 버전을 선택하세요.
3. Practical: Creating an Ubuntu-Based Dockerfile
Ubuntu 환경에서 필요한 패키지 설치하기
markdown.
Ubuntu 환경을 Dockerfile로 구축할 때 추가 패키지를 설치해야 하는 경우가 많습니다. 예를 들어, 개발 환경을 설정할 때 다음 유틸리티를 자주 사용합니다:
curl: 파일 다운로드 및 API 테스트용vim: 가벼운 텍스트 편집기git: 버전 관리 시스템build-essential: C/C++ 프로그램 빌드에 필요한 필수 도구
Dockerfile에서 이러한 패키지를 설치하려면 RUN 명령을 사용합니다.
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y \
curl \
vim \
git \
build-essential
먼저 apt-get update를 실행하면 최신 패키지 목록을 가져온 뒤 설치를 진행할 수 있습니다.
비대화식 설치 설정
Ubuntu에서 apt-get install은 때때로 사용자 입력을 요구합니다. 그러나 Docker 빌드 중에는 대화형 작업이 불가능합니다. 이를 방지하려면 환경 변수를 설정하고 비대화식 모드를 활성화하는 것이 좋습니다.
ENV DEBIAN_FRONTEND=noninteractive
이렇게 하면 로케일이나 시간대 선택과 같은 프롬프트가 표시되지 않아 설치가 원활히 진행됩니다.
불필요한 캐시 제거로 이미지 크기 줄이기
APT를 사용할 때 다운로드된 임시 파일(캐시)이 이미지에 남아 최종 크기가 커질 수 있습니다. 아래와 같이 캐시를 제거하면 이미지 크기를 줄일 수 있습니다.
RUN apt-get update && apt-get install -y \
curl \
vim \
&& rm -rf /var/lib/apt/lists/*
여러 명령을 하나의 RUN 명령으로 결합하면 레이어가 불필요하게 증가하는 것을 방지할 수 있습니다.
Dockerfile 작성 시 모범 사례
실제 개발 환경에서는 다음과 같은 Dockerfile 모범 사례가 널리 권장됩니다:
- 가능한 한
RUN명령을 결합하여 레이어 수를 줄이기 ENV를 사용해 버전 및 설정을 명시적으로 정의하기- 각 단계의 목적을 명확히 설명하기 위해 주석 활용하기
rm및--no-install-recommends옵션을 사용해 불필요한 파일 남기지 않기
예시:
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
git \
&& rm -rf /var/lib/apt/lists/*
이러한 접근 방식은 가볍고 유지보수가 쉬운 Dockerfile을 만들 수 있게 해줍니다.
4. Docker 이미지 빌드 및 검증
Dockerfile로부터 Docker 이미지 빌드
Dockerfile이 준비되면 다음 단계는 Docker 이미지 빌드입니다. docker build 명령을 사용합니다. Dockerfile이 있는 디렉터리에서 아래 명령을 실행하세요:
docker build -t my-ubuntu-image .
-t옵션은 이미지에 이름(태그)을 지정합니다. 여기서는 이미지 이름을my-ubuntu-image로 지정했습니다..은 Dockerfile이 위치한 현재 디렉터리를 의미합니다.
Docker는 Dockerfile의 명령을 순차적으로 읽어 이미지를 빌드합니다.
빌드된 Docker 이미지 확인
이미지가 성공적으로 빌드된 후에는 다음 명령으로 확인할 수 있습니다:
docker images
이 명령은 로컬에 저장된 Docker 이미지 목록을 표시하며, 다음과 같은 정보를 포함합니다:
- REPOSITORY (이미지 이름)
- TAG
- IMAGE ID (고유 식별자)
- CREATED (생성 날짜)
- SIZE
예시:
REPOSITORY TAG IMAGE ID CREATED SIZE
my-ubuntu-image latest abcd1234abcd 5 minutes ago 189MB
이를 통해 이미지가 정상적으로 등록되었는지 확인할 수 있습니다.
검증을 위한 Docker 컨테이너 실행
생성된 이미지가 기대대로 동작하는지 확인하려면 아래 명령으로 Docker 컨테이너를 시작합니다:
docker run -it my-ubuntu-image
-it옵션은 인터랙티브 터미널 세션을 시작합니다.- 성공하면 Bash 프롬프트가 나타나 Ubuntu 컨테이너 안에 들어왔음을 알 수 있습니다.
컨테이너 내부에서 다음과 같은 명령으로 설치된 도구들을 확인할 수 있습니다:
curl --version
vim --version
이 명령어들이 올바르게 작동한다면, Dockerfile이 제대로 구성된 것입니다.
사용하지 않는 이미지와 컨테이너 정리
반복적인 빌드와 실험으로 인해 시스템에 사용하지 않는 Docker 이미지와 컨테이너가 남아 있을 수 있습니다. 다음 명령어를 사용하여 주기적으로 이를 정리하는 것이 좋습니다:
- 중지된 컨테이너 제거:
docker container prune
- 사용하지 않는 이미지 제거:
docker image prune
- 모든 사용하지 않는 데이터 제거 (주의해서 사용):
docker system prune
이러한 작업은 디스크 공간을 절약하고 잠재적인 문제를 방지하는 데 도움이 됩니다.
5. 고급: Python 환경 빌드
Ubuntu 기반 Dockerfile에서 Python 활성화
Dockerfile을 사용하여 Ubuntu 환경을 빌드할 때 Python 런타임 환경을 추가하면 개발, 테스트, 머신러닝을 포함한 다양한 사용 사례를 가능하게 합니다. Ubuntu에 Python이 기본적으로 설치되어 있을 수 있지만, 더 나은 버전 및 패키지 관리를 위해 명시적으로 구성하는 것이 일반적인 관행입니다.
APT를 사용한 Python 설치
가장 간단한 방법은 APT 패키지를 사용하여 Python을 설치하는 것입니다. 아래는 예시입니다:
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/*
이 방법은 안정적인 시스템 Python 버전(예: Ubuntu 릴리스에 따라 Python 3.10 또는 3.12)을 제공합니다. pip 명령어를 사용하여 추가 Python 패키지도 설치할 수 있습니다.
pyenv를 사용한 Python 버전 관리
특정 Python 버전이 필요하거나 여러 버전 간에 전환하고 싶다면 pyenv를 사용하는 것이 강력히 권장됩니다.
다음 예시는 Dockerfile에서 pyenv를 사용하여 Python 3.11.6을 설치하는 방법을 보여줍니다:
FROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
git \
curl \
make \
build-essential \
libssl-dev \
zlib1g-dev \
libbz2-dev \
libreadline-dev \
libsqlite3-dev \
wget \
llvm \
libncurses5-dev \
libncursesw5-dev \
xz-utils \
tk-dev \
libffi-dev \
liblzma-dev \
&& rm -rf /var/lib/apt/lists/*
# Install pyenv
RUN git clone https://github.com/pyenv/pyenv.git ~/.pyenv
ENV PYENV_ROOT="$HOME/.pyenv"
ENV PATH="$PYENV_ROOT/bin:$PATH"
RUN echo 'eval "$(pyenv init --path)"' >> ~/.bashrc
# Install a specific Python version
RUN pyenv install 3.11.6 && pyenv global 3.11.6
이 설정은 유연하고 잘 제어된 Python 환경을 제공합니다.
requirements.txt를 사용한 패키지 관리
대부분의 실제 프로젝트는 여러 Python 라이브러리를 필요로 합니다. 이러한 종속성은 일반적으로 requirements.txt 파일을 사용하여 관리됩니다.
먼저, 프로젝트 루트에 requirements.txt 파일을 생성합니다:
flask==2.3.2
requests>=2.25.1
pandas
그 다음 Dockerfile에서 다음과 같이 참조합니다:
COPY requirements.txt /app/requirements.txt
WORKDIR /app
RUN pip install --no-cache-dir -r requirements.txt
이렇게 하면 모든 필요한 라이브러리를 한 번에 설치할 수 있으며 환경 재현성을 크게 향상시킵니다.
모범 사례
- Python을 사용할 때
virtualenv또는venv로 가상 환경을 생성하면 종속성 충돌을 방지하는 데 도움이 됩니다. --no-cache-dir와 같은 캐시 억제 옵션을 사용하면 Docker 이미지 크기를 줄일 수 있습니다.- 패키지를 설치하기 전에
pip install --upgrade pip를 실행하면 설치 오류를 피하는 데 도움이 됩니다.
6. 일반적인 문제 및 문제 해결
권한 오류
예시:
Permission denied
이 오류는 복사된 파일에 실행 권한이 없거나 파일 소유권과 실행 사용자가 잘못 구성되었을 때 발생합니다.
해결 방법:
- 파일을 실행 가능하게 만듭니다:
RUN chmod +x script.sh
- 필요 시 파일 소유권을 변경합니다:
RUN chown root:root /path/to/file
패키지 찾을 수 없음 또는 설치 실패
예시:
E: Unable to locate package xxx
이 오류는 일반적으로 apt-get update가 실행되지 않았거나 패키지 이름이 잘못된 경우에 발생합니다.
해결 방법:
- 패키지 설치 전에 항상
apt-get update를 실행하세요:RUN apt-get update && apt-get install -y curl
- 패키지 이름을 확인하고 오타를 확인하세요
네트워크 관련 오류
예시:
Temporary failure resolving 'deb.debian.org'
이 오류는 빌드 과정에서 DNS 해석 문제를 나타냅니다.
해결 방법:
- Docker 데몬을 재시작하면 문제를 해결할 수 있습니다:
sudo systemctl restart docker
/etc/docker/daemon.json에 DNS 서버를 추가하여 Docker DNS 설정을 검토하세요:{ "dns": ["8.8.8.8", "8.8.4.4"] }
오래된 캐시를 사용한 빌드
Docker는 빌드를 가속화하기 위해 레이어 기반 캐싱을 사용합니다. 그 결과, Dockerfile의 변경 사항이 즉시 반영되지 않을 수 있습니다.
해결 방법:
- 캐시 없이 다시 빌드:
docker build --no-cache -t my-image .
컨테이너가 즉시 종료되거나 시작 명령어가 실행되지 않음
원인:
CMD또는ENTRYPOINT에 지정된 명령어에 오류가 있음- 대화형 모드 없이
CMD ["/bin/bash"]를 사용하면 즉시 종료됨
해결 방법:
- 디버그 모드로 컨테이너를 시작:
docker run -it my-image /bin/bash
CMD와ENTRYPOINT의 차이점을 이해하고 적절히 사용
이러한 문제를 만나고 해결함으로써 Dockerfile 설계 기술이 꾸준히 향상될 것입니다. 오류가 발생하면 오류 메시지를 주의 깊게 읽고 어떤 지시문과 레이어가 문제를 일으켰는지 식별하세요.
7. 요약
Ubuntu 기반 Dockerfile 생성의 주요 요점
이 기사는 Dockerfile을 사용하여 Ubuntu 환경을 빌드하는 방법에 대한 단계별 설명을 제공하며, 기본 및 고급 주제를 다룹니다. 주요 포인트를 검토해 보겠습니다:
- Dockerfile 기본 이해가 첫 번째 단계입니다
FROM,RUN,CMD,ENV등의 지시문은 자동화된 환경 생성을 가능하게 합니다. - Ubuntu는 안정적이고 유연한 베이스 이미지입니다 광범위한 패키지 생태계, 대규모 사용자 기반, LTS 릴리스가 개발 환경에 이상적입니다.
- 실용적인 패키지 관리는 필요한 도구와 라이브러리 설치를 허용합니다
apt-get의 적절한 사용, 캐시 정리, 비대화형 설치는 필수입니다. - Python과 같은 실용적인 환경 빌드는 Dockerfile에 의해 완전히 지원됩니다
pyenv,pip,requirements.txt와 같은 도구는 재현 가능한 설정을 보장합니다. - 문제 해결 기술은 안정적인 운영에 직접적인 영향을 미칩니다 권한, 네트워킹, 빌드 캐시 동작 이해는 생산성을 크게 향상시킵니다.
Dockerfile 학습의 다음 단계
Dockerfile 사용에 익숙해지면 개발을 넘어 테스트와 프로덕션 배포로 기술을 확장할 수 있습니다. 다음 주제를 탐구해 보세요:
- Docker Compose를 사용한 멀티 컨테이너 설정 관리
- GitHub Actions 및 GitLab CI와 같은 CI/CD 도구와의 통합
- Kubernetes와 같은 컨테이너 오케스트레이션 플랫폼 작업
공식 문서 및 참조 링크
8. 자주 묻는 질문 (FAQ)
Q1. Dockerfile에서 어떤 Ubuntu 버전을 선택해야 하나요?
A1. 대부분의 경우 안정성과 장기 유지보수를 위해 LTS (Long Term Support) 릴리스를 선택하는 것이 권장됩니다. ubuntu:22.04 및 ubuntu:20.04와 같은 버전은 널리 사용되며 5년 동안 지원됩니다.
최신 패키지나 언어 버전이 필요하다면 ubuntu:24.04와 같은 최신 릴리스를 선택할 수 있지만, 철저한 테스트가 권장됩니다.
Q2. 왜 apt-get install이 “package not found”를 보고하나요?
.A2. 가장 흔한 이유는 사전에 apt-get update를 실행하지 않은 것입니다. 패키지 목록을 업데이트하지 않으면 APT가 요청된 패키지를 찾을 수 없습니다.
Correct example:
RUN apt-get update && apt-get install -y curl
패키지 이름이 올바르고 더 이상 사용되지 않는 것이 아닌지 확인하십시오(예: python 대신 python3를 사용).
Q3. Dockerfile에서 환경 변수를 어떻게 설정합니까?
A3. ENV 명령을 사용하여 빌드 시와 컨테이너 실행 시 모두 사용할 수 있는 환경 변수를 정의합니다.
Example:
ENV DEBIAN_FRONTEND=noninteractive
이는 APT 설치 중 대화형 프롬프트를 억제하는 데 일반적으로 사용됩니다. 환경 변수는 애플리케이션 구성 및 API 키에도 유용합니다.
Q4. CMD와 ENTRYPOINT의 차이점은 무엇인가요?
A4. 두 명령 모두 컨테이너가 시작될 때 실행되는 명령을 지정하지만 동작 방식이 다릅니다.
| Item | CMD | ENTRYPOINT |
|---|---|---|
| Overridable | Can be overridden by docker run | Generally not overridden (treated as fixed command) |
| Use Case | Define a default command | Define a command that must always run |
Example:
CMD ["python3", "app.py"]
# vs
ENTRYPOINT ["python3"]
CMD ["app.py"]
후자의 경우 docker run my-image another_script.py와 같이 인수를 전달할 수 있습니다.
Q5. Dockerfile 변경 사항이 반영되지 않는 이유는 무엇인가요?
A5. Docker는 빌드 캐시를 사용하므로 Dockerfile을 수정한 후에도 변경되지 않은 레이어가 재사용될 수 있습니다.
Solution:
docker build --no-cache -t my-image .
이렇게 하면 전체 재빌드를 강제하고 모든 변경 사항이 적용됩니다.


