도커(Docker)란 무엇이며, 어떤 상황에서 도커가 왜 필요한지 알아보겠습니다.
Udemy Docker & Kubernetes: 실전 가이드 - 2022년판 강의를 보면서 추가적인 내용과 함께 정리하였습니다 :)
Docker와 Container
🐋도커(Docker)란?
- 도커(Docker)는 리눅스 어플리케이션을 컨테이너로 묶어서 실행할 수 있는 오픈 소스 컨테이너 프로젝트입니다.
- 도커(Docker)를 통해 개발, 테스트 그리고 서비스 환경을 하나로 통합하여 관리할 수 있도록 하는 도구입니다.
- 도커(Docker)를 통해 OS를 공유, 격리화하여 관리할 수 있습니다.
🚢컨테이너란?
- 컨테이너(Container)는 가상화 기술 중 하나로, OS 레벨의 가상화로 프로세스를 격리시켜 동작하는 방식입니다.
이는 기존 OS를 가상화(VM 가상화)시키는 것과 차이점이 존재합니다. - 컨테이너(Container)는 각각 네트워크 설정, 환경 변수등의 시스템 자원을 독립적으로 소유합니다.
- 컨테이너 간 격리
1. 프로세스 : 특정 컨테이너에서 작동하는 프로세스는 다른 컨테이너의 프로세스와 독립적입니다.
2. 네트워크 : 컨테이너 하나에 IP 주소가 하나씩 할당됩니다.
3. 파일 시스템 : 특정 컨테이너에서의 명령이나 파일 등의 엑세스를 제한할 수 있습니다. - 컨테이너 간 공유
1. CPU 성능, 2. 메모리, 3. 리눅스 커널(호스트 OS)
Docker의 필요성
docker의 필요성을 보여주는 사용 사례들은 굉장히 많은데요, 그 중에서 가장 중요하다고 생각하는 사례 몇가지를 소개해보겠습니다.
- 1. Differnt Development & Production Environment - 배포 단계
예를 들어 NodeJs 14.3 버전에서 성공적으로 실행되는 어플리케이션을 다음과 같이 개발했다고 해봅시다.
import express from 'express';
import connectToDatabase from './myApp.mjs';
const app = express();
app.get('/', (req,res) =>{
res.send('<h2>Hello world!</h2>');
});
await connectToDatabase();
app.listen(3000);
해당 어플리케이션을 실행하기 위해서는 NodeJs 14.3 이상의 버전이 필요하죠. 이때 해당 어플리케이션을 호스트되어야 하는 서버의 일부 원격 시스템에 배포할 경우, 해당 원격 시스템에 이전 버전의 NodeJs가 있을 수 있습니다. 그렇다면 우리가 개발했던 환경에서는 성공적으로 실행되던 코드가 갑자기 그곳에서는 더 이상 작동하지 않는 거죠. 그리고 이를 해결하기 위해 문제를 찾는 과정에서 많은 시간이 소요됩니다.
위 예시는 아주 간단하지만, 만약 규모가 크고 복잡한 어플리케이션의 경우 위와 같은 문제는 꽤 심각하게 다가오기 시작합니다. 개발자들은 자신의 개발 환경과 배포 환경에 대한 다양한 설정들을 기록하고 문제가 일어나지 않도록 관리해야 합니다. 이는 상당히 번거로운 작업이기 때문에, 도커와 컨테이너 기술이 사용되기 시작한 것입니다.
예를 들어 특정 노드 버전을 도커 컨테이너에 고정시켜서 코드가 항상 정확한 버전으로 실행될 수 있도록 합니다.
- 2. Differnt Development Environments Within a Team/Company - 개발 단계 with Team/Company
규모가 큰 개발 팀에 속한 개발자가 한동안 프로젝트에서 빠져있어서 이전 버전의 NodeJs를 사용한다고 해봅시다.
이때, 최신 버전에서만 작동하는 코드를 해당 개발자와 공유한다면, 그 개발자 입장에서는 작동하지 않을 겁니다.
물론 이 경우 간단하게 업데이트를 진행하면 해결되지만, 관리하고 설치해야 하는 더 복잡한 종속성이 있는 복잡한 프로젝트에서는 해당 문제는 굉장히 해결하기 어려울 수 있습니다.
결국에는 같은 코드임에도 불구하고, 함께 작업할 수 없다는 것, 항상 같은 환경을 사용한다는 보장과 항상 작동할 것이라는 보장이 없다는 사실이 이러한 문제를 야기하고 있습니다.
즉, 배포에서의 문제(1번)뿐만 아니라 개발 단계에서도 컨테이너에 코드가 필요로 하는 모든 것을 포함하는 환경을 보유하여 고정시키는 것은 상당히 중요하다고 할 수 있겠죠. - 3. Clashing Tools/ Versions Between Differnt Projects
만약 작업 중인 프로젝트가 여러 개인 경우 충돌하는 버전이 존재할 수 있습니다.
프로젝트 A에서는 낮은 버전을, 프로젝트 B에서는 최신 버전의 NodeJs가 반드시 필요하다면, 프로젝트를 전환할 때 마다 잘못된 버전을 제거하고 올바른 버전을 새로 설치해야 하는 번거로움이 생깁니다.
이를 해결하기 위해서 각 버전의 컨테이너를 보유하고 각 프로젝트마다 해당 컨테이너를 보유한다면, 위 문제를 해결할 수 있습니다. 매번 제거하고, 다시 설치할 필요가 없어지는 것이죠! 이제는 프로젝트를 쉽게 전환할 수 있습니다.
VM 가상화 vs 컨테이너 가상화
- Virtual Machine : 호스트 머신(물리적 컴퓨터)위에, OS를 포함한 가상화 소프트웨어를 두는 방식입니다.
예를 들어 윈도우 OS를 사용하는 제 노트북 위에 Linux 기반의 VM을 설치하는 것이죠. 가상으로 존재하지만 다른 머신이기 때문에 제 노트북으로 리눅스를 사용하며 그곳에 원하는 무엇이든 설치할 수 있는 것입니다.
따라서, 프로그램에 필요한 모든 라이브러리, 종속성 및 도구를 설치한 다음, 소스 코드를 올리게 되면 필요한 모든 것을 포함하는 캡슐화된 가상 머신이기 때문에 도커, 컨테이너와 동일한 결과를 얻을 수 있습니다.
단, 여러 가상 머신에서 발생하는 오버헤드때문에 메모리. CPU, 하드 드라이브의 공간을 낭비하게 됩니다.
예를 들어 아래 사진에서 3대의 가상머신이 모두 리눅스를 사용하지만, 각각 설치를 해줘야 되기 때문에 낭비입니다.
이는 곧 성능 저하로 이어지게 됩니다. 해당 방법으로 문제를 해결할 수는 있지만, 완벽한 방법은 아닌 거죠.
- Container : 하나의 머신에 몇 대의 머신을 설치하지 않으며 OS의 내장 컨테이너를 사용합니다!
내장 컨테이너 위에 도커 엔진을 실행하고, 이를 기반으로 여러 분리된 컨테이너를 가동하는 방식입니다.
이를 통해서 가상 머신에 설치하는 것 보다 훨씬 작은 운영 체제의 매우 가벼운 버전만을 설치할 수 있게 된 것입니다.
또한 구성 파일을 통해서 각 컨테이너를 설명할 수 있습니다. 이를 이미지 형태로 만들어서 다른 사람과 공유하여 모든 사람, 즉 모든 환경에서 자신의 시스템에 있는 동일한 컨테이너를 시작할 수 있도록 할 수 있습니다!
- Docker Container의 이점
1. 운영 체제와 시스템에 미치는 영향이 적고, 매우 빠르며 공간을 작게 차지한다.
2. 이미지와 구성 파일을 통해서 공유와 재구축 및 배포가 간편하다.
3. 어플리케이션을 실행하는데 필요한 모든 것을 캡슐화 시킬 수 있다.
결론은 Docker Container가 완벽하게 우리가 원하는 해결 방안인 것입니다. 가상머신은 컴퓨터 전체를 캡술화 하기 때문에 불필요하고 중복된 것들로 인해 낭비가 심한 것이죠. 일종의 거품이 낀 별도의 머신을 굳이 사용할 필요없이 Container 기술로 가볍고 빠르게 사용하는 것이 절대 다수의 상황에서 정답이 되는 것이죠.
Docker 아키텍처
- Client : 도커 Container를 관리하고 실행하기 위해서 Deamon과 상화작용하는 Binary 파일입니다.
- Registory : 도커 Image의 저장소입니다. ex) Docker Hub
- Daemon : Host에 설치되어 도커 Container를 관리하는 프로세스 입니다.
- Image : 도커 Daemon을 통해 Container로 실행하기 위해 필요한 프로그램, 라이브러리, 소스등이 설치된 파일입니다.
- Container : Image를 실행한 상태입니다.
Docker는 클러이언트와 서버 구조로 이루어졌습니다. Docker binary 커맨드가 클라이언트, docker engine이 서버에 해당합니다. 이때, Docker engine에 접근하기 위한 Remote API도 제공됩니다.
Docker Image를 만드는 것은 "build"에 해당하는데, Docker Container에서 실행시키고 싶은 어플리케이션을 docker Image 형태로 빌드해서 실행시키는 것이죠. Docker Container는 빌드한 이미지를 실행시키는 가상화 공간입니다.
이러한 Image를 공유하는 곳이 바로 repository입니다.
Docker Image
다시 정리하자면, Docker Image는 어플리케이션 실행에 필요한 소스 코드, 라이브러리 등의 모든 파일과 설정값을 묶은 형태로, 더 이상의 의존성 파일을 컴파일 하거나 설치할 필요가 없는 상태의 파일을 의미합니다. 그렇기 때문에 용량이 꽤 큰데, 도커의 이미지가 변할 때 마다 새로 다운받기에 부담이 크므로, Layer라는 개념을 도입하였습니다.
즉, 기존 이미지에서 추가적인 파일이 필요하다면, 다시 다운받지 않고 해당 파일을 추가하는 방식을 도입한 것이죠.
위 그림 예시에서, ubuntu의 이미지는 Layer A,B,C로 구성되는데, 여기에 nginx나 web app을 추가함으로써 이미지를 수정할 수 있습니다.
다음으로 - Docker 기본 명령어
이제 Docker가 무엇이고 왜 써야 하는지에 대해서 알아보았으니, 다음에는 어떻게 도커를 설정하고 이미지를 생성하는 지에 대해서 포스팅해보겠습니다!
작성이 완료되면 아래에 링크를 남기도록 하겠습니다.
참고자료
Udemy Docker & Kubernetes: 실전 가이드 - 2022년판 강의
https://velog.io/@whitebear/%EC%84%A4%EB%A7%88-%EB%98%90-%EC%A7%80%EB%82%98%EC%B9%98%EB%8A%94-%EA%B1%B0-%EC%95%84%EB%8B%88%EC%A7%80-%EB%8F%84%EC%BB%A4%EC%9D%B8%EB%8D%B0