현재 파일 처리의 문제점
현재 서버는 파일을 직접 처리한다. 즉, InputStream으로 데이터를 읽고, OutputStream으로 쓰고 있다. 그냥 봤을 땐 문제가 없어 보이지만, 사용자의 요청이 증가하면 문제가 발생한다. 트래픽이 문제라면 그냥 서버를 다중화하면 되는 게 아닌가?라고 생각할 수 있다. 하지만, Spring 서버는 파일 처리만 하는 것이 아니라 다른 API에 대한 요청도 처리해야 한다. 이때 모든 스레드가 파일 처리를 하고 있으면 파일 업로드가 완료될 때까지 다른 요청들은 처리할 수 없게 되는 문제가 발생한다. 어떤 API의 요청이 0.1초 만에 끝나도 파일 업로드를 위해 스레드가 10초 동안 사용하지 못한다면 결국 간단한 요청도 오래 기다리거나 timeout이 발생하게 된다.
위 문제는 파일 처리용 서버와 다른 API를 처리하는 서버를 별도로 두면 간단하게 해결된다. 그렇다면 굳이 Spring을 사용할 필요가 없다고 생각했다. 파일처리만 하는 서버를 위해 수많은 기능이 들어간 Spring을 할 필요가 있을까?라는 생각이 들었다. 그래서 파일 처리는 어떻게 하는지 찾아보았고, ceph가 사용하기 좋아 보였다. 참고할 자료가 상대적으로 많았고, 상대적으로 간단히 구현이 가능해 보였다.
추가로 현재 서버는 파일 저장소가 사라지면 영영 읽을 수 없는 문제가 있었는데 ceph는 여러 저장소에 동일한 데이터를 복제하여 안정성을 높일 수 있었다.
ceph에 대해 잘 모르지만, 클라우드 저장소는 사용자가 저장한 파일을 최대한 안전하게 관리하는 것이 좋다고 생각했기 때문에 일단 진행했다.
그래서 중간에 잘못된 부분이 분명히 있을 텐데, 알려주시면 감사하겠습니다..!
Ceph
설치를 하기 전에 ceph가 무엇인지 간단하게 살펴보자.
잘 모르겠지만 외부와 소통을 할 수 있고, LIBRADOS라는 중간 다리를 거쳐 RADOS라는 곳에 데이터를 저장하는 것으로 보인다.
RADOS는 Reliable, Autonomous, Distributed Object Store라는 의미로 말 그대로 안정적이고 자율적이며 분산된 객체 저장소라는 뜻이다. OSD, Monitor, Manager 등이 올라가는 곳이고 ceph의 기반이 되는 클러스터이며 실제 데이터가 저장되는 곳이다. 왜냐하면 OSD에 데이터가 저장되기 때문이다.
LIBRADOS는 RADOS에 직접 접속할 수 있도록 허용한다. RADOS에 구성된 클러스터와 socket 통신을 한다. 그냥 저장소에 접근할 수 있는 API를 제공하는 것으로 이해했다.
RGW는 Rados Gateway로 클라이언트가 접근할 수 있는 게이트웨이로 이해했다. 우리는 RGW를 통해 LIBRADOS의 API를 호출하고 데이터를 관리할 수 있다. RGW는 REST 기반의 gateway이고 S3 호환이 되기 때문에 이를 통해 데이터를 저장할 것이다.
RBD는 블록 스토리지, CEPH FS는 파일 스토리지이다. 블록 스토리지는 고성능으로 알고 있는데, 그래서 DB나 가상머신에서 사용된다. 파일 스토리지는 파일 계층 구조를 유지하며 관리하는 것으로 알고 있다. 하지만 계층 구조는 DB에서 논리적으로 관리하고 데이터는 수평적으로 저장할 생각이기 때문에 나에게는 필요 없다고 생각했다. 보통 이런 파일 스토리지는 NFS에 적합한 것으로 알고 있다.
OSD (Object Storage Daemon)
말 그대로 객체 저장소 역할을 한다. 디스크에 데이터를 저장하며 하나의 디스크에 하나의 OSD가 할당되는 개념이다. 클러스터를 구성해서 데이터를 보다 안전하게 보존할 수 있으며 각 object에 대한 저장소 연결을 직접 수행한다. 클러스터를 구성하면 heartbeat를 통해 Monitor에 상태를 주고받는다.
MON(Monitor)
모니터를 중심으로 클러스터가 구성되는 것으로 이해했다. 모니터에 모든 RADOS 구성 요소들이 상태를 주고받게 되고 전체적인 상태를 모니터링할 수 있다. 각종 map의 상태를 유지한다. 객체 저장을 하면 어디에 저장되었는지, 어떤 OSD에 저장을 해야 하는지 등을 map 형태의 자료구조로 관리하고 있는 것으로 보인다. 정리하자면 여러 클러스터 구성 요소들에 대해 상태를 체크하며 어디에 데이터를 저장할지, 저장을 했다면 어디에 있는지 등을 체크하여 요청이 발생하면 이러한 정보를 제공하는 것이다.
컨트롤 타워 역할을 하는 것으로 이해했다. 그래서 모니터도 다중화를 하던데, 나는 컴퓨터가 힘들어해서 하나의 모니터만 사용했다. 보통 3개 이상의 모니터를 사용할 것을 권장한다고 한다.
MGR(Manager)
MON이 관리하는 여러 상태들을 볼 수 있는 dashboard를 제공한다. 실시간 metric 정보를 취합해서 dashboard에 보여준다. prometheus와 같은 것도 연결해서 사용이 가능한 것으로 보인다.
RGW (Rados Gateway)
위에서 설명한 RGW이다. 여기까지 4종류의 요소를 활용해서 아주 간단하게 클러스터를 구성했다.
CRUSH (Controlled Replication Under Scalable Hashing)
저장된 object를 찾으려면 어떤 OSD에 접근해야 하는지 알아야 한다. 이를 알기 위해 사용하는 것이 CRUSH 알고리즘으로 데이터를 저장하고 검색하는 방법을 결정한다. 사실 자세하게는 이해를 못 했다.
CRUSH 소개
스토리지 클러스터에 대한 CRUSH맵은 CRUSH 계층 구조 내의 디바이스 위치와 CEPH가 데이터를 저장하는 방법을 판별하는 각 계층 구조에 대한 규칙을 설명합니다. CRUSH맵에는 하나 이상의 노드 및 리
www.ibm.com
2장. CRUSH 관리 | Red Hat Product Documentation
스토리지 클러스터의 CRUSH 맵은 CRUSH 계층 구조 내의 장치 위치와 Ceph가 데이터를 저장하는 방식을 결정하는 각 계층 구조에 대한 규칙을 설명합니다. CRUSH 맵에는 하나 이상의 노드 계층 구조가
docs.redhat.com
여러 특징과 왜 사용해야 하는지 설명을 하지만 사실 무슨 소리인지 잘 모르겠고 스토리지 장치 간에 데이터를 어떻게 저장하고 어떻게 찾을 것인지를 정의하는 알고리즘이라고만 이해하고 넘어갔다. 자세한 건 위 링크를 참고하면 좋을 것 같다.
PG (Placement Group)
논리적인 그룹인 pool이라는 것이 있는데, PG는 이런 풀의 하위 집합이다. ceph가 pool을 PG로 분할하고, 각 PG는 OSD에 랜덤으로 분배된다. PG수가 많으면 CPU와 메모리를 많이 사용해서 부담이 되고, 너무 적으면 한 번에 많은 데이터를 옮기며 네트워크 부하가 생겨 클러스터 전체적인 성능이 저하될 수 있다. 나 같은 경우 로컬에서 여러 컨테이너를 띄워서 진행하다 보니 리소스가 많이 부족했고 PG 수를 낮추는 방향으로 진행했다.
PG가 그럼 왜 필요하냐?라고 생각할 수 있는데, 각각의 객체를 찾기에는 그 양이 너무 방대하니 PG라는 보다 큰 그룹을 두어서 찾는 것으로 이해했다. MySQL의 innoDB도 인덱스도 해당 데이터가 있는 페이지를 빠르게 찾고, 그 내부에서 각각의 레코드를 더 빠르게 찾기 위해 레코드를 일정 단위로 묶어서 찾는다. 이와 유사하게 관리를 보다 쉽게 하고 빠르게 찾기 위한 방법으로 이해했다.
자세한 건 아래 링크를 참고해 보면 좋을 것 같다.
Chapter 2. The core Ceph components | Red Hat Product Documentation
FormatMulti-pageSingle-pageView full doc as PDF
docs.redhat.com
이해한 내용 도식화
여기까지 보고 이해한 요청의 흐름을 간단하게 그려보았다.
중간에 PG나 Pool이나 그런 복잡한 요소들이 더 있지만 복잡하니까 큰 틀은 위와 같이 동작하는 것 같다. 모니터는 요청을 주고받는 서버들과 모두 heartbeat를 통해 상태를 체크한다.
도커로 ceph 컨테이너 띄우기
이게 제일 힘들었다. 우선 ceph 공식 문서를 보면 cephadm을 사용해서 클러스터를 구성하는 것을 추천한다. 이때 조건은 cephadm과 docker, python이 설치되어 있어야 한다. 이때 cephadm은 리눅스 운영체제만 지원을 한다.
그렇다면 내 맥북에서는 도커 컨테이너 내부의 리눅스 환경에서 cephadm을 설치하고, 컨테이너 안에서 도커와 파이썬이 필요하다. 그래서 이 방법은 사용하지 않았다. 다만 이걸 시도하는 삽질을 했었다..
두 번째 방법은 쿠버네틱스를 활용하는 방법이다. 하지만 내 계획은 최소한의 컨테이너만 띄워서 클러스터를 구성하는 것이 목표였고, 굳이 쿠버네틱스를 사용할 필요는 느끼지 못했다.
그래서 수동으로 각각의 컨테이너를 전부 띄우고 하나씩 연결하는 방법을 사용했다.
우선 각 ceph 서버 간 heartbeat를 주고받으려면 네트워크 구성이 필요했다.
docker network create \\
--subnet=192.168.1.0/24 \\
ceph-net
그냥 대충 하나 만들고 핵심인 모니터부터 생성했다.
Monitor
docker run -d -it\\
--name ceph-mon \\
--hostname ceph-mon \\
--privileged \\
--net ceph-net \\
--ip 192.168.1.101 \\
-e CEPH_DAEMON=MON \\
-e MON_IP=192.168.1.101 \\
-e CEPH_PUBLIC_NETWORK=192.168.1.0/24 \\
-v /Users/seungh/Desktop/ceph/monitor/mon:/var/lib/ceph/mon \\
-v /Users/seungh/Desktop/ceph/monitor/config:/etc/ceph \\
--entrypoint "/bin/bash" \\
ceph/daemon:v6.0.4-stable-6.0-pacific-centos-8
참고로 이미지는 ceph/daemon을 사용했는데, ceph/ceph의 경우 cephadm이나 쿠버네틱스를 사용할 때 사용하는 이미지로 이해했다. 나는 직접 수동으로 배포할 생각이기 때문에 ceph/daemon 이미지를 사용했다.
CEPH_DAEMON을 MON으로 설정하면 Monitor로 실행을 한다.
볼륨 설정이 많은데, /var/lib/ceph 경로는 여러 데이터를 저장한다. 인증 관련 정보 등 중요한 정보를 저장하기 때문에 마운트를 하지 않으면 컨테이너를 재실행했을 때 처음부터 모든 컨테이너를 다시 실행해야 하는 대참사가 발생할 수 있다.
또 중요한 것이 /etc/ceph 경로에 있는 데이터인데, 여기에 부팅에 필요한 keyring 파일과, 설정 파일들이 포함된다.
생성해서 접속하면 ceph.conf 파일이 생성된 것을 볼 수 있는데, 필요한 설정을 추가하면 된다.
[global]
fsid = c92a50ae-62d0-4672-955b-0643c2d4a25f
mon initial members = ceph-mon
mon host = 192.168.1.101
public network = 192.168.1.0/24
cluster network = 192.168.1.0/24
osd journal size = 100
auth_cluster_required = cephx
auth_service_required = cephx
auth_client_required = cephx
log_file = /var/log/ceph/ceph.log
log_level = info
[osd.1]
host = ceph-osd1
[osd.2]
host = ceph-osd2
[osd.3]
host = ceph-osd3
이건 현재 사용하고 있는 최종 파일이고, 처음 생성하면 내가 컨테이너를 실행할 때 사용한 옵션을 바탕으로 osd journal size까지는 아마 생성되어 있을 것이다. 이후 필수적으로 필요한 내용이 auth_cluster_required, auth_service_required, auth_client_required에 대한 옵션인데, cephx라는 인증 방법을 사용한다는 것이다. keyring을 통해 모니터에 요청을 보내려면 해당 방식을 따라야 했다.
주의할 점은 파일의 맨 마지막 행을 항상 빈 상태로 만들어야 한다는 것이다. 맨 마지막 줄에 공백 없이 파일을 저장하면 ceph.conf 파일을 제대로 읽지 못한다.
모니터는 여기서 크게 더 작업할 것은 없고, 다른 ceph 서버를 띄울 때 모니터 서버에서 인증 정보를 생성하고, 인증 정보에 대한 keyring을 생성하여 다른 ceph 서버에 넘겨주면 된다.
Manager
우선 부팅용 keyring을 인증 정보로부터 생성하고 매니저 서버에 마운트 된 곳에 복붙을 한다.
ceph auth get client.bootstrap-mgr -o /etc/ceph/ceph.client.bootstrap-mgr.keyring
참고로 필수적인 파일들이 있는데, 모니터 서버에 있는 ceph.client.admin.keyring, ceph.conf 파일은 필수적으로 /etc/ceph 경로에 복붙을 해야 한다.
그럼 위와 같이 부팅 이후에 사용할 키링을 만들어서 이를 사용하여 통신을 진행한다. ceph-admin은 잘못 만든 거라서 무시해도 된다.
매니저를 사용하는 건 대시보드에서 상태를 편리하게 체크하기 위함이다. 그래서 대시보드를 활성화해야 한다. 대시보드의 경우 대시보드에 사용할 포트와 허용할 ip를 설정해야 한다.
[mgr]
mgr/dashboard/port = 8080
mgr/dashboard/server_addr = 0.0.0.0
위 정보를 매니저 서버의 ceph.conf에 추가해 준다.
이후 http로 접속하기 위해 ssl 비활성화와 인증 비활성화를 해준다.
ceph config set mgr mgr/dashboard/ssl false
ceph dashboard create-self-signed-cert
이후 대시보드 활성화를 해준다.
ceph mgr module disable dashboard
ceph mgr module enable dashboard
하나는 비활성화 명령어이다. 이후 아래 명령어를 입력했을 때 다음과 같은 결과가 나와야 한다.
ceph mgr services
그리고 내가 로컬의 11111번 포트를 매니저의 8080 포트로 포트 포워딩을 했기 때문에 localhost:11111로 접속하면 다음과 같은 화면이 나와야 한다.
하지만 우리는 계정이 없다. 이제 매니저 서버에서 계정을 만들어서 해당 계정으로 접속을 하자
ceph dashboard ac-user-create admin administrator -i password.txt
모든 계정 생성은 -i 옵션을 통해 파일로부터 읽어와야 한다. 파일을 만들어서 비밀번호를 작성하고 저장 후에 위와 같은 명령어로 계정을 생성하면 된다.
administrator의 경우 최고 권한 옵션을 의미한다. 다른 권한이 2개가 더 있다.
- operator
- ceph 클러스터의 상태를 모니터링하고 로그 및 데이터를 확인할 수 있는 권한을 부여한다.
- 하지만 클러스터를 변경하거나 설정을 수정할 수 없는 읽기 전용 권한이다.
- guest
- 클러스터에 대한 세부적인 정보를 확인하는 데 제한이 있다. 즉, 최소한의 읽기 권한만 가진다.
다음은 데이터 저장을 위한 OSD를 생성해야 한다.
OSD
도커에 대한 이해도 부족하고, OSD에 대한 이해도 부족해서 여기가 상당히 오래 걸렸다.
OSD는 결국 데이터 저장소이기 때문에 물리적으로 저장할 공간이 필요하다. 처음에는 그냥 컨테이너 띄워서 아무 곳이나 저장하면 되지 않나?라고 생각했다. 하지만 ceph가 사용하는 형태로 디스크를 포맷해야 하기 때문에 여기서 문제가 발생했다. 별도의 디스크 공간이 필요했고, 이를 마운트를 할 필요가 있었다. 그래서 나는 외부에서 디스크 이미지를 만들고, 해당 이미지를 컨테이너 내부에서 마운트를 하여 저장소로 사용했다.
위의 문제 때문에 모니터나 매니저처럼 도커 명령어로 간단히 실행되지가 않았다. 그래서 전부 수동으로 설정해야 했다.
우선 /etc/ceph에 마운트 할 경로에 모니터의 ceph.conf 파일과 ceph.client.admin.keyring 파일을 복붙 하자. 그리고 매너지에서 본 것처럼 부팅키 외에 자신의 고유 키링이 필요하다. 우선 모니터 서버에서 이것부터 생성하자.
ceph auth get-or-create osd.1 osd 'allow *' mon 'allow profile osd' -o /etc/ceph/ceph1.keyring
ceph auth get-or-create osd.2 osd 'allow *' mon 'allow profile osd' -o /etc/ceph/ceph2.keyring
ceph auth get-or-create osd.3 osd 'allow *' mon 'allow profile osd' -o /etc/ceph/ceph3.keyring
난 OSD 클러스터 구성을 위한 최소 개수인 3개를 사용할 것이기 때문에 키링도 3개를 생성했다.
위와 같은 결과가 나온다면 정상적으로 생성이 된 것이다. 그럼 각 서버에 마운트를 한 곳에 해당 아래와 같이 키링 파일을 복붙 하면 된다.
이건 개인 소통용 키링이기 때문에 부팅용 키링도 필요하다. 부팅용 키링도 추출하자.
ceph auth get client.bootstrap-osd -o /etc/ceph/ceph.client.bootstrap-osd.keyring
만약 이런 부팅용 인증 정보가 존재하지 않으면 이것도 일반 키링처럼 생성을 해야 한다. 생성한 부팅용 키링은 /etc/ceph 경로에 복붙을 하자
이후 아래와 같이 컨테이너를 띄우고 entrypoint를 /bin/bash로 설정한다.
docker run -d -it \\
--name ceph-osd1 \\
--hostname ceph-osd1 \\
--privileged \\
--net ceph-net \\
--ip 192.168.1.201 \\
-e CEPH_DAEMON=OSD \\
-e OSD_ID=1 \\
-v /Users/seungh/Desktop/ceph/osd1/osd:/var/lib/ceph/osd \\
-v /Users/seungh/Desktop/ceph/osd1/config:/etc/ceph \\
-v /Users/seungh/Desktop/ceph/osd1/keyring:/var/lib/ceph/bootstrap-osd \\
--entrypoint "/bin/bash" \\
ceph/daemon:v6.0.4-stable-6.0-pacific-centos-8
위와 같이 entrypoint를 설정하지 않으면 osd가 디스크 저장소를 찾지 못해 바로 다운되기 때문에 반드시 필요하다. 다른 컨테이너와 마찬가지로 OSD는 CEPH_DAEMON=OSD로 설정하면 OSD로 사용할 준비가 된다.
그리고 내부에서 사용할 디스크 이미지를 외부에서 생성해야 한다. 내부에서 만들어도 되지만 컨테이너 내부에서는 너무 느려서 난 외부에서 했다.
dd if=/dev/zero of=/var/lib/ceph/osd/osd1_disk_image.img bs=1M count=5120
얘도 사라지지 않게 볼륨 설정을 했는데 컨테이너 죽어서 포맷을 새로 하고 실행하고 이러면 큰 의미는 없었던 것 같다..
실제 내 맥북 디스크를 어느 정도 할당해도 되지만, 괜히 건드렸다가 대참사가 발생할 수 있다는 생각에 위와 같이 진행했다. 운영체제 수업에서 디스크 포맷하고 건드리다가 싹 다 날린 경험이 있어서 최대한 안전하게 진행했다. 사이즈의 경우 여유가 있으면 더 크게 해도 상관없다. 난 여유가 없어서 작게 만들었다.
이후 루프 디바이스 설정을 했다.
losetup /dev/loop1 /var/lib/ceph/osd/osd1_disk_image.img
위 설정은 파일을 블록 디바이스처럼 사용할 수 있도록 만들어주는 가상 블록 디바이스를 설정하는 것이다. 일반 파일을 디스크 파티션으로 다룰 수 있게 된다. 즉, 난 0으로 채워진 파일을 만들었고, 이를 디스크처럼 활용하기 위한 설정이다.
위 설정이 신기했던 게, OSD끼리 모니터를 통해 설정을 공유해서 그런지 losetup을 /dev/loop1로 통일하면 안 된다. 다른 OSD에 가면 저게 할당되어 있다고 나온다. 통신하는 다른 ceph 서버에도 이 설정이 전부 전파됐던 게 신기했다. 아마 상태를 공유해서 그런 것으로 추측된다
losetup -a
위 명령어를 입력하면 루프 디바이스로 연결된 리스트를 보여준다. 만약 잘못해서 삭제해야 한다면 아래와 같이 삭제 명령어를 입력하면 된다.
losetup -d /dev/loop1
그리고 여기서 처음에는 당연히 별도의 파일 시스템을 생성해야 하는 줄 알았다. 왜냐하면 ceph가 운영체제의 파일 시스템을 사용해서 데이터를 읽어오는 줄 알았는데, ceph에서 관리하기 위한 파일 시스템으로 초기화를 하고 사용하기 때문에 필요가 없었다.
위와 같은 형태로 구성되고, OSD는 bluestore, filestore라는 두 가지 저장소를 지원하는데, 내가 명시한 저장소 형태로 포맷을 하는 것 같다. 그리고 포맷팅 한 디스크에 접근이 가능하도록 가상 파일 시스템에 이걸 연결해 주는 과정이 있지 않을까?라는 생각이다.
이제 루프 디바이스를 실제로 내가 사용할 저장 경로에 마운트를 해주자
mount /dev/loop1 /var/lib/ceph/osd/ceph-1
마운트를 했다면 해당 경로를 사용해서 아래오 같이 OSD 초기화를 해준다.
ceph-osd --cluster ceph --id 1 --mkfs --keyring /var/lib/ceph/osd/ceph.keyring --osd-data /var/lib/ceph/osd/ceph-1 --osd-objectstore bluestore --log-to-stderr
참고로 위 명령어에서 사용한 ceph.keyring은 부팅용 키링이 아닌, 위에서 생성한 OSD 고유의 키링을 사용해야 한다.
—osd-data 옵션이 실제 데이터를 저장할 경로이다. —osd-objectstore는 OSD가 데이터를 저장하는 방식과 구조를 정의하는 것으로 ceph 최신 버전에서는 bluestore가 기본으로 설정된다.
—log-to-stderr은 실행 로그를 보기 위해 사용했다. 위 명령어를 통해 —mkfs 옵션으로 OSD에 필요한 형태로 디스크를 포맷하여 초기화를 진행한다. 초기화를 하면 모니터에 어떤 OSD가 초기화 됐는지 알리게 된다.
이제 진짜 끝났다. 실행을 하자
ceph-osd --cluster ceph --id 1 --keyring /var/lib/ceph/osd/ceph.keyring --osd-data /var/lib/ceph/osd/ceph-1 --osd-objectstore bluestore
위 과정을 반복하여 OSD 서버를 2대 더 띄우게 되면, 3대부터 헬스 체크를 자동으로 시작한다. osd pool list를 확인해 보면 없던 health check pool이 갑자기 생긴다.
참고로 나는 그냥 했는데, 찾아보니까 아래와 같은 방법이 정석인 것 같다.
사실 난 잘 안 돼서 내 방식대로 했는데, 혹시 UUID 관련 이슈가 있다면 위처럼 UUID 옵션을 넣어보는 것을 추천한다.
Monitor에서 Pool 설정
ceph osd pool create data_pool 8 8
ceph osd pool set data_pool size 2
data_pool 뒤의 숫자 옵션은 각각 pg_num, pgp_num의 수를 의미한다. 각각 placement group number, placement group for placement number의 준말이다. 위에서 말한 PG에 해당한다고 생각하면 된다.
pgp_num는 PG 데이터를 실제 OSD에 데이터를 배치할 때 실제 사용하는 PG의 개수를 의미한다. 클러스터 초기에는 pg_num과 pgp_num을 동일하게 설정해야 데이터가 제대로 분산되고, 클러스터를 늘릴 때 이 값들을 조정하여 점진적으로 분산되도록 하는 것으로 이해했다. 여하튼 pg_num과 pgp_num이 크면 결국 PG 수가 많아지고 cpu와 메모리 사용이 늘어난다. 생각 없이 256 256으로 설정했는데 컴퓨터가 죽어버려서 그냥 8로 설정했다.
data_pool size는 pool의 복제본 수를 얼마로 할 것인지 설정하는 것이다. 2라는 의미는 어떤 데이터가 저장될 때 2개를 저장할 것이고, 이는 별도의 OSD에 복제되어 각각 저장되는 것을 의미한다. 즉, 한 서버가 죽어도 다른 서버에서 내 데이터를 볼 수 있게 되는 것이다. 이 숫자를 늘리면 당연히 더 안전하겠지만, 복제하는 시간만큼의 오버헤드가 발생하기 때문에 더 느려진다.
생성 확인은 아래의 명령어를 사용한다.
ceph osd pool ls
여기까지 완료하면 아래와 같은 결과가 나와야 한다.
RGW
여기도 애먹은 구간이다. 다른 서버들은 대시보드에서 상세 정보가 보이는데 RGW만 보이지 않았고 , 결국은 해결은 못했다. 이거 해결해 보려고 시간을 너무 많이 썼다.. 하지만 굳이 상세 정보가 보이지 않더라도 작동은 잘 되었다.
docker run -d -it\\
--name ceph-rgw \\
--hostname ceph-rgw \\
--net ceph-net \\
--ip 192.168.1.210 \\
-e MON_IP=192.168.1.101 \\
-e CEPH_DAEMON=rgw \\
-v /Users/seungh/Desktop/ceph/rgw/config:/etc/ceph \\
-v /Users/seungh/Desktop/ceph/rgw/keyring:/var/lib/ceph/bootstrap-rgw \\
-v /Users/seungh/Desktop/ceph/rgw/radosgw:/var/lib/ceph/radosgw \\
-p 7480:7480 \\
ceph/daemon:v6.0.4-stable-6.0-pacific-centos-8 radosgw
RGW도 별도의 설정 없이 위와 같이 실행을 해준다. 대신 이전의 과정들처럼 볼륨 마운트를 한 곳에 필요한 키들은 전부 필요하다.
그러면 위와 같이 필요한 키링을 설정해서 실행까지 해준다.
정상적으로 실행하면 ceph -s라는 명령어를 입력했을 때 아래와 같이 실행한 모든 ceph 노드들이 보여야 한다.
RGW 실행을 이렇게 하면 귀찮은 점이 있다. 뭔가 문제가 생겨서 재실행할 때 이미 생성된 pool을 위처럼 전부 제거해야 한다는 점이다. 자동으로 생성해 주니 재실행 시 충돌이 나서 기존 정보를 전부 날려줘야 했다. 기억이 잘 안 나는데 osd와도 연결돼서 osd pool도 제거하고 osd 컨테이너도 다시 실행했던 것 같기도 하다..
추가로 RGW도 다중화를 하면 zone id, zone group 같은 것을 전부 따로 설정을 해야 하는 것으로 보이는데, 나는 그냥 실행해서 기본 설정인 default로 채워졌다. 아마 실제 서비스 제공 환경에서는 이런 것도 전부 신경을 써야 할 것으로 보인다..
여하튼 필요한 키링이 생성되었으니 대시보드 연결을 해보자.
아마 대시보드에 접속하면 위와 같은 화면을 볼 수 있다. 그래서 대시보드와 연결하는 과정이 필요하다.
우선 사용자를 생성해야 한다.
radosgw-admin user create --uid=adminUser --display-name="admin user" --email=seungh1024@naver.co --system
— system 옵션은 시스템 사용자로 계정을 생성한다는 의미이다. 즉, 관리자 역할이나 시스템 내부 작업을 위해 생성되는 계정이다. 어차피 대시보드에서 사용할 거니 관리자 권한으로 생성했다.
{
"user_id": "adminUser",
"display_name": "admin user",
"email": "seungh1024@naver.co",
"suspended": 0,
"max_buckets": 1000,
"subusers": [],
"keys": [
{
"user": "adminUser",
"access_key": "RCMM0BLUUO19H6TIULHD",
"secret_key": "jW9aGzd074Lf2CDxSJEArb3ojQIqYdIzLPQJufzQ"
}
],
"swift_keys": [],
"caps": [],
"op_mask": "read, write, delete",
"system": "true",
"default_placement": "",
"default_storage_class": "",
"placement_tags": [],
"bucket_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
},
"user_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
},
"temp_url_keys": [],
"type": "rgw",
"mfa_ids": []
}
그럼 이렇게 사용자가 생성될 텐데, 이때 access_key와 secret_key를 어디에 저장해서 기록해 두자. 이걸 사용해서 통신하게 된다.
Manager 컨테이너에 접속해서 사용자 정보를 등록하고 RGW의 host와 port를 등록하면 끝이다.
ceph dashboard set-rgw-api-access-key RCMM0BLUUO19H6TIULHD
ceph dashboard set-rgw-api-secret-key jW9aGzd074Lf2CDxSJEArb3ojQIqYdIzLPQJufzQ
ceph dashboard set-rgw-api-host 192.168.1.210
ceph dashboard set-rgw-api-port 7480
ceph dashboard set-rgw-api-ssl-verify false
아마 위처럼 실행했을 때 key는 별도의 파일로 사용하라고 할 수 있는데, 그 경우 이전과 동일하게 -i 옵션을 사용하면 된다
ceph dashboard set-rgw-api-access-key -i access-key.txt
ceph dashboard set-rgw-api-secret-key -i secret-key.txt
이 과정이 끝나면 다음과 같은 화면을 볼 수 있다.
이 화면까지 나왔다면 최소한의 설정은 끝났다. ceph와 docker를 잘 몰라서 오래 걸렸지만, 최소한으로 필요하다고 생각한 형태로 구성할 수 있었다.
조금 아쉬운 점은 로컬에서 여러 컨테이너를 띄우다 보니 Monitor와 RGW는 다중화를 하지 못하여 SPOF가 된 것이다. 또한 저장소를 다중화해서 가용성을 높이고자 했지만, 저장소만 신경 쓸 것이 아닌, Monitor나 RGW 등 신경 쓸 것이 많았다.
마지막으로 기존에는 이러한 문제를 생각조차 하지 못해서 단순히 Spring 서버에서 파일 처리를 했다. 보다 넓게 어떤 문제가 발생할 수 있는지 생각하지 못한 것 같다. 이번 경험을 통해 보다 넓게 어떤 문제가 발생할 수 있는지 바라보는 것이 중요함을 느꼈다.
참고 자료
https://greencloud33.tistory.com/11
https://docs.ceph.com/en/latest/
https://docs.redhat.com/en/documentation/red_hat_ceph_storage/8
'Java > My-Storage 프로젝트' 카테고리의 다른 글
[My-Storage 개선하기] Ceph에 파일 저장하기 (0) | 2025.01.05 |
---|---|
[My-Storage 개선하기] 데드락 해결, DB lock 사용 줄이기(2) - 테스트 (0) | 2024.12.19 |
[My-Storage 개선하기] 데드락 해결, DB lock 사용 줄이기(1) (0) | 2024.12.19 |
[우아한 테크 캠프 팀 프로젝트] 파일 이동 및 삭제 My-Storage(3) (0) | 2024.11.18 |
[우아한 테크 캠프 팀 프로젝트]동기 처리 vs 비동기 처리, 비동기 처리에서 발생한 OOM 문제 My-Storage(2) (0) | 2024.09.09 |