Kubernetes-Masterclass | YAML , EBS

YAML & EBS
김주혁's avatar
Aug 05, 2024
Kubernetes-Masterclass | YAML , EBS
 

Yaml introduction

 
k8s에서 선언형 manifest를 작성하려면, yaml을 이해해야 한다.
 
  • YAML은 마크업 언어가 아닙니다.
  • YAML은 다양한 정보들을 저장하는 데 사용됩니다.
  • YAML을 사용하여 변수, 리스트 및 객체와 같은 키-값 쌍을 정의할 수 있습니다.
  • YAML은 JSON(JavaScript Object Notation)과 매우 유사합니다.
  • YAML은 가독성과 사용자 친화성에 중점을 둡니다.
  • YAML은 깨끗하고 읽기 쉽게 설계되었습니다.
  • YAML 파일은 .yml 또는 .yaml 확장자로 정의할 수 있습니다. 둘 다 사용 가능합니다.
 
YAML에서 주석을 정의하려면 해시(#)를 사용하고, 키-값 쌍은 key: value 형식으로 작성한다. 콜론(:) 다음에 공백이 있어야 키와 값을 구분할 수 있다. 공백이 중요한 역할을 한다. 공백이 없으면 키와 값을 구분하기 어렵다.
 

Dictinary / Map

person: name: kalyan age: 23 city: Hyderabad
 

Array / Lists

person: # Dictionary name: kalyan age: 23 city: Hyderabad hobbies: # List - cycling - cookines hobbies: [cycling, cooking] # List with a differnt notation
 

Multiple Lists

person: # Dictionary name: kalyan age: 23 city: Hyderabad hobbies: # List - cycling - cooking hobbies: [cycling, cooking] # List with a differnt notation friends: # - name: friend1 age: 22 - name: friend2 age: 25
 

Sample Pod Tempalte for Reference

apiVersion: v1 # String kind: Pod # String metadata: # Dictionary name: myapp-pod labels: # Dictionary app: myapp spec: containers: # List - name: myapp image: stacksimplify/kubenginx:1.0.0 ports: - containerPort: 80 protocol: "TCP" - containerPort: 81 protocol: "TCP"
 

Kubernetes & Yaml

 
Kubernetes에서 최상위 YAML 항목은
  • API 버전
  • 종류(kind)
  • 메타데이터(metadata) 및
    • 메타데이터(metadata)에서 핵심 요소는 이름(name)과 라벨(labels)이다.
    • 메타데이터의 라벨(labels) 섹션에서는 원하는 키-값 쌍을 정의할 수 있다. 그러나 이름(name)은 모든 Kubernetes 객체를 생성할 때 필수로 포함해야 한다.
    • 네임스페이스(namespace)와 같은 추가 설정도 정의하게 된다. 그러나 핵심적으로 이름(name)과 라벨(labels)은 항상 필수적으로 채워야 하는 항목이다.
    • 메타데이터 항목을 잘 정의하면 장기적으로 유용하며, 특히 Kubernetes 객체를 정의할 때 항상 이름과 라벨을 포함하는 것이 좋은 방법이다.
  • 스펙(spec) 이다.
    • spec에서는 세 가지가 중요하다:
    • type
      • type은 로드 밸런서를 사용하면 LoadBalancer
      • 외부 이름 서비스를 사용하면 externalName
      • Cluster IP를 정의하면 ClusterIP 라고 정의할 수 있다.
      • 여기선 노드포트를 정의하기 때문에 NodePort라고 정의했다.
    • selector
      • selector는 포트와 라벨 및 선택기를 사용하여 트래픽을 로드 밸런싱하는 데 사용된다. 이 서비스로 들어오는 트래픽을 라벨 Selector와 일치하는 포트에 라우팅한다. 즉, 이 서비스로 들어오는 모든 트래픽을 이 라벨 Selector를 기반으로 해당 포트로 보내게 된다. 그래서 선택기에 정의된 모든 라벨들은 해당 포드로 트래픽을 보내는 데 사용된다.
      • 트래픽은 selector 값과 일치하는 label을 가진 포드로 분배된다.
      • # pod create lables labels: # Dictionary app: myapp # service selector selector: app: myapp
    • port
  • 네임스페이스(namespace)와 같은 추가 설정도 정의하게 된다. 그러나 핵심적으로 이름(name)과 라벨(labels)은 항상 필수적으로 채워야 하는 항목이다. 메타데이터 항목을 잘 정의하면 장기적으로 유용하며, 특히 Kubernetes 객체를 정의할 때 항상 이름과 라벨을 포함하는 것이 좋은 방법이다.
    • apiVersion: v1 # String kind: Pod # String metadata: # Dictionary name: myapp-pod labels: # Dictionary app: myapp spec: containers: # List - name: myapp image: stacksimplify/kubenginx:1.0.0 ports: - containerPort: 80
 
Kubernetes의 모든 것은 객체다. 여기서 다루는 핵심 객체는
  • 포드(pod)
    • 참고로 파드를 생성할 때 직접적으로 생성하는 것이 아닌 컨트롤러를 통하여 생성하라고 되어있다.
      • Deployment
      • Job
      • StatefulSet이 있다.
  • 레플리카셋(replica set),
  • 디플로이먼트(deployment),
  • 서비스(service) 등이 있다.
각 YAML 정의는 해당 Kubernetes 객체를 정의한다.
 

Create ReplicaSet

 
apiVersion: apps/v1 kind: ReplicaSet metadata: name: myapp2-rs spec: replicas: 3 selector: matchLabels: app: myapp2 template: metadata: # Dictionary name: myapp2-pod labels: # Dictionary app: myapp2 spec: containers: # List - name: myapp2-container image: stacksimplify/kubenginx:2.0.0 ports: - containerPort: 80
중요한 것은, 셀렉터의 matchLables이다. ReplicaSet을 생성할 때 selectormatchLabels는 ReplicaSet이 관리할 포드를 식별하는 데 사용되는 라벨 셋을 의미한다. ReplicaSet이 어떤 포드를 관리하고, 어떤 포드를 대상으로 동작할지 결정하는 기준이 된다.
  • 포드 선택: matchLabels는 특정 키-값 쌍을 기반으로 포드를 선택합니다. ReplicaSet은 이 라벨 셋과 일치하는 포드만 관리합니다.
  • 스케일링: ReplicaSet은 지정된 라벨과 일치하는 포드의 수를 유지합니다. 만약 포드 수가 설정된 복제본 수보다 적다면 새로운 포드를 생성하고, 많다면 초과된 포드를 종료합니다.
 
강의에서 이후 에 대부분 이전의 반복이기 때문에 중요하게 살펴볼만한 것은 없지만, 한 가지를 본다면 tier다.
tier 라벨은 Kubernetes에서 애플리케이션의 계층(티어)을 나타내는 데 사용되는 일반적인 라벨이다. 이는 애플리케이션 구조에서 특정 역할이나 기능을 명확히 구분하는 데 도움이 된다.
  1. Frontend:
      • 사용자 인터페이스와 직접 상호 작용하는 계층입니다.
      • 웹 서버나 모바일 앱의 프론트엔드 컴포넌트 등이 해당됩니다.
  1. Backend:
      • 비즈니스 로직을 처리하는 계층입니다.
      • 데이터베이스 서버와의 상호작용, API 처리, 데이터 처리 등을 담당합니다.
  1. Database:
      • 데이터를 저장하고 관리하는 계층입니다.
      • MySQL, PostgreSQL 등의 데이터베이스 서버가 포함됩니다.
 
 

 

EKS Hosted Applications Storage with AWS EBS - Elastic Block Store

 

EKS Storage

 
EKS 스토리지에는 다양한 종류의 드라이버와 프로비저너가 있다.
 
  • In-Tree EBS Provisioner
    • 레거시이며, 곧 지원이 중단될 예정
  • EBS CSI Driver
    • 주로 사용할 드라이버
  • EFS CSI Driver
    • 주로 사용할 드라이버
  • FSx for Luster CSI
    • 주로 사용할 드라이버
 
CSI는 Container Storage Interface를 의미한다.
EBS는 Persistant Volume을 위한 Elastic block storage이다. EBS CSI 드라이버를 사용할 수 있으며, 또한 AWS에서 완전히 관리하는 파일 시스템인 Elastic 파일 시스템(EFS)을 사용할 수 있다. EFS CSI 드라이버를 사용할 수 있으며, 일반적인 FSX 4 클러스터 CSI도 Windows 파일 시스템용으로 제공된다.
 
EBS는 EC2 및 컨테이너 인스턴스와 함께 사용할 수 있는 블록 수준 스토리지 볼륨을 제공한다. 인스턴스에 연결된 EBS 볼륨은 EC2 또는 컨테이너 인스턴스의 수명과 독립적으로 지속된다. 간단히 말해, EC2 인스턴스를 종료하거나 컨테이너 인스턴스 또는 해당 Kubernetes 파드가 종료되더라도 볼륨은 독립적으로 유지된다. 따라서 볼륨에 저장된 데이터에 대해 걱정할 필요가 없다.
 
인스턴스에 연결된 볼륨의 구성을 동적으로 변경할 수 있다. 볼륨의 크기를 늘리거나 줄일 수 있다. AWS는 빠르게 접근해야 하고 장기적으로 저장해야 하는 데이터에 EBS를 권장한다. EBS는 무작위 읽기 및 쓰기가 필요한 데이터베이스 스타일 애플리케이션과 장기간 연속적인 읽기 및 쓰기를 수행하는 처리 집약적인 애플리케이션 모두에 적합하다.
 

Install CSI Driver

 
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ec2:AttachVolume", "ec2:CreateSnapshot", "ec2:CreateTags", "ec2:CreateVolume", "ec2:DeleteSnapshot", "ec2:DeleteTags", "ec2:DeleteVolume", "ec2:DescribeInstances", "ec2:DescribeSnapshots", "ec2:DescribeTags", "ec2:DescribeVolumes", "ec2:DetachVolume" ], "Resource": "*" } ] } # Get Worker node IAM Role ARN kubectl -n kube-system describe configmap aws-auth # from output check rolearn rolearn: 그 때마다 바뀐다.
먼저 iam을 생성해서 arn에 정책을 연결해줘야 한다. 그리고 kubernetes 버전을 확인해야 하는데 1.14이상이여야 한다. 버전이 문제가 없다면 CSI Driver를 설치한다.
 
# Deploy EBS CSI Driver kubectl apply -k "github.com/kubernetes-sigs/aws-ebs-csi-driver/deploy/kubernetes/overlays/stable/?ref=master"
 

Storage Class

 
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: ebs-sc provisioner: ebs.csi.aws.com volumeBindingMode: WaitForFirstConsumer
  • 스토리지 클래스는 storage.k8s.io로 시작한다.
  • spec 키 대신, provisioner를 사용한다.
  • 또 중요한 것은 volumeBindingMode이다.
    • volumeBindingMode는 Kubernetes에서 PersistentVolumePersistentVolumeClaim에 바인딩될 시점을 제어하는 속성이다.
    • volumeBindingMode에는 두 가지 옵션이 있다.
      • Immediate: PersistentVolumeClaim이 생성되면 즉시 PersistentVolume에 바인딩된다. 이 모드는 클러스터 전체에서 사용 가능한 모든 PersistentVolume을 고려하며, 특정 노드에 대한 제약이 없다.
      • WaitForFirstConsumer: PersistentVolumeClaim이 특정 파드에 연결되기 전까지 PersistentVolume에 바인딩되지 않는다. 이는 스케줄러가 파드를 특정 노드에 할당할 때까지 기다렸다가 그 노드에 접근 가능한 PersistentVolume을 바인딩한다. 이 모드는 클러스터가 멀티 존으로 구성된 경우에 유용하며, 데이터 로컬리티와 자원 최적화를 도와준다.
    • WaitForFirstConsumer 모드는 PersistentVolumeClaim를 사용하는 Pod가 생성될 때까지 PersistentVolume의 바인딩 및 프로비저닝을 지연시킨다.
    • 스토리지 클래스를 생성하고 퍼시스턴트 볼륨 클레임을 생성할 때 WaitForFirstConsumer모드를 선택하지 않는다면, 볼륨이 즉시 동적으로 프로비저닝되고 마운트된다. 어느 가용 영역에서 프로비저닝되는지 알 수 없다. 동적이기 때문이다. 나중에 파드를 생성할 때 볼륨이 다른 가용 영역에 마운트되면 문제가 발생한다. 따라서 파드가 생성될 때 볼륨이 동일한 가용 영역에서 프로비저닝되도록 만들어 준다. 이는 중요한 문제다.
 

Persistant Volume Claim

 
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: ebs-mysql-pv-claim spec: accessModes: - ReadWriteOnce storageClassName: ebs-sc resources: requests: storage: 4Gi
 

ConfigMap

apiVersion: v1 kind: ConfigMap metadata: name: usermanagement-dbcreation-script data: mysql_usermgmt.sql: |- DROP DATABASE IF EXISTS usermgmt; CREATE DATABASE usermgmt;
 
ConfigMap은 필요한 구성을 파드에 전달하는 데 사용된다. 이 ConfigMap 파일을 통해 배포 파일에 마운트할 수 있게 됐다.
 

 
# Create Storage Class & PVC kubectl apply -f mysql-manifests/ storageclass.storage.k8s.io/ebs-sc created persistentvolumeclaim/ebs-mysql-pv-claim created configmap/usermanagement-dbcreation-script create # List Storage Classes kubectl get sc # List PVC kubectl get pvc # List PV kubectl get pv
이제 만든 메니페스트 파일들을 실행시키면 pv는 아직 생성되지 않았다. 파드가 생성될 때까지 볼륨이 바인딩되지 않는다.
 

MySQL Deployment

 
apiVersion: apps/v1 kind: Deployment metadata: name: mysql spec: replicas: 1 selector: matchLabels: app: mysql strategy: type: Recreate template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:5.6 env: - name: MYSQL_ROOT_PASSWORD value: dbpassword11 ports: - containerPort: 3306 name: mysql volumeMounts: - name: mysql-persistent-storage mountPath: /var/lib/mysql - name: usermanagement-dbcreation-script mountPath: /docker-entrypoint-initdb.d #https://hub.docker.com/_/mysql Refer Initializing a fresh instance volumes: - name: mysql-persistent-storage persistentVolumeClaim: claimName: ebs-mysql-pv-claim - name: usermanagement-dbcreation-script configMap: name: usermanagement-dbcreation-script
  • mysql deployment spec은 3가지 최상위 객체를 가진다.
    • replicas
    • selector
    • pod 템플릿을 작성할 때 사용할 template이 있다.
  • strategy: type: Recreate
    • 데이터베이스이기 때문에, Pod가 다시 생성될 때마다 재생성될 것이다. 이는 항상 하나의 복제본(replica)만 있을 것이며, 롤링 업데이트가 필요 없기 때문이다.
  • metadata에는 pod의 이름을 정의할 필요가 없다. label 정의만으로 충분하다.
    • Pod 이름 자동 생성: Kubernetes는 Deployment, StatefulSet, ReplicaSet 등과 같은 리소스를 사용할 때 각 Pod의 이름을 자동으로 생성
    • 템플릿의 재사용성: Pod의 이름을 템플릿에서 명시적으로 정의하지 않으면, 동일한 템플릿을 여러 번 재사용할 수 있다. 이로 인해 동일한 템플릿을 기반으로 하는 여러 Pod가 생성될 때 충돌을 방지할 수 있다.
    • 레이블을 통한 관리: 레이블을 사용하면 특정 Pod를 식별하고 관리하는 데 충분하다. Kubernetes는 레이블 셀렉터를 사용하여 특정 레이블이 있는 Pod를 선택하고 작업을 수행할 수 있다.
    • 유연한 업데이트 및 확장성: 이름을 정의하지 않으면 Kubernetes가 Pod를 유연하게 생성, 업데이트, 삭제할 수 있다.
  • kubernetes fundamental에서는 컨테이너만 있었지만, 여기선 볼륨도 있다.
  • volume에선 다른 메니페스트 스크립트에서 정의한
    • volumes: - name: mysql-persistent-storage persistentVolumeClaim: claimName: ebs-mysql-pv-claim - name: usermanagement-dbcreation-script configMap: name: usermanagement-dbcreation-script
    • volumeMounts 추가하는 이유
      • volumeMounts: - name: mysql-persistent-storage mountPath: /var/lib/mysql - name: usermanagement-dbcreation-script mountPath: /docker-entrypoint-initdb.d
      • 컨테이너에 데이터를 저장하거나 데이터를 제공하기 위해 특정 디렉토리를 마운트하기 위함이다.
        • 데이터 지속성: 컨테이너는 기본적으로 휘발성 스토리지를 사용하므로, 컨테이너가 삭제되면 데이터도 함께 사라진다. Persistent Volume을 사용하여 데이터를 마운트하면, 컨테이너의 라이프사이클과 관계없이 데이터를 지속적으로 유지할 수 있다.
        • 초기화 및 설정 자동화: 초기화 스크립트를 마운트하면 데이터베이스 초기화 및 설정 작업을 자동화할 수 있다. 이를 통해 수동으로 스크립트를 실행하는 번거로움을 줄이고, 일관된 초기화 과정을 보장할 수 있다.
        • 운영 효율성: 데이터와 초기화 스크립트를 별도의 볼륨으로 관리하면 운영 효율성이 높아집니다. 데이터베이스 업데이트나 백업, 복구 작업이 용이해진다.
      • Persistent Storage:
        • 목적: MySQL 데이터베이스의 데이터를 영구적으로 저장하기 위함이다.
        • 설명: MySQL 컨테이너는 기본적으로 /var/lib/mysql 디렉토리에 데이터를 저장한다. 이 디렉토리를 Persistent Volume에 마운트하면, 컨테이너가 재시작되거나 삭제되어도 데이터가 손실되지 않는다. 이는 데이터베이스의 데이터를 지속적으로 유지하고, 장애 발생 시에도 데이터를 보호하기 위해 필수적이다.
      • Initialization Script:
        • 목적: 초기화 스크립트를 제공하여 MySQL 데이터베이스를 초기화하거나 스키마를 생성하기 위함이다.
        • 설명: MySQL Docker 이미지는 /docker-entrypoint-initdb.d 디렉토리에 있는 모든 .sh, .sql, .sql.gz 파일을 컨테이너 시작 시 실행한다. 이 디렉토리에 초기화 스크립트를 마운트하면, 데이터베이스가 처음 시작될 때 스크립트가 자동으로 실행되어 데이터베이스를 초기화하거나 기본 스키마를 설정할 수 있다.
  • MySQL 배포는 언제나 하나의 파드만 가지기 때문에, clusterIP를 None으로 하여 네트워크에 별도 IP를 할당하지 않도록 한다.
Share article
RSSPowered by inblog