서론
처음 프로젝트를 시작하고 로그백을 통해서 rolling policy며 로그 저장 경로며 다 설정을 했으나, 막상 배포 환경의 로그를 확인하려니 로그가 저장되지 않고 있었다. 분명 배포 환경에서 테스트를 했을 때 테스트가 잘 되고 있었는데, 클라이언트가 테스트를 하면 간헐적으로 오류가 발생한다는 얘기를 듣게 되었다. 억울한 마음에 로그를 뒤져봤으나 저장이 안 되고 있었고… 원인은 다음과 같았다.
Github Actions를 통해서 CI/CD 자동화 파이프라인을 구축해 사용하고 있었는데, 매번 재배포시마다 기존의 컨테이너를 삭제하고 새로운 컨테이너를 띄우게 된다. 그러면 기존 컨테이너에 저장되던 로그들이 새로운 컨테이너가 올라갔을 때 모두 삭제되고 마는 것이다.
그렇다면 컨테이너 내부에서 저장시키던 로그를 계속 유지할 수 있는 어딘가로 옮겨야 하는 작업이 필요하다.
⇒ 그래서 마운트를 사용한다.
도커의 스토리지와 마운트
https://docs.docker.com/engine/storage/
마운트는 포탈과 비슷하다.
컨테이너의 파일 시스템 경로
를 계속 유지할 수 있는 어딘가의 파일 시스템 경로
에 붙여서 컨테이너가 내려가더라도 컨테이너 로그와 같은 파일들을 특정 경로에 보존할 수 있다. 스토리지 간 동기화인 것이다.
마운트 방식은 세 가지가 존재한다.
- Volumes
- 도커 데몬에 의해 관리되는 영속 스토리지이다. 백업이 쉽다는 장점이 있다.
{호스트의 home 경로}/{볼륨경로}
→ 호스트가 바뀌어도 볼륨 경로는 같다.
- Bind mounts
- 호스트의 디스크에 의해 관리된다. ****호스트에 종속적인 파일 시스템 경로를 가지며, 운영체제 종속적이므로 백업 및 복원이 어렵다.
- 바인드의 장점은 도커에 독립적이기 때문에 호스트와 도커 양쪽에서 해당 디렉토리에 접근하여 파일을 CRUD 할 수 있다는 점이다. 공식 문서에 따르면 호스트에서 non-docker process에 의해 파일 변경이 가능하다고 한다.
- tmpfs mounts
- 호스트의 디스크가 아닌 메모리 차원에서 관리된다. 그래서 컨테이너가 삭제되지 않고, stop만 되더라도 해당 내용들은 모두 날라간다. 보통 비영속적 상태의 대량 데이터를 임시 저장하기 위해서 사용된다.
나는 이 중에서 볼륨 마운트 방식을 선택했다.
왜냐면 도커에 의해서 관리되기 때문에 EC2 서버 인스턴스가 죽더라도 백업을 쉽게 할 수 있다는 장점 때문이었다.
Volume에 Container 마운트 하기
주의사항1: 볼륨의 생성과 삭제
- 볼륨 하나에 여러 개의 컨테이너를 마운트시킬 수 있다.
- 만약 익명 볼륨에 마운트를 하게 된다면, 컨테이너 생성 시마다 불필요하게 볼륨이 계속 생성되는 문제가 있을 수 있다.
- 그래서 named Volume을 미리 생성해두고, named Volume에 마운트를 하는 방식에서는 컨테이너 생성 시마다 볼륨이 생성되지 않는다.
- 또한 컨테이너 생성 시 볼륨에 대해서
—rm
옵션을 지정하게 되면, 컨테이너가 삭제될 때 볼륨이 함께 삭제되는 대참사가 일어날 수 있으니 주의하자…# 볼륨 정보 확인 docker volume inspect {볼륨명}
# 볼륨 생성 docker volume create {볼륨명} # 도커 계정의 모든 볼륨 조회 docker volume ls # 볼륨 삭제 docker volume rm {볼륨명}
- 도커 볼륨의 정보를 확인하면 다음과 같은 결과를 볼 수 있다.
MountPoint
가 바로 호스트의 파일 시스템 경로이다. 도커 볼륨에 마운트된 컨테이너 각각에는 사용자가 지정한 mount-path가 존재한다.- mount-path = 컨테이너 내부의 지정된 파일 시스템 경로 이다.
- 컨테이너의 mount-path(파일 시스템 경로)에 저장되는 모든 파일들이 볼륨의 MountPoint에 그대로 저장되는 것이다.
[ { "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/{볼륨명}/_data", "Name": "{볼륨명}", "Options": {}, "Scope": "local" } ]
주의사항 2: 마운트 시점
- 볼륨 마운트는 컨테이너가 처음 생성될 때만 가능하다. 컨테이너가 이미 실행 중일 때 볼륨을 마운트하는 것은 불가능하므로, 생성 시 -v 옵션 혹은 —mount 옵션을 통해서 볼륨을 마운트 해줘야 한다.
# 볼륨 마운트
docker run --mount type=volume,src={볼륨명},dst={mount-path}
docker run --volume {볼륨명}:{mount-path}
- 두 명령어는 동일한 기능을 하지만,
—mount
옵션이 더 명시적이며 마운트 세부 옵션들에 대한 설정을 지원한다. —volume
옵션은 볼륨명과 마운트 경로만 지정할 수 있다. 또한 이 옵션은-v
로 줄여쓸 수 있다.
주의사항3: 마운트 옵션 위치
- 컨테이너를 만들 때 옵션은 반드시 이미지 이름 앞에 위치해야 한다.
- 옵션을 이미지 이름 뒤에 위치시키는 경우 ⇒ 마운트 실패…
sudo docker run -it -d \ -p 8080:8080 --name {컨테이너명} \ ${{ secrets.DOCKERHUB_USERNAME }}/{이미지명} \ --mount source={볼륨명},target={mount-path}
- 옵션을 이미지 이름 앞에 위치시키는 경우 ⇒ 마운트 성공!
sudo docker run -it -d \ -p 8080:8080 --name {컨테이너명} \ -v {볼륨명}:{mount-path} \ ${{ secrets.DOCKERHUB_USERNAME }}/{이미지명}
마운트 확인
컨테이너에 볼륨이 정상적으로 마운트 되었는지 확인하기 위해서는 다음 명령어를 사용하면 된다.
# 컨테이너 정보 확인
docker inspect {컨테이너명}
그리고 Mounts
키에 해당하는 value를 확인하면, 어떤 컨테이너가 마운트 되었는지 리스트를 확인할 수 있다. Source
는 볼륨의 파일 시스템 경로, Destination
은 mount-path(컨테이너의 파일 시스템 경로)이다.
"Mounts": [
{
"Type": "volume",
"Name": "{볼륨명}",
"Source": "/var/lib/docker/volumes/{볼륨명}/_data",
"Destination": "{mount-path}",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],