본문 바로가기
Docker

[Docker] Docker 이미지 & 컨테이너

by chan10 2023. 1. 24.

이미지 레이어 이해하기

  • Docker는 이미지 빌드 시 Dockerfile의 명령어를 실행 했을 때 결과가 이전과 다른 점이 없으면 캐시를 사용해 빠르게 생성함 (명령어를 수행 했을 때 디렉터리, 코드 등 변경 사항이 없으면 이전과 결과가 같다고 판단하기 때문)
  • Docker는 레이어 기반 아키텍처를 수행하는데 Dockerfile의 하나의 명령어는 하나의 레이어를 나타냄
  • Docker 이미지는 읽기 전용으로 명령이 실행되고 이미지가 빌드되면 이미지가 잠기고, 이미지를 다시 빌드하지 않는 한 그 코드를 변경할 수 없음 (새 이미지를 생성)
  • 특정 레이어가 변경될 때마다 변경된 레이어 이후 모든 레이어는 빌드를 다시 수행 (캐시 사용 X)npm install과 같이 변경 사항이 자주 일어나지 않으나 한번 수행 시 오래 걸리는 작업은 앞쪽에 변경 사항이 자주 있는 코드 같은 경우는 뒤 쪽에 배치하여 효율적인 빌드를 수행하도록 작성
FROM node:12

WORKDIR /app

# package.json만 먼저 복사하여 변경사항 여부 체크
# 이미지 레이어에 의해 변경사항이 있는 경우는 변경 사항이 반영된 레이어 이후는 다시 실행명령어 수행
COPY package.json /app

# package.json에서 변경 사항이 있는 경우 수행 (없는 경우 캐시를 이용, 최적화&속도 향상)
# npm install 시간이 오래 걸리기에 [COPY . /app]을 항상 먼저 수행할 경우 코드 변경 시 마다 npm install 수행하여 속도 저하 요인
RUN npm install

# 모듈에서 변경 사항이 없는 경우 위의 COPY, RUN 명령은 캐시로 적용
# 나머지 코드 복사 수행
COPY . /app

EXPOSE 80

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

 

Attached & Detached 모드 이해하기

  • Attached 모드
    docker run 입력 시 Default 수행 모드
    실행 중인 컨테이너와 연결이 되어있는 모드로 코드 상 콘솔 출력 시 터미널에 출력됨
docker run [ImageName]
docker start -a [ContainerName]
docker attach [ContainerName]

# 컨테이서 생성 및 실행 시 연결(Attached)
docker run 2ddf2ede7d6c

# 컨테이너 실행 시 연결(Attached)
% docker start -a goalsapp

# 실행 중인 컨테이너에 연결(Attached)
% docker attach goalsapp

 

  • Detached 모드
    docker start 입력 시 Default 수행 모드
    컨테이너는 background로 실행하는 모드로 컨테이너 실행 하면서 다른 작업 수행 가능
docker run -d [ImageName]
docker start [ContainerName]

% docker run -p 8000:80 -d 2ddf2ede7d6c
% docker start goalsapp
  • 컨테이너에 출력된 로그 확인
docker logs [ContainerName]

% docker logs goalsapp 
Learn Docker in-depth!!

# -f : 출력 로그 확인 및 수신 대기 (Attached 모드 처럼 동작)
% docker logs -f goalsapp
Learn Docker in-depth!!
Learn Docker in-depth!!@@

 

인터렉티브 모드 들어가기

  • Attached 모드로 컨테이너 연결 시 출력된 결과를 받을 수는 있지만 입력 값을 전달할 수는 없음
  • Java, Python의 input()과 같이 어플리케이션에서 특정 값을 입력 받기 위한 경우가 있을 경우 인터렉티브 모드로 실행하여 입력 값을 컨테이너에 전달 할 수 있음
  • docker run 옵션
    -i : 인터렉티브 모드 수행, 입력 받기 위한 수신 상태를 활성화
    -t : tty(터미널) 생성, 컨테이너에 터미널을 생성
    -it를 결합해서 사용하여 생성한 터미널로 입력을 수신
  • docker start 옵션
    입력 값 전달이 필요해 인터렉티브 모드로 만들어진 컨테이너는 다시 시작 시 인터렉티브 모드로 시작해야 정상적으로 입력값을 전달 할 수 있음
    -a : Attached모드로 컨테이너 시작
    -i : 인터렉티브 모드로 컨테이너 시작
# 코드에 입력 값을 전달해야 하는 코드가 있으나 그냥 컨테이너 생성 시 에러 출력
% docker run 98a2e866e7b3
Please enter the min number: Traceback (most recent call last):
  File "/app/rng.py", line 3, in <module>
    min_number = int(input('Please enter the min number: '))
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
EOFError: EOF when reading a line

# 인터렉티브 모드로 수행 시 입력 값 정상적으로 전달
% docker run -it 98a2e866e7b3
Please enter the min number: 0
Please enter the max number: 10
3

# 컨테이너명 확인
% docker ps -a               
CONTAINER ID   IMAGE                  COMMAND                  CREATED              STATUS                          PORTS                  NAMES
6c87b5481d45   98a2e866e7b3           "python rng.py"          About a minute ago   Exited (0) About a minute ago                          naughty_dewdney

# Attached모드로 수행 시 처음 한번만 입력 후 무반응
% docker start -a naughty_dewdney
Please enter the min number: 10
1
^C

# 기존 컨테이너 중지
% docker stop naughty_dewdney
naughty_dewdney

# Attached + 인터렉티브 모드로 수행 시 정상적으로 입력 값 전달
% docker start -ai naughty_dewdney
Please enter the min number: 2
Please enter the max number: 10
9

 

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

  • docker rm [ContainerName] : 컨테이너 제거
  • docker rmi [ImageID] : 이미지 제거
  • 이미지가 더 이상 컨테이너에 사용되지 않고 중지된 컨테이너에 포함된 경우만 제거할 수 있음
  • 중지된 컨테이너가 있는 경우 해당 컨테이너가 사용 중인 이미지는 제거할 수 없음 (컨테이너 먼저 제거 필요)
docker images - 이미지 목록 출력
docker rm [ContainerName] - 컨테이너 제거
docker rmi [ImageID] - 이미지 제거

# 다수 컨테이너 동시 제거
docker rm quizzical_mendel thirsty_elgamal

# 이미지 제거
docker rmi ac20ab7789a9

# 사용되지 않는 이미지 모두 제거
docker image prune

 

중지된 컨테이너 자동 제거

  • docker run --rm : 중지된 컨테이너를 자동으로 제거, 중지된 컨테이너를 수동으로 정리하지 않아도 됨
  • 코드가 변경된 경우에만 컨테이너를 중지하는 경우가 많음 → 이미지를 다시 빌드 → 기존 컨테이너 중지 및 제거 필요
  • docker run --rm 옵션 사용
    docker run으로 컨테이너 생성 시 --rm 옵션을 넣으면 해당 컨테이너는 종료 시 자동으로 제거 됨
% docker run -p 3000:80 -d --rm 3057672a42f9
6d173c5e96dad52034fe7128477a830701ce29836c09b86e94dcff3d2c9f0a33

% docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                            NAMES
6d173c5e96da   3057672a42f9   "docker-entrypoint.s…"   22 seconds ago   Up 21 seconds   3000/tcp, 0.0.0.0:3000->80/tcp   sweet_dirac

% docker stop sweet_dirac
sweet_dirac

% docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS                        PORTS     NAMES
fbc41cfcec49   98a2e866e7b3   "python rng.py"          21 minutes ago   Exited (0) 20 minutes ago               stupefied_volhard
0d7222657eab   3057672a42f9   "docker-entrypoint.s…"   2 days ago       Exited (137) 18 minutes ago             angry_solomon

 

이미지 검사

  • docker image inspect : 이미지 구성 정보 확인
docker image inspect [Image ID]
docker image inspect 98a2e866e7b3

 

컨테이너에/컨테이너로 부터 파일 복사하기

  • docker cp : 실행 중인 컨테이너로 또는 실행 중인 컨테이너 밖으로 파일 또는 폴더 복사
  • 소스 코드가 변경된 경우 이미지 빌드 대신 변경된 코드를 컨테이너에 넣을 수도 있음
    (오류 가능성으로 인해 잘 사용하지 않는 방법)
% docker cp [local_file_path] [container name]:[container file_path]
% docker cp [container name]:[container file_path] [local_file_path]

# local -> container
% docker cp dummy/. angry_solomon:/test

# container -> local
% docker cp angry_solomon:/test dummy

 

컨테이너, 이미지에 이름 & 태그 지정

  • 컨테이너 이름 지정
    • docker run -- name
docker run -p 3000:80 -d --rm --name [name] [Image ID]
docker run -p 3000:80 -d --rm --name goalsapp 2ddf2ede7d6c

docker start goalsapp
docker stop goalsapp

 

  • 이미지 이름 지정
    • docker build -t : [name : tag] 형식으로 작성하며 name을 통해 여러 개의 특정화된 이미지 그룹을 만듬 name(Repository) - 이미지 그룹명
      tag - 이미지의 버전 정보
docker build -t [name:tag] .
docker build -t goals:latest .

docker run -p 3000:80 -d --rm --name goalsapp goals:latest
docker start goalsapp
docker stop goalsapp

 

이미지 공유하기

  • 이미지 공유 방식
    • Dockerfile 공유 방식 Dockerfile과 App의 소스 코드를 제공하여 자체적으로 이미지를 빌드하고 컨테이너를 실행 이미지에 들어가는 코드 및 폴더 구조 필요
    • 빌드된(완성된) 이미지 공유 방식 (일반적인 방법) 모든 것이 이미지에 포함되어 있기에 이미지 다운로드 시 즉시 컨테이너 실행 가능 또한 코드 및 폴더 구조 필요 하지 않음

 

이미지 Tag명 변경하기

  • docker tag [name:tag] [name:tag]: 이미지 name, tag 변경 기존 변경 후이미지 이름 변경 시 기존
    이미지의 이름을 변경하는 것이 아닌 변경할 이름으로 복제본을 생성

 

DockerHub에 이미지 Push

  • docker push [Repository/ImageName] : 이미지 업로드
    • 이미지를 push하기 위해 이미지 name은 [Repository/ImageName] 형식으로 작성
  • 이미지 push 시 도커는 이미지의 전체 사이즈를 업로드 하는 것이 아님.
  • 베이스 이미지는 Docker Hub에 존재하기에 베이스 이미지에 대한 연결 설정하고 베이스 이미지외에 추가 정보만 push 함으로써 레포지토리 공간 및 대역폭을 절약할 수 있음
% docker images
REPOSITORY             TAG       IMAGE ID       CREATED         SIZE
node-demo              latest    fe7a8d0c5b43   3 minutes ago   869MB
<none>                 <none>    98a2e866e7b3   24 hours ago    881MB
<none>                 <none>    3057672a42f9   3 days ago      866MB

% docker tag node-demo:latest kkchan9210/node-demo

% docker images
REPOSITORY             TAG       IMAGE ID       CREATED         SIZE
kkchan9210/node-demo   latest    fe7a8d0c5b43   3 minutes ago   869MB
node-demo              latest    fe7a8d0c5b43   3 minutes ago   869MB
<none>                 <none>    98a2e866e7b3   24 hours ago    881MB
<none>                 <none>    3057672a42f9   3 days ago      866MB

% docker push kkchan9210/node-demo
Using default tag: latest
The push refers to repository [docker.io/kkchan9210/node-demo]
82c80b0f09c5: Pushed
....
  • docker push 입력 시 deny가 뜨는 경우 DockerHub에 접속하기 위한 로그인 설정이 필요
  • docker login 입력 → Username, Password 입력하여 로그인

 

공유 이미지 가져오기 (Pull)

  • docker pull [Repository/ImageName] : 이미지 다운로드
  • push의 경우 로그인이 필요하지만 pull의 경우 Public Repository이면 로그인 없이 가능
  • docker run [ImageName] 으로 실행 시
    • 로컬 시스템에 찾는 이미지가 없다면 DockerHub에서 자동으로 이미지를 폴링 (tag 정보 미 입력 시 최신 버전 이미지를 가져옴)
    • 로컬 시스템에 찾는 이미지가 있다면 로컬 이미지 사용 (최신 버전 검사 X)
    • 따라서 최신 이미지 버전을 받기 위해 docker pull → docker run을 실행해야 함
docker pull [Repository/ImageName]

docker pull kkchan9210/node-demo

docker run kkchan9210/node-demo