본문 바로가기
Docker | Kubernetes

AKS 쿠버네티스를 도입하면서 정리한 글 - 배포하기

by 자유코딩 2019. 12. 16.

이 글을 통해서 얻으실 수 있는 것

1. 도커 이미지 빌드하기

2. 쿠버네티스에 앱을 배포하는 방법

쿠버네티스 소개

쿠버네티스는 컨테이너 관리 환경입니다.

도커같은 기술을 통해서 컨테이너를 만들었을때 컨테이너를 관리하기 위한 환경입니다.

비슷한 컨테이너 관리 환경으로는 Docker Swarm이 있습니다.

Mesosphere 같은 서비스도 있지만 현재 컨테이너 관리환경은 쿠버네티스가 표준이 되고 있습니다.

Azure, AWS, Google Cloud 에서도 EKS , AKS , GKE 를 서비스하면서 컨테이너 관리 환경으로 쿠버네티스를 서비스 하고 있습니다.

 

이런 컨테이너 관리 환경이 왜 필요할까요

더 쉬운 말로 표현한 쿠버네티스

도커같은 기술로 이미지를 만들고 배포한 컴퓨터가 여러대 있다고 했을 때

그 여러대의 컴퓨터를 관리하는 서비스를 쿠버네티스라고 보시면 됩니다.

직접 서비스를 운영하면서 느낀 쿠버네티스의 필요성

Azure App service, AWS EC2 인스턴스로 배포한 경우 서버 인스턴스에 문제가 생겼을때 사용자가 직접 수동으로 인스턴스를 껐다 켜거나 복구해야합니다.

 

만약에 새벽 2시에 인스턴스에 문제가 생겼다는 전화를 받고 일어나서 껐다 켠다고 생각해보면 참 힘듭니다.

 

쿠버네티스와 프로메테우스 같은 모니터링 툴을 사용하면 서버에 문제가 생겼을때 자동으로 재부팅해서 복구하도록 할 수 있습니다.

 

그리고 인스턴스에 요청이 높아지거나 낮아질 경우 쿠버네티스가 배포 한 서비스의 크기를 줄이고 늘리고 관리 할 수 있습니다.

 

이런 이유로 쿠버네티스를 시작하게 됐습니다.

 

그리고 몇가지 문제를 겪었습니다.

1. 쿠버네티스에서 쓰이는 용어

2. pod간의 통신

3. autoscale 후 테스트

4. 배포한 pod의 상태확인 방법 - Typescript-rest api 에 상태확인 코드 넣기

 

어떻게 해결했는지 어떤 자료들이 도움이 되었는지 글로 남기고자 합니다.

 

https://kubernetes.io/ko/docs/tutorials/

 

튜토리얼

 

kubernetes.io

용어에 관한 부분은 여기 쿠버네티스 튜토리얼 문서를 봤습니다.

 

조대협 님의 블로그 글도 많은 도움이 되었습니다.

https://bcho.tistory.com/1255

 

쿠버네티스 #1 - 소개

Kubernetes #1 - 소개 조대협 (http://bcho.tistory.com) 배경 도커와 쿠버네티스를 알게 된건 수년전인데, 근래에 들어서 다시 쿠버네티스를 보기 시작하였다. 컨테이너 기반의 환경은 배포에 장점이 있고 마이크..

bcho.tistory.com

 

먼저 대표적으로 쓰는 용어부터 보겠습니다.

 

클러스터

클러스터는 쿠버네티스를 사용하면서 쓰는 하나의 전체 단위를 말합니다. 컴퓨터 클러스터를 말합니다.

예를 들어서 EKS(아마존 관리형 쿠버네티스 서비스) 나 AKS(애져 관리형 쿠버네티스 서비스) 에서는 만들어지는 한 개의 단위 입니다.

AKS 서비스를 통해서 만든 클러스터
쿠버네티스 공식 문서에서 가져온 그림

쿠버네티스 클러스터 안에는 노드들이 있습니다.

그럼 노드가 뭔지 알아보면

노드

노드는 클러스터 안에 있는 물리적인 컴퓨터나 가상머신을 말합니다.

 

Pod

pod는 쿠버네티스에서 하나의 배포 단위입니다. 아래 그림은 pod 그림입니다.

하나의 파드 안에는 저장소와 컨테이너가 포함 될 수 있습니다.

pod1은 컨테이너 하나만 담고 있는 경우입니다. 

 

쿠버네티스 홈페이지에서 가져온 그림

사이드카 패턴을 활용한다면 pod 가 2,3,4 의 형태를 띌 수도 있습니다.

사이드카 패턴은 하나의 컨테이너가 배포 될 때 자주 통신하는 다른 컨테이너를 같이 배포하는 방식입니다.

노드와 Pod 의 관계

하나의 노드 안에는 여러 개의 pod 가 포함될 수 있습니다.

Pod 는 쿠버네티스의 가장 기본적인 배포 단위입니다.

Pod는 언제나 노드상에서 동작하고 노드는 Pod(파드)를 동작시키기 위해 필요한 서비스를 포함합니다.

 

크기 순서로 이런 관계가 됩니다.

쿠버네티스 - 노드 - 파드 - 컨테이너

 

쿠버네티스 홈페이지에서 가져온 그림

kubernetes 서비스에 배포하기

시험삼아 쿠버네티스 서비스에 2개의 앱을 배포했습니다.

1개 클러스터에

1개의 노드안에

2개의 웹서비스 파드를 두었습니다.

그리고 두 파드끼리 통신을 해봤습니다.

배포는 AKS 를 활용했습니다.

 

클러스터는 azure portal 에서 만들었습니다.

이 부분은 eks 는 aws console 에서 만들면 됩니다.

클러스터 생성 화면

클러스터를 만들었다면 docker-compose 파일을 통해서 이미지를 만듭니다.

docker file로 만들어도 됩니다.

 

저는 dockerfile을 사용했습니다. 아래 파일같은 도커파일을 만들었습니다.

FROM python:3.7.3
RUN mkdir ./coin
# 도커 이미지 안에 폴더 만들기 
COPY . ./coin
# 현재 경로에 있는거 모두 도커 폴더 안으로 복사
WORKDIR /coin
# 프로젝트 실행 경로를 만든 경로로 바꿈 
RUN pip install -r requirements.txt 
# requirements.txt 파일 읽어서 pip 다운로드

 

docker build ./ --tag <image name>:0.1

 

이미지가 잘 만들어졌습니다.

aks에 배포하려면 컨테이너 레지스트리를 만들고 거기에 이 이미지를 푸시해야합니다.

https://docs.microsoft.com/ko-kr/azure/aks/tutorial-kubernetes-prepare-acr

 

Azure의 Kubernetes 자습서 - 컨테이너 레지스트리 만들기

이 AKS(Azure Kubernetes Service) 자습서에서는 Azure Container Registry 인스턴스를 만들고 애플리케이션 예제 컨테이너 이미지를 업로드합니다.

docs.microsoft.com

문서를 참고해서 이미지를 푸시했습니다.

 

이미지를 푸시한 다음에는 aks 서비스에 로그인 했습니다.

https://docs.microsoft.com/ko-kr/azure/aks/tutorial-kubernetes-deploy-cluster

 

Azure의 Kubernertes 자습서 - 클러스터 배포

이 AKS(Azure Kubernetes Service) 자습서에서는 AKS 클러스터를 만들고 kubectl을 사용하여 Kubernetes 마스터 노드에 연결합니다.

docs.microsoft.com

 

로그인을 했다면 이제 만들어진 클러스터에 이미지를 배포해야 합니다.

 

yaml 파일을 만들고 쿠버네티스에 적용하면 배포가 됩니다.

먼저 coin.yaml 파일을 만들었습니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: azure-vote-back
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: azure-vote-back
    spec:
      nodeSelector:
        "beta.kubernetes.io/os": linux
      containers:
      - name: azure-vote-back
        image: redis
        ports:
        - containerPort: 6379
          name: redis

yaml 파일의 예제는 쿠버네티스 문서에서도 제공하고 있습니다.

https://github.com/kubernetes/examples/blob/master/guestbook/all-in-one/guestbook-all-in-one.yaml

 

kubernetes/examples

Kubernetes application example tutorials. Contribute to kubernetes/examples development by creating an account on GitHub.

github.com

yaml파일 예제와 아래 문서를 참고해서 적절한 yaml 파일 작성하는 방법을 알아보겠습니다.

https://kubernetes.io/ko/docs/concepts/overview/working-with-objects/kubernetes-objects/

 

쿠버네티스 오브젝트 이해하기

 

kubernetes.io

apiVersion: apps/v1 # apps/v1beta2를 사용하는 1.9.0보다 더 이전의 버전용
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # 템플릿에 매칭되는 파드 2개를 구동하는 디플로이먼트임
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

이 파일에 대한 문서상의 설명을 보겠습니다.

먼저 apiVersion 은 쿠버네티스 API 버전입니다.

예제와 동일하게 작성해주면 될 것 같습니다.

kind는 어떤 종류의 오브젝트를 만들지에 대한 내용입니다.

다른 예제 yaml 도 봤을때는 Service와 Deployment가 있는 것 같습니다.

metadata는 이 오브젝트를 구분할 이름이 들어가면 됩니다.

spec은 이 오브젝트가 어떤 상태여야 하는지를 적습니다.

 

한번 샘플로 만든 웹사이트에 대한 yaml파일을 작성해보겠습니다.

 

우선 도커파일은 아래와 같이 작성했습니다.

FROM python:3.7.3
RUN mkdir ./coin
# 도커 이미지 안에 폴더 만들기 
COPY . ./coin
# 현재 경로에 있는거 모두 도커 폴더 안으로 복사
WORKDIR /coin
# 프로젝트 실행 경로를 만든 경로로 바꿈 
RUN pip install -r requirements.txt 
# requirements.txt 파일 읽어서 pip 다운로드
EXPOSE 8000
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

이걸 가지고 이미지를 하나 빌드했습니다.

docker build ./ --tag coin:0.1

이러면 coin 이라는 이름의 이미지가 만들어집니다.

그럼 이제 이걸 쿠버네티스에 배포합니다.

yaml파일은 아래와 같이 작성했습니다.

yaml 파일을 작성할때는 Deployment 와 아래 Service 두개를 작성해야 배포가 됐습니다.

apiVersion을 잘못 작성했을때도 배포가 되지 않으니 참고하시길 바랍니다.

apiVersion: apps/v1beta1 # apps/v1beta2를 사용하는 1.9.0보다 더 이전의 버전용
kind: Deployment
metadata:
  name: coin-app
spec:
  selector:
    matchLabels:
      app: coin-app
  replicas: 2 # 템플릿에 매칭되는 파드 2개를 구동하는 디플로이먼트임
  template:
    metadata:
      labels:
        app: coin-app
    spec:
      containers:
      - name: coin-app
        image: coin:0.1
        command: ["./manage.py", "runserver", "0.0.0.0:8000"]
        ports:
        - containerPort: 8000
---
apiVersion: v1
kind: Service
metadata:
  name: coin-app
spec:
  ports:
  - port: 8000
  selector:
    app: coin-app
---

쿠버네티스에 반영합니다.

kubectl apply -f coin.yaml

서비스는 아래 명령어로 확인 할 수 있습니다.

kubectl get services

이제 이 서비스를 외부로 노출시킵니다.

이건 아래 문서를 참고하면 할 수 있습니다.

 

https://kubernetes.io/ko/docs/tutorials/stateless-application/expose-external-ip-address/

 

외부 IP 주소를 노출하여 클러스터의 애플리케이션에 접속하기

 

kubernetes.io

여기서 3번 디플로이먼트를 외부로 노출시키는 서비스 오브젝트를 생성한다. 이 부분을 보시면 됩니다.

 

그래서 아래 명령어를 입력하고 서비스를 외부에 노출시켰습니다.

kubectl expose deployment coin-app --type=LoadBalancer --name=coin-service

다시 서비스 명령어를 입력하면 ip 주소가 노출됩니다.

kubectl get services

52.139.154.152에 접속해봅니다.

접속이 안됐습니다.

혹시나 해서 이미지를 바꾸고 docker hub에 push 했습니다.

 

public docker hub에 push 하니 ImagePullBackOff 에러가 뜨지 않습니다.

imagepullbackoff

 

get services 로 얻은 주소에 접속하면 잘 접속됩니다.

 

http://20.189.75.203:8080/

바꾼 이미지의 코드와 도커파일은 이렇습니다.

var http = require('http');

var handleRequest = function (request, response) {
    console.log('Received request for URL: ' + request.url);
    let data;
    var azure = require('http');
    var options = {
        hostname: 'http://20.189.78.86/',
        path: ''
    };

    function handleResponse(response) {
        var serverData = '';
        response.on('data', function (chunk) {
            serverData += chunk;
            data = serverData;
        });
        response.on('end', function () {
            console.log("received server data:");
            console.log(serverData);
        });
    }

    azure.request(options, function (response) {
        handleResponse(response);
    }).end();

    response.writeHead(200);
    response.end('Hello World!' + data);
};
var www = http.createServer(handleRequest);
www.listen(8080);

Dockerfile

FROM node:10
EXPOSE 8080
COPY server.js .
CMD node server.js

이제 dockerhub 를 사용해서 이미지를 2개 배포하고 통신하면 되겠습니다.

 

배포 할 때 yaml 파일을 처음에 어떻게 작성해야 하는지 살펴보는데 시간이 좀 걸렸습니다.

kubectl expose --type=LoadBalancer 같은 경우에는 명령어로 작성 할 수도 있지만 yaml 파일에 작성할 수도 있습니다.

---
apiVersion: v1
kind: Service
metadata:
  name: coin-app
spec:
  type: LoadBalancer
  ports:
  - port: 8000
  selector:
    app: coin-app

spec아래 type을 LoadBalancer로 지정하면 됩니다.

이렇게 2개 배포하면 아래 목록처럼 표시 됩니다.

댓글