Fairy ' s

[K8s] Imperative vs Declarative 본문

Study/K8s

[K8s] Imperative vs Declarative

berafairy 2023. 8. 8. 23:51

 

 쿠버네티스 인프라를 관리하는 것은 imperative(명령형) 접근 방식과 declarative(선언적) 접근 방식으로 분류할 수 있다.


Provisioning Infrastructure

Imperative : ' How ' 를 중요하게 두는 방식

  • Provision a VM by the name 'web server'
  • Install NGINX software on it
  • Edit configuration file to use port '8080'
  • Edit configuration file to web path '/var/www/nginx'
  • Load web pages to 'var/www/nginx' from Git Repo - X
  • Starting NGINX server

 무엇이 필요한지, 그것을 완료하려면 어떻게 해야 하는지 선언한다.

 오브젝트를 만들고, 삭제하고 수정하는 등의 관리에 대한 니즈를 어떻게 해야 하는지 인프라에게 정확하게 말하는 것이 Imperative 방식이다. yaml 파일을 다룰 필요가 없기 때문에 빠르게 오브젝트를 만들고 수정하는 데에 도움이 된다.

# Create Objects
$ kubectl create -f nginx.yaml
$ kubectl run --image=nginx nginx
$ kubectl expose deployment nginx --port 80

# Update Objects
$ kubectl edit deployment nginx
$ kubectl scale deployment nginx --replicas=5
$ kubectl set image deployment nginx nginx=nginx:1.18
$ kubectl replace -f nginx.yaml
$ kubectl replace --force -f nginx.yaml

# Delete Objects
$ kubectl delete -f nginx.yaml

 그러나 기능이 제한적이고 multi-container 파드나 deployment를 생성하는 것과 같이 advanced case의 경우 복잡한 커맨드를 작성해야 한다. 이러한 커맨드를 실행했던 사람의 세션 기록에서만 볼 수 있기 때문에 다른 사람이 이 오브젝트가 어떻게 만들어졌는지 알거나 트래킹하기가 어렵다

 또한, Imperative 접근 방식은 항상 현재 구성을 알고 있어야 하고, 변경 전 모든 것이 제자리에 있는 지 체크 해야 하므로 관리자에게 매우 부담이 된다.

 커맨드로 리소스를 생성했을 경우, 향후 변경 사항이 생기게 되면 처리할 수 있는 방법이 여러가지가 있다. 

1. kubectl edit

 이 커맨드가 실행되면 yaml definition file이 열리는데, 이 파일은 쿠버네티스 메모리에 있는 유사한 Pod definition file이다. 우리는 이 파일을 변경할 수 있으며, 저장하고 종료할 수 있다. 변경 사항은 live object에 적용되지만, live object와 로컬에 있는 definition file 사이에는 차이가 있으니 주의해야 한다.

 이 커맨드를 사용해 만든 변경사항은 실제로 어디에도 기록되지 않고, 변경이 적용되면 로컬 definition file만 남는데, 이 definition file에는 변경사항이 적용되지 않은 예전 버전이다. 향후 팀원이 kubectl edit를 이용해 오브젝트가 변경된 사실을 모르고 오브젝트를 변경하게 되면, 이전 버전의 image는 손실된다. 따라서 kubectl edit 커맨드는 자신이 더 이상 configuration file을 의존하지 않을 것이라고 확신할 때 사용해야 한다. 그러므로 마땅히 좋은 방법은 아니다.

 

2. kubectl replace / 로컬 버전 configuration file 수정

 image 이름을 configuration file에서 먼저 수정하고, kubectl replace를 실행해 오브젝트를 업데이트하는 방식이다. 이렇게 하면 변경사항이 기록되고, 변경 프로세스의 일부로 추적할 수 있다. 가끔 오브젝트를 완전히 삭제하고 다시 만들어야 할 때가 있는데, 이 경우 force 옵션과 함께 동일한 커맨드를 실행한다.

 replace 커맨드를 실행하기 전에 오브젝트가 존재하는지 항상 먼저 확인해야 한다. 오브젝트가 존재하지 않으면 에러 메시지와 함게 실패한다.


Declarative : ' What ' 을 중요하게 두는 방식

  • VM Name : web-server
  • Package : nginx
  • Port : 8080
  • Path : /var/www/nginx
  • Code: Git Repo - X

 요구 사항을 선언한다. 이러한 요구 사항에 대한 작업은 시스템이나 소프트웨어(Ansible, Puppet, Chef, Terraform 같은 오케스트레이션 툴)가 수행한다. Declarative 방식은 시스템이 지능적이기 때문에 이미 벌어진 일을 알고 있으며, 필요한 변경 사항만 적용한다.

 애플리케이션 및 서비스의 예상되는 상태를 정의하는 file 세트를 만드는 것이 Declarative 방식이다. 이 방식에서 쿠버네티스는 단 하나의 커맨드(apply)로 configuration file을 읽을 수 있어야 한다. 그리고 인프라를 예상되는 상태로 만들기 위해 해야 할 일을 스스로 결정한다. 따라서 오브젝트를 만들고, 수정하고, 삭제하기 위해 다음 커맨드를 실행한다.

# Create, Update Objects
$ kubectl apply -f nginx.yaml
$ kubectl apply -f /path/to/config-files

 apply 커맨드는 아직 존재하지 않는 객체를 생성할 정도로 지능적이며, 기존 구성을 확인하고 시스템에 어떤 변경이 필요한지 파악한다. 만일 configuration file이 여러 개 있는 경우, 단일 파일이 아니라 폴더 단위로 지정하면 여러 오브젝트를 한번에 생성할 수 있다. 오브젝트의 변경이 필요한 경우, 단순히 오브젝트의 configuration file을 업데이트 한 후 kubectl apply를 실행해주면 된다. 커맨드는 오브젝트가 이미 존재한다는 것을 파악해 새로운 변경 사항만 객체에 업데이트 하게 된다. 따라서 객체가 이미 존재한다는 에러나 업데이트를 적용할 수 없다는 에러는 발생하지 않는다. 


Exam Tips

 Imperative 방식은 시간을 아끼기 위해 사용할 수 있다. 예를 들어 파드를 생성하거나, 주어진 이미지를 사용해 deployment를 생성하는 것이라면, 직접 yaml 파일을 작성하기보다는, 커맨드를 이용하면 더 빠르게 문제를 풀 수 있을 것이다. 따라서 Imperative 커맨드를 연습하는 것이 중요하다. 

 여러 컨테이너가 필요한 경우나 복잡한 요구 사항이 있는 경우라면 configuration file을 사용해 오브젝트를 만드는 것이 좋다. 이러한 경우에는 kubectl apply 커맨드가 더 나은 선택이 될 것이다.

  • --dry-run : default로는 커맨드가 실행되는 즉시 리소스가 생성되지만, 단순히 커맨드를 테스트하려는 경우라면 -dry-run=client 옵션을 사용한다. 이 것은 리소스를 생성하는 것이 아니라 리소스를 생성할 수 있는지 여부와 커맨드가 올바른지 여부를 알려준다.
  • -o yaml : resource definition을 yaml 형식으로 화면에 출력한다.

Question 1.

'nginx:alpine' 이미지를 사용하는 'nginx-pod'라는 이름의 Pod를 배포해보세요.

$ kubectl run nginx-pod --image=nginx:alpine

 

Question 2.

'redis:alpine' 이미지를 사용하는' redis'라는 이름의 Pod를 배포하고 Labels는 'tier=db'로 설정해보세요.

$ kubectl run redis --image=redis:alpine --labels=tier=db

 

Question 3. 

서비스 'redis-service'를 생성해 포트 6379의 클러스터 내에서 redis 애플리케이션을 노출하게 설정해보세요.

$ kubectl expose pod redis --port=6379 --name redis-service

'kubectl expose' 명령은 클러스터 내에서 실행 중인 애플리케이션을 네트워크 트래픽에 노출하는 서비스를 생성하는 데에 사용된다.

 

Question 4. 

'kodekloud/webapp-color' 이미지를 사용하고 replicas가 3개있는 'webapp'이라는 이름의 deployment를 생성하세요.

$ kubectl create deployment webapp --image=kodekloud/webapp-color --replicas=3

 

Question 5. 

'nginx' 이미지를 사용하여 container 포트가 8080으로 노출된 'custom-nginx'라는 새로운 파드를 생성하세요.

$ kubectl run custom-nginx --image=nginx --port=8080

 


Question 6. 

'redis' 이미지를 사용하고 2개의 replicas를 가지고 있는 'redis-deploy'라는 deployment를 'dev-ns' 네임 스페이스 안에 생성하세요.

$ kubectl create deployment redis-deploy --image=redis --namespace=dev-ns --replicas=2

 

Question 7. 

'httpd:alpine' 이미지를 사용하는 'httpd'라는 Pod를 default namespace에 생성하고, 타입이 ClusterIP이며 이름은 'httpd'인 서비스를 생성하세요. 서비스의 타켓 포트는 80입니다.

$ kubectl run httpd --image=httpd:alpine --port=80 --expose

--expose : 이 옵션은 배포에 의해 생성된 파드를 노출하는 서비스를 생성하는 것을 나타낸다. 서비스는 클러스터의 다른 리소스가 안정적인 네트워크 엔드포인트를 사용해 파드와 통신할 수 있도록 한다.

'Study > K8s' 카테고리의 다른 글

[K8s] Scheduling  (0) 2023.08.10
[K8s] kubectl apply command  (0) 2023.08.09
[K8s] Namespaces  (0) 2023.08.08
[K8s] Services  (0) 2023.08.07
[K8s] kubectl command  (0) 2023.08.07
Comments