[Docker] 컨테이너 상태 - Stateless
본 내용은 인프런의 데브위키님 강의 “개발자를 위한 쉬운 도커” 내용을 바탕으로 정리한 내용입니다.
컨테이너의 기본적인 특징은 stateless(상태없음)
하다.
컨테이너와 stateless를 이해하기 위해 우리 주변의 친숙한 예시로 살펴보자.
Stateful vs Stateless
우리가 좋아하는 게임을 생각해보자.
게임을 하다가 저장을 하면 캐릭터의 레벨, 아이템, 진행 상황 등이 모두 저장된다.
그래서 다음에 게임을 시작하면 저장된 상태에서 이어서 플레이할 수 있다.
이렇게 상태를 가지고 있는 것을 stateful
이라고 한다.
반면에 stateless
는 이런 상태를 저장하지 않는 것을 말한다.
예를 들어 계산기 앱을 생각해보자.
계산기는 이전에 어떤 계산을 했든 상관없이, 새로 실행할 때마다 깨끗한 상태에서 시작한다.
이전 계산 결과를 기억할 필요가 없기 때문이다.
웹사이트 서비스를 예로 들어보자.
갑자기 접속자가 많아져서 서버를 더 늘려야 하는 상황이 발생했다고 가정했을 때 stateful
서버라면
“이전 서버가 어떤 상태였지?”, “그 정보를 새 서버에도 똑같이 설정해야 하나?”, “사용자의 이전 정보는 어떻게 옮기지?”
이런 복잡한 고민들을 해야 한다.
하지만 stateless
컨테이너라면 마치 새로운 계산기를 켜는 것처럼 간단하다.
동일한 이미지로 새 컨테이너를 실행하기만 하면 된다. 이전 컨테이너의 상태를 고려할 필요가 없기 때문이다.
컨테이너의 구조
컨테이너는 읽기 전용 레이어(이미지 레이어)와 읽기-쓰기 레이어(컨테이너 레이어)로 구성된다.
읽기 전용 레이어인 이미지를 컨테이너로 실행시키면 읽기 쓰기 레이어인 컨테이너 레이어가 추가된다. 그리고 컨테이너가 실행된 다음에 발생하는 모든 변경 사항들은 이 컨테이너 레이어에 쌓이게 된다.
이후 컨테이너가 삭제되면 컨테이너의 레이어도 함께 사라진다. 컨테이너 레이어에서 쌓여왔던 모든 내용들이 사라지게 되는 것이다.
만약 컨테이너의 이미지 버전을 변경할 경우 실행 중인 컨테이너를 삭제하고 새로운 이미지로 실행시켜야 한다.
컨테이너를 실행할 때 한 번 지정한 이미지는 변경할 수 없다.
변경 사항이 적용되어 있는 새로운 이미지를 통해서 새로운 버전의 컨테이너를 실행해야 한다.
⊙ ⊙ ⊙
stateless 특징
상태를 가진다는 것은 개수가 많아질수록 이 하나하나의 경우의 수가 늘어난다는 것을 의미한다. 결국에는 하나하나를 따로 관리를 해야 한다는 것을 의미한다.
컨테이너는 스테이트리스 하기 때문에 빠르고 쉽게 개수를 증가시킬 수 있다. 운영 중인 서버 환경은 여러가지 이유로 자주 변경될 수 있다. 예를 들어서 Nginx 웹서버 같은 경우는 Nginx 서버의 설정이 바뀌거나 버전을 업그레이드해야 할 경우가 있고 개발자가 새로운 버전의 소스 코드를 배포해야 하는 경우도 있다.
전통적인 방식에는 이런 변경 사항들을 모두 실행 중인 서버에 직접 변경 사항을 업데이트했다. 서버에 접근한 다음에 기존 애플리케이션을 중지시키고 새로운 버전의 애플리케이션을 덮어쓰기한 다음에 다시 애플리케이션을 실행시키는 방식으로 말이다. 동일한 서버가 10대가 있으면 이 10대에 모두 같은 변경사항을 적용시켜야만 했다.
이렇게 각각의 서버에 변경사항을 따로 적용한다는 것은 서버 한 대 한 대마다 유일한 상태를 가진다는 것을 의미한다. 이 방식에서는 변경사항을 적용한 서버 10대가 모두 동일한 상태라는 것을 보장하기 어렵다. 그리고 실제 소프트웨어가 실행 중인 서버에서 변경사항을 적용해야 하기 때문에 자칫하면 장애로도 이어질 수 있어서 변경사항을 적용하는 것이 어려워진다. 결과적으로는 소프트웨어의 업데이트 주기가 늦어지게 된다.
하지만 컨테이너는 이미지라는 템플릿을 기반으로 동작하기 때문에 기존과는 다른 방식으로 동작한다. 컨테이너 자체는 상태를 가지지 않고, 모든 상태는 이미지에 기록된다. 그래서 애플리케이션의 소스나 라이브러리 버전이 업데이트 되는 것과 같은 변경 사항은 모두 새로운 버전의 이미지로 만들어야 한다.
예를 들어 Nginx의 버전을 업그레이드하는 경우 실행 중인 컨테이너에 접근해서 Nginx를 업그레이드하는 것이 아니라
아예 새로운 버전의 이미지를 만들어서 배포해야 한다. 이런 컨테이너의 스테이트리스한 특징으로 빠르고 쉽게 컨테이너 개수를 증가시킬 수 있다.
어떤 환경에서도 이미지만 있으면 배포가 가능해 진다.
애플리케이션 실행에 필요한 것은 모두 이미지에 저장되어 있기 때문에 이 이미지에 컨테이너 레이어만 추가하여 바로 컨테이너를 실행시킬 수 있다.
이는 트래픽이 갑자기 증가해도 컨테이너를 증가시킴으로써 더 유연하게 대처할 수 있게 된다.
- 확장성
- 필요할 때마다 새로운 컨테이너를 쉽고 빠르게 추가할 수 있습니다
- 마치 계산기 여러 개를 동시에 켜는 것처럼 간단합니다
- 안정성
- 한 컨테이너에 문제가 생겨도 다른 컨테이너는 영향을 받지 않습니다
- 문제가 생긴 컨테이너는 그냥 새것으로 교체하면 됩니다
- 유지보수 용이성
- 모든 컨테이너는 동일한 상태에서 시작하므로 예측 가능합니다
- 문제 해결이나 업데이트가 훨씬 쉬워집니다
⊙ ⊙ ⊙
클라우드 네이티브
클라우드 네이티브 구조에서 서버를 다루는 방법론인 펫(pet)
과 캐슬(cattle)
방식에 대해서 알아보자.
클라우드 네이티브 환경에서는 MSA 아키텍처로 개발이 이루어진다. 아키텍처 구조상 서버의 개수가 아주 많아 지게 되는데 이로 인해 서버를 바라보는 관점이 변화하게 된다.
펫(pet)
과 캐슬(cattle)
이라는 개념으로 서버를 바라보는 관점의 변화를 나타난다.
전통적인 서버 관리 방법론이 펫 방식이고, 컨테이너를 활용한 방식이 캐슬 방식이다.
펫(pet) 방식
펫은 가정에서 키우는 애완동물을 의미하고 캐슬은 목장에서 관리하는 가축을 의미한다.
전통적인 방식인 펫 방식은 서버 한 대를 소중하게 생각하기 때문에 서버 한 대 한 대를 직접 관리한다.
이 펫 방식에서 서버에 문제가 생기거나 서버가 종료되는 것은 서비스의 장애라고 여겨지게 된다.
그리고 펫 방식은 서버의 상태를 내부에 저장한다. 상태라는 것은 주로 OS나 라이브러리의 버전, 실행 중인 소프트웨어의 버전을 의미한다. 그래서 버전이 변경되거나 패치가 발생하면 이 변경 사항들을 적용하고 관리해야 하며 항상 서버의 상태를 주시해야 한다.
이런 펫 방식에서는 서버를 교체하기가 아주 어렵다. 서버에 그동안의 히스토리가 모두 쌓여 있기 때문이다.
캐슬(cattle) 방식
이에 반해서 캐슬 방식은 서버를 일종의 소모품이라고 생각한다.
서버가 에러가 발생하거나 서버가 갑자기 종료되는 것은 충분히 일어날 수 있다고 생각한다.
그래서 서버가 종료되면 새로운 서버를 빠르게 실행시켜서 기존 서버를 대체한다.
이렇게 빠르게 서버를 늘리거나 기존 서버를 새 서버로 대체 시키려면 서버가 상태리스(stateless)
해야 한다.
캐슬 방식은 기본적으로 상태가 없고 상태를 유지해야 할 데이터가 있으면 외부 마운트를 통해서 데이터를 저장한다. 컨테이너에 상태가 없기 때문에 이 컨테이너를 쉽게 교체할 수 있다. 변경 사항을 적용한 새로운 이미지만 만들어 실행하면 된다.
⊙ ⊙ ⊙
stateless의 제약
- 컨테이너는 상태가 없기 때문에 데이터를 영구적으로 저장하기 위해서는 별도의 데이터베이스 서버의 사용이 필수입니다.
-
또한 저장 및 공유가 필요한 데이터는 무조건 외부에 저장해야 한다.
- 사용자 세션 정보나 캐시 같은 정보는 캐시 서버나 사용자 브라우저의 쿠키를 통해 관리해야 한다.
-
애플리케이션 내부에 파일이나 메모리에 저장하지 않아야 한다.
- 동일한 요청은 항상 동일한 결과를 제공해야 한다.
-
트래픽 증가로 여러 대의 서버를 제공했을 때 서버마다 다른 응답을 제공하면 안된다.
- 환경 변수나 구성 파일을 통해 설정을 외부에서 주입할 수 있어야 한다.
- 이미지를 컨테이너로 실행할 때 환경 변수를 통해 성격이 다른 애플리케이션을 만들 수 있다.
- 즉 하나의 이미지가 다양한 환경에서 컨테이너의 이미지로 활용될 수 있다.
댓글남기기