티스토리 뷰

간단 데일리 - 웹소켓 서버 분리

오늘 웹소켓 서버를 스프링 서버와 물리적으로 분리하였다. gitlab으로 소스코드를 관리하고 있고
빌드용 쉘 스크립트도 다 짜놓았기에 소스코드를 옮기고 보안그룹을 재설정해주는 정도에서 서버 분리 작업이 끝났다.
기존에 docker-compose를 사용해보고 싶어서 사용했었지만, 서버에 띄우는 컨테이너가 당장은 하나이고(이후 모니터링용 컨테이너가 몇 개 더 띄워질 예정이지만)
docker를 사용함에도 불구하고 git의 버전관리에 의존하는 상황에서
docker image를 만들어 immutable한 이미지로 관리하는 방향을 바꾸기 위해 dockerfile를 작성하게 되었다.

dockerfile

잘 쓰던 docker-compose를 dockerfile로 다시 바꾸겠다는 것은, 둘의 차이를 이해하고 dockerfile이 지금 상황에
더 적합하다고 생각한다는 것과 동일하다. 그냥 바꾸고 싶어서 바꾼 건... 디테일이 부족하다.
그러기 위해서는 각각을 잘 알아야한다고 생각한다. 때문에 우선 dockefile에 대해서 정리한다.

먼저 Dockerfile은 dockerfile에 작성된 instructions를 읽어서 이미지를 자동으로 빌드한다.
마치 CLI에서 쉘스크립트를 작성하여 여러 작업들을 자동화하는 것과 비슷하다.
dockerfile이 없다면 docker run을 하고 직접 컨테이너에 들어가서 필요한 작업(라이브러리 설치, 작업폴더 정리 등)을
해줘야할 것이다. 그럼 dockefile로 작성해서 이미지를 만드는 것은 어떤 이점이 있을까?

단순히 생각했을 때 먼저 생각나는 이점은 코드로 관리할 수 있으니 개발자의 실수를 줄이고 동일한 결과물을 낼 수 있다는 점이다.
어딘가에 명령어를 잔뜩 적어놓고 하나씩 복사-붙여넣기로 실행하는 것보다는 dockerfile로 작성해서 관리하는 것이 일관되고 빠르게 결과물을 낼 수 있을 것이다. 하지만 더 중요한 이점이 있다. 바로 이미지를 빌드하면서 전에 사용했던 레이어를 재사용(캐싱)한다는 점이다.

Images and Layers

Docker image는 컨테이너를 띄울 때 사용하는 것인데, 이미지는 read-only layer가 쌓여서 만들어진다(이 layer들 위에는 또 container layer라고, writable layer이다).
하나의 layer는 dockerfile의 하나의 instruction을 나타낸다고 할 수 있다.
그리고 그런 Layer들이 아래에서부터 차곡차곡 쌓이고 각각은 전의 layer의 변화가 반영되어있다.
Layer를 쌓으면서 Image를 만드는데 이때 전에 사용했던 layer와 동일한 layer라면 캐싱해서 재활용한다.
이렇게 Layer를 이용하면 여러 장점이 있다(이 장점들이 도커를 사용했을 떄 얻을 수 있는 큰 장점이라고 생각된다).
(Docker를 사용하면 분리된 가상공간을 가질 수 있다는 것도 장점이지만 이러한 장점들도 큰 비중을 차지하고 있다.)

  1. 디스크 용량을 절약할 수 있다.
    layer는 read-only이기 대문에 같은 layer는 여러 이미지들이 서로 돌려서 쓸 수 있다. 속도도 빨라지고 용량도 절약되니 꿩먹고... 알까지 먹을 수 있을지도?
  2. 이미지를 더 빠르게 만들 수 있다(빌드, 배포가 빨라짐)
    인터넷 환경에서 라이브러리를 다운 받는 등의 행위는 시간이 걸릴 수 있다. 하지만 Layer가 있다면 캐싱해서 빠르게 사용할 수 있다.
  3. Immutable한 환경을 구축할 수 있다.
    사실 3번을 말하려고 여기까지 빌드업을 하였다. read-only layer들로 이미지를 만들어서 어떤 환경에서도 동일한
    이미지를 구성할 수 있다는 것이 큰 장점이다. 같은 이미지, 같은 docker daemon만 있다면 동일한 배포 환경을 보장한다.

3가지 장점이 드러날 수 있는 예시를 생각해보자.

Dockerfile이 빛날 수 있는 상황

신입사원 성훈은 Nodejs 서버를 만들었고, 여러 서버에 같은 코드를 배포하고 구축해야하는 상황이다.
깃으로 코드를 관리하던 성훈은 서버 한대 한대마다 돌아다니면서 git clone, npm install, npm start 등을 반복수행해야 한다.
하지만 똑똑한 성훈은 이를 눈치채고 쉘스크립트를 작성하여 자동화하였다.
행복해하며 서버 한대한대마다 쉘스크립트를 놔주고 있던 와중... 아뿔싸. 모듈을 설치하던 중 npm이 무엇인가 오류를 뿜기 시작했다.(혹은 모듈을 설치하는 데에 너무 많은 시간이 걸림)
이미 여러 서버에 배포를 해서 전부 롤백하거나 어떻게든 문제를 해결해야 하지만 시간이 촉박하다.
그렇게 우여곡절 끝에 문제를 해결하고 배포를 마쳤지만 성훈의 소중한 하루는 그렇게 날아갔다.

사실 이런 문제의 궁극적 해결방법이 CI/CD의 자동화지만 일단 이게 없다고 생각했을 때, Docker가 좋은 해결 방법이 될 수 있다!
Dockerfile로 이미지를 만들면 다음과 같은 이점을 누릴 수 있다.

  1. 모듈 설치의 불안정성을 해결할 수 있음(시간, 인터넷 환경, OS환경 등)
  2. docker hub를 통한 빠르고 간편한 배포가 가능함
  3. 모든 서버가 동일한 구동 환경을 보장받을 수 있음

도커를 쓸 줄 몰라 인생의 절반을 손해봤던 성훈은, 도커를 공부하여 Immutable한 환경을 구축할 수 있게 되었고
전보다 안정적으로 서버를 배포할 수 있게 되었다.

대신 참고할 점은 Layer가 아래에서부터 쌓이다보니 중간에 layer가 변경되면 그 위로는 전부 새로운 layer로 쌓아야한다.
같은 instruction이라도 다른 layer로 취급된다(왜냐하면 각 layer는 이전 layer의 변경사항만을 담고 있으니).
그러니 좋은 Dockerfile을 작성하기 위해서는 변경사항이 적은 Instruction을 Dockefile 앞부분에 배치해야 한다.

Writable container

Writable container는 container layer라고도 하는데, read-only인 이미지 가장 위에 쌓이는 레이어라고 생각하면 좋다.
컨테이너가 구동 중일 때 컨테이너에 가해지는 모든 변경사항들(파일을 저장, 삭제, 추가 등)이 이 layer에 반영되고
해당 컨테이너가 삭제되면 이 container layer도 삭제된다.
이 container layer의 존재 덕분에 같은 이미지를 가지고 다른 데이터를 가진 여러 컨테이너를 띄울 수 있는 것이다.
또한 이런 특징을 살려서 여러 이미지들끼리 공유해야할 데이터가 있다면, 도커 볼륨이 이 데이터를 저장하고 각 컨테이너에 볼륨을 물려서 관리하면 좋다.

댓글