Kubernetes 개요 및 애플리케이션 배포


  • 2019 클라우드 스터디 잼 입문반에서 진행하는 Kubernetes in the Google Cloud 퀵랩을 듣고 정리한 내용입니다

Introduction to docker

  • Dokcer를 사용하면 인프라에서 어플리케이션을 분리하고 인프라를 managed 어플리케이션처럼 사용할 수 있음
  • Docker는 코드를 신속하게 제공하고 테스트, 배포 속도를 높이고 코드 작성과 실행 사이의 주기를 단축해줌
  • Dokcer 컨테이너는 쿠버네티스에서 쉽게 사용할 수 있음
  • Docker의 핵심을 배우며 쿠버네티스 및 컨테이너 응용 프로그램을 개발할 수 있음

Hello World

  • hello-world docker run!

      docker run hello-world
    
  • docker 이미지 출력

      docker images
    
  • docker running 컨테이너 보기

      docker ps
      >>> 처음엔 아무것도 뜨지 않음
    
  • 모든 docker 이미지를 보려면 -a 추가

      docker ps -a
    
  • docker run –name [container-name] hello-world

    • container 이름을 앞의 글자 3개만 사용해도 됨!

Build

  • test 폴더 생성

      mkdir test && cd test
    
  • Dockerfile 생성
      cat > Dockerfile <<EOF
      # Use an official Node runtime as the parent image
      FROM node:6 # 이미지 지정
      # Set the working directory in the container to /app
      WORKDIR /app # 컨테이너 작업 디렉토리 설정
      # Copy the current directory contents into the container at /app
      ADD . /app # 현재 디렉토리 내용을 컨테이너에 추가
      # Make the container's port 80 available to the outside world
      EXPOSE 80 # 80 포트를 연결을 허용
      # Run app.js using node when the container launches
      CMD ["node", "app.js"] # node 명령을 실행해 프로그램 시작
      EOF
    
  • app.js 생성

      cat > app.js <<EOF
      const http = require('http');
    	
      const hostname = '0.0.0.0';
      const port = 80;
    	
      const server = http.createServer((req, res) => {
          res.statusCode = 200;
            res.setHeader('Content-Type', 'text/plain');
              res.end('Hello World\n');
      });
    	
      server.listen(port, hostname, () => {
          console.log('Server running at http://%s:%s/', hostname, port);
      });
    	
      process.on('SIGINT', function() {
          console.log('Caught interrupt signal and will exit');
          process.exit();
      });
      EOF
    
  • build

      docker build -t node-app:0.1 .
      # Dockerfile이 있는 디렉토리에서 명령어 실행
      # -t는 이미지에 태그, name:tag 
    
  • docker images 확인

Run

  • Run

      docker run -p 4000:80 --name my-app node-app:0.1
    
  • 다른 터미널에서 아래 명령어 입력

      curl http://localhost:4000
      >>> Hello World
    
  • docker stop and remove

      docker stop my-app && docker rm my-app
    
  • 다시 run

      docker run -p 4000:80 --name my-app -d node-app:0.1
      docker ps
    
  • docker logs

      docker logs [container_id]
    
  • 호스트의 8080 포트를 컨테이너의 80포트로 연결

      docker run -p 8080:80 --name my-app-2 -d node-app:0.2
      docker ps
    

Debug

  • 작동중 container 로그 출력

      docker logs -f [container_id]
    
  • Interactive Bash session을 시작해 container로 진입

      docker exec -it [container_id] bash
    
  • inspect

    • metadata 검사
      docker inspect [container_id]
    
    • --format을 사용하면 특정 필드를 json타입으로 리턴
      docker inspect --format='' [container_id]
    

Publish

  • 자신의 이미지를 Google Container Registry에 push!
  • gcr이 호스팅하는 비공개 레지스트리에 이미지를 푸시
    • 형식 : [hostname]/[project-id]/[image]:[tag]
  • Project ID 확인

      gcloud config list project
    
  • docker tag

      docker tag node-app:0.2 gcr.io/[project-id]/node-app:0.2
    
  • push

      gcloud docker -- push gcr.io/[project-id]/node-app:0.2
    
  • 모든 컨테이너 stop and remove

      docker stop $(docker ps -q)
      docker rm $(docker ps -aq)
    
  • 컨테이너 이미지 삭제

      docker rmi node-app:0.2 gcr.io/[project-id]/node-app node-app:0.1
      docker rmi node:6
      docker rmi $(docker images -aq) # remove remaining images
      docker images
    
  • gcloud docker pull

      gcloud docker -- pull gcr.io/[project-id]/node-app:0.2
    	
    

Hello Node Kubernetes

  • 쿠버네티스
    • Notebook, 멀티노드 클러스터, 클라우드에서 내부 배포할 수 있고 다양한 환경에서 실행할 수 있는 오픈소스
    • Kubernetes Engine(Google의 Managed Service)를 사용해 인프라 설정보다 쿠버네티스를 경험하는 것에 집중
    • kubectl document
  • Node.js 애플리케이션 만들기
    • 쿠버네티스 엔진에 배포할 애플리케이션 작성
    • server.js
      var http = require('http');
      var handleRequest = function(request, response) {
        response.writeHead(200);
        response.end("Hello World!");
      }
      var www = http.createServer(handleRequest);
      www.listen(8080);
    
    • node server.js
  • 이걸 docker 컨테이너로 패키징
    • vi Dockerfile
      FROM node:6.9.2 # docker 허브의 node 이미지로 시작
      EXPOSE 8080 # 포트 8080 노출
      COPY server.js . # 사용자가 만든 server.js를 이미지로 복사
      CMD node server.js # node 서버 시작
    
    • 이미지 빌드
      docker build -t gcr.io/PROJECT_ID/hello-node:v1 .
    
    • Docker 컨테이너 이미지에서 포트 8080로 데몬 실행
      docker run -d -p 8080:8080 gcr.io/PROJECT_ID/hello-node:v1
    
    • Docker 컨테이너 중지
      • docker ps에 나오는 컨테이너 중지
    • Google Container Registry로 이미지 Push
      • Container Registry는 Google Cloud 프로젝트에서 액세스 가능
        gcloud docker -- push gcr.io/PROJECT_ID/hello-node:v1
      
      • 이제 쿠버네티스가 접근할 수 있는 도커 이미지 만들어짐
  • 클러스터 만들기
    • Container Engine 클러스터 생성
    • 하나의 클러스터는 쿠버네티스 마스터 API 서버와 노드로 구성, 노드는 Computer Engine 가상 머신
    • Kubernetes Engine에 접속
      gcloud container clusters create hello-world \
                  --num-nodes 2 \
                  --machine-type n1-standard-1 \
                  --zone us-central1-f
    
  • 포드 만들기
    • 포드는 관리 및 네트워킹 용도로 서로 연결된 컨테이너 그룹
    • 포드는 하나 또는 여러 개의 컨테이너를 포함할 수 있음
      kubectl run hello-node \
      --image=gcr.io/PROJECT_ID/hello-node:v1 \
      --port=8080
    
    • deployment “hello-node” created란 문구가 나오면 배포 개체를 만든 것!
    • 포드를 만들고 확장할 땐 배포를 사용하는게 좋음
    • 배포 확인(마치 docker ps 같음)

        kubectl get deployments
      
    • 배포 만들어진 포드 확인

        kubectl get pods
      
    • 클러스터 정보 확인

        kubectl cluster-info
      
    • 클러스터 config 확인

        kubectl config view
      
    • pod 로그 확인

        kubectl get events
        kubectl logs <pod name>
      

외부 트래픽 허용

  • Pod는 클러스터에 포함된 내부 IP로만 액세스 가능
    • 가상 네트워크 외부에서 컨테이너에 액세스 하려면 포드를 쿠버네티스 서비스로 노출시켜야 함
    • kubectl expose 명령에 –type=”LoadBalancer” 플래그를 사용!

        kubectl expose deployment hello-node --type="LoadBalancer"
      
    • 직접 노출시키는 것이 아닌 배포를 노출시킴!!!!
    • 서비스가 이 배포에서 관리하는 모든 포드에 걸쳐 트래픽의 부하를 분산
  • IP 주소 확인
    • 외부 부하 분산 IP 1개 보임
      kubectl get services
    

서비스 규모 확장하기

  • 쿠버네티스의 강력한 기능은 애플리케이션을 간편하게 확장할 수 있는 것
    • 갑자기 용량이 필요해졌을 경우 복제 컨트롤러에 새로운 복제를 관리하라고 명령할 수 있음

        kubectl scale deployment hello-node --replicas=4
      
    • 배포에 관한 설명 확인

        kubectl get deployment
        kubectl get pods
      

서비스의 업그레이드 롤아웃

  • 배포한 애플리케이션에 버그 수정이나 추가 기능을 적용해야 할 경우
    • server.js 하단에 response.end(“Hello Kubernetes World!”); 추가
    • 빌드 및 push

        docker build -t gcr.io/PROJECT_ID/hello-node:v2 . 
        gcloud docker -- push gcr.io/PROJECT_ID/hello-node:v2
      
    • 실행 중인 컨테이너의 이미지 라벨을 기존 hello-node-deployment를 수정해야 함
      • gcr.io/PROJECT_ID/hello-node:v1 => gcr.io/PROJECT_ID/hello-node:v2
      • 이를 위해 kubectl edit 명령 사용
      • kubectl edit deployment hello-node
      • containers의 image를 수정
    • 새로운 이미지 배포

        kubectl get deployments
      

그래픽 대시보드

  • kubernetes 클러스터 대시보드에 액세스 하려면 아래 명령어 실행

      gcloud container clusters get-credentials hello-world \
      --zone us-central1-f --project <PROJECT_ID>
      kubectl proxy --port 8081
    
  • URL에서 ?authuser=0을 삭제하고 끝이 /ui를 붙임

    • 근데 대시보드 안나오는데요..?

Kubernetes를 통한 클라우드 조정

  • kubectl을 사용해 Docker 컨테이너를 배포하고 관리
  • 하나의 애플리케이션을 마이크로 서비스로 나눔
  • 영역 설정

      gcloud config set compute/zone us-central1-b
    
  • 클러스터 설정(시간이 좀 소요됨)

      gcloud container clusters create io
    
  • 코드 clone

      git clone https://github.com/googlecodelabs/orchestrate-with-kubernetes.git
      cd orchestrate-with-kubernetes/kubernetes
    

쿠버네티스 데모

  • Kubernetes 시작하는 가장 쉬운 방법 : kubectl run
  • ngninx 컨테이너 인스턴스 실행

      kubectl run nginx --image=nginx:1.10.0
    
  • 실행 중인 nginx 컨테이너 보기

      kubectl get pods
    
  • Kubernetes 외부로 노출
    • 공개 IP 주소로 도달한 클라이언트는 서비스 뒤에 있는 포드로 라우팅
      kubectl expose deployment nginx --port 80 --type LoadBalancer
    
  • 서비스 나열

      kubectl get services
    
  • curl http://:80 로 확인

Pod

  • 쿠버네티스의 핵심 요소
    • 하나 이상의 컨테이너가 포함된 집합
    • 종속도가 높은 여러 컨테이너가 있을 경우 컨테이너들은 단일 포드로 패키징
  • 볼륨
    • 포드가 활성화되어 있어야 사용 가능한 데이터 디스크
    • 포드는 컨텐츠에 대한 공유 네임스페이스를 제공
    • 예제 포드에 속한 두 컨테이너가 서로 통신할 수 있으며 연결된 볼륨도 공유함
  • 포드는 네트워크 네임스페이스도 공유
    • 포드마다 IP 주소 하나씩 존재

포드 만들기

pods/monolith.yaml
  • 구성 파일 출력

      apiVersion: v1
      kind: Pod
      metadata:
        name: monolith
        labels:
          app: monolith
      spec:
        containers:
          - name: monolith
            image: kelseyhightower/monolith:1.0.0
            args:
              - "-http=0.0.0.0:80"
              - "-health=0.0.0.0:81"
              - "-secret=secret"
            ports:
              - name: http
                containerPort: 80
              - name: health
                containerPort: 81
            resources:
              limits:
                cpu: 0.2
                memory: "10Mi"
    
    • 포드는 하나의 컨테이너로 구성
    • 시작할 때 몇 개의 인수를 컨테이너에 전달
    • http 트래픽을 위해 포트 80을 개방
  • kubectl을 사용해 모놀리식 포드 생성

      kubectl create -f pods/monolith.yaml
    
  • kubectl get pods를 사용해 포드 나열
  • 모놀리식 포드 정보 요약

      kubectl describe pods monolith
    

포드 상호 작용

  • 포드는 기본적으로 비공개 IP 주소가 할당되고 클러스터 외부에 도달할 수 없음
  • kubectl port-forward 명령을 사용해 로컬 포트를 모놀리식 포드의 포트로 매핑
  • (새 터미널에서) 포트 전달

      kubectl port-forward monolith 10080:80
    
  • 통신 확인

      curl http://127.0.0.1:10080
    
  • 로그인

      curl -u user http://127.0.0.1:10080/login
    
    • 비밀번호 : password를 입력하면 토큰이 생성됨! 복사해서 사용
      TOKEN=$(curl http://127.0.0.1:10080/login -u user|jq -r '.token')
    
  • 안전한 엔드포인트 도달

      curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:10080/secure
    
  • 모놀리식 포드 로그 조회

      kubectl logs monolith
    
  • 새 터미널을 열고 실시간 로그 스트림 받기

      kubectl logs -f monolith
    
  • 쿠버네티스 포드의 대화형 셸 실행하기

      kubectl exec monolith --stdin --tty -c monolith /bin/sh
    

서비스

  • 서비스 문서
  • 포드는 영구적인 것이 아님
    • 활성 여부나 준비 확인의 실패 등 여러 이유로 중단되거나 시작될 수 있음
  • 포드 집합과 통신하려고 하면?
    • 다시 시작될 때는 다른 IP 주소가 할당될 수도 있는데, 이 떄 서비스를 사용함
  • 서비스는 포드를 위한 안정적인 엔드포인트를 제공함
  • 서비스는 라벨을 사용해 서비스가 수행될 포드를 판단
    • 포드에 올바른 라벨이 있으면 서비스에서 자동으로 포드를 선택해 노출
  • 서비스가 포드 집합에 제공하는 액세스 수준은 서비스 유형에 따라 다름
    • ClusterIP(내부) : 클러스터 내부에서만 볼 수 있음
    • NodePort : 클러스터의 각 노드에 외부 액세스가 가능한 IP 제공
    • LoadBalancer

서비스 만들기

  • 서비스를 만들기 전에 https 트래픽을 처리할 수 있는 안전한 포드 생성

      cd ~/orchestrate-with-kubernetes/kubernetes
      cat pods/secure-monolith.yaml
    
      kubectl create secret generic tls-certs --from-file tls/
      kubectl create configmap nginx-proxy-conf --from-file nginx/proxy.conf
      kubectl create -f pods/secure-monolith.yaml
    
  • 서비스 구성 파일 탐색

      cat services/monolith.yaml
    
      kind: Service
      apiVersion: v1
      metadata:
        name: "monolith"
      spec:
        selector: # 포드를 자동으로 찾아 노출
          app: "monolith"
          secure: "enabled"
        ports:
          - protocol: "TCP"
            port: 443
            targetPort: 443
            nodePort: 31000 # 31000에서 443로 외부 트래픽 전송
        type: NodePort
    
  • 모놀리식 서비스 생성

      kubectl create -f services/monolith.yaml
    
  • service “monolith” created라는 출력은 포트를 사용해 서비스를 노출하고 있다는 의미
  • 노출된 포트에서 트래픽 허용

      gcloud compute firewall-rules create allow-monolith-nodeport \
    --allow=tcp:31000
    
  • curl

      curl -k https://<EXTERNAL_IP>:31000
    
    • 시간이 초과됨

포드에 라벨 추가

  • 현재 위 모놀리식 서비스에는 엔드포인트가 없음
  • kubectl get pods 명령과 라벨 쿼리를 사용해 문제를 해결할 수 있음

      kubectl get pods -l "app=monolith"
    
  • secure=enabled 추가

      kubectl get pods -l "app=monolith,secure=enabled"
    
  • 누락된 secure=enabled 라벨을 포드에 추가

      kubectl label pods secure-monolith 'secure=enabled'
      kubectl get pods secure-monolith --show-labels
    
  • 모놀리식 서비스의 엔드포인트 조회

      kubectl describe services monolith | grep Endpoints
    
  • 이제 접근 가능

      curl -k https://<EXTERNAL_IP>:31000
    

Kubernetes를 사용한 애플리케이션 배포

  • 프러덕션 단계에서 컨테이너를 확장하고 관리하는 방법에 대해 배움
  • 실행 중인 포드의 수가 사용자가 지정한 포드 개수와 일치하도록 보장
  • 앱의 세 부분
    • 1) 인증 : 인증된 사용자의 JWT 토큰 생성
    • 2) 환영 : 인증된 사용자에게 인사
    • 3) 프론트엔드 : 인증 및 환영 서비스로 트래픽 라우팅
  • 서비스마다 배포를 하나씩 생성
    • 내부 서비스와 프론트엔드 배포의 외부 서비스를 정의할 예정
    • 완료되면 모놀리식 앱에서처럼 마이크로 서비스와 상호 작용할 수 있음
    • 각 부분의 독립적 확장 및 배포가 가능해짐
  • 배포 객체 생성

      kubectl create -f deployments/auth.yaml
    
  • 인증 배포 서비스 생성

      kubectl create -f services/auth.yaml
    
  • 환영 배포를 만들고 노출

      kubectl create -f deployments/hello.yaml
      kubectl create -f services/hello.yaml
    
  • 프론트엔드 배포 및 노출

      kubectl create configmap nginx-frontend-conf --from-file=nginx/frontend.conf
      kubectl create -f deployments/frontend.yaml
      kubectl create -f services/frontend.yaml
    
  • 외부 IP 확인 후 curl

      kubectl get services frontend
      curl -k https://<EXTERNAL-IP>
    

정리

  • 리소스 정리

      cat cleanup.sh
      chmod +x cleanup.sh
      ./cleanup.sh
    	
      gcloud container clusters delete io --zone 
    

Reference


카일스쿨 유튜브 채널을 만들었습니다. 데이터 사이언스, 성장, 리더십, BigQuery 등을 이야기할 예정이니, 관심 있으시면 구독 부탁드립니다 :)

PM을 위한 데이터 리터러시 강의를 만들었습니다. 문제 정의, 지표, 실험 설계, 문화 만들기, 로그 설계, 회고 등을 담은 강의입니다

이 글이 도움이 되셨거나 다양한 의견이 있다면 댓글 부탁드립니다 :)

Buy me a coffeeBuy me a coffee





© 2017. by Seongyun Byeon

Powered by zzsza