Images vs Containers
- 이미지를 기반으로 여러 개의 컨테이너를 생성할 수 있다:
- 이미지는 애플리케이션의 모든 설정, 명령어, 코드가 포함된 불변(immutable) 패키지이다.
- 컨테이너는 이 이미지를 바탕으로 실행되는 독립적인 실행 인스턴스이다.
- 즉, 이미지는 애플리케이션을 실행하기 위한 **청사진(blueprint)**이며, 컨테이너는 그 이미지를 기반으로 실행된 애플리케이션이다.
- 간단히 말해, 이미지는 템플릿이고, 컨테이너는 실행 중인 인스턴스라고 볼 수 있다.
- 이미지를 직접 실행하는 것이 아니라, 이미지를 기반으로 컨테이너를 실행하는 것이다.
- 비유: 이미지 = 청사진(코드 + 설정), 컨테이너 = 그 청사진을 바탕으로 실행된 실제 애플리케이션 인스턴스
Image
- 이미지를 만드는 방법에는 두 가지가 있다:
- 기존 이미지 사용: Docker Hub와 같은 저장소에서 **프리빌트 이미지(Pre-built Image)**를 가져다 사용할 수 있다. 예를 들어, Node.js, Python, Nginx와 같은 이미지들이 존재하며, 이들을 다운로드하여 바로 사용할 수 있다.
예: docker pull nginx 명령어로 Nginx 이미지를 로컬에 다운로드하고 실행 가능하다.
- 사용자 정의 이미지 생성(Custom Image): 특정 애플리케이션에 맞춘 커스텀 이미지를 만들려면, Dockerfile을 사용해 이미지를 빌드할 수 있다. Dockerfile은 이미지 빌드 과정을 설명하는 스크립트로, 베이스 이미지와 추가할 패키지, 설정 등을 정의한다. Dockerfile은 애플리케이션을 실행하기 위한 설정 파일과 유사하다.
- 사용자 정의 이미지 생성 과정
- 커스텀 이미지를 만들기 위해 Dockerfile 작성이 필요하다. Dockerfile은 애플리케이션 실행 환경을 설정하는 명령어들로 이루어져 있다.
- Dockerfile 기본 구조
- FROM: 베이스 이미지를 정의. 예: FROM ubuntu는 Ubuntu를 기반으로 하는 이미지를 사용한다.
- RUN: 이미지를 빌드하는 동안 실행할 명령어를 정의. 예: RUN apt-get update는 시스템을 업데이트한다.
- COPY: 로컬 파일 시스템의 파일을 컨테이너 이미지로 복사.
- CMD 또는 ENTRYPOINT: 컨테이너가 시작될 때 실행할 명령어 지정. 종료 시 컨테이너도 종료된다.
- 이 예시는 Node.js 애플리케이션을 위한 Dockerfile 예시이다. 주요 명령어들은 다음과 같다:
- FROM node: Node.js 베이스 이미지 사용.
- WORKDIR /app: 컨테이너 내부 작업 디렉토리를 /app으로 설정.
- COPY ./app: 현재 디렉토리의 모든 파일을 컨테이너 내부로 복사.
- RUN npm install: 컨테이너 내부에서 의존성 설치.
- EXPOSE 80: 외부에서 컨테이너의 포트 80으로 접근할 수 있게 설정.
- CMD ["node", "server.js"]: 컨테이너 시작 시 Node.js 서버 실행.
FROM node
WORKDIR /app
COPY . /app
RUN npm install
EXPOSE 80
CMD ["node", "server.js"]
- Dockerfile 작성: 애플리케이션 실행에 필요한 설정 및 명령어를 포함한 Dockerfile을 작성한다.
- Docker 빌드 명령: docker build 명령어로 Dockerfile을 기반으로 이미지를 빌드한다.
예: docker build -t myapp . 명령어로 myapp이라는 이름의 이미지를 생성.
- 컨테이너 실행: 빌드된 이미지를 기반으로 컨테이너를 실행한다. 예: docker run -p 80:80 myapp 명령어로 myapp 이미지를 기반으로 컨테이너를 생성하고, 호스트 시스템의 포트 80을 컨테이너 내부 포트 80에 연결하여 트래픽을 전달.
내부 코드 수정 후 커스텀 이미지 재빌드
- 코드 변경 후 docker build . 명령어로 이미지를 재빌드하면, Docker는 기존 이미지의 **레이어(layer)**들을 캐시로 저장해 둔다. Docker 이미지는 각 명령어 실행 시 새로운 레이어가 생성되고, Docker는 이를 재사용하려고 시도한다.
- 캐시 사용
- Docker는 캐시된 레이어를 사용하여 빌드 시간을 단축한다. 예를 들어, 이전에 실행된 명령어와 동일한 명령어가 Dockerfile에 포함되어 있으면, Docker는 캐시된 레이어를 사용하여 다시 실행하지 않는다.
- 레이어 재사용
- Dockerfile의 COPY package.json /app과 RUN npm install은 package.json이 변경되지 않는 한 캐시된 레이어를 재사용한다. 이는 빌드 시간을 줄이는 중요한 방법이다.
# 기존 순서
COPY . /app
RUN npm install
- 위와 같은 구조는 코드가 변경될 때마다 npm install이 재실행된다. 그러나 이는 불필요한 작업이다. 의존성 관리가 코드와 무관하므로 비효율적이다.
# 수정된 순서
COPY package.json /app
RUN npm install
COPY . /app
- 순서를 변경하면, package.json 파일이 변경되지 않는 한 npm install은 캐시된 레이어를 재사용하고, 의존성 설치가 생략되며 나머지 파일만 복사된다.