[AITech][Product Serving] 20220216 - Docker
본 포스팅은 SOCAR의 ‘변성윤’ 강사 님의 강의를 바탕으로 제작되었습니다.
학습 내용
본 포스팅은 Docker에 대한 강의를 수강하며 정리한 내용입니다. 그렇지만 제가 워낙 cloud system, container system에 대한 개념이 없어서 Docker나 Kubernetes에 대한 내용은 따로 책을 이용해 학습할 계획입니다. 이 포스팅에서는 간단히 Docker가 무엇이고, 사용하는 기본적인 커맨드들에는 무엇이 있는지 알아보겠습니다.
Docker 소개
가상화란?
Docker에 대해 알아보기 전에, 가상화라는 개념을 알아야 합니다. 가상화란 무엇이고, 왜 알아야 하는 것일까요?
우리가 개발을 할 때는, 서비스 운영에 사용하는 서버에서 직접 하는 것이 아닙니다. Local 환경에서 개발하고, 완료되면 Staging 서버, Production 서버에 배포하게 되죠.
이 때 개발을 진행한 Local 환경과 Production 서버의 OS가 다르거나, OS가 같더라도 환경변수나 기타 설정이 일치하지 않는 경우 올바르게 작동하지 않을 수 있습니다. 이를 해결하는 방법으로 개발 설정들을 README에 기록하고 실행하는 방법이 있지만, 서버가 여러 개라면 매번 이를 반복하는 것도 쉬운 일이 아닙니다.
이런 고민을 해결하기 위해 나온 개념이 ‘가상화’입니다. 가상화는 하드웨어, 소프트웨어를 모두 포함하는 넓은 개념이지만, 소프트웨어 관점에서 보면 서버 환경까지 모두 한 번에 소프트웨어화하는 것이 가상화입니다. 즉, 특정 소프트웨어 환경을 만들고 Local, Production 서버에서 그대로 활용할 수 있습니다.
Docker가 등장하기 전
Docker가 등장하기 전에는 가상화 기술로 주로 VM(Virtual Machine)을 사용했었습니다. VM은 호스트 머신이라고 하는 실제 물리적인 컴퓨터 위에, OS를 포함한 가상화 소프트웨어를 두는 방식입니다. 그러나 이런 방식은 OS위에 다른 OS를 하나 더 실행시킨다는 점에서 굉장히 많은 리소스를 요구합니다(이를 ‘무겁다’라고 표현합니다).
대신에 가상화를 좀 더 경량화된 프로세스의 개념으로 만든 ‘Container’라는 것을 사용하면서, 가상화를 더 빠르고 가볍게 달성할 수 있게 되었습니다.
그리고 바로 이런 Container 기술을 쉽게 사용할 수 있도록 나온 도구가 바로 Docker입니다.
Docker 소개
Docker는 Container 기술을 쉽게 사용할 수 있도록 나온 도구이며, 2013년에 오픈소스로 등장하여 컨테이너에 기반한 개발과 운영을 매우 빠르게 확장할 수 있게 해주었습니다.
Container에 대한 감을 잡기가 조금 어렵다면, PC방의 경우를 떠올려보면 이해하기 쉽습니다. PC방에서 특정 게임만 설치하고, 고객이 특정 프로그램을 깔아도 재부팅할 때 항상 PC방에서 저장해둔 형태로 다시 복구됩니다. Docker를 사용하면 이렇게 특정 상태를 Docker Image로 만들어두고, 재부팅하면 Docker Image의 상태로 실행되도록 할 수 있습니다.
- Docker Image: 컨테이너를 실행할 때 사용할 수 있는 ‘템플릿’ (Read Only)
- Docker Container: Docker Image를 활용해 실행된 인스턴스 (Write Avaliable)
Docker로 할 수 있는 일
Docker를 사용하면 다른 사람이 만든 Docker Image(OS, 설정을 포함한 실행 환경)를 가져와 바로 사용할 수 있습니다. 예를 들어 MySQL, Jupyter Notebook, PyTorch 등을 다른 사람이 만든 소프트웨어를 가져와서 바로 사용할 수 있습니다.
또한 자신만의 이미지를 만들어 다른 사람에게 공유할 수 있고, 이 때 원격 저장소에 저장하여 이용합니다. 이 원격 저장소를 Container Registry라 하고, 회사에서 서비스를 배포할 때는 이렇게 원격 저장소에 이미지를 업로드하고, 서버에서 받아서 실행하는 식으로 진행합니다.
Docker 실습하며 배워보기
설치하고 실행하기
Docker를 설치하는 과정은 Linux냐 Windows/Mac이냐에 따라 다르고, Windows의 경우 Home이냐 Pro냐에 따라 다르기 때문에 인터넷에 설치법을 검색해서 설치하는 것을 추천드립니다. (저는 여기에서 했습니다)
설치 후, 터미널에서 docker 커맨드가 동작하는지 확인합니다. 여러 옵션과 관련한 내용들이 출력되면 잘 설치된 것입니다.
MySQL 실행하기
MySQL container image를 이용해 실습을 해보겠습니다.
-
docker pull "이미지 이름:태그"
- docker pul mysql:8로 mysql 8 버전의 이미지를 다운
-
docker images
- 다운받은 이미지 확인
-
docker run "이미지 이름:태그"
- 다운받은 MySQL 이미지 기반으로 Docker Container 만들고 실행
-
docker ps
- 실행 중인 컨테이너 확인
-
docker exec -it "컨테이너 이름(혹은 ID)" /bin/bash
- MySQL이 실행되고 있는지 확인하기 위해 컨테이너에 진입
- Compute Engine에서 SSH와 접속하는 것과 유사
-
mysql -u root -p
- MySQL 프로세스로 들어가면 MySQL 쉘 화면이 보임
-
docker ps -a
- 작동을 멈춘 컨테이너 확인
-
docker rm "컨테이너 이름(혹은 ID)"
- 멈춘 컨테이너를 삭제
- 뒤에 ‘-f’ 옵션 추가 시 실행 중인 컨테이너도 삭제 가능
정리
- docker pull “이미지 이름:태그” : 필요한 이미지 다운
- docker images :다운받은 이미지 목록 확인
- docker run “이미지 이름:태그” : 이미지를 기반으로 컨테이너 생성
- docker ps : 실행중인 컨테이너 목록 확인
- docker exec -it “컨테이너 이름(ID)” /bin/bash : 컨테이너에 진입
- docker stop “컨테이너 이름(ID)” : 실행중인 컨테이너를 중지
- docker rm “컨테이너 이름(ID)” : 중지된 컨테이너 삭제
Docker Image 만들기
여기서는 직접 간단한 FastAPI 애플리케이션을 실행하는 서버를 Docker Image로 생성해보겠습니다.
프로젝트 셋팅
먼저 폴더를 하나 만들고, 여기에 가상환경 세팅과 FastAPI 패키지를 설치합니다.
Fast API 코드 작성
GET /hello 로 요청하면, 메시지를 전달하는 간단한 코드를 작성합니다.
사용한 라이브러리 명시
pip freeze
: 설치한 라이브러리를 모두 보여줌- 또는 pip list –not-required –format=freeze: 의존성에 따라 설치된 라이브러리는 보이지 않음
pip로 설치한 라이브러리를 모두 requirements.txt에 저장
Dockerfile 작성
Dockerfile이라는 파일을 만들어 다음처럼 작성(Docker Image를 빌드하기 위한 정보가 담김)
FROM "이미지 이름:태그"
- 이미지 빌드에 사용할 베이스 이미지를 지정
- 베이스 이미지는 이미 만들어진 이미지
- 보통 처음부터 만들지 않고, 이미 공개된 이미지를 기반으로 새로운 설정을 추가
- python:3.8.7-slim-buster (이 이미지는 Dockerhub에 존재)
COPY "로컬 디렉토리(파일) "컨테이너 내 디렉토리(파일)
- 컨테이너는 자체적인 파일 시스템과 디렉토리를 가짐.
- COPY 명령어는 Dockerfile이 존재하는 걸로 기준 로컬 디렉토리를 컨테이너 내부의(자체 파일 시스템을 가진) 디렉토리로 복사
- 해당 코드는 프로젝트 최상위에 존재하는 모든 파일을 컨테이너 내부 /app 디렉토리로 복사
- 파일을 컨테이너에서 사용하려면 COPY 명령어로 반드시 복사해야 함
WORKDIR "컨테이너 내 디렉토리"
- Dockerfile의 RUN, CMD, ENTRYPOINT 등의 명령어를 실행할 컨테이너 경로 지정
- 이 라인 뒤에 등장하는 RUN, CMD는 컨테이너 내부의 /app 에서 실행
ENV "환경변수 이름=값"
- 컨테이너 내 환경변수를 지정
- 파이썬 애플리케이션의 경우 통상 위 두 값을 지정
RUN "실행할 리눅스 명령어"
- 컨테이너 내에서 리눅스 명령어를 실행
- 위의 경우 pip install pip와 -r requirements.txt 두 명령어를 실행. 한번에 실행할 명령어가 여러 개인 경우 && \로 이어줌
- 이전 라인에서 COPY와 WORKDIR이 실행되었기 때문에 컨테이너 내에 requirements.txt 이 존재하고, 이를 pip install -r 명령어로 실행시킬 수 있음
CMD ["실행할 명령어", "인자", ...]
- docker run으로 이 이미지를 기반으로 컨테이너를 만들 때, 실행할 명령어
- 이 이미지는 실행되는 즉시 python main.py를 실행하며 CMD는 띄어쓰기를 사용하지 않음
Docker Image Build
docker build "Dockerfile이 위치한 경로"
- 이미지 생성(빌드라고 표현)
- 아래 이미지에서 ‘.’는 현재 폴더에 Dockerfile이 있음을 의미
- -t “이미지 이름:태그” 옵션으로 이미지 이름과 태그를 지정할 수 있음
- 태그는 미지정시 ‘latest’로 채워짐
빌드된 이미지 확인
빌드를 마치면 docker image 명령어로 방금 빌드한 이미지를 확인합니다.
컨테이너 실행
docker run "이미지 이름:태그"
- 방금 만든 이미지를 실행
- 태그가 ‘latest’인 경우 생략 가능
다른 터미널을 열어 curl로 애플리케이션이 잘 작동하는지 확인할 수 있습니다.
정리
- 파이썬 환경 및 애플리케이션 코드를 작성
- Dockerfile 작성
- FROM으로 베이스 이미지를 지정
- COPY로 로컬 내 디렉토리 및 파일을 컨테이너 내부로 복
- WORKDIR로 RUN, CMD 등을 실행할 컨테이너 내 디렉토리 지정
- RUN으로 애플리케이션 실행에 필요한 여러 리눅스 명령어들을 실행
- CMD로 이미지 실행 시 바로 실행할 명령어를 지정
- 그 외에 Cockerfile에서 사용하는 것
- EXPOSE : 컨테이너 외부에 노출할 포트 지정
- ENTRYPOINT : 이미지를 컨테이너로 띄울 때 항상 실행하는 커맨드
- docker build “Dockerfile이 위치한 경로” -t “이미지 이름:태그” 으로 이미지 빌드
- docker run “이미지 이름:태그”로 빌드한 이미지를 실행
Leave a comment