본문 바로가기
실습/NHN

실습1. NHN Kubernetes Service(NKS)로 컨테이너 배포

by 나르는나른 2025. 6. 29.

https://byeongg96.tistory.com/104

 

실습4. NHN Container Registry에 이미지 빌드 및 업로드

먼저 내 NHN Cloud Console의 Container메뉴에는 NHN Container Registry(NCR)서비스메뉴가 없기때문에홈페이지에서 서비스 이용하기를 따로 해줘야한다. 여기서 서비스 이용하기를 누르면 이렇게 Console에 NCR

byeongg96.tistory.com

 

Docker 실습 단계에서 NCR에 Spring Boot 웹 애플리케이션 이미지를 저장했다.

 

이 이미지를 사용해서 NKS로 5개의 컨테이너를 배포하고 로드밸런서까지 적용해서 부하 분산 및 고가용성을 확보해보자.

 

 

먼저 NKS 클러스터를 생성해준다.

 

 

우선은 간단하게 배포 테스트만 진행할것이기 때문에, VPC와 서브넷은 Default를 사용하겠다.

 

파드 네트워크: 클러스터 내 모든 파드가 사용할 수 있는 전체 IP대역

파드 서브넷 크기: 각 노드마다 할당되는 파드용 서브넷 크기

 

즉, 클러스터 전체 파드 네트워크를 노드마다 /24 서브넷 단위로 나누어 할당한다.

각 노드마다 할당되는 파드용 서브넷 크기를 /24로 지정했다는것은 각 노드마다 256-2=254개의 파드용 IP를 사용하겠다는것이다.

 

파드 네트워크는 총 65,536개의 IP 범위를, 그리고 노드 하나당 256개의 IP 범위를 갖는다면, 노드수를 구하는 공식은 쉽다.

65,536을 256으로 나누면 몫은 256이다.

그리고 클러스터는 안정적 운영을 위해 3개의 예약 서브넷이 필요하기 때문에, 256-3=253개의 노드수가 나온다.

 

다음은 Add-ons 설정이다.

 

CNI: 쿠버네티스에서 컨테이너 간 네트워크 연결을 관리하는 네트워크 인터페이스 플러그인이다.

파드 간 통신을 관리하고, 파드에 IP를 할당하여 통신이 가능하게 한다.

CNI는 마치 DHCP가 하는 일과 유사한 역할을 수행한다. 

 

kube-dns: 쿠버네티스 클러스터 내부의 DNS 서비스를 담당한다. 클러스터 내 서비스와 파드를 이름 기반으로 손쉽게 찾고 연결할 수 있게 해준다. 예를 들어, my-service라는 서비스가 클러스터에 생성된 경우 다른 파드가 서비스 이름(my-service)으로 접근을 요청하면, CoreDNS가 이름을 IP로 변환해줘서 자동으로 파드와 연결해준다.

 

여기서 이미지는 쿠버네티스가 실행될 환경을 선택하는것이다.

노드 수를 2개로 지정했으니까, 우분투 서버 VM이 2개 생긴다고 보면 된다.

각 노드에 2~3개정도의 파드를 실행할 예정이다.

 

블록 스토리지 타입은 SSD를 선택할 수 있지만, 개인 실습 목적이기 때문에 비용문제를 사전에 방지하기 위해 HDD로 설정한다.

 

최종 검토까지 마치고 나면..

클러스터가 생성된다!

 

'작업 상태'가 꽤 오래걸린다. 10~20분정도 걸리는것같다.

작업이 완료되면 사진처럼 'kubeconfig 파일' 다운로드 버튼이 활성화된다.

다운로드 후 .kube 폴더에 config 이라는 이름으로 저장해준다.

kubectl 명령어는 기본적으로 설정 파일이 어디 있는지 알려주지 않으면 C:\Users\<사용자명>\.kube\config 경로에서 설정파일을 자동으로 찾는다. 다른 파일명을 사용하고 싶다면 환경변수나 명령어 옵션으로 매번 지정해줘야한다.

물론 그렇게 해야 하는 경우도 있을테지만, 지금은 실습을 위해 간단히 config이라는 이름으로 저장해주겠다.

 

왜... 왜안되는거야!

혹시몰라서 config 파일 경로를 명시해서 다시 시도해봤다.

 

 

원인을 대충 파악한것같다. 일단 kubectl이 C:\Users\방병관\.kube 디렉터리를 찾지못하는것같다.

아오.. 설마 또 사용자명이 한글이라서 발생하는 문제인건가 싶어서

C:\kube 폴더를 만들어서 config 파일을 옮기고 재시도

역시 안된다..

고민을 하다가 문득 들은 생각이 혹시.. config 파일 확장자명을 적어줘야 하는게 아닐까 싶어서 확인해보니까

config.yaml으로 입력하니까 잘 된다.

 

아무래도 사용자명이 한글인게 또 말썽을 일으킨것같다...

 

이제 드디어 배포용 YAML 파일을 작성한다.

deployment.yaml 파일을 생성해준다. 파일명은 꼭 deployment로 할 필요는 없다. 쿠버네티스는 파일명이 아니라 파일의 내용에 있는 리소스 정의를 보고 동작하기 때문이다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-spring-app
  namespace: spring-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-spring-app
  template:
    metadata:
      labels:
        app: my-spring-app
    spec:
      imagePullSecrets:
        - name: ncr-regcred
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchLabels:
                app: my-spring-app
            topologyKey: kubernetes.io/hostname
      containers:
        - name: my-spring-app
          image: b32dc???-kr1-registry.container.nhncloud.com/my-spring-app-registry/my-spring-app:v1
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: "100m"
              memory: "256Mi"
            limits:
              cpu: "800m"
              memory: "1Gi"
          envFrom:
            - secretRef:
                name: spring-app-secrets

 

apiVersion: apps/v1
kind: Deployment

리소스 종류와 API 버전을 설정한다.

Deployment 객체에 대한 yaml파일임을 명시하고, 객체의 버전은 v1을 사용하겠다는 의미이다.

아래 링크에서 객체별 최신버전을 확인할 수 있다.

https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/

 

Kubernetes API Reference Docs

API Overview Welcome to the Kubernetes API. You can use the Kubernetes API to read and write Kubernetes resource objects via a Kubernetes API endpoint. Resource Categories This is a high-level overview of the basic types of resources provide by the Kuberne

kubernetes.io

 

metadata:
  name: my-spring-app
  namespace: spring-app

객체의 이름과 네임스페이스를 설정한다.

name: 클러스터 안에서 리소스를 식별하기 위한 고유한 이름을 설정한다. 식별자 역할을 한다.

namespace: 리소스 안에서 논리적으로 분리 또는 관리하기 위한 가상의 분리공간이다. 동일한 클러스터 내에서 여러 팀, 프로젝트, 환경 등을 격리하고 관리할때 사용한다.

spec:
  replicas: 2

애플리케이션 컨테이너를 실행할 파드 개수를 설정한다. 필자의 클러스터는 2개의 노드가 있고, 각 노드에 1개의 컨테이너를 실행하도록 할것이다.

  selector:
    matchLabels:
      app: my-spring-app

파드를 식별할 라벨을 지정한다.

  template:
    metadata:
      labels:
        app: my-spring-app

파드를 생성할 때 사용하는 템플릿을 설정한다. 파드는 이 설정에 따라 생성된다.

생성되는 파드마다 my-spring-app이라는 라벨을 부여한다.

    spec:
      imagePullSecrets:
        - name: ncr-regcred

프라이빗 컨테이너 레지스트리에서 이미지를 당겨오기 위한 인증 정보이다.

여기서는 NHN Cloud NCR(컨테이너 레지스트리)에 접근하기 위한 Secret인증 'ncr-regcred'를 사용한다.

※필자의 NCR은 Public URI를 사용하고있어서 사실 필요없는 과정이긴 하지만 실습을 위해 설정해봄

※Secret인증정보를 생성하는 과정은 다음 실습단계에 포스팅 예정

      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchLabels:
                app: my-spring-app
            topologyKey: kubernetes.io/hostname

파드 간 분산 배치 조건을 설정한다.

여기서는 'my-spring-app'이라는 라벨을 가진 파드는 서로 다른 노드에 분산배치 하도록 강제한다.

다소 무식한 방식일수도 있다는 생각이 드는데, 이렇게 하면 일단 각 노드당 1개의 파드만 실행된다.

      containers:
        - namemy-spring-app
          imageb32dc???-kr1-registry.container.nhncloud.com/my-spring-app-registry/my-spring-app:v1

컨테이너의 이름을 설정하고, 이미지가 있는 컨테이너 주소와 태그를 입력한다.

          ports:
            - containerPort: 8080

컨테이너 내부에서 노출할 포트 번호를 설정한다.

          resources:
            requests:
              cpu: "100m"
              memory: "256Mi"
            limits:
              cpu: "800m"
              memory: "1Gi"

리소스 요청 및 제한에 대한 설정이다.

requets는 컨테이너 실행을 위해 최소한으로 요구되는 리소스를 설정한다.

limits는 컨테이너가 최대 사용할 수 있는 리소스를 설정한다.

즉, 여기서는 각 파드가 최소, 최대로 사용할 수 있는 리소스를 설정한다고 보면된다.

          envFrom:
            - secretRef:
                name: spring-app-secrets

환경 변수를 설정한다.

하드코딩이 권장되지 않는 민감한 정보들을 spring-app-secrets라는 이름의 Secret 리소스에서 가져와 환경변수로 설정한다.

※환경변수 설정을 위한 Secret리소스를 생성하는 과정은 다음 실습단계에 포스팅 예정

 

이렇게 작성을 마쳤다면 아래 명령어를 사용하여 yaml파일을 쿠버네티스 클러스터에 적용해준다.

kubectl --kubeconfig="C:\kube\config.yaml" apply -f deployment.yaml\

※ --kubeconfig="C:\kube\config.yaml" 이 옵션은 필자가 config.yaml을 임의의 경로에 저장하였기 때문에, 명령어 사용시마다 config.yaml의 경로를 따로  지정해줘야해서 입력하는 옵션이다.

반영이 잘 된 모습이다.

이 명령어를 수행하면 자동으로 쿠버네티스가 파드를 생성한다.

그 다음, 아래 명령어를 사용하여 파드가 원하는 개수만큼 정상적으로 실행되고 있는지 확인한다.

kubectl --kubeconfig "C:\kube\config.yaml" -n spring-app get pods -w

설계한대로 2개의 파드가 실행중인 모습을 볼 수 있다.

 

이제 2개의 파드가 실행중이고, 그 안에서 spring boot 컨테이너가 실행중이다.

 

하지만 쿠버네티스의 노드는 기본적으로 외부에서 접근이 불가능한 프라이빗(Private) 환경에 위치하도록 구성되기 때문에, 로드밸런서를 구성하여 외부에서 로드밸런서를 통해 웹 애플리케이션에 접근할 수 있도록 설정해주어야 한다.

이 과정 또한 다음 실습 단계에서 알아보도록 하자.