Docker 이미지 활용하기

DockerBeginner
지금 연습하기

소개

이 실습에서는 컨테이너를 생성하고 실행하는 데 필수적인 기반인 Docker 이미지를 살펴봅니다. Docker Hub 에서 이미지를 가져오고, 다양한 이미지 버전을 사용하여 컨테이너를 실행하며, 이미지 목록 확인 및 삭제, 이미지 레이어의 구조 이해, 이미지 검색, 그리고 기본적인 이미지 태깅 방법을 학습합니다. 이러한 실습 경험은 Docker 이미지를 효율적으로 다루는 데 필요한 핵심 기술을 제공할 것입니다. Docker 가 처음이더라도 걱정하지 마세요. 각 단계를 상세한 설명과 함께 안내해 드립니다.

이 과정은 단계별 지침을 통해 학습과 연습을 돕는 가이드형 실습입니다. 각 단계를 완료하고 실무 경험을 쌓으려면 지침을 주의 깊게 따르십시오. 통계에 따르면 이 실습은 초급 수준으로 90%의 완료율을 보이고 있습니다. 또한 학습자들로부터 99%의 긍정적인 평가를 받았습니다.

Docker Hub 에서 이미지 가져오기

Docker Hub 는 코드의 GitHub 와 유사한 Docker 이미지의 공용 저장소입니다. 이곳에서 많은 인기 소프트웨어 애플리케이션과 운영 체제의 빌드된 이미지를 찾을 수 있습니다. 먼저 공식 Nginx 이미지를 가져오는 (pull) 것부터 시작해 보겠습니다.

시스템에서 터미널을 엽니다. 다음과 같은 프롬프트가 표시될 것입니다.

labex:project/ $

이제 Nginx 이미지를 가져와 보겠습니다. 다음 명령어를 입력하고 Enter 를 누르세요.

docker pull nginx

이 명령어는 Docker 에게 Docker Hub 에서 최신 버전의 Nginx 이미지를 다운로드하도록 지시합니다. 다음과 유사한 출력이 표시됩니다.

Using default tag: latest
latest: Pulling from library/nginx
5040bd298390: Pull complete
d7a91cdb22f0: Pull complete
9cac4850e5df: Pull complete
Digest: sha256:33ff28a2763feccc1e1071a97960b7fef714d6e17e2d0ff573b74825d0049303
Status: Downloaded newer image for nginx:latest

진행 과정을 분석해 보겠습니다.

  1. "Using default tag: latest" - 버전을 지정하지 않으면 Docker 는 사용자가 최신 버전을 원한다고 가정합니다.
  2. 다음 몇 줄은 Docker 가 이미지의 서로 다른 "레이어 (layer)"를 다운로드하는 것을 보여줍니다. 각 레이어는 파일 시스템 변경 사항의 집합을 나타냅니다.
  3. "Digest"는 이 특정 버전의 이미지에 대한 고유 식별자입니다.
  4. 마지막 줄은 이미지가 성공적으로 다운로드되었음을 확인해 줍니다.

이미지를 다운로드했으므로 시스템에 있는지 확인해 보겠습니다. 로컬에 있는 모든 Docker 이미지를 나열하여 확인할 수 있습니다.

docker images

다음과 유사한 출력이 표시됩니다.

REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
nginx         latest    605c77e624dd   2 weeks ago    141MB

출력 항목의 의미는 다음과 같습니다.

  • REPOSITORY: 이미지의 이름 (nginx)
  • TAG: 이미지의 버전 (latest)
  • IMAGE ID: 이 이미지의 고유 식별자
  • CREATED: 이 버전의 이미지가 생성된 시기
  • SIZE: 이미지가 차지하는 디스크 공간

정확한 숫자가 다르더라도 걱정하지 마세요. 중요한 것은 nginx 항목이 표시된다는 점입니다.

시스템에 다른 이미지가 무엇이 있는지 궁금하다면 "jenkins/jenkins"나 "gcr.io/k8s-minikube/kicbase"와 같은 항목이 보일 수도 있습니다. 이것들은 사전 설치된 이미지이며 이번 실습에서는 사용하지 않습니다.

다양한 버전의 이미지 실행하기

Docker 에서는 태그 (tag) 를 사용하여 이미지의 특정 버전을 실행할 수 있습니다. 태그는 이미지의 특정 버전에 대한 별칭과 같습니다. Python 이미지를 통해 이 개념을 살펴보겠습니다.

먼저 최신 Python 이미지를 가져옵니다.

docker pull python

Nginx 이미지를 가져올 때와 유사한 출력이 표시됩니다. 이는 최신 버전의 Python 을 다운로드하는 것입니다.

이제 특정 버전의 Python, 예를 들어 3.7 버전을 가져와 보겠습니다.

docker pull python:3.7

python 뒤에 :3.7을 추가한 것에 주목하세요. 이는 Docker 에게 최신 버전이 아닌 3.7 버전을 명시적으로 가져오도록 지시합니다.

Python 이미지 목록을 확인하여 서로 다른 버전을 확인해 보겠습니다.

docker images python

다음과 유사한 출력이 표시됩니다.

REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
python       3.7       1f1a7b570fbd   2 weeks ago    907MB
python       latest    98ccd1643c71   2 weeks ago    920MB

이제 두 개의 Python 이미지가 있습니다. 하나는 latest 태그 (실습 시점에 따라 Python 3.9 또는 3.10 일 수 있음) 이고, 다른 하나는 3.7 태그입니다.

이 서로 다른 버전들을 사용하여 컨테이너를 실행하고 차이점을 확인해 보겠습니다.

docker run --rm python:latest python --version

이 명령어는 몇 가지 작업을 수행합니다.

  1. docker run: 새 컨테이너를 생성하고 시작합니다.
  2. --rm: 컨테이너가 종료된 후 자동으로 삭제하도록 설정합니다.
  3. python:latest: 사용할 이미지를 지정합니다.
  4. python --version: 컨테이너 내부에서 실행할 명령어입니다.

출력에서 최신 Python 버전을 확인할 수 있습니다.

이제 Python 3.7 로 동일하게 실행해 보겠습니다.

docker run python:3.7 python --version

이번에는 출력에 Python 3.7.x가 표시될 것입니다 (여기서 x는 Python 3.7 의 최신 패치 버전입니다).

이 명령어들은 서로 다른 이미지 태그를 사용하여 동일한 소프트웨어의 다양한 버전을 어떻게 사용할 수 있는지 보여줍니다. 이는 특정 버전의 Python(또는 다른 소프트웨어) 이 필요한 애플리케이션을 실행해야 할 때 매우 유용합니다.

이미지 목록 확인 및 삭제하기

Docker 를 사용하다 보면 시간이 지남에 따라 이미지가 쌓이게 됩니다. 이미지 목록을 확인하고 더 이상 필요하지 않은 이미지를 삭제하는 등 이미지를 관리하는 방법을 아는 것이 중요합니다.

먼저 시스템의 모든 이미지를 나열해 보겠습니다.

docker images

지금까지 가져온 Nginx 와 Python 이미지를 포함한 모든 이미지 목록이 표시됩니다.

이제 공간을 확보하기 위해 Python 3.7 이미지를 삭제하고 싶다고 가정해 보겠습니다. docker rmi 명령어를 사용하여 삭제할 수 있습니다 (rmi 는 "remove image"의 약자입니다).

docker rmi python:3.7

명령어가 성공하면 다음과 같은 출력이 표시됩니다.

Untagged: python:3.7
Untagged: python@sha256:1f93c63...
Deleted: sha256:1f1a7b57...
Deleted: sha256:8c75ecde...
...

하지만 대신 다음과 같은 오류 메시지가 표시될 수도 있습니다.

Error response from daemon: conflict: unable to remove repository reference "python:3.7" (must force) - container <container_id> is using its referenced image <image_id>

이 오류는 해당 이미지로 생성된 컨테이너 (실행 중이거나 정지된 상태) 가 있을 때 발생합니다. Docker 는 시스템 무결성을 유지하기 위해 사용 중인 이미지를 삭제하지 못하도록 방지합니다.

이를 해결하려면 먼저 해당 이미지를 사용하는 모든 컨테이너를 삭제해야 합니다. 정지된 컨테이너를 포함한 모든 컨테이너를 나열해 보겠습니다.

docker ps -a

python:3.7 이미지로 생성된 컨테이너를 찾습니다. 찾았다면 docker rm 명령어를 사용하여 삭제합니다.

docker rm <container_id>

<container_id> 부분을 실제 삭제하려는 컨테이너의 ID 로 바꿉니다.

이제 다시 이미지를 삭제해 보세요.

docker rmi python:3.7

이번에는 성공적으로 삭제될 것입니다.

Python 이미지 목록을 다시 확인하여 이미지가 삭제되었는지 확인합니다.

docker images python

목록에서 Python 3.7 이미지가 더 이상 보이지 않아야 합니다.

이미지 레이어의 이해

Docker 이미지는 레이어드 파일 시스템 (layered filesystem) 을 사용하여 빌드됩니다. 각 레이어는 파일 시스템 변경 사항의 집합을 나타냅니다. 이러한 레이어 방식 덕분에 Docker 는 저장 공간과 네트워크 사용량을 효율적으로 관리할 수 있습니다. 이 개념을 살펴보겠습니다.

먼저 이전에 가져온 Nginx 이미지의 레이어를 검사해 보겠습니다.

docker inspect --format='{{.RootFS.Layers}}' nginx

다음과 유사한 출력이 표시됩니다.

[sha256:2edcec3590a4ec7f40cf0743c15d78fb39d8326bc029073b41ef9727da6c851f sha256:e379e8aedd4d72bb4c529a4ca07a4e4d230b5a1d3f7a61bc80179e8f02421ad8 sha256:b5357ce95c68acd9c9672ec76e3b2a2ff3f8f62a2bcc1866b8811572f4d409af]

이 긴 문자열들 (SHA256 해시라고 함) 각각은 이미지의 레이어를 나타냅니다. 각 레이어는 이미지를 빌드하는 데 사용된 Dockerfile 의 명령어 하나하나에 대응합니다.

레이어를 더 잘 이해하기 위해 간단한 커스텀 이미지를 만들어 보겠습니다. 먼저 현재 디렉토리에 Dockerfile이라는 새 파일을 생성합니다.

nano Dockerfile

파일에 다음 내용을 추가합니다.

FROM nginx
RUN echo "Hello from custom layer" > /usr/share/nginx/html/hello.html

이 Dockerfile 은 두 가지 작업을 수행합니다.

  1. 이전에 가져온 Nginx 이미지에서 시작합니다 (FROM nginx).
  2. 이미지에 새 파일을 추가합니다 (RUN echo...).

파일을 저장하고 종료합니다 (nano 에서는 Ctrl+X 를 누른 다음 Y, Enter 를 누르면 됩니다).

이제 이 이미지를 빌드해 보겠습니다.

docker build -t custom-nginx .

출력 예시:

Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM nginx
 ---> 5ef79149e0ec
Step 2/2 : RUN echo "Hello from custom layer" > /usr/share/nginx/html/hello.html
 ---> Running in 2fa43e649234
Removing intermediate container 2fa43e649234
 ---> 73b62663b5c3
Successfully built 73b62663b5c3
Successfully tagged custom-nginx:latest

이 명령어는 Dockerfile 을 기반으로 새 이미지를 빌드하고 custom-nginx라는 태그를 붙입니다. 끝에 있는 .은 Docker 에게 현재 디렉토리에서 Dockerfile 을 찾으라고 지시하는 것입니다.

이제 커스텀 이미지의 레이어를 검사해 보겠습니다.

docker inspect --format='{{.RootFS.Layers}}' custom-nginx

이 이미지가 원래 Nginx 이미지보다 레이어가 하나 더 많다는 것을 알 수 있습니다. 이 추가된 레이어는 RUN 명령어로 인해 발생한 변경 사항을 나타냅니다.

레이어를 이해하는 것이 중요한 이유는 다음과 같습니다.

  1. 레이어는 캐시되므로 유사한 이미지의 빌드 속도가 빨라집니다.
  2. 레이어는 이미지 간에 공유되므로 디스크 공간이 절약됩니다.
  3. 이미지를 푸시 (push) 하거나 풀 (pull) 할 때 변경된 레이어만 전송하면 됩니다.

Docker Hub 에서 이미지 검색하기

Docker Hub 는 방대한 이미지 컬렉션을 보유하고 있습니다. Docker Hub 웹사이트에서 이미지를 검색할 수도 있지만, Docker 는 터미널에서 직접 이미지를 검색할 수 있는 명령줄 도구도 제공합니다.

먼저 Nginx 이미지를 검색해 보겠습니다.

docker search nginx

Nginx 와 관련된 이미지 목록이 반환됩니다. 출력에는 여러 열이 포함됩니다.

  • NAME: 이미지의 이름
  • DESCRIPTION: 이미지에 대한 간략한 설명
  • STARS: Docker Hub 에서 해당 이미지가 받은 별점 수 (인기도를 나타냄)
  • OFFICIAL: Docker 에서 관리하는 공식 이미지인지 여부
  • AUTOMATED: GitHub 저장소에서 자동으로 빌드되는 이미지인지 여부

예를 들어 다음과 같은 내용을 볼 수 있습니다.

NAME                              DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
nginx                             Official build of Nginx.                        15763     [OK]
jwilder/nginx-proxy               Automated Nginx reverse proxy for docker c...   2088                 [OK]
...

공식 Nginx 이미지는 일반적으로 목록의 맨 위에 있습니다.

이제 특정 버전의 Python 을 검색해 보겠습니다.

docker search python:3.8

이 검색은 예상대로 작동하지 않을 것입니다. docker search는 특정 태그 (예: 3.8) 검색을 지원하지 않습니다. 대신 이름이나 설명에 "python:3.8"이 포함된 이미지를 검색합니다.

이미지의 특정 버전을 찾으려면 다음 방법이 더 좋습니다.

  1. 일반적인 이미지 이름으로 검색합니다 (예: docker search python).
  2. Docker Hub 웹사이트를 방문하여 자세한 정보를 확인합니다.
  3. docker pull로 이미지를 다운로드한 후 로컬에서 검사합니다.

docker search는 이미지를 빠르게 찾는 방법이지만, 더 상세한 정보가 필요할 때는 Docker Hub 웹사이트가 더 유용하다는 점을 기억하세요.

이미지 저장 및 불러오기

Docker 를 사용하면 이미지를 tar 파일로 저장하고 나중에 다시 불러올 수 있습니다. 이는 레지스트리를 사용하지 않고 시스템 간에 이미지를 전송하거나 이미지를 백업할 때 유용합니다.

먼저 Nginx 이미지를 파일로 저장해 보겠습니다.

docker save nginx > nginx.tar

이 명령어는 Nginx 이미지를 현재 디렉토리에 nginx.tar라는 이름의 파일로 저장합니다. > 기호는 docker save 명령어의 출력을 파일로 리다이렉션하는 데 사용됩니다.

현재 디렉토리의 내용을 나열하여 파일이 생성되었는지 확인할 수 있습니다.

ls -lh nginx.tar

nginx.tar 파일과 그 크기 (100MB 이상) 가 표시되어야 합니다.

이제 시스템에서 Nginx 이미지를 삭제하여 이미지가 없는 시스템으로 전송하는 상황을 시뮬레이션해 보겠습니다.

docker rmi nginx

이미지가 삭제되었는지 확인합니다.

docker images nginx

결과가 표시되지 않아야 하며, 이는 시스템에서 Nginx 이미지가 제거되었음을 의미합니다.

이제 tar 파일에서 이미지를 다시 불러와 보겠습니다.

docker load < nginx.tar

< 기호는 nginx.tar 파일의 내용을 docker load 명령어의 입력으로 리다이렉션하는 데 사용됩니다.

불러오기가 완료되면 Nginx 이미지가 다시 생겼는지 확인합니다.

docker images nginx

삭제하기 전과 마찬가지로 목록에 Nginx 이미지가 다시 표시되어야 합니다.

이미지를 저장하고 불러오는 이 프로세스는 다음과 같은 경우에 매우 유용합니다.

  • 인터넷 연결이 없는 시스템으로 이미지 전송
  • 특정 버전의 이미지 백업
  • 레지스트리를 사용하지 않고 커스텀 이미지를 다른 사람과 공유

이미지 태깅 기초

태깅 (Tagging) 은 Docker 이미지에 별칭을 만드는 방법입니다. 주로 버전 관리와 이미지 정리에 사용됩니다. 이미지를 태깅하는 방법을 살펴보겠습니다.

먼저 Nginx 이미지에 새 태그를 만들어 보겠습니다.

docker tag nginx:latest my-nginx:v1

이 명령어는 nginx:latest와 동일한 이미지를 가리키는 my-nginx:v1이라는 새 태그를 생성합니다. 각 부분의 의미는 다음과 같습니다.

  • nginx:latest: 원본 이미지와 태그
  • my-nginx: 새로 만들 이미지 이름
  • v1: 새로 할당할 태그

이제 이미지 목록을 확인하여 새 태그를 확인합니다.

docker images

목록에 nginx:latestmy-nginx:v1이 모두 표시되어야 합니다. 두 이미지의 Image ID 가 동일하다는 점에 주목하세요. 이는 이름만 다를 뿐 실제로는 같은 이미지이기 때문입니다.

이 새 태그를 사용하여 컨테이너를 실행할 수 있습니다.

docker run -d --name my-nginx-container my-nginx:v1

이 명령어는 다음을 수행합니다.

  • -d: 컨테이너를 백그라운드 (데몬 모드) 에서 실행합니다.
  • --name my-nginx-container: 새 컨테이너에 이름을 부여합니다.
  • my-nginx:v1: 컨테이너 생성에 사용할 이미지와 태그입니다.

컨테이너가 실행 중인지 확인합니다.

docker ps

실행 중인 컨테이너 목록에 방금 만든 컨테이너가 표시되어야 합니다.

태깅은 여러 가지 이유로 유용합니다.

  1. 버전 관리: 이미지에 버전 번호 (v1, v2 등) 를 붙일 수 있습니다.
  2. 환경 분리: 개발 (dev), 스테이징 (staging), 운영 (prod) 등 서로 다른 환경에 맞게 태그를 붙일 수 있습니다.
  3. 가독성: 커스텀 태그를 통해 이미지가 어떤 용도인지 더 명확하게 알 수 있습니다.

태그는 단지 별칭일 뿐이라는 점을 기억하세요. 태그를 만든다고 해서 새 이미지가 생성되는 것이 아니라, 기존 이미지를 가리키는 새 이름이 생기는 것뿐입니다.

요약

이 실습에서는 Docker 이미지를 다루는 다양한 측면을 살펴보았습니다. 우리가 학습한 내용은 다음과 같습니다.

  1. Docker Hub 에서 이미지 가져오기
  2. 다양한 이미지 버전을 사용하여 컨테이너 실행하기
  3. 이미지 목록 확인 및 삭제하기
  4. 이미지 레이어의 구조 이해하기
  5. Docker Hub 에서 이미지 검색하기
  6. 이미지 저장 및 불러오기
  7. 기본적인 이미지 태깅 수행하기

이러한 기술은 프로젝트에서 Docker 이미지를 효과적으로 관리하기 위한 토대가 됩니다. Docker 여정을 계속하면서 이러한 작업들이 컨테이너화된 애플리케이션을 빌드하고 배포하는 데 필수적이라는 것을 알게 될 것입니다.

Docker 이미지는 Docker 작동 방식의 핵심입니다. 이미지는 애플리케이션을 패키징하고 배포하는 일관되고 이식 가능하며 효율적인 방법을 제공합니다. 이러한 이미지 조작법을 마스터함으로써 여러분은 Docker 전문가로 나아가는 중요한 발걸음을 내디뎠습니다.

이 명령어들을 계속 연습하고 다양한 이미지를 탐색해 보세요. Docker 를 더 많이 다룰수록 더 편안하고 능숙해질 것입니다. 즐거운 Docker 실습 되세요!