cloudwithbass

[Docker]Docker와 Dockerfile 소개 및 실습 본문

Docker and Jenkins

[Docker]Docker와 Dockerfile 소개 및 실습

여영클 2024. 7. 8. 20:05

 

 

목차

     

     

     

     

    1. 도커 소개

    Docker는 소프트웨어 컨테이너의 형태로 애플리케이션을 배포할 수 있는 오픈 소스 프로젝트입니다.

    Docker를 사용하면 application과 실행 환경을 통합해서, application을 어디서든 실행할 수 있습니다.

     

    2. 하드웨어 가상화 VS 운영체제 가상화

    Docker는 운영체제 가상화를 사용합니다. 그렇다면 이는 하드웨어 가상화와 어떻게 다를까요?

    2-1. 하드웨어 가상화

    하드웨어 가상화는 하이퍼바이저를 이용해 각 application이 실행할 게스트 OS를 생성합니다.

    하이퍼바이저의 예시로는 흔히 사용하는 VMware와 Xen이 있습니다.

    각 application마다 게스트OS를 사용하므로 자원 효율이 떨어지며 파일의 크기가 커서 서버에 배포할 때 배포 속도가 느립니다.

    호스트 OS: 실제 컴퓨터에 설치된 운영체제
    게스트 OS: 하이퍼바이저에 의해 생성된 OS. 가상 머신에서 작동한다.

    2-2. 운영체제 가상화

     

    운영체제 가상화에선 각 이미지에 게스트OS가 포함되어 있지 않습니다.

    호스트OS수준에서 격리하기 때문에 하드웨어 가상화보다 application 간의 격리 수준은 낮을 수 지만, 오버헤드가 적어 리소스를 효율적으로 사용할 수 있습니다.

    Docker에서는 이미지의 실행 인스턴스를 컨테이너라고 하며, 이를 이용해 컨테이너를 생성, 시작, 중지, 삭제할 수 있습니다. 컨테이너는 CI/CD 워크플로우에 적합합니다.

     

    3. 도커 아키텍처

    사진 출처: https://docs.docker.com/guides/docker-overview/#docker-architecture

     

    Docker는 Client-Server 아키텍처를 사용합니다. Docker Client는 REST API를 이용해서 Docker Daemon과 통신하고, Docker Daemon이 컨테이너를 빌드, 실행, 배포하는 작업을 수행합니다.

     

    추후 설치할 Docker Desktop에는 Docker Daemon, Docker Client, Docker Compose 등이 포함되어 있습니다.

     

    4. 이미지 빌드 과정

    운영체제에 맞게 Docker-Desktop을 설치한 후 터미널에서 docker run hello-world를 실행합니다.

    docker run hello-world 명령 실행 시 다음과 같은 일들이 발생합니다.

    1. 사용자가 docker run 명령어로 Docker client를 실행한다.
    2. Docker client는 Docker daemon에 접속해 hello-world라는 이름의 이미지에서 컨테이너 생성을 요청한다.
    3. Docker daemon은 로컬에서 hello-world 이미지를 찾는다. 만약 로컬에 이미지가 없으면, Docker registry(기본적으로 Docker Hub)에 hello-world 이미지를 요청한다.
    4. Docker daemon이 Docker registry에서 이미지를 가져온다(pull).
    5. Docker daemon이 hello-world 이미지로부터 신규 컨테이너를 생성하고, 컨테이너가 실행되면 hello-world 프로그램이 실행되어 메시지를 출력한다.
    6. Docker daemon은 이 출력문을 Docker client에 전달한다.
    7. Docker client는 이 출력문을 터미널로 전송한다.
    8. hello-world 컨테이너는 메시지를 출력한 후 자동으로 종료된다.

    복잡해보이지만, 각 단계를 도식으로 표현하면 아래와 같습니다.

    5. 도커 이미지 빌드

    도커 이미지를 빌드하는 방법은 두 가지가 있습니다. 

    하나는 docker commit 명령어를 이용하는 것이고, 다른 하나는 Dockerfile을 이용해 docker build 명령을 이용하는 것입니다.

    두 방법에 대해 각각 알아보겠습니다.

    5-1. Docker commit 명령어 사용

    터미널에서 다음 명령어를 실행합니다.

    docker run -i -t ubuntu:20.04 /bin/bash

    ubuntu:20.04 이미지를 가져와서 컨테이너를 실행 후 /bin/bash 명령을 호출합니다.

    -i와 -t 옵션을 줘야 bash를 정상적으로 이용할 수 있습니다.

     

    bash 진입에 성공했으면 다음 명령어를 실행해 git을 설치하고, 확인합니다.

    apt-get update
    apt-get install -y git
    which git

     

    which 명령어로 git 명령어의 위치를 확인

     

    이제 exit 명령으로 bash에서 탈출하고, docker commit [컨테이너 ID] [이미지 이] 명령으로 이미지를 커밋할 수 있습니다.

    이미지 커밋에 성공한 모습
    docker images 명령으로 빌드한 이미지 목록을 확인할 수 있습니다.

    이미지가 생성됐으니 이제 git이 포함된 ubuntu가 필요한 경우 docker run -i -t ubuntu_with_git /bin/bash를 실행하면 됩니다.

     

    5-2. Dockerfile 사용

    위 방식처럼 도커 이미지를 만들 때마다 commit 명령어를 사용하는 방법은 번거로울 뿐더러 CI/CD 프로세스나 빌드 자동화에 적용할 수도 없습니다.

     

    하지만 Dockerfile을 이용하면 자동으로 이미지를 빌드하고 배포할 수 있으며, 이미지를 문서화할 수 있고, 빌드 과정에서 어떤 일이 발생하는지 투명하게 볼 수 있으므로 docker commit보다 권장됩니다.

     

    5-2-1. 도커파일 예제1

    Dockerfile이라는 이름으로 다음 내용의 파일을 생성합니다.

    FROM은 베이스 이미지, RUN은 컨테이너에서 실행할 명령어를 의미합니다.

    #Dockerfile
    FROM ubuntu:20.04
    RUN apt-get update&&apt-get install -y python

     

    이제 docker build -t ubuntu_with_python . 명령을 실행하면 현재 디렉토리(.)의 Dockerfile의 내용을 기반으로 ubuntu_with_python이라는 태그를 갖는 이미지를 빌드합니다.

     

    5-2-2. 도커파일 예제2

    다음 두 파일 hello.py와 Dockerfile을 생성합니다.

    #hello.py
    print "Hello World from Python!"

     

    #Dockerfile
    FROM ubuntu:20.04
    RUN apt-get update && apt-get install -y python
    COPY hello.py .
    ENTRYPOINT ["python", "hello.py"]
    • COPY [파일명] [위치] 명령: 해당 위치의 파일을 이미지의 파일 시스템으로 복사하는 명령어입니다.
    • ENTRYPOINT 명령: 컨테이너가 시작될 때 실행할 명령어를 정의합니다.
      • 이 예제에선 컨테이너 시작시  'python hello.py' 명령을 수행합니다.

     

    docker build -t hello_world_python . 명령으로 Dockerfile을 빌드하고 docker run hello_world_python 명령을 실행하면 다음 사진처럼 애플리케이션이 실행된 것을 확인할 수 있습니다.

    주목할 점은 로컬에 파이썬을 설치하지 않았는데도  파이썬 코드가 실행됐다는 점입니다.

    그 이유는 이미지로 패키징된 애플리케이션 내에 모든 실행 환경이 포함되어 있기 때문입니다.

     

    FROM, RUN, COPY, ENTRYPOINT 외 Dockerfile의 명렁어들은 Dockerfile reference 문서를 참고바랍니다.

     

    6. 환경 변수

    애플리케이션을 실행할 때 옵션을 줄 필요가 있을 경우 사용합니다.

     

    #hello.py
    import os
    print "Hello World from %s !"% os.environ['NAME']

    환경변수 NAME으로 준 변수를 %s자리에 포매팅합니다.

     

    docker build -t hello_world_python_name . 명령으로 빌드 후 NAME 환경 변수를 이용해 docker run해보겠습니다.

    -e 옵션은 환경 변수를 정의합니다.

    참고: Dockerfile에 ENV 명령어를 이용해 환경 변수를 정의할 수도 있습니다.

     

    7. 도커 컨테이너 상태

    4. 이미지 빌드 과정에서 8단계에 컨테이너는 메시지를 출력 후 종료된다고 했습니다.

    하지만 서비스처럼 종료되지 않고 백그라운드에서 계속 실행돼야 하는 애플리케이션들도 존재합니다.

    컨테이너를 백그라운드에서 실행하려면 docker run 명령 시 -d (또는 --deatch)옵션을 사용하면 됩니다.

    위와 같이 hello_world_python_name 이미지는 -d 옵션 없이 빌드했고, ubuntu:20.04 이미지는 -d 옵션과 함께 빌드했습니다.

     

    이제 docker ps -a 옵션으로 이전부터 실행했던 컨테이너들을 확인해보면 hello_world_python_name은 Exited 상태고, ubuntu:20.04는 실행 중인 것을 확인할 수 있습니다.

     

    docker stop [컨테이너 ID] 명령으로 컨테이너를 exited 상태로 만들 수 있습니다.