Docker 로 쾌적한 개발환경 구축하기

Ruby on Rails 개발환경을 Docker로 옮겨보았습니다.

Share
Docker 로 쾌적한 개발환경 구축하기

개발자라면 입사 후, 제일 먼저 하는 일이 PC를 지급받고 개발환경을 세팅하는 일입니다.
특히, server-side program의 개발환경은 SDK뿐 아니라, 추가적인 package 들이 필요할 수도 있고, 데이터베이스, 웹서버 등이 추가로 요구됩니다.

또한 OS나 패키지 버전 이슈로 문제가 생길 수 있으니 최대한 실 서버 환경과 동일하게 맞추는 것이 중요하고, 실 서버의 변경이 있을 때 이를 잘 동기화하는 것까지도 신경 써야 합니다.
이런 생각을 하며 입사 후 개발환경을 정리하다 보면 아무 작업도 하지 못하는 하루, 이틀이 금방 지나버렸던 경험 다들 있을 거라고 생각합니다.
특히나 개발환경에 대한 문서가 없이 구전으로 내려오거나, 유지보수가 잘 안되어 설치 도중 여러 이슈를 마주치게 되는 경우 더욱 오랜 시간을 소요하게 됩니다.

마이리얼트립의 개발환경

마이리얼트립은 기본적으로 로컬환경으로 개발을 하고 있습니다. 재택근무가 가능한 마이리얼트립에서 모든개발자가 각자의 PC에 각각 통합개발환경을 가지고 있는 것은 매우 유용합니다. 이는 서비스 코드 뿐 아니라 서비스 작동에 필요한 대부분을 포함합니다.

그러나 마이리얼트립의 기술 스택에서 볼 수 있듯 서비스를 작동시키는데 필요한 요소가 매우 많기 때문에 하나하나 설치하고 업데이트 하는 것은 매우 비효율적이고 고통스러운 작업이 아닐 수 없습니다.

Virtual Machine

기존 마이리얼트립은 이러한 문제를 해결하기 위해 VMWare 와 Vagrant를 사용해서 구축해 둔 개발환경이 있었습니다. 저도 마찬가지로 처음 입사해서 Vagrant를 사용해서 환경설정을 마쳤는데, 하나의 가상머신에 Ruby on Rails, Node.js, PostgreSQL, MongoDB, Redis 등을 전부 가동하기 위해서 너무 큰 메모리를 차지하고 있었습니다.
가상머신은 기본적으로 자원을 동적으로 할당해 주지 않고, 고정적으로 할당해 두기 때문에 서버를 실행하기 위해서 큰 메모리를 점유하게 됩니다.
추가로 개발을 위해 IDE를 실행하고, 테스트를 위해 브라우저를 실행하고, 커뮤니케이션을 위해 메신저를 실행하면 개발용 노트북의 메모리 부족으로 종종 오류가 나기도 했습니다.

또한 패키지들의 설치, 버전 관리들을 셸 스크립트를 실행해서 설치하게 되어 있기 때문에 가시적이지 않았고, 만약 설치된 가상머신에 오류라도 생기면 가상머신 생성부터 설치까지 그 모든 과정을 다시 수행해야 하는 문제도 품고 있었습니다.

Docker for Development Environment

일반적으로 Docker를 개발환경에만 사용하기 위해 도입하려고 생각하지는 않을 것입니다.
하지만 Docker는 개발환경에서 일어날 수 있는 많은 문제를 해결해 줍니다.

도커는 Linux, Mac, Windows를 전부 지원하고 있기 때문에 어느 OS에서라도 Docker 와 Docker compose만 설치하면 더는 설치할 것은 없습니다.
또한 Docker container는 이미지 단위로 동작하기 때문에, 버전 변경이나 다른 의존성이 추가되었을 때 이미지만 추가하거나, 바꾸어주면 되기 때문에 실 서버와 동기를 맞추기도 쉽고, 유지보수 또한 편리합니다.
기본적으로 자원을 동적으로 할당해 주기 때문에 낭비되는 자원도 줄어듭니다.

오늘은, 실제로 Docker로 개발환경을 구축하기 위해서 어떤 작업을 해야 했는지 이야기해 보고, 이 과정에서 생겼던 다양한 이슈들과 저의 고민이 담긴 해결책에 대해 공유하고자 합니다.

Create the Base Image

제일 먼저 가장 기본이 될 Docker Image를 만들어야 합니다.
하나의 이미지만으로 개발환경을 구축할 수 있겠지만, 빌드 시간을 단축하기 위해 Base Image와 Service Image를 분리하였습니다. Base Image는 기본적으로 설치될 패키지들을 관리하며, Service Image는 소스 코드의 dependency 들을 관리합니다. Base Image는 마이리얼트립의 소스 코드나 의존성을 가지지 않기 때문에 public 하게 공유하여 다른 유사한 환경을 사용하는 개발자들에게 기여할 수도 있습니다.

마이리얼트립은 현재 Ruby on Rails + heroku 로 서비스되고 있습니다.
heroku 도 기본적으로 Ubuntu 를 기반으로 서비스 되고 있으니, base image 를 Ubuntu 로 설정했습니다. 이후 서버에 기본적으로 필요한 패키지들을 설치해 줍니다. 개발환경에서는 컨테이너에서 기타 유지관리에 필요한 유틸리티들을 추가로 설치해 주면 좋습니다.

base image Dockerfile 예

왜 rvm 을 안 쓰는지 의아해하실 분들이 있을 것 같습니다.
일단 docker의 기본 로그인 계정은 root 계정인데, rvm 은 root 계정에서 정상적으로 설치가 되지 않아서 문제가 발생합니다.
다른 다양한 방법을 통해서 rvm 을 설치할 수는 있겠지만, 버전별로 이미지를 만들어 관리하는 docker image의 특징과 rvm 은 맞지 않는다고 판단했고, 직접 루비를 소스 코드로 설치 하여 image별로 루비 버전을 관리하도록 구성했습니다.

Create the Service Image

서비스 이미지는 소스 코드가 직접 실행될 이미지입니다. 배포하는 이미지라고 한다면 소스 코드를 전부 COPY 한 후 빌드하도록 만들겠지만, 제가 만들 이미지는 dependency 만 이미지가 가지고 소스 코드는 로컬 디렉터리에서 sync 되는 이미지입니다. 이렇게 했을 때의 이점은 dependency의 변화가 없는 이상 이미지를 다시 빌드하지 않아도 된다는 점입니다.

Rails dependency를 설치하기 위해 .dockerignore 를 이용하여 Gemfile 을 제외한 모든 파일을 build 단계에서 무시하도록 하였습니다.

example of .dockerignore for rails dependencies

.dockerignore는 wildcard를 지원하기 때문에 Dockerfile 에서 일일이 하나씩 COPY 해 주지 않아도 간단하게 원하는 파일만 옮길 수 있습니다.

Docker-compose

Docker compose는 여러 Docker container들을 하나의 yaml 파일로 관리하게 도와줍니다.
docker compose를 이용하여 container 들을 실행하면, 하나의 network를 만들어 container 들을 묶고, 통신할 수 있게 되어 다양한 서비스를 붙이는 데에 매우 효과적입니다.
예를 들면, postgresql 서비스를 정의하면, docker compose network의 dns를통해 postgresql라는 도메인으로 해당 container에 접근할 수 있습니다.

서비스에서 특정 IP만 허용하는 옵션이 있을 때는, docker compose 의 network 옵션을 통해 container에 고정 IP를 발급하여 해결할 수 있습니다.

db data 등 consistency가 유지되어야 하는 데이터는 container 안에 데이터를 저장하면 container를 삭제하면 데이터도 삭제되기 때문에 volume 옵션을 통해 저장공간을 따로 지정해 주어야 합니다.
또한 같은 디렉터리를 공유해야 하는 경우도 (nginx public file serving 등) volume 설정을 이용하면 유용하게 사용할 수 있습니다.
로컬 디렉터리는 각 사용자 환경에 따라 다를 수 있으므로 고정적으로 사용하기보다는 .env 파일을 활용하면 docker-compose 파일을 수정하지 않고도 여러 환경을 지원할 수 있습니다.

Docker-Sync

열심히 docker-compose를 설정하고 컨테이너들을 실행하니 제가 만난 화면은 이런 오류들이었습니다.

보통의 리눅스 기반 환경에서는 위 정도의 내용으로 설정하면 구동에 큰 무리가 없이 작동됩니다.
하지만 windows/mac 환경에서 docker로 개발환경을 구축하기에는 치명적인 문제점이 있습니다. 바로 volume을 로컬에 bind 하면 file read/write에 매우 큰 속도 저하(일반적으로 약 60배가량)가 일어난다는 점입니다.
ruby on rails에서 자주 일어나는 file cache, view template rendering, rails asset pipeline compile 등 다양한 부분에서 치명적인 성능 문제를 일으키게 됩니다.

이 문제를 해결하기 위해서 docker for mac에서 지원하는 cache도 사용해 보았지만, 큰 개선을 보이지는 못했습니다.
여기서 해결책을 준 것이 바로 docker sync라는 third-party 프로그램이었습니다.
docker sync는 원하는 디렉터리를 container로 만들고 비동기적으로 sync를 해주며 이를 다른 container에서 mount 하여 사용하도록 제공하는 프로그램입니다.

이를 이용해서 해서 volume을 설정하고 나서, local volume에 견줄만한 read/write 속도를 얻을 수 있었습니다.

docker-sync 파일 예시

Debugging

ruby는 pry 라는 디버깅 툴이 있습니다. 이는 ruby를 실행시킨 콘솔에서 활성화되어 입력을 받을 수 있게 구성되는데, docker container를 실행하면 실행된 container에 대한 입/출력이 콘솔에 연결되지 않은 상태입니다.
이는, docker attach 라는 명령어를 통해서 해결할 수 있습니다.
docker-compose에 stdin_open 과 tty 옵션으로 container를 입력을 받을 수 있는 상태로 실행시킨 후 docker attach 를 통해 해당 container 에 콘솔을 붙이면 pry를 사용할 수 있는 환경이 완성됩니다.

docker-compose service 설정 예시

결론

처음 ruby on rails의 작동방식도 모르는 상태에서 docker를 사용해서 개발환경을 구축하려고 했을 때, 이렇게 많은 이슈가 있을 거라고 생각하지 못하고 뛰어들었습니다.
이 과정에서 docker로 개발환경을 구축하는 것이 과연 옳은 방법인가에 대한 고민도 재차 들었습니다.
하지만 container service를 사용하는 것은 시대의 흐름이고, 개발환경에서부터 이를 테스트하고, 익숙해지며 서비스 환경에도 빠르게 적용해 나갈 수 있는 발판을 마련했다고 생각합니다.
또한 더욱 단축된 개발환경 세팅 시간과 쾌적해진 메모리, 가시적인 유지보수 등으로 매우 편안해진 개발자들의 모습을 볼 수 있었습니다.

이 정도면 docker로 개발환경 구축하기, 하지 않을 이유가 있을까요?

쾌적한 환경에서 함께 마이리얼트립을 만들어가실 분들을 모시고 있습니다. 새로운 개발자는 언제나 환영입니다!

https://career.myrealtrip.com

Read more

우리가 찾는 '창업가처럼 일하는 사람': 신입 공개채용 설명회에서 나눈 이야기

우리가 찾는 '창업가처럼 일하는 사람': 신입 공개채용 설명회에서 나눈 이야기

마이리얼트립은 첫 신입 공개채용을 진행 중입니다. 지원자들이 회사와 일하는 방식을 더 가까이에서 알 수 있도록 온라인 채용설명회와 오프라인 밋업 '창업가에게 묻다'도 열었습니다. 밋업에는 이동건 대표가 직접 나와 회사와 공채를 소개하고, 지원을 고민하는 분들의 질문에 답했습니다. 두 자리에서 나눈 이야기를 정리했습니다. 신입 공개채용은 10월 11일까지 채용 페이지에서 지원할

By 마이리얼트립
마이리얼트립 2026 신입 공개채용 지원 가이드: 밋업 '창업가에게 묻다'에 오지 못했다면

마이리얼트립 2026 신입 공개채용 지원 가이드: 밋업 '창업가에게 묻다'에 오지 못했다면

마이리얼트립 2026 신입 공개채용 밋업 '창업가에게 묻다'가 10월 1일 저녁 마이리얼트립 오피스에서 열렸습니다. 지원을 고민하는 분들이 이동건 대표를 직접 만나 궁금한 것을 묻고 답을 듣는 자리였습니다. 필수 전형도 아니고, 주말도 아닌 평일 저녁이었는데도 많은 지원 희망자가 행사장을 채웠습니다. 전날 온라인 채용설명회를 보고 다시 찾아온 분도 있었습니다. 목요일

By 마이리얼트립
첫 커리어를 창업가처럼: 마이리얼트립 신입 두 사람의 20개월

첫 커리어를 창업가처럼: 마이리얼트립 신입 두 사람의 20개월

마이리얼트립은 '창업가처럼 일한다'를 정해진 역할에 경계를 두지 않고, 문제를 자신의 것으로 받아들여 결과를 내는 방식으로 정의합니다. 이번 신입 공개채용에서 찾는 사람도 이 방식으로 일할 사람입니다. 그렇다면 신입에게 창업가처럼 일한다는 건 실제로 어떤 모습일까요? 작년 초에 입사해 올해 2년 차인 두 분의 20개월을 따라가 봤습니다. 한 사람은 인턴

By 마이리얼트립
딱 내가 바라던 여행, LAFC 홈구장 곳곳에서의 특별한 경험

딱 내가 바라던 여행, LAFC 홈구장 곳곳에서의 특별한 경험

경기 시작 전 아직은 조용한 경기장. 관중석이 채워지기 전, 선수들이 그라운드로 나와 몸을 풉니다. 누군가는 그 모습을 관중석이 아니라 바로 앞에서 봤습니다. 선수들이 걸어 나오는 통로 앞, 숨소리가 들릴 만큼 가까운 자리였습니다. 몇 시간 뒤 함성으로 채워진 경기장 전광판에는 이들을 맞는 문구가 떴고, 경기가 끝난 뒤에는 선수에게 직접 사인을 받았습니다.

By 마이리얼트립