项目作者: chanshik

项目描述 :
Korea Ceph User Group: CEPH TECH TALK 02 (201812) Hands-on Note
高级语言: Shell
项目地址: git://github.com/chanshik/ceph-201812-meetup.git
创建时间: 2018-12-03T08:14:42Z
项目社区:https://github.com/chanshik/ceph-201812-meetup

开源协议:

下载


Ceph with Rook Hands-on

Ceph 분산 파일 시스템을 Rook Operator 를 이용해 VM 위에 직접 구축해보는 실습을 진행합니다.

  • Vagrant 와 Virtualbox 를 이용해 Kubernetes 클러스터 구성
  • Rook Operator 설치 및 클러스터 환경 설정
  • Ceph 분산 파일 시스템 설치
  • 어플리케이션을 Ceph 와 연결하여 배포

Used packages in this hands-on

Setup Environments

  • Host OS: Ubuntu 16.04
  • Guest OS: Ubuntu 16.04 (ubuntu/xenial64) / 18.04 (ubuntu/bionic64)
  • Automation Tool: Vagrant

Install Virtualbox

사용하는 운영체제에 맞는 패키지를 받아 설치합니다.

  1. sudo apt install virtualbox

Install Vagrant

VM 을 생성하면서 기본적인 초기화를 진행할 때 사용할 Vagrant 프로그램을 설치합니다.

  1. sudo dpkg -i vagrant_2.2.1_x86_64.deb

Downloads Vagrant box image

Vagrant 를 이용해 VM 을 생성할 때 사용할 Box 파일을 미리 받아 디스크에 저장해둡니다.

Ubuntu 16.04 혹은 18.04 이미지를 이용합니다.

  1. vagrant box add ubuntu/bionic64

Downloads worksheet

github 저장소에 실습을 진행하면서 사용할 파일을 디렉토리별로 구분하여 저장해두었습니다.

  1. git clone https://github.com/chanshik/ceph-201812-meetup.git
  2. cd ceph-201812-meetup
  3. ceph-201812-meetup$

VM Networks

VM 에 할당한 IP 와 역할은 다음과 같습니다.

Node IP Role Devices
k8s-1 10.254.1.2 Master /dev/sdc, /dev/sdd
k8s-2 10.254.1.3 Worker /dev/sdc, /dev/sdd
k8s-3 10.254.1.4 Wokrer /dev/sdc, /dev/sdd

Start VMs

미리 작성해둔 Vagrantfile 을 이용해 VM 3대를 시작합니다. 사용하는 장비 사양에 맞도록 CPU, 메모리, 추가 디스크 공간을 지정합니다.

실습에 필요한 환경을 구축하기 위해 VM 세 대를 생성합니다. 각 VM 은 시스템 디스크 외에 두 개의 디스크를 더 가지고 있습니다. 추가해둔 /dev/sdc, /dev/sdd 디스크를 Ceph 에서 BlueStore 로 활용합니다.

  1. # -*- mode: ruby -*-
  2. # vi: set ft=ruby :
  3. Vagrant.configure("2") do |config|
  4. config.vm.box = "ubuntu/bionic64"
  5. config.vm.box_check_update = false
  6. node_subnet = "10.254.1"
  7. (1..3).each do |i|
  8. config.vm.define "k8s-#{i}" do |node|
  9. node.vm.hostname = "k8s-#{i}"
  10. node.vm.network "private_network", ip: "#{node_subnet}.#{i + 1}"
  11. attached_disk_a = "disk-k8s-#{i}-a.vdi"
  12. attached_disk_b = "disk-k8s-#{i}-b.vdi"
  13. node.vm.provider "virtualbox" do |vb|
  14. vb.name = "k8s-#{i}"
  15. vb.gui = false
  16. vb.cpus = 2
  17. vb.memory = "4096"
  18. unless File.exists?(attached_disk_a)
  19. vb.customize [
  20. 'createhd', '--filename', attached_disk_a,
  21. '--variant', 'Fixed',
  22. '--size', 10 * 1024]
  23. end
  24. unless File.exists?(attached_disk_b)
  25. vb.customize [
  26. 'createhd', '--filename', attached_disk_b,
  27. '--variant', 'Fixed',
  28. '--size', 10 * 1024]
  29. end
  30. vb.customize [
  31. 'storageattach', :id, '--storagectl', 'SCSI',
  32. '--port', 2, '--device', 0, '--type', 'hdd',
  33. '--medium', attached_disk_a]
  34. vb.customize [
  35. 'storageattach', :id, '--storagectl', 'SCSI',
  36. '--port', 3, '--device', 0, '--type', 'hdd',
  37. '--medium', attached_disk_b]
  38. end
  39. node.vm.provision "bootstrap", type: "shell", inline: <<-SHELL
  40. sudo curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
  41. sudo bash -c 'cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
  42. deb http://apt.kubernetes.io/ kubernetes-xenial main
  43. EOF'
  44. sudo apt update
  45. sudo apt install -y docker.io kubelet kubeadm kubectl ntp
  46. sudo usermod -aG docker vagrant
  47. sudo sed -i '/k8s/d' /etc/hosts
  48. sudo echo "#{node_subnet}.#{i + 1} k8s-#{i}" | sudo tee -a /etc/hosts
  49. SHELL
  50. end
  51. end
  52. end

앞에서 작성한 Vagrantfile 을 이용해 VM 을 생성합니다.

  1. vagrant up

VM 생성이 모두 끝난 다음에 ssh 를 실행하여 원하는 노드에 접속합니다.

  1. vagrant ssh k8s-1

Setup Kubernetes Cluster

Select pod network add-on

Kubernetes 에서 사용할 CNI (Container Network Interface) 선택하고 kubeadm 을 이용해 초기화 할 때 같이 지정합니다. 실습에서는 Calico CNI 를 사용합니다.

Initialize master node

Master node 에서 kubeadm init 명령을 실행하여 클러스터 초기화 작업을 시작합니다.

  1. sudo swapoff -a
  2. sudo kubeadm init --pod-network-cidr=192.168.0.0/16 --apiserver-advertise-address=10.254.1.2
  3. [init] using Kubernetes version: v1.12.2
  4. [preflight] running pre-flight checks
  5. [WARNING Service-Docker]: docker service is not enabled, please run 'systemctl enable docker.service'
  6. [preflight/images] Pulling images required for setting up a Kubernetes cluster
  7. [preflight/images] This might take a minute or two, depending on the speed of your internet connection
  8. [preflight/images] You can also perform this action in beforehand using 'kubeadm config images pull'
  9. [kubelet] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
  10. [kubelet] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
  11. [preflight] Activating the kubelet service
  12. ...
  13. [bootstraptoken] using token: s9qd0j.beetbemlhmmx1etd
  14. [bootstraptoken] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
  15. [bootstraptoken] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
  16. [bootstraptoken] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
  17. [bootstraptoken] creating the "cluster-info" ConfigMap in the "kube-public" namespace
  18. [addons] Applied essential addon: CoreDNS
  19. [addons] Applied essential addon: kube-proxy
  20. Your Kubernetes master has initialized successfully!
  21. To start using your cluster, you need to run the following as a regular user:
  22. mkdir -p $HOME/.kube
  23. sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  24. sudo chown $(id -u):$(id -g) $HOME/.kube/config
  25. You should now deploy a pod network to the cluster.
  26. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  27. https://kubernetes.io/docs/concepts/cluster-administration/addons/
  28. You can now join any number of machines by running the following on each node
  29. as root:
  30. kubeadm join 10.254.1.2:6443 --token dzjclo.a8d0kjwcc64r7kvs --discovery-token-ca-cert-hash sha256:ce7c94f7863dbc1ad8d32028cb5388e4ea47a12959317d035b722e2a4fb3e5f3

Add nodes

Master node 초기화 이후에는 추가하려는 노드에서 kubeadm join 명령을 실행합니다.

@k8s-2

  1. sudo swapoff -a
  2. sudo kubeadm join 10.254.1.2:6443 --token s9qd0j.beetbemlhmmx1etd --discovery-token-ca-cert-hash sha256:573bf08c800f2c9736d9b1b8a66421777dcd9e8991a2b9e0d7612c248bcdcdc5

@k8s-3

  1. sudo swapoff -a
  2. sudo kubeadm join 10.254.1.2:6443 --token s9qd0j.beetbemlhmmx1etd --discovery-token-ca-cert-hash sha256:573bf08c800f2c9736d9b1b8a66421777dcd9e8991a2b9e0d7612c248bcdcdc5

Show kubernetes nodes

위 과정을 거쳐 생성한 Kubernetes 에 접근하려면 /etc/kubernetes/admin.conf 파일이 필요합니다. 홈 디렉토리에 복사하고 소유자를 변경한 이후에 KUBECONFIG 환경변수에 위치를 지정합니다.

  1. sudo cp /etc/kubernetes/admin.conf ./k8s-admin.conf
  2. sudo chown vagrant:vagrant k8s-admin.conf
  3. export KUBECONFIG=/home/vagrant/k8s-admin.conf
  4. echo "export KUBECONFIG=/home/vagrant/k8s-admin.conf" >> .bashrc
  5. kubectl get nodes
  6. NAME STATUS ROLES AGE VERSION
  7. k8s-1 NotReady master 8m48s v1.12.2
  8. k8s-2 NotReady <none> 2m31s v1.12.2
  9. k8s-3 NotReady <none> 2m28s v1.12.2

Install CNI

kubectl get nodes 명령 결과를 보면 STATUS 가 현재 NotReady 입니다. 초기화 단계에서 선택한 CNI 를 설치해야 실제로 사용 가능한 상태가 됩니다.

Calico CNI 를 사용하기 위해 kubectl 명령어를 이용해 설치합니다.

  1. kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml
  2. clusterrole.rbac.authorization.k8s.io/calico-node created
  3. clusterrolebinding.rbac.authorization.k8s.io/calico-node created
  1. kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml
  2. configmap/calico-config created
  3. service/calico-typha created
  4. deployment.apps/calico-typha created
  5. poddisruptionbudget.policy/calico-typha created
  6. daemonset.extensions/calico-node created
  7. serviceaccount/calico-node created
  8. customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created
  9. customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created
  10. customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created
  11. customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created
  12. customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created
  13. customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created
  14. customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created
  15. customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created
  16. customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created
  1. kubectl get nodes
  2. NAME STATUS ROLES AGE VERSION
  3. k8s-1 Ready master 25m v1.12.2
  4. k8s-2 Ready <none> 19m v1.12.2
  5. k8s-3 Ready <none> 19m v1.12.2

Master isolation

Kubernetes 기본 설정은 Master 역할을 하는 노드에 다른 컨테이너를 배포하지 않도록 되어있습니다. 실습을 진행할 때는 Master 노드도 사용하기 위해 설정을 변경합니다.

  1. kubectl taint nodes --all node-role.kubernetes.io/master-
  2. node/k8s-1 untainted
  3. taint "node-role.kubernetes.io/master:" not found
  4. taint "node-role.kubernetes.io/master:" not found

Setup Ceph with Rook

Ceph and Rook

Kubernetes 위에서 동작하는 어플리케이션이 저장 공간을 필요로 할 경우에는 Persistent Volume 을 생성하여 연결해주어야 합니다. 여기에서는 Ceph 분산 파일 시스템을 이용하여 실행된 노드에 관계없이 원하는 저장 공간을 생성하고 연결하는 데 활용합니다.

Ceph 클러스터를 직접 구축하고 설정하는 것은 쉽지 않은 일이지만, Rook 을 이용해 상대적으로 쉽고 편리하게 구축할 수 있습니다. 아래는 Rook 프로젝트 홈페이지에서 가져온 Rook 소개글입니다.

Rook is an open source cloud-native storage orchestrator,
providing the platform, framework, and support for a diverse set of
storage solutions to natively integrate with cloud-native environments.

Rook 을 이용해 클러스터를 생성할 때 사용하는 설정 파일은 https://github.com/rook/rook/tree/release-0.8/cluster/examples/kubernetes/ceph 경로에 있는 것을 사용합니다.

Initialize Ceph Cluster

VM 노드 3대가 가지고 있는 추가 디스크 중 한 개를(/dev/sdc) Ceph 에 할당하여 클러스터를 구성합니다. Ceph BlueStore 는 직접 파티션을 생성하고 관리하기 때문에, 노드에 장착되어 있는 빈 디스크를 직접 지정합니다. 미리 작성해둔 Vagrantfile 에서는 /dev/sdc, /dev/sdc 장치에 아무런 파티션 작업도 하지 않은 디스크를 연결해두었습니다.

Rook Operator 를 통해 Ceph 클러스터를 생성할 때 필요한 몇 가지 설정을 rook/operator.yaml 파일에 기록합니다.

rook/operator.yaml

  1. ...
  2. spec:
  3. serviceAccountName: rook-ceph-system
  4. containers:
  5. - name: rook-ceph-operator
  6. image: rook/ceph:v0.8.3
  7. ...
  8. - name: ROOK_ALLOW_MULTIPLE_FILESYSTEMS
  9. value: "true"
  10. ...
  11. - name: ROOK_HOSTPATH_REQUIRES_PRIVILEGED
  12. value: "true"
  13. ...

rook/ceph 컨테이너 버전을 현재 Stable 상태인 v0.8.3 으로 지정합니다. Shared File System 을 두 개 이상 만들어서 사용하려면 ROOK_ALLOW_MULTIPLE_FILESYSTEMS 옵션을 “true” 로 지정합니다.

BlueStore 를 사용하려면 컨테이너에서 직접 파일 시스템을 생성할 수 있어야 하기 때문에 ROOK_HOSTPATH_REQUIRES_PRIVILEGED 옵션에 “true” 를 지정합니다.

operator.yaml 파일을 수정하고 Rook operator 를 배포합니다.

  1. kubectl create -f rook/operator.yaml
  2. namespace/rook-ceph-system created
  3. customresourcedefinition.apiextensions.k8s.io/clusters.ceph.rook.io created
  4. customresourcedefinition.apiextensions.k8s.io/filesystems.ceph.rook.io created
  5. customresourcedefinition.apiextensions.k8s.io/objectstores.ceph.rook.io created
  6. customresourcedefinition.apiextensions.k8s.io/pools.ceph.rook.io created
  7. customresourcedefinition.apiextensions.k8s.io/volumes.rook.io created
  8. clusterrole.rbac.authorization.k8s.io/rook-ceph-cluster-mgmt created
  9. role.rbac.authorization.k8s.io/rook-ceph-system created
  10. clusterrole.rbac.authorization.k8s.io/rook-ceph-global created
  11. serviceaccount/rook-ceph-system created
  12. rolebinding.rbac.authorization.k8s.io/rook-ceph-system created
  13. clusterrolebinding.rbac.authorization.k8s.io/rook-ceph-global created
  14. deployment.apps/rook-ceph-operator created

cluster.yaml 파일에 Ceph 에서 사용할 디스크 장치명을 나열합니다.

rook/cluster.yaml

  1. ...
  2. storage:
  3. useAllNodes: false
  4. useAllDevices: false
  5. deviceFilter:
  6. location:
  7. config:
  8. storeType: bluestore
  9. databaseSizeMB: "512"
  10. journalSizeMB: "512"
  11. nodes:
  12. - name: "k8s-1"
  13. devices:
  14. - name: "sdc"
  15. - name: "k8s-2"
  16. devices:
  17. - name: "sdc"
  18. - name: "k8s-3"
  19. devices:
  20. - name: "sdc"

각 노드에서 사용할 디스크 장치명을 추가한 후 Ceph 클러스터를 생성합니다.

  1. kubectl create -f rook/cluster.yaml
  2. namespace/rook-ceph created
  3. serviceaccount/rook-ceph-cluster created
  4. role.rbac.authorization.k8s.io/rook-ceph-cluster created
  5. rolebinding.rbac.authorization.k8s.io/rook-ceph-cluster-mgmt created
  6. rolebinding.rbac.authorization.k8s.io/rook-ceph-cluster created
  7. cluster.ceph.rook.io/rook-ceph created

만약에 Rook 으로 Ceph 클러스터를 한번 생성한 이후에 삭제하고 다시 생성하려면 /var/lib/rook/osd-*, /var/lib/rook/mon-* 디렉토리를 모두 지운 이후에 위 명령을 다시 실행합니다.

디스크 파티션 작업을 마무리하고 모두 완료되면 rook-ceph namespace 에서 배포된 Ceph 구성요소를 확인할 수 있습니다.

  1. kubectl get deploy -n rook-ceph
  2. NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
  3. rook-ceph-mgr-a 1 1 1 1 112s
  4. rook-ceph-mon-a 1 1 1 1 2m31s
  5. rook-ceph-mon-b 1 1 1 1 2m15s
  6. rook-ceph-mon-c 1 1 1 1 2m5s
  7. rook-ceph-osd-0 1 1 1 1 95s
  8. rook-ceph-osd-1 1 1 1 1 94s
  9. rook-ceph-osd-2 1 1 1 1 93s

Ceph Dashboard

Ceph Dashboard 를 외부에서 접속할 수 있게 해주는 Service 객체를 생성합니다.

rook/dashboard-external-http.yaml

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: rook-ceph-mgr-dashboard-external-http
  5. namespace: rook-ceph
  6. labels:
  7. app: rook-ceph-mgr
  8. rook_cluster: rook-ceph
  9. spec:
  10. ports:
  11. - name: dashboard
  12. port: 7000
  13. protocol: TCP
  14. targetPort: 7000
  15. nodePort: 30001
  16. selector:
  17. app: rook-ceph-mgr
  18. rook_cluster: rook-ceph
  19. sessionAffinity: None
  20. type: NodePort

외부에서 Dashboard 에 접속할 수 있게 NodePort 를 할당합니다.

  1. kubectl create -f rook/dashboard-external-http.yaml
  2. service/rook-ceph-mgr-dashboard-external-http created

생성한 Service 객체를 확인합니다.

  1. kubectl get svc -n rook-ceph
  2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  3. rook-ceph-mgr ClusterIP 10.103.51.139 <none> 9283/TCP 7m21s
  4. rook-ceph-mgr-dashboard ClusterIP 10.96.111.38 <none> 7000/TCP 7m20s
  5. rook-ceph-mgr-dashboard-external-http NodePort 10.99.153.69 <none> 7000:30001/TCP 37s
  6. rook-ceph-mon0 ClusterIP 10.100.187.206 <none> 6790/TCP 7m46s
  7. rook-ceph-mon1 ClusterIP 10.100.234.23 <none> 6790/TCP 7m36s

클러스터만 선언한 Ceph 상태를 보여주는 화면입니다.

ceph-dashboard

동작 중인 OSD Daemon 목록과 각 OSD 별 용량을 볼 수 있습니다.

ceph-osd

Ceph Storages provide by Rook

Rook 을 통해서 Ceph 의 세 가지 저장소를 Kubernetes 에서 사용할 수 있습니다.

Type Description Access
Block Storage 하나의 Pod 만 사용할 수 있는 저장소 Inside
Shared File System 여러 Pod 이 공유할 수 있는 저장소 Inside
Object Storage S3 API 를 통해 어플리케이션이 사용할 수 있는 저장소 Inside, Outside

Provison Storage

Ceph 저장소를 Kubernetes 에서 사용하기 위해 StorageClass 를 등록합니다. Kubernetes 는 PersistentVolume 을 생성할 때 미리 등록해둔 StorageClass 를 이용해 Ceph 저장소를 생성합니다.

rook/storageclass.yaml

  1. apiVersion: ceph.rook.io/v1beta1
  2. kind: Pool
  3. metadata:
  4. name: replicapool
  5. namespace: rook-ceph
  6. spec:
  7. replicated:
  8. size: 2
  9. ---
  10. apiVersion: storage.k8s.io/v1
  11. kind: StorageClass
  12. metadata:
  13. name: rook-ceph-block
  14. provisioner: ceph.rook.io/block
  15. parameters:
  16. pool: replicapool
  17. clusterNamespace: rook-ceph
  18. fstype: xfs

위에서 지정한 Replicapool 은 두 개의 복제본을 유지합니다.

  1. kubectl create -f rook/storageclass.yaml
  2. pool.ceph.rook.io/replicapool created
  3. storageclass.storage.k8s.io/rook-ceph-block created

생성한 StorageClass 는 이후에 어플리케이션을 독립적인 Persistent Volume 에 붙여서 배포할 때 사용합니다.

Create Shared File System

여러 Pod 이 동시에 공유해서 사용할 파일 시스템을 생성합니다. rook/operator.yaml 파일 속성 중에 ROOK_ALLOW_MULTIPLE_FILESYSTEMS 값을 “true” 로 지정하였다면, 두 개 이상의 파일 시스템을 생성해서 사용할 수 있습니다.

rook/filesystem.yaml

  1. apiVersion: ceph.rook.io/v1beta1
  2. kind: Filesystem
  3. metadata:
  4. name: k8s-fs
  5. namespace: rook-ceph
  6. spec:
  7. metadataPool:
  8. replicated:
  9. size: 2
  10. dataPools:
  11. - failureDomain: osd
  12. replicated:
  13. size: 2
  14. metadataServer:
  15. activeCount: 1
  16. activeStandby: true
  17. placement:
  18. resources:

k8s-fs 이름을 가진 File System 을 생성합니다.

  1. kubectl create -f rook/filesystem.yaml
  2. filesystem.ceph.rook.io/k8s-fs created

생성한 File System 을 Ceph Dashboard 화면에서 확인할 수 있습니다.

ceph-filesystem

파일 시스템 상세 페이지에서 세부적인 내용을 살펴볼 수 있습니다.

ceph-filesystem-2

Extend Ceph Storage

Ceph 클러스터 디스크 공간을 확장해보겠습니다. 앞에서 Ceph 클러스터를 생성할 때 사용한 cluster.yaml 파일을 열어 각 노드에서 사용할 디스크 장치를 추가합니다.

rook/cluster.yaml

  1. ...
  2. storage:
  3. useAllNodes: false
  4. useAllDevices: false
  5. deviceFilter:
  6. location:
  7. config:
  8. storeType: bluestore
  9. databaseSizeMB: "512"
  10. journalSizeMB: "512"
  11. nodes:
  12. - name: "k8s-1"
  13. devices:
  14. - name: "sdc"
  15. - name: "sdd"
  16. - name: "k8s-2"
  17. devices:
  18. - name: "sdc"
  19. - name: "sdd"
  20. - name: "k8s-3"
  21. devices:
  22. - name: "sdc"
  23. - name: "sdd"

Rook 을 통해 Ceph 클러스터 공간을 확장합니다.

  1. kubectl apply -f rook/cluster.yaml
  2. namespace/rook-ceph unchanged
  3. serviceaccount/rook-ceph-cluster unchanged
  4. role.rbac.authorization.k8s.io/rook-ceph-cluster unchanged
  5. rolebinding.rbac.authorization.k8s.io/rook-ceph-cluster-mgmt unchanged
  6. rolebinding.rbac.authorization.k8s.io/rook-ceph-cluster unchanged
  7. cluster.ceph.rook.io/rook-ceph configured

Ceph Dashboard 를 통해 공간이 늘어난 것을 확인할 수 있습니다.

ceph-extend

Rook Toolbox

Rook Toolbox 는 Ceph 를 관리하는 데 필요한 다양한 도구들을 미리 설치해둔 컨테이너입니다. Toolbox 를 이용해 Ceph 클러스터 설정을 직접 살펴보고 변경할 수 있습니다.

Rook Toolbox 를 Kubernetes 에 배포합니다.

  1. kubectl create -f rook/toolbox.yaml
  2. deployment.apps/rook-ceph-tools created

Toolbox 이미지를 받아서 실행되는지 확인합니다.

  1. kubectl -n rook-ceph get pods -w
  2. NAME READY STATUS RESTARTS AGE
  3. rook-ceph-mds-k8s-fs-5f87c5fb64-57qzn 1/1 Running 0 51m
  4. rook-ceph-mds-k8s-fs-5f87c5fb64-btftv 1/1 Running 0 51m
  5. rook-ceph-mgr-a-5f6dd98574-x5kgf 1/1 Running 0 74m
  6. rook-ceph-mon0-jwxdk 1/1 Running 0 18m
  7. rook-ceph-mon1-tdlcr 1/1 Running 0 21m
  8. rook-ceph-osd-id-0-6bd66fc767-jwtk8 1/1 Running 0 74m
  9. rook-ceph-osd-id-1-5bc5c8459d-fjwhv 1/1 Running 0 74m
  10. rook-ceph-osd-id-2-68469f46bb-ln4m7 1/1 Running 0 74m
  11. rook-ceph-osd-id-3-7777db5b7c-sbt5q 1/1 Running 0 7m40s
  12. rook-ceph-osd-id-4-69b8fc69b6-dq5ks 1/1 Running 0 7m38s
  13. rook-ceph-osd-id-5-867f946f7f-h4mxm 1/1 Running 0 7m35s
  14. rook-ceph-osd-prepare-k8s-1-w8ptv 0/1 Completed 0 7m56s
  15. rook-ceph-osd-prepare-k8s-2-86js9 0/1 Completed 0 7m54s
  16. rook-ceph-osd-prepare-k8s-3-hd2tv 0/1 Completed 0 7m52s
  17. rook-ceph-tools-5bc8b8f97-d2h4n 1/1 Running 0 51s

Toolbox 가 실행되는 것을 확인한 후에 컨테이너에 접속합니다.

  1. kubectl -n rook-ceph exec -it rook-ceph-tools-5bc8b8f97-d2h4n bash

ceph, rados 등의 명령어를 이용해 Ceph 클러스터 설정을 확인하고 변경할 수 있습니다.

  1. [root@k8s-2 /]# ceph status
  2. cluster:
  3. id: af422e45-a3a0-488a-9888-50823aac830d
  4. health: HEALTH_WARN
  5. clock skew detected on mon.rook-ceph-mon1
  6. services:
  7. mon: 2 daemons, quorum rook-ceph-mon0,rook-ceph-mon1
  8. mgr: a(active)
  9. mds: k8s-fs-1/1/1 up {0=k8s-fs-5f87c5fb64-btftv=up:active}, 1 up:standby-replay
  10. osd: 6 osds: 6 up, 6 in
  11. data:
  12. pools: 3 pools, 300 pgs
  13. objects: 21 objects, 2246 bytes
  14. usage: 6181 MB used, 48724 MB / 54905 MB avail
  15. pgs: 300 active+clean
  16. io:
  17. client: 852 B/s rd, 2 op/s rd, 0 op/s wr
  1. [root@k8s-2 /]# ceph osd status
  2. +----+-------------------------------------+-------+-------+--------+---------+--------+---------+-----------+
  3. | id | host | used | avail | wr ops | wr data | rd ops | rd data | state |
  4. +----+-------------------------------------+-------+-------+--------+---------+--------+---------+-----------+
  5. | 0 | rook-ceph-osd-id-0-6bd66fc767-jwtk8 | 1030M | 8120M | 0 | 0 | 0 | 0 | exists,up |
  6. | 1 | rook-ceph-osd-id-1-5bc5c8459d-fjwhv | 1030M | 8120M | 0 | 0 | 1 | 90 | exists,up |
  7. | 2 | rook-ceph-osd-id-2-68469f46bb-ln4m7 | 1030M | 8120M | 0 | 0 | 0 | 0 | exists,up |
  8. | 3 | rook-ceph-osd-id-3-7777db5b7c-sbt5q | 1030M | 8120M | 0 | 0 | 0 | 0 | exists,up |
  9. | 4 | rook-ceph-osd-id-4-69b8fc69b6-dq5ks | 1030M | 8120M | 0 | 0 | 0 | 0 | exists,up |
  10. | 5 | rook-ceph-osd-id-5-867f946f7f-h4mxm | 1030M | 8120M | 0 | 0 | 1 | 16 | exists,up |
  11. +----+-------------------------------------+-------+-------+--------+---------+--------+---------+-----------+
  1. [root@k8s-2 /]# ceph df
  2. GLOBAL:
  3. SIZE AVAIL RAW USED %RAW USED
  4. 54905M 48724M 6181M 11.26
  5. POOLS:
  6. NAME ID USED %USED MAX AVAIL OBJECTS
  7. k8s-fs-metadata 1 2246 0 22988M 21
  8. k8s-fs-data0 2 0 0 22988M 0
  9. replicapool 3 0 0 22988M 0
  1. [root@k8s-2 /]# rados df
  2. POOL_NAME USED OBJECTS CLONES COPIES MISSING_ON_PRIMARY UNFOUND DEGRADED RD_OPS RD WR_OPS WR
  3. k8s-fs-data0 0 B 0 0 0 0 0 0 0 0 B 0 0 B
  4. k8s-fs-metadata 2.2 KiB 21 0 42 0 0 0 1190 595 KiB 44 8 KiB
  5. replicapool 0 B 0 0 0 0 0 0 0 0 B 0 0 B
  6. total_objects 21
  7. total_used 6.0 GiB
  8. total_avail 48 GiB
  9. total_space 54 GiB

Change Ceph configuration through Toolbox

Toolbox 컨테이너에 접속하여 현재 설정되어 있는 pg_num, pgp_num 값을 확인합니다.

  1. kubectl -n rook-ceph exec -it rook-ceph-tools-5bc8b8f97-d2h4n bash
  2. [root@k8s-2 /]# ceph osd lspools
  3. 1 k8s-fs-metadata,2 k8s-fs-data0,3 replicapool,
  4. [root@k8s-2 /]# ceph osd pool get k8s-fs-data0 pg_num
  5. pg_num: 100
  6. [root@k8s-2 /]# ceph osd pool get k8s-fs-data0 pgp_num
  7. pgp_num: 100

ceph osd pool set 명령을 이용해 pg_num, pgp_num 값을 150으로 변경합니다.

  1. [root@k8s-2 /]# ceph osd pool set k8s-fs-data0 pg_num 150
  2. set pool 2 pg_num to 150
  3. [root@k8s-2 /]# ceph osd pool set k8s-fs-data0 pgp_num 150
  4. set pool 3 pgp_num to 150
  5. [root@k8s-2 /]# ceph osd pool set replicapool pg_num 150
  6. set pool 3 pg_num to 150
  7. [root@k8s-2 /]# ceph osd pool set replicapool pgp_num 150
  8. set pool 1 pgp_num to 150

Dashboard 화면에서 변경된 값을 확인할 수 있습니다.

ceph-changed-status

Remove Ceph node

현재 세 대로 구성되어 있는 Ceph 클러스터에서 한 노드를 제거해보겠습니다. cluster.yaml 를 수정하여 삭제하려는 노드와 관련된 내용을 제거합니다.

rook/cluster.yaml

  1. ...
  2. storage:
  3. useAllNodes: false
  4. useAllDevices: false
  5. deviceFilter:
  6. location:
  7. config:
  8. storeType: bluestore
  9. databaseSizeMB: "512"
  10. journalSizeMB: "512"
  11. nodes:
  12. - name: "k8s-2"
  13. devices:
  14. - name: "sdc"
  15. - name: "sdd"
  16. - name: "k8s-3"
  17. devices:
  18. - name: "sdc"
  19. - name: "sdd"

Rook Operator 를 이용해 실제 Ceph 클러스터에 적용합니다.

  1. kubectl apply -f rook/cluster.yaml
  2. namespace/rook-ceph unchanged
  3. serviceaccount/rook-ceph-cluster unchanged
  4. role.rbac.authorization.k8s.io/rook-ceph-cluster unchanged
  5. rolebinding.rbac.authorization.k8s.io/rook-ceph-cluster-mgmt unchanged
  6. rolebinding.rbac.authorization.k8s.io/rook-ceph-cluster unchanged
  7. cluster.ceph.rook.io/rook-ceph configured

Ceph Dashboard 를 통해 노드가 삭제된 것을 확인할 수 있습니다.

ceph-reduced

OSD 데몬 화면에서 2개가 줄어들어 4개만 남아있는 것을 볼 수 있습니다.

ceph-reduced-osd

Deploy Application with Ceph

Deploy Minio

Minio 어플리케이션을 Shared File System 과 함께 배포해보겠습니다.

배포하기 전에 File System 안에 사용할 디렉토리를 먼저 만드는 것이 필요합니다. 여기에서는 간단하게 nginx 컨테이너 내부 /tmp/fs 디렉토리에 Share File System 을 붙인 후에 디렉토리를 생성합니다.

  1. kubectl create -f rook/nginx-fs-deploy.yaml
  2. deployment.apps/nginx-fs created

실행된 Pod 이름을 확인합니다.

  1. kubectl get pod
  2. NAME READY STATUS RESTARTS AGE
  3. nginx-fs-5bfc8dbf5f-5ggz8 1/1 Running 0 77s

kubectl exec 명령을 이용해 앞에서 실행한 Pod 에 접속해 필요한 디렉토리를 미리 생성해둡니다.

  1. rook$ kubectl exec -it nginx-fs-5bfc8dbf5f-5ggz8 /bin/bash
  2. root@nginx-fs-5bfc8dbf5f-5ggz8:/# cd /tmp/fs
  3. root@nginx-fs-5bfc8dbf5f-5ggz8:/tmp/fs# mkdir minio
  4. root@nginx-fs-5bfc8dbf5f-5ggz8:/tmp/fs# exit
  5. exit

minio/minio-deploy.yaml

  1. apiVersion: extensions/v1beta1
  2. kind: Deployment
  3. metadata:
  4. name: minio
  5. spec:
  6. template:
  7. metadata:
  8. labels:
  9. k8s-app: minio
  10. spec:
  11. containers:
  12. - name: minio
  13. volumeMounts:
  14. - name: minio-store
  15. mountPath: "/data"
  16. image: minio/minio
  17. args:
  18. - server
  19. - /data
  20. env:
  21. - name: MINIO_ACCESS_KEY
  22. value: "minio"
  23. - name: MINIO_SECRET_KEY
  24. value: "minio123"
  25. ports:
  26. - containerPort: 9000
  27. volumes:
  28. - name: minio-store
  29. flexVolume:
  30. driver: ceph.rook.io/rook
  31. fsType: ceph
  32. options:
  33. fsName: k8s-fs
  34. clusterNamespace: rook-ceph
  35. path: /minio

minio 를 클러스터에 배포합니다.

  1. kubectl create -f minio/minio-deploy.yaml
  2. deployment.extensions/minio created
  1. kubectl create -f minio/minio-svc.yaml
  2. service/minio-svc created

배포한 minio 저장소에 파일을 저장해보겠습니다.

minio

Deploy MySQL

MySQL 어플리케이션을 Block Storage 와 함께 배포해보겠습니다.

먼저 앞에서 생성한 StorageClass 이름으로 PersistentVolumeClaim 을 생성합니다.

mysql/mysql-pvc.yaml

  1. apiVersion: v1
  2. kind: PersistentVolumeClaim
  3. metadata:
  4. name: mysql-pvc
  5. labels:
  6. k8s-app: mysql
  7. spec:
  8. storageClassName: rook-ceph-block
  9. accessModes:
  10. - ReadWriteOnce
  11. resources:
  12. requests:
  13. storage: 5Gi
  1. kubectl create -f mysql/mysql-pvc.yaml
  2. persistentvolumeclaim/mysql-pvc created

MySQL 컨테이너에 앞에서 생성한 mysql-pvc 를 붙여줍니다.

mysql/mysql-deploy.yaml

  1. apiVersion: apps/v1beta1
  2. kind: Deployment
  3. metadata:
  4. name: mysql
  5. labels:
  6. k8s-app: mysql
  7. spec:
  8. strategy:
  9. type: Recreate
  10. template:
  11. metadata:
  12. labels:
  13. k8s-app: mysql
  14. spec:
  15. containers:
  16. - image: mysql:5.7
  17. name: mysql
  18. env:
  19. - name: MYSQL_ROOT_PASSWORD
  20. value: changeme
  21. ports:
  22. - containerPort: 3306
  23. name: mysql
  24. volumeMounts:
  25. - name: mysql-persistent-storage
  26. mountPath: /var/lib/mysql
  27. volumes:
  28. - name: mysql-persistent-storage
  29. persistentVolumeClaim:
  30. claimName: mysql-pvc
  1. kubectl create -f mysql/mysql-deploy.yaml
  2. deployment.apps/mysql created
  1. kubectl create -f mysql/mysql-svc.yaml
  2. service/mysql created

생성한 MySQL 서버에 접속하여 제대로 동작하고 있는지 확인해봅니다.

  1. kubectl get svc
  2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  3. kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 149m
  4. minio-svc NodePort 10.111.32.46 <none> 9000:30010/TCP 4m54s
  5. mysql-svc NodePort 10.102.219.47 <none> 3306:30020/TCP 42s

서비스 내용을 확인하고 mysql client 를 이용해 접속합니다.

  1. mysql -uroot -p -h 10.254.1.2 -P 30020
  2. Enter password:
  3. Welcome to the MySQL monitor. Commands end with ; or \g.
  4. Your MySQL connection id is 2
  5. Server version: 5.7.24 MySQL Community Server (GPL)
  6. Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
  7. Oracle is a registered trademark of Oracle Corporation and/or its
  8. affiliates. Other names may be trademarks of their respective
  9. owners.
  10. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
  11. mysql> show databases;
  12. +--------------------+
  13. | Database |
  14. +--------------------+
  15. | information_schema |
  16. | mysql |
  17. | performance_schema |
  18. | sys |
  19. +--------------------+
  20. 4 rows in set (0.01 sec)

Deploy Ghost

Ghost 어플리케이션에서 사용할 디렉토리를 Share File System 에 미리 생성해둡니다.

  1. kubectl exec -it nginx-fs-5bfc8dbf5f-5ggz8 /bin/bash
  2. root@nginx-fs-5bfc8dbf5f-5ggz8:/# cd /tmp/fs
  3. root@nginx-fs-5bfc8dbf5f-5ggz8:/tmp/fs# mkdir ghost
  4. root@nginx-fs-5bfc8dbf5f-5ggz8:/tmp/fs# ls -al
  5. total 4
  6. drwxr-xr-x 1 root root 2 Nov 18 15:35 .
  7. drwxrwxrwt 1 root root 4096 Nov 18 15:05 ..
  8. drwxr-xr-x 1 root root 0 Nov 18 15:35 ghost
  9. drwxr-xr-x 1 root root 2 Nov 18 15:15 minio

MySQL 에 접속하여 사용할 데이터베이스를 생성합니다.

  1. mysql -uroot -p -h 10.254.1.2 -P 30020
  2. Enter password:
  3. Welcome to the MySQL monitor. Commands end with ; or \g.
  4. Your MySQL connection id is 4
  5. Server version: 5.7.24 MySQL Community Server (GPL)
  6. Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
  7. Oracle is a registered trademark of Oracle Corporation and/or its
  8. affiliates. Other names may be trademarks of their respective
  9. owners.
  10. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
  11. mysql> create database ghost;
  12. Query OK, 1 row affected (0.02 sec)

PersistentVolume 과 Database 생성을 완료한 후에 Ghost 어플리케이션을 배포합니다.

ghost/ghost-deploy.yaml

  1. apiVersion: apps/v1beta1
  2. kind: Deployment
  3. metadata:
  4. name: ghost
  5. spec:
  6. template:
  7. metadata:
  8. labels:
  9. k8s-app: ghost
  10. spec:
  11. containers:
  12. - name: ghost
  13. volumeMounts:
  14. - name: ghost-volume
  15. mountPath: "/var/lib/ghost/content"
  16. image: ghost:2
  17. env:
  18. - name: database__client
  19. value: "mysql"
  20. - name: database__connection__host
  21. value: "mysql-svc"
  22. - name: database__connection__user
  23. value: "root"
  24. - name: database__connection__database
  25. value: "ghost"
  26. - name: database__connection__password
  27. value: "changeme"
  28. - name: url
  29. value: "http://10.254.1.2:30030"
  30. ports:
  31. - containerPort: 2368
  32. volumes:
  33. - name: ghost-volume
  34. flexVolume:
  35. driver: ceph.rook.io/rook
  36. fsType: ceph
  37. options:
  38. fsName: k8s-fs
  39. clusterNamespace: rook-ceph
  40. path: /ghost

Ghost 어플리케이션을 배포합니다.

  1. kubectl create -f ghost/ghost-deploy.yaml
  2. deployment.apps/ghost created

외부에서 접속할 수 있도록 Service 를 생성합니다.

  1. kubectl create -f ghost/ghost-svc.yaml
  2. service/ghost-svc created

Ghost 어플리케이션이 배포된 것을 확인합니다.

  1. kubectl get deploy ghost
  2. NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
  3. ghost 1 1 1 1 6m9s

배포가 완료된 후 웹 페이지에 접속하여 확인합니다.

ghost

MySQL 에 테이블이 제대로 생성되었는지 확인해봅니다.

  1. mysql -uroot -p -h 10.254.1.2 -P 30020
  2. Enter password:
  3. Welcome to the MySQL monitor. Commands end with ; or \g.
  4. Your MySQL connection id is 27
  5. Server version: 5.7.24 MySQL Community Server (GPL)
  6. Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
  7. Oracle is a registered trademark of Oracle Corporation and/or its
  8. affiliates. Other names may be trademarks of their respective
  9. owners.
  10. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
  11. mysql> use ghost;
  12. Reading table information for completion of table and column names
  13. You can turn off this feature to get a quicker startup with -A
  14. Database changed
  15. mysql> show tables;
  16. +------------------------+
  17. | Tables_in_ghost |
  18. +------------------------+
  19. | accesstokens |
  20. | api_keys |
  21. | app_fields |
  22. | app_settings |
  23. | apps |
  24. | brute |
  25. | client_trusted_domains |
  26. | clients |
  27. | integrations |
  28. | invites |
  29. | migrations |
  30. | migrations_lock |
  31. | mobiledoc_revisions |
  32. | permissions |
  33. | permissions_apps |
  34. | permissions_roles |
  35. | permissions_users |
  36. | posts |
  37. | posts_authors |
  38. | posts_tags |
  39. | refreshtokens |
  40. | roles |
  41. | roles_users |
  42. | sessions |
  43. | settings |
  44. | subscribers |
  45. | tags |
  46. | users |
  47. | webhooks |
  48. +------------------------+
  49. 29 rows in set (0.00 sec)

Summary

Kubernetes 클러스터를 이용해 어플리케이션을 배포할 때 CephPersistent Storage 로 활용하는 실습을 진행하였습니다. HostPath Volume 을 이용할 경우에는 어플리케이션이 특정한 노드에서 동작해야 하기 때문에 Kubernetes 클러스터를 적극 활용하는데 제약을 받을 수 있습니다. Ceph 의 Shared File System 을 이용해 여러 컨테이너에서 공유할 공간으로 사용하거나, Block Storage 를 생성해 특정 컨테이너를 위한 전용 저장 공간을 붙여 사용할 수도 있습니다.

실습 내용에 대하여 부족하거나 보완해야할 점이 있다면 있다면 메일로 보내주세요. 감사합니다.

임찬식 (chanshik@gmail.com)