6.3.1 오브젝트 생성, 조회, 수정, 삭제 (CRUD)
이제 쿠버네티스 클러스터의 아키텍처와 핵심 개념인 오브젝트 모델에 대한 이해를 바탕으로, 실제로 클러스터와 상호작용하며 우리가 원하는 상태를 만들어가는 방법을 배울 시간입니다. 쿠버네티스와 소통하는 가장 기본적인 도구는 바로 kubectl(큐브컨트롤 또는 큐브씨티엘이라고 읽습니다)이라는 커맨드라인 인터페이스(CLI)입니다. kubectl을 사용하면 마치 마법 지팡이를 휘두르듯 쿠버네티스 클러스터 내의 다양한 오브젝트들을 생성(Create), 조회(Read), 수정(Update), 삭제(Delete)할 수 있습니다. 이러한 네 가지 기본 작업을 흔히 CRUD 연산이라고 부르며, 이는 대부분의 데이터 관리 시스템에서 공통적으로 사용되는 용어입니다. 이번 섹션에서는 kubectl을 사용하여 이러한 CRUD 연산을 어떻게 수행하는지, 그리고 각 명령어의 주요 옵션과 사용법을 자세히 살펴보겠습니다.

6.3.1.1 오브젝트 생성: kubectl create -f <filename.yaml> 와 kubectl apply -f <filename.yaml>
쿠버네티스에서 새로운 오브젝트를 만드는 가장 일반적인 방법은 YAML(YAML Ain’t Markup Language) 또는 JSON(JavaScript Object Notation) 형식의 매니페스트(manifest) 파일을 사용하는 것입니다. 이 매니페스트 파일에는 우리가 생성하고자 하는 오브젝트의 ‘원하는 상태(Desired State)’, 즉 오브젝트 명세(Spec)가 상세하게 기술되어 있습니다. 예를 들어, 새로운 파드를 생성하고 싶다면 파드 명세 파일에 어떤 컨테이너 이미지를 사용할지, 어떤 포트를 열지 등을 정의하는 것이죠. 이렇게 작성된 매니페스트 파일을 kubectl에 전달하여 오브젝트 생성을 요청하게 됩니다.
오브젝트를 생성하는 데 주로 사용되는 kubectl 명령어는 create와 apply 두 가지가 있습니다. 둘 다 파일로부터 오브젝트를 생성할 수 있지만, 동작 방식과 사용 목적에 약간의 차이가 있습니다.
kubectl create -f <filename.yaml>:
이 명령어는 지정된 매니페스트 파일(-f 옵션은 파일을 지정한다는 의미입니다)에 정의된 오브젝트를 새롭게 생성합니다. 만약 동일한 이름과 종류의 오브젝트가 이미 클러스터에 존재한다면, kubectl create 명령어는 기본적으로 오류를 발생시키며 생성을 중단합니다. 즉, create는 주로 처음 오브젝트를 만들 때 사용되며, 이미 존재하는 오브젝트를 덮어쓰거나 수정하는 용도로는 적합하지 않습니다. (물론 –save-config와 같은 옵션을 사용하여 추후 관리를 용이하게 할 수는 있지만, apply만큼 유연하지는 않습니다.)
예를 들어, my-pod.yaml이라는 파일에 파드 명세가 정의되어 있다면, kubectl create -f my-pod.yaml 명령을 실행하여 해당 파드를 클러스터에 생성할 수 있습니다.
kubectl apply -f <filename.yaml>:
apply 명령어는 create보다 훨씬 더 선언적인 방식으로 오브젝트를 관리하며, 현재 쿠버네티스에서 가장 권장되는 방식입니다. apply는 지정된 매니페스트 파일의 내용과 클러스터에 이미 존재하는 오브젝트의 현재 설정을 비교하여, 필요한 경우 오브젝트를 새로 생성하거나 기존 오브젝트를 수정(업데이트)합니다.
- 만약 해당 오브젝트가 클러스터에 존재하지 않으면, create와 마찬가지로 새로운 오브젝트를 생성합니다.
- 만약 해당 오브젝트가 이미 존재한다면, apply는 매니페스트 파일의 내용과 현재 클러스터의 오브젝트 설정을 비교하여 변경된 부분만 선택적으로 업데이트하려고 시도합니다. 이 과정에서 apply는 이전에 apply 명령을 통해 적용된 설정을 기억하고(보통 오브젝트의 metadata.annotations에 kubectl.kubernetes.io/last-applied-configuration라는 어노테이션으로 저장됨), 이를 기반으로 변경 사항을 계산하여 병합(merge)합니다.
- 이러한 특징 덕분에, apply는 동일한 매니페스트 파일을 반복적으로 실행해도 안전하며(멱등성, idempotency), 형상 관리 시스템(예: Git)에 매니페스트 파일을 저장해두고 이를 사용하여 클러스터의 상태를 선언적으로 관리하는 GitOps 워크플로우에 매우 적합합니다.
- 예를 들어, my-deployment.yaml 파일에 디플로이먼트 명세가 있고, 처음에는 kubectl apply -f my-deployment.yaml로 디플로이먼트를 생성한 후, 나중에 컨테이너 이미지를 변경하거나 복제본 수를 조정한 후 다시 동일한 명령을 실행하면, apply는 변경된 부분만 반영하여 디플로이먼트를 업데이트합니다.
create vs apply 선택 가이드:
일반적으로, 처음 한 번만 오브젝트를 생성하고 이후에는 직접 수정하지 않을 간단한 경우에는 create를 사용할 수도 있습니다. 하지만, 지속적으로 오브젝트의 상태를 매니페스트 파일로 관리하고 업데이트하려는 경우에는 apply를 사용하는 것이 훨씬 더 강력하고 안전한 방법입니다. 특히, 여러 사람이 협업하거나 자동화된 파이프라인을 통해 클러스터를 관리하는 환경에서는 apply가 거의 필수적이라고 할 수 있습니다. apply는 “이 매니페스트 파일이 바로 내가 원하는 최종 상태야!”라고 선언하는 것과 같습니다.
6.3.1.2 오브젝트 조회: kubectl get [name] [-o wide|yaml|json]
클러스터에 생성된 오브젝트들의 상태를 확인하거나 상세 정보를 조회하는 것은 매우 빈번하게 수행하는 작업입니다. kubectl get 명령어는 바로 이러한 오브젝트 조회를 위해 사용됩니다.
- 기본 사용법:
- kubectl get <resource-type>: 특정 종류의 모든 오브젝트 목록을 간략한 형태로 보여줍니다. 예를 들어, kubectl get pods는 현재 네임스페이스의 모든 파드 목록을, kubectl get services는 모든 서비스 목록을 보여줍니다.
- kubectl get <resource-type> <resource-name>: 특정 이름의 오브젝트 하나에 대한 정보를 보여줍니다. 예를 들어, kubectl get pod my-pod-123은 my-pod-123이라는 이름의 파드 정보를 보여줍니다.
- 여러 오브젝트를 동시에 조회할 수도 있습니다. 예를 들어, kubectl get pods pod1 pod2는 pod1과 pod2 두 파드의 정보를, kubectl get deployment,service는 모든 디플로이먼트와 서비스 목록을 함께 보여줍니다.
- 네임스페이스 지정:
- 기본적으로 kubectl get은 현재 컨텍스트에 설정된 기본 네임스페이스의 오브젝트만 보여줍니다.
- n <namespace-name> (또는 –namespace <namespace-name>) 옵션을 사용하면 특정 네임스페이스의 오브젝트를 조회할 수 있습니다. 예를 들어, kubectl get pods -n kube-system은 kube-system 네임스페이스의 모든 파드를 보여줍니다.
- A (또는 –all-namespaces) 옵션을 사용하면 클러스터 전체의 모든 네임스페이스에 있는 해당 종류의 오브젝트를 한 번에 조회할 수 있습니다. 예를 들어, kubectl get pods -A는 모든 네임스페이스의 모든 파드를 보여줍니다.
- 출력 형식 지정 (-o 또는 –output 옵션):kubectl get 명령어의 출력 형식을 다양하게 제어할 수 있는 -o 옵션은 매우 유용합니다.
- o wide: 기본 출력보다 더 많은 정보(예: 파드의 IP 주소, 실행 중인 노드 이름 등)를 함께 보여줍니다. kubectl get pods -o wide와 같이 사용합니다.
- o yaml: 오브젝트의 전체 명세와 상태를 YAML 형식으로 출력합니다. 이는 오브젝트의 현재 설정을 자세히 확인하거나, 기존 오브젝트를 기반으로 새로운 매니페스트 파일을 작성할 때 매우 유용합니다. 예를 들어, kubectl get pod my-pod-123 -o yaml은 해당 파드의 전체 YAML 정의를 보여줍니다.
- o json: 오브젝트의 전체 명세와 상태를 JSON 형식으로 출력합니다. 스크립트에서 JSON 파서를 사용하여 정보를 처리할 때 유용합니다.
- o custom-columns=<spec>: 사용자가 직접 출력할 컬럼과 해당 컬럼에 표시할 정보를 JSONPath 표현식을 사용하여 정의할 수 있습니다. 매우 유연한 맞춤형 출력이 가능합니다.
- o jsonpath=<template>: JSONPath 표현식을 사용하여 오브젝트의 특정 필드 값만 추출하여 원하는 형식으로 출력할 수 있습니다. 스크립팅에 매우 강력한 기능을 제공합니다.
- 레이블 셀렉터 활용 (-l 또는 –selector 옵션):특정 레이블(label)을 가진 오브젝트들만 선택하여 조회할 수 있습니다. 예를 들어, kubectl get pods -l app=my-app,env=production은 app 레이블이 my-app이고 env 레이블이 production인 파드들만 보여줍니다. 이는 특정 애플리케이션이나 환경에 속한 리소스들을 필터링하는 데 매우 유용합니다.
kubectl get 명령어와 다양한 옵션들을 잘 활용하면, 클러스터 내의 수많은 오브젝트들 중에서 원하는 정보를 효과적으로 찾아내고 분석할 수 있습니다.
6.3.1.3 오브젝트 수정: kubectl edit
이미 클러스터에 존재하는 오브젝트의 설정을 변경하고 싶을 때 kubectl edit 명령어를 사용할 수 있습니다. 이 명령어는 마치 텍스트 편집기를 사용하여 오브젝트의 명세를 직접 수정하는 듯한 경험을 제공합니다.
- 동작 방식:kubectl edit <resource-type> <resource-name> (예: kubectl edit deployment my-app-deployment) 명령을 실행하면, kubectl은 먼저 해당 오브젝트의 현재 설정을 kube-apiserver로부터 가져와서 YAML 형식으로 로컬 임시 파일에 저장합니다. 그런 다음, 시스템에 설정된 기본 텍스트 편집기(보통 vi 또는 nano, 환경 변수 KUBE_EDITOR 또는 EDITOR로 변경 가능)를 실행하여 이 임시 파일을 엽니다. 사용자는 이 편집기에서 오브젝트의 명세(주로 spec 필드 하위 내용)를 직접 수정한 후 저장하고 편집기를 종료합니다. 그러면 kubectl은 수정된 내용을 kube-apiserver에 다시 전송하여 오브젝트를 업데이트합니다.
- 주의사항:
- edit 명령어는 매우 편리하지만, 직접적인 수정을 가하는 만큼 주의해서 사용해야 합니다. 특히, 오브젝트의 status 필드나 시스템이 관리하는 다른 필드(예: metadata.uid, metadata.resourceVersion)는 수정해서는 안 됩니다. 주로 사용자가 정의한 spec 필드 내용을 변경하는 데 사용됩니다.
- edit를 통해 수정한 내용은 매니페스트 파일에는 반영되지 않으므로, 형상 관리 시스템에 저장된 매니페스트 파일과 클러스터의 실제 상태 사이에 불일치가 발생할 수 있습니다. 따라서, 일관된 상태 관리를 위해서는 가급적 매니페스트 파일을 수정한 후 kubectl apply -f <filename.yaml> 명령을 사용하는 것이 권장됩니다. edit는 주로 임시적인 테스트나 간단한 수정, 또는 apply로 변경하기 어려운 특정 필드를 수정할 때 제한적으로 사용하는 것이 좋습니다.
- 만약 편집기에서 저장하지 않고 종료하거나, 유효하지 않은 변경(예: 필수 필드 삭제)을 가하면 업데이트는 적용되지 않습니다.
kubectl edit 외에도, 특정 필드만 선택적으로 업데이트하는 kubectl patch 명령어, 컨테이너 이미지 버전만 빠르게 변경하는 kubectl set image 명령어, 복제본 수를 조절하는 kubectl scale 명령어 등 특정 목적에 특화된 수정 명령어들도 존재합니다. 하지만 가장 일반적이고 선언적인 방식은 역시 kubectl apply입니다.
6.3.1.4 오브젝트 삭제: kubectl delete or -f
더 이상 필요 없는 오브젝트를 클러스터에서 제거하고 싶을 때는 kubectl delete 명령어를 사용합니다. 오브젝트를 삭제하는 방법도 크게 두 가지가 있습니다.
- 이름으로 직접 삭제: kubectl delete <resource-type> <resource-name>특정 이름의 오브젝트를 직접 지정하여 삭제합니다. 예를 들어, kubectl delete pod my-pod-to-delete는 my-pod-to-delete라는 이름의 파드를 즉시 삭제하려고 시도합니다.여러 오브젝트를 한 번에 삭제할 수도 있습니다. 예를 들어, kubectl delete pod pod1 pod2 pod3은 세 개의 파드를 동시에 삭제합니다.
이 방식은 특정 오브젝트를 명확히 알고 있고 즉시 삭제하고 싶을 때 유용합니다.
- 매니페스트 파일로 삭제: kubectl delete -f <filename.yaml>오브젝트를 생성할 때 사용했던 매니페스트 파일이나, 삭제할 오브젝트 목록이 정의된 파일을 사용하여 관련된 오브젝트들을 한 번에 삭제할 수 있습니다. 예를 들어, kubectl delete -f my-app-resources.yaml 명령은 my-app-resources.yaml 파일에 정의된 모든 오브젝트(예: 디플로이먼트, 서비스, 컨피그맵 등)를 삭제하려고 시도합니다.이 방식은 특정 애플리케이션과 관련된 모든 리소스를 한 번에 정리하거나, kubectl apply -f로 관리하던 리소스를 동일한 파일로 삭제할 때 유용합니다.
- 레이블 셀렉터로 삭제: kubectl delete <resource-type> -l <label-selector>특정 레이블을 가진 모든 오브젝트를 한 번에 삭제할 수도 있습니다. 예를 들어, kubectl delete pods -l app=old-app은 app 레이블이 old-app인 모든 파드를 삭제합니다. 이 방식은 매우 강력하지만, 의도치 않은 오브젝트까지 삭제할 위험이 있으므로 주의해서 사용해야 합니다. (실행 전 –dry-run=client 또는 –dry-run=server 옵션으로 어떤 오브젝트가 삭제될지 미리 확인하는 것이 좋습니다.)
- 삭제 옵션:
- -grace-period=<seconds>: 오브젝트를 삭제할 때 유예 기간(grace period)을 지정합니다. 이 기간 동안 파드 내의 컨테이너들은 정상적으로 종료(graceful shutdown)할 시간을 갖게 됩니다. 기본값은 보통 30초입니다. –grace-period=0으로 설정하면 즉시 강제 종료(force delete)를 시도하지만, 이는 권장되지 않습니다.
- -force: 유예 기간을 무시하고 즉시 강제 삭제를 시도합니다. (일부 리소스는 Terminating 상태에 오래 머무를 수 있는데, 이 경우 최후의 수단으로 사용될 수 있지만 데이터 유실 등의 위험이 따릅니다.)
- -cascade=orphan (또는 –cascade=false): 디플로이먼트나 레플리카셋과 같이 다른 오브젝트를 소유(own)하는 오브젝트를 삭제할 때, 기본적으로는 소유된 오브젝트(예: 파드)들도 함께 삭제됩니다(이를 ‘Cascading Deletion’이라고 합니다). –cascade=orphan 옵션을 사용하면 부모 오브젝트만 삭제하고 자식 오브젝트들은 남겨둡니다. (반대로 –cascade=background나 –cascade=foreground는 기본 동작을 명시적으로 지정합니다.)
오브젝트 삭제는 되돌리기 어려운 작업이므로, 항상 신중하게 수행해야 하며, 특히 운영 환경에서는 삭제 대상과 범위를 명확히 확인하는 습관을 들이는 것이 중요합니다.
지금까지 kubectl을 사용하여 쿠버네티스 오브젝트를 생성, 조회, 수정, 삭제하는 기본적인 CRUD 연산에 대해 자세히 알아보았습니다. 이 네 가지 명령어와 그 옵션들을 잘 익혀두시면, 쿠버네티스 클러스터를 관리하는 데 있어 훌륭한 첫걸음을 내디딘 것이라고 할 수 있습니다. 다음 섹션에서는 오브젝트의 상태를 좀 더 상세하게 확인하는 방법과, 레이블 및 어노테이션과 같은 유용한 메타데이터를 활용하는 방법에 대해 알아보겠습니다.