4장

4.1 모니터링

시스팀 구축 이후 운영하는 도중 발생하는 장애를 파악하고 이상이 발생했을 때 관리자에게 알리는 방법을 설명한다.

4.1.1 클러스터 상태 파악

EKS 컨트롤 플레인은 AWS를 통해 운영되는 관리형 서비스로 클러스터에 문제가 발생했는지 상태를 파악하는 정도로 충분히 활용할 수 있다.

4.1.2 Cloudwatch의 Container Insights로 애플리케이션 상태 파악

Cloudwatch의 Container Insights를 통해 애플리케이션 상태를 파악할 수 있는데 클러스터 노드, 파드, 네임스페이스, 서비스 레벨의 메트릭을 참조할 수 있다.

CloudWatch 에이전트를 데몬셋으로 동작시킨 후 필요한 메트릭을 CloudWatch로 전송하면 된다.

추가과정은

  1. 네임스페이스 생성

    kubectl apply -f https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/master/k8s-yaml-templates/cloudwatch-namespace.yaml
    
    namespace/amazon-cloudwatch created
  2. CloudWatch용 서비스 계정 생성

    kubectl apply -f https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/master/k8s-yaml-templates/cwagent-kubernetes-monitoring/cwagent-serviceaccount.yaml
    
    serviceaccount/cloudwatch-agent created
    clusterrole.rbac.authorization.k8s.io/cloudwatch-agent-role created
    clusterrolebinding.rbac.authorization.k8s.io/cloudwatch-agent-role-binding created
  3. CloudWatch 에이전트가 사용할 컨피그맵 생성

    curl -O https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/master/k8s-yaml-templates/cwagent-kubernetes-monitoring/cwagent-configmap.yaml
  4. CloudWatch 에이전트가 사용할 컨피그맵 파일 수정

    cat cwagent-configmap.yaml
    # create configmap for cwagent config
    apiVersion: v1
    data:
      # Configuration is in Json format. No matter what configure change you make,
      # please keep the Json blob valid.
      cwagentconfig.json: |
        {
          "logs": {
            "metrics_collected": {
              "kubernetes": {
                "cluster_name": "eks-work-cluster",
                "metrics_collection_interval": 60
              }
            },
            "force_flush_interval": 5
          }
        }
    kind: ConfigMap
    metadata:
    name: cwagentconfig
    namespace: amazon-cloudwatch
  5. 컨피그맵 생성

    kubectl apply -f cwagent-configmap.yaml
    configmap/cwagentconfig created
  6. CloudWatch 에이전트를 데몬셋으로 동작시키기

    kubectl apply -f https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/master/k8s-yaml-templates/cwagent-kubernetes-monitoring/cwagent-daemonset.yaml
    daemonset.apps/cloudwatch-agent created

CloudWatch 에이전트는 Container Insight로 메트릭을 보내는 동시에 CloudWatch Logs에 데이터도 전송한다.

Container Insights에서 수집한 메트릭도 확인할 수 있다.

4.1.3 CloudWatch 경보를 이용한 통지

Container Insights로 수집한 메트릭은 AWS의 일반적 메트릭과 같다.

4.1.4 리소스 삭제

CloudWatch 리소스를 삭제하는 방법

kubectl delete -f .
configmap "cwagentconfig" deleted
daemonset.apps "cloudwatch-agent" deleted
serviceaccount "cloudwatch-agent" deleted
clusterrole.rbac.authorization.k8s.io "cloudwatch-agent-role" deleted
clusterrolebinding.rbac.authorization.k8s.io "cloudwatch-agent-role-binding" deleted

또한, IAM 정책과 로그 그룹도 삭제한다.

4.2 로그 관리와 운영

애플리케이션이 출력한 각종 로그를 EKS에서 효율적으로 수집, 저장, 모니터링, 시각화하는 방법에 대해 설명한다.

  • 수집: Fluentd 컨테이너를 데몬셋으로 동작시키고 파드의 로그를 CloudWatch Logs에 전송한다.

  • 저장: CloudWatch Logs에 로그를 저장하도록 설정한다.

  • 모니터링: 메트릭 디렉터리를 설정하고 CloudWatch 사용자 메트릭을 생성해 그 메트릭의 경보를 생성한다.

  • 시각화: CloudWatch의 Logs Insights를 사용해 대상 로그를 분석하고 CloudWatch의 대시보드로 시각화한다.

쿠버네티스는 재시작 등을 하게 되면 호스트가 변경 될 가능성이 있기 때문에 표준 출력으로 구성하는 것을 추천한다.

kubectl logs app=backend-app

으로 레이블을 지정해 특정 레이블에 있는 모든 파드의 로그를 참조할수도 있다.

4.2.2 로그 수집

AWS에서는 CloudWatch Logs라는 서비스를 제공하는데 이 책에서는 데몬셋으로 Fluentd 컨테이너를 동작시켜 파드 각각이 표준 출력한 로그를 확인하고 CloudWatch Logs로 수집, 관리하는 방법을 소개한다.

데이터 노드의 IAM 역할에 정책 추가

EKS에서 배포한 데몬셋에서 CloudWatch Logs에 로그를 전송하려면 데이터 플레인에 연결된 IAM 역할에 IAM 정책을 연결해야 한다.

  1. 플루언트디 컨테이너를 데몬셋으로 동작시키기

    kubectl create configmap cluster-info --from-literal=cluster.name=eks-work-cluster --from-literal=logs.region=ap-northeast-2 -n amazon-cloudwatch
    configmap/cluster-info created
  2. 플루언트디 컨테이너를 설치하는 매니페스트를 다운로드하고 플루언트디 컨테이너를 동작

  3. 플루언트디 컨테이너를 데몬셋으로 동작

     kubectl apply -f fluentd.yaml
     serviceaccount/fluentd created
     clusterrole.rbac.authorization.k8s.io/fluentd-role created
     clusterrolebinding.rbac.authorization.k8s.io/fluentd-role-binding created
     configmap/fluentd-config created
     daemonset.apps/fluentd-cloudwatch created

4.2.3 로그 저장

CloudWatch Logs로 전송된 로그는 기본적으로 기간 제한이 없어서 용도에 맞게 저장 기간을 설정해야한다.

CloudWatch Logs에서 보관 기간 설정

CloudWatch 로그 저장 기간은 로그 그룹 단위로만 설정 가능하므로 가장 오래 저장하고 싶은 로그에 맞춰 기간을 설정하는 것이 좋다.

4.2.4 로그 모니터링

CloudWatch 경보를 사용한 통지

애플리케이션에서 에러가 발생했을 때 통지를 보내고 싶다면 메트릭 필터에서 대상 로그를 추출하고 그것을 CloudWatch 메트릭으로 등록해 메트릭 경보를 생성하면 통지를 보낼 수 있다.

ERROR 로그가 출력된 경우 통지를 보내고 싶다면

  1. 메트릭 필터 조건을 'ERROR'로 설정하고 출력 횟수를 메트릭에 등록

  2. 출력 횟수 메트릭 통보 생성

메트릭 필터도 로그 그룹 단위로 설정해야 하기 때문에 앱이 A, B가 존재하는 경우 앱 A 에러, 앱 B 에러 등과 같이 별도로 필터와 경보를 생성하는 것이 좋다.

CloudWatch Logs 이벤트 검색을 이용한 디버그 예

CloudWatch Logs에서는 표준 출력이 JSON으로 저장된다.

# '애플리케이션 로그 AND 애플리케이션 이름이 backend-app AND "WARN"이나 "error"가 포함된다'라는 조건
{ $.log != "[*" && $.kubernetes.container_name = "backend-app" && ( $.log = "*WARN*" || $.log = "*error*" ) }

4.2.5 로그의 시각화와 분석

로그에서 에러를 추출하고 통지하는 것은 실시간 대응 속도를 위한 것이라면 시각화와 분석은 다양한 패턴을 파악해 장애를 바잊하거나 개발이 필요한 내용을 찾아내는 것이다.

CloudWatch는 저장된 로그를 검색하고 시각화하는 기능인 CloudWatch Logs Insights를 제공하며 여기서는 이 기능을 사용해 기본적인 로그 분석을 해본다.

위의 그림에서 View in Logs Insights를 클릭하면

# 애플리케이션 접속 확인
stats count(*) as ACCESS_COUNT
| filter ( kubernetes.container_name = "backend-app")
| filter ( log not like /^\[/ and (log like /Health GET API called./ or log like / 
REGION GET ALL API/ or log like /LOCATION LIST BY REGION ID API/ )

# 어떤 애플리케이션에서 얼마만큼의 에러가 발생하고 있는지 확인
stats count(*) as ERROR_COUNT by kubernetes.container_name as APP
| filter ( log not like /^\[/ and (log like /WARN/ or log like /error/) )

쿼리 결과를 대시보드에 저장

Logs Insights 쿼리 결과는 CloudWatch 대시보드에 저장할 수 있는데 여러 쿼리 결과를 대시보드에 저장해두면 전체 상황을 파악할 수 있다.

위 사진의 Add to dashboard 버튼을 통해 시행 가능하다

4.2.6 리소스 삭제

curl 명령어로 다운로드한 디렉토리에서 실행한다.

  1. IAM 역할에 정책 추가에서 생성한 IAM 정책을 삭제한다

  2. 데몬셋으로 자동 생성된 CloudWatch Logs의 로그 그룹 3개와 CloudWatch 대시보드도 삭제한다.

kubectl delete cm cluster-info -n amazon-cloudwatch
configmap "cluster-info" deleted

kubectl delete -f .
serviceaccount "fluentd" deleted
clusterrole.rbac.authorization.k8s.io "fluentd-role" deleted
clusterrolebinding.rbac.authorization.k8s.io "fluentd-role-binding" deleted
configmap "fluentd-config" deleted
daemonset.apps "fluentd-cloudwatch" deleted

4.3 오토스케일링

쿠버네티스의 오토스케일링 구조와 EKS에서 오토스케일링이 어떻게 동작하는지와 단점에 대해 알아본다.

4.3.1 Cluster Autoscaler를 이용한 데이터 플레인 오토스케일링

Cluster Autoscaler는 데이터 플레인 인스턴스에 대한 오토스케일링 기능으로 EKS CA는 AWS 오토스케일링과 연결되어 동작한다

Cluster Autoscaler를 이용한 발견적 오토스케일링

CA 스케일링 트리거 기준은 파드에 설정된 리소스 요청에 따라 판단한다. 새로운 파드를 배포하려 할 때 CPU와 메모리에 여유가 없다면 파드는 Pending 상태가 된다.

Cluster Autoscaler는 파드가 Pending 상황임을 감지하고 노드를 추가한다.

설정 방법은 다음과 같다.

  1. AWS 관리 콘솔에서 AutoScalingFullAccess를 부여한다

  2. eks 클러스터 데이터 노드로 설정된 오토스케일링 그룹 이름을 매니페스트 문서에 입력한다.

  3. 결과

     kubectl apply -f cluster-autoscaler.yaml
     serviceaccount/cluster-autoscaler created
     clusterrole.rbac.authorization.k8s.io/cluster-autoscaler created
     role.rbac.authorization.k8s.io/cluster-autoscaler created
     clusterrolebinding.rbac.authorization.k8s.io/cluster-autoscaler created
     rolebinding.rbac.authorization.k8s.io/cluster-autoscaler created
     deployment.apps/cluster-autoscaler created

    노드가 늘어나 파드가 점점 start 되는것도 확인할 수 있다.

     kubectl get pod
     NAME                           READY   STATUS    RESTARTS   AGE
     backend-app-59b66ccd45-5nk6l   1/1     Running   0          105s
     backend-app-59b66ccd45-6gc9r   0/1     Pending   0          105s
     backend-app-59b66ccd45-7fsbj   0/1     Pending   0          105s
     backend-app-59b66ccd45-8cpnp   0/1     Pending   0          105s
     backend-app-59b66ccd45-8whbv   1/1     Running   0          3d14h
     backend-app-59b66ccd45-9rftc   1/1     Running   0          3d14h
     backend-app-59b66ccd45-lm7pr   0/1     Pending   0          105s
     backend-app-59b66ccd45-wlm85   0/1     Pending   0          105s
     backend-app-59b66ccd45-xknhs   1/1     Running   0          105s
     backend-app-59b66ccd45-zq7c5   0/1     Pending   0          105s

    노드 오토 스케일링이 적용되지 않아서 여러 방법으로 접근해봤지만 아직 해결하지 못했다.

    기존에 설정한 v1.2.2는 베타 버전이 들어가 있어 cluster-autoscaler 버전을 업그레이드 해봤는데 이미지가 풀이 되지 않는 문제가 계속되고 있다.

Cluster Autoscaler에서 주의할 점

Cluster Autoscaler는 requests 값으로 스케줄링을 판단한다. 파드를 배치할 때만 스케일링을 판단하지 파드가 배치되면 노드의 스케줄링은 실행되지 않는다. 3.7절에서 이야기했던 대로 requests와 limits의 값을 적절히 조절해 리소스 사용량을 적절하게 맞춰야 한다.

AWS 오토스케일링 기능을 이용한 예방적 오토스케일링

문제가 발생했을 때 오토스케일링 하는 것이 아니라 임계값을 넘으면 노드를 추가하는 것이 운영 측면에선 더 좋다.

생성되는 Pod를 Pending 상태로 만들지 않으려면 노드의 부하를 판단할 필요가 있는데 이 때 CPU 사용률(pod_cpu_reserved_capacity)가 좋을 것이다. 이는 Container Insights를 활성화하면 자동 등록된다.

4.3.2 Horizontal Pod Autoscaler를 이용한 파드 오토스케일링

노드 오토스케일링은 파드를 원하는 수만큼 동작시키기 위해 용량을 확보하는 기능이므로 애플리케이션 스케일링을 하려면 쿠버네티스의 Horizontal Pod Autoscaler 기능을 사용해 파드 리소스 사용률에 맞춰 파드의 스케일 아웃, 인 기능을 구현할 수 있다.

HPA로 파드 수를 자동 조절하려면 클러스터 내부에서 파드 리소스를 파악하고 있어야 한다. HPA에서는 메트릭 서버슬 사용해 사용 현황을 파악한다.

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
serviceaccount/metrics-server created
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrole.rbac.authorization.k8s.io/system:metrics-server created
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created
service/metrics-server created
deployment.apps/metrics-server created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
kubectl get deployments metrics-server -n kube-system
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
metrics-server   1/1     1            1           63s
kubectl get apiservice v1beta1.metrics.k8s.io -o yaml
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apiregistration.k8s.io/v1","kind":"APIService","metadata":{"annotations":{},"labels":{"k8s-app":"metrics-server"},"name":"v1beta1.metrics.k8s.io"},"spec":{"group":"metrics.k8s.io","groupPriorityMinimum":100,"insecureSkipTLSVerify":true,"service":{"name":"metrics-server","namespace":"kube-system"},"version":"v1beta1","versionPriority":100}}
  creationTimestamp: "2024-06-13T12:15:47Z"
  labels:
    k8s-app: metrics-server
  name: v1beta1.metrics.k8s.io
  resourceVersion: "1674327"
  uid: 832bb0b7-9a0a-4954-83c9-20a5576ae578
spec:
  group: metrics.k8s.io
  groupPriorityMinimum: 100
  insecureSkipTLSVerify: true
  service:
    name: metrics-server
    namespace: kube-system
    port: 443
  version: v1beta1
  versionPriority: 100
status:
  conditions:
  - lastTransitionTime: "2024-06-13T12:16:19Z"
    message: all checks passed
    reason: Passed
    status: "True"
    type: Available

HPA 리소스 생성

예제 애플리케이션에 일정 부하가 발생했을 때 증감이 작동하도록 HPA 리소스를 생성한다.

kubectl apply -f horizontal-pod-autoscaler.yaml
horizontalpodautoscaler.autoscaling/backend-app created

부하를 준다.

kubectl run -i --tty load-generator --imgae=busybox --rm -- sh

while true; do wget -q -0- http://backend-app-service.eks-work.svc.cluster.local:8080/health; done

HPA에서는 기본값으로 스케일 아웃은 30초, 스케일 인은 5분에 한 번 동작한다.

4.4 보안

최소한의 보안 지식에 대해 설명한다.

4.4.1 클러스터 보안

인증

쿠버네티스 클러스터를 조작할 떄는 kubectl을 사용하며 이는 EKS에서도 동일하다. AWS CLI의 aws eks update-kubeconfig를 실행하면 kubectl을 자동으로 설정할 수 있다.

aws eks update-kubeconfig --name eks-work-cluster
Added new context arn:aws:eks:ap-northeast-2:566620743708:cluster/eks-work-cluster to /Users/hojin/.kube/config

이 설정으로 kubectl이 AWS CLI 인증 탐색 구조를 이용해 EKS 인증이 가능해진다.

  • .clusters[].cluster에서는 어떤 클러스터에 인증할지 설정한다.

  • .users[].user에서는 어떤 사용자로 인증할지 설정한다.

  • .contexts[].context에서는 클러스터와 사용자를 연결한다.

다음 명령어에서 나오는 이용해 토큰을 이용해 인증할 수 있다.

aws --region ap-northeast-2 eks get-token --cluster-name eks-work-cluster

kubectl은 인증 설정에서 AWS CLI를 사용하도록 설정하면 EKS 인증 시 해당 도구의 aws eks get-token 명령을 사용해 토큰을 생성하고 그것을 클러스터 인증 문자열로 사용한다. 토큰은 Go용 AWS SDK의 sts.GetCallerIdentityRequest에서 생성된 URL을 base64 인코딩하고 k8s-aws-v1 접두사를 붙인 문자열이다.

kubectl은 이 문자열을 사용해 EKS의 컨트롤 플레인에 요청을 보낸다. EKS는 받은 토큰을 디코딩하고 sts.GetCallerIdentity 요청을 발행해 응답에 포함된 IAM 사용자나 IAM 역할의 ARN을 확인한다.

인가

kubectl로 접속한 요청이 정상적으로 인증된 후에는 요청한 조작이 허가를 받은지 점검할 필요가 있다. 쿠버네티스에서는 Role-Based Access Control 기능을 이용해 구현한다. Role, RoleBinding이라는 쿠버네티스 오브젝트를 사용해 설정한다. 롤은 어떤 조작을 허가할지 권한 셋을 정의하고 롤바인딩은 어떤 사용자에게 어떤 롤을 부여할지 정의한다.

AWS는 aws-auth 컨피그맵 안에 AWS CLI 인증 정보로 설정한 IAM 사용자, IAM 역할의 아마존 리소스 이름, 쿠버네티스 오브젝트로 그룹을 연결해놓고 롤바인딩으로 그 그룹과 롤을 연결시키는 것으로 구현한다.

이런 방법을 통해 각 관리자가 특정 리소스에만 접근 가능하도록 권한을 부여할 수 있다.

애플리케이션 개발자로 리소스 접속이 제한된 사용자를 예를 들어서 특정 네임스페이스의 파드와 파드 로그, 디플로이먼트와 레플리카셋, 서비스만 참조 가능한 사용자를 등록해보자.

  1. 롤과 롤 바인딩 등록

     kubectl apply -f security/rbac.yaml
     namespace/rbac-test-ns created
     clusterrole.rbac.authorization.k8s.io/rbac-test-role created
     rolebinding.rbac.authorization.k8s.io/rbac-test-role-binding created
  2. 컨피그맵의 aws-auth에 롤바인딩의 .subjects[].name에서 설정한 이름과 IAM 사용자 또는 IAM 역할의 ARN 페어를 설정

    eksctl create iamidentitymapping --region ap-northeast-2 --cluster eks-work-cluster --username rbacTest --group rbac-test-group --arn arn:aws:iam::566620743708:user/developer
    checking arn arn:aws:iam::566620743708:user/developer against entries in the auth ConfigMap
    adding identity "arn:aws:iam::566620743708:user/developer" to auth ConfigMap

    AWS CLI로 사용할 인증 정보를 신규로 생성한 IAM 사용자의 정보로 변경하고 kubectl 관련 명령을 실행하면 rbac-test-ns 외의 조작은 불가능하다.

  3. 사용자 정보 변경 후 기존 네임스페이스로 변경

     aws configure
     AWS Access Key ID [****************2EC6]: AKIAYH3J2NAOMZZTHPXT
     AWS Secret Access Key [****************v2bI]: 
     Default region name [ap-northeast-2]:
     Default output format [json]:
    
     kubectl config use-context eks-work
     Switched to context "eks-work".
  4. 기존 네임스페이스 리소스 접근 시도

     kubectl get pod,deployments,replicaset,service
     Error from server (Forbidden): pods is forbidden: User "rbacTest" cannot list resource "pods" in API group "" in the namespace "eks-work"
     Error from server (Forbidden): deployments.apps is forbidden: User "rbacTest" cannot list resource "deployments" in API group "apps" in the namespace "eks-work"
     Error from server (Forbidden): replicasets.apps is forbidden: User "rbacTest" cannot list resource "replicasets" in API group "apps" in the namespace "eks-work"
     Error from server (Forbidden): services is forbidden: User "rbacTest" cannot list resource "services" in API group "" in the namespace "eks-work"
  5. rbac-test-ns 네임스페이스 리소스 참조

    kubectl get pod,deployments,replicaset,service -n rbac-test-ns
    No resources found in rbac-test-ns namespace.
  6. 리소스 생성 실패

     kubectl create deployment tnginx-test --image=nginx:latest
     error: failed to create deployment: deployments.apps is forbidden: User "rbacTest" cannot create resource "deployments" in API group "apps" in the namespace "eks-work"
  7. rbac-test-ns에도 추가 불가

     kubectl create deployment tnginx-test --image=nginx:latest -n rbac-test-ns
     error: failed to create deployment: deployments.apps is forbidden: User "rbacTest" cannot create resource "deployments" in API group "apps" in the namespace "rbac-test-ns"

4.4.2 노드 보안

파드에 부여하는 호스트 권한 제어

클러스터를 관리하면서 어떤 파드든 무조건 생성해도 되는 것은 아니다. 쿠버네티스는 파드에 부여할 권한을 관리하는 파드 시큐리티 폴리시라는 기능을 가지고 있다. 현재 EKS 클러스터에는 아무 제한이 걸려있지 않다. 파드를 특권 컨테이너로 이동시켜 노드 쪽 권한을 사용할 수도 있다.

kubectl get namespace eks-work --show-labels
NAME       STATUS   AGE    LABELS
eks-work   Active   7d4h   kubernetes.io/metadata.name=eks-work

제한을 사용해서 특정 컨테이너 사용을 막아보자

kubectl label namespace eks-work pod-security.kubernetes.io/enforce=restricted
namespace/eks-work labeled
kubectl apply -f -<<EOF
heredoc> apiVersion: v1
heredoc>
heredoc> kind: Pod
heredoc> metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
heredoc> EOF
Error from server (Forbidden): error when creating "STDIN": pods "nginx" is forbidden: violates PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "nginx" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "nginx" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "nginx" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "nginx" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")

여기서 nginx 컨테이너를 실행하려하면 권한에 막힌다.

과거에는 Pod Security Policy로 제어했지만 지금 해당 feature는 Deprecated되었고, Pod Security Admission 혹은 3rd party plugin으로 대체할 수 있다.

과거의 파드 시큐리티 폴리시를 사용해 파드에서 사용할 수 있는 권한을 제어함으로써 노드를 보호할 수 있었다. 만약 특정 사용자에게만 권한제한을 적용하고 싶을 경우 파드 시큐리티 폴리시를 생성해 해당 파드 시큐리티 폴리시를 룰로 선언하고 롤바인딩으로 롤과 사용자를 매핑시키면 파드 시큐리티 폴리시를 적용할 수 있었다.

4.4.3 파드 보안

컨테이너 라이프사이클에 맞춘 보안 대책의 필요성

컨테이너 보안은 라이프사이클에 맞춰 수행하며 컨테이너 이미지를 생성할 때는 취약성을 점검하고 동작시킬 때는 동작을 감시한다.

  • 컨테이너 이미지 취약성: 컨테이너 이미지를 스캔해 문제가 있는 소프트웨어 버전이 포함되었는지 자동으로 확인하게함으로써 취약한 컨테이너가 배포되는 것을 방지한다.

  • 동작 감시(런타임 보호): 실제 컨테이너에 문제되는 동작이 실행되는지 확인한다.

4.4.4 네트워크 보안

네트워크 수준의 보안은 인그레스와 내부통신 두 가지 관점으로 생각할 수 있다. 인그레스는 AWS 기능을 이용, 내부통신은 쿠버네티스 기능을 사용해 대응한다.

엔드포인트 IP 주소 제한

EKS에서는 엔드포인트의 IP 주소 제한 기능이 있으며 콘솔에서 설정할 수 있다.

kubectl을 VPC 내부로 제한하는 프라이빗 엔드포인트

기본적으로 EKS 클러스터 엔드포인트는 인터넷에 공개되는데 IAM으로 인증하고 앞에서 설명한 IP 주소로 접속도 제한할 수 있다.

프라이빗 엔드포인트도 제공해 VPC 내부에서만 접속할 수 있는 클러스터를 생성할 수도 있다.

네트워크 정책을 사용한 클러스터 내부 통신 제어

파드에는 VPC 내부의 IP 주소가 할당돼 클러스터 외부와 통신할 수 있지만 어떤 노드에 어떤 IP 주소가 할당되는지 제어할 수 없다. 또, 모든 노드에 공통 보안 그룹이 설정돼있어 클러스터 내부 통신을 보안 그룹으로 제어하는 것은 어렵다.

클러스터 내부 서비스 사이의 통신 제어는 네트워크 정책이라는 클러스터 내부 구조를 이용해 실현한다.

매니페스트를 통해 살펴보면 대상 네임스페이스 내에서는 모든 서비스 사이의 통신을 거부한다.

cat network-policy-all-deny.yaml

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
spec:
  podSelector:
    # 모든 파드(Pod)에 적용
    matchLabels: {}

이후 서비스 B에서 http 요청만 허가하는 네트워크 정책을 생성한다. .spec.podSelector.matchLabels에서 어떤 파드에 네트워크 정책을 적용할지 설정한다. 여기선 app: serviceA에 .spec.ingress에는 전달받는 통신의 허가 조건을 설정한다. 이렇게 두 설정으로 그림과 같은 구성을 실현할 수 있다.

cat network-policy-allow-http-from-serviceB2ServiceA.yaml

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  # 적용 대상 네임스페이스 설정
  name: network-policy-for-servicea
spec:
  podSelector:
    matchLabels:
    # 적용 대상 파드 레이블 설정
      app: ServiceA
  policyTypes:
  - Ingress
  ingress:
  # 수신 규칙 설정
  - from:
    - podSelector:
        matchLabels:
          app: ServiceB
    ports:
    - protocol: TCP
      port: 80
kubectl apply -f network-policy-all-deny.yaml
networkpolicy.networking.k8s.io/default-deny created

kubectl apply -f network-policy-allow-http-from-serviceB2ServiceA.yaml
networkpolicy.networking.k8s.io/network-policy-for-servicea created

kubectl apply -f network-policy-sample-serviceA.yaml
deployment.apps/servicea created
service/servicea created
calico
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/calico-vxlan.yaml
poddisruptionbudget.policy/calico-kube-controllers created
serviceaccount/calico-kube-controllers created
serviceaccount/calico-node created
serviceaccount/calico-cni-plugin created
configmap/calico-config created
customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/bgpfilters.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created
clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created
clusterrole.rbac.authorization.k8s.io/calico-node created
clusterrole.rbac.authorization.k8s.io/calico-cni-plugin created
clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created
clusterrolebinding.rbac.authorization.k8s.io/calico-node created
clusterrolebinding.rbac.authorization.k8s.io/calico-cni-plugin created
daemonset.apps/calico-node created
deployment.apps/calico-kube-controllers created

서비스 A로 HTTP 요청

kubectl run -it servicec --image=busybox --labels="app=ServiceC" --rm -- sh

wget -q -0 - http://servicea.eks-work.svc.cluster.local

4.5 매니페스트 관리와 지속적 통합/지속적 전달

서비스 환경에서 유지, 운영하기 위해서는 항상 클러스터의 상태를 감시해 문제가 발생할 경우 통지 받는 구조로 만들어야 한다.

4.5.1 깃옵스와 깃옵스를 구현하기 위한 도구 등장

쿠버네티스는 모든 설정 정보를 매니페스트라는 yaml 파일로 정의한다 모든 설정을 코드로 관리하면 CI/CD 구현이 가능하다.

CD 툴로는 다양한 툴들이 존재한다.

4.5.2 CodePipeline을 이용해 깃옵스 구현

AWS에서도 CodePipeline이라는 CI/CD 서비스를 제공하는데 소스 작성, 빌드, 배포 단계를 정의하고 각종 설정을 수행해 CI/CD 파이프라인을 구성할 수 있는 서비스다.

  1. 코드를 리포지터리에 푸시

  2. 파이프라인이 동작

  3. 애플리케이션 빌드를 실시

  4. 컨테이너 이미지를 생성해 ECR에 푸시

  5. ECR 컨테이너 이미지를 EKS에 자동으로 배포

소스 리포지터리와 EKS 매니페스트 리포지터리는 별도 관리되어야 하고 빌드 단계와 배포 단계도 분리해 실행해야 하지만 여기서는 간소화된 파이프라인을 구축한다

CI/CD에 필요한 리소스 생성

기존 cicd-environment-template.yaml에서

  CodePipelineServiceRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: EKS-SampleAP-CodePipelineServiceRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AWSCodePipelineFullAccess
      Path: /
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement: 
          - Effect: "Allow"
            Principal: 
              Service: "codepipeline.amazonaws.com"
            Action: "sts:AssumeRole"

AWSCodePipelineFullAccess -> AWSCodePipeline_FullAccess로 변경해줬더니 실행 가능했다.

EKS 클러스터 엑세스 권한에 CodeBuild의 IAM 역할 추가

해당 파이프라인에서는 CodePipeline의 CodeBuild 프로젝트 안에서 EKS 클러스터에 매니페스트를 적용한다. 따라서, CodeBuild가 kubectl 관련 명령을 사용해 설정 내용을 적용할 수 있도록 kubectl 명령어의 인증 정보를 생성해야 한다.

eksctl create iamidentitymapping --region ap-northeast-2 --cluster eks-work-cluster --username codebuild --group system:masters --arn arn:aws:iam::566620743708:role/EKS-SampleAP-CodeBuildServiceRole
2024-06-14 22:45:03 [ℹ]  checking arn arn:aws:iam::566620743708:role/EKS-SampleAP-CodeBuildServiceRole against entries in the auth ConfigMap
2024-06-14 22:45:03 [ℹ]  adding identity "arn:aws:iam::566620743708:role/EKS-SampleAP-CodeBuildServiceRole" to auth ConfigMap

예제 소스 코드를 AWS CodeCommit에 푸시하도록 설정

깃허브 리포지터리를 바로 사용할 수 없으므로 CodeCommit 리포지터리를 생서해 사용한다. 로컬 환경의 예제 애플리케이션 코드를 CodeCommit에 생성한 리포지터리에 푸시한다.

  1. eks-app-git이라는 사용자를 생성해 awscodecommitpoweruser 정책을 추가한다.

  2. aws cli용 credentials을 생성한다.

  3. 기존 코드의 리모트 대상에 새로 생성한 CodeCommit 리포지터리를 추가한다.

    git remote add origin https://git-codecommit.ap-northeast-2.amazonaws.com/v1/repos/eks-work-cicd-repo
  4. 코드 수정

    public class RegionDto {
    
     private Integer regionId;
    
     private String regionName;
    
     public RegionDto() {
     }
    
     public RegionDto(Region region) {
         this.regionId = region.getRegionId();
         this.regionName = "*" + region.getRegionName();
     }
    }
    
     cat backend-app/build.gradle
    
     plugins {
         id 'org.springframework.boot' version '2.2.5.RELEASE'
         id 'io.spring.dependency-management' version '1.0.9.RELEASE'
         id 'java'
     }
    
     group = 'k8sbook'
     version = '1.0.1'
     sourceCompatibility = '11'
    
     repositories {
         mavenCentral()
     }

ECR의 URI와 버전 번호를 업데이트, 매니페스트 수정

ECR에 새 도커 이미지를 푸시하고, EKS 클러스터에 매니페스트 적용, 새로운 도커 이미지를 ECR에서 풀해서 배포한다.

우선 kustomization.yaml의 이미지 태그와 ECR URI를 변경한다.

cat cicd/kustomization/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

bases:
- ../base  # 기반이 되는 매니페스트 장소

images:
  - name: backend-app-image  # 여기는 바꾸지 않음
    newTag: 1.0.1  # 애플리케이션 버전 번호
    newName: 566620743708.dkr.ecr.ap-northeast-2.amazonaws.com/k8sbook/backend-app # ECR 레지스트리 URI

코드 커밋에 푸시

리포지터리에 푸시한다.

git add .
git commit -m 'Test'
git push origin master
Username for 'https://git-codecommit.ap-northeast-2.amazonaws.com': eks-app-git-at-566620743708
Password for 'https://eks-app-git-at-566620743708@git-codecommit.ap-northeast-2.amazonaws.com':

오브젝트 나열하는 중: 469, 완료.
오브젝트 개수 세는 중: 100% (469/469), 완료.
Delta compression using up to 11 threads
오브젝트 압축하는 중: 100% (261/261), 완료.
오브젝트 쓰는 중: 100% (469/469), 2.08 MiB | 730.00 KiB/s, 완료.
Total 469 (delta 153), reused 437 (delta 139), pack-reused 0
remote: Validating objects: 100%
To https://git-codecommit.ap-northeast-2.amazonaws.com/v1/repos/eks-work-cicd-repo
 * [new branch]      master -> master

자동으로 EKS에 배포된 것 확인

[Container] 2024/06/15 01:38:26.869089 Running command python get-pip.py
ERROR: This script does not work on Python 3.7 The minimum supported Python version is 3.8. Please use https://bootstrap.pypa.io/pip/3.7/get-pip.py instead.
[Container] 2024/06/15 01:38:26.993854 Command did not exit successfully python get-pip.py exit status 1
[Container] 2024/06/15 01:38:26.997881 Phase complete: PRE_BUILD State: FAILED
[Container] 2024/06/15 01:38:26.997900 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: python get-pip.py. Reason: exit status 1

pipeline build 중 에러 발생

      - apt update
      - apt install -y wget
      - apt install -y python3.8 python3.8-venv python3.8-dev
      - update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 1

파이썬 버전 업그레이드

4.5.3 kustomize를 이용한 실전 배포

환경에 따라 다른 정보들을 동적으로 변경시키기 위해서 kustomize는 동적으로 값을 변경하고 싶다는 요구사항을 해결하는 구조를 제공한다.

kustomize는 kubectl의 서브 명령어로 여러 개의 매니페스트나 환경에 의존적인 설정값을 합해 매니페스트 하나로 만들어 준다.

디렉토리 각각의 kustomization.yaml에는 기본 매니페스트가 어디에 있는지 기본 설정을 작성한다. 이렇게 하면 test 디렉토리의 kustomization.yaml와 deployment.yaml은 기본 파일을 덮어쓰며 생성할 리소스는 -test 접미사를 붙인다.

cat cicd/kustomization/test/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

bases:
- ../base # 기본이 되는 매니페스트 디렉토리
patches:
- deployment.yaml # deployment.yaml의 내용을 덮어쓰기하는 설정

nameSuffix: -test # 모든 리소스 이름 끝에 -test를 붙인다
commonLabels: # 모든 리소스에 설정하는 레이블
  app: backend-app-test

images:
  - name: centos
    newTag:   # 애플리케이션 버전 번호
    newName:   # ECR 레지스트리 URI

그리고 덮어쓰기하는 deployment.yaml에는 덮어쓰기 대상의 디플로이먼트 이름을 설정하고 레플리카셋 수만 적어둔다.

cat cicd/kustomization/test/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend-app # 덮어쓰기 대상 리소스 이름
spec:
  replicas: 1 # 이 부분만 base 매니페스트 덮어쓰기

이 구조를 파이프라인에 도입하면 환경에 따라 변경되는 값들을 동적으로 변경하는 파이프라인을 구성할 수 있다.

4.6 버전 관리

쿠버네티스 버전 업데이트에 필요한 작업과 방법, 고려사항을 설명한다.

4.6.1 쿠버네티스 버전 업데이트 계획과 지원 정책

쿠버네티스는 연간 4번 새로운 버전이 출시되며 EKS도 최신버전을 포함해 3개의 버전을 서포트한다. 하나의 버전의 수명은 9개월 정도라고 보면 된다.

4.6.2 버전 업데이트에 필요한 작업

쿠버네티스는 컨트롤 플레인과 데이터 플레인을 각각 업데이트 해야 되는데 EKS에서 eksctl 관련 명령을 사용하면 효율적으로 실행할 수 있다.

eksctl upgrade cluster --name eks-work-cluster --approve
2024-06-16 20:34:34 [ℹ]  will upgrade cluster "eks-work-cluster" control plane from current version "1.29" to "1.30"
2024-06-16 20:43:10 [✔]  cluster "eks-work-cluster" control plane has been upgraded to version "1.30"
2024-06-16 20:43:10 [ℹ]  you will need to follow the upgrade procedure for all of nodegroups and add-ons
2024-06-16 20:43:10 [ℹ]  re-building cluster stack "eksctl-eks-work-cluster-cluster"
2024-06-16 20:43:10 [✔]  all resources in cluster stack "eksctl-eks-work-cluster-cluster" are up-to-date
2024-06-16 20:43:10 [ℹ]  checking security group configuration for all nodegroups
2024-06-16 20:43:10 [ℹ]  all nodegroups have up-to-date cloudformation templates

데이터플레인에서 동작하는 시스템 컴포넌트 파드인 kube-proxy와 coredns를 업데이트한다.

eksctl utils update-kube-proxy --cluster eks-work-cluster --approve
2024-06-16 20:43:34 [ℹ]  "kube-proxy" is now up-to-date

eksctl utils update-coredns --cluster eks-work-cluster --approve
2024-06-16 20:43:41 [ℹ]  replaced "kube-system:Service/kube-dns"
2024-06-16 20:43:41 [ℹ]  replaced "kube-system:ServiceAccount/coredns"
2024-06-16 20:43:41 [ℹ]  replaced "kube-system:ConfigMap/coredns"
2024-06-16 20:43:41 [ℹ]  replaced "kube-system:Deployment.apps/coredns"
2024-06-16 20:43:41 [ℹ]  replaced "ClusterRole.rbac.authorization.k8s.io/system:coredns"
2024-06-16 20:43:42 [ℹ]  replaced "ClusterRoleBinding.rbac.authorization.k8s.io/system:coredns"
2024-06-16 20:43:42 [ℹ]  "coredns" is now up-to-date

계속해서 데이터 플레인 업데이트를 실시한다.

데이터 플레인 업데이트

데이터플레인은 실제 서비스가 동작하고 있기 때문에 주의해야 한다. 새로운 노드 그룹으로 새로운 버전의 데이터 플레인을 생성하고 기존 데이터 플레인에서 전환하는 방법을 사용할 수 있다.

# 현재 노드 그룹 설정 확인
eksctl get nodegroups --cluster=eks-work-cluster

eksctl create nodegroup --cluster eks-work-cluster --version 1.29 --name eks-work-nogroup-2 --node-type t2.small --nodes 2 --nodes-min 2 --nodes-max 5 --node-ami auto

모든 노드가 Ready상태가 되면 다음 명령으로 기존 노드 그룹을 삭제한다. 기존 노드 그룹을 삭제하면 파드가 자동으로 새로운 노드에 재배치된다.

eksctl delete nodegroup --cluster eks-work-cluster --name eks-work-nodegroup

4.6.4 파드를 안전하게 재배치하는 방법

eksctl을 이용한 노드 변경 동작

  1. eksctl에서 노드 그룹을 삭제하면 삭제 대상 노드 그룹의 실제 노드들은 Schedule Disabled 상태가 되며 스케줄링이 금지된다.

  2. 해당 노드를 드레인 상태로 만든다.

  3. 드레인 상태가 되면 그 노드상에서 동작하는 파드가 다른 노드로 재배치된다.

모든 파드가 동시에 정지하지 않기 위한 방법

드레인 구조를 사용하면 노드 단위에 순차적으로 파드를 재배치할 수 있다. 하지만 최악의 경우 모든 파드가 동시에 재배치될 수 있다. 혹은 헬스 체크 전에 다음 파드의 재배치가 시작돼 정상적 파드가 없는 상태가 될 수도 있다.

쿠버네티스는 이를 방지하기 위해 PodDisruptionBudget 리소스가 준비돼있는데 노드를 드레인해 파드가 재배치될 때 정상이 아닌 파드를 허용하는 수를 결정하는 것이다.

.spec.maxUnavailable을 설정하면 그 파드를 재배치할 때 반드시 레플리카수 - maxUnavailabe개의 파드를 정상 상태로 유지하도록 동작한다.

apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: pdb-backend-app
spec:
  maxUnavailabe: 1
  selector:
    matchLabels:
      app: backend-app

4.7 파게이트

파게이트는 데이터 플레인인 가상 머신 계층의 운영 및 관리에서 해방될 수 있다. 다시말하면 데이터 플레인 버전 업데이트 작업이 필요 없다.

4.7.2 파게이트로 파드를 동작시키는 구조

파드를 동작시키면 쿠버네티스 내부의 스케줄러라는 컴포넌트가 특정 조건을 기준으로 어떤 노드에 파드를 동작시킬지 결정한다.

이 구조를 이용해 어떤 파드를 파게이트로 동작시킬지 결정하는 파게이트 프로파일(서브넷, 네임스페이스, 레이블 조건을 포함해서)을 생성해준다.

파게이트에서는 파드와 노드가 1:1로 동작한다. 다시말해, 파드가 요구하는 용량에 맞춰 노드가 자동 동작한다. 데이터플레인 용량 관리가 필요 없어져 Cluster Autoscaler를 고려하지 않아도 된다.

4.7.4 파게이트 주요 제약 사항

결국 데이터플레인이 블랙박스이기 때문에 호스트 접속이 제한된다.

특권 컨테이너는 호스트 권한을 갖기 때문에 사용할 수 없다. 또한, 파드에서 호스트의 디렉토리를 마운트하는 HostPath도 사용할 수 없다.

또한 데몬셋을 이용할 수 없다. 파게이트에서는 파드와 노드가 1:1로 동작하기 때문에 데몬셋을 도입할 이유가 없다. 따라서 다른 방법으로 모니터링, 로그 관리를 해야 한다.

4.7.5 EKS on Fargate 모니터링과 로그 관리, 운영

책이 최신 내용이 아니라 조사가 필요해보인다.

4.8 쿠버네티스를 지탱하는 에코시스템

4.8.1 확장성

쿠버네티스는 확장성을 확보하기 위해 pluggable하게 기능을 추가할 수 있게 설계됐다.

4.8.2 쿠버네티스의 조정 루프

쿠버네티스는 여러 컴포넌트가 비동기로 자율적으로 동작하면서 기능한다.

디플로이먼트를 클러스터에 적용했을 때를 예로 들면

  1. kubectl 명령어로 매니페스트가 컨트롤 플레인의 API서버를 경유해

  2. 쿠버네티스 데이터베이스(etcd)에 등록되면

  3. 컨트롤러는 해당 파드가 동작하도록 etcd에 등록

  4. 스케줄러는 매니페스트에 정의된 파드가 동작할 노드를 선정

  5. 각 노드상에서 동작 중인 kubelet이 자신의 노드에서 동작해야 할 파드가 동작하지 않는것을 감지

  6. 파드를 동작시킨다

  7. 컨트롤러는 파드 상태를 감시하고 이상이 있을 경우 재시작한다.

4.8.3 커스텀 리소스로 사용자 기능을 추가하는 구조

쿠버네티스는 조정 루프를 근거로 리소스 각각을 관리한다. 조정 루프 원칙에 따라 자체적으로 리소스를 구성해 새로운 리소스를 정의할 수 있다.

이 구조는 커스텀 리소스 정의와 커스텀 리소스 컨트롤러로 구현한다.

쿠버네티스는 파드 디플로이먼트 서비스 등 다양한 리소스를 .kind의 리소스 타입을 설정하고 그 아래 설정 정보를 정의한다 이를 커스텀 리소스 컨트롤러가 정의 정보를 확인한 후 처리해야 의미를 갖는다.

커스텀 리소스 컨트롤러

쿠버네티스에는 리소스 상태를 관리하는 컨트롤러가 존재하는데 컨트롤러는 대상 리소스가 매니페스트 내용대로 배치됐는지 모니터링 하고 상태 유지를 한다.

예를 들어, 실드시크릿을 이용할 때는 SealedSecrets라는 커스텀 리소스 정의를 등록해두고 해당 리소스를 이용해 매니페스트 안의 문자열을 복호화해 시크릿으로 등록하는 구조를 구현한다.

4.8.4 오퍼레이터를 이용한 운영 자동화

이런 커스텀 리소스를 사용해 운영을 자동화 하는 구조를 오퍼레이터라고 하며 오퍼레이터 허브를 사용하는 다양한 자동화 처리가 공개되어 있다.

S3, Dynamo 등 다양한 오퍼레이터가 존재한다.

4.8.5 헬름을 이용한 매니페스트 패키지 관리

비슷한 설정을 병렬로 배포하려면 헬름을 이용하면 된다.

헬름은 차트 기능을 만들기 위한 매니페스트 집합을 템플릿화해 기능 패키지를 관리하는 개념이다. 예를 들어 공통 모니터링 구조를 여러 클러스터에 도입하는 경우나 특정 소프트웨어 설정 등에 활용할 수 있다.

Last updated