Docker가 무엇인지, 왜 쓰는지 감을 잡는 데에 도움받은 영상
(저같은) 초보자 관점에서 서술합니다.
AWS E2C 인스턴스, RDS 생성을 했다는 가정 하에 서술합니다.
Docker란
도커는 컨테이너 가상화 시스템이다. 소프트웨어적으로 가상의 컴퓨터 시스템을 만드는 것.
도커는 각 요소(application)가 설치된 모습을 ‘image’라는 형태로 박제해서 저장한다. 박제한 image는 github에 push하는 것과 같은 원리로 dockerhub에 push해서 어디서든 pull해서 작업할 수 있다. 따라서 다른 팀원이 내가 push한 이미지를 끌어와서 본인 작업 공간에서 쓸 수 있다. 팀에서 github을 쓰는 방식과 같다.
Miniconda로 가상환경을 만들어서 그 안에서 작업했듯이 docker는 ‘container’라는 가상 공간을 만들어서 박제한 image를 이용해 그 가상공간에 각 요소를 설치한다. Miniconda에서도 다른 가상환경을 생성해서 이동하면 그 전 공간에 설치했던 프로그램이 없듯이 도커 컨테이너도 마찬가지다. 각 컨테이너는 독립적으로 돌아간다.
Virtual Machine(VM)과 Container 가상화 차이점
Virtual Machine 가상화 특징
- 하드웨어 스펙을 정하고 하드웨어 가상화
- 가상 하드웨어에 OS 설치
- 한 번 쓰는 데에 시간이 오래 걸리는 게 단점
- 컴퓨터 한 대로 여러 대를 돌리는 것처럼 쓸 수 있기 때문에 비용 절감 차원에서 사용
- 일단 플레이어를 만든 후 테이프/CD를 꽂아서 플레이 하는 것과 같은 원리
Container 가상화 특징
- 컨테이너 기반 가상화 서비스
- 동일한 OS 상에서 독립된 공간을 생성
- 하드웨어 가상화보다 가볍고 빠름
- 플레이어를 만들지 않아도 원하는 테이프/CD를 바로 꽂아서 플레이할 수 있는 것과 같은 원리
VM 방식은 하드웨어 자체를 가상화하기 때문에 각 가상환경마다 OS가 독립적으로 운영된다. CPU가 필요한 OS나 서비스에 그때그때 할당될 수 있으므로 리소스를 효율적으로 사용할 수 있으나, 부팅 시간이 길고 리소스를 많이 차지한다는 단점이 있다.
Container 가상화 기술은 호스트 서버 하나에 가상 공간을 여러 개 만드는 것으로 VM 보다 가볍고 빠르다. 클라우드 기반 서비스는 용량이 적을수록 비용을 아낄 수 있으므로 용량이 적은 container 가상화가 유리하다.
Docker 구조
- Docker client 와 Server(혹은 Docker engine)
Docker는 클라이언트가 서버에 명령을 전달하고 서버가 실행시키는 구조다. docker command는 HTTP라는 프로토콜을 이용하는 REST API이다. 예를 들어 docker ps는 docker server의 GET /api-version/containers 으로 HTTP 요청을 보낸 것과 동일한 방식이다. 출처 - Docker 이미지
위에서 언급했듯 도커는 각 application이 설치된 모습을 ‘image’라는 형태로 박제해서 저장한다. Docker container에서 실행시키고 싶은 application을 docker 이미지로 빌드해서 실행시킨다. - Docker registries
Docker registires는 docker 이미지를 저장하는 repository다. 소스 코드를 github에서 관리하듯 docker 이미지를 docker registries에 저장해 관리한다. (예 - Dockerhub) - Docker containers
Docker container는 도커 이미지를 실행하는 가상 공간이다. 컨테이너 하나에서 여러 프로세스를 실행할 수 있지만 하나만 실행하는 것을 권장한다.
Docker는 git처럼 적층형 구조다. 즉, 새로 업데이트 된 부분만 조각조각 쌓인다. 적층형 구조의 장점은 배포 시 기존 서버를 중단하지 않아도 된다는 점이다. CI/CD 서버가 중단되지 않고 실시간으로 배포할 수 있게 해주는 것이 도커다.
Docker 사용 흐름
- 기본 명령어
docker ps -a
컨테이너 전체 리스트 보기
docker images -a
이미지 전체 리스트 보기
sudo docker logs 컨테이너명
ssh에서 컨테이너 로그 보기
ps -ef | grep python
프로세스 조회. 여기서 pid 확인 가능
sudo kill pid번호
EC2 서버 종료
참고) -a
명령어는 실행 중인 것, 종료된 것까지 모두 보여준다.
- my_setting.py DB HOST 항목에 RDS 주소를 넣어준다.
- 장고 프로젝트 폴더(메인 폴더)에 Dockerfile 생성
vi Dockerfile
# FROM OS 이름
# 기반이 될 이미지 지정
# python 버전 3대 환경의 리눅스 운영체제로 지정
FROM python:3
# 작업 디렉토리(default)설정
# 홈 디렉토리와 같은 개념
# docker 이미지 파일 시스템 안에 리눅스가 담겨있고 그 안에 있는 디렉토리
WORKDIR /usr/src/app
# Install packages
# 현재 패키지 설치 정보를 도커 이미지에 복사
COPY requirements.txt ./
# 설치 정보를 읽어 들여서 패키지를 설치
# 장고 프로젝트 진행 시 requirements.txt에 설치할 프로그램을 적어두고 한 번에 설치하는 것과 같은 작업
RUN pip install -r requirements.txt
# Copy all src files
#현재경로에 존재하는 모든 소스파일을 이미지에 복사
COPY . .
# Run the application on the port 8080
# 8000번 포트를 외부에 개방하도록 설정
EXPOSE 8000
# CMD ["python", "./setup.py", "runserver", "--host=0.0.0.0", "-p 8080"]
# gunicorn을 사용해서 서버를 실행
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "DB이름.wsgi:application"]
참고) gunicorn은 서버를 백그라운드 프로세스로 구동하기 위해 사용한다. python manage.py runserver
명령어는 개발용이므로 실제 배포에는 사용하지 않는다.
- 이미지 빌드하기
docker build -t 도커허브계정명/프로젝트명:버전 .
예) docker build -t account/project:0.1.0 .
이 명령어를 실행하면 python과 requirements.txt에 저장한 application이 자동으로 설치된다.
- dockerhub에 빌드한 이미지를 push하기
# 도커 허브 계정 정보를 입력하고 로그인
docker login
# 도커 허브에 push
# 위에서 빌드한 버전과 동일하게 써준다.
docker push 도커허브아이디/프로젝트명:버전`
- ssh 접속
.pem 파일이 있는 곳에서 실행한다.
ssh -i 키이름.pem ubuntu@퍼블릭IP
퍼블릭 IP 주소는 AWS EC2 인스턴스 생성 후 확인할 수 있다.
- docker 설치
별도 OS이므로 도커를 다시 설치해준다. 아래 명령어를 한 줄씩 붙여넣어 실행한다.
sudo apt update
sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
sudo apt update
apt-cache policy docker-ce
sudo apt install docker-ce
docker
명령어를 입력해 정상 설치되었는지 확인한다.
- dockerhub에서 pull 해오기
sudo docker pull nanaon/zigbang:0.1.0
참고) 우분투 OS이므로 도커 명령어를 입력할 때 앞에 꼭 sudo
를 붙여야 한다.
- 빌드한 이미지 실행
sudo docker run --name 컨테이너명 -d -p 8000:8000 도커허브계정명/프로젝트명:버전
컨테이너 이름 지정은 필수가 아니다. 지정하지 않아도 docker에서 두 단어를 조합해 컨테이너 이름을 만들어준다. 단, 한 번 사용한 컨테이너 이름은 재사용할 수 없다.
-d
는 컨테이너를 백그라운드로 실행하는 옵션이다.
-p 8000:8000
은 port forwarding으로, 내 로컬 8000 포트와 도커 8000 포트를 매칭해준다.
만약 코드에 수정사항이 있다면 이미지 빌드 단계부터 다시 실행한다. 버전은 그때마다 올려주어야 한다. (예 - 0.1.0 -> 0.1.1)