본문 바로가기
MLOps/Doker & Kubernetes

Udemy CKA 강의 정리 43: Imperative vs Declarative

by 공부하는 무니 2023. 1. 5.
반응형

해당 내용은 Udemy의 Certified Kubernetes Administrator (CKA) with Practice Tests  강의를 공부한 내용입니다. 내용을 그대로 번역하기보다는, 제가 이해하기 쉬운 대로 수정한 부분들이 있습니다.

⚠️ 영어 독해가 많이 부족합니다. 틀린 내용이 있으면 알려주시면 감사하겠습니다.


이번 강의에서는 Kubernetes imperative 접근 방식과 declarative 접근 방식에 대해 알아보도록 하겠습니다. 강의를 끝낼 무렵에는 시험에 사용할 수 있는 몇 가지 팁에 대해서도 이야기해보겠습니다.

Imperative vs Declarative

지금까지 우리는 Kubernetes에서 오브젝트를 생성하고 관리하는 다양한 방법을 보았습니다. 우리는 커맨드를 사용해서 직접 오브젝트를 생성하기도 했고, configuration file을 사용하기도 했습니다. 인프라 관리에 있어서 이 방법들은 imperative(명령형) 접근 방식과 declarative(선언적) 접근 방식으로 분류됩니다.

비유를 들어 이해해보겠습니다. Street D에 있는 친구집에 놀러가고 싶습니다.

Imperative

과거에는 택시를 타면 목적지에 도달하는 방법에 대해 step-by-step으로 기사님께 말씀드려야 했습니다.

Street B로 우회전 하시고, 좌회전해서 Street C로 가주세요. 그다음 다시 좌회전 하고 우회전하면 Street D에요. 거기서 직진하면 됩니다.

이처럼 '어떻게'를 중요하게 두는 방식이 Imperative 방식입니다.

Declarative

반면에, 오늘날 택시를 타면 최종 목적지만 지정하면 친구 집으로 운전해주십니다. 이것이 Declarative 방식입니다. 여기서는 단계별 지침을 말할 필요가 없습니다. 대신 최종 목적지만 지정하면 됩니다. 우리가 최종 목적지를 지정하면 시스템이 올바른 경로를 파악합니다. 이렇게 '무엇을' 할 것인지를 중요하게 두는 방식이 Declarative방식입니다.

Infrastructure as Code

이러한 접근 방식이 우리가 배우는 것과 무슨 상관이 있을까요? infrastructure-as-code(코드형 인프라) 세계에서 provisioning infrastructure의 imperative 접근 방식의 예로는 단계별로 쓰여진 instructions 세트가 될 수 있습니다.

  • provisioning a VM named a web server
  • installing the NGINX software on it
  • editing configuration file to use port 8080
  • setting the path to web files
  • downloading source code of repositories from Git
  • starting the NGINX server

여기서 우리는 무엇이 필요한지 말하고, 그것을 완료하려면 어떻게 해야 하는지 말합니다.

반면 declarative 접근방식에서 우리는 우리의 요구를 선언합니다. 예를 들어 nginx 소프트웨어가 있는 "web server"라는 이름으로 VM이 필요하고 포트는 8080으로 설정하고 싶다면, 단계별 지침을 제공할 필요 없이시스템 또는 소프트웨어에 의해 수행됩니다. Ansible, Puppet, Chef, Terraform과 같은 오케스트레이션 툴이 범주에 속합니다. imperative 접근 방식에서 첫 단계의 반만 실행되면 어떻게 될까요? 나머지를 완료하기 위해 같은 지침을 또 제공해야 할까요? 이런 상황을 다루기 위해, 관련된 많은 추가적인 단계들이 있을 것입니다. 예를 들어 이미 존재하는지 체크하는 것이라던가, 체크한 결과에 따라 조치를 취하는 것 같은 것들 말입니다.

예를 들어 VM을 프로비저닝하는 동안 "web server"라는 VM이 이미 존재한다면 어떻게 될까요? 데이터베이스를 만들거나 데이터를 가져올 때도 마찬가지입니다. VM이 이미 존재한다면, 해당 instruction은 실패한걸까요 아니면 계속해야 하는 것일까요? 소프트웨어 버전을 예를 들어 NGINX 1.18로 업그레이드하기로 결정한 경우, configuration file에서 nginx 버전을 업그레이드하는 것 만큼 간단해야 할 것입니다. 그리고 나머지는 시스템이 처리해야 할 것입니다. 이상적으로, 시스템이 충분히 지능적이어서 이미 벌어진 일을 알고 필요한 변경 사항만 적용합니다. 이것이 declarative 방식입니다.

Kubernetes

쿠버네티스 세계에서는 인프라 관리를 imperative 방식으로 한다는 것은 파드를 생성할 때 kubectl run커맨드를 사용하는 것과 같습니다. deployment를 생성할 때에는 kubectl create deployment 를, service를 생성할때는 kubectl expose 를 사용합니다.그리고 kubectl edit커맨드는 이미 존재하는 오브젝트를 수정하는데 쓰입니다. Deployment나 ReplicaSet을 확장하기 위해서는 kubectl scale커맨드를 사용합니다. deployment에서 image를 업데이트하려면 kubectl set image 커맨드를 사용하면 됩니다.

우리는 오브젝트를 생성하고 관리하기 위해 configuration file들도 사용했습니다. kubectl create -f커맨드를 사용해서 configuration file을 지정했습니다. 또한 오브젝트를 수정하기 위해 kubectl replace커맨드를 사용하고 오브젝트를 삭제하기 위해 kubectl delete커맨드를 사용했습니다. 이 모든 것들은 Kubernetes에서 오브젝트를 관리하는 imperative 접근 방식입니다. 우리는 오브젝트를 만들고, 업데이트하고, 삭제하는 니즈를 위해 어떻게해야 하는지 인프라에게 정확하게 말하고 있습니다. declarative 접근 방식은 다음과 같습니다. Kubernetes 클러스터의 애플리케이션 및 서비스의예상되는 상태를 정의하는 file 세트를 만드는 것입니다. 그리고 단 하나의 커맨드 kubectl apply커맨드로 Kubernetes는 configuration file을 읽을 수 있어야 합니다. 그리고 인프라를 예상되는 상태로 만들기 위해 해야 할 일을 스스로 결정합니다. 따라서 declarative 접근 방식에서는 오브젝트를 만들고, 업데이트하고, 삭제하기 위해 kubectl apply커맨드를 실행합니다. apply 커맨드는 기존 구성을 확인하고 시스템에 어떤 변경이 필요한지 파악할 것입니다. 그럼, 이들을 더 자세히 살펴보겠습니다.

Imperative Commands

imperative 접근 방식에는 두 가지 방법이 있습니다. 첫 번째는 imperative(명령형) 커맨드를 사용하는 것입니다. 오브젝트를 생성하기 위한 run, create, expose 커맨드와 기존에 존재하는 오브젝트를 업데이트하기 위한 edit, scale, set 커맨드가 imperative 커맨드입니다. 이러한 커맨드는 yaml파일을 다룰 필요가 없기 때문에 빠르게 오브젝트를 만들고 수정하는데 도움이 됩니다. 그리고 자격증 시험에도 도움이 됩니다.

그러나, 기능이 제한적이고 multi-container 파드나 deployment을 생성하는 것과 같이 advanced use case의 경우 길고 복잡한 커맨드를 작성해야 합니다. 또한 이러한 커맨드는 한 번 실행되고 잊혀집니다. 해당 커맨드를 실행했던 사람의 세션 기록에서만 볼 수 있습니다. 따라서 다른사람이 이 오브젝트가 어떻게 만들어졌는지 알기 어렵고 트래킹하기가 어렵습니다. 따라서 크고 복잡한 환경에서는 이러한 커맨드로 작업하기가 어렵습니다. 이 점이 오브젝트 configuration file로 오브젝트를 관리할 때 도움을 받을 수 있는 점입니다.

Imperative Object Configuration Files

Definition file (=configuration file, manifest file)을 만드는 것은 우리가 원하는 것을 yaml 형식으로 정확히 기록하고 kubectl create커맨드로 오브젝트를 만드는데 도움을 줍니다. yaml파일이 있으면 git과 같은 코드 레포지토리에 저장할 수도 있습니다. 프로덕션에 반영되기 전에 변경사항을 검토하고 승인 프로세스를 넣을 수도 있겠지요.

향후 변경사항이 있으면, 예를 들어 이미지 이름을 다른 버전으로 고칠 때, 이를 처리하는 여러 방법이 있습니다. 한 가지 방법은 kubectl edit커맨드를 사용하는 것입니다. 따라서 이 커맨드가 실행되면 오브젝트를 만드는 것과 유사하게 yaml definition file이 열립니다. 이것은 오브젝트를 만들 때 사용한 파일이 아닙니다. Kubernetes 메모리에 있는 유사한 Pod definition file입니다. 우리는 이 파일을 변경하고 저장하고 종료할 수 있습니다. 그러면 이 변경사항은 live object에 적용됩니다. 그러나 live object 와 로컬에 있는 definition file 사이에 차이가 있으니 주의해주세요. 

kubectl edit커맨드를 사용해 만든 변경사항은 실제로 어디에도 기록되지 않습니다. 변경이 적용되면 로컬 definition file만 남는데, 이 definiton file에는 변경사항이 적용되지 않은 예전 버전입니다. 향후 당신이나 팀원이 kubectl edit커맨드를 사용해서 오브젝트가 변경된 사실을 모르고 오브젝트를 변경했다고 합시다. 변경사항이 적용될 때 이전 버전의 image는 손실됩니다. 따라서 kubectl edit 커맨드는 내가 더이상 configuration file을 의존하지 않을 것이라고 확신할 때 사용할 수 있습니다.

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

지금까지도 이것은 imperative 접근 방식입니다. 어떻게 오브젝트를 생성하고 업데이트하는지 여전히 kubernetes에게 지시하고 있기 때문입니다. 먼저, 오브젝트를 생성하기 위해 kubectl create커맨드를 실행합니다. 그리고 kubectl replace커맨드를 오브젝트를 교체하기 위해 사용하거나 오브젝트를 삭제하기 위해 kubectl delete커맨드를 실행합니다. 그리고 이제 create 커맨드를 입력하면 어떻게 되나요? 오브젝트가 이미 존재하는데 create 커맨드를 실행하면 어떻게 될까요? 파드가 이미 존재한다는 에러가 뜹니다. 오브젝트를 업데이트할 때, replace커맨드를 실행하기 전에 오브젝트가 먼저 존재하는지 항상 확인해야 합니다. 오브젝트가 존재하지 않으면 replace 커맨드가 에러 메세지와 함께 실패합니다. 따라서 imperative 접근 방식은 항상 현재 구성을 알고 있어야 하고, 변경 전에 모든 것이 제자리에 있는지 체크를 해야 하므로 관리자에게 매우 부담이 됩니다.

Declarative

declarative 접근 방식은 우리가 작업해 온 오브젝트 configuration file을 동일하게 사용합니다. 대신 create나 replace커맨드가 아닌, kubectl apply커맨드를 사용합니다. kubectl apply커맨드는 아직 존재하지 않는 객체를 생성할 정도로 지능적입니다. 만약 configuration file이 여러 개 있는 경우, 단일 파일이 아니라 폴더 단위로 지정하면 여러 오브젝트를 한번에 생성할 수 있습니다. 오브젝트의 변경이 필요한 경우에는, 우리는 단순히 오브젝트의 configuration file을 업데이트하고 kubectl apply커맨드를 실행해주면 됩니다. 이번에는 오브젝트가 이미 존재한다는 것을 커맨드는 알고 있으며, 새로운 변경사항만 객체에 업데이트하게 됩니다. 따라서 객체가 이미 존재한다는 에러나 업데이트를 적용할 수 없다는 에러는 발생하지 않습니다. 이 방식은 항상 오브젝트를 업데이트하는 옳은 방법을 알아낼 것입니다. 앞으로 애플리케이션의 어떤 변경사항이든, 이미지 업데이트, configuration file의 필드 업데이트, 새로운 configuration file추가, 완전히 새로운 오브젝트간에, 우리가 해야할 일은 단순히 로컬 디렉토리를 업데이트하고, kubectl apply커맨드를 실행하는 것입니다. kubectl apply커맨드가 어떻게 백엔드에서 작동하는지 다음 강의에서 자세히 설명하겠습니다.

Exam Tips

지금은 시험을 위한 몇 가지 팁을 알려드리겠습니다. 시험 관점에서, 시간을 최대한 아끼기 위해 imperative 방식을 사용할 수 있습니다. 예를 들어 질문이 파드를 생성하는 것이거나 주어진 이미지를 사용해 deployment를 생성하는 것이라면, imperative 커맨드는 빠르게 풀 수 있게 도와줄 것입니다. 따라서 imperative 커맨드를 연습하는 것이 중요합니다. 기존 오브젝트의 속성을 편집해야 한다면 kubectl edit커맨드가 가장 빠른 방법이겠지요? 만약에 예를 들어 여러 컨테이너가 필요한 경우나 환경 변수, 커맨드, 초기화 컨테이너 등 복잡한 요구사항이 있는 경우라면 configuration file을 사용하여 오브젝트를 만드는 것이 좋습니다. 이렇게 하면 혹시 실수를 했을 때 빨리 알아차리고 쉽게 고칠 수 있습니다. 이러한 경우에는 kubectl apply커맨드가 더 나은 선택이 될 것입니다. 접근 방식에 대한 더 자세한 내용은 kubernetes 공식 문서 페이지에서 익숙해질 수 있습니다. 그리고 다가오는 실습에서는 imperative 접근 방식을 사용하세요.

 

반응형

댓글