[Docker] 스토리지와 볼륨(컨테이너의 Stateless 와 Mount)

yoonthegarden·2024년 5월 27일
0

Docker

목록 보기
8/9
post-custom-banner

Part7. 스토리지와 볼륨

컨테이너의 상태(State)

  • 컨테이너는 상태 없음(Stateless) 이다. 컨테이너가 실행된 후 발생하는 모든 변경 사항은 컨테이너 레이어에만 있으며 컨테이너가 종료되면 변경 사항이 모두 사라진다.
  • 컨테이너는 Stateless하기 때문에 쉽게 개수를 증가시킬 수 있고, 다른 환경에서도 빠르게 배포할 수 있다.
  • 소프트웨어의 버전 등 컨테이너의 상태 변경이 필요한 경우 새로운 버전의 이미지를 만들어서 배포한다.
  • 컨테이너는 상태가 없기 때문에 여러 대의 컨테이너를 여러 곳에 빠르게 배포할 수 있다.

이미지는 읽기 전용 레이어이고, 이미지 실행 시 읽기 쓰기 레이어인 컨테이너가 추가된다. 컨테이너가 실행된 뒤 발생하는 모든 변경 사항은 추가된 컨테이너에 쌓이게 된다.
컨테이너가 삭제될 경우 컨테이너 레이어도 삭제된다.
기존 컨테이너를 실행 중인 상태에서 이미지를 변경할 경우도 실행 중인 컨테이너를 삭제하고, 다시 실행시켜야 한다.

→ 컨테이너를 실행할 때 한 번 지정한 이미지는 변경할 수 없고, 변경 사항이 적용된 새로운 이미지를 통해 새로운 버전의 컨테이너를 실행해야 한다.
컨테이너 자체는 상태를 가지지 않고, 모든 상태는 이미지에 기록된다.
→ 이미지에 컨테이너 레이어만 추가하면 바로 컨테이너를 실행시킬 수 있어서 컨테이너의 개수가 늘어나는 것이 작은 공간만 차지하며, 실행 속도가 빨라진다.
→ 트래픽이 증가해도 유연하게 대처할 수 있다.

Pet & Cattle

클라우드 네이티브 구조에서 서버를 다루는 방법론

  • 클라우드 네이티브 환경에서는 MSA 아키텍처에 따라 서버의 개수가 매우 많아진다.
    → 모던 애플리케이션의 요구사항을 충족시키기 위해 서버를 바라보는 관점도(서버 관리 방법론) 변화했다.

  • 전통적인 서버 방법론은 서버 한 대를 중요하게 생각하는 Pet 방식이다.
    → 서버 한 대, 한 대를 소중하게 케어한다.(직접 관리)
    → 서버에 문제가 생기거나 종료되는 것은 서비스의 장애라 인식해 서버의 상태를 주시하고 서버를 관리한다.

  • 컨테이너를 활용한 서버 방법론은 Cattle 방식이다.
    → 서버를 빠르게 교체할 수 있으며 서버의 상태를 최대한 제거한다.
    → 서버는 소모품이며, 서버 문제는 가능할 수 있기에 종료 시 새로운 서버를 빠르게 실행시켜 기존 서버를 대체한다.
    → 빠르게 서버를 늘리거나, 새 서버로 대체 시키려면 서버가 stateless 해야한다.

→ Cattle에서 사용하는 외부 마운트가 바로 도커 볼륨


실습

mkdir index && cd index → index 폴더 만들고 이동

echo Hello Volume! > index.html → index.html 파일 생성

cat index.html , ls → 파일 확인

docker run -d --name my-nginx nginx → nginx 컨테이너 실행

docker cp index.html my-nginx:usr/share/nginx/html/index.html → 실습 폴더의 index.html 파일을 my-nginx 컨테이너로 복사

→ my-nginx 파일은 새로 작성한 index.html 파일로 대체되었을 것

docker rm -f my-nginx → 실습용 컨테이너 삭제

docker run -d --name my-nginx nginx → nginx 컨테이너 실행

docker cp my-nginx:usr/share/nginx/html/index.html indexfromcontainer.html → 재생성된 my-nginx 컨테이너의 index.html 파일을 실습폴더의 → 재생성된 my-nginx 컨테이너의 index.html 파일을 로 복사

cat indexfromcontainer.html → 파일 확인

→Hello Volume이 아닌 default 내용을 확인할 수 있다.

  1. 컨테이너의 아이디도 다른 것을 확인할 수 있다.
  2. 컨테이너 삭제 시점엔 컨테이너가 가지고 있는 컨테이너의 모든 내용은 제거된다.
  3. 제거 후 다시 실행하면 기존 nginx 이미지 위에 새로운 읽기쓰기 레이어인 컨테이너 레이어가 추가된다.

→ 컨테이너는 stateless 하기 때문에 삭제된다는 것은 그동안 가진 컨테이너의 모든 변경사항을 잃어버린다는 것을 의미한다.
→ 실행한다는 것은 이미지에 저장된 상태를 그대로 출발한다는 것을 의미한다.

컨테이너의 Stateless

  • 컨테이너의 이미지는 한 번 지정된 후 변경되지 않는다. (불변성, Immutability)
    → 새로운 설정이나 패치가 필요한 경우 새로운 이미지를 만들어야 한다.
  • 컨테이너는 언제든지 새로운 컨테이너로 대체할 수 있다.
    → 컨테이너는 이미지 기반으로 실행되고, 실제 상태는 이미지에 저장되어 있기 때문에 컨테이너를 실행하고 종료하는 것이 자유롭다.
  • 컨테이너는 어떤 호스트에서든 컨테이너를 실행할 수 있다.
    → 호스트는 배포되는 환경을 의미한다. 개발, QA, 운영 서버 처럼 하나의 애플리케이션이 배포되는 여러가지 환경을 호스트라 할 수 있다.
    → 즉, 이미지만 있으면 환경의 제약없이 컨테이너를 실행할 수 있다.
  • 컨테이너는 동일한 컨테이너를 여러 개 쉽게 생성해서 트래픽에 대응할 수 있다.
  • 장애가 발생한 경우 새로운 컨테이너를 빠르게 시작할 수 있다.

컨테이너의 Stateless 제약

  • 데이터를 영구적으로 저장하기 위해서는 데이터베이스 서버 사용이 필수이다.
    → 상태가 없기 때문에 저장 및 공유가 필요한 데이터는 무조건 외부에 저장해야 한다.
  • 사용자 세션 정보나 캐시 같은 정보를 캐시 서버나 쿠키를 통해 관리한다. 파일이나 메모리에 저장하지 않아야 한다.
  • 동일한 요청은 항상 동일한 결과를 제공해야한다. 서버마다 다른 응답을 제공하면 안된다.
  • 환경 변수나 구성 파일을 통해 설정을 외부에서 주입할 수 있어야 한다.
    → 컨테이너를 구성할 때 컨테이너를 실행하는 시점에서 메타데이터의 값을 조정하면서 환경에 맞게 컨테이너를 구성할 수 있다. 이런 방식을 통해 이미지는 하나로 유지하면서 다양한 환경에서 이 이미지를 컨테이너로 활용할 수 있다.

도커 볼륨(Docker Volume)

컨테이너의 영속성(Persistence)

  • 컨테이너가 삭제되거나 재생성될 경우 컨테이너레이어가 초기화된다.
  • but 서버를 운영하다보면 데이터를 유지해야하는 경우가 있고, 이것은 IT 환경에서는 영속성이 있다고 한다.
  • 컨테이너 환경에서는 같은 서버의 대수가 여러 개 존재한다. (서버가 이중화되어 있다.) → 트래픽이 증가할 때 마다 컨테이너의 대수 증가로 트래픽을 처리한다.

DB이미지로 실행된 컨테이너 1,2,3이 있고, 클라이언트의 요청이 로드밸런싱이라는 네트워크 처리를 거쳐서 데이터베이스 1,2,3 컨테이너에게 전달된다.

로드밸런싱은 한 서비스의 트래픽을 여러 대의 서버로 분산해주는 네트워크 기술이다. 여기서 A라는 상품의 금액을 여러 번 조회하면 요청이 로드밸런싱 되어서 여러 개의 컨테이너에 상품조회 요청이 된다. 이때, 컨테이너마다 다르면 문제가 된다. 따라서 영속성이 필요한 데이터는 같은 종류의 모든 컨테이너가 함께 공유하고 있어야 한다.

도커는 영속성이 필요한 데이터를 위해서 도커 볼륨이라는 기능을 제공한다. 컨테이너 자체는 상태를 가지지 않지만 상태가 필요한 데이터는 외부 공유 저장소에 저장해둔다. 도커의 볼륨 기능을 사용하면 컨테이너가 데이터를 외부에 저장하고 다른 컨테이너들과 공유할 수 있다. 컨테이너의 모든 데이터를 저장하는 것이 아닌, 컨테이너의 특정 폴더를 공유용 폴더로 만들 수 있다.

이때, 컨테이너의 폴더를 볼륨에 마운트한다고 표현한다.

마운트 (Mount)

USB를 PC에 연결하면 새로운 드라이브가 만들어진다. 이를 사용해서, 데이터를 저장할 수 있고, 다른 PC와 공유할 수 있다.

USB는 물리적으로 연결하는 장치이고, 동일한 역할을 하는 것이 네트워크 파일시스템 NFS이다. NFS만 사용하면 네트워크에만 연결되어 있으면 USB와 동일하게 데이터를 외부에 저장할 수 있다.

한 번에 한대만 연결가능한 USB와 다르게 네트워크 파일 시스템에는 동시에 많은 PC를 연결할 수 있다.

NFS는 PC의 특정 폴더를 이 NFS에 마운트 시킬 수 있다. 스토리지의 종류에 따라 마운트되는 단위가 달라진다. 이렇게 연결할 때마다 새로운 드라이브가 추가되는 것처럼 드라이브 단위로 마운트가 될 수 있고, 특정한 디렉토리만 마운트 시킬 수도 있다.

마운트란?

  • 컴퓨터의 특정 디렉터리를 외부 저장소와 연결한다는 것을 말한다.

도커 볼륨은?

  • 컨테이너 실행 시 볼륨을 컨테이너의 내부 경로에 마운트할 수 있다.
  • USB처럼 데이터를 외부에 보관하는 기능을 제공한다.

컨테이너들은 도커 볼륨을 컨테이너의 특정 경로에 마운트해서 사용한다. DB 컨테이너를 실행하면, var/lib/postgresql/data에 실제 저장된다. 이 경로를 도커의 볼륨에 마운트한다고 하면, 컨테이너가 실행된 후 이 경로에 저장하는 파일들은 컨테이너 레이어에 저장되는 것이 아니라 마운트되어 있는 외부 볼륨에 저장된다.

여러 개의 컨테이너가 동일한 경로에 마운트(같은 볼륨)했을 경우 모두 동일한 데이터를 제공한다. 컨테이너가 삭제, 생성 되어도 볼륨의 데이터는 그대로 남아있기 때문에 데이터 영속성을 보장할 수 있다.

도커의 볼륨을 컨테이너의 디렉터리로 마운트해서 실행

docker run -v {도커의 볼륨명}:{컨테이너의 내부 경로}
docker run -v volume1:/var/lib/postgresql/data

  • 컨테이너가 삭제되어도 볼륨은 남아 있다.
  • 컨테이너가 실행 시 다시 마운트할 수 있다.
  • 하나의 컨테이너가 여러 개의 볼륨을 마운트(사용)할 수 있다. (하나의 컴퓨터에 여러개의 USB를 꽂을 수 있는 것)
  • 여러 개의 컨테이너가 하나의 볼륨을 공유할 수도 있다.

도커 볼륨을 마운트할 때 일반적으로 도커 볼륨의 이름을 지정한다. 이 볼륨의 Host OS의 데이터를 저장하는 경로를 volumes/볼륨이름 이다. 하지만 실제로 도커가 경로를 자동으로 관리하고, 도커가 실행되는 가상 머신 안에서 되기때문에 이 경로에 사용자가 직접 접근하기 어렵다.

Host OS에서 직접 데이터를 관찰하고 싶은 경우엔 Host OS의 경로를 직접 지정할 수 있는 Bind Mounts 기능을 사용하면 된다.

바인드 마운트

-v 마운트할 경로:컨테이너 내부 경로
-v /data/mypostgres:/var/lib/postgresql/data
  • Host OS에서 볼륨의 데이터에 더 쉽게 접근할 수 있다.
  • 볼륨이 별도로 만들어지지 않는다.
  • 볼륨을 통해서 관리하는 것이 좀 더 일반적이기 때문에 Bind Mounts 기능은 직접 디렉터리 내용을 관찰해야 하는 디버깅 같은 상황에서 활용 가능하다.

도커 볼륨 관련 명령어

볼륨 리스트 조회

docker volume ls

볼륨 상세 정보 조회

docker volume inspect 볼륨명

볼륨 생성

docker volume create 볼륨명

볼륨 삭제

docker volume rm 볼륨명

→ 컨테이너에 마운트되어 있는 볼륨은 삭제할 수 없다.

실습

  1. 데이터 저장 및 공유 Postgres

    • volume1 생성 후 PostgreSQL 컨테이너 실행하고, PostgreSQL 데이터 경로와 마운트 시킨다.
    • 데이터 삽입 후 PostgreSQL 컨테이너를 삭제한다.
    • 새로운 컨테이너 생성 시 기존 데이터 영역을 재활용할 수 있다.

    docker volume create mydata → 볼륨 생성

    docker volume ls → 볼륨 확인

    docker volume inspect mydata → 생성된 날짜, 볼륨 드라이버, 마운트 포인트와 이름 등.. 을 확인. Driver가 local이면 실제 데이터가 호스트 OS에 저장됨을 의미, Mountpoint는 저장되는 실제 경로이고, 리눅스에서 관찰 가능하다. (맥, 윈도우는 가상 머신형태로 실행되기 때문)

    docker run -d --name my-postgres -e POSTGRES_PASSWORD=password -v mvdata:/var/lib/postgresql/data postgres:13 → 볼륨을 마운트한 postgres 컨테이너 실행

    docker container inspect my-postgres → 컨테이너 상세 출력, Mounts에서 확인할 수 있음

    docker exec -it my-postgres psql -U postgres -c “CREATE DATABASE mydb;” → SQL문 실행으로 mydb(db server) 데이터 베이스 생성

    docker exec -it my-postgres psql -U postgres -c “\list” → DB 확인

    docker rm -f my-postgres → 컨테이너 삭제

    docker volume ls → 도커 볼륨 확인, 볼륨은 그대로 남아있음

    docker run -d --name my-postgres2 -e POSTGRES_PASSWORD=password -v mvdata:/var/lib/postgresql/data postgres:13 → 볼륨을 다시 마운트해서 postgres2 컨테이너 실행

    docker exec -it my-postgres2 psql -U postgres -c “\list” → DB 확인, mydb를 확인할 수 있음

    → 도커의 볼륨을 사용해서 컨테이너의 라이프사이클에 영향을 받지 않고 데이터의 영속성을 유지할 수 있다.

  1. Nginx index.html 공유 (바인드 마운트)

    • 호스트 OS의 디렉터리를 2개의 컨테이너가 마운트하여 공유한다.
    • nginxA에서 변경한 파일이 nginxB도 변경된다.
    • 바인드마운트는 별도의 볼륨이 만들어지지 않는다.
    • 호스트 OS에서 도커가 마운트한 경로를 직접 관찰하고 수정할 수 있다.

    mkdir index, cd index, pwd → index 폴더 생성 후 경로 확인

    docker run -d -p 8000:80 --name my-nginx-a -v {pwd결과경로}:/usr/share/nginx/html nginx → node.js 임시 컨테이너 실행

    docker run -d -p 8001:80 --name my-nginx-b -v {pwd결과경로}:/usr/share/nginx/html nginx → node.js 임시 컨테이너 실행

    docker volume ls → bind mounts 했기 때문에 실제 조회되는 볼륨 없음

    ls 하면 아무것도 없기 때문에 8000, 8001 접속 시 403에러

    echo Hello Volume! > index.html → 하면 두포트 접속시 해당 화면에 출력됨

    docker exec -it my-nginx-a /bin/bash → my-nginx-a 컨테이너 shell 접근

    컨테이너 셸에서 ls /usr/share/nginx/html → index.html 을 확인가능

    echo Bye Volume! > /usr/share/nginx/html/index.html 컨테이너 안에서 index.html 파일 덮어쓰기

    cat /usr/share/nginx/html/index.html → 변경된 것 확인

    exit으로 컨테이너 shell 나와서 cat index.html → 여기도 변경된 것을 확인

    → 8000, 8001 모두 변경된 것 확인

profile
https://garden-ying.tistory.com/
post-custom-banner

0개의 댓글