Docker를 활용한 Singlepage 웹앱(WebApp) 구현 환경 구성하기

최근의 개발은 Single page 웹앱 형태로 웹 페이지를 개발하고 있다.  이전 회사에서는 웹앱이라는 개념도 제대로 몰랐는데… 장족의 발전이다.

웹앱 개발 방식이 개발자 관점에서 좋은 점은 Frontend와 Backend를 명백하게 구분할 수 있다는 점이다. 백엔드는 Business Logic을 중심으로 Restful API 방식으로 개발한다.  UI를 배제하고 로직에 집중할 수 있고, 테스트 케이스도 작성할 수 있기 때문에 제대로 개발한다라는 느낌을 준다.  근데 로직은 UI가 있어야지 표현되는 것이기 때문에 이것도 개발은 해야한다.

UI를 담당하는 Frontend는 HTML과 JS로만 구성된다.  예전처럼 PHP 혹은 JSP 같이 서버에서 상황에 따라 다른 컨텐츠를 내려줄 필요가 없다.  따라서 이런저런 복잡한 시스템은 필요없이 아파치 혹은 nginx 정도만으로도 충분히 개발할 수 있다.  딱봐도 쉬울 것 같은데 이렇게 썰을 길게 푸는건 개발 환경을 이야기하고 싶기 때문이다.  HTML과 JS로 코드를 짜면 되기 때문에 코딩을 위한 환경 자체는 쉽다.  하지만 작성한 코드를 눈으로 확인할려면 웹서버를 실행시켜야 한다.

로컬에 웹서버를 실행하는 방법이 가장 쉽게 떠오른다.  물론 가장 쉬운 방법이다.  하지만 여러 웹앱의 개발하는 경우를 생각하면 좀 귀찮아진다.

  • 테스트할 때마다 설치된 웹 서버의 Document Root를 바꿔줘야 하기 때문이다.
  • 물론 Configuration 파일 각 프로젝트별로 정의하면 된다.
  • 하지만 Configuration을 git repo에 함께 두기 애매하다. 개발하는 사람들별로 디렉토리 구성이나 이런 것들이 틀리기 때문이다.
  • 결국 이건 개발하는 사람들이 각자 잘 하는 수밖에는 없다.

이게 정답일까?  좀 더 쉽게 개발하고 배포할 수 있는 환경이 뭘까 싶어서 좀 고민을 해봤다.  최근에 Docker를 자주 사용하고 있기 때문에 이걸 활용하는 방안을 찾아봤다.  다음과 같은 접근 방법을 생각해봤다.

  • 로컬에 Docker 환경을 구성하고, Docker instance가 직접 로컬의 특정 디렉토리를 보도록 설정한다.  코딩을 하면서 변경하는 부분들은 Docker에서 바로 보고 이를 반영해줄 것이다.  HTML, CSS, JS는 따로 컴파일 할 필요가 없지 않은가?
  • 서버에 배포를 위해서는 Dockerfile을 이용해서 모든 리소스가 하나가 되도록 패키징한다.  그럼 이 안에 설정 및 컨텐츠 파일들이 모두 포함되기 때문에 이를 죽~ 배포하면 된다.

먼저 디렉토리 구조를 아래와 같이 잡았다고 가정해보자.

docker-directory-structure

이걸 바탕으로 로컬에서 간단히 Docker instance를 실행하는 방법은 아래와 같다.

$ docker run --name webapp -v $HOME/Workspace/projects/webapp/content:/usr/share/nginx/html:ro \
-v $HOME/Workspace/projects/webapp/conf:/etc/nginx:ro \
-v $HOME/Workspace/projects/webapp/logs:/var/log/webapp \
-p 5050:80 -d nginx

docker 실행에서 각 파라미터에 대해 간단히 부연한다.

  • –name : 실행할 docker instance의 이름
  • -v : docker에 마운트할 설정 정보. local-path:docker-path 형식이며 :ro를 덧붙히면 docker-path는 readonly 디렉토리임을 알리는 지시자다.
  • -p : port mapping. -v 옵션과 마찬가지로 local-port:docker-port를 나타낸다.
  • -d : docker image의 이름을 나타낸다.  nginx를 웹앱용 웹서버로 사용한다. (설정이 간단해서 아파치보다 더 좋은 것 같다. ^^;)

여기에서 가장 핵심은 -v 옵션에 따라붙은 마운트 정보이다.  로컬에서 작업하는 각 파일들을 Docker에서 잘 볼 수 있도록 해당 디렉토리를 바인딩한다.  이렇게 설정된 Docker를 통해 브라우저를 통해 확인해보자.

http://localhost:port 라고 입력하면 되겠지? 물론 포트는 앞서 설정한 local-port를 입력하면 되겠지?  라고 생각해서 입력하면 찾을 수 없다라는 어이없는 메시지만 본다.  이거 뭘까???  문제는 Docker의 nginx 서버가 특정 IP Address에 Binding되어 있다는 점이다.  Docker가 바인딩한 IP를 확인하는 방법은 다음 명령을 통해 확인할 수 있다.

$ docker-machine ip default

출력 결과로 알려준 IP와 포트로 접속해보자.  만약 문제가 없다면 짜잔~ 하고 개발하던 내용을 확인할 수 있다.

안된다고?  그럼 문제를 진단할 때다.  가장 먼저 이게 실행중인지 여부를 확인하는게 우선이다.  실행 확인은 다음 명령을 이용하면 된다.

$ docker ps

그런데 나오질 않는다고? docker ps 명령으로 목록이 나타나지 않는 이유는 docker에서 실행될 프로세스가 죽어버렸기 때문이다. nginx가 죽는 이유는 딱 하나. 바로 nginx configuration에 문제가 있기 때문이다. 이전에 설치가 제대로 되기나 한건지를 먼저 확인할려면 docker ps -a 명령을 이용하면 된다. 우리는 개발자이니까 먼저 로그를 확인해야겠지?

$ docker logs webapp

결과를 보면 시스템에서 출력해주는 웹 엑세스 로그 내용을 확인해볼 수 있다.  만약 nginx 설정에 오류가 있는 경우에는 로그 내용 잠깐 살펴보면 바로 문제를 파악할 수 있다.

개발을 다 마무리했다면 이제 배포를 준비할 때다.  배포를 위해서 Dockerfile을 하나 작성하면 된다.

FROM nginx
COPY content /usr/share/nginx/html
COPY conf /etc/nginx

설정의 구성은 간단하다.

  • nginx의 기본 설정은 Linux 기준으로 /usr/share/nginx/html을 Document Root로 지정한다. (물론 설정 파일에서 이를 변경할 수도 있지만.)  해당 디렉토리에 프로젝트에서 작업한 파일을 복사해넣으면 된다.
  • 별도의 설정 변경이 있는 경우에 해당 설정을 /etc/nginx 디렉토리에 넣으면 된다.

물론 엑세스 로그등을 별도로 봐야할 필요성이 있다면 이런 설정을 추가할 수 있다. (단순 웹앱이기 때문에 이럴 필요성이 있을까 싶긴 하지만…)