명령형 vs 선언형
명령형 (Imperative)
명령형이란 수행하고자 하는 액션을 지시하는 것을 말합니다. 또한 이는 적은 리소스에 대해서 빠르게 처리가 가능하다는 단점이 있습니다. 다만 여러 명령어를 알아야 한다는 단점이 있습니다.
선언형 (Declarative)
요즘은 명령형보다 선언형이 트랜드인 것 같습니다. 선연형 방식으로 상태를 관리한다면 도달하고자 하는 상태(Desired State)를 선언할 수 있게 됩니다. 그럼 이 상태에 맞춰서 시스템이 해당 상태에 맞게 시스템을 적용하게되는 원리입니다.
는 코드로 관리할 수 있기 때문에 GitOps를 활용 가능하게 됩니다. 그 뿐만 아니라 변경사항에 대한 감사(Audit)이 용이하고, 코드리뷰를 통한 협업도 가능하게 됩니다.
멱등성 ( idempotent)
동일한 요청을 한 번 보내는 것과 여러 번 연속으로 보내는 것이 같은 효과를 지니고, 서버의 상태도 동일하게 남을 때, 해당 HTTP메서드가 멱등성을 가진다고 합니다.
또한 선연형 프로그램으로 코딩하면 멱등성을 보장할 수 있게 됩니다. (apply)
그리고 쿠버네티스 오브젝트의 수가 많아질 수록 조금 더 오브젝트를 효율적으로 관리할 수 있게 됩니다. 그 뿐만 아니라 알아야 할 명령어 수가 적습니다.
kubectl 명령형 ( Imperative ) 명령어
우선 맨 위에 run명령어는 docker run명령어와 매우 유사한 것을 보실 수 있습니다. 저기 맨 윗줄의 명령어를 조금 수정해야 하는데,
$ kubectl run -i -t ubuntu --image ubuntu:focal bash
이 kubectl명령어는 ubuntu파드를 생성하는데 ubuntu:focal 도커 이미지로 만든다는 것을 의미합니다.
그리고 아래에는 grafana라는 Deployment오브젝트가 있다고 할 때, Deployment에 대해 포트를 개방하는 명령어 입니다. 그 중 포트를 개방하는 방법이 여러가지 인데, 위 명령어는 NodePort타입의 Service 오브젝트를 생성해서 배포한 것입니다. ( 노드에 포트를 개방한 것과 동일합니다 ). 이들은 apiResource들의 목록을 배우고 나중에 심화되게 알아보겠습니다. 그냥 여기서는 kubectl이 이런 명령어를 제공하는 구나라고 이해하고 넘어가면 될것 같습니다.
그리고 아래 2개는 kubectl에서 특정 컨테이너의 버전을 업그레이드하고 리비전을 하는 명령어 입니다. 이렇게 kubectl에는 다양한 명령형 명령어가 존재합니다.
kubectl 선언형 (Declarative ) 명령어
우리가 선언형 방식으로 오브젝트를 만들면, 컨트롤러가 선언된 데이터들을 보면서 실제 클러스터 상태가 되도록 실제 클러스터에 적용을 합니다. 그래서 우리가 해야할 일은 매니페스트를 작성하는 과정입니다.
kubectl apply -f옵션에 매니페스트 파일을 적어주면 됩니다. 반대로 delete명령어는 해당 매니페스트에 정의된 오브젝트를 찾아서 제거하라는 의미입니다.
마지막으로는 나중에 더 심화되어 알아볼 kustomize를 활용하는 방법입니다. 이도 선언형 방식과 관련되어 있습니다.
실습
우선 명령형 방식입니다. 이의 명령어를 해석해보면 grafana라는 파드를 만드는데. grafana/grafana라는 이미지를 사용하고 3000번 포트를 개방하라는 의미입니다. 이것은 파드에 대한 포트를 개방하는 것이고 관련된 내용은 Pod를 공부하면서 더 자세히 작성해 보도록 하겠습니다.
그리고 deployment grafana에 대해서 NodePort로 3000번 포트로 다시한번 개방하라 라는 명령어가 그 아래에 있습니다. 그리고 minikube에서 제공하는 명령어로 grafana서비스의 url을 가져올 수 있게 됩니다.
저는 이전에도 위 쉘스크립트를 실행해서 이미 grafana라는 서비스가 존재한다고 오류를 내뱉는 것을 보실 수 있습니다. 그리고 아래와 같이 서비스의 개방포트와 이름, 네임스페이스와 URL을 띄우게 되는데, 진짜 저 URL로 들어가보겠습니다.
진짜 node의 목록을 확인하면 해당 내부 IP가 있는것을 확인할 수 있습니다. 저희는 NodePort라는 서비스를 만들어서 위에서 만든 grafana라는 Deployment를 쿠버네티스 노드의 포트로 바인딩 시켰다 라고 생각하면 됩니다.
그래서 진짜 요청을 하면 위와같이 응답이 옵니다. 위와같이 grafana Deployment와 Service를 생성해보았습니다.
그리고 clean.sh를 실행하면 grafana service와 Deployment를 제거합니다.
이게 가능한 이유는 deployment.yaml과 service.yaml을 보면 metadata의 name이 다 "grafana"이기 때문입니다.
그 다음은 선언형 방식으로 만들어보겠습니다.
이를 실행하고 나면 아래와같이 명령형과 동일하게 grafana deployment, service가 생성된 것을 보실 수 있습니다.
그리고 응답도 잘 오는 것을 보실 수 있습니다. 그리고 다시 쉘스크립트를 실행해도 명령형과는 다르게 오류를 내뱉지 않고 unchanged라고만 뜹니다.
그리고 마지막으로 deployment.yaml의 spec의 replicas를 2로 지정해 주었습니다. 그리고 다시 apply해보겠습니다.
그러면 grafana deployment만 configured된 것을 보실 수 있고, pod가 정상적으로 2개 생성된 것을 보실 수 있습니다.