728x90
반응형

Kubernetes Ingress

 

Ingress는 서비스는 L4 Layer의 Service와 달리 L7 Layer의 서비스이다.

쿠버네티스의 Ingress는 HTTP(S) 기반의 URL Path LoadBalancing을 하는 서비스라고 보면 된다.

 

아래는 Ingress의 구성도이다.

 

 

Ingress는 URL 기반 로드밸런싱을 하며 구동되려면 뒷단에 Service가 있어야 한다. 

Ingress -> Pod는 불가능하며 Ingress -> Service -> Pod 형태로 구성이 되어야 한다.

 

인그레스는 리소스와 컨트롤러로 구성되는데 yaml로 정의하는 것은 리소스이며 실제 트래픽을 처리하도록 하는 것은 컨트롤러가 한다.

아래의 그림을 보자

 

 

클라이언트로부터 트래픽이 유입되면 인그레스 컨트롤러가 받아 내용을 확인하고 설정된 인그레스 리소스의 Rule대로 포드에게 트래픽을 전달한다.

 

위의 그림처럼 구성되는 이유는 Ingress 컨트롤러의 경우 어떤 Pod로 트래픽을 전달해야할지 알지 못한다. 단지 자기와 연동된 인그레스 리소스만 알고 있을뿐이다.

컨트롤러는 자신과 연동된 인그레스 리소스에게 들어온 트래픽에 대한 경로 정보를 요청하고 인그레스 리소스는 자신에게 정의된 Rule 대로 연동된 서비스에게 다시 경로 요청 후 서비스에 등록된 포드의 엔드포인트를 받게되면 컨트롤러가 전달받은 엔드포인트로 트래픽을 전달하는 방식이다.

 

Yaml로 정의하여 생성한 인그레스 리소스는 Rule을 정의하는 리소스일뿐 실제 트래픽을 전달하는 것은 컨트롤러가 한다는 것이 핵심이다.

 

온프레미스 기반에서는 직접 컨트롤러를 인그레스 리소스와 연동하여야한다는데 이 부분은 해보지 않아 예제로 만들지는 못하였다.

 

아래의 예제는 직접 생성해본 AWS 에서의 ALB 생성 YAML이다.

 

1. AWS ALB Controller 생성

 

- alb-ingress-controller.yaml

 

# Application Load Balancer (ALB) Ingress Controller Deployment Manifest.

# This manifest details sensible defaults for deploying an ALB Ingress Controller.

# GitHub: https://github.com/kubernetes-sigs/aws-alb-ingress-controller

apiVersion: apps/v1

kind: Deployment

metadata:

  labels:

    app.kubernetes.io/name: alb-ingress-controller

  name: alb-ingress-controller

  # Namespace the ALB Ingress Controller should run in. Does not impact which

  # namespaces it's able to resolve ingress resource for. For limiting ingress

  # namespace scope, see --watch-namespace.

  namespace: kube-system

spec:

  selector:

    matchLabels:

      app.kubernetes.io/name: alb-ingress-controller

  template:

    metadata:

      labels:

        app.kubernetes.io/name: alb-ingress-controller

    spec:

      containers:

        - name: alb-ingress-controller

          args:

            # Limit the namespace where this ALB Ingress Controller deployment will

            # resolve ingress resources. If left commented, all namespaces are used.

            # - --watch-namespace=your-k8s-namespace

 

            # Setting the ingress-class flag below ensures that only ingress resources with the

            # annotation kubernetes.io/ingress.class: "alb" are respected by the controller. You may

            # choose any class you'd like for this controller to respect.

            - --ingress-class=alb

 

            # REQUIRED

            # Name of your cluster. Used when naming resources created

            # by the ALB Ingress Controller, providing distinction between

            # clusters.

            - --cluster-name=eks-test

 

            # AWS VPC ID this ingress controller will use to create AWS resources.

            # If unspecified, it will be discovered from ec2metadata.

            - --aws-vpc-id=vpc-OOOOOO

 

            # AWS region this ingress controller will operate in.

            # If unspecified, it will be discovered from ec2metadata.

            # List of regions: http://docs.aws.amazon.com/general/latest/gr/rande.html#vpc_region

            - --aws-region=ap-northest-2

 

            # Enables logging on all outbound requests sent to the AWS API.

            # If logging is desired, set to true.

            # - ---aws-api-debug

            # Maximum number of times to retry the aws calls.

            # defaults to 10.

            - --aws-max-retries=10

          # env:

            # AWS key id for authenticating with the AWS API.

            # This is only here for examples. It's recommended you instead use

            # a project like kube2iam for granting access.

            #- name: AWS_ACCESS_KEY_ID

            #  value: KEYVALUE

 

            # AWS key secret for authenticating with the AWS API.

            # This is only here for examples. It's recommended you instead use

            # a project like kube2iam for granting access.

            #- name: AWS_SECRET_ACCESS_KEY

            #  value: SECRETVALUE

          # Repository location of the ALB Ingress Controller.

          image: docker.io/amazon/aws-alb-ingress-controller:v1.1.2

      serviceAccountName: alb-ingress-controller

 

 

2. AWS ALB Controller에 대한 Cluster Role 생성 및 바인딩 (Cluster에서 Controller에 대한 권한을 허용해야함)

 

- alb-ingress-rbac.yaml

 

---

apiVersion: rbac.authorization.k8s.io/v1

kind: ClusterRole

metadata:

  labels:

    app.kubernetes.io/name: alb-ingress-controller

  name: alb-ingress-controller

rules:

  - apiGroups:

      - ""

      - extensions

    resources:

      - configmaps

      - endpoints

      - events

      - ingresses

      - ingresses/status

      - services

    verbs:

      - create

      - get

      - list

      - update

      - watch

      - patch

  - apiGroups:

      - ""

      - extensions

    resources:

      - nodes

      - pods

      - secrets

      - services

      - namespaces

    verbs:

      - get

      - list

      - watch

---

apiVersion: rbac.authorization.k8s.io/v1

kind: ClusterRoleBinding

metadata:

  labels:

    app.kubernetes.io/name: alb-ingress-controller

  name: alb-ingress-controller

roleRef:

  apiGroup: rbac.authorization.k8s.io

  kind: ClusterRole

  name: alb-ingress-controller

subjects:

  - kind: ServiceAccount

    name: alb-ingress-controller

    namespace: kube-system

---

apiVersion: v1

kind: ServiceAccount

metadata:

  labels:

    app.kubernetes.io/name: alb-ingress-controller

  name: alb-ingress-controller

  namespace: kube-system

...

 

 

3. ALB 생성

 

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

  name: api-alb-ingress

  namespace: api

  labels:

    app: nodejs

  annotations:

    kubernetes.io/ingress.class: alb

    alb.ingress.kubernetes.io/scheme: internet-facing

    alb.ingress.kubernetes.io/target-type: ip

    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]'

    #alb.ingress.kubernetes.io/security-groups: sg-OOOOOO

    alb.ingress.kubernetes.io/subnets: subnet-aaaaaa,subnet-bbbbbbb

    #alb.ingress.kubernetes.io/tags: "Name=alb-test"

    #alb.ingress.kubernetes.io/healthcheck-interval-seconds: '30'

    #alb.ingress.kubernetes.io/healthcheck-timeout-seconds: '10'

    #alb.ingress.kubernetes.io/healthy-threshold-count: '3'

    #alb.ingress.kubernetes.io/unhealthy-threshold-count: '3'

    alb.ingress.kubernetes.io/healthcheck-path: '/'

    #alb.ingress.kubernetes.io/healthcheck-port : '80'

    #alb.ingress.kubernetes.io/healthcheck-protocol : HTTP

    alb.ingress.kubernetes.io/success-codes : '200'

 

spec:

  backend:

    serviceName: api-svc

    servicePort: 80

 

 

4. ALB 인그레스와 연동된 Service 생성

 

apiVersion: v1

kind: Service

metadata:

  name: api-svc

  namespace: api

  labels:

    app: nodejs

spec:

  type: NodePort

  selector:

    app: nodejs

  ports:

  - port: 80

    targetPort: 80

 

LoadBalancer는 Ingress가 하기 때문에 Service의 Type은 NodePort가 된다.

반응형

'Kubernetes' 카테고리의 다른 글

Kubernetes Service  (0) 2019.09.17
Kubernetes Monitoring - Version1  (0) 2019.09.17
Kubernetes HorizontalPodAutoscaler  (0) 2019.08.31
Kubernetes Pod DaemonSet  (0) 2019.08.30
Kubernetes Pod Replica  (0) 2019.08.30
728x90
반응형

Kubernetes Service

 

쿠버네티스에서의 로드밸런싱에는 Service와 Ingress가 있는데 간단하게 Service는 L4 로드밸런서, Ingress는 로드밸런서 이해하면 된다.

우선 Service에 대해 설명하겠다.

 

Service는 다른 포드의 요청이나 외부 클라이언트로부터 오는 HTTP 요청에 응답한다. 외부 클라이언트는 L4 로드밸런서를 외부로 노출시켜 트래픽을 받아 서비스에 속한 포드에 전달하는 것인데 다른 포드의 요청이라는 건 이해하기 애매할 수 있다. 이건 간편하게 내부 로드밸런서를 사용하는 경우로 이해해도 좋다. 물론 사용 사례일 뿐이니 각 환경마다 다르다.

 

외부 클라이언트 -> 외부노출 Service -> Webserver Pod -> 내부 Service -> WasServer Pod

 

 

이런식으로도 구성 가능하다.

 

일단 서비스를 사용하는 일반적으로 로드밸런서를 사용하는 이유와 비슷하지만 쿠버네티스 환경에서는 포드는 Static IP를 가지지 않고 노드 환경에 따라 삭제되고 재생성되는 일이 많으며 포드가 노드로 스케줄되기 전에 IP를 할당받으므로 클라이언트는 서버 포드의 IP를 알 수 가 없다. 이런 문제가 있기 때문에 Service라는 리소스가 필요한 이유이다.

 

쿠버네티스 서비스란 동일한 서비스 (webserver, api server와 같은) 를 제공하는 포드 그룹에 하나의 진입점을 위해 생성하는 리소스이다. 하나의 진입점이란 IDC 환경에서 L4 스위치를 사용할때 VIP를 사용하여 하단에 리얼 IP를 가진 서버를 묶듯이 이렇게 사용하는 VIP라고 이해하면 될것같다. 서비스가 생성되고 할당한 IP주소와 포트는 서비스가 삭제되기전까지 변하지 않는다.

 

위의 그림처럼 Service라는 하나의 진입점으로 들어온 트래픽은 하단의 포드 그룹에 로드밸런싱 된다.

 

Service의 기능중 sessionAffinity라는게 있는데 AWS ELB의 Sticky Session과 같은 기능이라고 보면 된다. ELB에서 Sticky Session을 지정하면 A클라이언트가 A인스턴스로 접속 후 다시 접속을 요청하면 B인스턴스가 아닌 A 인스턴스로 접속할 수 있게 세션을 열어주는 것인데 이것은  https://bcho.tistory.com/tag/sticky%20session 조대협님의 글을 읽어보길 추천한다.

 

 

sessionAffinity를 유지할 클라이언트 IP를 지정해야하는데 이유는 아래와 같다.

Sticky Session, 즉 sessionAffinity를 유지하려면 세션이 쿠키 기반의 옵션을 제공해야하는데 이는 HTTP 수준 (L7 Layer) 에서 동작을 해야한다. 

하지만 Service는 TCP/UDP 수준의 L4 Layer이다. 그렇기 때문에 패킷을 처리하고 페이로드 (전송되는 데이터) 에 대해서는 신경을 쓰지 않는다. 

그렇기때문에 IP를 지정해서 유지해줘야하는 것 (쿠키는 HTTP 프로토콜에서만 의미 있기 때문에 서비스는 쿠키를 처리할 수 없기에 세션이 쿠키 기반 옵션을 제공하지 않는 것) 이다.

 

이 외에 간단한 예제 몇개를 올려놓겠다.

 

- 다중 포트 노출

 

- 이름으로 포트 사용

 

Service 파일에서 포트에 name 속성을 지정하면 포드에서 포트를 적을 필요없이 http, https 등과 같이 사용할 수 있다.

 

아래는 AWS에서 Service를 생성하면 NLB로 생성되는 예제이다.

 

 

이대로 구성하면 바로 NLB가 생성된다. ALB의 경우는 이것보다는 좀 더 복잡하다. 추가되야할게 두가지 더 있다. 이건 Ingress 항목에서 설명하겠다.

 

서비스의 타입에는 ClusterIP, NodePort, LoadBalancer, External Name 이렇게 네 가지가 존재한다. LoadBalancer는 방금 위에서 설명했고 Nodeport에 대해 설명하겠다.

 

NodePort는 말 그대로 노드의 포트를 사용하는 것이다. 아래 그림을 확인해보자

 

 

우선 외부 클라이언트는 노드의 30123포트를 통해 서비스에 접근하고 서비스에서 포드에게 트래픽이 전달된다.

Service를 생성하면 노드의 포트를 랜덤으로 할당하는데 지정된 노드의 포트를 사용하고 싶으면 이렇게 사용하여도 된다.

 

 

 

여기서 연관된 리소스 중 하나인 엔드포인트에 대해 추가 설명하겠다. 서비스를 생성하고 kubectl describe svc OOO 명령을 실행하여 설명을 보면 Endpoint라는 필드가 존재한다. 

 

서비스는 포드에 직접 링크하지 않는다. 대신 이 엔드포인트라 불리는 리소스가 서비스와 포드 사이에 존재하며 이 서비스를 통해 들어오는 트래픽이 전달될 타겟을 지정한다.

즉 엔드포인트는 서비스에 의해 노출되는 IP주소와 포트의 목록이라 보면 된다.

 

 

출력 내용을 보면 포드의 IP와 포트가 엔드포인트로 지정되어 서비스에 등록되어 있다.

 

이 엔드포인트를 수동으로도 지정할 수 있는데 이런 경우 서비스가 연결을 포워딩할 IP와 포트를 직접 지정하는 경우에 사용된다.

아래는 수동으로 지정된 엔드포인트 매니페스트이다.

 

- 서비스 리소스

 

- 엔드포인트 리소스

 

위 방식은 수동으로 서비스와 엔드포인트를 지정한 방식이며 아래처럼 서비스에 ExternalName 형식으로 지정할 수 있다.

 

 

위처럼 엔드포인트를 지정하는 서비스는 클러스터 밖에 서비스에 접근하기 위해 사용된다.

 

여기서 클러스터 밖의 서비스란 AWS RDS와 같이 데이터베이스나 다른 클라우드 서비스를 의미한다. 일반적으로 대부분의 운영 서버들은 DB에 접근하기 때문에 ExternalName 템플릿은

많이 쓰일 것이다.

 

생성된 서비스를 확인해보면 아래와 같다.

 

 

여기서 하나 체크할 부분은 서비스인데도 IP가 없다. 왜 그럴까?

 

ExternalName 서비스는 기본적으로 DNS레벨에서 구현되며 작동한다. 그러므로 ExternalName 서비스로 연결하는 클라이언트는 서비스 프록시를 통하지 않고 직접 외부서비스로 연결한다.

이런 이유로 인해 ExternalName 서비스는 클러스터 IP를 얻지 못한다.

 

 

반응형

'Kubernetes' 카테고리의 다른 글

Kubernetes Ingress  (0) 2019.09.19
Kubernetes Monitoring - Version1  (0) 2019.09.17
Kubernetes HorizontalPodAutoscaler  (0) 2019.08.31
Kubernetes Pod DaemonSet  (0) 2019.08.30
Kubernetes Pod Replica  (0) 2019.08.30
728x90
반응형

Kubernetes Monitoring

 

어떤 시스템이든 가장 중요한 부분 중 하나가 모니터링 일것이다. 쿠버네티스 환경에서 모니터링 하는 방법을 알아본다.

설명할 내용은 기본 메트릭 서버, 프로메테우스이다.

 

우선 가장 기본적으로 알아야 할 것은 메트릭 (지표) 의 수집이다. 쿠버네티스 환경에서는 기본적으로 cAdvisor라는 메트릭 수집도구를 사용한다.

 

 

cAdvisor란 쿠버네티스에서 사용하는 기본적인 모니터링 에이전트로 모든 노드에 설치되서 노드에 대한 정보와 포드 (컨테이너) 에 대한 지표를 수집한다.

이렇게 수집된 내용은 Kubelet에게 전달되는데 이 후 전달된 내용은 모니터링 툴 (메트릭 서버, 프로메테우스) 에서 다시 수집해 간다.

cAdvisor의 경우 리소스 데이터만 수집한다. 이 리소스에는 CPU, Memory, Filesystem, Network Used와 같은 통계를 수집하는 것이다. 

 

리소스외에 다른 메트릭을 수집하고 싶다면 별도의 에이전트를 사용해야한다. 

이제 메트릭이 수집되는 과정을 확인해보면 아래 그림과 같다. 

 

 

cAdvisor + Metrics Server 부분은 쿠버네티스에서 사용하는 모니터링의 가장 기본적인 조합이다. 리소스만 수집하는 형태이며 조합이다.

 

데이터가 수집되는 동작 과정은 아래와 같다.

1. cAdvisor에서 노드의 정보와 포드의 지표를 수집

2. cAdvisor에서 수집한 내용을 Kubelet에게 전달

3. Metrics Server는 Kubelet에게서 수집된 정보를 가져감 

 

이런 수집된 데이터를 가지고 무엇을 할까?

 

아래의 그림을 보도록 하자. 이전 자료이기 때문에 Node X 부분에 Heapster라고 표현되어 있는데 이 부분이 메트릭 서버라고 생각하면 된다.

cAdvisor -> Kubelet -> Metrics Server 를 통해 수집된 데이터는 HPA (Pod AutoScaler) 에서 가져가고 이 데이터를 기반으로 포드를 늘려야할지 줄여야할 지 결정한다.

 

 

이제 메트릭을 생성할텐데 소스 코드는 github에서 다운받을 수 있으며 deploy 안에 있는 파일들을 하나로 합치거나

# kubectl apply -f deploy/

형태로 한번에 실행하여도 된다. (https://github.com/kubernetes-incubator/metrics-server/releases/latest)

 

메트릭 서버가 정상적으로 실행되는지 확인하는 명령은 아래와 같다. 메트릭 서버 또한 하나의 포드로 배포되며 시스템 포드 중 하나이다.

 

# kubectl get deployment metrics-server -n kube-system

 

HPA를 구성한 하고 get으로 HPA를 가져오면 

 

 

Target 부분에 지정한 리소스의 모니터링 값이 표시된다. 0%는 사용량이고 80%는 임계값이다.

 

이제 기본 메트릭서버를 만들어보았으니 프로메테우스를 생성해보겠다. 프로메테우스는 모니터링툴로 쿠버네티스 환경에서 많이 사용된다.

프로메테우스 또한 메트릭 서버와 마찬가지로 하나의 포드로 생성된다. 리소스만 수집하는 메트릭 서버와 달리 프로메테우스는 커스텀 메트릭 또한 수집할 수 있다.

 

 

 

프로메테우스를 생성하는 방법은 Helm을 사용하는 방법과 매니페스트를 사용하여 생성하는 방법인데 EKS 기반에서 프로메테우스를 실행하도록 할 것이다.

매니페스트 : https://github.com/coreos/prometheus-operator/blob/master/bundle.yaml -> kubectl apply -f bundle.yaml

Helm : helm install stable/prometheus \

--name prometheus \

--namespace prometheus \

--set alertmanager.persistentVolume.storageClass="gp2",server.persistentVolume.storageClass="gp2"

 

* Helm 설치

# Helm install

curl https://raw.githubusercontent.com/helm/helm/master/scripts/get > get_helm.sh

chmod 700 get_helm.sh

./get_helm.sh

 

# tiller ServiceAccount Create and ClusterRoleBinding

kubectl -n kube-system create sa tiller

kubectl create clusterrolebinding tiller --clusterrole cluster-admin --serviceaccount=kube-system:tiller

 

# tiller Install

helm init --service-account tiller --upgrade

 

프로메테우스 포드 구동 확인

 

 

프로메테우스를 설치하면 지표 수집 도구가 cAdvisor 뿐만 아니라 kube-state-metrics도 설치가 된다.

이제 로컬시스템에서 프로메테우스로 포트포워딩을 하여 접속 가능하게 해보자

 

# kubectl --namespace=prometheus port-forward deploy/prometheus-server 9090

 

웹 브라우저에서 localhost:9090으로 접속 하면 아래와 같이 실행된다.

 

 

이렇게 생성된 프로메테우스는 그라파나와 연결할 수 있다.

 

모니터링 부분은 아직 내용이 빈약하기 때문에 나중에 다시 정리를 해야겠다.

 

 

 

 

반응형

'Kubernetes' 카테고리의 다른 글

Kubernetes Ingress  (0) 2019.09.19
Kubernetes Service  (0) 2019.09.17
Kubernetes HorizontalPodAutoscaler  (0) 2019.08.31
Kubernetes Pod DaemonSet  (0) 2019.08.30
Kubernetes Pod Replica  (0) 2019.08.30
728x90
반응형

HorizontalPodAutoscaler

 

포드의 오토스케일링에 대해서 알아본다. 레플리카셋으로 구성된 포드는 원하는 숫자만큼 포드를 유지시켜주지만 오토스케일링을 할 수 있는 기능은 없다. 그렇기 때문에 포드를 오토스케일링하려면

별도의 포드를 구성해 오토스케일링을 해야한다. 이런 기능을 해주는 것이 HorizontalPodAutoscaler 이다.

 

오토스케일링하는 방법에는 스케일 업,다운 또는 스케일 인,아웃이 있는데 스케일 업,다운은 VPA (VerticalPodAutoscaler) 라는 기능을 사용하고 스케일 인, 아웃은 HPA (HorizontalPodAutoscaler) 를 사용한다.

지금 알아볼 것은 HPA 이다.

 

 

오토스케일링 프로세스

 

오토스케일링 프로세스는 세 단계로 나눌 수 있다.

1. 스케일된 리소스 객체가 관리하는 모든 포드의 메트릭을 가져옴

2. 지정된 목표 값에 메트릭을 가져오는 데 필요한 포드 수를 계산

3. 스케일된 리소스의 복제본 필드를 업데이트

 

 

노드 X 부분은 힙스터로 되어있는데 이제 힙스터는 사용하지 않으니 메트릭서버 또는 프로메테우스를 사용하면 된다. 

이렇게 가져온 데이터를 통해 지정된 목표값 (cpu, memory 등) 과 현재 포드 수를 계산해 포드를 늘려야할지 줄여야 할지 결정한다.

 

가져온 데이터를 계산하여 목표값보다 현재 사용중인 사용량이 많다면 HPA는 Deployment의 유지해야하는 복제수 숫자를 늘린다. 이렇게 Deployment 수정하면 Replicaset은 새로운 포드를 생성해야함을 인지하고 스케줄러에게 새로운 포드를 생성하라고 전달한다. 그러면 스케줄러는 새로운 포드를 생성할 노드를 결정하고 해당 노드의 Kubelet에게 포드를 생성하라고 요청한다. 그러면 Kubelet은 Deployment의 템플릿에 정의된 대로 포드를 생성한다. 여기까지가 포드 오토스케일링이 되는 과정이다.

 

 

HPA의 계산 매커니즘

 

 

우선 CPU 타켓 기준으로 설명을 하겠다.

현재 세개의 포드가 구동 중이고 오토스케일링을 목표 값은 CPU 50%이다. 50%가 넘으면 스케일 아웃이 되는 설정인 상태

 

HPA는 메트릭 서버에서 가져온 값을 계산하기 시작한다. 세 포드의 평균 / 목표값 을 계산하여 구동되어야할 Replicas를 결정하는데 여기서 3.6이 나왔다면 HPA는 소수점 반올림으로 4개를 실행해야한다고 결정 내린다. 그렇게 되면 스케일 아웃이되는데 아래에 Target QPS 부분도 확인해보자

 

위의 그림의 경우 오토스케일링 정책이 2개가 설정되어있는 경우이다. 목표값이 50%가 넘거나 QPS 지표가 목표값을 넘거나 하면 스케일 아웃을 하는 경우이다. 근데 그림을 보면 CPU 지표를 보면 스케일 아웃을 해야하는데 QPS는 현재 상태를 유지해도 되는 지표이다. 이런 경우 어떤 값을 따를까? 가장 높은 값을 목표 값으로 설정한다. 둘중 하나라도 스케일아웃이 필요하면 그 포드는 스케일 아웃된다.

 

이것만 알아두면 좋을것 같다. 어떤 목표값을 여러개 지정하더라도 그중 하나의 값이 스케일 아웃에 해당된다면 다른 값들은 무시되고 스케일 아웃이 진행된다.

 

스케일 아웃 계산법을 알아봤으니 스케일인에 대한 계산법도 알아본다.

목표한 값이 50이고 세개의 포드 값이 90이다. 각 포드당 CPU가 30%인경우

 

그렇게 되면 90/50 = 1.8이 된다. 필요한 포드의 수가 1.8개, 반올림하면 2개

 

즉 2개의 포드가 필요한 계산이 나오므로 HPA는 실행중인 포드의 수를 2개로 맞추기 위해 하나의 포드를 랜덤으로 삭제하게된다.

 

 

HPA 만들기

 

 

- cpu의 평균 값이 80%이상되면 스케일 아웃을 하는  HPA를 생성한 예제이다.

 

반응형

'Kubernetes' 카테고리의 다른 글

Kubernetes Ingress  (0) 2019.09.19
Kubernetes Service  (0) 2019.09.17
Kubernetes Monitoring - Version1  (0) 2019.09.17
Kubernetes Pod DaemonSet  (0) 2019.08.30
Kubernetes Pod Replica  (0) 2019.08.30
728x90
반응형

Daemon Set

 

포드를 관리하는 컨트롤러는 크게 두 가지로 나뉜다. 레플리카셋, 데몬셋이다. 이전에 레플리카는 설명했으므로 이번에는 데몬셋을 설명해보려 한다.

 

데몬셋이란 모든 노드에 하나씩만 포드가 실행하도록 하는 컨트롤러이다. 레플리카셋은 원하는 복제수 만큼 노드에서 포드가 실행된다. 하나의 노드에 두개, 세개 이렇게 실행될 수 있지만 데몬셋은 무조건 노드하나에 포드하나만 실행한다. 모든 노드에 공평하게 하나씩만 분배하는 것이다. 

 

 

위의 그림은 레플리카셋과 데몬 셋의 차이점을 나타낸다. 개념 자체는 어려운 개념이 아니기 때문에 이정도면 설명이 될 것이다.

 

레플리카셋과 데몬셋은 어떤 차이점이 있을까?

우선 스케줄러를 사용하냐 안하냐의 차이가 있다. 레플리카셋의 경우 노드에서 실행되려면 스케줄러를 통해 해당 노드에서 실행될 수 있는지 없는지를 확인하는데 데몬셋은 스케줄러를 사용하지 않는다. 그냥 무조건 노드에 하나씩 배포되기 때문에 스케줄러를 사용할 필요가 없기때문이다. 그러니 복제본 수에 대한 설정도 없으며 라벨 셀렉터의 의미도 없다. 

 

데몬셋으로 실행되는 포드는 노드가 죽으면 자기도 같이 죽는다. 다른데 옮겨가지도 않으며 자신이 속한 노드에서만 실행되고 사라진다.

 

근데 여기서 알아둬야 할점은 노드를 선택해서 실행할 수 있다는 점이다. 이건 데몬셋을 왜 사용하는지를 이해하면 왜 노드를 선택하는지를 알 수가 있다.

 

일단 데몬셋을 사용하는 예제부터 알아본다.

 

1. 노드에서 기본적으로 실행해야하는 시스템 포드

2. 노드에서의 로그 수집 또는 모니터링

3. 특정 노드에서 실행되야하는 포드

 

환경에 따라 사용되는 방법이 모두 다르지만 기본적으로 사용한다면 이정도이다.  여기서 특정 노드에서 실행되야하는 포드가 이해가 안될 수 있는데 이를 위해 예를 하나 들어보겠다.

 

노드가 2개가 있는데 하나는 SSD, 다른 하나는 HDD를 가진 노드라고 가정한다. 여기서 일반적으로 데몬셋을 실행하면 두 노드위에 각자 포드가 생성되지만 사용자는 SSD에서 빠른 디스크 I/O 작업을 해야하는 포드를 실행해야 한다면 SSD를 가진 노드에서만 작업하려고 할것이다. 그렇다면 SSD를 가진 노드들에만 데몬셋을 실행시켜야 하는데 이런 경우 특정 노드셀렉터를 사용하여 실행하고싶은 노드에서만 데몬셋에 의한 포드가 생성되도록 할 수 있다.

 

아래는 간단하게 모든 노드에서 nginx를 구동하는 매니페스트이다.

 

 

반응형

'Kubernetes' 카테고리의 다른 글

Kubernetes Ingress  (0) 2019.09.19
Kubernetes Service  (0) 2019.09.17
Kubernetes Monitoring - Version1  (0) 2019.09.17
Kubernetes HorizontalPodAutoscaler  (0) 2019.08.31
Kubernetes Pod Replica  (0) 2019.08.30
728x90
반응형

Replication Controller

 

레플리케이션 컨트롤러 리소스란 쿠버네티스 리소스 중 하나로 포드가 항상 실행되도록 유지하게 하는 역할을 한다.

일단 레플리카 개념부터 이해해보자.

레플리카의 역할이란 예를 들어 두 개의 포드가 운영중이라고 하면 이 중 하나의 포드가 사용자의 실수 또는 노드의 장애로 실패 (삭제) 되었을 때 다른 포드를 바로 생성하여 두 개가 유지되도록 해주는 역할을 한다. 하나의 포드를 여러개 복사한 것을 복제본이라는 표현을 사용하는데 이런 복제본의 숫자가 항상 유지되도록 해주는 역할을 하는 것이 레플리카이다. 

 

아래는 그림으로 표현한 레플리카이다.

 

 

포드 A와 포드 B가 있는데 포드 A는 레플리카를 사용하지 않고 생성한 일반 포드이고 포드 B는 레플리카를 통해 생성한 포드이다. 이 두 포드가 실행되는 노드에 장애가 발생하였을 때 레플리카는 자신이 관리하는 포드에 문제가 생겼음을 감지하고 클러스터 내에 있는 다른 노드에 새로운 포드 B를 생성한다. 포드 A의 경우 레플리카가 관리하는 포드가 아니므로 삭제가 되어도 복구할 수 없다.

포드가 항상 실행상태로 유지되려면 레플리카의 영역내에서 실행되어야 한다. 그리고 당연한 얘기이겠지만 포드가 실패한 것을 레플리카가 어떻게 알 수 있냐인데 레플리카는 항상 자신이 관리하는 포드를 모니터링해서 자신이 원하는 포드의 수와 실행중인 포드의 수를 비교하여 일치하는지 확인한다.

 

쿠버네티스에서 레플리카를 실행하는 것이 레플리케이션컨트롤러이다. 현재는 레플리케이션 컨트롤러의 업그레이드 버전인 레플리카셋이 사용되며 라벨 셀렉터 부분에서 차이가 있으나 이 부분은 나중에 알아보고 레플리케이션 컨트롤러의 동작 과정 및 개념에 대해 알아보겠다.

 

 

레플리케이션 컨트롤러의 동작과정

 

레플리케이션 컨트롤러의 동작 과정을 알아보겠다.

 

  1. 레플리케이션 컨트롤러가 실행

  2. 자신이 가진 라벨셀렉터와 일치하는 라벨셀렉터를 가진 포드를 검색

  3. 검색된 포드의 수와 자신이 원하는 수의 포드의 수가 일치하는지 확인

  4. 원하는 수의 포드보다 더 많은 경우 실행 중인 포드 중 랜덤으로 지정하여 삭제함 (어떤 포드가 삭제될지는 알 수 없음, 다만 나중에 다른 글에서 설명하겠지만 종료 규칙을 지정하여 포드가 삭제되게 하도록 할 수 있다)

  5. 원하는 수보다 포드의 수가 적은 경우 정의된 템플릿대로 원하는 수와 일치하는만큼 포드를 실행함 (템플릿이란 레플리케이션 컨트롤러 매니페스트[yaml 파일] 에 정의된 내용)

  6. 이제 이 과정을 마쳤다면 다시 검색단계로 돌아가 지속적으로 위의 단계를 반복함

 

 

레플리케이션 컨트롤러에는 세 가지 요소가 있는데 아래와 같다.

 

1. 라벨 셀렉터 : 레플리케이션 컨트롤러 범위에 있는 포드를 결정

2. 복제본 수 : 실행하고 싶은 포드의 수

3. 포드 템플릿 : 새로운 포드 (복제본) 를 생성할 때 사용

레플리케이션 컨트롤러는 이렇게 세 가지의 요소를 가지고 있는데 이 요소들은 언제든 수정이 가능하다.

 

 

레플리케이션 컨트롤러의 생성 과정

 

 

그림 하나에 모든 설명이 들어가 있으므로 다른 설명은 생략하겠지만 항상 기억해둬야 할점은 포드를 생성하는 건 레플리케이션 컨트롤러가 아니라 Kubelet이다.

레플리케이션 컨트롤러는 스케줄러를 통해 노드의 Kubelet에게 포드를 생성하라고 전달을 할뿐이지 자신이 직접 생성하지 않는다.

 

 

레플리케이션 컨트롤러 생성 및 삭제

 

구성 요소들을 알아봤으니 레플리케이션 컨트롤러를 만드는 방법을 알아보자.

아래는 레플리케이션 컨트롤러를 생성하는 매니페스트 이다. 파일의 이름은 testrc.yaml 이라고 가정한다.

 

apiVersion: v1

kind: ReplicationController # 레플리케이션 컨트롤러 (RC) 의 매니페스트 정의

metadata:

    name: test # 레플리케이션 컨트롤러의 이름

spec:

    replicas: 3 # 원하는 포드 인스턴스 수

    selector: # 포드 셀렉터를 통해 RC가 관리하려는 포드를 결정

        app: web

    template: # 새 포드를 생성하는 포드 템플릿

        metadata:

            labels:

                app: web

        spec:

            containers:

                - name: nginx

                  image: nginx:latest

                  ports:

                    - containerPort: 8080

 

위의 매니페스트를 해석하면 RC (ReplicationController) 리소스를 생성하고 컨트롤러의 이름은 test 이며 app=web 이라는 라벨을 가진다. 이 컨트롤러는 항상 3개의 포드가 유지되도록 동작하며 생성할 포드의 템플릿에는 포드의 라벨, 컨테이너 이미지, 컨테이너 포트가 포함되어 있다.

 

위의 매니페스트를 실행하려면 아래의 명령을 실행한다.

 

# kubectl apply -f testrc.yaml

 

이 후 생성된 컨트롤러의 세부정보를 확인하려면 아래의 명령을 실행한다.

 

# kubectl describe rc test

 

여기서 rc는 레플리케이션 컨트롤러를 의미하며 test는 매니페스트 메타데이터에 정의한 이름이다.

 

생성 후 레플리케이션 컨트롤러를 삭제하면 실행중이던 포드들도 함께 삭제가 된다. 만약 레플리케이션 컨트롤러가 삭제되더라도 포드는 실행되기를 바란다면 삭제 명령에 옵션을 주면 포드는 삭제되지 않는다.

 

# kubectl delete rc test --cascade=false

 

해당 명령은 레플리케이션 컨트롤러만 삭제하고 포드는 유지할 수 있게한다. 

 

 

 

레플리케이션 컨트롤러와 레플리카 셋의 차이

 

예를 들어 포드 세개가 구동중이고 이 포드들의 라벨은 app=kubia 이다. 근데 이중 하나의 포드에 라벨을 추가하면 어떻게 될까?

# kubectl label pod kubia-OOOO app=foo --overwrite -> 포드에 라벨을 추가하는 옵션은 --overwrite 이다.

 

 

 

어차피 app=kubia를 가진 포드고 여기서 라벨 하나만 더 추가된다 하더라도 포함되어 있으니까 상관없지 않을까라는 생각을 하지만 레플리케이션 컨트롤러는 자신의 라벨과 포드의 라벨이 정확히 일치하지 않는다고 결정 내리고 기존 포드는 잃어버렸다(?) 라고 생각하여 새로운 포드를 추가한다. 이게 레플리케이션 컨트롤러의 단점이였다. 하지만 이 부분이 개선되서 나온것이 레플리카셋이다.

 

레플리카 셋은 레플리케이션 컨트롤러와 모든게 동일하지만 라벨 셀렉터에서 차이점이 생긴다. 위의 경우처럼 라벨이 정확히 일치하지 않는 포드가 있으면 레플리케이션 컨트롤러는 실패한 포드라고 생각을 하지만 레플리카 셋은 자신이 가진 라벨중 하나만 있어도 그 포드는 자신이 관리하는 포드라고 생각한다.

 

레플리카 셋은 레플리케이션 컨트롤러의 라벨 셀렉터를 개선하였다. 어떻게 개선하였냐면

 

레플리케이션 컨트롤러 : 라벨 env=dev 이면 포드의 라벨도 env=dev 이어야 한다. (무조건 정확히 일치해야함, 라벨이 더있거나 덜 있거나 문자가 다르면 안됨)

레플리카 셋 : 라벨 env=dev 이고 포드의 라벨이 env=dev, env=stg, env= 과 같이 있다하면 env=* 형식으로 자신이 가진 라벨 키와 같은 라벨키를 가진 포드를 모두 포함할 수 있다.

 

하나의 예를 더 들어서 설명하겠다.

 

Replication Controller Label : env=dev

ReplicaSet Label : env=prd

Pod Label : env=dev, env=prd

 

이렇게 라벨을 가진 경우 레플리케이션 컨트롤러는 포드가 두개의 라벨을 가진건지 두 개의 포드가 각자 하나씩 라벨을 가진 건지 알지 못한다. 포드에 있는 라벨 중 하나만 일치하고 다른 하나는 인식하지 못하는 라벨이기 때문에 자신이 관리하는 포드라고 지정할 수도 없다.

반면 레플리카셋은 포드의 두개의 라벨이 있고 그 라벨의 키가 자신이 가진 키와 동일하다면 하나의 포드가 두개의 라벨을 가진것을 알 수 있으며 자신이 관리하는 포드라고 알 수 있다.

 

이런 라벨 셀렉터를 정의하는 조건절도 있으며 매니페스트를 통해 어떻게 하는지 알아보겠다.

 

apiVersion: apps/v1

kind: ReplicaSet

metadata:

    name: test

spec:

    replicas: 3

    selector:

        matchExpressions: # 이 셀렉터는 포드에 "env" 키가 있는 라벨을 포함해야 함

            - key: env

             operator: In

             values:

                - stg # 라벨의 값은 stg이여야 함

    template:

        metadata:

            labels:

                env: stg

        spec:

            containers:

            - name: nginx

              image: nginx:latest

 

matchExpressions로 라벨 셀렉터에 표현식을 추가할 수 있다 (키, 연산자, 가능한 값)

 

연산자에는 네 가지의 연산자가 있다.

  • In : 라벨의 값이 지정된 값 중 하나와 일치해야함

  • NotIn : 라벨의 값이 지정된 값과 일치해서는 안됨

  • Exists : 포드에는 지정된 키가 있는 라벨이 포함돼야함 (값은 중요하지 않음), 이 연산자를 사용할 때 값 필드를 지정하면 안됨

  • DoesNotExist : 포드에는 지정된 키가 있는 라벨을 포함하면 안됨, values 속성을 지정하면 안되고 여러 표현식을 지정하면 셀렉터가 포드와 일치하도록 모든 표현식이 true로 평가돼야 함

 

 

테스트했던 내용

 

만약 두개의 레플리카셋이 있고 하나의 포드가 두 레플리카셋이 가진 라벨과 모두 일치한다면 어찌될까?

 

1번 Replicaset-1 : env=dev

2번 Replicaset-2 : env=prd

Pod : env=dev, env=prd

 

위 처럼 포드는 두 개의 레플리카셋이 관리하는 라벨을 모두 가지고 있다.

 

이런 경우에는 포드는 자신을 생성한 레플리카셋 (Replicaset-1) 의 관리만 받는다. 포드는 1번 레플리카의 관리 포드이므로 2번 레플리카에서는 관리할 수 없다.

만약 이 상태에서 1번 레플리카셋을 삭제한다면 포드는 함께 삭제되었는지 아니면 2번 레플리카 셋에 포함되었는지 기억이 나진 않는다.

다만 어찌됬든 1번 레플리카셋과 함께 삭제되던가 2번 레플리카셋에 포함되서 원하는 수를 넘으므로 삭제되던가 결국은 사라진다. 2번 레플리카셋에 포함되면 랜덤으로 사라짐 (동작 과정 보면 알수 있음)

반응형

'Kubernetes' 카테고리의 다른 글

Kubernetes Ingress  (0) 2019.09.19
Kubernetes Service  (0) 2019.09.17
Kubernetes Monitoring - Version1  (0) 2019.09.17
Kubernetes HorizontalPodAutoscaler  (0) 2019.08.31
Kubernetes Pod DaemonSet  (0) 2019.08.30

+ Recent posts