Today
-
Yesterday
-
Total
-
  • 👨‍🔧[Docker] 가장 쉬운 말로 풀어 쓴 백엔드 (도커 편)
    | 프로그래밍 분야/SRE 2024. 2. 6. 00:56

    프로그래밍을 처음 배울 때 소위 '개미털기'가 많이 되는 단계는 바로 C언어의 포인터입니다.
    마찬가지로, 백엔드 개발의 '개미털기 지점'은 도커, 쿠버네티스, 클라우드, 네트워크, AWS 등이 있습니다.
    이 중에서, 본 시리즈를 통해 도커 쿠버네티스의 등장 배경과 이론, 실습을 다뤄보려고 합니다.

    어려운 용어는 최대한 줄이고, 누구나 이해할 수 있도록 쉬운 말로 풀어쓰려 노력했습니다.

     

    1. 컨테이너 등장 배경

    도커를 얘기하기 전에, 먼저 컨테이너(Container)에 대해 설명이 필요합니다.

    컨테이너 등장 이전 선박 화물 운송 형태

    컨테이너 등장 이전, 선박을 통해 화물을 운송하는 모습입니다. 화물의 크기와 형태가 모두 다르기 때문에 사람이 직접 배에 실어야 했고, 비용과 시간이 많이 들었습니다. 배에 화물을 얼마나 실을 수 있을지도 가늠하기 어려웠습니다.

    컨테이너(Container)

    컨테이너가 등장한 이후, 선박으로 화물을 운송하는 모습입니다. 컨테이너는 규격화된 크기와 형태를 가지고 있기 때문에, 기구(크레인)를 통해 화물을 선적할 수 있게 되었습니다. 비용과 시간이 절약되고, 최대 적재량을 정의할 수 있게 되었습니다.

    서버 구성 추상화의 역사

    소프트웨어에서 컨테이너도 같은 역할을 합니다. 컨테이너 개념은 2000년대 초반에 등장하였습니다. 그 이전에는, 특정 환경에서 동작하는 애플리케이션을 가동시키기 위해 가상머신(VM: Virtual Machine)을 빌드해야 했습니다. 이 때, 각 VM마다 운영체제(OS: Operating System; Windows, Linux)를 설치해줘야 했고, 이 용량이 약 수십GB로 아주 무거웠습니다. 또, 시스템 설정, 라이브러리 버전도 매번 달라지고 자동화가 어려웠기 때문에 인력이 많이 요구되었습니다.

    컨테이너는 규격화된 크기와 형태(이미지)를 가지고 있기 때문에, 기구(컨테이너화 플랫폼; 도커)를 통해 애플리케이션을 가동할 수 있는 환경(컨테이너)을 구축할 수 있게 되었습니다. 비용과 시간이 절약되고, 메모리 및 디스크 용량을 더 효율적으로 활용할 수 있게 되었습니다.

    컨테이너마다 OS를 설치할 필요가 없도록 컨테이너화 플랫폼(;도커)이 지원해주었고, 해당 OS에 필요한 최소한의 필수 종속성 파일들만 설치하면 되었습니다. 이 파일들은 이미지에 미리 정의되어 있으며, 크기가 약 수KB ~ 1GB로 OS에 비해 아주 가벼웠습니다.

     

    [면접 질문] VM이 필요했던 이유?

    1. 호환성: 프로그램이 개발된 환경과 실행 환경이 다를 경우,프로그램이 동작하지 않거나 의도되지 않은 동작을 할 가능성이 큽니다. 가령 C언어만 해도, Windows와 Linux에서 기본 탑재된 standard library의 종류가 서로 다릅니다.
    이와 같이, OS 종속성이 있는 애플리케이션을 실행하기 위해 해당 OS로 VM을 빌드해서 사용했습니다.

    2. 격리: VM은 VM이 실행되는 컴퓨터 내의 애플리케이션, 그리고 다른 VM상의 애플리케이션들과 강하게 격리됩니다. 이는 종속성 충돌을 방지하고 보안 수준을 높여줍니다.

    3. 비용: VM이 생기기 이전에는 종속성 관리를 위해 사무실 내에 윈도우 컴퓨터, 리눅스 컴퓨터가 따로 여러 대씩 구비되어 있어야 했습니다. VM을 통해 하드웨어 구매 비용을 크게 절약할 수 있었습니다.

     

    2. 도커 등장 배경

    "오케이, VM이 필요했던 이유도 알겠고, VM이 너무 무겁고 라이브러리 관리가 어려워서 컨테이너로 대체된건 알겠어. 그래서 Docker가 뭔데?"

    먼저 백문이 불여일견, 도커의 창립자인 Solomon Hykes의 PYCON 2013 도커 발표 영상을 보고 오기를 추천합니다. 영어로 된 영상이긴 하지만, 유튜브 자동 한글 자막으로 봤을 때 이해에 어려움은 없었습니다. (오역이 조금 있는데, Lily는 Linux, Doklet은 Docker...정도로 이해하시면 됩니다.) 설명도 너무 깔끔하고, 시연 영상도 있고, PT는 이렇게 하는거구나 싶은 영상입니다. 솔로몬 왈, 오픈소스니까 구체적인 설명은 니가 알아서 뜯어봐라 ㅋㅋㅋ

    Docker 시연 영상

    도커는 위에서 얘기했듯, 컨테이너화 플랫폼 중 하나입니다. 컨테이너 개념은 2000년대 초반부터 있었고, 그 뒤로 다양한 컨테이너화 플랫폼이 발표되었지만 업계 표준으로 사용될만큼 사용성과 안정성이 확보된 플랫폼이 없었습니다. 그러던 중 2013년 PYCON에서 Docker 오픈소스가 발표되었고, 이후 Docker는 점차 업계 표준으로 자리잡게 됩니다.

    3. 도커의 기능 및 원리

    물론 Solomon이 말했듯, Docker에는 로드밸런싱이나 scale-out 지원, process 관리 등 다양한 기능이 있지만, 가장 핵심이 되는 기능은 다음과 같습니다.

    도커는 Pre-packaged된 도커 이미지(1 or more)로 컨테이너를 만들고, 그 위에서 애플리케이션을 실행시킵니다. 또한 컨테이너와 Host OS 커널이 통신할 수 있도록 네트워크 인터페이스를 구성하여 IP를 전달해줍니다.

    갑자기 말이 어려워졌네요. 아주 간단한 실습을 통해 그림과 함께 알아봅시다.

    4. 아주 간단한 도커 실습(환경 설정)

    Docker는 기본적으로 Linux System 위에서 동작합니다. 따라서 MacOS, Ubuntu, CentOS 등 Linux/Unix 계열 OS를 사용하시는 분들은 각자 패키지 매니저를 통해 docker를 설치하시면 바로 사용하실 수 있습니다.

    Windows를 사용하시는 분들은 별도의 작업이 필요합니다.
    각 step을 스크린샷으로 보여드리고 싶은데, 이미 wsl2나 docker desktop이 설치되어있어서.. 지웠다가 다시 깔수도 없고.. ㅎㅎ

    powershell 관리자로 실행

    •  시작 - powershell - 관리자로 실행
    • wsl --install
    • wsl --set-default-version 2
    • Docker Desktop 공식 홈페이지에서 Download for Windows
    • Docker Desktop 설치 - 설치 도중 Configuration WSL2 설정 필요

    configure WSL2

    • Docker Desktop 1회 실행 후 Get Started 클릭

    이제 Windows에서 docker를 사용할 준비가 완료됐습니다. powershell이나 wsl2에서 docker를 실행해보세요.
    ※ cmd와 powershell은 다릅니다. 본 예제에서는 powershell을 사용하니 주의해주세요.

    docker 실행!

    5. 아주 간단한 도커 실습(서버 구동)

    이제 docker를 통해 간단한 리눅스 계열 OS에서 파이썬 서버를 구동시켜 보겠습니다.
    실습을 통해 우리는 다음 같은 Workflow를 경험해볼 수 있습니다.

    실습 Process

    powershell에서 다음 명령어를 순서대로 입력합니다.

    • 바탕화면에 폴더를 생성합니다.
    mkdir ~/Desktop/docker-fastapi-test
    • 메모장을 열고, 아래 스크립트를 복붙합니다. 다른 이름으로 저장 - 새로 만든 경로에 "Dockerfile" 이라고 저장합니다. 파일 이름은 따옴표로 감싸고, 파일 형식은 "모든 파일"로 지정합니다. (.txt파일로 저장되는 것을 막아줍니다.)
    FROM python:3.9-slim
    WORKDIR /app
    COPY . /app
    RUN pip install --no-cache-dir -r requirements.txt
    EXPOSE 80
    CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]

    Dockerfile

    Dockerfile은 Docker 이미지를 생성하기 위한 설정 파일입니다. 각 line은 다음과 같은 의미를 가집니다.

    Dockerfile 설명

    이 때, 위에서 말한 Linux OS는 어디에 있냐? 라고 하시면, python:3.9-slim 내부에 있습니다.
    python:3.9-slim은 Docker Hub라는, Dockerfile들을 모아놓은 저장소에 정의되어 있습니다.
    즉, python:3.9-slim 또한 별개의 Dockerfile이며, Dockerfile에서 다른 Dockerfile을 불러와서 사용할 수도 있습니다.

    python:3.9-slim dockerfile 링크

    위 링크에서 보면, OS는 내부적으로 debian:bookworm-slim 을 사용하고 있습니다. debian은 Linux OS(정확히는 Unix OS)의 한 종류인데, slim이라는 건 최소 기능만 남겨놓은 경량화 모델이라고 보시면 됩니다.

    uvicorn은 파이썬 서버를 구동하기 위한 애플리케이션으로, 자세한 설명은 생략합니다.
    ※ requirements.txt 및 main:app은 아래에서 작성합니다.


    • 마찬가지로 새 메모장에서 다음 코드를 복붙합니다. 같은 경로에 main.py 라는 이름으로 저장합니다. 이 때는 파일 이름을 따옴표로 감쌀 필요는 없고, 파일 형식은 "모든 파일"로 선택합니다.
    from fastapi import FastAPI
    
    app = FastAPI()
    
    @app.get("/")
    def read_root():
        return {"message": "Hello, welcome to the root path!"}
    
    @app.get("/home")
    def read_home():
        return {"message": "Hello, welcome to the home path!"}

    main.py

    위 코드는 파이썬의 서버 프레임워크 중 하나인 FastAPI로 작성한 Sample Code로, 자세한 설명은 생략합니다.

    • 마지막으로, 같은 경로에 다음과 같이 requirements.txt 를 작성해줍니다.
    fastapi==0.68.0
    uvicorn==0.15.0
    • 이제 드디어 Docker Image를 만들 수 있습니다.
      powershell에서 아까 만든 폴더로 이동 후, -t(--tag) 옵션으로 "fastapi-test"라는 이름의 이미지를 생성합니다.
    cd ~/Desktop/docker-fastapi-test
    docker build -t fastapi-test .

    docker image 생성

    • 위와 같이 출력되면 정상적으로 이미지가 생성된 것입니다. docker images 를 통해 생성된 이미지를 확인할 수 있습니다.

    docker images

    • 생성한 이미지를 컨테이너로 생성하고 실행시킵니다. -p 옵션을 통해 8080:80 과 같이 포트를 매핑합니다. (hostPort : containerPort)
    docker run -p 8080:80 fastapi-test

    docker run

    드디어 서버가 구동되었습니다. 이제 웹 브라우저를 켜고, 새 탭에서 127.0.0.1:8080에 접속해봅니다. 127.0.0.1:8080/home 에도 접속해봅니다.

    127.0.0.1:8080/home

    ip주소에서 0.0.0.0과 127.0.0.1은 특별한 의미를 가지고 있습니다.
    0.0.0.0은 "모든 ip주소"를 의미하고, 127.0.0.1은 "내 PC"를 의미합니다.

    즉, 컨테이너 내부 main.py에서 설정했던 0.0.0.0:80 은 "모든 ip의 80번 포트에 대해" 응답을 대기한다는 뜻이고, Host PC의 127.0.0.1:8080 은 "내 컴퓨터의 8080번 포트에 대해" 요청을 보낸다는 뜻입니다.

    통신 프로세스

    우리가 웹에서 "내 컴퓨터의 8080 포트로 요청을 보내줘"라고 했을 때의 통신 프로세스입니다. 1~6번 과정을 거쳐, 우리는 웹에서 welcome 메세지를 볼 수 있게 됩니다.

    사용이 끝난 컨테이너와 이미지는 지워줍시다.

    • Ctrl - C : uvicorn 서버 종료
    • docker ps -a : exit된 컨테이너의 ID code 확인
    • docker rm (id code) : 컨테이너 완전 삭제. id code 앞의 몇글자만 적어도 됨.
    • docker image rm fastapi-test : 이미지 삭제
    • docker images : 이미지 삭제된 것 확인

    이미지 삭제


    이번 포스팅을 통해 컨테이너와 도커의 탄생 배경, 개념, 원리, 실습을 진행했습니다.
    최대한 쉬운 말로 풀어쓰려 열심히 노력했는데, 내용 전달이 잘 되었길 바랍니다.

    다음 포스팅을 통해 쿠버네티스, k8s에 대해 알아보도록 하겠습니다.

    지적이나 질문은 항상 감사합니다.

sangilyoon.dev@gmail.com