약 2달 전 친한 친구들과 웹 개발을 시작한 이후로 지금까지 참 많은 일이 있었다. 군대 전역 후 웹에 대해서 아무것도 몰랐던 내가 네이버 클라우드 플랫폼을 이용해 서버를 구축하고, Django를 활용해 Web Application Server를 만들고, Nginx로 리버스 프록시 환경을 만들었으며, 프론트엔드와 백엔드를 각각 Docker image로 만들어 버전관리 및 배포를 자동화하고, 필요한 도메인별로 https를 위한 ssl 인증서를 자유자재로 발급받을 수 있게 될 줄은 정말 상상도 못했다.
물론 아직도 gunicorn과 worker에 대한 이해, 무중단 배포 및 서버 오류를 위한 로드 밸런싱과 관련된 설정들, 깔끔한 logging을 위한 log rotation, git branch 사용법, 각종 웹 서버 보안 등 부족하고 배워야할 것이 많은 것은 사실이다. 하지만 벌써 남들에게 자신있게 보여줘도 부끄럽지 않을 예쁜 사이트 하나를 완성했다는 것이 뿌듯할 따름이다.
그래서인지 내가 두 달 동안 공부하고 알게된 것들을 따로 정리해둬야겠다는 생각을 전부터 하고는 있었다. 하지만 시간과 체력 모두 부족했기에 실현하지 못하고 있다가, 이번 연휴를 통해 한번 쭉 정리해볼까 한다. 아직 계획일 뿐이긴 하지만 다음과 같은 주제들로 글을 쓰게 되지 않을까 싶다.
그래서 오늘은 1번 Docker를 쓰는 이유에 대해 간단하게 적어보겠다.
도커에 대해 위키백과는 다음과 같이 설명하고 있다.
도커는 리눅스의 응용 프로그램들을 프로세스 격리 기술들을 사용해 컨테이너로 실행하고 관리하는 오픈 소스 프로젝트이다 - 위키백과
설명만 들으면 감이 잘 안 올 수도 있지만 직접 사용해보면 저것보다 정확한 설명이 없다.
간단하게 내가 느낀대로 표현하자면, docker는 vmware같이 아예 다른 os를 여러개 사용할 수 있는 환경이다. 물론 vmware와는 전혀 다른 형태로 가상화가 이루어지기는 한다. qemu나 vmware들은 OS가 구동되는 하드웨어 레벨에서부터 가상화가 이루어지지만 Docker는 그보다 훨씬 가볍게 동작한다. 호스트의 리눅스 커널이 제공하는 기능에 의존하며 단순히 리소스들의 격리 공간만 따로 마련해기 때문이다. 그래서 속도가 생명이라고 할 수 있는 웹과 같은 분야에서도 충분히 사용할 수 있는 것이다.
위의 설명을 듣고 나면 Docker가 무엇인지 감이 올 수는 있지만, "그렇다고 굳이 써야돼?"라는 질문을 할 수 있다. 애초에 로컬 환경만 보더라도 8000번 포트를 사용하는 Django와 3000번 포트를 사용하는 React를 동시에 run하는 것이 전혀 어렵지 않고, 그렇다면 가상화를 사용해 리소스를 손해보는 것보다는 그냥 로컬에서 하는 것처럼 서버 환경을 맞춰 주는 것이 더 나아보일 수 있기 때문이다.
하지만 실제로 docker를 써보면 도커의 진짜 무기는 따로 있다는 사실을 깨닫게 된다.
Docker hub
git에 github이 있다면 docker에는 docker hub가 있다. 내가 만든 도커 이미지를 저장할 수도 있고, 남이 만들어놓은 도커 이미지를 다운받아서 쓸 수도 있다. 여기서 중요한 점은 그 '남'에 python이나 node, postgresql 등 웹 개발에 빠져서는 안될 것들도 포함된다는 것이다. 이로 인해 작업이 굉장히 편해지는데, 귀찮고 짜증나는 개발 환경 및 인프라의 버전 관리가 이미지의 tag를 확인하는 것 하나로 해결되기 때문이다. 예를 들어 내 로컬 개발 환경에서 python 3.9.1로 개발을 했고 서버에 python 3.10이 이미 깔려있을 경우, 원래라면 3.9.1을 따로 설치하거나 3.10에서 사용할 수 없는 모듈을 코드에서 바꿔준다거나 하는 추가 작업이 필요하지만, 도커를 사용하게 되면 단순히 python/python:3.9.1을 FROM해서 바로 이용할 수 있게 된다. 이러한 장점은 뒤에 나오는 장점들을 십분 활용할 수 있게 해주는 촉매 역할도 해준다.
docker는 기본적으로 컨테이너를 올리기 위해서 이미지가 필요하다. vmware로 생각하면 스냅샷 같은 건데, 격리된 공간에서 서버 구동을 위해 필요한 파일 및 설정들을 완료해 놓고 이미지로 만들어놓으면 단순히 실행시키는 것만으로 컨테이너가 서버의 역할을 하는 것이다. 이러한 형태의 배포판 구성은 물리적인 서버를 업그레이드해야할 때 빛을 발한다. 소규모의 프로젝트로 시작한 웹 개발이 예상보다 많은 접속자를 감당해야할 일이 생겼을 때, 퍼포먼스가 나빠지는 문제를 해결하기 위해서 더 좋은 컴퓨터를 쓰거나 더 비싼 클라우드 서버를 구매하게 될 수 있다. 이 때 도커를 쓰지 않았다면 개발 환경과 같은 인프라를 다시 설정해주어야 하는데 생각보다 귀찮고 짜증나는 경험일 것이다. 하지만 이전 서버에서 도커 이미지로 배포판들을 관리했다면 단순히 도커를 설치해주고 도커허브에 올라간 내 이미지를 다운받는 것만으로 그 모든 일을 끝낼 수 있다.
이 외에도 배포판을 도커 이미지로 만들어놓게 되면 위에서 언급한 python처럼 버전 관리를 할 수 있는데 이는 나중에 현 버전에 문제가 생겨 빠른 롤백이 필요할 때 큰 의미를 갖는다. 소스코드 관리에 git이 있다면 배포판 관리는 docker로 할 수 있게 되는 것이다.
React와 Django로만 서버를 올릴 거라면 사실 Docker Compose에 대해서 몰라도 상관이 없다. 하지만 nginx를 사용하는 컨테이너를 만들고, https 인증서를 발급받겠다며 certbot같은 컨테이너도 활용하고 하면서 한 번에 관리해야하는 docker 컨테이너가 많아지자 문제가 생겼다. 컨테이너들 사이에 네트워크도 설정해줘야 했으며 logging 및 중요파일 저장을 위한 volume등을 한 줄로 관리하려 했지에 docker commands가 점점 지저분해졌던 것이다.
다행히 docker에는 이런 상황을 해결할 수 있는 유용한 tool이 있는데, 그것이 바로 docker compose이다. .yaml(or .yml) 형식으로 docker 컨테이너들을 어떻게 관리할지 설정해줄 수 있고, docker-compose up 명령 한 번이면 설정한대로 모든 컨테이너가 실행되는 것이다. yaml 문법이 그렇게 어렵지도 않아 금방 배울 수 있고, 또 엄청나게 편하기 때문에 안 쓸 이유가 없다고 볼 수 있다.
이 외에도 여러 장점이 있겠지만, 위의 3개가 내가 도커를 사용하면서 느낀 가장 큰 장점들이었다. 이 3개만으로도 docker를 사용할 이유는 충분하다고 생각한다. 실제로 스타트업에서 개발자로 일해본 적 있는 친구에게 물어보았을 때도 "docker를 대체할 만한 게 아직 없다."라는 말을 들을 수 있었다. 나 스스로도 도커를 쓰면서 참 편하다는 생각을 많이 했었기에 만약 누군가 웹 개발을 하면서 하나의 물리 서버에 여러 애플리케이션을 구동하려고 하면서 문제를 겪고 있다고 하면, Docker를 써보는 게 어떻겠냐고 자신있게 추천해줄 것 같다.
다만 도커를 vmware와 비슷하게 생각하고 사용할 경우 자꾸 docker container가 exit (0) 되는 문제를 맞닥뜨리게 될 수도 있다. 이 문제로 꼬박 하루정도 고생한 적이 있는데, 이에 대해서는 나중에 한 번 따로 다뤄볼까 한다.
다음 포스트에서는 Django와 React가 어떻게 연동될 수 있는지 개발 초기에 했던 고민에 대해 이야기해볼 것이다.
2편 나오나용..?