λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

Container/Kubernetes

[Kubernetes] νŒŒλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 또 λ‹€λ₯Έ μ˜€λΈŒμ νŠΈλ“€: Jobs, DaemonSets, StatefulSets

λ°˜μ‘ν˜•

πŸ”Š ν•΄λ‹Ή ν¬μŠ€νŒ…μ€ μ‹œμž‘ν•˜μ„Έμš”! 도컀/μΏ λ²„λ„€ν‹°μŠ€ μ„œμ μ„ 읽고 개인적인 λͺ©μ  ν•˜μ— μž‘μ„±λ˜λŠ” κΈ€μž…λ‹ˆλ‹€. ν¬μŠ€νŒ…μ— μ‚¬μš©λ˜λŠ” λͺ¨λ“  μžλ£ŒλŠ” μ œκ°€ 직접 μž¬κ΅¬μ„±ν•˜μ˜€μŒμ„ μ•Œλ¦½λ‹ˆλ‹€.
 

Kubernetes


이번 ν¬μŠ€νŒ…μ—μ„œλŠ” νŒŒλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 또 λ‹€λ₯Έ μƒμœ„ λ¦¬μ†ŒμŠ€ μ˜€λΈŒμ νŠΈλ“€λ‘œ Jobs, DaemonSet, StatefulSet에 λŒ€ν•΄μ„œ μ•Œμ•„λ³΄λ„λ‘ ν•˜μž. μ§€κΈˆκΉŒμ§€ μ‚΄νŽ΄λ³Έ ReplicaSet, Deployment 와 같은 λ¦¬μ†ŒμŠ€ μ˜€λΈŒμ νŠΈλ“€λ„ λ°°μ› μ—ˆλŠ”λ°, 이것듀도 νŒŒλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” μƒμœ„ λ¦¬μ†ŒμŠ€ μ˜€λΈŒμ νŠΈλ“€μ΄λΌκ³  ν•  수 μžˆλ‹€. ν•˜μ§€λ§Œ νŒŒλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” λ¦¬μ†ŒμŠ€ μ˜€λΈŒμ νŠΈλ“€λ‘œμ„œ Jobs, DaemonSet, StatefulSet은 Replicaset, Deployment μ™€λŠ” μ•½κ°„ λ‹€λ₯Έ λͺ©μ μœΌλ‘œ μ‚¬μš©ν•˜κ³€ ν•œλ‹€. ν•˜λ‚˜μ”© μ‚΄νŽ΄λ³΄λ„λ‘ ν•˜μž.

1. νŠΉμ • λ™μž‘μ„ μˆ˜ν–‰ν•˜κ³  μ’…λ£Œν•΄! : Jobs

κ°€μž₯ λ¨Όμ € μ•Œμ•„λ³Ό λ¦¬μ†ŒμŠ€ μ˜€λΈŒμ νŠΈλŠ” Jobs 이닀. 사싀 JobsλŠ” 이λ₯Έλ°” '작' 이라고 λΆ€λ₯΄λ©° 특히 데이터 μ—”μ§€λ‹ˆμ–΄λ§μ΄λ‚˜ Airflowλ₯Ό 닀루어본 μ‚¬λžŒλ“€μ—κ²ŒλŠ” μ΅μˆ™ν•œ μš©μ–΄μΌ 수 μžˆλ‹€. Job에 λŒ€ν•΄μ„œ μ •μ˜ν•˜λ©΄ "νŠΉμ • λ™μž‘μ„ μˆ˜ν–‰ν•˜κ³  μ’…λ£Œν•΄μ•Ό ν•˜λŠ” μž‘μ—…μ„ μœ„ν•œ 였브젝트"이닀. νŒŒλ“œλ₯Ό μƒμ„±ν•΄μ„œ μ–΄λ–€ λ™μž‘μ„ μˆ˜ν–‰μ‹œν‚¨λ‹€λŠ” μ μ—μ„œλŠ” ReplicaSet μ΄λ‚˜ Deployment 와 λ™μΌν•˜λ‹€κ³  λ³Ό 수 μžˆλ‹€. ν•˜μ§€λ§Œ 큰 차이점은 νŒŒλ“œμ˜ μ΅œμ’… μƒνƒœμ΄λ‹€

 

ReplicaSet μ΄λ‚˜ DeploymentλŠ” 보톡 항상 운영되고 μžˆμ–΄μ•Ό ν•˜λŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„μ— 주둜 이용되며 이런 λ¦¬μ†ŒμŠ€ μ˜€λΈŒμ νŠΈλ“€μ΄ 지ν–₯ν•˜λŠ” νŒŒλ“œμ˜ μ΅œμ’… μƒνƒœλŠ” μ‹€ν–‰ 쀑 즉, Running 이닀. ν•˜μ§€λ§Œ Job이 지ν–₯ν•˜λŠ” νŒŒλ“œμ˜ μ΅œμ’… μƒνƒœλŠ” 정상 μ’…λ£Œ 즉, Completed 이닀.(참고둜 νŒŒλ“œμ˜ μƒνƒœ μ’…λ₯˜μ— λŒ€ν•΄μ„œλŠ” 잘 λͺ¨λ₯Έλ‹€λ©΄ μ €λ²ˆ ν¬μŠ€νŒ…μ„ μ°Έμ‘°ν•˜μž) 즉, Job은 ν•΄λ‹Ή νŒŒλ“œ μ»¨ν…Œμ΄λ„ˆμ˜ init ν”„λ‘œμ„ΈμŠ€μ˜ μ’…λ£Œ μ½”λ“œ(exit code)κ°€ 0을 λ°˜ν™˜ν•΄μ•Ό ν•˜λŠ” 것을 λͺ©μ μœΌλ‘œ ν•œλ‹€.

 

그러면 Job을 μƒμ„±ν•˜λŠ” κ°„λ‹¨ν•œ μ˜ˆμ‹œ λ§€λ‹ˆνŽ˜μŠ€νŠΈλ₯Ό ν•˜λ‚˜ μ‚΄νŽ΄λ³΄μž.

 

apiVersion: batch/v1
kind: Job
metadata:
  name: zedd-hello-job
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - image: busybox
          args: ["sh", "-c", "echo Hello, World && exit 0"]
          name: zedd-hello-job

 

μœ„ λ§€λ‹ˆνŽ˜μŠ€νŠΈλ₯Ό 보면 Deployment λ§€λ‹ˆνŽ˜μŠ€νŠΈλž‘ 맀우 μœ μ‚¬ν•¨μ„ λ³Ό 수 μžˆλ‹€. 특히, template 뢀뢄에 νŒŒλ“œ ν…œν”Œλ¦Ώ μ˜μ—­μ„ μ •μ˜ν•˜λ©΄ λœλ‹€. ν•˜μ§€λ§Œ Job λ§€λ‹ˆνŽ˜μŠ€νŠΈλ₯Ό μž‘μ„±ν•  λ•ŒλŠ” μ£Όμ˜ν•΄μ•Ό ν•  점이 μžˆλ‹€. λ°”λ‘œ restartPolicy 이닀. μ €λ²ˆ ν¬μŠ€νŒ…μ—μ„œ 배운 κ²ƒμ²˜λŸΌ restartPolicyλŠ” νŒŒλ“œκ°€ μž¬μ‹œμž‘ν•˜λŠ” 정책을 잘 μ„€μ •ν•΄μ•Ό ν•œλ‹€. restartPolicy에 λͺ…μ‹œν•  수 μžˆλŠ” κ°’μœΌλ‘œλŠ” Always, Never, OnFailureκ°€ μžˆμ—ˆλŠ”λ°, 이 쀑 Never, OnFailure λ‘˜ 쀑 ν•˜λ‚˜λ‘œ λͺ…μ‹œν•΄μ£Όμ–΄μ•Ό ν•œλ‹€. 이λ₯Ό μ΄ν•΄ν•˜κΈ° μœ„ν•΄μ„œλŠ” Job의 λͺ©μ μ„ λ‹€μ‹œ μƒκΈ°μ‹œν‚¬ ν•„μš”κ°€ μžˆλ‹€. 

 

λ‹€μ‹œ ν•œλ²ˆ μ΄μ•ΌκΈ°ν•˜μ§€λ§Œ, Job의 λͺ©μ μ€ νŒŒλ“œκ°€ 정상 μ‹€ν–‰λ˜κ³  '정상 μ’…λ£Œ'λ˜λŠ” 것을 λͺ©ν‘œλ‘œ ν•œλ‹€. λ”°λΌμ„œ, 정상 μ’…λ£Œλ¨μ—λ„ λ‹€μ‹œ μž¬μ‹œμž‘ν•˜λ„λ‘ λͺ…μ‹œν•˜λŠ” Alwaysλ₯Ό μ‚¬μš©ν•΄μ„œλŠ” μ•ˆλ˜λŠ” 것이닀. 

 

그리고 args μΈμžμ—μ„œ 보닀 μ‹œν”Ό νŒŒλ“œ μ»¨ν…Œμ΄λ„ˆμ˜ init ν”„λ‘œμ„ΈμŠ€ λ§ˆμ§€λ§‰μ— μ’…λ£Œ μ½”λ“œλ₯Ό 0을 λ°˜ν™˜ν•¨μœΌλ‘œμ¨ 잘 μ’…λ£Œλ˜λ„λ‘ ν•΄μ£Όμ—ˆλ‹€.

 

μ΄λ ‡κ²Œ Job은 보톡 배치(Batch) μž‘μ—…μ„ μœ„ν•΄ 주둜 μ‚¬μš©λ˜κ³€ ν•œλ‹€. ν¬λ‘€λ§μ΄λ‚˜ 데이터 ETL, ν”„λ ˆμž„ λ Œλ”λ§, 파일 인코딩 λ“±κ³Ό 같이 ν•œ 번 μˆ˜ν–‰ν•˜κ³  μ’…λ£Œλ˜λ©΄ λ˜λŠ” μž‘μ—…λ“€μ— 주둜 μ‚¬μš©λœλ‹€. μ£Όμ˜ν•  점으둜 Job은 λ™μ‹œμ„±μ„ μ—„κ²©ν•˜κ²Œ 지킀고 보μž₯ν•΄μ•Ό ν•˜λŠ” 병렬 처리λ₯Ό μœ„ν•΄ μ‚¬μš©ν•˜λŠ” 것은 μ•„λ‹ˆλΌλŠ” 점을 μ•Œμ•„λ‘μž. 그리고 Job이 μ‹€ν–‰ν•˜λŠ” νŒŒλ“œκ°€ μ‹€νŒ¨ν•˜λ©΄ restartPolicy에 따라 μž¬μ‹œμž‘λ  μˆ˜λ„ μžˆμœΌλ‹ˆ Job이 μ²˜λ¦¬ν•˜λŠ” λ‘œμ§μ€ λ©±λ“±μ„±(연산을 μ—¬λŸ¬ 번 μ μš©ν•΄λ„ κ²°κ³Όκ°€ 달라지지 μ•ŠλŠ” νŠΉμ„±)을 κ°€μ§€λŠ” 것이 μ’‹λ‹€.

 

Job을 μ’€ 더 μ„Έλ°€ν•˜κ²Œ μ‚¬μš©ν•˜λŠ” 방법에 λŒ€ν•΄μ„œ μ•ŒκΈ° μœ„ν•΄ Job의 μ˜΅μ…˜μ— λŒ€ν•΄μ„œ μ•Œμ•„λ³΄λ„λ‘ ν•˜μž. 크게 2가지가 μ‘΄μž¬ν•œλ‹€. 방금 μ‚΄νŽ΄λ³Έ λ§€λ‹ˆνŽ˜μŠ€νŠΈμ— μ˜΅μ…˜ 2가지λ₯Ό μΆ”κ°€ν•΄λ³΄μ•˜λ‹€.

 

apiVersion: batch/v1
kind: Job
metadata:
  name: zedd-hello-job
spec:
  completions: 3
  parallelism: 1
  template:
    spec:
      restartPolicy: OnFailure
      containers:
        - image: busybox
          args: ["sh", "-c", "echo Hello, World && exit 0"]
          name: zedd-hello-job

 

μ²«λ²ˆμ§Έλ‘œλŠ” spec.completions 이닀. 이 값은 Job이 μ„±κ³΅ν–ˆλ‹€κ³  여겨지렀면 λͺ‡ 개의 νŒŒλ“œκ°€ 성곡 즉, λͺ‡ 개의 νŒŒλ“œκ°€ 정상 μ’…λ£Œλ˜μ–΄μ•Ό ν•˜λŠ”μ§€λ₯Ό μ„€μ •ν•œλ‹€. κΈ°λ³Έ 값은 1이닀. λ‹€μ‹œ 말해, μœ„ Job λ§€λ‹ˆνŽ˜μŠ€νŠΈλ₯Ό apply ν•˜λ©΄ νŒŒλ“œ ν…œν”Œλ¦Ώμ— λͺ…μ‹œλ˜μ–΄ μžˆλŠ” busybox νŒŒλ“œ μ»¨ν…Œμ΄λ„ˆκ°€ 순차적으둜 3개 생성이 되고, 3개 λͺ¨λ‘ 정상 μ’…λ£Œλ˜λ©΄ Job이 μ„±κ³΅ν–ˆλ‹€κ³  μ—¬κ²¨μ§„λ‹€λŠ” λœ»μ΄λ‹€.

 

그런데 방금 busybox νŒŒλ“œ μ»¨ν…Œμ΄λ„ˆκ°€ '순차적으둜' 3개 생성이 λœλ‹€κ³  ν–ˆλ‹€. κΌ­ μ΄λ ‡κ²Œ 1κ°œκ°€ 생성 및 μ’…λ£Œκ°€ 되고 λ‚œ λ‹€μŒ λ‹€λ₯Έ 1κ°œκ°€ μƒμ„±λ˜μ–΄μ•Ό ν• κΉŒ? μ΄μœ λŠ” λ°”λ‘œ spec.parallelism 값이 1이기 λ•Œλ¬Έμ΄λ‹€. spec.parallelismλŠ” λ™μ‹œμ— 생성될 νŒŒλ“œμ˜ 개수λ₯Ό μ„€μ •ν•˜λŠ” 값이닀. 이 값도 λ””ν΄νŠΈ 값이 1이닀. λ”°λΌμ„œ μœ„ λ§€λ‹ˆνŽ˜μŠ€νŠΈμ—μ„œλŠ” spec.parallelism에 1을 λͺ…μ‹œν–ˆκΈ° λ•Œλ¬Έμ— '순차적으둜' νŒŒλ“œκ°€ 1κ°œμ”© 생성 및 μ’…λ£Œλ˜λŠ” 것이닀.

 

λ§Œμ•½ spec.parallelism을 3으둜 λ°”κΎΈλ©΄ μ–΄λ–»κ²Œ 될까? 3개의 νŒŒλ“œκ°€ λ™μ‹œμ— μƒμ„±λ˜κ³  μ’…λ£Œλ˜λŠ” 것을 λ³Ό 수 μžˆλ‹€.

 

μΆ”κ°€λ‘œ μ•Œμ•„λ‘˜ 점은 Job의 νŒŒλ“œκ°€ μ‹€νŒ¨ν•˜λ©΄ restartPolicy에 λͺ…μ‹œλœ 정책에 μ˜ν•΄ νŒŒλ“œκ°€ μž¬μ‹œμž‘(OnFailure)λ˜κ±°λ‚˜ μ•„λ‹ˆλ©΄ μƒˆλ‘œμš΄ νŒŒλ“œλ₯Ό λ‹€μ‹œ 생성(Never)ν•œλ‹€κ³  ν–ˆλ‹€. 이 λ•Œ, Jobμ—μ„œλŠ” νŒŒλ“œκ°€ μ‹€νŒ¨ν•  μ‹œ μ΅œλŒ€ 6λ²ˆκΉŒμ§€ μž¬μ‹œλ„λ₯Ό μˆ˜ν–‰ν•œλ‹€. λ¬Όλ‘  이 μž¬μ‹œλ„ μ΅œλŒ€ νšŸμˆ˜λ„ spec.backoffLimit κ°’μœΌλ‘œ μ»€μŠ€ν„°λ§ˆμ΄μ§• ν•  수 μžˆλ‹€. λ˜ν•œ Job의 νŒŒλ“œκ°€ λͺ¨μ’…μ˜ 이유둜 μž‘μ—…μ΄ μ§„ν–‰λ˜μ§€ μ•Šκ³  계속 νŽœλ”©λ˜λŠ” 경우, Job은 성곡도 μ‹€νŒ¨λ„ μ•„λ‹Œ μ€‘κ°„μ˜ μƒνƒœλ‘œ μ˜€λžœμ‹œκ°„ 머무λ₯Ό μˆ˜κ°€ μžˆλ‹€. μ΄λŸ¬ν•œ μƒν™©μ—μ„œ λΉ μ Έλ‚˜μ˜€κΈ° μœ„ν•΄ Job의 νŒŒλ“œκ°€ 싀행될 수 μžˆλŠ” μ΅œλŒ€ μ‹œκ°„μ„ spec.activeDeadlineSeconds μ˜΅μ…˜μœΌλ‘œ μ œν•œν•  μˆ˜λ„ μžˆλ‹€. ν•΄λ‹Ή μ‹œκ°„λ³΄λ‹€ 더 였래 쀑간 μƒνƒœλ‘œ 머무λ₯Έλ‹€λ©΄ νŒŒλ“œλŠ” κ°•μ œ μ’…λ£Œλ˜λ©° νŒŒλ“œμ˜ μƒνƒœλŠ” 비정상 μ’…λ£Œλ‘œ 여겨진닀.

2. Jobs에 주기적인 λ°˜λ³΅μ„ λ”ν•˜λ‹€: CronJobs

λ‹€μŒμœΌλ‘œ μ•Œμ•„λ³Ό λ¦¬μ†ŒμŠ€ μ˜€λΈŒμ νŠΈλŠ” Jobs의 μžλ§€ν’ˆ 격이라고 ν•  수 μžˆλŠ” 크둠작(Cronjobs)이닀. CronjobsλŠ” Jobsλ₯Ό 주기적인 κ°„κ²©μœΌλ‘œ μ‹€ν–‰ν•˜λŠ” λ¦¬μ†ŒμŠ€ 였브젝트인데, 특히 Unix 계열 OSμ—μ„œμ˜ Cron μŠ€μΌ€μ₯΄λ§μ„ μ‚¬μš©ν•΄λ³Έ μ‚¬λžŒμ΄λΌλ©΄ 맀우 μ΅μˆ™ν•  것이닀. μ‹€μ œλ‘œ Cron μŠ€μΌ€μ₯΄λ§ κ·œμΉ™μ„ κ·ΈλŒ€λ‘œ μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ— 더 μ΄ν•΄ν•˜κΈ° 쉽닀. μ˜ˆμ‹œ λ§€λ‹ˆνŽ˜μŠ€νŠΈλŠ” λ‹€μŒκ³Ό κ°™λ‹€.

 

apiVersion: batch/v1
kind: CronJob
metadata:
  name: zedd-cronjob
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
            - name: zedd-cronjob
              image: busybox
              args: ["sh", "-c", "echo Hello World && exit 0"]

 

μΆ”κ°€λœ λ‚΄μš©μ€ spec.schedule κ³Ό spec.jobTemplate μ˜μ—­μ΄λ‹€. spec.schedule μ—λŠ” ν•΄λ‹Ή CronJob을 μ–΄λŠ κ°„κ²©μœΌλ‘œ 싀행할지λ₯Ό λͺ…μ‹œν•œλ‹€. 그리고 spec.jobTemplate μ˜μ—­μ—λŠ” 직전 λͺ©μ°¨μ—μ„œ λ³Έ Job λ§€λ‹ˆνŽ˜μŠ€νŠΈμ—μ„œ spec.template μ˜μ—­ 즉, νŒŒλ“œ ν…œν”Œλ¦Ώμ„ λͺ…μ‹œν•΄μ£Όλ©΄ λœλ‹€.

(참고둜 μ˜λ„ν•˜λŠ” μ£ΌκΈ°λ₯Ό Cron μŠ€μΌ€μ₯΄λ§λ‘œ μ–΄λ–»κ²Œ κ·œμΉ™ν™”μ‹œν‚€λŠ”μ§€ ν—·κ°ˆλ¦°λ‹€λ©΄ μ—¬κΈ°λ₯Ό μ°Έμ‘°ν•΄λ³΄μž. λ§ˆμ΄λ„ˆν•˜κ²Œ μœ μš©ν•˜λ‹€)

 

그리고 λ§€λ‹ˆνŽ˜μŠ€νŠΈμ— kindκ°€ Jobκ³Ό 달리 CronJob으둜 λͺ…μ‹œλ˜μ–΄ μžˆμ§€λ§Œ μΏ λ²„λ„€ν‹°μŠ€ μƒμ—μ„œ λ¦¬μ†ŒμŠ€λ₯Ό μ‘°νšŒν•  λ•ŒλŠ” jobs둜 두 개 λͺ¨λ‘ μ‘°νšŒκ°€ λœλ‹€. 그리고 μ‘°νšŒν•  λ•Œ κΈ°λ³Έμ μœΌλ‘œλŠ” μ„±κ³΅ν•œ 작의 기둝은 μ΅œλŒ€ 3κ°œκΉŒμ§€, μ‹€νŒ¨ν•œ 작의 기둝은 μ΅œλŒ€ 1κ°œκΉŒμ§€λ§Œ κΈ°λ‘λ˜μ§€λ§Œ, 이 μ„€μ • 값도 Job λ˜λŠ” CronJob λ§€λ‹ˆνŽ˜μŠ€νŠΈμ— spec.successfulJobsHistoryLimit κ³Ό spec.failedJobsHistoryLimit κ°’μœΌλ‘œ μ»€μŠ€ν„°λ§ˆμ΄μ§• ν•  수 μžˆλ‹€.

3. λͺ¨λ“  λ…Έλ“œμ— νŒŒλ“œλ₯Ό ν•˜λ‚˜μ”© ν• λ‹Ήν•˜μž: DaemonSets

λ‹€μŒμœΌλ‘œ μ•Œμ•„λ³Ό λ¦¬μ†ŒμŠ€ μ˜€λΈŒμ νŠΈλŠ” 데λͺ¬μ…‹(DaemonSets)이닀. DaemonSets은 λ™μΌν•œ νŒŒλ“œλ₯Ό μΏ λ²„λ„€ν‹°μŠ€ ν΄λŸ¬μŠ€ν„° λ‚΄μ˜ λͺ¨λ“  λ…Έλ“œμ— ν•˜λ‚˜μ”© μƒμ„±ν•˜λŠ” 것을 λͺ©μ μœΌλ‘œ ν•œλ‹€. κ·Έλž˜μ„œ DaemonSets은 주둜 λ‘œκΉ…, λͺ¨λ‹ˆν„°λ§, λ„€νŠΈμ›Œν‚Ή 등을 μœ„ν•œ μ—μ΄μ „νŠΈλ₯Ό 각 λ…Έλ“œμ— 생성해야 ν•  λ•Œ 주둜 μ‚¬μš©ν•œλ‹€. 단적인 예둜, μΏ λ²„λ„€ν‹°μŠ€ λ„€νŠΈμ›Œν‚Ήμ„ μœ„ν•œ kube-proxy λ‚˜ calico λ„€νŠΈμ›Œν¬ ν”ŒλŸ¬κ·ΈμΈ, 그리고 λ§€λ‹ˆμ§€λ“œ λͺ¨λ‹ˆν„°λ§ μ‹œμŠ€ν…œμΈ λ°μ΄ν„°λ…μ˜ datadog-agent 등이 μžˆλ‹€. DaemonSets을 μƒμ„±ν•˜λŠ” μ˜ˆμ‹œ λ§€λ‹ˆνŽ˜μŠ€νŠΈλ₯Ό μ‚΄νŽ΄λ³΄μž.

 

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: zedd-daemonset
spec:
  selector:
    matchLabels:
      name: zedd-daemonset-pod
  template:
    metadata:
      labels:
        name: zedd-daemonset-pod
    spec:
      tolerations:
        - key: node-role.kubernetes.io/master
          effect: NoSchedule
      containers:
        - name: busybox-pod
          image: busybox
          args: ["tail", "-f", "/dev/null"]
          resources:
            limits:
              cpu: 100m
              memory: 200Mi

 

DaemonSets λ§€λ‹ˆνŽ˜μŠ€νŠΈλ„ Deployment λ§€λ‹ˆνŽ˜μŠ€νŠΈλž‘ μœ μ‚¬ν•˜λ‹€. 특히, Deploymentμ—μ„œ 라벨 μ…€λ ‰ν„°λ₯Ό μ΄μš©ν•΄ νŠΉμ • 라벨을 κ°–λŠ” νŒŒλ“œλ“€μ„ 관리할 수 μžˆλ„λ‘ ν•œ κ²ƒμ²˜λŸΌ DaemonSets도 라벨 μ…€λ ‰ν„°λ₯Ό μ΄μš©ν•΄ νŠΉμ • 라벨을 κ°–λŠ” νŒŒλ“œλ₯Ό κ΄€λ¦¬ν•œλ‹€. DaemonSetsμ—μ„œ 라벨 셀렉터도 spec.selector.matchLabels μ˜μ—­μ— λͺ…μ‹œν•œ λ ˆμ΄λΈ”μ΄ νŒŒλ“œ ν…œν”Œλ¦Ώ μ˜μ—­ 즉, spec.template.metadata.labels μ˜μ—­κ³Ό μΌμΉ˜μ‹œμΌœμ£Όμ–΄μ•Ό ν•œλ‹€.

 

μΆ”κ°€λ‘œ, λ§ˆμŠ€ν„° λ…Έλ“œμ—λ„ ν•΄λ‹Ή νŒŒλ“œκ°€ 할당될 수 μžˆλ„λ‘ tolerations을 μΆ”κ°€ν–ˆλ‹€. 이 뢀뢄은 ν•„μˆ˜μ μΈ 것은 μ•„λ‹ˆλ‹€. λ˜ν•œ μœ„ λ§€λ‹ˆνŽ˜μŠ€νŠΈμ—μ„œ resources μ˜μ—­μ„ 보면 νŒŒλ“œμ˜ λ¦¬μ†ŒμŠ€λ₯Ό Guaranteed 클래슀둜 μ„€μ •ν–ˆλ‹€. 즉, requests 와 limits 값이 λͺ¨λ‘ λ™μΌν•˜κ²Œ ν•œ 것이닀.(μœ„ λ§€λ‹ˆνŽ˜μŠ€νŠΈμ—μ„œλŠ” requests μ˜μ—­μ΄ μƒλž΅λ˜μ–΄ μžˆμ§€λ§Œ μ΄λ ‡κ²Œ ν•˜λ©΄ λͺ…μ‹œλœ limits의 값을 requests와 λ™μΌν•˜κ²Œ μžλ™μ„€μ •ν•œλ‹€) 

 

μ΄λ ‡κ²Œ Gruaranteed 클래슀둜 μ„€μ •ν•œ 것은 데λͺ¬μ…‹μ΄λΌλŠ” 것이 보톡 λͺ¨λ“  λ…Έλ“œμ— λŒ€ν•œ μ—μ΄μ „νŠΈ 역할을 ν•˜κΈ° λ•Œλ¬Έμ— μ€‘μš”ν•œ 역할을 ν•  κ²ƒμž„μ„ μ˜λ―Έν•œλ‹€. λ”°λΌμ„œ λ¦¬μ†ŒμŠ€ λΆ€μ‘±μœΌλ‘œ 인해 데λͺ¬μ…‹ νŒŒλ“œλ“€μ΄ μ’…λ£Œλ˜λŠ” 것을 λ§‰κ³ μž Guaranteed 클래슀둜 μ„€μ •ν•˜λ„λ‘ ν•˜λŠ” 것이 κΆŒκ³ λœλ‹€.

4. μƒνƒœ(State)λ₯Ό κ°–λŠ” νŒŒλ“œλ₯Ό κ΄€λ¦¬ν•œλ‹€: StatefulSets

일반적으둜 μΏ λ²„λ„€ν‹°μŠ€μ—μ„œλŠ” μƒνƒœλ₯Ό 갖지 μ•ŠλŠ” 즉, Statelessν•œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ λ‹€λ£¨λŠ” κ²½μš°κ°€ λ§Žλ‹€. 이λ₯Ό μœ„ν•΄μ„œλŠ” κ·Έλ™μ•ˆ μš°λ¦¬κ°€ μ•Œμ•„λ³΄μ•˜λ˜ λ””ν”Œλ‘œμ΄λ¨ΌνŠΈμ™€ 같은 λ¦¬μ†ŒμŠ€ 였브젝트λ₯Ό μ΄μš©ν•΄μ„œ κ΄€λ¦¬ν•˜λ©΄ λœλ‹€. ν•˜μ§€λ§Œ λ°μ΄ν„°λ² μ΄μŠ€ μ„œλ²„μ™€ 같이 μƒνƒœλ₯Ό κ°–λŠ” 즉, Statefulν•œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μΏ λ²„λ„€ν‹°μŠ€μ—μ„œ μ‹€ν–‰ν•˜κ³  κ΄€λ¦¬ν•˜λŠ” 것은 κ½€λ‚˜ λ³΅μž‘ν•œ 일이 λœλ‹€. μ™œλƒν•˜λ©΄ 'μƒνƒœ'λ₯Ό κ°–λŠ”λ‹€λŠ” 것은 곧 'μƒνƒœ'λ₯Ό λ‚˜νƒ€λ‚΄λŠ” '데이터'λ₯Ό νŒŒλ“œ λ‚΄λΆ€μ—μ„œ μ–΄λ–»κ²Œ 관리할지, 또 μ™ΈλΆ€μ—μ„œ μƒνƒœλ₯Ό κ°–λŠ” νŒŒλ“œλ“€μ— μ–΄λ–»κ²Œ 접근할지 등에 λŒ€ν•΄μ„œ κ³ λ €ν•΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

 

μΏ λ²„λ„€ν‹°μŠ€μ—μ„œλŠ” μƒνƒœλ₯Ό κ°–λŠ” νŒŒλ“œλ₯Ό μœ„ν•΄ StatefulSets μ΄λΌλŠ” λ¦¬μ†ŒμŠ€ 였브젝트λ₯Ό μ œκ³΅ν•΄μ„œ μƒνƒœλ₯Ό κ°–λŠ” νŒŒλ“œλ₯Ό μ™„λ²½νžˆλŠ” μ•„λ‹ˆμ§€λ§Œ, μ–΄λŠμ •λ„ 관리할 수 μžˆλ„λ‘ κΈ°λŠ₯을 μ œκ³΅ν•΄μ€€λ‹€. 

 

λ¨Όμ € μƒνƒœλ₯Ό κ°–λŠ” νŒŒλ“œμ™€ μƒνƒœλ₯Ό 갖지 μ•ŠλŠ” νŒŒλ“œ κ°„μ˜ 차이점이 무엇인지 μ΄ν•΄ν•˜κΈ° μœ„ν•΄ μ‹€μ œ μΏ λ²„λ„€ν‹°μŠ€μ—μ„œ λΉ„μœ λ₯Ό λ“€μ–΄λ³΄μž. λ¨Όμ € μƒνƒœλ₯Ό 갖지 μ•ŠλŠ” Stateless νŒŒλ“œλ₯Ό 'κ°€μΆ•'이라고 ν•  수 μžˆλ‹€. κ°€μΆ•μ΄λΌλŠ” λ‹¨μ–΄μ˜ 사전적 μ˜λ―ΈλŠ” 'μ§‘μ—μ„œ κΈ°λ₯΄λŠ” 짐승. μ†Œ, 말, 돼지, 개 λ‹­, λ“±. 작짐승' 이닀. μ—¬κΈ°μ„œ μš°λ¦¬κ°€ μ£Όλͺ©ν•  뢀뢄은 이 가좕에 μ†ν•˜λŠ” μ§μŠΉλ“€μ€ μ–Έμ œλ“ μ§€ λŒ€μ²΄λ  수 있고 각각을 κ³ μœ ν•œ 쑴재둜 여기지 μ•ŠλŠ”λ‹€λŠ” 것이닀. 이λ₯Ό μΏ λ²„λ„€ν‹°μŠ€ λ””ν”Œλ‘œμ΄λ¨ΌνŠΈλ‘œ μ—°κ²°μ‹œμΌœλ³΄λ©΄, λ””ν”Œλ‘œμ΄λ¨ΌνŠΈκ°€ κ΄€λ¦¬ν•˜λŠ” νŒŒλ“œλ“€μ€ μ–Έμ œλ“ μ§€ λŒ€μ²΄λ  수 μžˆλ‹€. μΌλ‘€λ‘œ, 이미 Running 쀑인 νŒŒλ“œλ₯Ό μž¬μ‹œμž‘ν•˜λ©΄ μƒˆλ‘œ μƒμ„±λ˜λŠ” νŒŒλ“œλŠ” 이전에 μ‹€ν–‰λ˜κ³  있던 νŒŒλ“œλž‘μ€ λ‹€λ₯Έ μ‘΄μž¬μ΄λ‹€. λ‹€λ₯Έ μ‘΄μž¬μž„μ„ μ–΄λ–»κ²Œ μ•Œ 수 μžˆλƒκ³ ? νŒŒλ“œ 이름 끝에 λΆ™λŠ” 해쉬값이 λ‹¬λΌμ§μœΌλ‘œμ¨ 인식할 수 μžˆλ‹€. μ‹€μ œ νŒŒλ“œκ°€ μž¬μ‹œμž‘λ˜λ©΄ 끝에 해쉬값이 λ³€κ²½λ˜μ–΄ μƒˆλ‘œμš΄ νŒŒλ“œκ°€ μƒμ„±λ˜λŠ” 것을 λ³Ό 수 μžˆλ‹€. λ”°λΌμ„œ μš°λ¦¬λŠ” Stateless νŒŒλ“œλ₯Ό 이λ₯Έλ°” 'κ°€μΆ•'이라고 λΉ„μœ ν•˜λŠ” μ…ˆμ΄λ‹€.

 

λ°˜λ©΄μ— μƒνƒœλ₯Ό κ°–λŠ” Stateful νŒŒλ“œλŠ” '애완동물'이라고 ν•  수 μžˆλ‹€. 반렀견 λ˜λŠ” 반렀묘 λ“± μ–΄λ– ν•œ 동물을 μ• μ™„λ™λ¬Όλ‘œμ„œ ν‚€μš°λŠ” μ‚¬λžŒλ“€μ„ 보면 κ·Έ 동물 ν•œ λ§ˆλ¦¬λ§ˆλ‹€ κ³ μœ ν•œ 이름을 λΆ™μ—¬μ€€λ‹€.(ex. ν˜Έλ‘, 흰λ‘₯이, λˆ„λ μ΄, .... λ“±λ“±..) μ΄λ ‡κ²Œ κ³ μœ ν•œ 이름을 λΆ™μ—¬μ€€λ‹€λŠ” 것은 λŒ€μ²΄ λΆˆκ°€λŠ₯ν•œ μ‘΄μž¬λΌλŠ” κ±Έ μ˜λ―Έν•˜λ©°, κ³ μœ ν•œ μ‹λ³„μžλ₯Ό κ°–λŠ”λ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€. μΏ λ²„λ„€ν‹°μŠ€μ—μ„œλŠ” μ΄λŸ¬ν•œ 역할을 StatefulSets λ¦¬μ†ŒμŠ€ μ˜€λΈŒμ νŠΈκ°€ ν•œλ‹€. κ·Έλž˜μ„œ StatefulSets은 λ””ν”Œλ‘œμ΄λ¨ΌνŠΈμ™€ 달리 μž¬μ‹œμž‘ν•΄λ„ λ™μΌν•œ νŒŒλ“œ μ΄λ¦„μœΌλ‘œ 생성이 λœλ‹€. μ—¬λ‹΄μ΄μ§€λ§Œ, StatefulSets은 μΏ λ²„λ„€ν‹°μŠ€ 1.5 이전 λ²„μ „μ—λŠ” μ‹€μ œλ‘œ 'PetSets' λΌλŠ” μ΄λ¦„μ΄μ—ˆλ‹€.

 

StatefulSetsκ°€ μ–΄λ–€ κ°œλ…μΈμ§€ 이둠적으둜 μ΄ν•΄ν•΄λ³΄μ•˜λ‹€. 그러면 이제 StatefulSets에 λŒ€ν•œ λ§€λ‹ˆνŽ˜μŠ€νŠΈ μ˜ˆμ‹œλ₯Ό ν•˜λ‚˜ μ‚΄νŽ΄λ³΄μž. 

 

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: example-statefulsets
spec:
  serviceName: statefulsets-svc
  selector:
    matchLabels:
      name: zedd-statefulsets
  replicas: 3
  template:
    metadata:
      labels:
        name: zedd-statefulsets
    spec:
      containers:
        - name: statefulsets-container
          image: alicek106/rr-test:echo-hostname
          ports:
            - containerPort: 80
              name: web
---
apiVersion: v1
kind: Service
metadata:
  name: statefulsets-svc
spec:
  ports:
    - port: 80
      name: web
  clusterIP: None
  selector:
    name: zedd-statefulsets

 

μœ„ λ§€λ‹ˆνŽ˜μŠ€νŠΈμ˜ 의미λ₯Ό ν•˜λ‚˜μ”© μ‚΄νŽ΄λ³΄μž. λ¨Όμ € StatefulSet μ΄λΌλŠ” kindλ₯Ό λͺ…μ‹œν•¨μœΌλ‘œμ¨ μŠ€ν…Œμ΄νŠΈν’€μ…‹μ΄λΌλŠ” λ¦¬μ†ŒμŠ€ 였브젝트λ₯Ό μƒμ„±ν•œλ‹€. 이 λ§€λ‹ˆνŽ˜μŠ€νŠΈλŠ” λ””ν”Œλ‘œμ΄λ¨ΌνŠΈ λ§€λ‹ˆνŽ˜μŠ€νŠΈλž‘ 거의 μœ μ‚¬ν•˜λ‹€. λ‹€λ§Œ ν•œ 가지 차이점이 μžˆλŠ”λ° λ°”λ‘œ spec.serviceName ν•­λͺ©μ΄λ‹€. ν•΄λ‹Ή ν•­λͺ©μ—λŠ” μŠ€ν…Œμ΄νŠΈν’€μ…‹μ˜ νŒŒλ“œλ‘œ μ ‘κ·Όν•  수 μžˆλŠ” μ„œλΉ„μŠ€ 이름을 μž…λ ₯ν•΄μ•Ό ν•œλ‹€. 즉, μœ„ μ˜ˆμ‹œλ‘œ 따지면 kind에 Serviceλ₯Ό λͺ…μ‹œν•œ μ„œλΉ„μŠ€ λ¦¬μ†ŒμŠ€ 였브젝트의 이름인 "statefulsets-svc" λΌλŠ” 값을 κ·ΈλŒ€λ‘œ λͺ…μ‹œν•΄μ£Όμ–΄μ•Ό ν•œλ‹€.

 

그러면 이 spec.serviceName ν•­λͺ©μ„ μ •μ˜ν•¨μœΌλ‘œμ¨ μ–΄λ–€ νš¨κ³Όκ°€ λ°œμƒν•˜λŠ” 걸까? μš°μ„  ν•΄λ‹Ή ν•­λͺ©μ„ μ •μ˜ν•˜μ§€ μ•ŠλŠ” λ””ν”Œλ‘œμ΄λ¨ΌνŠΈμ˜ 경우 μ„œλΉ„μŠ€λ‘œ μš”μ²­μ΄ μ „λ‹¬λ˜λ©΄ μ„œλΉ„μŠ€λŠ” λžœλ€ν•œ νŒŒλ“œλ₯Ό μ„ νƒν•΄μ„œ νŠΉμ • νŒŒλ“œλ‘œ νŠΈλž˜ν”½μ„ μ „λ‹¬ν•œλ‹€. 그림으둜 도식화해보면 λ‹€μŒκ³Ό κ°™λ‹€.

 

λ””ν”Œλ‘œμ΄λ¨ΌνŠΈμ— μ„œλΉ„μŠ€λ₯Ό λΆ™ν˜”μ„ λ•Œ νŠΈλž˜ν”½ 전달 방식

 

ν•˜μ§€λ§Œ μŠ€ν…Œμ΄νŠΈν’€μ…‹μ„ μ‚¬μš©ν•œλ‹€λ©΄ νŒŒλ“œκ°€ μƒνƒœλ₯Ό κ°–κ³  있기 λ•Œλ¬Έμ— μ„œλΉ„μŠ€κ°€ λžœλ€ν•˜κ²Œ μš”μ²­μ„ μ „λ‹¬ν•˜λŠ” 게 μ•„λ‹Œ νŒŒλ“œμ˜ μ‹λ³„μžλ₯Ό 직접 μ§€μ •ν•΄μ„œ μš”μ²­μ„ 전달할 수 있게 ν•œλ‹€. 그림은 μ•„λž˜μ™€ κ°™λ‹€.

 

μŠ€ν…Œμ΄νŠΈν’€μ…‹μ— μ„œλΉ„μŠ€λ₯Ό λΆ™ν˜“μ„ λ•Œ νŠΈλž˜ν”½ 전달 방식

 

μœ„μ™€ 같이 νŒŒλ“œμ˜ μ‹λ³„μžλ₯Ό 직접 μ§€μ •ν•΄μ„œ μš”μ²­μ„ 전달할 수 μžˆλ„λ‘ ν•΄μ£ΌλŠ” μ„œλΉ„μŠ€λ₯Ό ν—€λ“œλ¦¬μŠ€(Headless) μ„œλΉ„μŠ€λΌκ³  ν•˜κ³ , μŠ€ν…Œμ΄νŠΈν’€μ…‹μ€ μ΄λŸ¬ν•œ ν—€λ“œλ¦¬μŠ€ μ„œλΉ„μŠ€λ₯Ό μ΄μš©ν•œλ‹€. λ§€λ‹ˆνŽ˜μŠ€νŠΈ μƒμ—μ„œλŠ” Service λ§€λ‹ˆνŽ˜μŠ€νŠΈμ˜ spec.clusterIP에 None 값을 λͺ…μ‹œν•¨μœΌλ‘œμ¨ μ‚¬μš©μ΄ κ°€λŠ₯ν•˜λ‹€. 참고둜 ν—€λ“œλ¦¬μŠ€ μ„œλΉ„μŠ€μ˜ 이름은 SRV λ ˆμ½”λ“œλ‘œ 쓰이기 λ•Œλ¬Έμ— 이둜 인해 ν—€λ“œλ¦¬μŠ€ μ„œλΉ„μŠ€μ˜ 이름을 톡해 νŒŒλ“œμ— μ ‘κ·Όν•  수 μžˆλŠ” IPλ₯Ό λ°˜ν™˜ν•˜κ²Œ λœλ‹€. 

 

μΆ”κ°€μ μœΌλ‘œ, StatefulSets은 주둜 PV(Persistent Volume)κ³Ό 자주 μ‚¬μš©λœλ‹€. μ™œλƒν•˜λ©΄ PVλ₯Ό μ΄μš©ν•˜λ©΄ StatefuleSets이 λ‚΄λΆ€μ—μ„œ κ΄€λ¦¬ν•˜λŠ” 데이터λ₯Ό μ˜μ†μ (persistent)으둜 보관할 수 있기 λ•Œλ¬Έμ΄λ‹€. 보톡 StatefuleSets도 μ—¬λŸ¬ 개의 νŒŒλ“œλ‘œ μš΄μ˜ν•˜κΈ° λ•Œλ¬Έμ— StatefulSetsκ°€ μƒμ„±ν•˜λŠ” 각 νŒŒλ“œλ§ˆλ‹€ PVC(Persistent Volume Claim)λ₯Ό λ³„λ„λ‘œ 생성해주어야 ν•˜λŠ” λ²ˆκ±°λ‘œμ›€μ΄ μžˆλ‹€. λ¬Όλ‘  이λ₯Ό μœ„ν•΄ StatefulSets λ¦¬μ†ŒμŠ€ 였브젝트 λ§€λ‹ˆνŽ˜μŠ€νŠΈμ—μ„œ μŠ€ν…Œμ΄νŠΈν’€μ…‹μ„ 생성할 λ•Œ νŒŒλ“œλ§ˆλ‹€ PVCλ₯Ό μžλ™μœΌλ‘œ μƒμ„±ν•¨μœΌλ‘œμ¨ PV도 κ·Έ μˆœκ°„ λ™μ μœΌλ‘œ 같이 μƒμ„±λ˜λŠ” λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œλΉ„μ Έλ‹ κΈ°λŠ₯을 μ‚¬μš©ν•  수 μžˆλ„λ‘ μ§€μ›ν•œλ‹€. μžμ„Έν•œ μ‚¬μš©λ²•μ€ κ³΅μ‹λ¬Έμ„œλ₯Ό 참쑰해보도둝 ν•˜μž. 

 

참고둜 μŠ€ν…Œμ΄νŠΈν’€μ…‹μ„ μ‚­μ œν•œλ‹€κ³  해도 PVC와 λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œλΉ„μ Έλ‹λœ PV도 같이 μ‚­μ œλ˜λŠ” 것은 μ•„λ‹˜μ„ μ•Œμ•„λ‘μž.

λ°˜μ‘ν˜•