이미지(Image)와 컨테이너(Container)
포스트
취소

이미지(Image)와 컨테이너(Container)

이미지란(Image)?

도커에서 컨테이너를 구성하기 위한 파일이다.

일반적으로 내 컴퓨터에 자바를 설치한다고 생각해보면
다운로드 페이지에 들어가서 설치 프로그램 다운받고 실행해서 설치하는 등
다양한 과정이 필요하다.

그런데 이미지의 경우에는 그런 과정을 압축한 파일이라고 보면 된다.
이미지에는 특정 프로그램을 실행하기 위해 필요한 설치 과정, 설정, 버전 정보 등
프로그램을 실행하기 위해 필요한 모든 정보가 모두 포함되어 있다.
그래서 특정 프로그램을 사용하고 싶다면 필요한 이미지를 다운 받아서 컨테이너를 생성하기만 된다.

이미지는 닌텐도에서 사용하는 칩같은 역할을 한다.
컴퓨터에서 게임하려고 하면 해당 게임을 설치해야 하지만,
칩을 꽂기만 하면 거기에 미리 설치되어 있는 게임을 바로 실행할 수 있다.

도커 허브

도커 허브는 컨테이너에서 사용할 이미지를 관리하는 이름 그대로 허브(Hub) 역할을 하는 저장소다.
Maven Repository같은 곳이라고 생각하면 된다.

명령문을 통해 이미지를 업로드 및 다운로드할 수 있다.

이미지 다운로드하기

docker pull 이미지명:태그명처럼 사용한다.
태그명 대신에 latest라고 붙이면 가장 최신 버전으로 다운받는다.
태그명을 아예 생략해도 되는데, 생략하면 latest를 붙이는 것과 동일하게 동작한다.

참고로 태그명이라는 것은 일반적인 버전명이랑 같은 뜻이다.

  • 예시
    • docker pull nginx
    • docker pull redis

이미지 종류

이미지는 사실 안을 까보면 순수하게 1개의 이미지로만 구성되어 있지는 않다.
도커는 리눅스 기반 기술인데 리눅스 자체도 다양한 버전이 존재이기 때문에
특정 버전의 리눅스 이미지를 받아서 프로그램을 설치하고 이미지를 빌드한 것이다.
이 때 원본이 되는 이미지를 베이스 이미지라고 부른다.

여러 이미지들의 태그명을 보면 뭔가 공통되는 명칭들이 있다.
이는 베이스 이미지가 되는 OS 버전에 대한 정보를 알려준다.
stretch, slim, alpine, windowsservercore 등 다양한 버전이 있다.

자주 쓰이는 것을 위주로 알아보자.

  • name:version
    • 태그명을 지정하지 않고 이미지를 다운받을 때 쓰는 기본 버전
    • 가장 최근의 안정적인 데비안 운영 체제 릴리스를 기반으로 만들어진다.
    • 예시 : python:3.8.3
  • name:version-slim
    • 실행하기 위한 최소한의 패키지만 설치된 버전
    • 불필요한 패키지가 제거되어 있기 때문에 컨테이너의 시작 속도와 실행 성능이 향상된다.
    • 일반 리눅스 배포판을 기반으로 만들어졌기 때문에 기존 애플리케이션과 호환성이 좋다.
    • 일반 리눅스 배포판을 기반으로 만들어졌기 때문에 alpine 버전보다는 보안 취약점이 더 많을 수도 있다.
    • 예시 : python:3.8.3-slim
  • name:verseion-alpine
    • 컨테이너 내부에서 사용하기 위해 최적화된 알파인 리눅스 OS를 기반으로 만들어진 버전
    • 이미지를 가능한 작게 만들기 위해 사용한다.
    • 알파인 리눅스가 보안 중점으로 개발되었기 때문에 slim 버전보다는 보안 취약점이 적다.
    • 이미지가 매우 가벼워 컨테이너의 시작 속도가 빠르다.
    • 알파인 리눅스는 다른 리눅스가 사용하는 glibc가 아닌 musl libc를 사용하기 떄문에 호환이 안 되는 경우가 있다.
    • 알파인 리눅스는 패키지 관리자를 aptyum이 아닌 apk를 사용하기 때문에 익숙하지 않으면 사용하기 어렵다.
    • 리눅스 CLI를 위한 쉘인 bash가 없다.
    • 예시 : python:3.8.3-alpine

이미지 조회하기

문법

docker image ls를 사용한다.
명령문을 실행하면 각 이미지에 대한 정보를 얻을 수 있다.

출력 정보

  • REPOSITORY
    • 이미지명
  • TAG
    • 이미지 태그명
  • IMAGE ID
    • 이미지 ID
  • CREATED
    • 이미지가 생성된 날짜
    • 이미지를 다운받은 날짜가 아닌 해당 이미지가 최초로 생성된 날짜를 의미한다.
  • SIZE
    • 이미지 크기

이미지 삭제하기

알아야 하는 사항

우선 알아야 하는 것은 이미지는 기본적으로는 어느 컨테이너에서도 사용하지 않는 것만 삭제할 수 있다.
집 지어놨는데 기둥 빼면 무너지니까 못 빼는 거라고 생각하면 된다.
물론 강제로 삭제하는 방법이 있긴 하다.

문법

docker image rm [이미지 ID or 이미지명]을 통해 특정 이미지만 삭제할 수 있다.
기본적으로는 어느 컨테이너에서도 사용 중이지 않은 이미지만 삭제할 수 있다.
그리고 신기한 점은 이미지 ID는 전체를 입력하지는 않아도 실행이 된다.
하지만 일부만 입력하게 된다면 그 일부 입력한 ID에 해당하는 이미지가 단 1개여야 한다.

참고로 띄워쓰기로 구분하면 여러 개의 이미지를 동시에 지울 수 있다.

-f 옵션

물론 컨테이너에서 사용 중인 이미지를 삭제하는 방법도 있다.
docker image rm -f [이미지 ID or 이미지명]를 실행하면 된다.
다만 “중지된 컨테이너”에서만 실행 가능하고, “실행 중인 컨테이너”에서는 불가능하다.

전체 이미지 삭제하기

docker image rm $(docker images -q)를 통해서 전체 이미지를 삭제하는 방법도 있다.
아까 설명했듯이 기본적으로 이미지를 삭제하는 것은 어느 컨테이너에서도 사용하지 않은 이미지만 삭제할 수 있기에,
기본적으로는 전체 삭제할 때도 동일하게 어느 컨테이너에서도 사용하지 않은 이미지만 삭제된다.
하지만 예외는 있듯이 이 때도 -f 옵션을 추가한다면 “중지된 컨테이너”에서 사용 중인 이미지까지는 삭제할 수 있다.

docker images -q

참고로 docker images -q는 시스템에 있는 모든 이미지의 정보를 반환하는 명령문이다.
다만 docker image ls의 차이점은 순수하게 이미지의 ID만 반환한다는 것이다.

컨테이너(Container)란?

이미지를 통해서 구성한 독립적인 컴퓨터 환경을 의미한다.

도커는 하나의 컴퓨터 환경 내에서 여러 개의 컨테이너를 만들 수 있는데
각 컨테이너는 독립적으로 존재한다.
그래서 각 컨테이너는 서로 각자의 저장 공간을 가지고 있으며 다른 컨테이너 내부에 있는 파일에는 접근할 수 없고,
고유한 네트워크를 가지고 있기 때문에 서로 다른 IP 주소를 가지고 있다.

컨테이너는 하나의 컴퓨터 환경 내에서 각자 독립적인 컴퓨터 환경을 갖고 있기 때문에
일종의 미니 컴퓨터라고 볼 수 있다.
그래서 컨테이너와 컨네이터를 포함하고 있는 메인 컴퓨터를 구분하기 위해
메인 컴퓨터를 호스트(host) 컴퓨터라고 부른다.

컨테이너 조회하기

문법

docker ps 명령문을 통해 실행 중인 컨테이너 목록을 확인할 수 있다.
참고로 psprocess status의 약자로 프로세스 상태를 의미한다.

-a 옵션

모든 컨테이너를 조회하고 싶다면 -a 옵션을 추가해서
docker ps -a 명령문을 실행하면 모든 컨테이너 목록을 확인할 수 있다.
이 때 -aaall의 약자다.

출력 정보

  • CONTAINER ID
    • 컨테이너 아이디
  • IMAGE
    • 이미지명
  • CREATED
    • 컨테이너가 생성된 후 경과된 시간
  • STATUS
    • 현재 컨테이너의 상태
    • 현재 컨테이너의 상태로 변경된 후 경과된 시간
  • PORTS
    • 사용 중인 포트 번호
  • NAMES
    • 해당 컨테이너의 별칭
    • 해당 컨테이너 실행 시 --name 옵션을 사용하면 노출된다.

컨테이너 생성하기

문법

docker create [이미지 ID or 이미지명]을 통해 컨테이너를 생성할 수 있다.
우선 로컬 환경에 다운받은 이미지가 있는지 확인해서 있다면 해당 이미지로,
없다면 자동으로 도커 허브에서 다운받아서 컨테이너를 생성한다.

예시

  • docker create nginx
  • docker create redis

컨테이너 실행하기

docker start [컨테이너 ID or 컨테이너명]을 통해 컨테이너를 실행할 수 있다.
정상적으로 실행되었다면 docker ps에서 확인 가능하다.

컨테이너 생성 및 실행하기

명렁어

docker run [컨테이너 ID or 컨테이너명]을 통해 컨테이너를 생성한 후에 바로 실행할 수 있다.
docker create 명령문과 동일하게 로컬 이미지가 있다면 로컬 이미지로,
없다면 도커 허브에서 이미지를 다운로드 받아서 컨테이너를 생성한다.

-d 옵션

-d 옵션을 추가해서 docker run -d [컨테이너 ID or 컨테이너명]처럼 실행하면
도커 컨테이너를 백그라운드에서 실행할 수 있다.

포그라운드와 백그라운드

포그라운드(foreground)는 내가 실행시킨 프로그램의 내용이 화면에서 실행되고 출력되는 상태를 뜻한다.
간단하게 설명하면 뭔가의 프로그램이 동작하고 있는 것을 내가 보고 있는 상황을 의미한다.
다만 해당 프로그램이 계속 실행되는 것을 보고 있어야 하기에 다른 프로그램을 조작할 수는 없다.
서버 컴퓨터에서 터미널 1개만 열어서 로그를 계속 켜두고 있으면 다른 프로그램을 실행하려면
터미널은 1개 더 열던가 아니면 로그를 보는 것을 종료하는 것을 예시로 들 수 있다.

백그라운드(background)는 내가 실행시킨 프로그램이 컴퓨터 내부적으로 실행되는 상태를 뜻한다.
그래서 프로그램이 어떻게 실행되고 있는지를 실시간으로 볼 수는 없다.
대신에 다른 명령문을 추가로 입력할 수도 있고, 새로운 프로그램을 조작할 수도 있다. 백신 프로그램처럼 돌아가는지 눈에 보이지는 않지만 항상 돌아가고 있는 프로그램들을 예시로 들 수 있다.

–name 옵션

--name 옵션을 추가해서 컨테이너에 별칭을 붙일 수 있다.
docker run --name 별칭 이미지명:태그명처럼 실행하면 된다.
도커는 컨테이너를 바로 실행하면 ID만 생기는데 나중에 정지할 때 아이디 찾기 귀찮으니
업무 규칙에 따라서 이름을 만들어 두는 것이 편하다.

호스트 포트와 컨테이너 포트

컨테이너를 실행하면 기본적으로 내부에 설치된 이미지에 따라 접속 가능한 포트가 정해져 있다.
Nginx의 경우에는 80번 포트일거고, MySQL의 경우에는 3306번 포트일 것이다.
하지만 필요에 의해서 접근하는 포트 번호를 바꾸고 싶을 때가 있다.

그럴 때는 docker run -p [호스트 포트]:[컨테이너 포트] 이미지명:태그명을 실행하면
내가 원하는 호스트 포트 번호로 해당 컨테이너에 접근할 수 있게 된다.

예를 들어 Nginx의 경우에는 기본적으로 80번 포트로 접근하게 되어 있다.
그런데 docker run -d -p 4000:80 nginx를 실행하게 된다면
호스트 컴퓨터의 4000번 포트를 통해 컨테이너의 80번 포트로 접근할 수 있다.

컨테이너 포트를 확인하고 싶을 때는 docker ps -a 명령문을 실행하면
해당 컨테이너가 사용 중인 포트를 확인할 수 있다.

포트를 변경하게 되면 docker ps -a 명령문을 실행했을 때 0.0.0.0:4000->80/tcp처럼 변경된 포트 정보를 확인할 수 있다.

-e 옵션

개발을 하다보면 환경변수를 건드릴 일이 있다.
컨테이너를 만들 때도 환경변수를 만들 수 있는데 docker run을 실행할 때 -e 옵션을 주면 된다.

docker run -e [환경변수명=값] 이미지명:태그명처럼 실행하면 된다.
만약에 여러 개의 환경변수를 주입하고 싶다면 -e [환경변수명=값] 부분을 여러 번 사용하면 된다.
쉼표나 앰퍼샌드(&) 연산자는 못 쓴다.
쉼표를 쓰면 쉼표를 포함해서 값으로 전달되고,
앰퍼샌드 연산자는 예약어라서 애초에 그냥 쓰면 잘못된 명령문이라고 경고 메시지를 반환한다.

컨테이너 중지하기

docker stop

docker stop [컨테이너 ID or 컨테이너명]를 통해 컨테이너를 중지할 수 있다.

docker kill

docker kill [컨테이너 ID or 컨테이너명]를 통해서도 컨테이너를 중지시킬 수도 있다.

docker stop과 docker kill의 차이점

docker stop은 컴퓨터를 시스템 종료 버튼을 통해 종료하는 것이고,
docker kill은 컴퓨터를 본체 버튼을 눌러서 강제 종료하는 것이나 다름이 없다.

정상적인 서비스 동작을 위해서는 docker stop을 사용하도록 하자. 참고로 포그라운드(foreground)에서 동작 중이라면 Ctrl + C를 통해서 중지시킬수도 있다.

컨테이너 삭제하기

문법

docker rm [컨테이너 ID]를 통해 컨테이너를 삭제할 수 있다.
컨테이너는 중지된 컨테이너만 삭제할 수 있으며,
실행 중인 컨테이너를 바로 삭제하려고 하면
Error response from daemon: cannot remove container "xxx": container is running: stop the container before removing or force remove라는
메시지가 출력된다.

-f 옵션

만약에 실행 중인 컨테이너를 바로 삭제하고 싶다면 -f 옵션을 추가해서
docker rm -f [컨테이너 ID] 명령문을 실행하면 실행 중인 컨테이너를 바로 삭제할 수 있다.

모든 컨테이너 삭제하기

또한 이미지를 삭제할 때처럼 컨테이너 ID 대신에 $(docker ps -qa)를 추가하면
모든 컨테이너에 대해서 처리할 수 있다.
docker rm $(docker ps -qa)를 실행하면 정지되어 있는 모든 컨테이너를 삭제할 수 있고,
docker rm -f $(docker ps -qa)를 실행하면 실행 중인 모든 컨테이너를 삭제할 수 있다.

컨테이너 로그 조회하기

컨테이너를 생성하고 실행하기만 하는 게 아니라
잘 실행되고 있는지, 에러가 발생한 건 아닌지 로그를 확인할 수 있어야 한다.

문법

docker logs [컨테이너 ID or 컨테이너명]을 통해 로그를 확인할 수 있다.
명령문을 실행한 시점까지 발생한 모든 로그를 조회한다.

–tail 옵션

전체 로그말고 최근 발생한 일부 로그만 확인하고 싶을 수도 있다.
그럴 때는 --tail 옵션울 통해서 지정한 라인 수만큼의 로그만 조회할 수 있다.

예를 들어 docker logs --tail 10 logs_test라는 명령문을 실행해봤다고 가정해보자.
그러면 logs_test라는 컨테이너에 대해서 가장 최근의 로그 중 10줄만 조회한다는 뜻이다.

-f 옵션

docker logs 명령문은 기본적으로 기존에 생성된 로그만 조회할 수 있다.
그런데 -f 옵션을 추가해주면 생성되는 로그를 실시간으로 확인할 수 있다.
docker logs -f logs_test처럼 실행하면 된다.
다만 -f만 추가하면 기존의 모든 로그도 함께 조회된다.

–tail 옵션과 -f 옵션 함께 사용하기

--tail 옵션과 -f 옵션을 함께 사용하면 필요한 라인 수만큼의 로그만 조회하면서,
동시에 실시간 로그를 조회할 수 있다.
docker losg --tail 10 -f logs_test처럼 실행하면 기존 로그 10줄 조회 후 실시간 로그를 조회한다.
라인 수를 0으로 지정할 수도 있는데,
docker losg --tail 0 -f logs_test처럼 실행하면 기존 로그를 조회하지 않고
명령문을 실행한 시점부터의 실시간 로그만 확인할 수 있다.

실행 중인 컨테이너 내부에 접속하기

컨테이너를 실행하고 로그만 보지는 않고,
컨테이너 내부에 접속해서 추가 작업할 일이 있을 것이다.

docker exec -it [컨테이너 ID or 컨테이너명] bash을 실행하면
실행 중인 컨테이너 내부에 접속하면서 동시에 bash에 접근할 수 있다.
참고로 bash 키워드를 붙이지 않으면 컨테이너 내부에 접근할 수 없다.

또한 -it 옵션을 사용해야지 지속적인 작업이 가능하다.
만약 -it 옵션이 없다면 명령문을 1번만 실행시키고 종료되어 버린다.
이 부분이 헷갈릴 수도 있는데 명령문을 1번만 실행시킨다는 것은
bash에 접근해서 명령문을 실행한다는 것이 아니라
정말 docker exec 명령문만 수행한다.
만약에 exec_test라는 컨테이너가 있다고 했을 때
docker exec exec_test bash라고 실행해보면 아무 변화가 없는 것을 알 수 있다.

참고로 bash에서 벗어날 때는 exit 명령문을 입력하면 된다.

bash

유닉스 계열 운영체제에서 제공하는 CLI(Command Line Interface, 명령 줄 인터페이스)를 위한 쉘

테스트 해보기

만약에 Nginx 이미지를 통해 생성된 exec_test라는 컨테이너가 있다고 가정해보자.

  1. dcocker exec -it exec_test bash 명령문을 입력해서 exec_test 컨테이너의 bash에 접근해보자.
  2. ls 명령문을 실행해 컨테이너 내부의 파일 목록을 조회해보자.
  3. cd /etc/nginx 명령문을 실행해 Nginx의 환경설정 폴더로 이동해보자.
  4. cat nginx.conf 명령문을 실행해 Nginx의 환경설정 파일의 내용을 출력해보자.

출처

비전공자도 이해할 수 있는 Docker 입문/실전 [Docker] 도커 이미지와 컨테이너 삭제 방법
Docker | 도커 이미지 종류 도커 Docker Alpine (알파인) 이미지

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.