가장 핵심이 되는 단어는 안정성이다. 조직에서 만든 애플리케이션이 안정성이 부족하여 작동하지 않거나 불안정한 경우 실제 비즈니스에 피해를 줄 수 있다는건 누구나 알고 있는 당연한 이야기이지만 100%의 안정적인 시스템은 존재하지 않으므로 적절한 수준(정량적으로 측정하긴 어렵지만 이해관계자들이 납들할만한 수준)의 안정성을 달성하기 위한 일련의 작업들을 수행하는 것이 SRE의 기본 속성이라고 볼수 있다.
SRE는 Google에서 2003년부터 7명의 소프트웨어 엔지니어로 구성된 팀에서 시작된 이후 (자세한 내용은 위 링크 ebook 참조) Google 사내에 널리 확산되고 내부적인 문화로 조성되는 중에 밖에서는 DevOps라고 하는 문화가 동시에 확산되었다 한다. 결국 동일한 문제를 해결하기 위한 측면에서 두개의 방법론은 다르다고 봐야한다.
새로운 서비스의 상태의 지표는 어떻게 정의할까? 보통은 무엇을 SLI(서비스 수준 지표)로 사용할지를 정하는것으로 본다. 일반적으로 성공 및 실패 측정값(200 OK,500 Error), 응답시간(ms), 처리량 등의 조합으로 결정될 수 있다. 보통 카나리아 분석을 통해 Scoring을 한 SLI를 200 OK와 500 또는 에러코드의 비율로 결정하는 방법을 사용하는 경우가 많다.
서비스 상태를 식별하는 지표를 정하고 나면 고객이나 우리가 원하는 안정성 수준을 결정해야 한다. 개발팀과 운영팀이 같이 만든 원하는 안전성 수준을 SLO(서비스 수준 목표)라고 말하면 된다.
SLO는 Prometheus나 Datadog과 같은 모니터링 시스템을 활용하여 정확하게 측정하고 표시해야 한다. 서비스의 안정성에 대해서 명확하게 이해할수 있는 목표이기도 하다. 반드시 SLO를 만족하는지 못하는지 명확한 측정값으로 데이터가 존재해야 하고 SLO를 충족하지 못하면 문제가 있는것으로 판단하고 문제를 해결해야 한다.
오류 예산이라는 말을 명확히 이해하려면 흔히 고객과 체결하는 계약서 상의 명시된 서비스 가동율(SLA)을 생각하면 될 것 같다. 보통 99.9% 의 SLO를 정한다고 한다면 1년에 8시간 45분 57초의 서비스 다운타임을 허용하는 것이다. 오류 예산은 서비스의 완벽한 안정성과 원하는 안정성의 차이(100%-99.9%=0.01%)를 말한다. 0.01%로 즉 8시간정도의 오류 예산을 가지는 것은 그 시간을 모두 사용할 때까지 추가 릴리스나 패치를 진행할 수 있다는 이야기와 같다. 어떤 팀은 해당 예산을 신규 기능을 릴리스하는데 사용하기도 하고 장애가 발생했을때 문제의 원인을 발견하고 개선하는데 사용하기도 한다.
일반적으로 서비스에 대한 오류 예산이 모두 사용되면 서비스가 원하는 안정성 수준으로 돌아갈때 까지 해당 서비스의 추가적인 릴리스를 보류하는게 일반적이긴 하지만 특정기간(월 또는 분기 또는 연간) 기준으로 계산되기 때문에 서비스 안정성이 정상 상태라면 오류 예산은 다시 주어지게 되므로 선순환 구조를 가진다고 볼 수 있다.
일반적으로 비즈니스에 크리티컬한 장애가 발생했을때 사후 분석(회고)을 하게 되는데 이때는 비난 없는 분석을 해야한다. 오래전 기억이지만 예전 직장 특정팀에서는 장애가 발생하면 유관자들이 모두 엔지니어 책상 뒤에 서서 모든 화살과 눈총을 주기 때문에 도저히 일을 할 수 없게 만든 경우가 많았었다.
특정 운영자의 작업 실수로 인해 장애가 발생했다 하더라도 해당 이벤트가 발생하게 된 프로세스나 기술기반에 실패 원인을 파악하는데 중점을 두어야 할것이다.
시스템의 안정성을 저하시키고 서비스를 중단시킨 작업(릴리스, 패치 등)을 사유로 개인에게 페널티를 주거나 고과에 반영하는 방법은 장애로 부터 교훈을 얻을수가 없고 해당 담당자의 충성도나 생산성 저하를 유발하는 안좋은 장치가 될 수 있다. 내 경험이기도 하지만 한동안 두려워서 아무 변경도 하지 못하는 경우가 종종 있었다.
회사나 조직, 팀은 시스템 중단으로부터 교훈을 얻고 지속적으로 시스템을 개선할수 있다. 적절한 분석을 통해 후속조치를 수행함으로써 실패를 수용하는 것이 SRE의 핵심 원칙이다. 이러한 내용을 모두에게 공유하고 타 조직이나 팀에게 인사이트를 제공하는 선순환 구조를 만드는것 또한 SRE의 기본 원칙이라고 볼 수 있다.
항상 SRE에서는 Toil에 초점을 맞춰야 한다. Toil은 사람이 수행하는 운영 작업 중 특정한 패턴이나 특성이 있는 작업을 말한다. 종종 반복적이고 자동화 될 수 있는 작업일지라도 대부분 수동작업으로 처리를 한다. 서비스의 규모가 커지거나 고객이 많아지게 되면 보통 우리가 이야기 하는 티켓(또는 SR)의 수가 많아지고 공수가 많이 필요하게 된다.
배포때마다 Config를 적용하거나 계정 등록, 볼륨이나 디스크 프로비저닝 등 수동으로 처리해야하는 모든 작업이 운영자에게는 부하로 다가올수 있다. 이러한 반복적인 작업을 티켓시스템을 통해 처리를 하게 되면 티켓 생성, 작업계획서 작성, 검토, 승인 단계를 그때 마다 해야하는 아주 번거로운 작업(Toil)을 해야한다.
SRE는 최대한 이러한 반복적이고 번거로운 작업을 제거하기 위해 노력해야하고 자동화와 Self-Service로 개발자가 편하게 직접 사용할수 있도록 환경을 제공해 주어야 한다. 이러한 요청이나 티켓을 자동으로 처리할 수 있으면 조금 더 생산적인 일을 수행할수 있다.
위에서 이야기한 적절한 안정성과 비슷한 맥락으로 생각하면 될 것 같다. 번거로운 작업을 없애는것이 다른 중요한 작업보다 우선순위가 떨어지기도 하지만 서비스 상에서 Toil을 제거하는것도 SRE의 주된 업무이다.
Toil을 제거하거나 서비스/시스템 안정성을 개선하기 위해 SRE는 장애를 해결하고 티켓을 처리하는 시간 비중을 50%를 넘겨서는 안된다. 티켓이 필요하지 않도록 개발자 Self-Service를 구성/제공하고 효율성을 증대시키기 위해서 IaC등(Shell, Ansible, Terraform)과 같이 자동화를 위한 코드를 만드는데에도 집중을 해야한다.
그림과 같이 서비스 안정성 계층 구조에서는 기본적으로 모든 서비스를 모니터링 하는 시스템을 갖추어야 한다고 말한다. 모니터링 시스템이 준비가 되면 서비스에 대한 SLI, SLO를 만들고 모니터링 시스템에서 구현하는것이 첫번째 SRE를 적용하는 방법이라고 할 수 있을 것이다.
17년까지 팀 막내였지만 새로운 부서로 이동하여 서비스개발 파트장을 맞게 되었음. 17년도에 개발이라고는 python를 사용하여 vmware vm을 openstack instance로 migration하는 프로젝트 및 kubernetes 기반 tensorflow 플랫폼을 개발하는 초보개발자 수준이였던 내가 인프라와 클라우드 플랫폼(openstack, vsphere, kubernetes) 경력이 인정되어 서비스 개발 파트를 맡게 되었다. 인생에서 가장 큰 변혁중 하나였다고 생각하고 항상 감사하는 마음으로 일을 하고 있다.
CNCF OpenSource들을 활용하여 FaaS(Function as a Service), IaC(Infra as Code) 플랫폼 개발을 진행하였다. 서비스 기획 및 두개 프로젝트의 Scrum Master 역할을 수행하였고 메인 업무는 SRE역할로 Kubernetes 설계 구축, 클러스터 및 스토리지 관리, LB, 인증서 등 클라우드 인프라 자원관리 정도였던것 같다.
Tech.
Public Cloud : AWS, DigitalOcean, IBM Cloud, GCP, Azure, nCloud
쓰고나서 보니 2018년도 회고라기 보다 거의 개발에 필요한 잡일(DevOps라고 두둔하면서)과 발표만 한거 같네...
19년도 부터는 다른업무를 하게 될거 같은데 초심을 잃지 말아야 하겠다.
최근 화두가 되었던 노력중독 이였던것 같은 18년은 털어버리고
내가 진짜로 좋아하고 하고 싶은 공부와 업무, 그리고 가족을 위해서 로드밸런싱 하면서 지내야 하겠다.
2006년에 쓴 미래의 내 모습과 어느정도 일치하는거 같지만 목표를 좀더 높이 잡아야할듯 하다.
번역에 참여하거나 책을 써본다던지 커뮤니티 활동을 좀더 적극적으로 해보고
회사에서 시키는 밋업이 아닌 자발적으로 참여하는 외부 강연이나 밋업을 위주로 해봐야겠다.
또한 점점 개발영역과 멀어지는거 같은 내모습이 나이가 들면서 더 심화될거 같아서 지인들과 별도의 개발 프로젝트를 진행해보려고 한다.
내 13년간 직장 생활중 가장 바쁘고 다이내믹하면서 바빴던 한해이자 많은 경험과 공부가 되었던 일년이였던것 같다.
나를 땡겨주셨던 June, 항상 분위기를 리드했던 Joonbum, 언제나 열정가득하고 최고의 DevOps 플레이어 Jeongho, 든든한 Backender Donghun, Excellent/Free/Kind(a.k.a EFK)한 Minyoung, 내가 인정하는 Frontier Sanghun, Best Rookie Minsoo, sorry because the hy HyunSang, Moontoring Jinsoo, Forever Mentor Jaemoon, Guru of CNI Youngchae 모두에게 감사의 말씀을 전하고 싶다. (무슨 수상소감도 아니고 ㅋㅋ)
19년에도 남들에게 존경을 받는 사람보다는 무슨일을 하든지 대중에게 욕먹지 않고 필요할때 도움을 요청을 할수 있는 그런 편한 사람이 되어야 겠다.
11/23 "Kubernetes Meetup" 1Day에서 발표한 이야기 연장선으로 작성한다.
고객에게 오퍼링을 위해 준비한 내용과 Kubernetes monitoring과 연계한 내용에 대해서 적어보려고 한다.
최근 발표를 다니면서 많이 받는 질문이 실제 사용할만 한가?라는 질문과 어떻게 활용해야 하는지에 대한 질문들을 많이 받는다.
오늘 최근 Spinnaker Summit 2018에서 중요하게 다뤘던 Kayenta 프로젝트를 가지고 이야기 해보려고 한다.
Kayenta는 자동 Canary 분석 오픈소스(Automated Canary Service(ACA))로 Spinnaker의 마이크로서비스중 하나로 동작한다.
Automated Canary Deployments에 사용되고 자세한 내용은 canary documentation을 확인하면 된다.
새 종류의 하나인 Canary는 1차 세계대전중에 인간이 해를 입기 전에 독성가스를 탐지하는 용도로 사용되었다고 한다.
DevOps에서는 CD(Continuous Deployment) 프로세스의 일부로 사용되며 Canary 릴리즈는 새로운 버전의 Software를 Production에 배포하는 위험을 줄여주는 기술이라고 생각하면 된다.
Canary 신규 버전의 Software를 안정적인 기존 버전과 함께 배포하고 특정사용자나 일부 대상에게 트래픽 일부를 흘려 기존 사용자에게 영향을 최소하하고 새로운 버전의 문제를 신속하게 발견하고 이전의 안정된 버전으로 트래픽을 다시 라우팅시키는것이 주요 기능이라고 보면 된다.
보통 품질 테스트 용도로 현재 운영 버전과 신규 버전의 주요한 지표(주로 Prometheus Metric)를 비교하여 평가를 진행하는데 이를 단위 테스트나 통합 테스트를 대체하여 사용해서는 절대 안된다.
위에서 언급하였듯이 예기치 않은 위험을 최소화 하거나 문제를 신속하게 발견하는 것을 주 목적으로 하기 때문이다.
Spinnaker에서는 기본적으로 3가지 Cluster(Logical Application Group)를 사용한다.
Production Cluster - 현재 실행중인 운영 버전으로 Replica는 임의로 변경할 수 있다.
Baseline Cluster - Production Cluster와 동일한 버전으로 실행됨
Canary Cluster - 변경된 신규 버전의 Software로 실행됨
기본적으로 수동으로 진행할 경우에는 로그와 수집된 메트릭을 분석하고 객관적인 지표로 평가를 진행하는게 기본이다.
하지만 직접 사람이 하는 일이라 메트릭 데이터를 보다 보면 편견과 착오가 발생할 수 밖에 없다.
그래서 Netflix는 ACA(Automated Canary Service)라고 하는 자동화된 접근 방식을 통해 카나리 분석을 진행하고 있다.
수동으로 계산된 여러가지 지표를 가중치 기반으로 점수를 내리고 원하는 점수에 도달하면 배포하는 자동화된 방식이다.
해당 pipeline내의 sampleapp은 python flask 기반으로 구성되어 간단히 internal 500 error를 원하는 비율을 configmap 변수로 구현할 수 있다. prometheus python client를 사용하여 Gauge, Counter, Metric 서버를 간단하게 구성을 해보았다. 그리고 코드내에서 500 error rate를 구한 이유는 18년 11월 기준 spinnaker kayenta 버전에서는 PromQL(rate,irate와 같은 함수) 지원이 되지 않는다. 개발중인 코드에 포함이 된것을 확인하였고 12월 kubecon때 정식 릴리즈에 포함될거라 생각한다.
#!/usr/bin/env python from random import randrange from flask import Flask from prometheus_client import start_http_server, Gauge, Counter import os app = Flask('kayenta-tester') c = Counter('requests', 'Number of requests served, by http code', ['http_code']) g = Gauge('rate_requests', 'Rate of success requests') responce_500 = 0 responce_200 = 0 rate_responce = 0 @app.route('/') def hello(): global responce_500 global responce_200 global rate_responce if randrange(1, 100) > int(os.environ['SUCCESS_RATE']): c.labels(http_code='500').inc() responce_500 = responce_500 + 1 rate_responce = responce_500 / (responce_500+responce_200) * 100 g.set(rate_responce) return "Internal Server Error\n", 500 else: c.labels(http_code = '200').inc() responce_200 = responce_200 + 1 rate_responce = responce_500 / (responce_500+responce_200) * 100 g.set(rate_responce) return "Hello World!\n" start_http_server(8000) app.run(host = '0.0.0.0', port = 8080)
해당앱을 Start Manual Execuction을 통해 배포한다. Comfirm Execution창에서 SUCCESS_RATE를 원하는 값(예:70%)으로 선택하고 배포를 하고 나면 Infrastructure - Clusters 메뉴에서 해당 샘플앱을 확인할 수 있다.
실제 해당 서비스를 접속해보면 위에 설정한 SUCCESS_RATE 비율로 200화면과 500에러를 확인할 수 있다.
해당 메트릭의 통계를 확인하기 위해 curl을 반복적으로 실행하는 injection container 를 실행한다.
kubectl -n default run injector --image=alpine -- \ /bin/sh -c "apk add --no-cache --yes curl; \ while true; do curl -sS --max-time 3 \ http://sampleapp:8080/; done"
5분정도 후에 Prometheus로 접속하여 코드내 작성한 rate_requests 메트릭을 확인해본다.
PromQL은 아래 쿼리를 실행하였다.
rate_requests{app="sampleapp",version="prod"}
아래 그림과 같이 4개의 pod에서 70% 정도 200 OK, 30% 정도 500 Error가 발생하는 것을 확인할 수 있다.
Prerequisite Canary Config 구성이 먼저 필요하다. Delivery - Canary Configs 메뉴에서 신규 컨피그를 작성한다.
Configuration Name - kayenta-test
Filter Templates 메뉴를 먼저 생성한다. Canary, Baseline구분을 위해 version 정보를 선택하였다.
Metrics - Add Metric 은 분석을 위한 Prometheus Metric을 설정하는 단계로 error_rate가 증가(increase)하면 Pipeline을 중단시키고 Metric은 앞에서 확인한 rate_requests를 지정한다. Filter Template은 위에서 지정한 version을 선택한다.
Configuration - Pipeline 실행시 초기 입력값(0-100, 10단위)으로 설정가능한 successRate 라는 Parameter를 설정한다.
2nd Stage
Find Baseline - 위에서 작성한 기본 Deploy Pipeline이 선택되었는지와 확인한다.
Deploy Canary Config - 앞에서 선택한 새로운 Parameter(successRate)를 신규 배포할 Canary Pod ConfigMap으로 설정하는 단계이다.
3rd Stage
Deploy Canary - yaml manifest로 Canary 버전을 배포한다. Replicas는 1로 설정하였고 배포될 Account(K8s Cluster)를 지정한다.
Deploy Baseline - yaml manifest로 Baseline 버전을 배포한다. 위와 동일하게 Replicas는 1로 설정하였고 배포될 Account(K8s Cluster)를 지정한다.
4th Stage
Canary Analysis - 중요한 Canary 분석 단계로 아래와 같이 설정을 확인한다. Prerequisite에서 설정한 Config(kayenta-test)를 선택하고 짧은 분석을 위해 1분(60초) 간격으로 3번 수행을 하도록 한다. Filter Template에서 지정한 version(version="${scope}") 분석을 위해 Baseline, Canary 설정을 하고 Location은 Namespaces로 생각하면 된다.
간단하게 Spinnaker 와 Prometheus Metric을 활용하여 Kayenta 기반 Canary 배포를 해봤다. 현재 Spinnaker 1.10에서 istio가 지원된다고 하니 다시 한번 확인하고 istio 기반 canary 배포와 함께 사용하는 방법을 더 연구해봐야 할 것 같다.
올해 AWS re:invent 끝나고 작년보다 큰 현자타임이 왔다. 오픈소스로 먹고사는 사람들의 기분은 다 비슷할거 같다고 생각이 든다. 12월 11일 부터 Kubecon이 열린다고 하니 Kubernetes 관련한 새로운 프로젝트와 기능들에 집중해서 남들보다 한발 나아가야하지 않을까? 오픈소스로 먹고사시는 분들 다들 힘냈으면 좋겠다.
최근 트렌드인 멀티 클라우드를 지향하는 오픈소스 플랫폼이다.
2014년 Netflix의 Asgard로 시작되어 2015년에 오픈소스화 되었다.
빠른 속도와 신뢰도있는 소프트웨어 릴리즈를 위해 만들어졌으며 대부분의 메이저 클라우드 프로바이더들을 지원한다.(AWS,GCP,Azure,openstack..)
현재 Netflix, Google, MS, Veritas등이 Contribution을 하고 있다.
사용하면서 혼돈이 많이 생기는 부분이다 이게 GCE나 EC2를 쓰면 용어 매칭이 쉬운데 k8s를 위한 별도의 메뉴가 아닌 기능을 통합하다보니 용어가 조금 혼동스럽게 구성이 되었다.
특히 Load Balancer 부분은 Service로 매핑되고 퍼블릭 k8s에서 제공하는 Type LoadBalancer는 미지원한다.
그리고 모든 Resource들은 Deploy, Delete, Scale, Rollout(Undo, Pause, Resume)을 지원하며 Versioning이 지원된다. Versioning은 여기에 설명된 대로 strategy.spinnaker.io/versioned annotation을 통해 manifest별로 재정의가 가능하다.
기본자원인 서버그룹은 배포할수 있는 artifacts(vm image, docker image, source)와 인스턴스(pod) 수, Auto-Scaling, metadata 등 기본 구성등을 가지고 있다.
서버그룹은 LoadBalacer나 Firewall 도 선택적으로 연결되고, vm이나 pod 형태로 배포된 application의 집합체라 볼수 있다.
Pipeline은 주요 배포 관리도구로 사용된다.
Stage라고하는 일련의 Action으로 구성되며 파이프라인을 따라 Stage간 매개변수 전달이 가능하다.
수동으로 시작하거나, Jenkins 작업완료, Docker Registry 신규 Docker 이미지, Cron일정 또는 다른 Stage와 같은 이벤트에 의해 자동으로 트리거링되도록 구성할수 있다.
Pipeline 실행중에(시작/완료/실패) mail, slack, hipchat(사라짐)을 통해 Alert가 가능하다.