Deployment와 Service

Deployment 와 Service 사용

Deployment

  • 파드 배포에 관한 객체
  • 단순히 파드를 배포하는 것 뿐 아니라 몇 개의 파드를 실행할 지 결정하는 것도 가능
  • Deployment를 이용해서 pod를 배포
    • nginx-deploy.yml 파일을 생성하고 작성
nginx-deploy.yml
#API 버전
apiVersion: apps/v1

#객체 종류
kind: Deployment


#객체에 대한 정보를 생성
#labels 가 중요
# Deployment의 Pod은 lable 기반으로 생성, 바꾸면 Pod 전부 다시 생성됨, Deployment 간의 label 이름은 달라야 함
metadata:
  name: nginx-deploy
  labels:
    app: nginx
spec:
  replicas: 2    #2개의 파드 생성
  selector:      #Deployment 가 관리할 파드를 선택
    matchLabels:
      app: nginx
  template:      #이 정보를 가지고 pod를 생성
    metadata:
      labels:
        app: nginx

    spec:        #컨테이너 정보
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
  • yaml 파일의 정보를 가지고 파드를 생성
kubectl apply -f nginx-deploy.yml
  • 모든 파드 삭제
kubectl delete pods --all
  • 파드 확인
kubectl get pods
  • Deployment로 배포한 replicas 에 설정한 파드의 개수를 유지할려고 하기 때문에 파드를 삭제하면 다시 생성해서 파드의 개수를 유지합니다. Pod로 만들면 삭제해도 복구가 되지 않습니다.
  • lables
    • 레이블이안 오브젝트에 키-값 쌍으로 리소스를 식별하고 속성을 지정하는데 사용을 하는데 일종의 카테고리라고 할 수 있습니다.
    • 아래 처럼 사용
    release: v1, v2
    environment: dev, production
    tier: frontend, backend
    app: webapp, middleware
    • 다른 객체와 연결을 할 때 label이 매핑이 되어야 합니다.
    • 모든 파드 이름 과 레이블 확인
    kubectl get pods -o custom-columns=NAME:metadata.name,LABELS:metadata.labels
    • Deployment 나 ReplicaSet은 파드를 직접적인 관계를 맺지 않고 자신의 레이블과 일치하는 파드가 개수만 맞게 존재하면 됩니다. 수동으로 레이블을 변경하게 되면 그 레이블에 맞게 파드가 생성되어야 된다고 판단
    • 레이블 변경
    kubectl label pods -l app=nginx --overwrite app=nginx-1
    • 파드 확인: 파드가 2개 추가 된 것을 확인할 수 있습니다.
    dh@swarm-manager:~/1024$ kubectl get pod
    NAME                           READY   STATUS              RESTARTS   AGE
    nginx-deploy-75fd5cdd7-45gcg   0/1     ContainerCreating   0          8s
    nginx-deploy-75fd5cdd7-569fb   0/1     ImagePullBackOff    0          10m
    nginx-deploy-75fd5cdd7-rdgcw   0/1     ImagePullBackOff    0          10m
    nginx-deploy-75fd5cdd7-rx28s   0/1     ContainerCreating   0          7s
    dh@swarm-manager:~/1024$ kubectl get pods -o custom-columns=NAME:metadata.name,LABELS:metadata.labels
    NAME                           LABELS
    nginx-deploy-75fd5cdd7-45gcg   map[app:nginx pod-template-hash:75fd5cdd7]
    nginx-deploy-75fd5cdd7-569fb   map[app:nginx-1 pod-template-hash:75fd5cdd7]
    nginx-deploy-75fd5cdd7-rdgcw   map[app:nginx-1 pod-template-hash:75fd5cdd7]
    nginx-deploy-75fd5cdd7-rx28s   map[app:nginx pod-template-hash:75fd5cdd7]
    • Deployment 나 ReplicaSet은 pod를 직접 관리하지 않기 때문에 레이블이 변경되면 변경된 레이블 아래 pod가 존재해야 한다고 판단
    • 레이블 변경 및 파드 확인
    dh@swarm-manager:~/1024$ kubectl label pods -l app=nginx-1 --overwrite app=nginx
    pod/nginx-deploy-75fd5cdd7-569fb labeled
    pod/nginx-deploy-75fd5cdd7-rdgcw labeled
    • 새로 만들어진 파드 2개가 소멸됨
    dh@swarm-manager:~/1024$ kubectl get pods 
    NAME                           READY   STATUS             RESTARTS   AGE
    nginx-deploy-75fd5cdd7-569fb   0/1     ImagePullBackOff   0          15m
    nginx-deploy-75fd5cdd7-rdgcw   0/1     ImagePullBackOff   0          15m
    • 맨 처음 nginx가 Deployment로 레이블을 생성해서 2개의 파드를 만들고 nginx-1로 labels를 수정하면 이 경우는 Deployment가 새로 만들어지는 것이 아니고 labels만 추가가 되서 Deployment 1개 와 새로운 labels 1개가 존재해서 총 4개의 파드가 존재하지만 변경한 labels를 nginx로 변경을 하면 labels에 nginx-1이 사라지기 때문에 다시 2개의 파드만 있으면 됨
  • Deployment가 자신의 내부 객체를 직접 관리하지 않고 이름을 통해서 연결되는 구조를 느슨한 결합이라고 함

Service

  • 기본적으로 파드는 같은 노드에 떠 있는 파드끼리만 통신이 가능

  • 다수의 노드에 떠 있는 파드 간의 통신이나 외부와의 통신을 위해서는 CNI 플러그인이 필요한데 이 때 파드에 위치한 서비스를 외부에서 접속할려면 서비스를 이용해야 함

  • 외부에서 파드에 접근하기 위해서는 포트포워딩 하는 방법이 있음

    • kubectl port-forward 파드이름 외부포트:내부포트
    • nginx-deploy-54b9c68f67-7xxbd 파드의 80번 포트를 호스트의 8000번 포트로 연결하도록 port-forwarding을 수행
    kubectl port-forward nginx-deploy-54b9c68f67-7xxbd 8000:80
  • 하나의 노드 안에 있는 파드끼리는 통신이 가능

  • 파드 와 파드끼리 IP를 안다면 통신이 가능

    • 파드는 고정된 위치에 있는 것이 아니고 소멸되었다가 다른 곳에서 만들어지는 동적인 개념
    • 파드 간의 통신: IP 이용
    • 파드 IP 정보 확인 kubectl describe 파드이름
    • 파드 삭제: kubectl delete pod 파드이름
    • 파드 이름 확인 kubectl get pod
    • 파드 IP 정보 확인: kubectl describe 파드이름
    • 파드의 IP가 변경된 것을 확인
  • 외부에서 서비스 이름으로 접근할 수 있도록 포트를 외부로 개방하기

    • 서비스를 생성하기 위한 nginx-svc.yml 파일을 생성하고 작성
nginx-svc.yml
apiVersion: v1

kind: Service # Service를 생성하는 yaml 파일

metadata:
  name: nginx-svc # Service 이름
  labels:
    app: nginx

spec:
  type: NodePort # NodePort를 이용해서 외부에 공개
  ports:
  - port: 8080
    nodePort: 31472
    targetPort: 80
  selector:
    app: nginx # app:nginx를 갖는 파드와 연결
  • 서비스 생성 kubectl apply -f nginx-svc.yml
  • 서비스 생성 확인 kubectl get svc
  • type
    • ClusterIP: 기본값으로 클러스터 내부의 다른 리소스들과 통신이 가능함. 이 때 IP 뿐 아니라 Service 이름으로도 통신이 가능
    • NodePort: 클러스터 외부에서 노드IP의 특정 포트로 들어오는 요청을 감지해서 해당 포트와 연결된 파드로 트래픽을 전달하는 것으로 이를 설정하면 ClusterIP도 자동으로 설정됨
    • LoadBalancer: LoadBalancer를 제공하는 Public Cloud와 연결할 때 사용하는데 NodePort와 ClusterIP는 자동 설정
    • ExternalName: selector 부분에 lables를 사용하지 않고 Domain Name을 직접 사용하고자 하는 경우 사용

롤백

  • 디플로이먼트는 기본적으로 롤링 업데이트와 함께 롤백도 지원
  • 롤백은 업데이트에 문제가 생겼을 때 이전 버전으로 바꿀 수 있는 기능
  • 새로운 이미지로 변경은 kubectl set image deployment 명령을 사용
    • 기본 배포된 이미지를 nginx:1.16.1로 변경
    kubectl set image deployment.v1.apps/nginx-deploy nginx=nginx:1.16.1
    • 확인
    kubectl describe deploy nginx-deploy
    • 존재하지 않는 버전으로 수정
    kubectl set image deployment/nginx-deploy nginx=nginx:1.200
    • 현재 상황 확인
    kubectl rollout status deployment/nginx-deploy
    kubectl get pods
    • 기존의 2개의 파드는 유지가 되지만 업데이트하다가 이미지를 가져올 수 없어서 업데이트가 이루어지지 않고 ImageBackoff 상태
    • 이전 버전으로 희귀
    kubectl rollout undo deployment/nginx-deploy
    • 업데이트 내역 확인
    kubectl rollout history deployment/nginx-deploy
    • 특정 revision으로 롤백이 가능
    kubectl rollout undo 디플로이먼트 --to-revision=번호
    
    kubectl rollout undo deployment/nginx-deploy --to-revision=1

ReplicaSet

  • 일정한 개수의 동일한 파드가 항상 실행되도록 관리해주는 객체
  • 필요한 이유는 서비스의 지속성 때문
  • 노드의 하드웨어에서 발생항는 장애 등의 이유로 파드를 사용할 수 없을 때 다른 노드에서 다시 생성해서 사용자에게 중단없는 서비스를 제공할 수 있음
  • yml 파일을 만들어서 실행
    • replicaset.yml 파일을 생성하고 작성
replicaset.yml
apiVersion: apps/v1

kind: ReplicaSet

metadata:
  name: 3-replicaset

spec:
  template:
    metadata:
      name: 3-replicaset
      labels:
        app: 3-replicaset
    spec:
      containers:
      - name: 3-replicaset
        image: nginx
        ports:
        - containerPort: 80
  replicas: 3
  selector:
    matchLabels:
      app: 3-replicaset
  • 적용 kubectl apply -f replicaset.yml
  • 스케일 변경: scale 명령과 --replicas=개수 옵션을 이용
  • 삭제는 delete 명령인데 –cascade=orphan 옵션을 이용하면 pod는 유지되고 replicaset 만 없어짐, 상위 객체만 날라감
kubectl delete -f replicaset.yml
kubectl delete -f replicaset.yml --cascade=orphan
Service 상위에서 하위
External IP: Domain Name 사용
   └── Load Balancer: 외부에서 public cloud의 load balancer를 통해서
        └── Node Port: 외부에서 Cluster 내부로
             └── Cluster IP: Cluster 내부에서 Service이름으로 Pod에 접근

DaemonSet

  • 모든 노드에 파드를 실행할 때 사용
  • 레플리카셋이 특정 개수의 파드를 유지하고자 할 때 사용하는 것이라면 데몬셋은 모든 노드에 파드를 배포할 때 사용
  • 모니터링이나 로그 수집에 이용
  • kind는 DaemonSet을 적용하면 되고 tier label을 이용해서 어떤 목적인지를 밝히는 경우가 많음
  • prom/node-exporter 이미지를 가지고 DaemonSet 생성
    • yaml 파일을 생성 (daemonset.yml)
daemonset.yml
apiVersion: apps/v1

kind: DaemonSet

metadata:
  name: prometheus-daemonset

spec:
  selector:
    matchLabels:
      tier: monitoring # 사용자 정의 레이블
      name: promethous-exporter
  template:
    metadata:
      labels:
        tier: monitoring
        name: promethous-exporter
    spec:
      containers:
      - name: promethous
        image: prom/node-exporter
        ports:
        - containerPort: 80

Job

  • 종류
    • job: 하나 이상의 파드가 특정한 파드의 정상적인 상태를 유지할 수 있도록 관리
      노드에 문제가 발생해서 특정 파드에 문제가 발생하면 정상적인 서비스를 할 수 있도록 새로운 파드를 다시 만드는 역할을 수행
    • cronjob: 주기적으로 어떤 액션을 발생시키는 잡
      어떤 액션을 얼마나 자주 발생시킬 지는 매니페스트에서 정의
  • cronjob의 메니페스트에는 schedule과 command라는 항목이 추가가 됨
  • 이미지를 사용할 때 아무런 옵션도 주지 않으면 이미지를 계속 다운로드 받을 수 있기 때문에 cronjob의 경우는 imagePullPolicy 속성을 이용해서 없을 때만 다운로드 받도록 해주어야 함
    • pod를 생성하는 작업은 pod를 만들 때는 이미지를 다운로드 받기 때문에 별문제가 없음
  • schedule 속성의 값을 설정하는 방법은 linux 의 crontab 가 동일, 5개의 항목(분 시 요일(0-6) 월 일)을 설정
  • CronJob을 수행하기 위한 yaml 파일 생성하고 실행
    • cronjob.yml 파일 생성하고 작성
cronjob.yml
apiVersion: batch/v1 # JJob의 경우 apiVersion이 batch/v1
kind: CronJob
metadata:
  name: asdf

spec:
  schedule: "*/1 * * * *" # Linux의 Crontab 설정 과 동일(명령문이 빠짐)
  jobTemplate: # Pod를 생성하는 경우는 template
    spec:
      template:
        spec:
          containers:
          - name: Hello
            image: busybox # minimum linux
            imagePullPolicy: IfNotPresent # 이미지가 존재하는 경우 어떻게 할 것인지 설정, 이 경우 없을 때만 Pull
            command: # 수행할 명령문 작성
            - /bin/sh
            - -c
            - date; echo Hi
          restartPolicy: OnFailure # 재시작 옵션 - 실패할 때에만 다시 시작
  • 크론잡 확인
dh@swarm-manager:~/1024$ kubectl get cronjob asdf
NAME   SCHEDULE      TIMEZONE   SUSPEND   ACTIVE   LAST SCHEDULE   AGE
asdf   */1 * * * *   <none>     False     3        52s             3m18s
  • NAME: cronjob의 이름
  • SCHEDULE: 스케쥴링 내용
  • TIMEZONE: 타임 존 설정 내용
  • SUSPEND: 지연 여부
  • ACTIVE: 수행한 횟수
  • LAST SCHEDULE: 마지막으로 수행되고 경과된 시간
  • AGE: 만들어져서 서비스된 시간
  • 크론잡의 수행 시 만들어지는 pod를 확인
kubectl get cronjob -w
  • status
Pending: 작업 준비 중

ContainerCreating: 컨테이너 생성 중

Completed: 명령어 수행이 완료됨

Terminating: 명령어 수행 중 중단
create: 새로 만듬
apply: 없으면 새로 만듬
delete: 이름으로 삭제
delete -f: 파일명으로 삭제