관리 메뉴

코딩하는 락커

섹션2. Docker이미지 & 컨테이너: 코어 빌딩 블록 본문

🐳 도커와 쿠버네티스

섹션2. Docker이미지 & 컨테이너: 코어 빌딩 블록

락꿈사 2022. 6. 24. 16:18

이미지 & 컨테이너: 무엇이며, 왜 사용하는가?

 

도커의 2가지 기초 개념

  1. 컨테이너
    • 애플리케이션, 웹사이트, 노드 서버, 애플리케이션을 실행하는 전체 환경 등을 포함하는 작은 패키지
    • 소프트웨어 실행 유닛이 존재하여 그 유닛이 실행됨
    • 이미지의 구체적인 실행 인스턴스, 즉 실행 애플리케이션이 됨
  2. 이미지
    • 템플릿, 컨테이너의 청사진
    • 모든 설정 명령과 모든 코드가 포함된 공유 가능한 패키지 
    • 이미지를 사용하여 이를 기반으로 한 여러 컨테이너를 만들 수 있음 

 

 

 이미지와 컨테이너의 관계

  • 컨테이너에 설치된 이미지는 컴퓨터에서 실행되는 것이 아니라 컨테이너 내부에 설치되고 실행됨 
  • 이미지는 run 명령어를 사용하여 이미지의 인스턴스를 만들고, 이 이미지를 기반으로 하는 구체적인 컨테이너를 생성함
  • 즉 컨테이너는 이미지의 인스턴스가 됨
  • 두개의 컨테이너가 동시에 실행될 수 있음 

 

 

이미지를 사용하는 2가지 방법

  1.  이미 존재하는 이미지를 가져오는 방법
    • 이미 개발된 이미지
    • 미리 구축된 공식 이미지
  2. 커스텀 이미지를 만드는 방법
    • 공식 이미지 베이스를 가져온 다음 그 위에 코드를 추가하여 그 이미지로 개발한 코드를 실행
    • 개발한 코드는 도커 허브에 공유해야함

 

커스텀 이미지로 nodeJS 앱 만들기 실습

  • Dockerfile 생성
DockerFile 생성
  • DockerFile 작성
# FROM: 다른 베이스 이미지에 커스텀 된 이미지를 구축할 수 있음
# node: 현재 시스템에 존재하거나 도커 허브 사에 존재하는 이미지 이름  
# (위에서 node 도커 허브 이미지를 실행했을 때 node 이미지가 로컬로 다운로드 및 캐시 되었으므로)
# (이 이미지를 기반으로 컨테이너를 실행한 순간 로컬 컴퓨터에도 존재함)
# node라는 이름의 이미지가 존재하며, 도커가 이를 찾을 수 있다는 것을 의미함  
FROM node

# WORKDIR: 도커 컨테이너의 작업 디렉토리 설정 
# 이곳에 /app을 넣게 되면 이후로부터 도커에게 내리는 모든 후속 명령이 /app 폴더에서 실행될 것을 알림  
WORKDIR /app

# 도커에게 로컬 컴퓨터에 있는 파일이 이미지에 들어가야 한다고 알려줌
# 첫번째 .: 이미지로 복사되어야 할 파일들이 있는 곳의 경로를 작성하는 곳
# 이곳에 .을 넣으면 도커에게 기본적으로 Dockerfile이 포함된 동일한 폴더임을 알림 (DockerFile은 제외)
# 이 프로젝트의 모든 폴더, 하위 폴더 및 파일을 복사해야 한다는 것을 의미함

# 두번째 .: 그 파일을 저장해야 하는 이미지 내부의 경로를 작성하는 곳  
# 모든 이미지와 이미지를 기반으로 하는 컨테이너에는 로컬 컴퓨터와 분리된 자체 내부 파일 시스템이 존재
# /app: 도커 컨테이너의 루트 엔트리를 사용하는 것이 아니라 서브 폴더 /app을 만들어서 사용하겠다는 것을 알림
# 이렇게 되면 DockerFile과 동일한 폴더에 있는 모든 파일 및 하위 폴더가 컨테이너 내부의 app 폴더에 복사됨
# .: 현재는 위에서 작업 디렉토리를 설정했으므로 현재 도커 작업 디렉토리를 의미하는 ./으로 작성가능
# /app: 이런식으로 명시적으로 절대 경로를 작성할 수도 있음 
COPY . /app

# RUN: 도커 컨터이너에 필요한 종속성을 설치하는 등의 명령어 수행가능
# node에 필요한 nmp 설치하라는 것을 의미함
RUN npm install

# EXPOSE: 로컬 컴퓨터에 도커 컨테이너의 특정 포트를 노출하는 명령어
# 도커 컨테이너는 로컬 컴퓨터와 분리되어 있고 자체 내부 네트워크도 분리되어 있음
# 컨테이너 내부의 노드 애플리케이션에서 포트 80을 수신할 때 로컬로 노출해 달라는 의미
EXPOSE 80

# CMD: 이미지가 생성될 때 실행되는 것이 아니라 이미지를 기반으로 컨테이너가 시작될 때 실행하라는 명령어 
# 이미지를 기반으로 한 컨테이너가 생성될 때마다 컨테이너 내부에 있는 node 명령어를 사용하여 server.js 파일을 실행하라는 의미
# 만약 cmd로 특정하지 않으면 베이스 이미지가 실행되며, 없는 경우 에러가 발생함
CMD ["node", "server.js"]
  • 도커 이미지 빌드

// docker build: 도커 이미지를 빌드하는 명령어
// build 뒤에 .을 입력하여 도커에게 이 명령을 실행하는 곳과 동일한 폴더에 dockerfile이 있음을 알림
// (--platform arm64: ARM64 Mac을 사용하여 해당 플랫폼에 맞게 빌드)
$ docker build --platform amd64 .

  • 도커 컨테이너 실행

$ docker run {이미지_id}
  • 그러나 localhost에서 웹 사이트가 표시되지 않는 것을 확인

  • 현재 실행중인 프로세스 보기
// -a 옵션 없이 ps만 붙이면 현재 실행중인 프로세스만 표시됨
$ docker ps

  • 컨테이너 이름으로 도커 컨테이너 종료
$ docker stop {컨테이너_이름}

  • 도커 포트 80에 엑세스 할 수 있는 로컬 컴퓨터 포트를 추가하여 도커 실행
$ docker run -p {로컬 컴퓨터 포트}:{도커 컨테이너 노출 포트} {이미지_id}

정상적으로 이미지가 빌드되어 3000번 포트로 접속하여 서버가 정상 실행된 것 확인 가능

 

 

이미지는 읽기 전용

  • 이미지는 읽기 전용이므로 소스 파일이 변경되면 도커 이미지를 새롭게 빌드해야 함

소스 파일이 변경된 것 확인

 

이미지 레이어 이해하기

  • 이미지는 레이어 기반 아키텍처로 이루어져 있음
    • 즉, 이미지를 빌드하거나 이미지를 다시 빌드할 때 변경된 부분의 명령과 그 이후의 모든 명령이 재평가 됨
    • 프로젝트 변경 없이 이미지를 빌드 시 매우 빠르게 완료 되는데, 그 이유는 캐쉬를 사용했기 때문임
      • 도커는 도커 파일을 사용하여 이미지를 빌드 했을 때 결과가 이전과 동일하다는 것을 인식하고, 이를 빌드 하는 것이 아니라 캐쉬 함
  • 이미지 레이어는 Dockerfile의 명령어를 기반으로 하여 생성됨
    • FROM, WORKDIR, COPY, RUN 등 CMD 명령어 이전의 명령어는 별도의 레이어가 됨
  • 그리고 이미지를 기반으로 컨테이너를 실행하면, Dockerfile 명령어를 기반으로 한 이미지 레이어 위에 새로운 레이어를 추가함
  • 이렇게 되면 이미지를 레이어로 실행할 때만 활성화 되는 최종 레이어가 추가됨
  • 한 레이어가 변경된다면 후속 레이어도 다시 실행됨
    • 코드 파일이 변경되어 COPY 레이어가 변경되면, 그 이후의 RUN 레이어도 다시 실행됨
    • 그러나 이것은 node를 재설치 하는 것은 불필요한 작업임
    • 따라서 아래 코드와 같이 Dockerfile을 최적화 할 수 있음
FROM node

WORKDIR /app

# package.json 파일을 app 폴더에 복사하고
COPY package.json /app

# 그 후에 RUN npm install을 실행하는 것
# 따라서 소스 코드가 변경되어도 npm install은 캐시된 결과를 사용함
# 따라서 재빌드 할 때도 속도가 빠름
RUN npm install

COPY . /app

EXPOSE 80

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

 

 

이미지 & 컨테이너 관리

  • 모든 도커 명령어에 --help를 추가하여 사용 가능한 모든 옵션을 볼 수 있음

 

컨테이너 중지 & 재시작

  • 실행중인 컨테이너 리스트 보기 
$ docker ps
  • 모든 컨테이너 리스트 보기 
$ docker ps -a
  • 중지된 컨테이너 시작하기
    • 그러나 즉시 종료 됨
# 컨테이너 리스트 검색 명렁어로 중지된 컨테이너를 검색하고
$ docker ps -a 

# 찾은 컨테이너의 이름으로 컨테이너 시작
$ docker start {컨테이너_이름/컨테이너_ID}

 

 

Attached & Detached 컨테이너 이해하기

  • $ docker start 로 실행시 실행이 되나 즉시 종료됨

  • 하지만 여전히 실행 중임

  • $ docker run 명령어로 실행할 경우 (다른 포트를 사용하여 동일한 이미지를 기반으로 새로운 추가 컨테이너 실행) 이 프로세스에서 막혀서 더 이상의 명령어를 입력할 수 없음)

  • $ docker start 는 background에서 실행되고, $ docker run은 foreground에서 실행되는 것
    • $ docker start 는 dettached 모드가 default
    • $ docker run 은 attached 모드가 default
      • attached 모드: 컨테이너의 출력 결과를 수신
  • $ docker run을 dettached 모드로 실행하는 방법
$ docker run -p {로컬 컴퓨터 포트}:{도커 컨테이너 노출 포트} -d {이미지_id}

  • $ docker start을 attached 모드로 실행하는 방법
$ docker start -a {컨테이너_이름/컨테이너_id}

  • dettached 모드로 실행중인 컨테이너를 보는 방법
$ docker attached {컨테이너_이름/컨테이너_id}

  • 컨테이너의 로그를 보는 방법
$ docker logs {컨테이너_이름/컨테이너_id}

# 컨테이너 로그를 Follow 모드로 실행하여 계속 수신 대기
$ docker logs -f {컨테이너_이름/컨테이너_id}

 

 

인터렉티브 모드로 들어가기

  • 컨테이너의 표준 입력을 열린 상태로 실행
# -i: 컨테이너를 인터렉티브 모드로 시작하여 표준 입력을 열린 상태로 유지하는 옵션
# -t: 컨테이너의 터미널을 생성하여 노출하는 옵션 
$ docker run -i -t {컨테이너_이름/컨테이너_id}

  • 컨테이너를 dettached 모드에서 표준 입력을 열린 상태로 실행
# -i: 컨테이너를 인터렉티브 모드로 시작하여 표준 입력을 열린 상태로 유지하는 옵션
# -a: 출력 결과를 계속 수신하게 하는 옵션
$ docker start -a -i {컨테이너_이름/컨테이너_id}

 

 

이미지 & 컨테이너 삭제하기

  • 컨테이너 삭제하기
$ docker rm {컨테이너_이름/컨테이너_id}

  • 이미지 삭제하기

 

 

 

도커 명령어

// Docker hub에서 찾은 공식 노드 이미지를 사용하여 이 이미지를 기반으로 하는 컨테이너를 생성하는 명령어
$ docker run node
// ps: 프로세스
// -a: 도커가 생성한 모든 컨테이너, 모든 프로세스가 표시됨
$ docker ps -a
// -it: 도커에게 컨테이너 내부에서 호스팅 머신으로 대화형 세션을 노출하고 싶다고 알리는 것
// 실제로 기본 노드 명령을 실행할 수 있는 언터렉티브 노드 터미널로 들어가 실행중인 노드와 상호작용 가능
$ docker run -it node
Comments