[Docker] 컨테이너와 이미지 - Section 2

liljoon·2023년 12월 14일
0

이 글은 Udemy의 "【한글자막】 Docker & Kubernetes : 실전 가이드" 강의의 학습 노트입니다.
https://www.udemy.com/course/docker-kubernetes-2022/

이미지와 컨테이너

컨테이너는 실제로 어플리케이션 실행되는 격리된 하나의 단위다.

이미지는 이 컨테이너가 실행되기 위한 블루 프린트(설계도)이다. 이미지 안에는 실제 소스코드와 필요한 도구를 포함하고 있다. 이미지를 통해 하나 또는 여러 개의 컨테이너를 생성하여 실행한다.


이미지

이미지의 종류는 크게 두가지로 나눌 수 있다.
1. 이미 존재하는 이미지 - docker hub 등을 통한 official image 또는 동료가 구축한 이미지
2. 기존 이미지를 이용해 직접 빌드한 이미지

  • docker hub는 마치 github처럼 공식적으로 올라온 이미지도 있고 개인이 올린 이미지도 존재한다. docker에서 이미지 이름으로 가져올 시 로컬에 해당 이미지가 존재하지 않으면 자동으로 docker hub에서 가져온다.

ex)

docker run node

-> nodejs팀에서 공식적으로 올려 놓은 이미지를 가져와서 실행
하지만 이를 실제로 실행하면 단순히 컨테이너 생성 후 실행하자마자 종료된다.
그 이유는 실행하면 컨테이너와 호스트는 기본적으로 격리된 상태이기 때문에 node shell이 host와 연결되지 못하고 종료된다.

docker -it run node

이렇게 -it 명령어를 붙이면 interactive하게 host와 연결되어 node shell을 작동시킬 수 있다. (대화형 세션 노출)
하지만 도커의 큰 목적은 아니다.


직접 이미지 빌드하는 경우

일반적으로는 공식 베이스 이미지를 통해 그 위에 코드를 추가하여 실행한다.
nodejs를 예시로 하겠다.
nodejs 실행하는 순서는 다음과 같다.

  1. npm install을 통해 package.json의 dependency를 설치
  2. 그 후 node server.js 를 통해 서버 실행

Dockerfile

FROM node

WORKDIR /app

COPY . /app

RUN npm install

EXPOSE 80

CMD [ "node", "server.js" ]
FROM

일반적으로 FROM 명령어를 통해 다른 베이스 이미지를 가져오는 것으로 시작된다. 여기서는 node를 가져오면 자동으로 node:latest(최신버전)으로 설치된다.

WORKDIR

이미지 또한 호스트와 격리된 환경과 코드를 갖고 있다. 해당 환경에서 실행되는 구조이다. 그냥 최상위 폴더에서 해도 상관은 없지만 보통 서브 폴더를 만드는게 권장된다고 한다. 해당 명령어를 통해 /app 폴더에서 밑에 명령어들이 실행된다.

COPY

' . ' 현재 경로에 있는 모든 파일(Dockerfile을 제외됨)을 이미지 환경 /app에 복사한다. 이미 WORKDIR을 해서

COPY . .

로 해도 무관하지만 절대 경로로 작성해주는 것이 가독성에 좋다고 한다.

RUN
npm install

을 실행해주는 명령어이다. package.json을 통해 dependency 설치

EXPOSE

80번 포트를 노출한다는 의미이다. 컨테이너는 내부 네트워크가 존재하고 격리된 상태이기 때문이다.
하지만 해당 명령어는 이미지 빌드 시 사실 아무런 영향이 없다. 실제로 포트를 노출할 때는 추가적인 옵션이 들어가야한다. 하지만 가독성을 위해 마치 주석처럼 작성해주는 것이 좋다.

CMD
node server.js

를 실행한다는 의미이다. 가장 중요한 점은 RUN과의 차이점이다.
RUN은 이미지가 빌드될 때 실행하는 명령어이고
CMD는 이미지가 실제로 컨테이너로 실행될 때 작동한다.
서버 실행은 컨테이너로 실행될 때 필요함으로 CMD를 통해 작성한다.
특이한 점은 배열로 작성해야한다는 점이다.


이미지 빌드

Dockerfile이 있는 경로에서 실행

docker build .

하나씩 실행되며 image id가 보이는 것을 알 수 있다.

docker run c1d8a

실행하여 이미지를 컨테이너로 실행한다. 뒤에 id는 다른 id와 겹치지 않는 선에서 몇개만 작성하면 된다.
하지만 이렇게 실행하면 아까 언급했던 대로 port가 노출되지 않는다.

docker run -p 3000:80 <image id>

이러한 식으로 실행한다. 이렇게 되면 호스트의 3000번 포트에 컨테이너의 80번 포트를 매핑하는 것이다. 호스트에서 3000번으로 접속하면 접속되는 것을 확인할 수 있다.


종료방법

docker ps // 실행 중인 컨테이너 확인

docker stop <container 이름>

추가 내용

도커 이미지는 기본적으로 read-only이다. 코드에 변화가 생겼다면 새로 빌드를 해야한다.

도커 이미지를 빌드할 때 기본적으로 기존과 소스가 같다면 캐싱을 통해 매우 빠르게 빌드한다. (마치 C 프로젝트에서 Makefile과 유사)

도커는 기본적으로 layer기반 아키텍쳐로 여러 이미지가 레이어로 구성된다.
(컨테이너도 이미지 위에 레이어가 쌓인 구조)

하지만 중간에 하나라도 변화가 생기면 그 뒤의 레이어는 전부 새로 다시 빌드된다. 중간의 하나의 명령어와 관계된 코드가 변화하면 그 밑에 명령어도 새로 빌드 된다는 의미.

해당 코드에서 package.json은 변화가 없는데 소스코드만 변했을 경우 npm install을 다시 해야하는 단점이 생긴다.(시간이 오래걸리는 부분)
그래서 미리 package.json만 COPY를 통해 복사 후 npm install하면 소스코드만 변할 때 npm install은 캐싱을 통해 빠르게 된다. 이러한 방식으로 최적화 할 수 있다.

FROM node

WORKDIR /app

COPY ./package.json /app/

RUN npm install

COPY . /app

EXPOSE 80

CMD [ "node", "server.js" ]

0개의 댓글