반응형

Kubernetes를 사용하면서 자주 사용하는게 kubectl 명령어 이다. 그리고 그중에서 컨테이너를 생성할때 항상 kubectl create 명령어를 사용했다. 그런데 사용하다보니 어떤 글에는 create 를 사용하고 어디에서는 apply 를 사용하는 것을 보게 되었다. 그래서 이 차이점이 궁금해서 이렇게 정리하게 되었다. 


아래 내용들은 kubernetes document 에서 요약한 내용들이다. 

https://kubernetes.io/docs/concepts/overview/object-management-kubectl/overview/



Kubernetes 에서 Object Management 에는 3가지가 있다. 


Management technique

Operates on

Recommended environment 

Supported writers 

 Imperative commands

 Live objects 

 Development 

 1+ 

 Imperative object configuration

 Individual files  

 Production 

 1 

 Declarative object configuration

 Directories of files 

 Production 

 1+ 



Imperative Commands


장점

- 클러스터에 특정 오브젝트를 한번에 실행하거나 시작할수 있는 가장 쉬운 방법이다. (실제 이미지 바로 실행 시킨다. )


단점

- 기존 설정에 대한 히스토리를 제공하지 않는다. (그래서 위에 권장 환경이 Development 인것 같다.)

- 변경사항이나 audit 내역, 템플릿등을 제공하지 않는다. 


ex)

kubectl run nginx --image nginx



Imperative object configuration


- 최소한 1개 이상의 YAML 이나 JSON 포맷의 파일을 이용해서 Object 를 생성한다. 


ex)

kubectl create -f nginx.yaml

Imperative object configuration vs Imperative Commands

장점

- 설정파일 내용을 Git 같은 곳에 저장이 가능하기 때문에 설정에 대한 변경 히스토리가 확인 가능하다. 

- 새로운 Object를 생성하기 위한 템플릿을 제공한다. 

단점

- YAML 파일 작성이 필요하며 템플릿 사용을 위해 Object schema 에 대해서 이해가 필요하다.


Imperative object configuration vs Declarative object configuration 

장점
- 더 간단하고 이해하기 쉽다.

단점

- 파일로 적용할때에만 동작한다. 디렉토리는 불가능.

- 실행중인 object 를 update 하기 위해서는 설정파일에 반영을 해야 한다. 



Declarative object configuration

- 모든 설정 파일들은 디렉토리 안에 들어있고 오브젝트를 생성하거나 패치 한다.


ex)

kubectl apply -f configs/


Declarative object configuration vs Imperative object configuration

장점

- 실행중인 오브젝트 직접 적용한 변경사항을 설정파일에 merge 하지 않더라도 유지된다.(???)


단점

- 디버깅 하기 어렵고 예상한 결과가 아닐 경우 이해하기 어렵다.

- diffs 를 사용한 부분 업데이트는 복잡한 병합과 패치를 만들게 된다.


Imperative commands 나  Imperative object configuration 는 이해가 되는데  Declarative object configuration 은 약간 이해가 안된다. 


https://kubernetes.io/docs/concepts/overview/object-management-kubectl/declarative-config/


여기 있는 샘플을 가지고 확인해보자.


sample_deployment.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
cs



Create : kubectl apply -f sample_deployment.yaml 

Live configuration : kubectl get -f sample_deployment.yaml -o yaml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
kind: Deployment
metadata:
  annotations:
    # ...
    # This is the json representation of simple_deployment.yaml
    # It was written by kubectl apply when the object was created
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.7.9","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}
  # ...
spec:
  # ...
  minReadySeconds: 5
cs


kubectl.kubernetes.io/last-applied-configuration 어노테이션에 보면 sample_deployment.yaml  에 적용한 내용들이 나와있다. 


다시 아래와 같이 명령어를 실행해보고 확인해보자.


kubectl scale deployment/nginx-deployment --replicas=2

Live configuration : kubectl get -f sample_deployment.yaml -o yaml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # note that the annotation does not contain replicas
    # because it was not updated through apply
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.7.9","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}
  # ...
spec:
  replicas: 2 # written by scale
  # ...
  minReadySeconds: 5
cs


이 경우에는 apply를 하지 않았기 때문에 kubectl.kubernetes.io/last-applied-configuration 어노테이션에 포함되지 않았다.


sample_deployment.yaml 파일을 수정해보자. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.11.9 # update the image
        ports:
        - containerPort: 80
cs


nginx image 버전이 1.7.9 에서 1.11.9 로 변경 되었다.


Create : kubectl apply -f sample_deployment.yaml 

Live configuration : kubectl get -f sample_deployment.yaml -o yaml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # The annotation contains the updated image to nginx 1.11.9,
    # but does not contain the updated replicas to 2
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.11.9","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}
    # ...
spec:
  replicas: 2 # Set by `kubectl scale`.  Ignored by `kubectl apply`.
  # minReadySeconds cleared by `kubectl apply`
  # ...
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.11.9 # Set by `kubectl apply`
cs


확인을 해보면 apply 로 적용한 nginx 버전은 kubectl.kubernetes.io/last-applied-configuration 어노테이션에 포함 되어있다. 하지만 replicas 는 포함되지 않았다.


Warning: Mixing kubectl apply with the imperative object configuration commands create and replace is not supported. This is because create and replace do not retain the kubectl.kubernetes.io/last-applied-configuration that kubectl apply uses to compute updates


그리고 위와 같은 주의 사항도 있다. apply 는 create 나 replace 를 지원하지 않는다는 거다. 이유는 create 나 replace 는 kubectl.kubernetes.io/last-applied-configuration 어노테이션을 유지 하지 않기 때문이라고 한다. 



apply 와 create 의 차이점을 찾아보다가 여기까지 오게 되었다. 결과적으로 가장 큰 차이점은 apply 를 할 경우에는 기존 설정에 대한 정보를 가지고 있다는 점인것 같다. 


apply 이외에도 다른 명령어들이 있지만 우선은 이것만 이해하는걸로 하자.





728x90
반응형

+ Recent posts