(작성중) velero를 이용한 kubernetes 영혼 백업하기

1. 서론

  • 서버에 관심이 많고, 개발 및 서비스 용도로 자체적으로 서버를 구축하여 사용해오고 있다. (※ 서버 히스토리 참고 : https://taking.kr/about)
  • 개인적으로 현재 블로그를 포함한 서비스는 Docker를 통해 서비스를 하고 있으나, Kubernetes로의 전환을 생각하고 있었고, 여러 방법을 테스트하면서 겪은 정보와 결과를 공유하고자 글을 작성한다.
  • 이외의 kubernetes 관련 내용은 Taking Gist에서 정리하고 있다.

2. 본론

2.1. 환경구축

  • 개인 서버 내 3개의 VM을 하단과 같이 구성하고 기본적인 설정을 끝냄
구성 환경

2.2. 전제조건

Step 1.1. Velero 설치 (Helm)
  • 우선 기본적으로 Minio를 설치하여 velero bucket 생성 및 accesskey, secretkey를 발급받은 후 진행한다.
helm repo add vmware-tanzu https://vmware-tanzu.github.io/helm-charts/
helm repo update vmware-tanzu

Helm Add & Update

  • minio object storage을 사용하여 백업을 진행하기 위해 velero-plugin-for-aws를 추가해준다.
  • PV,PVC 백업을 위해 defaultVolumesToFsBackup 옵션과 deployNodeAgent 옵션을 True로 설정했다.
  • backupStorageLocation 설정에 minio 주소, bucket 명, Region 명을 입력해주고, Credentials 설정을 통해 minio 접근을 위한 access Key, secretKey를 입력해준다.
cat <<EOF > velero-values.yaml
initContainers:
  - name: velero-plugin-for-aws
    image: velero/velero-plugin-for-aws:v1.7.0
    imagePullPolicy: IfNotPresent
    volumeMounts:
      - mountPath: /target
        name: plugins
        
configuration:
  defaultVolumesToFsBackup: true
  backupStorageLocation:
  - name: default
    provider: aws
    bucket: velero
    accessMode: ReadWrite
    default: true
    config:
      region: us-east-1
      s3ForcePathStyle: true
      s3Url: http://192.168.0.101:9000
      publicUrl: http://192.168.0.101:9000
  volumeSnapshotLocation:
  - name: aws
    provider: aws
    config:
      region: us-east-1
      
credentials:
  useSecret: true
  secretContents:
    cloud: |
      [default]
      aws_access_key_id = {your-minio-access-key}
      aws_secret_access_key = {your-minio-secret-key}
deployNodeAgent: true
EOF

velero-values.yaml (External)

  • helm으로 velero를 설치해준다. 네임스페이스는 velero 이며, 위에 작성한 velero-values.yaml 내 작성한 설정 값으로 진행된다.
helm upgrade my-velero vmware-tanzu/velero \
  --install \
  --create-namespace \
  --namespace velero \
  -f velero-values.yaml

velero install with HELM

  • velero 제어를 위해 cli를 설치해준다. 주의해야할 점은 아래 스크린샷과 같이 server와 client의 버전이 동일해야한다.
wget https://github.com/vmware-tanzu/velero/releases/download/v1.11.0/velero-v1.11.0-linux-amd64.tar.gz
tar xvzf velero-v1.11.0-linux-amd64.tar.gz 
sudo mv velero-v1.11.0-linux-amd64/velero /usr/local/bin
rm -rf ./velero-v1.11.0-linux-amd64

velero cli install

  • backup-location 이 정상적으로 연결되었는지, 아래의 명령어를 입력하고 PHASE를 확인해본다. Avaiable 이면 정상이다.
velero backup-location get

velero backup-location lists

Step 1.2. Velero 설치 (CLI) (추천)
  • 개인적으로 CLI로 설치를 추천한다. 백업 및 복구를 위해서 CLI가 필수인 만큼 helm은 의미가 없어보이기 때문이다. 삭제도 쉬움 velero uninstall
cat <<EOF > credentials-velero
[default]
 aws_access_key_id = {your-minio-access-key}
 aws_secret_access_key = {your-minio-secret-key}
EOF

providerName="aws"
pluginName="velero/velero-plugin-for-aws:v1.7.0"
bucketName="velero"
minioAddress="http://192.168.0.101:9000"

velero install \
 --provider ${providerName} \
 --plugins ${pluginName} \
 --bucket ${bucketName}  \
 --secret-file ./credentials-velero \
 --use-volume-snapshots=true \
 --backup-location-config region=us-east-1,s3ForcePathStyle="true",s3Url=${minioAddress},publicUrl=${minioAddress} \
 --image velero/velero:v1.11.0  \
 --snapshot-location-config region="us-east-1" \
 --use-node-agent \
 --default-volumes-to-fs-backup \
 --wait

velero install with CLI

Step 2. 백업 및 재해복구 시나리오
2.1. nfs-subdir-external-provisioner (실패)
  • NFS를 사용하는 만큼 Dynamic Provisioner를 사용하여 진행 및 테스트를 했었다. Velero는 PVC spec.volumeName으로 구분을 하여 백업을 하지만, Dynamic으로 PV,PVC을 자동으로 생성해주기 때문에 velero를 이용하여 백업 및 복구 시 PV,PVC UUID가 재생성되어 기존 백업된 볼륨을 못 찾는 문제가 발생하였다. 하루종일 삽질 결과 실패하였다.
image
복구 전
image
복구 후
2.2. Static Provisioning with HostPath (반만 성공)
  • Kubernetes 서버 내 NFS 폴더를 Mount 한 후, hostpath 로 지정해서 진행해보았다.
  • 다들 잘 알겠지만, HostPath의 경우에는 배포된 DataNode 내 HostPath로 진행이되기 때문에 노드 별로 NFS Mount 작업을 진행해줘야한다.
nfs mount in /etc/fstab
  • 우선 테스트를 위해 Static PV,PVC를 아래와 같이 생성해주었다.
  • hostpath 이기 때문에 수동으로 필히 해당 폴더를 생성하고 진행해야하는 단점이 존재한다.
mkdir -p /volume/1TB_NVME/kubernetes
  • 테스트를 위해 Portainer를 설치했다.
  • hostPath를 위해 Static PV,PVC를 아래와 같이 생성했다.
  • 네임스페이스 / PV / PVC 생성
NAME=portainer
HOSTPATH=/volume/1TB_NVME/kubernetes/portainer-pvc
STORAGE_ClASS=manual
STORAGE_CAPACITY=1Gi

cat << EOF | kubectl apply -f -
---
# namespace
---
apiVersion: v1
kind: Namespace
metadata:
  labels:
    component: ${NAME}
    kubernetes.io/metadata.name: ${NAME}
  name: ${NAME}
---
# nfs pv,pvc
---
apiVersion: v1 
kind: PersistentVolume 
metadata: 
  name: ${NAME}-pv
  namespace: portainer
spec: 
  accessModes: 
    - ReadWriteOnce
  capacity: 
    storage: ${STORAGE_CAPACITY}
  volumeMode: Filesystem 
  persistentVolumeReclaimPolicy: Retain 
  hostPath:
    path: ${HOSTPATH}
  storageClassName: ${STORAGE_ClASS}
--- 
apiVersion: v1 
kind: PersistentVolumeClaim 
metadata:               
  name: ${NAME}-pvc 
  namespace: portainer
spec: 
  accessModes: 
    - ReadWriteOnce
  resources: 
    requests: 
      storage: ${STORAGE_CAPACITY}
  storageClassName: ${STORAGE_ClASS}
  volumeMode: Filesystem
  volumeName: ${NAME}-pv
EOF

c

pv, pvc created
  • helm을 통해 portainer를 설치한다.
  • 네임스페이스는 portainer 그리고 서비스 타입은 NodePort, https 만 사용하기때문에 tls.force는 true, 그리고 개인적으로 라이센스가 있기 때문에 enterpriseEdition.enabled 는 true로 설정했다. true일 경우 EE false일 경우 CE로 설치된다.
  • persistence는 자동 생성이 아니라 이미 위와 같이 생성해두었기 때문에 persistence.existingClaim 값은 portainer-pvc로 설정했다.
helm upgrade portainer portainer/portainer \
    --install \
    --create-namespace \
    --namespace portainer \
    --set service.type=NodePort \
    --set enterpriseEdition.enabled=true \
    --set persistence.existingClaim=portainer-pvc \
    --set tls.force=true
pod,svc,pv,pvc lists
  • Portainer 설치 후, 접속하여 계정과 라이센스를 입력하여 데이터를 저장하였다.
Portainer Username, Password Init
Portainer License Init
First Start
  • velero cli를 사용하여 backup을 생성해준다.
  • velero backup create {backupName} --include-namespaces {nameSpaceName}
  • velero backup describe {backupName}을 통해 백업 정보를 상세히 확인할 수 있다.
  • velero backup logs {backupName}을 통해 백업 로그를 상세히 확인할 수 있다.
velero backup & describe
  • velero 설치 시, 입력한 Object Storage로 portainer 백업이 정상적으로 이루어진걸 확인 할 수 있었다.
  • nfs-subdir-external-provisioner를 사용할 땐 restic 백업이 활성화되었는데, hostPath의 경우에는 Restic 백업이 안되는 것을 확인할 수 있었다.
  • 하지만, Static PV,PVC와 hostPath 지정했기 때문에 restic 백업은 안되도 문제 없다.
minio object storage in velero/portainer
  • portainer 네임스페이스 내 PV,PVC를 우선 삭제 요청하고 pod를 제거했다.
  • velero restore create --from-backup {backupName} 명령어를 통해 restore를 요청한다.
  • 정상적으로 velero restore 를 통해 pv,pvc가 복구된 것을 볼 수 있다. 사실 pv,pvc 이외에 configmaps, secrets 등 또한 같이 백업 및 복구된다. 자세한건 Documents를 확인 바람
  • 기존에 생성한 계정으로 접속할 수 있다.

2.3. Static Provisioning with NFS (예정)
NAME=portainer
NFS_ADDR=192.168.0.100
NFS_PATH=/volume/1TB_NVME/kubernetes/portainer-pvc
STORAGE_ClASS=manual
STORAGE_CAPACITY=1Gi

cat << EOF | kubectl apply -f -
---
# namespace
---
apiVersion: v1
kind: Namespace
metadata:
  labels:
    component: ${NAME}
    kubernetes.io/metadata.name: ${NAME}
  name: ${NAME}
---
# nfs pv,pvc
---
apiVersion: v1 
kind: PersistentVolume 
metadata: 
  name: ${NAME}-pv
  namespace: portainer
spec: 
  accessModes: 
    - ReadWriteMany
  capacity: 
    storage: ${STORAGE_CAPACITY}
  volumeMode: Filesystem 
  persistentVolumeReclaimPolicy: Retain 
  nfs:
    server: ${NFS_ADDR}
    path: ${NFS_PATH}
  storageClassName: ${STORAGE_ClASS}
--- 
apiVersion: v1 
kind: PersistentVolumeClaim 
metadata:               
  name: ${NAME}-pvc 
  namespace: portainer
spec: 
  accessModes: 
    - ReadWriteMany
  resources: 
    requests: 
      storage: ${STORAGE_CAPACITY}
  storageClassName: ${STORAGE_ClASS}
  volumeMode: Filesystem
  volumeName: ${NAME}-pv
EOF
helm upgrade portainer portainer/portainer \
    --install \
    --create-namespace \
    --namespace portainer \
    --set service.type=NodePort \
    --set enterpriseEdition.enabled=true \
    --set persistence.existingClaim=portainer-pvc \
    --set tls.force=true

2.4. local-path-provisioner (보류)
  • local-path-provisioner는 nfs-subdir-external-provisioner와 다르게 VolumeBindingMode가 설정이 가능하다.
  • 아직 테스트 전이라 nfs와 동일하게 randomly uuid로 인해 동일한 문제로 진행안될 것으로 예상되어 보류한다.
  • Kubernetes 의 Local Volume Provisioner 은 현재 Dynamic Provisioning 을 지원하지 않는다. local-path-provisioner 에선 지원하나 Volume Capacity 제한 기능이 현재 지원하지 않는다.
2.5. rook ceph (예정)
  • 가장 마지막 보루였다. rook ceph은 생각보다 많은 자원을 요하기 때문에 rook ceph 전에 해결보고 싶었다.
You've successfully subscribed to taking
Great! Next, complete checkout to get full access to all premium content.
Error! Could not sign up. invalid link.
Welcome back! You've successfully signed in.
Error! Could not sign in. Please try again.
Success! Your account is fully activated, you now have access to all content.
Error! Stripe checkout failed.
Success! Your billing info is updated.
Error! Billing info update failed.