Last Updated on 10월 5, 2021 by Jade(정현호)
안녕하세요
이번 포스팅에서는 쿠버네티스(kubernetes) 에 대한 기본 용어 및 개념, 컴포넌트 , 클러스터 구성 등에 대해서 확인 해보도록 하겠습니다.
해당 글은 아래 포스팅에서 이어지는 글 입니다.
쿠버네티스란 무엇인가요?
쿠버네티스는 구글(Google)이 만들었고, 구글은 예전부터 컨테이너를 아주 많이 사용을 하였고, 지금도 아주 많이 사용을 하고 있는 회사 중에 하나 입니다.
일례로 대표적인 서비스인 유튜브에서도 아주 많은 컨테이너를 사용을 하는 것으로 알려져 있습니다
이러한 컨테이너를 구글은 일주일에 수십억개의 컨테이너를 생성, 배포를 하고 있었으며 많은 수의 컨테이너와 컨테이너가 동작하는 서버들을 관리하기 위한 솔루션 또는 툴이 필요 하였고 그런 관리 및 배포시스템인 컨테이너 오케스트레이션을 만든 것이 쿠버네티스 입니다.
쿠버네티스 와 도커에 대한 더 자세한 기본 내용은 아래 포스팅을 참조하시면 됩니다.
기본 용어
쿠버네티스에서 주로 사용되는 기본 용어에 대해서 확인 해보도록 하겠습니다.
클러스터
하나의 그룹, 또는 묶음의 단위이고 현재 포스팅에서 구성은 3대로, 마스터 1대, Worker(워커) 노드 2대로 구성된 클러스터로 진행하고 있습니다.
마스터(Master)
컨트롤 플레인(Control Plane) 이라고도 불리며, 노드를 제어하고 전체 클러스터를 관리해주는 컨트롤러 입니다. 전체적인 제어/관리를 하기 위한 관리 서버 입니다.
많은 worker 노드가 있더라도 마스터가 문제가 발생된다면 쿠버네티스에 문제가 발생됩니다.
워커노드는 1개에 문제가 생겨도 다른 워커노드가 대신할 수 있지만 마스터가 문제가 생기면 많은 워커 노드 더라도 문제가 될 수 밖에 없습니다.
마스터도 여러개로 구성하여 고가용성 형태로 구성이 가능 합니다 다만 여러개로 구성하더라도 Active-Standby 또는 Active-Backup 형태라서 실제로 관리는 1개의 마스터가 사용 됩니다.
해당 마스터가 문제가 생기면 고가용성에서 예비노드에서 관리 및 제어는 관리 할 수 있습니다.
마스터는 제어의 역할이 주이기 때문에 워커노드를 관리하고 제어하며, 파드의 관리 및 배치, 장애 처리 등의 역할을 하게 됩니다.
워커(Worker)
마스터의 명령을 전달받아서 컨테이너인 파드(pod) 가 실제적으로 실행되는 서버를 의미 합니다.
노드는 쿠버네티스에 있어서 워커 머신이며 클러스터에 따라 VM 또는 물리 머신이 될 수 있습니다. 여러 개의 파드는 하나의 노드 위에서 동작할 수 있습니다.
[노드 개요]
파드는 언제나 노드 상에서 동작을 하게 되며 마스터에서는 배치 되지 않습니다. 그리고 각 노드는 컨트롤 플레인(마스터 또는 마스터)에 의해 관리 됩니다.
워커노드는 파드의 실제 실행 과 중지 , 안정적인 유지 등의 역할을 하게 됩니다
파드(pod)
단일 워커노드에 배포된 하나 이상의 컨테이너 그룹 또는 컨테이너의 집합을 의미 하며, 파드라는 단위로 여러개의 컨테이너를 묶어서 파드 단위로 관리 할 수 있게 해줍니다.
[파드 개요]
파드에 여러개의 컨테이너가 구성된다면 컨테이너들은 같은 파드 IP를 가지게 되고 각각의 포트번호를 통해서 엑세스 하게 됩니다.
보통은 파드1개 당 컨테이너 1개 를 사용 및 운용 하는 것이 일반적이긴 합니다.
좀더 효율적인 것이 파드에 문제가 생겼을 경우 해당 파드에 해당 하는 컨테이너 1개만 영향을 받기 때문에 입니다.
컴포넌트
무엇으로 구성 되어있는지에 대한 정보로, 구성 요소를 컴포넌트 라고 합니다.
구성 요소인 컴포넌트는 마스터 와 노드(워커노드) 별로 있습니다.
마스터의 컴포넌트
마스터는 kube-scheduler, kube-api ,kube-controller-manager, etcd 가 주요 구성 요소 입니다.
컴포넌트를 확인 하는 방법으로는 먼저 노드에서 ps 로 조회 할 수 있습니다. 아래는 마스터에서 ps 로 조회한 결과 입니다.
/home/devops:$ ps -e | grep kube 987 ? 00:36:22 kubelet 2710 ? 00:03:37 kube-scheduler 2712 ? 00:28:36 kube-controller 3133 ? 01:14:01 kube-apiserver 3614 ? 00:00:11 kube-proxy 4373 ? 00:00:04 kube-utils
그런데 위에서 주요 구성 요소로 언급한 etcd 는 ps 명령어로 확인 되지 않고, ps 명령어로 보이지 않는 구성 요소는 컨테이너로 동작하고 있습니다.
컨테이너로 동작하는 컴포넌트는 도커를 통해서 조회 할 수 있습니다
(현재 포스팅에서의 컨테이너는 도커를 사용 중)
/home/devops:$ docker ps CONTAINER ID IMAGE COMMAND NAMES 08e1d05b7dc6 296a6d5035e2 "/coredns -conf /etc…" k8s_coredns_coredns-558bd4d5db-lxkxt_kube-system_68008138-89f3-4607-985b-34e1d99fd740_2 db9bfa3e45f5 296a6d5035e2 "/coredns -conf /etc…" k8s_coredns_coredns-558bd4d5db-xldsf_kube-system_24a3fda8-21ab-4188-9336-ac6f04a4648c_2 e0e59db99e0c k8s.gcr.io/pause:3.4.1 "/pause" k8s_POD_coredns-558bd4d5db-xldsf_kube-system_24a3fda8-21ab-4188-9336-ac6f04a4648c_2 0ecd92fc429c k8s.gcr.io/pause:3.4.1 "/pause" k8s_POD_coredns-558bd4d5db-lxkxt_kube-system_68008138-89f3-4607-985b-34e1d99fd740_2 a1da382e7622 7f92d556d4ff "/usr/bin/launch.sh" k8s_weave-npc_weave-net-s9w4h_kube-system_a15385c7-9884-4b3a-93cb-2a15f4bbf061_4 41c5f958e978 df29c0a4002c "/home/weave/launch.…" k8s_weave_weave-net-s9w4h_kube-system_a15385c7-9884-4b3a-93cb-2a15f4bbf061_4 fe99df537499 425ebe418b9b "/speaker --port=747…" k8s_speaker_speaker-hwctn_metallb-system_8454886f-03f7-409d-ba7b-4714078dc398_3 90b4b43485c1 k8s.gcr.io/pause:3.4.1 "/pause" k8s_POD_weave-net-s9w4h_kube-system_a15385c7-9884-4b3a-93cb-2a15f4bbf061_4 bcec7cc36fd3 a6ebd1c1ad98 "/usr/local/bin/kube…" k8s_kube-proxy_kube-proxy-f5pk5_kube-system_e42eff69-cdda-42ac-b3df-3cbff1f4dedd_4 413d985d945e k8s.gcr.io/pause:3.4.1 "/pause" k8s_POD_speaker-hwctn_metallb-system_8454886f-03f7-409d-ba7b-4714078dc398_3 e8e56171eb1a k8s.gcr.io/pause:3.4.1 "/pause" k8s_POD_kube-proxy-f5pk5_kube-system_e42eff69-cdda-42ac-b3df-3cbff1f4dedd_4 5a4ecd5cd671 106ff58d4308 "kube-apiserver --ad…" k8s_kube-apiserver_kube-apiserver-master_kube-system_2bbaaa3a9d60ad58f262923fed454748_5 a64f1e1ae323 0369cf4303ff "etcd --advertise-cl…" k8s_etcd_etcd-master_kube-system_1c5c4a551bb33a28a3b7d0ad23489830_5 80ceb21a07e9 k8s.gcr.io/pause:3.4.1 "/pause" k8s_POD_kube-apiserver-master_kube-system_2bbaaa3a9d60ad58f262923fed454748_4 0a7ae1404c94 k8s.gcr.io/pause:3.4.1 "/pause" k8s_POD_etcd-master_kube-system_1c5c4a551bb33a28a3b7d0ad23489830_4 aa0c77746ed0 f917b8c8f55b "kube-scheduler --au…" k8s_kube-scheduler_kube-scheduler-master_kube-system_35ae2ec46407146c0fe6281c2c3292ce_6 3f24c7afa3ae ae24db9aa2cc "kube-controller-man…" k8s_kube-controller-manager_kube-controller-manager-master_kube-system_fbf09edd69cbd0f7402e528c61519fda_7 131fdd33a291 k8s.gcr.io/pause:3.4.1 "/pause" k8s_POD_kube-scheduler-master_kube-system_35ae2ec46407146c0fe6281c2c3292ce_4 37a778d57fb4 k8s.gcr.io/pause:3.4.1 "/pause" k8s_POD_kube-controller-manager-master_kube-system_fbf09edd69cbd0f7402e528c61519fda_4
docker ps 조회 결과 에서 아래와 같이 etcd 컨테이너를 확인 할 수 있습니다.
a64f1e1ae323 0369cf4303ff "etcd --advertise-cl…" k8s_etcd_etcd-master_kube-system_1c5c4a551bb33a28a3b7d0ad23489830_5
docker ps 로 조회 해보면 docker 와 쿠버네티스 설치 직후 이지만 많은 컨테이너가 실행되고 있는 것을 확인 할 수 있습니다
사실 쿠버네티스 자체도 컨테이너로 동작을 하는 것 이며 그렇기 때문에 쉽게 쿠버네티스의 설치 및 구성이 가능한 것 입니다
마스터 컴포넌트 설명
마스터 의 주요 컴포넌트인 kube-scheduler, kube-api ,kube-controller-manager, etcd 에 대해서 확인 해보도록 하겠습니다.
kube-api-server
마스터에 있는 구성요소(컴포넌트) 중 하나로 api-server 는 여러 컴포넌트 중에 핵심적인 요소 이기도 합니다.
위의 그림에 있는 에서도 api-server 는 여러 컴포넌트 중심에 배치 되어 있으며 컴포넌트 들은 api-server 와 연결되어 있는 구조로 되어 있는 것을 이미지로 확인 할 수 있습니다.
쿠버네티스 API 로 외부/내부에서 관리자의 원격 명령을 받을 수 있는 컴포넌트 입니다.
Kubernetes 제어 영역의 프런트 엔드 역할로 사용자가 kubectl 로 명령을 전달하면 api-server 가 받아서 처리를 하게 됩니다.
명령의 처리 중에서 대표적으로 파드의 실행, 종료 등에 대한 명령을 노드(워커노드) 로 전달하여 노드에서 파드의 실행과 종료 등이 수행되게 합니다.
etcd
쿠버네티스의 기본 데이터 저장소인 etcd는 쿠버네티스 클러스터의 중요한 컴포넌트로서, 모든 클러스터의 상태를 저장하고 있습니다.
쿠버네티스의 etcd는 분산형 키-값 (key-value) 저장소로 되어 있습니다 매우 중요함으로 etcd 데이터에 대한 백업 계획은 필수적이게 됩니다
etcd는 쿠버네티스 클러스터를 구성하는 필수 요소이므로 설정 및 관리에 대한 신뢰할 수 있는 접근 방식을 갖추는 것이 중요합니다.
kube-scheduler
kube-scheduler 는 쿠버네티스의 기본 스케줄러이며 컨트롤 플레인의 일부로 실행 되게 됩니다.
kube-scheduler 파드를 어디에 배치할 것인지를 결정하는 역할을 하게됩니다.
생성된 파드를 노드에 할당해 주는 컴포넌트로 스케줄링이라고 하며, 리소스/하드웨어/소프트웨어/정책/워크로드 등을 모두 참고하여 가장 최적화된 노드에 파드를 배치하게 됩니다.
스케줄러가 발견한 모든 파드에 대해 스케줄러는 해당 파드가 실행될 최상의 노드를 찾는 책임을 지게 되고, 스케줄러는 파드의 배치 할때 어떤 노드에서 파드를 실행할지 아래 설명된 스케줄링 원칙을 고려하여 배치가 결정 됩니다
클러스터에서 파드에 대한 스케줄링 요구사항을 충족하는 노드를 실행 가능한(feasible) 노드 라고 합니다. 적합한 노드가 없으면 스케줄러가 배치할 수 있을 때까지 파드가 스케줄 되지 않은 상태로 유지가 됩니다.
스케줄러는 파드가 실행 가능한 노드를 찾은 다음 실행 가능한 노드의 점수를 측정하는 기능 셋을 수행하고 실행 가능한 노드 중에서 가장 높은 점수를 가진 노드를 선택하여 파드를 실행하게 됩니다.
그런 다음 스케줄러는 바인딩 이라는 프로세스에서 이 결정에 대해서 API 서버에 알리게 됩니다
스케줄링 결정을 위해 고려해야 할 요소에는 개별 및 집단 리소스 요구사항, 하드웨어 / 소프트웨어 / 정책 제한조건, 어피니티 및 안티-어피니티 명세, 데이터 지역성(data locality), 워크로드 간 간섭 등이 포함되게 됩니다.
위와 같이 판단하는 여러가지 정보인 리소스가 얼만큼 남아있고 파드가 몇개 이고 어느 노드에 파드가 몇개 배치 되어있고 등의 정보는 어디를 참조하게 될까요?
이러한 정보는 위에서 설명한 etcd 를 참조하게 되는 것 입니다 etcd 의 컴포넌트에는 클러스터 상태, 노드 상태, 파드 상태 등을 실시간에 가깝게 수집을 하고 저장하고 있습니다.
그래서 스케줄러는 이렇게 수집된 정보인 etcd 를 확인 하여 아래와 같은 2단계를 통해서 노드를 선택하게 됩니다.
kube-scheduler 에서 노드 선택
kube-scheduler는 2단계 작업에서 파드에 대한 노드를 선택하게 됩니다.
- 필터링
- 스코어링(scoring)
필터링 단계는 파드를 스케줄링 할 수 있는 노드 셋을 찾습니다. 예를 들어 PodFitsResources 필터는 후보 노드가 파드의 특정 리소스 요청을 충족시키기에 충분한 가용 리소스가 있는지 확인하게 됩니다.
스코어링 단계에서 스케줄러는 목록에 남아있는 노드의 순위를 지정하여 가장 적합한 파드 배치를 선택하게 됩니다. 스케줄러는 사용 중인 스코어링 규칙에 따라 이 점수를 기준으로 필터링에서 통과된 각 노드에 대해 점수를 지정하게 됩니다.
마지막으로 kube-scheduler는 파드를 순위가 가장 높은 워커 노드에 할당하게 됩니다. 점수가 같은 노드가 두 개 이상인 경우 kube-scheduler는 이들 중 하나를 임의로 선택 하게 됩니다.
위에 언급한 것처럼 api-server 는 마스터의 구성 요소 중 핵심 요소로 모든 컴포넌트는 api-server 와 연결 되어 있습니다(그림 참조)
그렇기 때문에 스케줄러가 etcd 를 참조 때도 api-server 를 통해서만 참조 할 수 있게 되고, 어느 노드에 배치 할지가 결정이 되면 다시 api-server 통해서 노드에서 파드를 실행 하도록 명령을 요청을 하게 되는 것 입니다.
kube-controller-manager
kube-controller-manager 컴포넌트는 컨트롤러 프로세스를 실행하고 클러스터의 실제 상태를 원하는 사양(상태)으로 조정합니다.
아래의 컨트롤러들을 구동하는 역할을 하는 컴포넌트 입니다.
- Node Controller : 노드가 다운되었을 때 알림과 대응에 관한 역할을 합니다
- Replication Controller : 지정된 수의 파드들을 동작되도록(유지 되도록) 하는 역할을 합니다
예를 들어 Nginx 5개로 지정하였다면 5개 파드가 유지 되도록 하는 기능으로, 몇 개의 파드가 문제가 발생된 경우 설정한 만큼을 유지하기 위해서 파드를 기동을 시켜주는 역할을 하게 됩니다.
- Endpoints Controller: 서비스와 파드를 연결시켜 엔드포인트 오브젝트를 생성하는 역할을 하게 됩니다.
- Service Account & Token Controllers: 계정 과 토큰에 관련된 컨트롤이며, 새로운 네임스페이스에 대한 기본 계정과 API 접근 토큰을 생성 합니다.
기본적으로 사용되는 계정은 관리자 계정으로 모든 걸 다 할 수 있는 계정 입니다.(클러스터 관리자)
여러 사용자가 같이 사용하는 환경에서 모든 사용자가 모든 권한을 다 가지고 있을 경우 문제가 발생될수도 있으므로 권한을 분리하여 계정 정책을 수립하여 사용할 수 있습니다.
별도의 계정에 대한 작업 없는 상태에서 현재 상태를 확인 해보겠습니다.
/home/devops:$ groups devops wheel docker
사용중인 유저는 OS의 일반 유저 입니다. 해당 유저의 쿠버네티스 계정 또는 롤에 대한 확인은 config view 를 통해서 할 수 있습니다.
/home/devops:$ kubectl config view apiVersion: v1 clusters: - cluster: certificate-authority-data: DATA+OMITTED server: https://192.168.56.55:6443 name: kubernetes contexts: - context: cluster: kubernetes namespace: testns user: kubernetes-admin name: kubernetes-admin@kubernetes <-- admin current-context: kubernetes-admin@kubernetes kind: Config preferences: {} users: - name: kubernetes-admin <-- admin user: client-certificate-data: REDACTED client-key-data: REDACTED
설명 한 내용과 같이 별도의 계정에 대한 설정 등을 진행 한 내역이 없기 때문에 현재 사용중인 계정은 관리자 계정으로 사용중 입니다.
노드(워커 노드)의 컴포넌트
kubelet 와 kube-proxy 가 대표적인 컴포넌트 입니다. kube-proxy는 컨테이너로 실행되게 됩니다.
워커노드에서 kubelet 이 시작되지 않고 있거나 문제가 있다면 아래의 노드 정보에서도 Ready 라고 표시되지가 않습니다.
- 정상 실행 시
/home/devops:$ kubectl get nodes NAME STATUS ROLES AGE VERSION master Ready control-plane,master 53d v1.21.2 worker1 Ready <none> 53d v1.21.2 worker2 Ready <none> 53d v1.21.2
워커노드가 가 Ready 가 아니라 문제가 있다면 워커노드에서 docker 와 kubelet 서비스가 정상적으로 기동 중인지 확인 해봐야 합니다.
kubelet
kubelet 이 하는 일은 마스터의 kube-api-server 에서 받은 명령을 노드에서 실행을 하는 역할로써 노드에서 파드의 실행, 중지, 삭제 를 하는 역할을 하게 됩니다.
그외 파드와 관련된 삭제 중지 등의 일을 하게 됩니다.
kube-proxy
네트워크 연결을 관리하고 노드간에 네트워크 규칙을 유지합니다
Docker 에서 컨테이너 실행시 Port Forwarding 을 하게 되면 iptables 설정을 하여 사용하게 되는 부분이 있으며 이런한 부분과 유사하게 네트워크 접속에 관련된 부분을 쿠버네티스의 워커노드에서는 kube-proxy 가 하게 됩니다.
kube-proxy 는 방화벽 관련 설정, 패킷이 도착하였을 때 어디로(어느 파드로) 전달해줄지 등의 일을 하게 됩니다.
kube-proxy 는 컨테이너로 동작하고 있으며 워커노드에서 docker 에서 조회해 볼 수 있습니다.
[devops@worker1 ~]$ docker ps | grep proxy 0b4a0c3b75fa a6ebd1c1ad98 "/usr/local/bin/kube…" k8s_kube-proxy_kube-proxy-4ftkg_kube-system_29b14026-9dee-4b2c-98f9-88ae2f1e4908_3 1f3eae383df3 k8s.gcr.io/pause:3.4.1 "/pause" k8s_POD_kube-proxy-4ftkg_kube-system_29b14026-9dee-4b2c-98f9-88ae2f1e4908_3
클러스터의 모든 노드에서 Kubernetes 서비스 개념을 구현합니다.
패킷이 외부에서 들어왔을 때 어떤 파드로 패킷을 보내줄지를 서비스 라는 오브젝트가 담당을 하게 되고 해당 서비스가 kube-proxy 와 관련이 되어 있습니다.
쿠버네티스 개념
쿠버네티스에서 사용하는 개념은 크게 객체(Object)와 그것을 관리하는 컨트롤러(Controller)가 있습니다.
객체(Object)는 종류가 많이 있으며 사용자가 쿠버네티스에 바라는 상태(desired state)를 의미하게 되고, 컨트롤러는 객체(Object)가 원래 설정된 상태를 잘 유지 할 수 있게 관리하는 역할을 하게 됩니다.
쿠버네티스는 클러스터의 상태를 나타내기 위해 이 오브젝트를 이용하게 됩니다. 구체적으로 말하자면, 다음같이 기술할 수 있습니다.
- 어떤 컨테이너화된 애플리케이션이 동작 중인지 (그리고 어느 노드에서 동작 중인지)
- 그 애플리케이션이 이용할 수 있는 리소스
- 그 애플리케이션이 어떻게 재구동 정책, 업그레이드, 그리고 내고장성과 같은 것에 동작해야 하는지에 대한 정책
오브젝트를 생성하게 되면, 쿠버네티스 시스템은 그 오브젝트의 생성을 보장하기 위해 지속적으로 작동 하게 됩니다.
오브젝트를 생성함으로써, 여러분이 클러스터의 워크로드를 어떤 형태로 보이고자 하는지에 대해서 효과적으로 쿠버네티스 시스템에 전하게 되고 이것이 바로 사용자가 클러스터에 대해 "의도한 상태(desired state)" 가 되게 됩니다.
그리고 위에서 설명한 내용과 같이 컨트롤러는 오브젝트가 의도한 상태(desired state) 를 잘 유지 할 수 있도록 관리를 하게 됩니다.
객체(Object)에서 사용할 수 있는 리소스에는 파드(pod), 서비스(service), 볼륨(volume), 네임스페이스(namespace) 등이 있습니다.
컨트롤러에는 ReplicaSet, Deployment, StatefulSet, DaemonSet, Job 등이 있습니다.
쿠버네티스 클러스터에 오브젝트(객체)나 컨트롤러가 어떤 상태여야 하는지를 제출할때는 yaml 파일형식의 템플릿을 사용합니다.
yaml의 기본 형식은 다음과 같습니다(대소문자 구분)
--- : 생략 가능하거나 대쉬(-) 로 시작
apiVersion: v1 <= object 를 생성하기 위한 api version, v1 외에 다른 버전도 있습니다.
Kind: Pod <= 어떤종류의 리소스 인지를 명시, 대소문자를 구별하며 첫글자는 대문자 입니다.
metadata: 해당 쿠버네티스 객체를 유니크하게 식별할수 있는 데이터이름, uid, 네임스페이스, 파드 이름 등이 포함됩니다.
Spec : 해당 객체의 의도가 기술되며 파드의 경우 컨테이너 정보가 포함되며 Kind 에서 기술된 리소스의 종류에 따라서 Spec 은 생략 할 수 있습니다 (예를 들어 네임스페이스)
Resource
쿠버네티스에는 수 많은 리소스가 있습니다.
많은 리소스 중에서 자주 사용하는 리소스 위주로 사용법이나 내용을 확인 할 필요가 있습니다.
resource 에 대한 정보 확인은 kubectl api-resources 를 통해서 확인 할 수 있으며 버전 정보 등도 확인 할 수 있습니다.
[devops@master ~]$ kubectl api-resources NAME SHORTNAMES APIVERSION NAMESPACED KIND bindings v1 true Binding componentstatuses cs v1 false ComponentStatus configmaps cm v1 true ConfigMap endpoints ep v1 true Endpoints events ev v1 true Event limitranges limits v1 true LimitRange namespaces ns v1 false Namespace nodes no v1 false Node persistentvolumeclaims pvc v1 true PersistentVolumeClaim persistentvolumes pv v1 false PersistentVolume pods po v1 true Pod < ... 중략 ... >
다음 포스팅에서는 리소스 중에서 주요한 리소스를 확인 해보도록 하겠습니다.
관련된 다른 글
Principal DBA(MySQL, AWS Aurora, Oracle)
핀테크 서비스인 핀다에서 데이터베이스를 운영하고 있어요(at finda.co.kr)
Previous - 당근마켓, 위메프, Oracle Korea ACS / Fedora Kor UserGroup 운영중
Database 외에도 NoSQL , Linux , Python, Cloud, Http/PHP CGI 등에도 관심이 있습니다
purityboy83@gmail.com / admin@hoing.io