Docker #2 - 이미지, 컨테이너, Dockerfile, 읽기 전용 레이어
Docker 이미지와 컨테이너의 동작 원리, Dockerfile 작성법, 이미지 레이어와 캐싱 전략
Docker #2 - 이미지, 컨테이너, Dockerfile, 읽기 전용 레이어
이미지 (Image)
설계도만 있다면 어디서든 동일한 결과물(컨테이너)를 만들어 낼 수 있다.
재사용성: 한번만 잘 만들어 두면 이미지를 팀원과 공유하거나 여러 서버에 배포하여 동일한 환경을 수십, 수백 개 복제할 수 있다.
불변성 (Immutable): 이미지는 한 번 빌드되면 내용이 변하지 않는다.
- 만약 프로젝트를 진행하다가 코드에 변경 사항이 생기는 경우, 변경된 코드를 포함하여 새로운 이미지를 다시 빌드해야 한다.
컨테이너 (Container)
이미지의 실행 가능한 인스턴스(Instance)이다.
- 격리된 실행 공간: 실제 애플리케이션이 실행되는 격리된 공간이다.
- 독립성: 컨테이너는 호스트 시스템이나 다른 컨테이너와 완전히 분리되어 독립적으로 작동한다.
멀티 애플리케이션 지원: 덕분에 하나의 서버에서 여러 애플리케이션을 충돌 없이 실행할 수 있다.
- 1:N 관계: 하나의 이미지로 여러 개의 컨테이너를 생성하고 실행할 수 있으며, 각 컨테이너는 서로 영향을 주지 않는 독립적인 환경이기 때문에 충돌이 발생하지 않는다.
Dockerfile 작성법
Dockerfile은 이미지를 어떻게 만들지 도커에게 알려주는 텍스트 파일이다.
1
2
3
4
5
6
7
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 80
CMD ["node", "server.js"]
주요 명령어 설명
- FROM node:18-alpine
- 어떤 베이스 이미지에서 시작할지 지정한다.
- 이미 검증된 Node.js 공식 이미지를 기반으로 우리만의 설정을 추가하겠다는 의미이다.
- WORKDIR /app
- 컨테이너 내부의 작업 디렉터리를
/app
으로 설정한다. - 이후의 COPY, RUN 등의 명령어는 이 디렉터리를 기준으로 실행된다.
- 컨테이너 파일 시스템의 루트를 어지럽히지 않고 깔끔하게 관리할 수 있다.
- 컨테이너 내부의 작업 디렉터리를
- COPY package*.json ./
- 의존성 설정 파일을 먼저 복사한다.
- RUN npm install
- 이미지를 빌드하는 과정에서 실행할 명령이다.
- 필요한 모든 의존성 패키지를 이미지 내부에 설치한다.
- COPY . .
- 현재 디렉터리의 모든 파일과 폴더를 컨테이너의
/app
디렉터리로 복사한다.
- 현재 디렉터리의 모든 파일과 폴더를 컨테이너의
- EXPOSE 80
- 이 컨테이너가 80번 포트를 사용할 것임을 문서화하는 역할을 한다.
- 실제로 포트를 외부에 노출시키지는 않지만, 이 이미지를 사용하는 다른 사람에게 어떤 포트를 열어야 하는지 알려주는 중요한 정보이다.
- CMD [“node”, “server.js”]
- 이 이미지로부터 컨테이너가 시작될 때 실행될 기본 명령이다.
- RUN과의 결정적인 차이점이다.
이미지 레이어와 캐싱 전략
도커 이미지는 여러 개의 읽기 전용 레이어가 겹쳐진 구조로 되어 있다.
레이어 구조의 이해
- 레이어 생성: Dockerfile의 각 명령어는 새로운 레이어를 생성한다.
- 레이어 스택: 여러 레이어가 겹쳐져서 최종 이미지를 만든다.
- 읽기 전용: 각 레이어는 한 번 생성되면 변경되지 않는다.
캐싱 메커니즘
- 캐시 저장:
docker build
를 실행할 때, 도커는 각 명령어(레이어)의 결과를 캐시에 저장한다. - 캐시 재사용: 다음 번에 빌드할 때는 Dockerfile의 내용이나 COPY할 파일의 내용이 바뀌지 않았다면, 도커는 명령을 다시 실행하지 않는다.
- 레이어 무효화: 한 레이어가 변경되면 그 이후의 모든 레이어가 무효화된다.
빌드 최적화 전략
문제 상황:
1
2
3
# 비효율적인 순서
COPY . . # 소스코드 변경 시 이 레이어가 무효화됨
RUN npm install # 매번 다시 실행됨
해결 방법:
1
2
3
4
# 효율적인 순서
COPY package*.json ./ # 의존성 파일만 먼저 복사
RUN npm install # package.json이 동일하면 캐시 사용
COPY . . # 나머지 소스코드 복사
최적화 효과:
- 소스코드가 변경되어도
package.json
이 동일하면npm install
은 캐시를 사용 - 빌드 시간이 크게 단축됨
- 불필요한 의존성 재설치 방지
주요 도커 명령어
이미지 관련 명령어
1
2
3
4
5
6
7
8
9
10
11
# 이미지 빌드
docker build -t my-app .
# 이미지 목록 확인
docker images
# 이미지 삭제
docker rmi <image_id>
# 이미지 상세 정보 확인
docker inspect <image_id>
컨테이너 관련 명령어
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 컨테이너 실행
docker run -p 3000:3000 my-app
# 백그라운드에서 컨테이너 실행
docker run -d -p 3000:3000 my-app
# 실행 중인 컨테이너 확인
docker ps
# 모든 컨테이너 확인 (중지된 것 포함)
docker ps -a
# 컨테이너 중지
docker stop <container_id>
# 컨테이너 삭제
docker rm <container_id>
# 컨테이너 로그 확인
docker logs <container_id>
# 실행 중인 컨테이너에 접속
docker exec -it <container_id> /bin/bash
유용한 옵션들
1
2
3
4
5
6
7
8
9
10
11
# 포트 매핑
docker run -p 8080:3000 my-app
# 환경 변수 설정
docker run -e NODE_ENV=production my-app
# 볼륨 마운트
docker run -v /host/path:/container/path my-app
# 컨테이너 이름 지정
docker run --name my-container my-app
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.