SLASH 기술 블로그

쿠버네티스로 배포하기 2 - 쿠버네티스에 이미지 올리기 본문

인프라/쿠버네티스

쿠버네티스로 배포하기 2 - 쿠버네티스에 이미지 올리기

SLASH 2021. 5. 19. 11:57
반응형

1. How to containerize your app - 앱을 컨테이너화하는 방법에 대해 알아보자.

2. Running on Kubernetes Cluster - 쿠버네티스 클러스터에서 이미지 실행하기

3. Exposing the service - 서비스를 외부에 공개하기

4. Simplifying deployment process - 배포 과정 단순화하기

 

이전 글에서는 작업하던 앱을 컨테이너화하는 방법을 알아보았다. 이미지를 만들었으니 도커가 지원되는 환경이라면 어디서든 배포를 할 수 있다.

 

이제 그 다음 단계로, 쿠버네티스 클러스터에서 이미지를 실행하는 방법에 대해 알아보자. 이전에 docker build / docker run 명령어를 통해서 실행했던 것과 조금 달라진 부분들(환경 변수 설정 등)이 있다.

 

사전 준비 - 로컬 클러스터

시작하기 전에 로컬에서 쿠버네티스 클러스터를 띄워서 테스트해볼 수 있도록 환경을 구축해야 한다. minikube가 가장 무난한 방법이고, kind같은 대안도 있다.

 

쿠버네티스 API를 사용할 수 있는 클라이언트도 필요한데, 쿠버네티스의 CLI 도구인 kubectl을 사용하거나, k9s같은 유틸리티를 써도 된다.

 

어떤 방법을 선택했든, 로컬에서 클러스터를 구축하고 이에 접근할 수 있는 도구를 준비했다면 이제 시작해보자.

 

1단계: Deployment 작성하기

쿠버네티스를 통해 배포하기 위해서 우선 Deployment를 작성한다. Deployment는 팟의 복제본 수를 조절하거나, 배포 이력 등을 관리할 수 있는 오브젝트로, 쿠버네티스에서 가장 널리 사용되는 오브젝트이다.

 

이전 글에서 만들었던 이미지를 사용하는 Deployment를 작성해보았다. selector.matchLabelsapptemplate.metadata.labelsapp을 동일하게 지정해야 한다.

 

이 때, AWS의 ECR같은 private registry를 사용할 경우 imagePullSecrets를 설정하거나 service account를 설정해야 이미지를 제대로 가져올 수 있다. 관련 글을 참고하자.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deno-app
spec:
  selector:
    matchLabels:
      app: deno-app
  template:
    metadata:
      name: deno-app-pod
      labels:
        app: deno-app
    spec:
      containers:
        - name: deno-app-container
          image: ghcr.io/turastory/deno-app-test:latest
          resources:
            limits:
              memory: "256Mi"
              cpu: "500m"
          ports:
            - containerPort: 8080 # does not affect actual port
      imagePullSecrets:           # for private registry
        - name: ghcr-turastory

 

Deployment가 제대로 생성되는지 확인해보자. kubectl apply, 그리고 kubectl get을 사용한다.

$ kubectl apply -f deno-app.yaml
deployment.apps/deno-app configured

$ kubectl get po,deploy
NAME                            READY   STATUS    RESTARTS   AGE
pod/deno-app-76db8ddd9b-9bf8q   1/1     Running   0          5s

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/deno-app   1/1     1            1           5s

 

한 가지 주의해야 할 점이라면, ports.containerPort에 지정한 conatinerPort는 Dockerfile의 EXPOSE와 같이 문서화 용도이고, 실제로 컨테이너의 포트에 영향을 주지는 않는다는 점이다. 보안 상의 이유로 저런 식으로 포트를 개방하지 못하도록 되어 있다.

 

외부에서 파드에 접근하기 위해서는 Service를 사용해야 하거나, 포트 포워드를 사용해야 한다.

 

 

+ VSCode로 쿠버네티스 설정 편집하기

처음 쿠버네티스 설정 파일을 편집할 때 어느 정도 가이드가 있으면 훨씬 편할 것이다. VSCode를 사용하면 쿠버네티스가 제공하는 Kubernetes Tools 익스텐션을 사용할 수 있다.

 

클러스터를 조작할 수 있는 다양한 기능들이 있지만, 우선 에디터 기능만 훑고 넘어가자. 익스텐션을 설치한 다음 YAML 파일에서 쿠버네티스 오브젝트의 앞 글자를 입력하면 아래 이미지와 같이 템플릿이 제공된다.

 

Deploy를 입력하니 Deployment 템플릿을 추천해준다.
쿠버네티스 익스텐션을 통해 생성한 Deployment 템플릿

세부 설정들은 문서를 참고해야겠지만, 타입 체크나 warning도 표시해주어 작성하는 데 큰 도움이 된다. 혹시 지금까지 사용하지 않고 있었다면 이번 기회에 설치해서 사용해보자!

 

2단계: Service 작성하기

작성한 Deployment를 외부에서 접근하기 위해서는 Service가 필요하다. 두 가지 방법이 있는데, NodePort 서비스로 노드의 포트를 열거나, 포트 포워딩을 활용하는 방법이 있다.

 

먼저 포트 포워딩을 통해서 우리가 만든 앱을 테스트해보는 방법부터 알아보자.

 

옵션 1 - ClusterIP + Port forwarding

외부에서 파드에 접근할 수 있는 방법으로 보통 NodePort 타입의 서비스를 많이 이야기하는데, ClusterIP 타입의 서비스와 포트 포워딩을 사용해서 외부에서 파드에 접근할 수도 있다.

 

이전과 마찬가지로 서비스를 작성한다. 어느 방법을 택하든 서비스는 필요한데, 서비스가 있어야 논리적인 파드 집합에 접근할 수 있는 단일 엔드 포인트를 정의할 수 있기 때문이다. (replica가 여러 개일 경우 / 장애 등으로 일부 파드가 재생성됬을 경우 등의 상황을 생각해보자)

 

이번에는 ClusterIP 타입을 사용한다. ClusterIP 타입은 파드가 실행되는 노드의 포트는 건들지 않고 파드에 포트 연결만 해준다.

apiVersion: v1
kind: Service
metadata:
  name: deno-app-service
spec:
  type: ClusterIP
  selector:
    app: deno-app
  ports:
    - port: 8080
      targetPort: 8080

 

포트 포워딩을 하는 명령어는 kubectl port-forward 이다. 호스트 포트, 컨테이너 포트 순으로 : 를 사이에 두고 입력하면 된다. 9090 포트를 컨테이너의 8080 포트로 연결해보자.

 

$ kubectl port-forward service/deno-app-service 9090:8080
Forwarding from 127.0.0.1:9090 -> 8080
Forwarding from [::1]:9090 -> 8080

 

9090 -> 8080으로 포트 포워딩 되었다!

 

 

옵션 2 - NodePort Service

포트 포워딩은 일반적으로 단순 테스트할 때 용이하고, 실제로 서비스를 할 때는 NodePort 타입의 서비스와 함께 AWS같은 범용 클라우드 프로바이더가 제공하는 로드 밸런서를 사용하거나, 후술할 Ingress를 사용한다.

 

앞에서 설정했던 app: deno-app을 selector로 해서 NodePort 타입의 서비스를 작성했다. 서비스의 타입 중 NodePort 타입은 실제로 파드가 실행되는 노드(예를 들어, EC2 인스턴스)의 포트를 개방한다.

apiVersion: v1
kind: Service
metadata:
  name: deno-app-service
spec:
  type: NodePort
  selector:
    app: deno-app
  ports:
    - port: 8080
      targetPort: 8080

 

kubectl apply 명령을 통해 작성한 yaml 파일을 적용하면 디플로이먼트와 서비스가 생성된다.

$ kubectl apply -f deno-app.yaml
deployment.apps/deno-app unchanged
service/deno-app-service created

 

노드의 포트를 개방했다면 kubectl cluster-info 명령을 통해서 클러스터의 외부 IP 주소를 가져와 사용할 수 있는데, EKS와 같은 매니지드 클러스터 서비스를 사용한다면 보안 그룹으로 막혀 있는 인스턴스의 포트를 따로 개방해줘야 한다.

 

그 외에, minikube를 통해서 로컬에 클러스터를 생성한 경우에는 minikube service 명령으로 서비스에 접근할 수 있는 주소를 받을 수 있다.

$ kubectl cluster-info # Get public IP of the cluster
$ curl http://<ip-address>:8080

# Minikube를 사용할 경우
$ minikube service deno-app-service --url

 

minikube가 52297번 포트를 통해 접근할 수 있도록 해주었다.


이미지를 제작해서 배포한데 이어서, 이번 단계에서는 쿠버네티스에 해당 이미지를 배포하는 과정을 살펴보았다. 하지만 아직 다루지 못한 부분이 너무 많다. 로드 밸런싱은 어떻게 하는지, 도메인은 어떻게 연결해야 하는지, 그리고 이 모든 과정을 어떻게 자동화해야 하는지...

 

쿠버네티스에는 도커와 다르게 생소한 개념이 많아서 처음 사용했을 때 무척 혼란스럽고 어려운 게 당연하다. 그래서 여러 다른 자료들과 병행하면서 앱을 쿠버네티스로 올리는 과정을 무사히 마쳤으면 좋겠다.

 

@turastory

반응형
Comments