첫 번째 컨테이너 실행

Beginner

This tutorial is from open-source community. Access the source code

소개

이 랩에서는 첫 번째 Docker 컨테이너를 실행합니다.

컨테이너는 격리된 환경에서 실행되는 프로세스 (또는 프로세스 그룹) 일 뿐입니다. 격리는 리눅스 네임스페이스, 제어 그룹 (cgroups), seccomp 및 SELinux 를 통해 달성됩니다. 리눅스 네임스페이스와 제어 그룹은 리눅스 커널에 내장되어 있다는 점에 유의하십시오! 리눅스 커널 자체 외에는 컨테이너에 특별한 것은 없습니다.

컨테이너를 유용하게 만드는 것은 이를 둘러싼 도구입니다. 이 랩에서는 컨테이너를 사용하여 애플리케이션을 구축하는 데 널리 사용되는 도구인 Docker 를 사용합니다. Docker 는 개발자와 운영자에게 Docker 엔진이 있는 모든 환경에서 컨테이너를 구축, 배포 및 실행할 수 있는 친숙한 인터페이스를 제공합니다. Docker 클라이언트는 Docker 엔진이 필요하므로, Podman을 사용하는 대안이 있습니다. Podman 은 OCI 컨테이너를 개발, 관리 및 실행하기 위한 데몬리스 컨테이너 엔진이며, root 권한 또는 rootless 모드로 컨테이너를 실행할 수 있습니다. 이러한 이유로 Podman 을 권장하지만, 널리 사용되고 있기 때문에 이 랩에서는 여전히 Docker 를 사용합니다.

이 랩의 첫 번째 부분에서는 첫 번째 컨테이너를 실행하고 이를 검사하는 방법을 배웁니다. 리눅스 커널에서 얻는 네임스페이스 격리를 확인할 수 있습니다.

첫 번째 컨테이너를 실행한 후에는 컨테이너의 다른 용도에 대해 자세히 알아보겠습니다. Docker Store 에서 이러한 예제를 많이 찾을 수 있으며, 동일한 호스트에서 여러 유형의 컨테이너를 실행합니다. 이를 통해 격리의 이점을 확인할 수 있습니다. 즉, 충돌 없이 동일한 호스트에서 여러 컨테이너를 실행할 수 있습니다.

이 랩에서는 몇 가지 Docker 명령을 사용합니다. 사용 가능한 명령에 대한 전체 문서는 공식 문서를 참조하십시오.

이것은 가이드 실험입니다. 학습과 실습을 돕기 위한 단계별 지침을 제공합니다.각 단계를 완료하고 실무 경험을 쌓기 위해 지침을 주의 깊게 따르세요. 과거 데이터에 따르면, 이것은 초급 레벨의 실험이며 완료율은 90%입니다.학습자들로부터 92%의 긍정적인 리뷰율을 받았습니다.

시작하기

LabEx VM 에서 터미널을 열고 docker -h를 실행합니다. 그러면 Docker CLI 에 대한 도움말 페이지가 표시됩니다.

$ docker -h
Flag shorthand -h has been deprecated, please use --help

Usage: docker [OPTIONS] COMMAND

A self-sufficient runtime for containers

...

Management Commands:
builder Manage builds
config Manage Docker configs
container Manage containers
engine Manage the docker engine
image Manage images
network Manage networks
node Manage Swarm nodes
plugin Manage plugins
secret Manage Docker secrets
service Manage services
stack Manage Docker stacks
swarm Manage Swarm
system Manage Docker
trust Manage trust on Docker images
volume Manage volumes

Docker 명령줄은 Docker Engine 의 여러 기능을 관리하는 데 사용할 수 있습니다. 이 랩에서는 주로 container 명령에 집중합니다.

LabEx VM 에 podman을 설치합니다.

sudo apt-get update
sudo apt-get install podman -y

podman이 설치된 경우, 비교를 위해 대체 명령을 실행할 수 있습니다.

sudo podman -h

docker version을 사용하여 Docker 설치 버전을 추가로 확인할 수 있습니다.

docker version

Client:
Version: 20.10.21
...

Server:
Engine:
Version: 20.10.21
...

Docker 는 ClientServer: Docker Engine을 모두 설치한다는 점에 유의하십시오. 예를 들어, podman 에 대해 동일한 명령을 실행하면 CLI 버전만 표시됩니다. 이는 podman 이 데몬리스로 실행되며, 실행 중인 컨테이너를 생성하기 위해 OS 와 인터페이스하는 OCI 호환 컨테이너 런타임 (runc, crun, runv 등) 에 의존하기 때문입니다.

sudo podman version --events-backend=none
Version: 3.4.4
API Version: 3.4.4
Go Version: go1.17.3
Built: Thu Jan 1 08:00:00 1970
OS/Arch: linux/amd64

첫 번째 컨테이너 실행

Docker CLI 를 사용하여 첫 번째 컨테이너를 실행합니다.

LabEx VM 에서 터미널을 엽니다.

명령을 실행합니다.

docker container run -t ubuntu top

docker container run 명령을 사용하여 top 명령을 사용하는 ubuntu 이미지로 컨테이너를 실행합니다. -t 플래그는 top이 올바르게 작동하는 데 필요한 가상 TTY 를 할당합니다.

$ docker container run -it ubuntu top
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
aafe6b5e13de: Pull complete
0a2b43a72660: Pull complete
18bdd1e546d2: Pull complete
8198342c3e05: Pull complete
f56970a44fd4: Pull complete
Digest: sha256:f3a61450ae43896c4332bda5e78b453f4a93179045f20c8181043b26b5e79028
Status: Downloaded newer image for ubuntu:latest

docker run 명령은 먼저 docker pull을 실행하여 ubuntu 이미지를 호스트에 다운로드합니다. 다운로드가 완료되면 컨테이너를 시작합니다. 실행 중인 컨테이너의 출력은 다음과 같습니다.

top - 20:32:46 up 3 days, 17:40,  0 users,  load average: 0.00, 0.01, 0.00
Tasks:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.1 sy,  0.0 ni, 99.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  2046768 total,   173308 free,   117248 used,  1756212 buff/cache
KiB Swap:  1048572 total,  1048572 free,        0 used.  1548356 avail Mem

PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
      1 root      20   0   36636   3072   2640 R   0.3  0.2   0:00.04 top

top은 시스템의 프로세스를 출력하고 리소스 소비량별로 정렬하는 리눅스 유틸리티입니다. 이 출력에는 단일 프로세스만 있습니다. 즉, top 프로세스 자체입니다. PID 네임스페이스 격리 때문에 이 목록에서 호스트의 다른 프로세스는 보이지 않습니다.

컨테이너는 리눅스 네임스페이스를 사용하여 다른 컨테이너 또는 호스트로부터 시스템 리소스를 격리합니다. PID 네임스페이스는 프로세스 ID 에 대한 격리를 제공합니다. 컨테이너 내에서 top을 실행하면 컨테이너의 PID 네임스페이스 내의 프로세스가 표시됩니다. 이는 호스트에서 top을 실행할 때 볼 수 있는 것과 매우 다릅니다.

ubuntu 이미지를 사용하고 있지만, 컨테이너 자체에는 자체 커널이 없다는 점에 유의하는 것이 중요합니다. 호스트의 커널을 사용하며, ubuntu 이미지는 ubuntu 시스템에서 사용할 수 있는 파일 시스템과 도구를 제공하는 데만 사용됩니다.

docker container exec로 컨테이너 검사

docker container exec 명령은 새 프로세스로 실행 중인 컨테이너의 네임스페이스에 "진입"하는 방법입니다.

새 터미널을 엽니다. Terminal > New Terminal을 선택합니다.

새 터미널에서 docker container ls 명령을 사용하여 방금 생성한 실행 중인 컨테이너의 ID 를 가져옵니다.

$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b3ad2a23fab3 ubuntu "top" 29 minutes ago Up 29 minutes goofy_nobel

그런 다음 해당 ID 를 사용하여 docker container exec 명령을 사용하여 해당 컨테이너 내에서 bash를 실행합니다. bash 를 사용하고 터미널에서 이 컨테이너와 상호 작용하려는 경우, 대화형 모드를 사용하여 실행하는 동시에 가상 터미널을 할당하기 위해 -it 플래그를 사용합니다.

$ docker container exec -it ID < CONTAINER > bash
root@b3ad2a23fab3:/#

그리고 짜잔! 방금 docker container exec 명령을 사용하여 bash 프로세스로 컨테이너의 네임스페이스에 "진입"했습니다. bash와 함께 docker container exec를 사용하는 것은 Docker 컨테이너를 검사하는 일반적인 패턴입니다.

터미널의 접두사가 변경된 것을 확인하십시오. 예를 들어, root@b3ad2a23fab3:/. 이는 컨테이너 "내부"에서 bash 를 실행하고 있음을 나타냅니다.

참고: 이는 별도의 호스트 또는 VM 에 ssh 로 접속하는 것과 동일하지 않습니다. bash 프로세스와 연결하기 위해 ssh 서버가 필요하지 않습니다. 컨테이너는 커널 수준 기능을 사용하여 격리를 달성하고 컨테이너는 커널 위에서 실행된다는 점을 기억하십시오. 컨테이너는 동일한 호스트에서 격리되어 실행되는 프로세스 그룹일 뿐이며, docker container exec를 사용하여 bash 프로세스로 해당 격리에 진입할 수 있습니다. docker container exec를 실행한 후 격리되어 실행되는 프로세스 그룹 (즉, 컨테이너) 에는 topbash가 포함됩니다.

동일한 터미널에서 ps -ef를 실행하여 실행 중인 프로세스를 검사합니다.

root@b3ad2a23fab3:/## ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 20:34 ? 00:00:00 top
root 17 0 0 21:06 ? 00:00:00 bash
root 27 17 0 21:14 ? 00:00:00 ps -ef

top 프로세스, bash 프로세스 및 ps 프로세스만 표시됩니다.

비교를 위해 컨테이너를 종료하고 호스트에서 ps -ef 또는 top을 실행합니다. 이러한 명령은 리눅스 또는 Mac 에서 작동합니다. Windows 의 경우 tasklist를 사용하여 실행 중인 프로세스를 검사할 수 있습니다.

root@b3ad2a23fab3:/## exit
exit
$ ps -ef
## Lots of processes!

기술 심층 분석 PID 는 컨테이너에 시스템 리소스에 대한 격리를 제공하는 리눅스 네임스페이스 중 하나일 뿐입니다. 다른 리눅스 네임스페이스는 다음과 같습니다.

  • MNT - 다른 네임스페이스에 영향을 주지 않고 디렉토리를 마운트 및 마운트 해제
  • NET - 컨테이너에는 자체 네트워크 스택이 있습니다.
  • IPC - 메시지 큐와 같은 격리된 프로세스 간 통신 메커니즘.
  • User - 시스템의 사용자 격리된 보기
  • UTC - 컨테이너별로 호스트 이름 및 도메인 이름 설정

이러한 네임스페이스는 함께 컨테이너가 동일한 시스템에서 실행되는 다른 컨테이너와 안전하게 충돌 없이 함께 실행될 수 있도록 컨테이너에 대한 격리를 제공합니다. 다음으로, 컨테이너의 다양한 용도를 보여주고 동일한 호스트에서 여러 컨테이너를 실행할 때 격리의 이점을 보여줍니다.

참고: 네임스페이스는 리눅스 커널의 기능입니다. 그러나 Docker 를 사용하면 Windows 및 Mac 에서 컨테이너를 실행할 수 있습니다... 어떻게 작동합니까? 비결은 Docker 제품 또는 Docker 엔진에 내장된 리눅스 서브시스템입니다. Docker 는 이 리눅스 서브시스템을 새로운 프로젝트인 LinuxKit에 오픈 소스로 제공했습니다. 여러 다른 플랫폼에서 컨테이너를 실행할 수 있다는 것은 컨테이너와 함께 Docker 도구를 사용하는 것의 장점 중 하나입니다.

리눅스 서브시스템을 사용하여 Windows 에서 리눅스 컨테이너를 실행하는 것 외에도, Windows OS 에서 컨테이너 기본 요소가 생성되어 네이티브 Windows 컨테이너가 이제 가능합니다. 네이티브 Windows 컨테이너는 Windows 10 또는 Windows Server 2016 이상에서 실행할 수 있습니다.

참고: 컨테이너화된 터미널에서 이 연습을 실행하고 터미널에서 ps -ef 명령을 실행하면 exec 명령을 종료한 후에도 제한된 프로세스 집합이 표시됩니다. 로컬 머신의 터미널에서 ps -ef 명령을 실행하여 모든 프로세스를 볼 수 있습니다.

<ctrl>-c를 입력하여 top 프로세스를 실행하는 컨테이너를 정리하고, 모든 컨테이너를 나열하고 ID 별로 컨테이너를 제거합니다.

docker ps -a

docker rm <CONTAINER ID>

여러 컨테이너 실행

Docker Hub 탐색

Docker Hub는 커뮤니티 및 공식 이미지를 포함하는 Docker 이미지의 공개 중앙 레지스트리입니다.

이미지를 검색할 때 "Docker Certified", "Verified Publisher" 및 "Official Images" 이미지에 대한 필터를 찾을 수 있습니다. "Docker Certified" 필터를 선택하여 엔터프라이즈 준비가 되었으며 Docker Enterprise Edition 제품으로 테스트된 이미지를 찾습니다. 프로덕션 환경에 배포하려는 자체 이미지를 개발할 때는 Docker Store 에서 검증되지 않은 콘텐츠를 사용하지 않는 것이 중요합니다. 이러한 검증되지 않은 이미지는 보안 취약점이나 악성 소프트웨어를 포함할 수 있습니다.

이 랩의 2 단계에서는 Docker Hub 에서 몇 가지 검증된 이미지를 사용하여 nginx 웹 서버와 mongo 데이터베이스의 컨테이너를 몇 개 시작합니다.

Nginx 서버 실행

Docker Hub 에서 공식 Nginx 이미지를 사용하여 컨테이너를 실행해 보겠습니다.

docker container run --detach --publish 8080:80 --name nginx nginx

여기서는 몇 가지 새로운 플래그를 사용하고 있습니다. --detach 플래그는 이 컨테이너를 백그라운드에서 실행합니다. publish 플래그는 컨테이너의 포트 80(nginx 의 기본 포트) 을 호스트의 포트 8080 을 통해 게시합니다. NET 네임스페이스는 컨테이너의 프로세스에 자체 네트워크 스택을 제공한다는 점을 기억하십시오. --publish 플래그는 컨테이너를 통해 네트워킹을 호스트에 노출할 수 있는 기능입니다.

포트 80 이 nginx 의 기본 포트라는 것을 어떻게 알 수 있습니까? Docker Hub 의 설명서에 나열되어 있기 때문입니다. 일반적으로 검증된 이미지에 대한 설명서는 매우 훌륭하며, 해당 이미지를 사용하여 컨테이너를 실행할 때 참조해야 합니다.

또한 컨테이너의 이름을 지정하는 --name 플래그도 지정하고 있습니다. 모든 컨테이너에는 이름이 있으며, 이름을 지정하지 않으면 Docker 가 임의로 이름을 할당합니다. 자체 이름을 지정하면 컨테이너 ID 대신 이름을 참조할 수 있으므로 컨테이너에서 후속 명령을 더 쉽게 실행할 수 있습니다. 예를 들어, docker container inspect nginx 대신 docker container inspect 5e1입니다.

이것이 nginx 컨테이너를 처음 실행하는 것이므로 Docker Store 에서 nginx 이미지를 다운로드합니다. Nginx 이미지에서 생성된 후속 컨테이너는 호스트에 있는 기존 이미지를 사용합니다.

Nginx 는 경량 웹 서버입니다. LabEx VM 의 Web 8080 탭에서 nginx 서버에 액세스할 수 있습니다. 전환하고 페이지를 새로 고쳐 nginx 의 출력을 확인하십시오.

step 2 nginx

mongo DB 서버 실행

이제 mongoDB 서버를 실행합니다. Docker Hub 에서 공식 mongoDB 이미지를 사용합니다. latest 태그 (태그가 지정되지 않은 경우 기본값) 를 사용하는 대신, mongo 이미지의 특정 버전인 4.4 를 사용합니다.

docker container run --detach --publish 8081:27017 --name mongo mongo:4.4

다시 말하지만, 이것이 mongo 컨테이너를 처음 실행하는 것이므로 Docker Store 에서 mongo 이미지를 다운로드합니다. --publish 플래그를 사용하여 호스트에서 27017 mongo 포트를 노출합니다. 호스트 매핑에 대해 8080 이 아닌 다른 포트를 사용해야 합니다. 해당 포트는 이미 호스트에서 노출되어 있기 때문입니다. mongo 이미지를 사용하는 방법에 대한 자세한 내용은 Docker Hub 의 공식 문서를 참조하십시오.

웹 브라우저에서 0.0.0.0:8081을 사용하여 mongoDB 의 출력을 확인하십시오. MongoDB 에서 경고를 반환하는 메시지가 표시됩니다.

MongoDB server output warning

docker container ls로 실행 중인 컨테이너를 확인합니다.

$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d6777df89fea nginx "nginx -g 'daemon ..." Less than a second ago Up 2 seconds 0.0.0.0:8080- nginx > 80/tcp
ead80a0db505 mongo "docker-entrypoint..." 17 seconds ago Up 19 seconds 0.0.0.0:8081- mongo > 27017/tcp
af549dccd5cf ubuntu "top" 5 minutes ago Up 5 minutes priceless_kepler

호스트에서 Nginx 웹 서버 컨테이너와 MongoDB 컨테이너가 실행 중인 것을 볼 수 있습니다. 이러한 컨테이너가 서로 통신하도록 구성하지 않았다는 점에 유의하십시오.

컨테이너에 지정한 "nginx" 및 "mongo" 이름과 ubuntu 컨테이너에 대해 생성된 임의 이름 (제 경우에는 "priceless_kepler") 을 볼 수 있습니다. --publish 플래그로 지정한 포트 매핑도 볼 수 있습니다. 이러한 실행 중인 컨테이너에 대한 자세한 정보는 docker container inspect [container id 명령을 사용할 수 있습니다.

한 가지 눈에 띄는 점은 mongo 컨테이너가 docker-entrypoint 명령을 실행하고 있다는 것입니다. 이것은 컨테이너가 시작될 때 실행되는 실행 파일의 이름입니다. mongo 이미지는 DB 프로세스를 시작하기 전에 몇 가지 사전 구성이 필요합니다. github에서 스크립트가 정확히 무엇을 하는지 확인할 수 있습니다. 일반적으로 Docker Store 웹사이트의 이미지 설명 페이지에서 github 소스에 대한 링크를 찾을 수 있습니다.

컨테이너는 자체 포함 및 격리되어 있으므로 서로 다른 시스템 또는 런타임 종속성이 있는 컨테이너 간의 잠재적인 충돌을 방지할 수 있습니다. 예를 들어, Java 7 을 사용하는 앱과 Java 8 을 사용하는 다른 앱을 동일한 호스트에 배포합니다. 또는 포트 80 을 기본 수신 포트로 사용하는 여러 nginx 컨테이너를 실행합니다 (호스트에서 --publish 플래그를 사용하여 노출하는 경우 호스트에 대해 선택된 포트는 고유해야 합니다). 격리 이점은 Linux 네임스페이스 때문에 가능합니다.

참고: 이러한 프로세스를 실행하기 위해 호스트에 (Docker 외에) 아무것도 설치할 필요가 없었습니다! 각 컨테이너에는 컨테이너 내에 필요한 종속성이 포함되어 있으므로 호스트에 직접 아무것도 설치할 필요가 없습니다.

동일한 호스트에서 여러 컨테이너를 실행하면 단일 호스트에서 사용할 수 있는 리소스 (CPU, 메모리 등) 를 최대한 활용할 수 있습니다. 이는 기업에 막대한 비용 절감 효과를 가져올 수 있습니다.

Docker Hub 에서 직접 이미지를 실행하는 것이 때로는 유용할 수 있지만, 사용자 지정 이미지를 만들고 이러한 이미지의 시작점으로 공식 이미지를 참조하는 것이 더 유용합니다. 랩 2 에서 자체 사용자 지정 이미지를 빌드하는 방법을 자세히 살펴보겠습니다.

정리

이 랩을 완료하면 호스트에서 많은 컨테이너가 실행됩니다. 이를 정리해 보겠습니다.

먼저 docker container ls를 사용하여 실행 중인 컨테이너 목록을 가져옵니다.

$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d6777df89fea nginx "nginx -g 'daemon ..." 3 minutes ago Up 3 minutes 0.0.0.0:8080- nginx > 80/tcp
ead80a0db505 mongo "docker-entrypoint..." 3 minutes ago Up 3 minutes 0.0.0.0:8081- mongo > 27017/tcp
af549dccd5cf ubuntu "top" 8 minutes ago Up 8 minutes priceless_kepler

다음으로, 목록의 각 컨테이너에 대해 docker container stop [container id]를 실행합니다. 이전에 지정한 컨테이너 이름을 사용할 수도 있습니다.

$ docker container stop d67 ead af5
d67
ead
af5

참고: ID 의 고유성을 위해 충분한 자릿수만 참조하면 됩니다. 세 자릿수면 거의 항상 충분합니다.

중지된 컨테이너 제거

docker system prune은 시스템을 정리하는 데 매우 유용한 명령입니다. 중지된 모든 컨테이너, 사용하지 않는 볼륨 및 네트워크, 그리고 댕글링 이미지를 제거합니다.

$ docker system prune
WARNING! This will remove:
- all stopped containers
- all volumes not used by at least one container
- all networks not used by at least one container
- all dangling images
Are you sure you want to continue? [y/N] y
Deleted Containers:
7872fd96ea4695795c41150a06067d605f69702dbcb9ce49492c9029f0e1b44b
60abd5ee65b1e2732ddc02b971a86e22de1c1c446dab165462a08b037ef7835c
31617fdd8e5f584c51ce182757e24a1c9620257027665c20be75aa3ab6591740

Total reclaimed space: 12B

요약

이 랩에서는 첫 번째 Ubuntu, Nginx 및 MongoDB 컨테이너를 생성했습니다.

핵심 내용

  • 컨테이너는 다른 컨테이너 및 호스트로부터 격리를 제공하는 Linux 네임스페이스 (namespace) 와 제어 그룹 (control group) 으로 구성됩니다.
  • 컨테이너의 격리 속성으로 인해, 충돌하는 종속성에 대한 걱정 없이 단일 호스트에서 많은 컨테이너를 예약할 수 있습니다. 이를 통해 단일 호스트에서 여러 컨테이너를 더 쉽게 실행할 수 있습니다. 즉, 해당 호스트에 할당된 리소스를 완전히 활용하고 궁극적으로 서버 비용을 절감할 수 있습니다.
  • 자체 이미지를 개발할 때는 Docker Store 에서 검증되지 않은 콘텐츠를 사용하지 마십시오. 이러한 이미지는 보안 취약점이나 악성 소프트웨어를 포함할 수 있습니다.
  • 컨테이너에는 컨테이너 내에서 프로세스를 실행하는 데 필요한 모든 것이 포함되어 있으므로 호스트에 추가 종속성을 직접 설치할 필요가 없습니다.