이미지는 읽기 전용 레이어이고, 이미지 실행 시 읽기 쓰기 레이어인 컨테이너가 추가된다. 컨테이너가 실행된 뒤 발생하는 모든 변경 사항은 추가된 컨테이너에 쌓이게 된다.
컨테이너가 삭제될 경우 컨테이너 레이어도 삭제된다.
기존 컨테이너를 실행 중인 상태에서 이미지를 변경할 경우도 실행 중인 컨테이너를 삭제하고, 다시 실행시켜야 한다.
→ 컨테이너를 실행할 때 한 번 지정한 이미지는 변경할 수 없고, 변경 사항이 적용된 새로운 이미지를 통해 새로운 버전의 컨테이너를 실행해야 한다.
→ 컨테이너 자체는 상태를 가지지 않고, 모든 상태는 이미지에 기록된다.
→ 이미지에 컨테이너 레이어만 추가하면 바로 컨테이너를 실행시킬 수 있어서 컨테이너의 개수가 늘어나는 것이 작은 공간만 차지하며, 실행 속도가 빨라진다.
→ 트래픽이 증가해도 유연하게 대처할 수 있다.
클라우드 네이티브 구조에서 서버를 다루는 방법론
클라우드 네이티브 환경에서는 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 내용을 확인할 수 있다.
→ 컨테이너는 stateless 하기 때문에 삭제된다는 것은 그동안 가진 컨테이너의 모든 변경사항을 잃어버린다는 것을 의미한다.
→ 실행한다는 것은 이미지에 저장된 상태를 그대로 출발한다는 것을 의미한다.
DB이미지로 실행된 컨테이너 1,2,3이 있고, 클라이언트의 요청이 로드밸런싱이라는 네트워크 처리를 거쳐서 데이터베이스 1,2,3 컨테이너에게 전달된다.
로드밸런싱은 한 서비스의 트래픽을 여러 대의 서버로 분산해주는 네트워크 기술이다. 여기서 A라는 상품의 금액을 여러 번 조회하면 요청이 로드밸런싱 되어서 여러 개의 컨테이너에 상품조회 요청이 된다. 이때, 컨테이너마다 다르면 문제가 된다. 따라서 영속성이 필요한 데이터는 같은 종류의 모든 컨테이너가 함께 공유하고 있어야 한다.
도커는 영속성이 필요한 데이터를 위해서 도커 볼륨이라는 기능을 제공한다. 컨테이너 자체는 상태를 가지지 않지만 상태가 필요한 데이터는 외부 공유 저장소에 저장해둔다. 도커의 볼륨 기능을 사용하면 컨테이너가 데이터를 외부에 저장하고 다른 컨테이너들과 공유할 수 있다. 컨테이너의 모든 데이터를 저장하는 것이 아닌, 컨테이너의 특정 폴더를 공유용 폴더로 만들 수 있다.
이때, 컨테이너의 폴더를 볼륨에 마운트한다고 표현한다.
USB를 PC에 연결하면 새로운 드라이브가 만들어진다. 이를 사용해서, 데이터를 저장할 수 있고, 다른 PC와 공유할 수 있다.
USB는 물리적으로 연결하는 장치이고, 동일한 역할을 하는 것이 네트워크 파일시스템 NFS이다. NFS만 사용하면 네트워크에만 연결되어 있으면 USB와 동일하게 데이터를 외부에 저장할 수 있다.
한 번에 한대만 연결가능한 USB와 다르게 네트워크 파일 시스템에는 동시에 많은 PC를 연결할 수 있다.
NFS는 PC의 특정 폴더를 이 NFS에 마운트 시킬 수 있다. 스토리지의 종류에 따라 마운트되는 단위가 달라진다. 이렇게 연결할 때마다 새로운 드라이브가 추가되는 것처럼 드라이브 단위로 마운트가 될 수 있고, 특정한 디렉토리만 마운트 시킬 수도 있다.
컨테이너들은 도커 볼륨을 컨테이너의 특정 경로에 마운트해서 사용한다. DB 컨테이너를 실행하면, var/lib/postgresql/data에 실제 저장된다. 이 경로를 도커의 볼륨에 마운트한다고 하면, 컨테이너가 실행된 후 이 경로에 저장하는 파일들은 컨테이너 레이어에 저장되는 것이 아니라 마운트되어 있는 외부 볼륨에 저장된다.
여러 개의 컨테이너가 동일한 경로에 마운트(같은 볼륨)했을 경우 모두 동일한 데이터를 제공한다. 컨테이너가 삭제, 생성 되어도 볼륨의 데이터는 그대로 남아있기 때문에 데이터 영속성을 보장할 수 있다.
도커의 볼륨을 컨테이너의 디렉터리로 마운트해서 실행
docker run -v {도커의 볼륨명}:{컨테이너의 내부 경로}
docker run -v volume1:/var/lib/postgresql/data
도커 볼륨을 마운트할 때 일반적으로 도커 볼륨의 이름을 지정한다. 이 볼륨의 Host OS의 데이터를 저장하는 경로를 volumes/볼륨이름 이다. 하지만 실제로 도커가 경로를 자동으로 관리하고, 도커가 실행되는 가상 머신 안에서 되기때문에 이 경로에 사용자가 직접 접근하기 어렵다.
Host OS에서 직접 데이터를 관찰하고 싶은 경우엔 Host OS의 경로를 직접 지정할 수 있는 Bind Mounts 기능을 사용하면 된다.
바인드 마운트
-v 마운트할 경로:컨테이너 내부 경로
-v /data/mypostgres:/var/lib/postgresql/data
볼륨 리스트 조회
docker volume ls
볼륨 상세 정보 조회
docker volume inspect 볼륨명
볼륨 생성
docker volume create 볼륨명
볼륨 삭제
docker volume rm 볼륨명
→ 컨테이너에 마운트되어 있는 볼륨은 삭제할 수 없다.
데이터 저장 및 공유 Postgres
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를 확인할 수 있음
→ 도커의 볼륨을 사용해서 컨테이너의 라이프사이클에 영향을 받지 않고 데이터의 영속성을 유지할 수 있다.
Nginx index.html 공유 (바인드 마운트)
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 모두 변경된 것 확인