JENNIFER – 쿠버네티스 환경(AKS, EKS, GKE,…) 지원
컨테이너 환경으로의 변화
물리 머신을 가상화 한 VM과는 또 다른 수준의 가상화를 제공하는 컨테이너 가상화(Container Virtualization) 기술이 마이크로서비스의 활성화와 맞물려 운영 환경에서의 도입이 성공적으로 안착하고 있습니다. 하지만 컨테이너 층이 운영체제로부터 실행 환경을 격리하는 수준으로만 제공되므로 직접적인 운영 면에서 보면 소규모 서비스 정도에만 가능할 뿐 현실적인 수준에서 대규모 서비스를 운영하는 것에는 불편함이 산재해 있습니다. 즉, “그림 1”처럼 운영자가 다중 컨테이너를 다뤄야 하는 경우 자칫 관리적인 실수를 유발할 여지가 다분합니다.
이러한 단점을 보완하기 위해 컨테이너의 관리를 추상화하는 오케스트레이션 도구들이 나왔습니다. 따라서 시스템 운영자는 “그림 2”와 같이 오케스트레이션 도구를 이용해 다중 컨테이너를 다룰 수 있게 되었으며, 이로써 대규모 서비스를 위한 컨테이너 기술의 도입이 더욱 활성화할 수 있었습니다.
이러한 운영 환경의 변화를 클라우드 서비스를 제공하는 업체에서도 발빠르게 자사의 제품군들에 도입하고 있습니다. 왜냐하면, 오케스트레이션 도구가 있다고 해도 결국 컨테이너 기술이 활성화되는 인프라는 반드시 필요하기 때문입니다. 결국 클라우드 서비스 제공자는 기존 가상 인프라 환경 위에 k8s 서비스만 적절하게 얹는 것으로 완벽하게 추상화된 컨테이너 서비스를 제공하며 이것은 클라우드 서비스들이 한결같이 강조하는 “인프라 관리 비용의 절감”과도 잘 맞아떨어집니다. 현재 이런 추세를 반영해 대표적으로 Azure의 AKS, GCP의 GKE, AWS의 EKS 서비스 등이 운영 중에 있습니다.
제니퍼 에이전트의 k8s 지원
참고
이번 글에서는 AKS 환경을 예로 들었지만 제니퍼 제품의 관점에서는 결국 k8s를 지원하는 것이기 때문에 모든 환경에서 유사하게 지원이 가능합니다. 또한 다양한 컨테이너 기술이 있지만 여기서는 docker를 대상으로 설명합니다
제니퍼 에이전트가 k8s를 지원하는 구조는 근본적으로 컨테이너 환경을 지원하는 것과 다를 바 없습니다. 결국 에이전트의 실행 파일과 환경 변수를 위한 설정을 컨테이너에 알리는 방법이 필요한데, 기존에도 제니퍼 에이전트는 다음의 2가지 방식으로 docker 환경에서 활성화가 되었습니다.
- 실행 시 에이전트의 바이너리가 있는 볼륨과 환경 변수를 지정
2. 기존 컨테이너의 Dockerfile에 에이전트 바이너리와 환경 변수를 포함해 빌드
K8s 오케스트레이션 도구는 컨테이너를 한 단계 래핑해 Pod 단위의 배포를 하는 방식이므로 결국 에이전트의 k8s 지원은 위의 2가지 원칙에서 벗어나지 않습니다. 실제로 2번 방식은 k8s 환경에서도 그대로 사용할 수 있습니다.
하지만 볼륨 연결은 컨테이너에 직접 연결하는 기존 구조와는 달리 컨테이너의 집합일 수 있는 Pod와 연결이 된다는 특징으로 인해 k8s가 정한 PV(Persistent Volume)를 거쳐 에이전트의 바이너리와 컨테이너를 연결합니다.
일단 에이전트의 바이너리를 담은 볼륨을 마련했으면 이후 각각의 서비스 배포를 위한 yaml 파일 내에 해당 PV와 연결되는 volumes와 env 설정을 추가하면 됩니다.
apiVersion: apps/v1 kind: Deployment metadata: name: net-razor31-sample ...[생략]... spec: ...[생략]... template: ...[생략]... spec: containers: ...[생략]... env: - name: CORECLR_ENABLE_PROFILING value: "1" - name: CORECLR_PROFILER value: "{6C7CAF0F-D0E5-4274-A71B-6551761BBDC8}" - name: CORECLR_PROFILER_PATH value: "/netagent/bin/libAriesProfiler.so" - name: ARIES_SERVER_ADDRESS value: "127.0.0.1" - name: ARIES_SERVER_PORT value: "5000" - name: ARIES_DOMAIN_ID value: "1000" volumeMounts: - mountPath: "/netagent" name: volume volumes: - name: volume persistentVolumeClaim: claimName: my-agent-file
이후 kubectl을 이용해 yaml을 적용하면 정상적으로 모니터링이 되는 것을 확인할 수 있습니다.
$ kubectl apply -f demo.yaml
클라우드 플랫폼의 장점이라면, 추상화된 인프라를 기반으로 한 워커 노드를 k8s에 자유롭게 추가/제거할 수 있다는 점입니다. 이와 함께 응용 프로그램의 Pod 인스턴스 수를 수동 및 자동으로 스케일링 할 수 있습니다. K8s의 경우 자동 스케일링을 위해 Horizontal Pod Autoscaling(이하 hpa)을 지원하는데 AKS에서도 동일한 명령어를 사용할 수 있습니다. 가령, 위에서 배포한 “demo.yaml”에 대해 1개의 인스턴스를 항상 실행해 놓고, 부하에 따라 최대 3개까지 실행하려는 경우 아래와 같이 실행할 수 있습니다.
$ kubectl autoscale deployment --max=3 net-razor31-sample --min=1 horizontalpodautoscaler.autoscaling/net-razor31-sample autoscaled $ kubectl get pod NAME READY STATUS RESTARTS AGE net-razor31-sample-6b747bb886-c2kgk 1/1 Running 0 116s
보는 바와 같이 부하가 없어도 pod가 1개 운영되지만, 제니퍼 콘솔에는 없을 수도 있습니다. 왜냐하면, Pod가 올라온 것과 내부의 응용 프로그램에 요청이 전달된 것과는 다를 수 있기 때문입니다.
물론 이 상황에서 부하 테스트를 한다면,
$ docker run --name loadtest --rm -it azch/loadtest http://...[서비스URL]
3개의 Pod가 자동으로 올라오고 제니퍼 콘솔에서도 그 결과를 확인할 수 있습니다.