TOPIC/Infra

#1 Docker 그리고 Docker Network

admin_cloud 2024. 5. 29. 17:19

안녕하세요. TAK 입니다:)

 

날이 점점 더워지고 있는 요즘입니다😓

 

이번 포스팅의 주제로 Docker 그리고 Docker Network를 준비하였습니다😄

(아무래도 Docker 개념을 선행하는 것이 Network 영역을 이해하는데 도움이 되겠죠?!)

 

그럼 바로 시작하겠습니다!


Contents

    1. Docker

    1-1. Docker 란?

    https://www.docker.com/wp-content/uploads/2023/05/symbol_blue-docker-logo.png

     

    : Docker는 2013년 Docker사에서 Go 언어로 개발한 오픈소스 플랫폼입니다.

    이는 Docker Engine 혹은 관련된 모든 프로젝트를 포함한 것을 의미하여, Docker Engine을 사용하여 *리눅스 컨테이너(Linux Container)를 제어하고, 다양한 기능을 사용하여 더 편리하고 쉽게 관리할 수 있습니다.

     

    Docker라는 플랫폼은 컨테이너라는 격리된 환경에서 애플리케이션을 패키징하고 실행하는 기능을 제공합니다.

    격리 및 보안을 통해 특정 호스트에서 동시에 많은 컨테이너를 실행할 수 있습니다.

    컨테이너는 가볍고 애플리케이션을 실행하는 데 필요한 모든 것을 포함하고 있으며, 이식성이라는 특징이 있어, 이는 개발환경, 테스트 환경, 서비스 환경을 모두 동일(Onprem, Cloud 또는 Hybird 환경 등에서도 실행 가능)하게 사용할 수 있기 때문입니다.

     

    *리눅스 컨테이너란?

    https://www.weave.works/blog/a-practical-guide-to-choosing-between-docker-containers-and-vms

     

    : 리눅스 컨테이너는 컨테이너 가상화 기술을 사용합니다. 리눅스 컨테이너에는 애플리케이션이나 이에 필요한 라이브러리 및 설정 파일 등이 포함되어 있습니다.

     

    리눅스 컨테이너를 설명할 때 빠지지 않는 것이 바로 가상 머신과의 비교입니다.

    리눅스 컨테이너는 가상 머신과 다르게 가상화 계층이 없고 커널이 별로 존재하지 않기 때문에 가상 머신에 비해 가볍고 실행 속도 또한 빠르다는 특징을 가지고 있습니다.

     

    즉, 도커는 리눅스 컨테이너를 다루는 도구이며, 컨테이너 런타임이라고 합니다.

    (위 그림의 Container Engine --> Docker Engine) 

     

    리눅스 컨테이너를 사용할 때 가장 핵심 기술 두 가지는 cgroup과 namespace 입니다.

    • cgroup
      : control group의 약자로, Process 또는 Thread를 그룹화하여 관리하는 기능과 시스템 리소스(CPU, 메모리, 디스크 입출력 등)의 사용을 제한하는 기술입니다. 리눅스 컨테이너는 호스트의 리소스를 공유하여 사용하는데, 이때 cgroup을 사용하여 컨테이너가 사용하는 리소스의 양을 제한할 수 있습니다. 또한 같은 호스트에서 동작하는 서로 다른 컨터이너에 영향을 주지 않도록 막아주는 역할을 합니다.

    • namespace
      : namespace는 직역하면 이름공간으로, 이 공간에 다수의 Object를 격리할 수 있습니다. 예를 들어 동일한 호스트에서 동일한 PID를 가칠 수 없지만 서로 다른 namespace에서는 동일한 PID를 가질 수 있습니다.

     

    1-2. Docker 구조

    https://docs.docker.com/get-started/images/docker-architecture.webp

     

    • Docker 클라이언트(docker)
      : 클라이언트는 docker 커맨드를 통해 한 개 이상의 데몬과 통신할 수 있으며 사용자가 Docker와 상호작용할 수 있는 가장 우선적인 방법입니다.

    • Docker 데몬(dockerd)
      : 다른 Docker 데몬과 통신하거나 Docker API 요청을 기다리고 이미지, 컨테이너, 네트워크, 볼륨 등을 관리하는 역할을 합니다.

    • Docker 레지스트리
      : Docker 이미지 저장소. 기본적으로 Docker Hub라는 퍼블릭 레지스트리로 설정되어 있고 프라이빗 레지스트리도 생성할 수 있으며, Docker Datacenter(DDC)를 사용하는 경우, Docker Trusted Registy(DTR)로부터 pull, push 할 수 있습니다.

     

    위 용어를 통해 그림의 흐름을 간략히 설명하면 다음과 같습니다.

    - Clinet에서 Docker Command 실행

    - Docker Host의 Daemon을 통해 동작하는데, Reigstry에 있는 images를 가져와 Container에게 전달(배포) 

     

    1-3. Docker 개념 및 용어 정리

    • Container(컨테이너)
      : 위에서도 언급한 것처럼, 컨테이너는 앱의 각 구성 요소에 대해 격리된 프로세스입니다.
      • 각 컨테이너에는 호스트 시스템에 사전 설치된 종속성에 의존하지 않고, 작동하는 데 필요한 모든 요소가 포함되어 있습니다.
      • 컨테이너는 격리되어 실행되므로 호스트 및 기타 컨테이너에 미치는 영향이 최소화되어 애플리케이션의 보안이 향상됩니다.
      • 각 컨테이너는 독립적으로 관리됩니다. 하나의 컨테이너를 삭제해도 다른 컨테이너에는 영향을 미치지 않습니다.
      • 컨테이너는 어디에서나 실행될 수 있습니다. 실행되는 컨테이너는 On-Premise, Cloud 등 인프라 환경에 상관없이 동일한 방식으로 작동합니다.

    • Image(이미지)
      : 컨테이너 이미지는 컨테이너를 실행하는 데 필요한 모든 파일, Binary, Library 및 구성을 포함하는 표준화된 패키지입니다. 다만, 이미지는 다음과 같은 특징이 있습니다.
      • 이미지는 이미지 생성 후, 변경(수정)할 수 없습니다. 새 이미지를 만들거나 그 위에 변경 사항을 추가하는 것만 가능합니다. 즉, 기존 이미지를 기반으로 새로운 이미지를 생성하는 것을 의미합니다.
      • 컨테이너 이미지는 레이어로 구성됩니다. 각 계층은 파일을 추가, 제거 또는 수정하는 일련의 파일 시스템 변경 사항을 나타냅니다.

        이 두 가지 특징을 기반으로 기존 이미지를 추가하거나 확장할 수 있습니다. 쉽게 표현하자면, Nginx 같은 기본 이미지(version 1.0)를 시작하고 추가 레이어를 추가하여 코드를 추가하여 새로운 이미지(version 2.0)를 만들 수 있습니다.

    • Registry(레지스트리)
      : 말 그대로, 이미지를 저장하는 장소를 Registry라 말합니다. 저장소라는 용어와 구분하여 설명하자면 저장소는 레지스트리 내 관련 이미지의 모음이며, 레지스트리는 이미지를 저장하고 관리하는 상위 개념입니다.

      개발을 위한 소스코드를 저장하고, 다른 사람들과 공유할 수 있는 Github와 같이 이미지를 저장하고 공유할 수 있는  Docker Hub 공용 레지스트리가 있으며, CSP 사에서 제공하는 Azure Container Registry, Amazon Elastic Container Registy 같은 Private 레지스트리 혹은 Harbor, JFrog Artifactory, GitLab 컨테이너 레지스트리 등이 있습니다.

    • Docker Compose
      : Docker사의 권장 사항으로 각 컨테이너가 한 가지 작업을 수행하는 것입니다. 다만, 하나의 컨테이너에 여러 작업을 실행할 수 있는데, 바로 Docker Compose를 수행하는 방법입니다. 즉, 앱을 구성하는 서비스를 docker-compose.yml에 정의하여 격리된 환경에서 함께 실행할 수 있습니다.

    • Dockerfile
      : Dockerfile은 컨테이너 이미지를 빌드하기 위한 지침을 제공합니다. 즉, 사용자가 이미지를 생성하는데, 해당 이미지를 통해 실행될 애플리케이션의 필요한 종속성을 포함합니다. 이는 단일 이미지를 빌드하기 위한 명세서이며, 나열된 명령어(텍스트)가 차례대로 수행되는데, 베이직 이미지, 환경 변수, 수행 명령어 등 이미지를 빌드하기 위한 명령어가 포함되어 있습니다.
      FROM python:3.12
      WORKDIR /usr/local/app
      
      # Install the application dependencies
      COPY requirements.txt ./
      RUN pip install --no-cache-dir -r requirements.txt
      
      # Copy in the source code
      COPY src ./src
      EXPOSE 5000
      
      # Setup an app user so the container doesn't run as the root user
      RUN useradd app
      USER app
      
      CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080"]

      각 요소는 다음을 의미합니다.
      • FROM <image> : 빌드가 확장될 기본 이미지를 지정합니다.
      • WORKDIR <path> : 이 명령은 "작업 디렉터리" 또는 파일이 복사되고 명령이 실행될 이미지의 경로를 지정합니다.
      • COPY <host-path> <image-path> : 이 명령은 빌더에게 호스트에서 파일을 복사하여 컨테이너 이미지에 넣으라고 지시합니다.
      • RUN <command> : 이 명령은 빌더에게 지정된 명령을 실행하도록 지시합니다.
      • ENV <name> <value> : 이 명령은 실행 중인 컨테이너가 사용할 환경 변수를 설정합니다.
      • EXPOSE <port-number> : 이 명령은 이미지가 노출하려는 포트를 나타내는 이미지 구성을 설정합니다.
      • USER <user-or-uid> : 이 명령은 모든 후속 명령에 대한 기본 사용자를 설정합니다.
      • CMD ["<command>", "<arg1>"] : 이 지침은 이 이미지를 사용하는 컨테이너가 실행할 기본 명령을 설정합니다.

     

    1-4. Docker 설치 및 구성 확인

    : Azure VM(Ubuntu 22.04)에서 테스트 진행하였습니다. 

    다음 2부에서 자세히 설명하겠지만, Docker의 경우, 기본적으로 172.17.0.0/16  으로 설정(!변경 가능!)되어 있습니다.

     

    실습에서(Default Network를 변경하지 않을 예정), 해당 대역과 중첩하게 된다면 컨테이너 통신이 되지 않기 때문에 유의하시기 바랍니다.

     

    관련하여 보다 자세한 내용은 2편에서 진행할 예정입니다.

    1-4-1. Docker Command

    Docker에서 주로 사용되는 기본 명령어를 다음과 같이 정리하였습니다.

    (보다 자세한 명령어는 공식 문서를 참고해 주세요!)

    Docker Image 이미지 검색(From Docker Hub) docker search {이미지 이름}
    이미지 다운로드 docker image pull {이미지명:태그}
    (다운로드 된) 이미지 조회 docker images
    이미지 빌드(Dockerfile) docker build -t {이미지명:태그명} {dockerfile의 경로}
    이미지 삭제 docker image rm {이미지 ID or 이름} 
    이미지 업로드 docker image push {이미지명:태그}
    Docker Container 실행중인 컨테이너 목록 조회 docker ps
    컨테이너 생성 후, 실행 docker run -it --name {컨테이너 이름} -p {Host 포트} : {컨테이너 포트} {이미지 Repository}
    컨네이너 실행 docker start {이미지 이름:태그}
    컨테이너 중지 docker stop {컨테이너 ID or 이름}
    컨테이터 삭제 docker rm {컨테이너 ID or 이름}
    컨테이너 내부 접속 docker exec -it {컨테이너 ID 또는 이름}
    /bin/bash
    Docker Compose 빌드 docker-compose build
    빌드 후, 실행 docker-compose up
    조회 docker-compose ps
    삭제 docker-compose down

     

    1-4-2. Docker 설치

    • 설치를 위한 apt 레포지토리 설정
      # Add Docker's official GPG key:
      sudo apt-get update
      sudo apt-get install ca-certificates curl
      sudo install -m 0755 -d /etc/apt/keyrings
      sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
      sudo chmod a+r /etc/apt/keyrings/docker.asc
      
      # Add the repository to Apt sources:
      echo \
        "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
        $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
        sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
      sudo apt-get update


    • 패키지 설치
      sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin


    • 설치 확인
      : 서비스 등록되어 Status(Active) 확

    • 테스트 이미지 실행

    • 이미지 목록 확인(조회)

     

    1-4-3. Image Pull (다운로드)  - Run 

    : 일반적으로 이미지를 Push/Pull 하는 단계에서 Docker Hub의 이미지를 사용하기 위해서넌 Login이 필요합니다.

    다만, Push의 경우, Commit 을 위한 Docker Hub의 User ID와 저장소인 Repository 를 명령어에 사용하기 때문에 반드시 필요합니다. Pull의 경우, 이미지를 다운로드할 때 Docker Hub Login 없이 가능하지만, 기능의 일부 제약이 존재합니다.

     

    앞서 설명한 것처럼, Docker Hub는 Public 합니다. 따라서 공개된 이미지나 Pull 가능하며, Push 가능합니다. 다만, 보안 위험 등 존재할 수 있는 사고를 줄이고자 공식 이미지(Official Imgae), 인증된 게시자(Verified Publisher) 이미지 혹은 자신이 만든 이미지를 사용하는 것을 권장합니다.

     

    • Trusted content

    https://hub.docker.com/explore
    명령어로 이미지 검색 시, 확인되는 OFFICIAL CHECK

     

     

    • Nginx 공식 이미지 다운로드
      : 태그(tag)의 경우, 별도 지정하지 않는다면, 자동적으로 latest 기본값으로 사용됩니다.

     

    • Container 생성 및 실행
      : Conatiner 생성 및 실행을 위해서는 docker run 명령어를 실행합니다. 해당 명령어는 이미지에서 새 컨테이너를 생성 및 실행하는 명령어입니다.
      자주 사용되는 옵션과 예시는 다음과 같으며, 보다 자세한 옵션과 설명은 공식 문서를 참고해 주세요.
      docker (container) run [OPTIONS] IMAGE [COMMAND] [ARG...]
      • -d( --detach) : 컨테이너를 백그라운드에서 실행
      • -p(--publish) : 호스트 포트와 컨테이너 포트 연결
      • --name : 컨테이너 이름 지정
      • -it(--interatice & --tty) : 컨테이너와 상호 작용하는 대화형 모드로 컨테이너 안에서 터미널을 사용하는 것처럼 명령어를 입력하고 출력을 확인 가능. 주로 컨테이너 내부에서 Shell에 접근하기 위해 사용
      • -v(--volume) : 호스트의 디렉터리를 컨테이너의 디렉터리로 마운트
      • -e(--env) : 환경 변수 설정
      • --network : 특정 네트워크에 컨테이너 연결
    # nginx 라는 이미지를 
    # nginx_svr 라는 컨테이너 이름으로 백그라운드 실행
    # 호스트 포트(8000)와 컨테이터 포트(80) 연결
    
    sudo docker run -d --name=nginx_svr -p 8000:80 nginx

     

    정상 실행 시, 컨테이터 ID 출력
    현재 실행중인지 확인(Status : Up)
    curl 명령어로 확인
    인터넷에서 액세스 확인

     

    *Azure VM에서 실행 중이므로 외부에서 해당 웹 페이지를 액세스 하기 위해서는 NSG의 인바운드 정책을 추가하여야 합니다.

     

     

    1-4-4. Image Push (업로드) 

    : 이미지를 Docker Hub와 같은 레지스트리에 Push(업로드) 합니다.

    위 단계에서 Pull(다운로드)한 nginx 이미지를 기반으로 Content를 일부 수정 후, 새로운 이미지를 생성하여 Docker Hub의 레지스트리에 Push 하는 과정입니다.

    • 기존 이미지 수정
      : HTML 파일 수정을 위해, 실행 중인 컨테이너 내부에 접근하여 Nginx가 바라보는 HTML 파일이 저장된 경로를 파악합니다.
    sudo docker exec -it nginx_svr /bin/bash

     

    # 이미지는 삽입하기 위해 컨테이너 내부에 디렉터리 생성
    sudo docker exec nginx_svr mkdir -p /usr/share/nginx/html/images
    
    # 이미지 파일을 컨테이너 내부로 복사
    sudo docker cp ./IMG_4559.JPG\?type\=w773 nginx_svr:/usr/share/nginx/html/images/
    > Successfully copied 29.2kB to nginx_svr:/usr/share/nginx/html/images/

    컨테이너 내부 확인

     

    NGINX에서 정적 파일을 제공할 때, 쿼리 문자열을 무시하고 파일 이름만 사용하기에 이미지를 제대로 서빙하기 위해서 파일 이름 변경

    # 해당 이미지가 저장된 경로(./images/)에서 변경
    mv 'IMG_4559.JPG?type=w773' IMG_4559.JPG

     

    마지막으로 HTML 파일을 수정합니다.

    # index.html 파일 수정
    echo "<h1>Hello, Tak's World</h1><img src='images/IMG_4559.JPG?type=w773' alt='My Image'>" > /usr/share/nginx/html/index.html

     

     

    • 새로운 이미지 정의하여 Docker Hub에 Push
      : 위 단계까지 변경 작업한 사항을 반영하여 새로운 이미지를 생성하여 이미지를 Push 합니다. 레지스트리에 이미지를 Push 하기 위해서는 Docker Hub 로그인이 필수입니다.

    수정한 내용을 새로운 Docker 이미지로 Commit 합니다.

     

     

    변경 사항을 Docker Hub에 Push 하기 위해 login 합니다.

    계정 정보를 기입하여 로그인을 시도합니다. warning이 표시되는 이유는 로그인 정보다 해당 호스트(서버)에 남기에 주의하라는 내용이며, 해당 테스트에서는 개인용 VM을 사용하기에 무시합니다.

     

    이제, 해당 이미지를 본인의 저장소(레포지토리)에 Push 합니다.

    명령어를 통해 레포지토리에 이미지를 Push 하기 위해서는 Docker hub에 레지스트리를 생성하여야 합니다.

     

    로그인 후, [Repositories] - [Create repository] 를 선택합니다.

     

    Namespace는 본인의 Account를 의미하며, 그 안에 포함되는 레포지토리 이름을 정의하여 생성합니다.

     

    마지막으로 이미지를 Push 합니다.

    # 이미지 식별 등 버전 관리를 위한 tag 명령어 사용
    # 호스트(로컬)에 있는 'nginx_svr:modified001' 이미지를 Docker hub에 생성한 레포지토리 'tak2da/taks-blog:v1' 태그 설정
    
    docker tag nginx_svr:modified001 tak2da/taks-blog:v1

     

    **docker login을 통해 login 여부를 확인합니다.

    # tag가 설정된 이미지를 Docker hub에 Push
    
    docker push tak2da/taks-blog:v1

     

    • 업로드 확인

     

    해당 이미지를 통해 Pull을 시도하여 새로운 Container를 생성 및 실행할 수 있습니다.

    1-4-5. Dockerfile - Build

    : 이번에는 Docker Hub에서 만들어진 이미지 같은 표준화된 이미지나 빠른 배포를 위해 사용하는 Pull-Run 방식이 아닌, Dockerfile을 작성하여 커스터마이징 된 이미지를 빌드하고 실행하는 테스트를 해보겠습니다.

     

    Python 애플리케이션인 Flask 를 Docker 컨테이너로 생성 및 실행하는 과정입니다.

    (Python 및 Flask 설치의 경우, 해당 과정에서는 생략합니다. 간단하고 기본적인 Flask만 구성하시면 됩니다!)

    • 의존성 파일 작성
      : 설치한 Flask의 버전을 확인하여, 의존성을 명시한 requirement.txt 파일에 기입합니다. 

     

    • Dockerfile 생성
    # 베이스 이미지로 Python 3.9 사용
    FROM python:3.9-slim
    
    # 작업 디렉토리 설정
    WORKDIR /usr/src/app
    
    # 의존성 파일 복사 및 설치
    COPY docker-flask/requirements.txt ./
    RUN pip install --no-cache-dir -r requirements.txt
    
    # 애플리케이션 파일 복사
    COPY docker-flask/. .
    
    # Flask 애플리케이션 실행
    CMD ["python", "app.py"]

     

    • 이미지 Build
    # 이미지 빌드 시, tag(1.0) 적용
    # docker-flask 는 이미지의 이름이고, .(마침표)는 Dockerfile이 있는 현재 디렉토리를 의미
    
    docker build -t docker-flask:1.0 .

     

    • Docker 컨테이너 생성 및 실행
    # docker-flask:1.0 라는 이미지를 
    # flaks_svr 라는 컨테이너 이름으로 백그라운드 실행
    # 호스트 포트(8080)와 컨테이터 포트(5000) 연결
    
    sudo docker run -d --name=flaks_svr -p 8080:5000 docker-flask:1.0

    *위 Nginx와 마찬가지로 외부(인터넷)에서 액세스 하기 위해서는 NSG 인바운드 정책에 8080 포트를 Open 해야 합니다.


    지금까지 " #1 Docker 그리고 Docker Network 중 Docker" 에 대해 알아보았습니다.

    다음 편에는 " #02 Docker Network "으로 돌아오겠습니다 🙉 (!!많관부!!)


    여러분의 생각하는 부족한 점, 궁금한 점 등 자유로운 의견을 남겨주세요!

    728x90
    320x100
    SMALL