레이블이 etcd인 게시물을 표시합니다. 모든 게시물 표시
레이블이 etcd인 게시물을 표시합니다. 모든 게시물 표시

systemd timer 에 etcdctl defrag 등록하기

# prometheus 알람 중 다음과 같은 k8s etcd 디스크 할당관련 에러가 온다
etcd cluster "kube-etcd": database size in use on instance 10.10.10.10:2379 is 48.18% of the actual allocated disk space, please run defragmentation (e.g. etcdctl defrag) to retrieve the unused fragmented disk space.

# 실제 master 노드에 들어가 etcdctl 수행하기
# kube-apiserver 프로세스 옵션 중 인증 부분을 참고하자
ps -ef | grep kube-apiserver 
...
--etcd-cafile=/etc/ssl/etcd/ssl/ca.pem --etcd-certfile=/etc/ssl/etcd/ssl/node-master1.pem --etcd-keyfile=/etc/ssl/etcd/ssl/node-master1-key.pem

# etcdctl 옵션명으로 바꿔서 etcdctl 수행할 수 있다.
# cluster member 를 확인해 보자.
sudo etcdctl --cacert=/etc/ssl/etcd/ssl/ca.pem --cert=/etc/ssl/etcd/ssl/node-master1.pem --key=/etc/ssl/etcd/ssl/node-master1-key.pem member list

# etcdctl defrag 를 수행한다.
sudo etcdctl --cacert=/etc/ssl/etcd/ssl/ca.pem --cert=/etc/ssl/etcd/ssl/node-master1.pem --key=/etc/ssl/etcd/ssl/node-master1-key.pem defrag --cluster
Finished defragmenting etcd member[https://10.10.10.10:2379]


#####


# 주기적으로 etcdctl defrag 수행하기
# etcd 서비스 설정이 이미 있다.
# /etc/systemd/system/etcd.service
# etcd 서비스 동작 확인
sudo journalctl -f -u etcd.service

# etcdctl defrag 를 주기적으로 실행하기 위해선 cron 대신 systemd service timer 를 사용하자
# 서비스명.service 와 서비스명.timer 로 파일명에서 서비스명이 같아야 한다.
# etcdctl defrag 서비스 등록
sudo vi /etc/systemd/system/etcdctl-defrag.service
[Unit]
Description=Run etcdctl defrag
# 유닛(이서비스)의 의존성, network.target(네트워크가 연결된 이후여야 한다.)
After=network.target
[Service]
# oneshot: 한번 실행하고 끝나는 서비스
Type=oneshot
Environment="LOG_DIR=/var/log"
Environment="ETCDCTL_API=3"
ExecStart=/usr/local/bin/etcdctl defrag --cacert=/etc/ssl/etcd/ssl/ca.pem --cert=/etc/ssl/etcd/ssl/node-master1.pem --key=/etc/ssl/etcd/ssl/node-master1-key.pem
[Install]
# linux run level 중 3 단계(multi-user.target, 네트워크등이 활성화 되는 시점)일대 동작(서비스로 설치)
WantedBy=multi-user.target

# 매일 1시에 etcdctl-defrag 서비스가 수행할 수 있도록 timer 파일 생성
sudo vi /etc/systemd/system/etcdctl-defrag.timer
[Unit]
Description=Run etcd-defrag.service every day
After=network.target
[Timer]
OnCalendar=*-*-* 01:00:0
[Install]
WantedBy=multi-user.target

# systemctl 로 서비스, 타이머 시작(등록)
sudo systemctl start etcdctl-defrag
sudo systemctl start etcdctl-defrag.timer

# systemctl 동작  확인
sudo systemctl status etcdctl-defrag --no-pager
sudo systemctl status etcdctl-defrag.timer

# 참고

k8s etcdctl unexpected EOF

# k8s bitnami-etcd(etcd 3.5.3) 를 새로 구성 후 로컬에서 접속하기 위해 etcd service 에 nodeport 30090 을 추가했다.
# 로컬에서 go.etcd.io/etcd/client/v3 로 Get 을 수행하면 다음과 같은 에러가 발생한다.
{"level":"warn","ts":"2023-02-04T10:46:30.933+0900","logger":"etcd-client","caller":"v3@v3.5.7/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"etcd-endpoints://0xc0001bc000/10.10.10.10:30090","attempt":0,"error":"rpc error: code = Internal desc = unexpected EOF"}

# 하지만 이전 etcd service 로 변경하면 에러 없이 수행된다.
# k8s ysoftman_app --> etcd 도 에러 없이 수행된다.


#####


# etcdctl(etcd client cli)로 설치해서 확인을 해보자.
brew install etcd

# etcdctl 및 api 버전 확인
etcdctl version
etcdctl version: 3.5.7
API version: 3.5

# endpoint 정보 확인하면 정상적으로 응답한다.
etcdctl --endpoints=10.10.10.10:30090 --write-out=table endpoint status
etcdctl --endpoints=10.10.10.10:30090 --write-out=table endpoint health

# etcd 클러스터(pod) 3개가 정상적으로 응답한다.
etcdctl --endpoints=10.10.10.10:30090 member list

# 특정 키 값을 조회해도 정상적으로 응답한다.
etcdctl --endpoints=10.10.10.10:30090 get "/user/key-ysoftman

# 그런데 prefix 로 키들을 조회 하면 위 에러(unexpected EOF)가 발생한다.
# 이전 etcd endpoint 를 사용하면 잘된다.
etcdctl --endpoints=10.10.10.10:30090 get --prefix "/user/"

# limit 로 조회 개수를 줄이면 동작한다.
etcdctl --endpoints=10.10.10.10:30090 get --prefix "/user/" --limit=10
# limit 로 조회 안되는 지점을 찾아보니 157 부터 조회가 안된다.
# 하지만 157 번째 키를 단건으로 조회하면 조회가 되는걸 보니 데이터값 자체의 문제는 아닌것으로 보인다.
etcdctl --endpoints=10.10.10.10:30090 get --prefix "/user/" --limit=157

# --print-value-only 로 결과에서 키는 제외하는 옵션을 줘도 157이상이면 에러가 발생한다.
# 찾아보니 클라에서 출력시 키만 제외하는것 같다.
etcdctl --endpoints=10.10.10.10:30090 get --prefix "/user/" --print-value-only --limit 157

# key 만 조회하면 450 건까지 조회된다.
etcdctl --endpoints=10.10.10.10:30090 get --prefix "/user/" --keys-only --limit 450


#####


# bitnami-etcd logLeve=debug 설정 후 요청에 대한 debug 로그 확인해보자
# -limit 156 옵션으로 정상 응답오는 경우
"message": "{\"level\":\"debug\",\"ts\":\"2023-02-06T16:26:28.408Z\",\"caller\":\"v3rpc/interceptor.go:182\",\"msg\":\"request stats\",\"start time\":\"2023-02-06T16:26:28.406Z\",\"time spent\":\"2.424678ms\",\"remote\":\"xxx.xxx.xxx.xxx:26355\",\"response type\":\"/etcdserverpb.KV/Range\",\"request count\":0,\"request size\":37,\"response count\":544,\"response size\":65215,\"request content\":\"key:\\\"/user/\\\" range_end:\\\"/user0\\\" limit:156 \"}",

# limit 없이 전체 조회한 경우, 로컬 Unexpected EOF 발생했을때 로그
"message": "{\"level\":\"debug\",\"ts\":\"2023-02-06T16:36:15.365Z\",\"caller\":\"v3rpc/interceptor.go:182\",\"msg\":\"request stats\",\"start time\":\"2023-02-06T16:36:15.361Z\",\"time spent\":\"3.948059ms\",\"remote\":\"xxx.xxx.xxx.xxx:42568\",\"response type\":\"/etcdserverpb.KV/Range\",\"request count\":0,\"request size\":34,\"response count\":544,\"response size\":264867,\"request content\":\"key:\\\"/user/\\\" range_end:\\\"/user0\\\" \"}",

# 둘다 정상적으로 아이템 개수 (response count:544) 개의 아이템을 응답했다고 나온다.
# 전체 조회시 response size 도 크게(정상) 나온다.


#####


# linux 서버에 etcdctl 설치 후 --> k8s bitnami-etcd 에서는 전체 조회가 정상적으로 된다.


#####


# 로컬 etcd 에 k8s bitnami-etcd 스냅샷(ysoftman.db) 가져와 복구해서 올려서 테스트해보자
# ysoftman.db 를 복구해서 ./etcd-data(이미 있다면 삭제필요)에 준비
etcdutl snapshot restore ./ysoftman.db --data-dir ./etcd-data

# etcd 서버 올리기
etcd --data-dir ./etcd-data

# 로컬 etcd 로는 접속이 limit 없이 모두 조회된다.
etcdctl --endpoints=localhost:2379 get --prefix "/user/" --print-value-only | jq


#####


# etcd container 접속해서 etcdctl 로 확인해보자.
# 먼저 버전을 확인해보면 API 버전은 3.5 로컬과 같지만 etcdctl version 은 낮다.
# 참고로 로컬에 etcdctl 3.5.3 버전을 다운받아 조회했지만 안됐다.
I have no name!@bitnami-etcd-0:/opt/bitnami/etcd$ etcdctl version
etcdctl version: 3.5.3
API version: 3.5

# 전체 조회가 잘된다.
I have no name!@bitnami-etcd-0:/opt/bitnami/etcd$ etcdctl --endpoints=10.10.10.10:30090 get --prefix "/user/" --print-value-only


#####


# 상황별 테스트를 정리해보면
# 같은 클러스터 k8s pod <--> k8s bitnami-etcd service(nodeport) 정상
# 별도 linux <--> k8s bitnami-etcd service(nodeport) 정상
# 로컬(mac) <--> 로컬 etcd 정상
# 로컬(mac) <--> k8s bitnami-etcd service(nodeport) 경우만 응답 데이터 일정 크기 이후에 null 값 발생한다.

# etcdctl(https://github.com/etcd-io/etcd) 소스 빌드 및 테스트해보자.
# endpoints="이전 etcd" 로 빌드 테스트하면 전체 조회된다.
# endpoints="local etcd" 서버(k8s etcd 와 같은 데이터) 로 빌드 테스트하면 전체 조회된다.
cd etcd/etcdctl/
go build && ./etcdctl --endpoints=10.10.10.10:30090 get --prefix "/user/"

# etcdctl > etcd client > grpc(외부 패키지) > rpc_util.go 의 다음 함수에서
# 실제 read 한 msg 를 프린트해보면 데이터(json)가 끊겨져 있다.
# EOF 에러를 리턴하는 grpc 소스코드
func (p *parser) recvMsg()
p.r.Read(msg);
 ... > io.ErrUnexpectedEOF 에러 리턴

# 응답 메시지의 크기
# length 276518 인데, Read 에서 65530 만큼 읽다 EOF 발생
# msg(read 한 내용)을 파일로 출력해보면 65530 이후 210988 개의 null 이 포함되어 있다.
go build && ./etcdctl --endpoints=10.10.10.10:30090 get --prefix "/user/" > out.txt

# 찾아보니 grpc eof 관련해 연결 및 스트림의 window size 이슈가 있다.
# etcd client 접속 옵션 부분에
# 다음과 같이 grpc window 크기를 늘려주니 모든 결과가 조회된다.
opts := append(dopts, grpc.WithResolvers(c.resolver), grpc.WithInitialWindowSize(1_000_000), grpc.WithInitialConnWindowSize(1_000_000))

# etcdctl 에서는 InitialWindowSize 과 InitialConnWindowSize 를 설정하는 부분이 없어 grpc 의 64K 디폴트 및 최소값을 그대로 사용하게 된다.

# eof 시 read한 크기가 65530(대충 64K)정도인걸 보면 네트워트 환경(grpc 이슈에 보면 mac 에서 자주 발생하는것 같다.)에 따라 window size 작으면 스트림을 제대로 읽지 못하는 문제가 있다.
# etcdctl cli 나 library 에서는 window size 를 설정할 수 없어 현재로선 etcd 소스를 별도 수정해서 사용해야 한다. 흠...

bitnami etcd snapshot 으로 복구하기

bitnami-etcd helm chart 옵션 중 snapshot 파일로 백업된 db를 복구하기 위해 다음과 같이 파라메터를 사용할 수 있다.
startFromSnapshot:
  enabled: true
  existingClaim: bitnami-etcd-snapshotter
  snapshotFilename: db-2023-01-20_05-00

다른곳의 phase 의 snaphot 파일을 sudo 로 복사해온 경우
uid 1001 로 변경해줘야 한다.
sudo chown 1001:root db-2023-01-20_05-00

위 설정을 적용 후 etcd 클러스터를 재시작했지만 스냅샷 db 가 복구되지 않았다.
그래서 etcd container 접속해 다음 명령으로 복구를 시도하니
etcdctl snapshot restore /snapshot/db-2023-01-20_05-00 --data-dir /bitnami/etcd/data
--> /bitnami/etcd/data 를 읽을 수 없다고 에러가 발생했다.

bitnami-etcd 는 다음과 같은 구성요소를 가지고 있다.
- etcd bitnami-etcd-snapshotter(cronjob) 으로 container /snapshots/db-xxxx 로 백업되고 있음
- Statefulsets(sts)는 etcd pod 3개를 관리(순차적으로 시작해야함)
- 각 etcd pod는 /bitnami/etcd/data 경로를 Persistentvolumeclaims(pvc)로 저장하고 있다.

[해결방법]
1.우선 Statefulsets(sts) 삭제로 etcd pod 를 제거한다.(pvc 사용처를 없앤다.)
2.data-bitnami-etcd-0~2 pod가 사용했던 Persistentvolumeclaims(pvc, /bitnami/etcd/data) 삭제를 삭제한다.
3.이제 다음과 같이 파일(container /snapshots/db-xxxx)명 명시하고 재시작
이제 etcdkeeper 등으로 보면 스냅샷 db 내용이 복구된것을 확인 할 수 있다.

[bitnami-etcd-snapshotter (pvc) 삭제된 경우]
startFromSnapshot > enables: false 로 적용하면 bitnami-etcd-snapshotter pvc 가 생성된다.
이후 startFromSnapshot 를 활성화할 수 있다.