Home > Infrastructure > Docker > 도커(Docker)Dive - 기본 개념

도커(Docker)Dive - 기본 개념
Docker

서버 운영

  • 서버
    • 하드웨어에서 실행 중인 소프트웨어 (문맥에 따라 하드웨어 지칭할 수도 있음)
    • 어떤 소프트웨어가 실행 중인지에 따라 다양한 서버로 분류
      • e.g. 파일 서버 (파일 업로드/다운로드), DB 서버, 웹서버, 웹애플리케이션서버
    • 엔터프라이즈 환경에서는 아주 많은 양의 서버를 운영해야 함
    • 서버 운영 방법
      • 베어메탈(Baremetal)- 비효율적
        • 서버를 하나 구입하고 OS 설치 후 여러 개의 소프트웨어 실행
        • 단점
          • 하나의 소프트웨어에 문제가 생기면 다른 소프트웨어에게 영향을 미침 (에러, 사용량 급증)
      • 하이퍼바이저(Hypervisor) - 전통적 가상화 기술
      • 컨테이너(Container) - 최신 가상화 기술
  • 큰 서버효율적으로 나눠서 사용하기 위해 가상화 기술이 필요

가상화 기술

virtualization

  • 물리적 컴퓨팅 환경 내부에서 논리적 컴퓨팅 환경을 만들 수 있는 기술
  • 실제로 존재하는 컴퓨터가 아니지만, 마치 존재하는 것처럼 만듦
    • e.g. 하나의 OS안에서 4개의 추가 OS 만듦
      • 8 Core/64 GB RAM -> OS(1 Core/8GB RAM) + 프로그램(1 Core/8GB RAM) X 4
  • 장점
    • 마치 여러 대의 컴퓨터를 사용하는 것처럼, 안전하게 소프트웨어 운영 가능
      • 가상 컴퓨터에는 사용자가 직접 리소스를 분배할 수 있음 (리소스 최대값 지정)
      • OS가 많아져 총 리소스 사용량은 증가하겠지만, 논리적으로 격리되어 한 프로그램의 문제가 다른 프로그램에 영향을 미치지 않음
    • 물리적 컴퓨터 한 대만 사용할 수 있어 경제적
      • 기업 입장에서는 낮은 사양 컴퓨터 여러대보다 높은 사양의 컴퓨터 한 대가 효율적

하이퍼바이저 가상화 (전통적 가상화 기술)

  • 가상 환경 운영 프로그램설치해 관리하는 방식
    • e.g. VMWare, VirtualBox, Red Hat의 하이퍼바이저 제품
  • 과정
    • 호스트 OS(물리, 기본 OS)에 하이퍼바이저를 설치
    • 격리된 환경으로 게스트 OS(논리, 가상머신) 실행하고 프로세스 운영
  • 게스트 OS 커널의 시스템 콜을 호스트 OS 커널에게 전달할 때 중간에서 번역
    • 시스템 콜: 커널에 하드웨어 자원을 요청하기 위한 표준
    • 서버가 한 대라서 게스트 OS가 물리적 자원을 쓰려면 호스트 OS를 거쳐야만 함
    • 각 OS 커널의 언어가 다르므로 번역 필요
  • 핵심 특징
    • 각각의 게스트 OS독립적인 커널을 가질 수 있음
  • 장점
    • 커널을 독립적으로 가지고 있어 보안면에서는 더 나을 수도 있음
  • 단점: 무겁고 느림
    • 하나의 게스트 OS가 차지하는 오버헤드가 큼
    • 독립적인 커널로 인해 부팅 시간이 매우 느림

컨테이너 가상화

hypervisor_vs_container

  • 커널의 자체 기능(LXC)을 활용한 가상화 방식
    • e.g. Docker
  • LXC(Linux Containers)
    • 리눅스 커널이 제공하는 자체 격리 기술
    • 커널 자체 기능만 사용해 격리된 공간(컨테이너) 생성 가능
      • 네임스페이스: 리소스를 나누는 기준 역할
        • e.g. 프로세스, HDD, Network, 사용자, 호스트네임…
      • Cgroups: 리소스의 사용량을 배분하는 기술
        • e.g. 프로세스가 사용하는 메모리, CPU, HDD, Network, BandWidth
  • 컨테이너
    • LXC 기술을 사용해 만들어진 격리된 공간
    • 컨테이너를 생성하면 완전히 격리된 CPU, Disk, Network, Memory 공간을 차지
      • 내부에서 프로세스를 띄우면 완전히 격리된 공간에서 띄우는 것
    • 여러 개의 컨테이너를 실행시키면 각각의 컨테이너는 격리된 공간에서 안전하게 운영
  • 핵심 특징
    • 모든 컨테이너는 HostOS의 커널을 공유해 사용
  • 장점: 가볍고 빠르다!!!
    • 오버헤드가 적어 빠름
      • 하이퍼바이저와 달리 번역을 거치는 중간 단계가 없어 빠름
    • 부팅이 매우 빠름
      • 자체적인 커널 없이 호스트 OS의 커널을 공유하므로 커널 실행 시간 자체가 없음
    • -> 모던 애플리케이션 요구사항에 적합
      • 빠르게 변화하는 사용자 니즈에 맞춰 변경 사항을 빠르게 적용 가능
      • e.g. 가벼운 웹서버 올리기
        • 하이퍼바이저: 60초
        • 컨테이너: 3초
  • 단점: 호스트 OS의 커널을 공유하므로, 호스트 OS와 다른 종류의 OS는 실행할 수 없음
  • 유의: 어떤 컨테이너 플랫폼 사용할지 어떤 컨테이너 런타임을 사용할지 선택 가능

도커 (오픈소스, 2013~)

  • 커널의 컨테이너 가상화 기술을 쉽게 사용하기 위한 소프트웨어 (컨테이너 플랫폼)
    • 하이퍼바이저와 달리 실제 격리 수행 주체커널 자체
  • 목적: 컨테이너 내에서 소프트웨어(서버)를 빠르고 가볍게 운영하기 위해 사용
  • 가장 점유율이 높은 컨테이너 플랫폼
    • 컨테이너 플랫폼 예시 - Docker, Podman, Containerd…
  • 컨테이너 플랫폼 구조
    structure_of_container_platform
    • 컨테이너 엔진
      • 사용자의 요청을 받아 컨테이너를 관리해주는 역할
      • 도커 아키텍처 (클라이언트-서버 모델)
        docker_architecture
        • Docker CLI - 클라이언트
          • 사용자가 입력한 명령어를 서버 API 양식에 맞게 변환해 대신 전달
          • 덕분에 사용자는 도커 데몬의 API와 쉽게 통신 가능
        • Docker Daemon (=dockerd) - 서버
          • 호스트 OS에서 지속적으로 실행되면서 클라이언트 요청에 따라 컨테이너 관리
          • 클라이언트를 위한 API 제공
          • 컨테이너 런타임을 통해서 컨테이너를 조작하고 결과를 CLI에게 전달
    • 컨테이너 런타임
      • 직접 커널과 통신하면서 실제로 격리된 공간을 만드는 역할
      • 인터페이스: CRI(Container Runtime Interface) - OCI가 규정한 표준
      • 구현: RUNC (도커 지원 기본 컨테이너 런타임)

이미지와 컨테이너

  • 서버에서 소프트웨어 실행을위해 필요한 것들
    • 하드웨어
    • OS
    • 프로그램 실행 위한 구성 요소 (패키지, 라이브러리, 런타임 언어)
    • 소프트웨어 (실행 시킬 프로그램)
  • 이미지 = 실제 압축 파일 + 메타 데이터
    • 컨테이너 실행 시 실제 압축 파일과 메타 데이터가 격리된 공간에 복사되어 프로세스로 실행
  • 이미지 (Image)
    • 특정 시점의 파일시스템(디렉터리)을 저장한 압축 파일
    • 이미지 = OS + 구성 요소 + 소프트웨어 => 실행 준비가 완료된 상태 자체를 압축해 공유
      • Windows 백업 기능, 가상 머신의 스냅샷과 비슷
    • 백업이나 스냅샷보다 압축 사이즈가 매우 작아 인터넷을 통한 저장과 공유가 수월함
      • 이미지는 다른 사람이 만든 것을 사용하거나 직접 만들 수 있음
    • 이미지 : 컨테이너 = 프로그램 : 프로세스 (1개의 이미지로 여러 컨테이너 실행 가능)
      • 이미지는 파일 시스템 (압축 파일 형태로 호스트 머신 특정 경로에 위치)
      • 컨테이너는 실행 상태의 이미지
  • 이미지 메타데이터 (Metadata)
    • 이미지에 대한 정보를 기술하는 데이터
      • 이미지 이름, 사이즈
      • Env: 소프트웨어실행 시 참조할 환경설정 정보 (키-값 쌍)
        • 소프트웨어 버전, 실행을 위해 필요한 파일 경로 등이 있음 (바뀌면 동작도 달라짐)
          • e.g. VERSION=1.23.2,PATH=/usr/..
      • Cmd: 컨테이너 실행 시 프로세스 실행 명령어 지정 (리눅스 명령어)
        • e.g. nginx -g daemon off;
    • 컨테이너 실행 시 다른 값으로 덮어쓰기도 가능 (e.g. CMD 명령어 변경 등)
      • 같은 이미지도 전혀 다른 역할을 수행하는 컨테이너로 만들 수 있음
      • 보통 이미지디버깅할 때 주로 사용
  • 컨테이너 라이프사이클
    container_lifecycle
    • 생성 단계 (Created) - docker create
      • 컨테이너를 실행하기 위한 격리된 공간이 만들어지는 상태
      • 네트워크, 스토리지, 환경 변수 등 모든 리소스를 격리
    • 실행 단계 (Running) - docker start
      • 컨테이너의 메타 데이터 CMD 값을 사용해 컨테이너를 실행
      • 실제 프로세스가 실행되어 CPU메모리 사용
    • 일시정지 단계 (Paused) - docker pause, docker unpause
      • 컨테이너에서 실행 중인 모든 프로세스일시 중지된 상태
      • 현재 상태를 모두 메모리에 저장 (CPU X, 메모리 O)
        • 저장된 상태에서부터 재시작
    • 정지 단계 (Stopped = Exited) - docker stop, docker start
      • 컨테이너에서 실행 중인 프로세스완전히 중단
      • CPU와 메모리 사용 모두 중단 (재시작시 프로세스를 처음부터 다시 실행)
    • 삭제 단계 (Deleted) - docker rm, docker rm -f
      • 컨테이너가 삭제된 상태 (격리된 공간 삭제)
    • 참고
      • 컨테이너의 상태는 대부분 컨테이너 내에서 실행되는 프로세스 상태일치
        • 프로세스를 잘 설계하고 다루는 것 => 컨테이너를 잘 사용하는 것
      • docker run = docker create + docker start
      • docker restart: 프로세스를 재시작
        • 실행 중 프로세스에 종료재시작 신호를 보내면 10초 뒤 반응

이미지 레지스트리

  • 도커 이미지를 저장하기 위한 저장소
    • e.g. Docker Hub (대표적)
  • 개인 및 팀이 필요한 이미지를 서로 공유하고 다운로드 (GitHub과 유사)
    • GitHub이 소스 코드만 보관 <-> Docker Hub는 이미지 보관 (소스 코드 + 실행 환경)
    • 이미지명만 서로 알면 실행 환경이 일치하는 애플리케이션 공유 가능
      • 새 서버 구성 시간 및 서버 운영 비용 크게 감소
  • 공통 제공 기능
    • 이미지 공유, 이미지 검색, 이미지 버전 관리, 보안, 파이프라인 (DevOps 배포)
  • 이미지 저장 공간 종류
    • 호스트 머신의 로컬 스토리지 (특정 디렉터리)
    • 온라인 저장소
      • 퍼블릭 레지스트리 (e.g. Docker Hub)
      • 프라이빗 레지스트리
        • 보안 상 사내망, 내부망에서만 사용 가능한 레지스트리
        • 방법
          • 설치형 레지스트리
            • 로컬 서버에 직접 설치
            • e.g. Harbor, Docker 프라이빗 레지스트리
          • 퍼블릭 클라우드 서비스
            • 시간 당 사용 요금 지불
            • e.g. Amazon ECR, Azure Container Registry (ACR)
    • => docker run 실행 시
      • 이미지가 로컬 스토리지에 있으면 바로 실행
      • 없으면 온라인 레지스트리에서 로컬 스토리지로 이미지를 다운 후 실행
  • 이미지 네이밍 규칙
    • 이미지 네이밍: 레지스트리주소/프로젝트명/이미지명:이미지태그
      • 레지스트리주소 (기본값: 도커에서는 Docker Hub 주소 docker.io)
        • 어떤 레지스트리에서 이미지를 다운로드/업로드할 지 지정
      • 프로젝트명 (기본값: library)
        • 이미지를 보관하는 폴더 같은 개념 (Docker Hub에서는 사용자의 계정명)
        • library: 도커사가 직접 검증한 오피셜 이미지를 관리하는 프로젝트
      • 이미지명: 다운로드 받을 이미지의 이름
      • 이미지태그 (기본값: 최신 버전을 의미하는 latest)
        • 이미지의 버전 (숫자, 영문 모두 사용 가능)
        • stable: 안정적 버전
        • alpine, perl…: 베이스 이미지로 사용했던 OS 버전
        • slim: 프로그램 실행에 정말 필요한 것들만 남겨놓음
          • 이미지 전송 시간은 크게 단축하나 디버깅이나 사용이 불편할 수 있음
    • e.g.
      • devwiki.com/myProject/myNginx:2.1.0-alpine
      • nginx -> docker.io/library/nginx:latest (오피셜 이미지)
    • 참고: 이미지 : 이미지 명 = 실제파일 : 참조 링크

이미지 빌드

  • 이미지 레이어
    layered_image
    • 이미지레이어드 파일 시스템으로 구성됨
      • 레이어가 모여 하나의 이미지 구성
      • e.g. 이미지 다운 시, pull이 여러차례 걸쳐 일어남
        • 한 줄이 하나의 레이어
    • 레이어(Layer)
      • 이전 레이어에서 변경된 내용을 저장 (소스코드 커밋, 푸시와 유사)
      • 특징
        • 레이어는 순차적으로 쌓임
        • 여러 이미지 간 공유 가능 (재사용)
        • Copy-on-Write 전략 사용
          • 다음 레이어에서 이전 레이어의 특정 파일을 수정할 때, 해당 파일의 복사본을 만들어 변경 사항을 적용
            • e.g. 컨테이너 레이어는 파일수정 시 이전 레이어의 파일을 복사해와 수정
          • 원래 레이어는 수정되지 않고 그대로 유지됨
        • 불변 레이어 (Immutable Layer): 레이어는 한 번 생성되면 변경되지 않음
          • 이미지의 일관성을 유지
          • 동일한 이미지를 사용하는 컨테이너는 동일한 파일 시스템 상태 사용을 보장
        • 캐싱
          • 레이어를 캐시해두고 이미 빌드된 레이어를 재사용할 수 있음
          • 이미지 빌드 시간이 크게 향상 (같은 레이어 사용하는 여러 이미지에서 효율적)
      • 장점
        • 중복 데이터를 최소화효율적인 저장소 사용 가능
          • 재사용에 유리한 구조 (각 레이어가 서로 영향 X)
          • => 이미지 저장 및 전송 시 스토리지네트워크 사용량 절약
        • 빌드 속도 상승
      • e.g.
        • 레이어 1: OS 파일 시스템
        • 레이어 2: Nginx 설치 파일 (추가 파일만 저장)
        • 레이어 3: Nginx 설정 파일 (추가 파일만 저장)
        • 레이어 4: index.html 파일 수정
    • 레이어 구분
      image_layer_and_container_layer
      • 이미지 레이어 : 컨테이너 레이어 = 건축 도면 : 실제 건물
      • 이미지 레이어
        • 읽기 전용 레이어
        • 컨테이너 실행을 위한 세이브 포인트 역할
        • 각각의 레이어는 고유한 해시값을 가짐
      • 컨테이너 레이어
        • 모든 컨테이너가 가지는 자신만의 읽기/쓰기 레이어
          • 컨테이너 실행 시, 이미지 레이어 위에 새로 추가
        • 컨테이너 실행 후 프로세스가 변경하는 내용을 기록
        • 장점: 같은 이미지로 여러 컨테이너를 만들어도 하나의 이미지 레이어를 공유
          • => 컨테이너 생성 속도 향상공간 절약
  • 이미지를 만드는 방법
    • 이미지 커밋
      • 실행 중인 컨테이너의 상태그대로 이미지로 저장
      • 새로운 이미지 = 기존 이미지 레이어 + 컨테이너 레이어
      • 단점
        • 휴먼 에러 가능성이 높음
          • 이미지를 만들 때마다 컨테이너를 실행해 직접 커밋 명령을 수행해야 함
        • 레이어 쌓을 때마다 컨테이너 실행 및 커밋 반복이 번거로움
    • 이미지 빌드 (주로 사용)
      • IaC 방식을 활용해 이미지를 저장 (Dockerfile)
      • 원하는 이미지 상태를 소스 코드로 작성하면 컨테이너 생성 및 커밋 작업도커가 대신 수행
      • Dockerfile 지시어마다 레이어를 쌓는지 여부가 다름
        • 레이어를 쌓는 지시어 하나 당 레이어 1개 추가
        • 예를 들어, CMD는 레이어를 쌓지 않음
      • 과정 (docker build) -> 커밋 과정을 자동 반복
        • 임시 컨테이너 생성
        • 변경 사항 적용 후 커밋 (새로운 레이어 생성)
        • 임시 컨테이너 삭제
  • 빌드 컨텍스트 (Build Context)
    • 도커 데몬이 이미지를 빌드할 때 전달되는 폴더
      • 도커 데몬은 빌드 컨텍스트에 있는 파일만 카피 명령으로 복사할 수 있음
    • 폴더 내에 도커 파일빌드에 사용되는 파일들이 담겨야 함
      • 빌드 컨텍스트가 너무 크면 전송 시간이 길어지거나 문제 발생
        • C 드라이브 전체 사용 등은 절대 안되고, 따로 폴더로 관리할 것!
      • .dockerignore : 빌드 컨텍스트로 전달될 파일 관리
  • 멀티 스테이지 빌드 (Multi-Stage Build)
    • 빌드 스테이지실행 스테이지 2개로 나누어 빌드하는 방식
    • 장점: 애플리케이션 실행용 이미지크기가 크게 감소
    • 문제
      • 빌드 과정에서 사용하는 파일들은 용량을 많이 차지 (e.g. 메이븐 빌드 도구)
      • 실행용 이미지의 사이즈가 커지면 이미지 전송 및 다운로드 시간이 더 걸림
    • 해결책: 빌드에 사용하는 이미지와 실행에 사용하는 이미지 나누기
      • e.g.
        • 빌드 이미지: 메이븐 도구, 소스코드
        • 실행 이미지: 자바 런타임 및 빌드된 jar 파일
    • 참고: 두 개의 FROM -> 도커가 두 개의 컨테이너를 동시 실행 (메이븐 컨테이너, JDK 컨테이너)

IaC(Infrastructure as Code)

인프라를 코드를 통해서 관리하는 것을 말한다.
사람이 화면이나 CLI를 통해 관리하는 기존 방식은 인수인계도 어렵고 휴먼 에러를 일으킬 확률이 높다.
반면에, IaC는 사람이 코드로 인프라 상세 작업을 기재한다. 그러면 프로그램이 코드를 읽어 대신 인프라 관리를 수행하므로, 더 빠르고 안전하다.
또한, 이러한 코드 명세서를 GitHub에 올리면 인프라 상태도 소스코드처럼 버전 관리를 할 수 있다.

애플리케이션 빌드

애플리케이션 빌드는 필요한 라이브러리들을 설치하고 소스코드를 실행 가능한 프로그램으로 만드는 것을 말한다. (소스코드 -> 애플리케이션)
빌드의 결과물애플리케이션 프로그램(Program) 혹은 아티팩트(Artifact)라고 부른다.
예를 들어, 자바로 개발한 소프트웨어는 소스 코드를 실행 가능한 아티팩트로 빌드할 수 있다. (소스코드 + OS, Java Runtime, 빌드 도구(mvn), 라이브러리 -> jar 혹은 war 파일)

개발한 소스 코드를 이미지로 빌드하는 과정에는 일반적으로 이러한 애플리케이션 빌드 과정을 직접 포함시켜야 한다.


Reference

개발자를 위한 쉬운 도커