[AI 서비스 개발 개론] Docker

임수정·2022년 2월 19일
2
post-thumbnail

Docker

1. Docker 소개

1.1. 가상화란?

1) 가상화의 필요성

  • 개발할 때, 서비스 운영에 사용하는 서버에 직접 들어가서 개발하는 게 아니라,
    Local 환경에서 개발하고, 완료되면 staging 서버, production 서버에 배포하는 식으로 진행된다.

  • 개발을 진행한 local 환경과 production 서버 환경이 다른 경우에,
    os가 다르기 때문에 라이브러리, 파이썬 등을 다른 방법으로 설치해야 하는 경우가 많다.

    • 예) local : 윈도우, production 서버 : linux
  • 또한 local 환경과 서버가 같은 OS를 사용해고, 서버에서 올바르게 작동하지 않을 수도 있다.

    • 예) local의 환경변수와 production 서버의 환경변수가 다를 경우


  • 이를 해결하기 위해, 다양한 설정을 README 등에 기록하고, 항상 실행하도록 하는 방법이 있다. 하지만 이 방식에는 두 가지 한계가 존재한다.

    1. 사람이 진행하는 일이라 human error가 발생할 수 있고,
    2. 매번 이런 작업을 해야 하는 과정이 귀찮다.

  • 또한 만약 운영하고 있는 서버가 100대라면?(=매우 많다면?)

    • 특정 서버 업데이트가 진행될 때마다 나머지 서버에도 모두 접속해서 업데이트를 해야 한다.=> 엄청난 시간이 들 것이다...
  • 이 부분에서 생기는 고민:

    '서버 환경까지도 모두 한번에 소프트웨어화 할 수 없을까?'
    ( 밀키트를 만들어서 집에서도 사용하고 레스토랑에서도 사용할 수 있게 할 수 없을까? )

  • 이런 고민을 해결하기 위해 나온 개념이 바로 '가상화'이다.(엄밀하게는 하드웨어 가상화 등 더 넓은 개념이지만, 여기선 소프트웨어 가상화로 한정한다.)


2) 가상화 : Research / Production환경에서 공통적으로 사용하는 일종의 템플릿

  • 가상화를 사용하면 특정 소프트웨어 환경을 만들고, local, production서버에서 그대로 활용
  • 개발(local)과 운영(production) 서버의 환경 불일치가 goth
  • 어느 환경에서나 동일한 환경으로 프로그램을 실행할 수 있음
  • 개발 외에 research도 동일한 환경을 사용할 수 있음


1.2. Docker의 등장

1) Docker 등장 전

  • 가상화 기술로 주로(Virtual Machine)을 사용
  • VM은 호스트 머신이라고 하는 실제 물리적인 컴퓨터 위에, OS를 포함한 가상화 소프트웨어를 두는 방식
    • 예) 호스트 머신은 윈도우인데, 윈도우에서 리눅스를 실행

  • GCP의 Compute Engine 또는 AWS EC2가 이런 개념을 활용
    => 클라우드 회사에서 미리 만든 이미지를 바탕으로, Computing 시스템을 통해 사용자에게 동일한 컴퓨팅 환경을 제공
  • 그러나 OS위에 OS를 하나 더 실행시킨다는 점에서 VM은 굉장히 리소스를 많이 사용 => 이런 경우를 '무겁다'라고 표현
  • Container: VM의 무거움을 덜어주면서, 가상화를 좀 더 경량화된 프로세스의 개념으로 만든 기술
    => 이 기술의 등장으로 이전보다 빠르고 가볍게 가상화를 구현할 수 있게 됨

2) Docker 등장!

  • Container 기술을 쉽게 사용할 수 있도록 나온 도구가 바로 Docker
  • 2013년에 오픈소스로 등장
  • 컨테이너에 기반한 개발과 운영을 매우 빠르게 확장

(출처: https://www.vembu.com/blog/containers-vs-virtual-machines-differences-and-advantages/)

  • Docker의 실행 : Docker Image로 만들어두고, 재부팅하면 Docker Image 상태로 실행됨

  • Docker Image

    • 컨테이너를 실행할 때 사용할 수 있는 템플릿(객체지향 클래스와 유사)
    • Read only(immutable)
  • Docker Container

    • Docker Image를 활용해 실행된 인스턴스
    • Write 가능

3) Docker로 할 수 있는 일

  • 다른 사람이 만든 소프트웨어를 가져와서 바로 사용할 수 있음

    • 예) MySQL을 Docker로 실행
    • 예) Jupyter notebook을 docker로 실행
    • 다른 사람이 만든 소프트웨어 : Docker Image
    • OS, 설정을 포함한 실행 환경
    • Linux, Window, Mac 어디에서나 동일하게 실행할 수 있음
  • 자신만의 이미지를 만들어 다른 사람에게 공유할 수 있음

    • 원격 저장소에 저장하면 어디서나 사용할 수 있음
    • 원격 저장소: Container Registry
    • 원격 저장소로는 dockerhub, GCR, ECR 등이 있음
    • 회사에서 서비스를 배포할 때에는 원격 저장소에 이미지를 업로드하고, 서버에서 받아서 실행하는 식으로 진행

2. Docker 사용법

2.1. Docker 기본 명령어 정리

  • docker pull "이미지 이름:태그": 필요한 이미지 다운
  • docker images: 다운받은 이미지 목록 확인
  • docker run "이미지 이름:태그" : 이미지를 기반으로 컨테이너 생성
  • docker ps : 실행중인 컨테이너 목록 확인
  • docker exec -it "컨테이너 이름(id) /bin/bash : 컨테이너에 진입
  • docker stop "컨테이너 이름(id): 실행중인 컨테이너를 중지
  • docker rm "컨테이너 이름(id): 중지된 컨테이너 삭제
  • 그 외
    • docker run할 때 파일을 공유하는 방법 : Volume Mount
      • docker container 내부는 특별한 설정이 없으면 컨테이너를 삭제할 때 파일이 사라짐(=host와 container가 파일공유가 안됨)
      • 만약 파일을 유지하고 싶다면 host(우리 컴퓨터)와 container의 저장소를 공유해야 함
      • volume mount를 진행하면 host와 container의 폴더가 공유됨
      • -v 옵션을 사용하며, -p(port)처럼 사용함.
        (-v HOST_FOLDER:CONTAINER_FOLDER)
      • 예시)
      docker run -it -p 8888:8888 -v /some/host/folder/for/work:/home/sujeongim/workspace jupyter/minimal-notebook
  • 참고 : Dockerhub에서 공개된 모든 이미지를 다운 받을 수 있음

2.2. Docker 실습

1) 도커 공식 홈페이지에서 자신의 운영체제에 맞는 Docker Desktop 설치

  • 설치 후, 터미널에서 docker 커맨드가 동작하는지 확인(아래처럼 뭔가 주르륵 뜨면 성공!)

2) Docker image 다운 받기(MySQL 실행하기)

  • docker pull "이미지 이름:태그"
    : docker pull mysql:8로 mysql 8 버전의 이미지를 다운(git clone과 비슷)

  • 참고로 mac m1에서는 docker pull "이미지 이름:태그"만 치면 실행이 안된다. 위와 같이 linux/arm64/v8 에 해당하는 manifest가 없다는 오류가 나오는데, 이 경우 --platform 옵션을 사용해 플랫폼을 linux/x86_64로 명시해 주면 된다.(참고1,참고2)
    아..이전 실습 때 내가 이미 mysql 최신 이미지를 다운 받아서 아래와 같이 결과가 나온다. 그러면 지우고 다시 해보자.

    이미지를 지우는 명령어는 rmi이다. docker rmi "이미지 이름:태그"하면 이미지를 지울 수 있다.(docker 삭제 관련 링크)

    그러면 다시 docker pull "이미지 이름:태그"로 이미지를 다운 받아보자.

    다운로드가 성공적으로 되었다:)


3) 다운받은 이미지 확인 : docker images

  • docker images 명령어를 사용하여 다운받은 이미지를 확인할 수 있다.

4) Docker 실행하기 : docker run "이미지 이름:태그"

  • 다운 받은 mysql 이미지 기반으로 docker container 만들고 실행

  • 명령어는 다음과 같은 형식으로 작성한다.

    docker run --name "컨테이너 이름" -e 환경변수=환경변수값 -d -p "로컬 호스트 포트:컨테이너 포트" "이미지 이름:태그"

    (m1의 경우 호환이 되지 않는다는 warning이 뜨는데, 아직 맞는 해결책을 찾지는 못했다..ㅠㅜ warning이기에 container가 생성되긴한다.)

  • 컨테이너 이름 : 지정하지 않으면 랜덤으로 생성

  • 환경 변수 설정 : 사용하는 이미지에 따라 설정이 다름, mysql은 환경변수를 통해 root계정의 비밀번호를 설정

  • 포트 지정: "로컬 호스트 포트:컨테이너 포트" 형태로, 로컬 포트 3306으로 접근 시 컨테이너 포트 3306으로 연결되도록 설정. mysql은 기본적으로 3306 포트를 통해 통신(로컬 호스트:우리의 컴퓨터, 컨테이너 포트:컨테이너 이미지 내부)

  • 실행한 컨테이너는 docker ps 명령어로 확인할 수 있다.


5) MySQL이 실행되고 있는지 확인하기 위해 컨테이너 진입하기

  • (Compute Engine에서 SSH와 접속하는 것과 유사)
    docker exec -it "컨테이너 이름(혹은 ID)" /bin/bash
    • 아래 명령어를 통해 MySQL프로세스로 들어가면 MySQL 쉘 화면이 보임
      mysql -u root -p

6) 컨테이너 중지하기

  • docker stop 명령어를 통해 실행 중인 컨테이너를 중지시킬 수 있다.


  • 작동을 멈춘 컨테이너는 docker ps -a 명령어로만 확인할 수 있음
    (docker ps는 실행중인 컨테이너 목록만 보여줌)


2.3. Docker Image 만들기

  • 간단한 FastAPI애플리케이션을 실행하는 서버를 Docker Image로 생성해보자

1) 먼저 폴더를 하나 만들고, 여기에 가상환경 세팅과 FastAPI 패키지 설치

2) GET /hello 요청하면, 메세지를 전달하는 간단한 코드를 작성

3) 설치한 라이브러리 모두 보기 : pip freeze

  • 또는 pip list --not-required --format=freeze를 실행할 경우에는 의존성에 따라 설치된 라이브러리는 보이지 않음
  • pip로 설치한 라이브러리를 모두 requirements.txt에 저장

4) Dockerfile이라는 파일을 만들어 다음처럼 작성(Docker Image를 빌드하기 위한 정보가 담김)

  • Dockfile은 한 줄씩 자세히 살펴보자.

  • FROM python:3.8.7-slim-buster

    • FROM "이미지 이름:태그"
    • 이미지 빌드에 사용할 베이스 이미지를 지정
    • 베이스 이미지는 이미 만들어진 이미지
    • 보통 처음부터 만들지 않고, 이미 공개된 이미지를 기반으로 새로운 설정을 추가
    • 여기에서는 python:3.8.7-slim-buster를 사용(이 이미지는 Dockerhub에 존재) (slim-buster는 비교적 가벼운 이미지를 뜻함)
  • COPY . /app

    • COPY "로컬 디렉토리(파일)" "컨테이너 내 디렉토리(파일)"
    • 컨테이너는 자체적인 파일 시스템과 디렉토리를 가짐
    • COPY 명령어는 Dockerfile이 존재하는 경로 기준 로컬 디렉토리를 컨테이너 내부의(자체 파일 시스템을 가진) 디렉토리로 복사
    • 파일을 컨테이너에서 사용하려면 COPY 명령어로 반드시 복사해야 함
  • WORKDIR /app

    • WORKDIR "컨테이너 내 디렉토리"
    • Dockerfile의 RUN, CMD, ENTRYPOINT 등의 명령어를 실행할 컨테이너 경로 지정
    • 이 라인 뒤에 등장하는 RUN, CMD는 컨테이너 내부의 /app에서 실행
  • ENV PYTHONPATH=/app ...

    • ENV "환경변수이름=값"
    • 컨테이너 내 환경 변수를 지정
    • 파이썬 애플리케이션의 경우 통상 위 두 값을 지정
  • RUN pip install

    • RUN "실행할 리눅스 명령어"
    • 컨테이너 내에서 리눅스 명령어를 실행
    • 위의 경우 pip install pip와 -r requirements.txt 두 명령어를 실행
    • 한 번에 실행할 명령어가 여러 개인 경우 &&\로 이어줌
    • 이전 라인에서 COPY와 WORKDIR이 실행되었기 때문에 컨테이너 내에 requirements.txt
  • CMD ["python", "main.py"]

    • CMD ["실행할 명령어", "인자",...]
    • docker run으로 이 이미지를 기반으로 컨테이너를 만들 때, 실행할 명령어
    • 이 이미지는 실행되는 즉시 python main.py를 실행하며 CMD는 띄어쓰기를 사용하지 않음
  • RUN과 CMD 차이점

  • Docker Image Build 하기

    • docker build "Dockerfile이 위치한 경로"
    • 이미지를 생성하는 과정(빌드라고 표현)
    • 아래 이미지에서 . 는 현재 폴더에 dockerfile이 있음을 의미
    • -t "이미지 이름:태그" 옵션으로 이미지 이름과 태그를 지정할 수 있음
    • 태그는 미 지정시 'latest'로 채워짐


  • 빌드된 이미지 확인

    • docker images 명령어로 방금 빌드한 이미지를 확인할 수 있다


  • 방금 만든 이미지에 대해 컨테이너를 만들고 실행하기

    • docker run “이미지 이름:태그”
    • 방금 만든 이미지를 실행한다
    • 태그가 “latest” 인 경우 생략 가능


  • 다른 터미널을 열어 curl로 애플리케이션이 잘 작동하는지 확인할 수 있다.

  • Docker Image 만들기 정리!!

    • 파이썬 환경 및 애플리케이션 코드를 작성
    • Dockerfile 작성
      • FROM으로 베이스 이미지를 지정
      • COPY로 로컬 내 디렉토리 및 파일을 컨테이너 내부로 복사
      • WORKDIR로 RUN, CMD 등을 실행할 컨테이너 내 디렉토리 지정
      • RUN으로 애플리케이션 실행에 필요한 여러 리눅스 명령어들을 실행
      • CMD로 이미지 실행 시 바로 실행할 명령어를 지정
      • 그 외에 Dockerfile에서 사용하는 것
        • EXPOSE : 컨테이너 외부에 노출할 포트 지정
        • ENTRYPOINT : 이미지를 컨테이너로 띄울 때 항상 실행하는 커맨드
    • docker build “Dockerfile이 위치한 경로” -t “이미지 이름:태그” 으로 이미지 빌드
    • docker run “이미지 이름:태그”로 빌드한 이미지를 실행

3. 추가 자료 & 과제

 
profile
유쾌하게, 열정적으로, 진심을 다해

0개의 댓글