Kuma's Curious Paradise
[이룸] 도커의 작동 방식과 주요 개념들 본문
지난 글 요약
지난 글에서는 가상 머신과 비교하여 컨테이너가 어떤 특징을 갖는지 살펴보았다. 컨테이너란 애플리케이션 실행에 필요한 환경(코드, 의존성, 환경 설정 등)을 패키징하여 담아 전달 및 배포를 쉽게 만든 것으로, 호스트 OS의 커널을 공유하기 때문에 자원 사용이 적고, 가볍기 때문에 전송이 쉽다. 도커는 이런 컨테이너를 생성하고 관리하는 오픈소스 소프트웨어다. 보통 '도커'라고 하면 '도커 엔진'을 뜻한다.
1. 도커의 작동 방식
- 사용자가' Docker Container Run' 같은 명령어를 도커 client(도커 CLI)에 입력하면, CLI는 이 명령을 적절한 REST API 요청 데이터로 변환하여 도커 데몬(dockerd)에 POST 요청을 보낸다.
- 요청을 받은 도커 데몬(dockerd)은 레지스트리에서 해당 이름의 이미지를 찾고, 그 이미지로부터 컨테이너를 빌드하고 실행하는 작업을 수행한다. (실제로는 containerd로 컨테이너 생성 관련 요청이 전달되고 runc가 컨테이너를 생성한 후 사라지며, shim이 해당 컨테이너의 부모가 되지만... 모두 제외하고 단순하게 설명하자면 이렇다.) 도커 CLI와 도커 데몬의 통신은 UNIX socket이 담당한다.
한번 더 정리하면 이렇다.
- 도커 클라이언트 (Docker Client) : 사용자가 도커 데몬과 통신할 수 있게 하는 도구. 명령어를 API 요청으로 변환해 도커 데몬에게 전달.
- 도커 데몬 (Docker Deamon) : 도커 서비스를 전체적으로 관리. 이미지 빌드, 실행, 관리, REST API 처리, 인증 및 보안, 네트워크 설정, 오케스트레이션 등 중요한 일을 모두 담당한다.
다음은 엘라스틱서치를 빌드하며 썼던 명령어가 도커 데몬에게 어떻게 전달되는지를 구성하여 보았다.
Docker Client "docker run --name es01 - -net elastic -p 9200:9200 -it -m 1GB docker.elastic.co/ elasticsearch/elasticsearch:8.13.2" |
적절한 REST API 요청 데이터로 변환 1. POST /containers/create { "Image": "docker.elastic.co/elasticsearch/elasticsearch:8.13.2", "Cmd": ["/bin/bash"], "name": "es01", "HostConfig": { "Memory": 1073741824, "PortBindings": { "9200/tcp": [{ "HostPort": "9200" }] }, "NetworkMode": "elastic" } } 2. POST /containers/(id)/start |
Docker Deamon 1. 컨테이너 생성 요청 : POST /containers/create 2. 컨테이너 시작 요청 : POST /containers/{id}/start |
*** 기본 도커 명령어
- docker build: Dockerfile('이렇게 도커 이미지를 빌드하시오!'라고 설정하여 자동으로 이미지를 생성하게 도와주는 구성 파일)을 기반으로 새로운 이미지를 생성한다.
- docker pull: 원격 레지스트리에서 로컬 시스템으로 이미지를 가져온다.
- docker run: 이미지를 기반으로 새로운 컨테이너를 생성하고 실행한다.
2. 도커의 주요 객체
2-1) 네트워크
네트워크는 도커 컨테이너 간의 통신을 관리하며, 각각의 컨테이너가 독립적으로 또는 함께 작동할 수 있도록 연결한다. 예를 들면, 'bridge' 네트워크는 도커의 디폴트 네트워크로, 같은 브리지 네트워크 안에 있는 컨테이너들이 서로 통신할 수 있게 한다. 나는 Elasticsearch를 도커에 설치하면서, 'elastic'이라는 네트워크를 구성했고, 이 네트워크 안에 kibana를 설치하여 kibana와 ES의 통신이 가능하게끔 구성하였다. 'host' 네트워크는 네트워크 격리 없이 컨테이너와 host가 동일한 IP와 포트를 사용할 수 있다.
2-2) 도커 이미지
도커 이미지는 애플리케이션과 그를 실행하는 데 필요한 모든 의존성, 라이브러리, 필요한 파일들을 포함하는 '불변의 읽기 전용 파일'이다. 이미지는 필요한 모든 것을 가지고 있지만, 자체적으로 '동작'하지는 않는다. 이 이미지를 '실행'시키는 것이 바로 컨테이너.
- Immutable / Read-only : 한번 만들어진 이미지는 변경이 불가능하므로, 변경 사항이 생긴다면 그를 포함한 새로운 이미지를 생성해야 한다. (코드에 변경이 생기면 이미지를 새로 생성해야 한다.)
- 레이어화 구조 : 도커 이미지는 여러 개의 레이어로 구성되어 있다. 겹겹이 쌓인 케이크같은 모양을 상상해도 좋겠다. 각 레이어는 이전 레이어 위에 쌓이게 되고, 이는 이미지를 효율적으로 저장하고 재사용하기 쉽게 한다. 코드 레이어가 맨 위에 있는데, 만약 코드 변경이 생겨서 이미지를 다시 빌드하면, 해당 코드 레이어만 바꾸면 되므로 빌드 시간과 리소스가 크게 줄어든다.
2-3) 도커 컨테이너
컨테이너는 이미지를 기반으로 한 동적이고 일시적인 '실행 환경'이다. 각 컨테이너는 독립된 공간과 파일 시스템을 가지고 운영된다. 컨테이너는 이미지의 읽기 전용 레이어 위에 쓰기 가능 레이어를 추가하여 생성된다. 웹 서버가 클라이언트의 요청을 받아 처리하고, 로그 파일을 기록하는 것이 가능한 건 모두 이 쓰기 가능 레이어 덕분.
필요에 따라 쉽게 생성, 삭제 가능하다는 점이 컨테이너의 특장점. elasticsearch를 도커에 설치했다가 지우는 상황을 가정해 보자. 컴퓨터라는 집에 ES 방이 있었던 셈이고 그 방을 비우면 ES가 지워진다. 만약 컴퓨터 내에 바로 설치했더라면 여기저기 흩어져 있는 ES를 지워야 했을 것이다.
2-4) Docker 레지스트리
도커 레지스트리는 도커 이미지를 저장하는 곳이다. 가장 유명한 공용 레지스트리인 Docker Hub를 포함하여, 개인 레지스트리를 사용할 수도 있다. (위의 명령어에서 드러나기도 하지만, 엘라스틱서치는 'docker.elastic.co'라는 대표 레지스트리를 사용한다.) 레지스트리는 이미지를 버전 관리하고, 다운로드하여 사용할 수 있도록 하며, 사용자들이 이미지를 공유할 수 있는 플랫폼을 제공한다.
3. 도커는 언제 쓰면 좋을까? 도커 사용 시나리오
- 개발자 A가 채팅 앱을 개발했다. 이후 관련된 모든 코드와 데이터베이스 설정을 포함한 도커 이미지를 생성하였다. 이 과정은 Dockerfile을 작성하여 진행되었다. 준비된 Dockerfile을 바탕으로 도커 이미지를 빌드하고, 이를 Docker Hub와 같은 이미지 레지스트리에 업로드하였다. 각 이미지 버전은 '태그'를 사용하여 관리하기로 했다.
- 개발자 B는 이 이미지를 Docker Hub에서 당겨와 로컬에서 채팅 앱을 손쉽게 실행할 수 있었다. B는 채팅 관련 기능을 추가하고 수정된 애플리케이션을 새로운 이미지로 빌드하여 레지스트리에 푸시하였다. 환경 설정이 달라서 애플리케이션이 안 켜지거나 하는 일은 없었다. B는 'latest'라는 태그를 달아 이미지를 빌드하였다.
- 개발이 끝났다! 개발이 완료된 이미지는 실제 운영 환경에 배포되었다. 사용자 또한 도커 레지스트리에서 해당 이미지를 다운받아서 자신의 로컬 환경에서 실행할 수 있다.
- A와 B 개발자는 계속해서 개발을 진행 중이므로, 이미지는 계속 업데이트된다.
다음 글에서는 이룸의 도커파일을 살펴보고, 도커 이미지를 통해 어떻게 버전 관리를 하려고 했는지, CI/CD와 도커는 어떤 관계가 있는지 적어보려 한다!
'이룸 프로젝트' 카테고리의 다른 글
[이룸] Github Actions Workflow 설정 파일 살펴보기 / 버전 관리 (0) | 2024.04.29 |
---|---|
[이룸] 검색 기능 고도화 4 - MySQL FULL-TEXT 성능 테스트 (0) | 2024.04.29 |
[이룸] Redis 영속성 설정 / RDB + AOF (0) | 2024.04.24 |
[이룸] Redis 저장을 위한 직렬화 / 역직렬화 (1) | 2024.04.23 |
[이룸] elasticsearch 관련 트러블슈팅 1 - config에 ssl 관련 설정 삽입 (0) | 2024.04.17 |