docker를 사용하면서 그 편리함을 느끼고 있었다. 그리고 요 근래 it회사에서 docker와 kubernets를 이용하여 인프라를 운영을 하는 것을 많이 들었다.

나는 그런 환경을 접해보지는 못했기 때문에 정확하게 kuberntes가 무엇인지 잘 모른다. 그래서 이번 기회에 kubernets(이하 쿠버네티스)에 대한 기본 개념을 정리하고 설치해서 공부를 위한 초석을 닦아보자.

 

쿠버네티스 (kubernetes)

쿠버네티스는 도커 컨테이너 운영을 자동화 하기위한 오케스트레이션 도구이다. 구글에서 만들었으며 컨테이너를 운영하고 다루기 위한 api와 cli등을 제공한다. 컨테이너 배포 이외에도 효율적인 컨테이너 배치 및 스케일링, 로드밸런싱, 헬스 체크, secure등의 기능을 제공한다.

AWS ECS 와 GClound에서 도커 관리 기능을 제공하면서 컨테이너를 사용한 애플리케이션 개발이 점차 보급 되었다.  기존에도 docker에 스웜(swarm)이라는 기능이 있었으나 사용해 봤을 때 불편한 점이 많았는데 쿠버네티스가 더 편리하게 이 점이 보완되었다. 

 

쿠버네티스 설치 (MacOs)

실습을 진행할 컴퓨터가 mac os이기 때문에 mac에서 설치하는 방법을 알아보자. 우선 docker에서 preference에 들어가면 kubernetes 탭이 존재한다. 여기서 아래와 같이 체크하고 Apply를 누르면 설정이 우선 완료된다.

그리고 cli로 쿠버네티스를 다루기 위한 도구인 kubectl을 설치한다.

curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl
chmod +x kubectl
mv kubectl /usr/local/bin

위에 명령어를 통해 kubectl을 명령어로 등록해주는데 자세한 방법은 홈페이지에 잘 나와있다.

https://kubernetes.io/docs/tasks/tools/install-kubectl/

설치가 완료된 후 버전을 확인해보면 출력되면 정상적으로 설치가 된 것 이다.

 

단일 노드 쿠버네티스 클러스터 Minikube 설치

쿠버네티스 클러스터에는 여러 노드들이 존재하지만 실습을 위해서 단일 노드로 되어 있는 Minikube를 설치해서 사용한다. 맥 기준으로 brew로 설치하면 되고 자세한 방법은 아래를 참조하면 된다.

brew cask install minikube

https://kubernetes.io/ko/docs/tasks/tools/install-minikube/

 

쿠버네티스 구성요소

쿠버네티스로 실행되는 애플리케이션은 노드, 네임스페이스, 파드, 레플리카세트, 디플로이먼트 등 다양한 리소스가 함께 연동해 동작한다. 

그 구성 요소들에 대해 간단하게 정리해보자.

1. 노드

-> 노드는 쿠버네티스 클러스터의 관리 대상으로 등록된 도커 호스트로 컨테이너가 배치되는 대상이다. 노드는 마스터와 일반 노드들로 구성되는데 쿠버네티스 클러스터 전체를 관리하는 서버에는 마스터가 적어도 하나 이상 있어야 한다. 마스터는 클러스터를 상호 조정하는 장치이고 노드는 애플리케이션이 실제로 돌아가는 곳이다. 노드에는 여러 파드들이 위치할 수 있고 그 파드에는 컨테이너들이 존재한다.

구글 이미지 출처

또한 쿠버네티스는 노드의 리소스 사용 현황 및 배치 전략을 근거로 컨테이너를 적절하게 배치한다. 클러스터에 배치된 노드 수, 노드의 사양 등에 따라서 노드에 배치할 수 있는 컨테이너의 수를 결정한다. 클러스터의 처리 능력은 노드에 의해서 결정된다.

kubectl get nodes

 

 현재 노드는 아까 설치한 단일 노드 Minikubes가 마스터로 위치해 있는 걸 볼 수 있다.

 

2. 네임스페이스

쿠버네티스 클러스터 내부에는 여러개의 가상 클러스터를 만들 수 있는데 이 네임스페이스는 하나의 공간으로써 사람또는 상황에 따라서 나눠서 사용할 수 있다. 기본적으로는 default로 되어있다.

 

3. 파드 (pod)

 pod는 컨테이너가 모인 집합체로써 하나 이상의 컨테이너로 이루어 진다. nginx, was처럼 서로간의 연결고리가 있는 컨테이너들은 하나로 묶어 일괄배포한다. pod는 노드내에 배치되고 같은 파드는 여러 노드에 배치할 수도 있고 한 노드에 여러개 배치할 수도 있다. pod는 하나 또는 그 이상의 애플리케이션 컨테이너 그룹을 나타내는 쿠버네티스의 추상적 개념으로 컨테이너에 대해 서로 자원을 공유한다.

  • 볼륨과 같은 공유 스토리지
  • 클러스터 IP 주소와 같은 네트워킹
  • 컨테이너 이미지 버전 또는 사용할 특정포트와 같은 각 컨테이너가 동작하는 방식에 대한 정보

 

apiVersion: v1
kind: Pod
metadata:
  name: sample-echo
spec:
  containers:
  - name: nginx
    image: ddd/nginx:latest
    env:
    - name: BACKEND_HOST
      value: localhost:8080
    ports:
    - containerPort: 80
  - name: echo
    image: dd/echo:latest
    ports:
    - containerPort: 8080
    
 # 파드 yaml 예제

 

4. 레플리카 세트

파드를 하나만 사용하여 가동할 경우에 실제 가용성이 떨어지기 때문에 레플리카 세트를 만들어서 여러 파드를 함께 구성해준 것이다.

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: echo
  labels:
    app: echo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: echo
  template: # template하단은 pad.yaml과 같음

 

5. 서비스 (servce, svc)

서비스를 이용해서 각 Pod에 있는 애플리케이션을 외부에서 접근하게 할 수있다.

쿠버네티스에서 서비스는 하나의 논리적인 파드 셋과 그 파드들에 대한 접근할 수 있는 정책을 정의하는 추상적인 개념이다. 서비스는 종속적인 파드들 사이를 느슨하게 결합되도록 도와준다. 서비스는 모든 쿠버네티스 오브젝트들과 같이 yaml로써 정의 할 수있다. 각 서비스가 되는 대상을 labelSelector를 통해 지정할 수 있다.

각 파드들이 고유의 IP를 갖고 있기는 하지만, 그 IP들은 서비스의 도움없이 클러스터의 외부로 노출될 수 없다. 서비스들은 애플리케이션들에 트래픽이 실릴 수 있도록 허용해준다. 서비스들은 ServiceSpec에서 type을 지정함으로써 다양한 방식들로 노출시킬 수 있다.

clusterIp(기본값) - 클러스터 내에서 내부 IP에 대해 서비스를 노출해준다. 이 방식은 오직 클러스터 내에서만 서비스가 접근될 수 있도록 해준다.

NodePort - NAT가 이용되는 클러스터 내에서 각각 선택된 노드들의 동일한 포트에 서비스를 노출시켜준다.
<NodeIP>:<NodePort>를 이용하여 클러스터 외부로부터 서비스가 접근할 수 있도록 해준다. CluserIP의 상위 집합이다.

LoadBalancer - (지원 가능한 경우) 기존 클라우드에서 외부용 로드밸런서를 생성하고 서비스에 고정된 공인 IP를 할당해준다. NodePort의 상위 집합이다.

ExternalName - 이름으로 CNAME 레코드를 반환함으로써 임의의 이름(스펙에서 externalName으로 명시)을 이용하여 서비스를 노출시켜준다. 프록시는 사용되지 않는다. 이 방식은 kube-dns 버전 1.7 이상에서 지원 가능하다.

 

6. 디플로이먼트 (deployment)

서비스, 파드, 레플리카세트의 집합체로써 애플리케이션의 기초가 되는 단위이다. 디플로이먼트 내부에는 서비스, 파드, 레플리카세트 등을 한번에 구성하여 적용 시킬 수 있다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: echo
  labels:
    app: echo
spec:
  replicas: 3
  selector:
    matchLabels
      app: echo
  template: # template는 pod와 동일

 

서비스와 디플로이먼트에 차이는 서비스는 내부에 여러 pod들을 외부와 연결해주는 역할을 담당하고 디플로이먼트는 쿠버네티스에서 돌아가는 pod들의 상태를 확인하면서 재시작 등등을 진행하는 담당을 한다.

다음 시간에는 실제 애플리케이션 하나를 이미지로 빌드하고 그것을 minikube에 디플로이먼트를 통해 파드로 배포를 진행해본다. 그리고 스케일적용과 이미지 변경 시 자동으로 새로 배포되는 블루그린 배포도 적용해보자.

 

참고 싸이트

https://kubernetes.io/ko/docs/tasks/administer-cluster/highly-available-master/
https://kubernetes.io/ko/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/
https://kubernetes.io/ko/docs/concepts/overview/working-with-objects/labels/
https://devopscube.com/kubernetes-deployment-tutorial/

api의 성능 테스트를 위해서 네이버에서 만든 ngrinder 설치하고 테스트를 진행해봤다.


ngrinder는 controller와 agent로 구성이 되어 있는데 이에 대한 내용은 https://naver.github.io/ngrinder/ 해당 내용을 체크하자.


1. Controller 설치
- 톰캣을 설치하고 아래 주소에서 war를 다운받아서 실행시킨다.
https://github.com/naver/ngrinder/releases
단, 3.4.2는 테스트 스크립트 실행 시 unexpected token에러가 발생한다. 그래서 3.4.1을 사용하는걸 추천한다.

설치 완료되면 아래 url로 접근 해서 확인 (초기 계정은 admin/admin)
- 뒤에 root path는 편의를 위해서 war 파일을 ngrinder-controller-3.4.1.war => ngrinder.war로 변경해서 ngrinder로 사용

http://localhost:8080/ngrinder

 

2. Agent 설치
Agent는 테스트에서 필요한 worker process를 실행시켜주고 관리하는 역할을 한다.
- agent를 다운받고 내부에 ./run_agent.sh를 실행시킨다.

- 실행이 완료되면 Agent Management에 들어가면 정상적으로 동작하는걸 확인할 수 있다.

주의사항
먼저 자바 1.9이상의 버전에서는 Agent을 지원을 하지 않는다. 1.9에서 agent 실행 시 다음과 같은 오류가 난다.

1
java.lang.ClassCastException: class jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to class java.net.URLClassLoader (jdk.internal.loader.ClassLoaders$AppClassLoader and java.net.URLClassLoader are in module java.base of loader 'bootstrap')
cs
이는 1.9에서 URLClassLoader를 사용하는 방식이 바뀌었으나 ngrinder agent가 아직 지원하지 못해서 발생하는 오류인거 같다. 1.8을 사용하면 괜찮다.



테스트 진행

각 옵션을 설정하고 테스트를 진행하면 아래와 같이 TPS결과가 나온다. 각 설정 옵션에 대해서는 인터넷이나 메인 git에 가면 자세히 나와있다.


Agent, VUser를 조절해가면서 api의 성능을 tps를 확인하면서 조절해서 테스트하면 된다.



'IT 지식 > ngrinder' 카테고리의 다른 글

ngrinder Mac os 간단 설치 및 테스트 방법  (0) 2019.03.11

synology에서 docker나 redis 등을 패키지 센터에서 설치하여 사용할 수 있다.


하지만 이상하게 저렴하게 나온 NAS, 그 중에서 x86 cpu를 사용하는 경우에는 패키지 센터에서 직접 redis를 설치할 수가 없다 ㅜㅜ


그래서 방법을 찾았다. 그 방법을 까먹지 않기 위해서 정리해보자.


1. DSM에서 SSH 허용

이 부분은 아주 간단하게 DSM > 설정 > 네트워크에서 SSH 허용하여 접속을 킬 수 있다. 보안상 포트는 22가 아닌 다른 번호로 바꾸고 방화벽을 설정하는 것을 추천한다. 자세한건 검색하면 엄청 나오고 간단하다.


2. redis 다운로드

redis 설치하여 운용하기 위해서 공식홈페이지에서 다운로드한다. 그리고 SFTP나 FTP 또는 단순하게 DSM에 드래그 해서 파일을 NAS에 옮겨준다. (wget으로 직접 콘솔로 받아도 무관)

https://redis.io/


3. redis 컴파일

다운 받은 redis 설치은 tar로 압축되어있다. 압축된 파일을 "tar xvfz 파일명"으로 해제한다. 그리고 이를 컴파일 해야하는데 make 명령어를 쳐도 먹질 않는다 ㅜㅜ make command not found가 발생한다 ㅜㅜ 이를 해결하기 위해서 ipkg를 설치해야 한다.


4. ipkg 설치

ipkg 설치를 위해서 패키지 센터에 설정에 들어가서 패키지 소스를 누르고 해당 주소를 추가한다.

https://www.cphub.net/

그리고 Easy Bootstrap Installer를 설치하고 ipkg gui를 설치한다. ipkg gui는 설치된 유틸리티를 유아이로 자세히 보기 위해서 사용된다. 굳이 필요없으면 안 깔아도 되고 깔게 될 경우 perl이 필요하다.



5. 필요한 명령 유틸리티 설치

1
2
3
4
/opt/bin/ipkg install autoconf
/opt/bin/ipkg install make
/opt/bin/ipkg install gcc
cs

redis 설치에 필요한 몇 개의 유틸리티를 설치한다. 


6. redis 컴파일 및 설치

다시 압축을 해제한 폴더 내부로 이동하여 make 명령어를 쳐서 컴파일을 수행한다.

컴파일이 완료되면 sudo make install 명령어를 통해 설치를 진행한다.


7. 실행

설치가 완료되면 redis-server 명령어를 입력하여 실행한다. background에서 실행시키기 위해서 &를 함께 사용한다. 실행이 되면 redis-cli를 쳐서 정상적으로 동작하는지 확인해보자.


NAS를 사용해서 개인적으로 서버를 가지고 놀아보는것도 좋다. 

기존에는 aws로 자주 놀았지만 아무래도 비용도 비싸고 실수로 비용청구가 될 가능성이 많으니 nas로 잘 놀아보자.

  1. Favicon of https://wedul.site BlogIcon 위들 wedul 2019.02.24 01:02 신고

    https://xpenology.com/forum/topic/4320-공유-각종-유틸리티-사용을-위한-ipkg-설치-과정

  2. Favicon of https://wedul.site BlogIcon 위들 wedul 2019.02.25 08:29 신고

    export PATH=/opt/sbin:/opt/bin:$PATH

  3. Favicon of https://wedul.site BlogIcon 위들 wedul 2019.02.25 08:42 신고

    https://dzone.com/articles/building-redis-from-source-on-ubuntu-server-1804

  4. 손상진 2019.07.25 00:47

    글 도움 많이 받았습니다
    저같은 경우는 컴파일시에 libfl.so 파일을 못찾아서.. 추가적으로
    /opt/bin/ipkg install flex
    를 해서 해당 라이브러리를 설치하고 진행하니 잘 되더라고요~!

Elasticsearch에서 인덱스를 만들고 타입을 지정하여 데이터를 삽입하는 과정을 정리해보자. elasticsearch는 Restful API가 지원되기 때문에 BSL 쿼리를 이용하여 쉽게 데이터를 조작할 수 있다.


인덱스 생성

Methd : put
URLI : /{indexname}?pretty


생성된 인덱스 확인

Method : GET
URI : _cat/indices?v
kibana dev-tool에서 customer 인덱스가 생성된 것을 확인할 수 있다.


타입, Document 생성 및 데이터 추가

Method : PUT
URI : /{indexname}/{typename}/[documentid]?pretty
만약 documentid를 넣지 않으면 랜덤으로 만들어서 삽입된다.


입력된 데이터 확인
Method : GET
URI : /{indexname}/{typename}/{documentid}

데이터를 조회해보면 _source에 삽입한 데이터가 들어가 있는것을 확인할 수 있다


색인 삭제

Method : DELETE
URI : /{indexname}?pretty

데이터 삭제

Method : DELETE
URI : /{indexname}/{typename}/{documentid}?prettry

데이터 수정

Method : POST
URI : /{indexname}/{typename}/{documentid}/_update?pretty

변경된 내용 확인

Bulk update

Method : POST
URI : /{indexname}/{typename}/_bulk?pretty
여러가지 쿼리를 한번에 수행할 수 있다.

수행 결과

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
{
  "took"16,
  "errors"false,
  "items": [
    {
      "index": {
        "_index""customer",
        "_type""wedul",
        "_id""2",
        "_version"1,
        "result""created",
        "_shards": {
          "total"2,
          "successful"1,
          "failed"0
        },
        "_seq_no"0,
        "_primary_term"1,
        "status"201
      }
    },
    {
      "index": {
        "_index""customer",
        "_type""wedul",
        "_id""3",
        "_version"1,
        "result""created",
        "_shards": {
          "total"2,
          "successful"1,
          "failed"0
        },
        "_seq_no"0,
        "_primary_term"1,
        "status"201
      }
    },
    {
      "update": {
        "_index""customer",
        "_type""wedul",
        "_id""1",
        "_version"3,
        "result""updated",
        "_shards": {
          "total"2,
          "successful"1,
          "failed"0
        },
        "_seq_no"4,
        "_primary_term"1,
        "status"200
      }
    },
    {
      "delete": {
        "_index""customer",
        "_type""wedul",
        "_id""2",
        "_version"2,
        "result""deleted",
        "_shards": {
          "total"2,
          "successful"1,
          "failed"0
        },
        "_seq_no"1,
        "_primary_term"1,
        "status"200
      }
    }
  ]
}
cs

검색 API

기본적으로 검색 실행방법은 REST 요청 URI 통해 검색 매개변수를 보내는 방법과 REST 요청 본문을 통해 보내는 방식이있다. (REST 요청 본문으로 보내는 것은 위에서 확인 하였음.) 이 두가지 방식 중에 요청 본문 방식을 이용하는것이  효율적이다. 왜냐하면 URI를 조작해서 검색을 하는 것 보다 본문에 내용을 조작해서 수행하는 것이 더 유연하게 수정할 수 있다.

주소로 요청하기 위해서는 _search 엔드포인트를 사용해서 엑세스 해야한다.

그럼 먼저 주소 요청을 진행해보자.



URI 요청을 통한 검색

Method : GET
URI : /customer/_search?q=*&sort=age:desc&pretty
q=*  : Elasticssearch에게 색인의 모든 문서를 비교하여 일치 여부를 확인 하라고 표시.
sort={fieldname}:order_type(desc | asc) : 정렬을 사용할 필드와 정렬방식을 지정


결과
- took : Elasticsearch 검색하는데 걸린시간
- timed_out : 검색 시간 초과 여부
- _shards : 검색한 샤드   검색에 성공/실패한 샤드 
- hits: 검색 결과 (Array 순서대로 검색결과가 출력)
- hits > total :  검색 결과
- hits > hits : 검색 결과의 실제 배열
- hits > sort : 결과의 정렬 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 2,
    "max_score": null,
    "hits": [
      {
        "_index": "customer",
        "_type": "wedul",
        "_id": "3",
        "_score": null,
        "_source": {
          "name": "kskim",
          "age": 35,
          "add": "Gwang ju"
        },
        "sort": [
          35
        ]
      },
      {
        "_index": "customer",
        "_type": "wedul",
        "_id": "1",
        "_score": null,
        "_source": {
          "name": "wedul babo",
          "age": 28,
          "addr": "seoul"
        },
        "sort": [
          28
        ]
      }
    ]
  }
}
cs


#본문 요청 검색

Method : GET
URI : /{indexname}/_search_pretty
나머지 조건은 body에 삽입

1
2
3
4
5
6
7
GET /customer/_search?pretty
{
  "query": { "match_all": {} },
  "sort": [
    { "age": "desc" }
  ]
}
cs


다음번에는 더 자세한 검색 조건을 수행해보자.

맥에서는 docker 설치와 운용이 쉬웠는데, 맥북이 망가지고 윈도우 컴퓨터를 사용하고 있으니 Docker 사용이 생각보다 쉽지 않았다.

그래서 저번에 Windows Subsystem for linux (ubuntu)를 설치하고 여기에 docker를 올려보면 어떨까 싶어서 도전해 보았다. 

우선 docker engine는 WSL에서 실행되지 않아서 호스트 컴퓨터에 Windows용 Docker를 설치해야한다. 그리고 나서 Linux(ubuntu)에서 실행되는 Docker 클라이언트(WSL)가  Windows에 설치된 Docker Engine 데몬으로 명령어를 보내서 운용할 수 있다.

우선 Ubuntu에 Docker를 설치해보자.

1. 우선 패키지를 업데이트 한다.

1
sudo apt-get update
cs


2. 그리고 apt에서 https를 통해 저장소를 사용할 수 있도록 패키지들을 설치한다.

1
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
cs


3. Docker의 공식 GPG키를 추가한다.

1
2
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add 
$ sudo apt-key fingerprint 0EBFCD88
cs


4. Docker를 설치한다.

1
2
$ sudo apt-get update
$ sudo apt-get install docker-ce
cs

이렇게 하면 Linux에 설치가 완료되나 Docker Engine은 WSL에서 실행되지 않으므로 윈도우와 연결해야한다.

먼저 Docker 호스트가 있는 Docker 클라이언트에게 알려주어야 하므로 다음 명령어를 사용한다.

1
2
3
4
5
$ 도커 -H localhost : 2375 이미지
 
// 매번 하기 귀찮으면 환경변수에 등록
$ export DOCKER_HOST = localhost : 2375
$ echo "export DOCKER_HOST = localhost : 2375">> ~ / .bash_profile
cs


그리고 Windows에서 데몬을 공개해주어야 정상적으로 동작한다.


이미지를 다운받아보고 docker 명령어를 사용해보면 정상적으로 연결이 되는 것을 확인할 수 있다.



https://medium.com/@sebagomez/installing-the-docker-client-on-ubuntus-windows-subsystem-for-linux-612b392a44c4

+ Recent posts