Docker를 알아보기 위해서는 컨테이너와 가상화에 대해 먼저 이야기를 해야한다!
컨테이너
그럼 컨테이너란 무엇일까?
소프트웨어와 SW를 실행하기 위해 필요한 모든 구성 파일을 포함한 소프트웨어 패키지라고 생각하면 됨!
컨테이너가 왜 필요할까?
만약 FastAPI 와 Flask를 이용해 각각 서버를 구축하기 위해 로컬에 직접 python 라이브러리들을 설치했다고 생각해보자
프로젝트 간 라이브러리 의존성 충돌 문제, python 버전 충돌 문제 등등 여러 문제들이 발생할 수 있다
=> 이를 위해 프로젝트(서비스)마다 컨테이너를 만들어서 환경을 격리하는게 좋음!
Dockerfile은 만들고자 하는 컨테이너의 세부사항을 적어놓은 파일이고
Requirements.txt는 컨테이너 내부에 설치할 파이썬 라이브러리들을 명시해놓은 파일이다!
컨테이너 기술을 통해 각 서비스마다 사용하는 의존성을 격리하자는게 포인트!
또 하나의 경우로는 Environment Disparity를 생각해볼 수 있다!
(개발 환경이 맞지 않는 상태를 Docker로 해결 할 수 있음!)
같은 업무를 하는 서버가 여러 대 있을 때, 각 서버를 운영하기 위한 OS부터 컴파일러, 설치된 패키지 까지 같은 환경으로 구축하고자한다!
정말 완벽하게 동일함을 보장할 수 있을까?
또한, Windows에서 개발을 완료한 뒤 서버에 업로드했을 때, 서버에서 내 코드가 정상적으로 작동함을 무조건적으로 보장할 수 있을까?
그래서 현재까진 서비스 코드 개발 이후 배포, 운영 단계에서 애를 많이 먹었다
=> 컨테이너 기술을 사용하면 이런 문제 해결을 넘어서 CI/CD, 무중단 배포 등 엄청난 기술들이 가능함
가상화
하드웨어 가상화
사진에서 보이는 하이퍼바이저 가상화가 하드웨어를 가상화하는 것이다!
=> 한 대의 머신에서 다수의 운영체제를 동시에 실행하는 소프트웨어
(Virtual box를 생각하면 됨)
호스트 머신 : 가상화 소프트웨어(하이퍼바이저)를 구동하는 물리 시스템
게스트 머신 : 하이퍼바이저 위에 설치되는 가상 머신(VM)
어플리케이션 가상화
어플리케이션 가상화가 컨테이너라고 생각하면 된다!
컨테이너 기반의 가상화는 어플리케이션 실행환경 자체를 가상화 하는 것임
=> 패키징 + 격리된 실행으로 서버 환경에 영향을 주지 않고 사람의 개입 없이 자동으로 배포 가능!
그럼 다시 한번 컨테이너에 대해 얘기해보자면
1. 격리된 환경과 제한된 리소스로 제어되는 프로세스
2. 운영체제(커널) 위에 독립적으로 가상화된 공간
3. 공유 자원을 프로세스별로 할당치만큼만 사용하도록 제한
4. 의존성 라이브러리, 설정 등 실행에 필요한 모든 것들을 '이미지'로 모아 패키징
패키징과 격리가 목적이라면 VM도 가능한데 왜 컨테이너를 더 자주 이용할까?
가상 머신은 기존 서버에 하이퍼바이저를 설치하고 그 위에 가상 OS를 올려서 패키징한 VM을 만들어서 실행하는 것임!
(하드웨어 레벨의 가상화)
=> 개별 VM은 독립된 OS를 사용하므로 고립성(보안)은 더 좋지만 오버헤드가 크기때문에 무겁고 느림
컨테이너는 운영체제를 제외한 나머지 어플리케이션을 실행할 모든 파일을 패키징
(OS 레벨 가상화)
=> 적은 오버헤드로 더 가벼 프로세스 실행 + 컨테이너 복제가 용이함
컨테이너는 호스트와 커널을 공유하는데 가상화된 공간을 생성하기 위해 리눅스의 여러 기능을 사용한다
=> 프로세스 단위의 격리환경과 리소스 제공
그래서 이유는 결국 성능의 차이...
Docker
일단 Docker를 container라고 하는 표현은 잘못 됨! 도커는 컨테이너 솔루션 중 하나임
(도커 ≠ 컨테이너)
=> 컨테이너를 구축하고 시작하는 데에 필요한 도구를 패키징
정의부터 살펴보면 도커(Docker)는 리눅스의 응용 프로그램들을 프로세스 격리 기술들을 사용해 컨테이너로 실행하고 관리하는 오픈 소스 프로젝트임
Docker의 장점
1. 구성 단순화
=> 도커는 모든 플랫폼에서 실행할 수 있고 Dockerfle에 전체 운영 환경변수를 담아 전달이 가능하다
2. 빠른 배포
=> 컨테이너는 별도의 OS를 부팅하지 않고 어플리케이션을 실행하므로 컨테이너를 빠르게 생성하고 실행할 수 있음
3. 코드 관리
=> Docker는 환경 자체를 배포하기 때문에 개발 및 코딩을 편하게 만들어 줌
4. 개발 생산성 향상
=> 예를들어 CentOS환경의 도커 컨테이너를 실행하는 경우에도 Shared Volume 기능을 통해 Windows 로컬 환경의 데이터를 통해 소스코드를 수정할 수 있으므로 업무 효율이 향상됨
5. 어플리케이션 격리
=> Web Server와 연결된 API 서버들을 격리해야하는 경우들이 있는데 이 때 서로 다른 컨테이너를 통해 API 서버를 실행시킬 수 있음!
Docker 아키텍쳐
Docker Engine은 클라이언트 - 서버 아키텍쳐를 따르는 어플리케이션이다!
구성요소를 살펴보면
1. Server(Docker_Host) + Docker daemon(dockerd)
=> 클라이언트의 명령을 REST API로 받아 Dockered라는 Docker daemon을 통해 컨테이너, 이미지, 네트워크, 볼륨을 관리
2. Docker client
=> Dockerd에 명령을 전달하는 컴포넌트로 docker 명령어를 사용하면 Docker API가 REST API 형식으로 dockerd의 소켓에 전달됨
3. Image
=> 필요한 프로그램과 라이브러리, 소스를 설치한 뒤 만든 하나의 파일로 도커 컨테이너를 만들기 위한 read-only 템플릿임
(상태값을 가지지 않고 변하지 않는 특성이 있음)
4. Container
=> 이미지를 기반으로 독립된 공간에서 실행한 가상환경
컨테이너는 크게 2가지로 나뉨
시스템 컨테이너 : 운영체제 위에 하드웨어 가상화 없이 운영체제를 실행함
=> 다수의 프로세스가 같은 환경을 공유하는 것을 목표로함
어플리케이션 컨테이너 : 하나의 어플리케이션(프로세스)를 실행하는 것을 목표로함
=> 확장이 쉽고 이것의 대표적인 컨테이너 런타임이 Docker임!
Docker의 대표적인 특징
1. 이미지를 이용한 훨씬 더 쉬운 컨테이너 구축 및 보편화
2. 특수한 아키텍처(Layer)를 통한 손쉬운 배포 및 이로 인한 강력한 커뮤니티(Docker Hub) 생성
여기서 말하는 Layer란 무엇일까?
기존 이미지에 추가적인 파일이 필요할 때 다시 다운로드 받지 않고, 해당 파일을 추가하기 위한 개념이다
=> 도커 이미지는 여러 개의 read-only layer로 구성되고, 파일이 추가되면 새로운 layer가 생성된다
(하나의 파일시스템으로서 사용할 수 있게 해줌)
Docker Registry
도커 이미지를 업로드해서 공유하는 저장소를 Docker Registry라고 한다
(위 사진을 참고)
도커의 공식 레지스트리인 Docker Hub를 통해 다른 도커 사용자들의 이미지를 가져올 수 있으며 docker pull, docker run 등의 CLI 명령어를 실행하여 필요한 도커 이미지를 가져올 수 있음!
Docker로 어떻게 컨테이너를 만들까?
Dockerfile : 도커 이미지를 빌드하기 위한 스크립트
=> 컨테이너 내부에 설치할 소프트웨어, 설정값, 실행 명령어들을 명시
# Dockerfile
# Use the official Python image from the Docker Hub
FROM python:3.9-slim
# Set the working directory in the container
WORKDIR /app
# Copy the current directory contents into the container at /app
COPY . /app
# Install FastAPI and Uvicorn
RUN pip install fastapi uvicorn
# Make port 8000 available to the world outside this container
EXPOSE 8000
# Run the FastAPI server
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
FROM : 생성할 이미지의 베이스 이미지 지정
WORKDIR :명령어를 실행할 디렉토리 설정(bash의 cd 명령어와 유사)
COPY : Docker 외부의 파일을 복사하여 내부에 추가
RUN : 이미지 빌드 시점에 실행되는 명령어
EXPOSE :이미지에서 노출할 포트
CMD : 컨테이너 생성 시 실행되는 명령어(Dockerfile에서 한번만 사용 가능)
Docker Image : 컨테이너 실행에 필요한 파일과 설정값들을 포함하고 있는 파일
서비스 운영에 필요한 서버 프로그램, 소스코드/라이브러리, 컴파일된 실행 파일을 묶는 형태이다!
=> 특정 프로세스(컨테이너)를 실행하기 위한 모든 파일과 설정값(환경)을 가짐
Docker Container : 이미지를 실행한 상태
이미지를 실행한 상태로 프로그램의 종속성과 함께 프로그램 자체를 패키징/캡슐화하여 격리된 공간에서 프로세스를 동작시키는 기술이다!
=> 컨테이너는 커널 공간과 호스트 OS 자원(시스템 콜)을 공유함