2010년대 초반에 리눅스 분야에서 경력을 시작했습니다. 이때 시스템 관리 분야는 중대한 변화를 요구하는 변전기적인 시기였습니다. 데브옵스(DevOps), 사이트 신뢰성 엔지니어링(Site Reliability Engineering), 그리고 클라우드 엔지니어링은 모두 시스템 및 응용 프로그램 팀이 함께 작업하는 방식에 대해 급격한 변화를 주장했으며 그 과정에서 가끔 논란이 있었습니다. 여러 책이 출판되었고, 직책들이 급증했으며, 수많은 방법론들이 기업의 속도와 소프트웨어 품질을 향상시키기 위해 기술적 하늘에서 비처럼 내렸습니다.
주장들이 의심스러울 수는 있지만, 주요 아이디어들은 상당히 이해하기 쉬웠습니다. 실제로 더 깊이 검토해도 토론의 여지는 있었지만, 개념들은 종종 견고했습니다. 데브옵스는 소프트웨어 개발을 지배해온 '그냥 토스하고 지나가는' 마인드를 종결시킬 낙원을 약속했습니다. 클라우드 엔지니어링은 "CapEx를 OpEx로 변환하자"라는 구절을 약속했는데, 현재로서는 듣지 못할 수 있겠지만 그 당시에는 (일부 진로지향적인 사람들에게) 이해할 만한 의미가 있었습니다. 사이트 신뢰성 엔지니어링은 아마도 여러분들이 중요한 지표를 추적하고 최적화를 목표로 할 필요가 있다는 주장을 했습니다. 구체적인 부분에 대해 논쟁할 수 있겠지만, 많은 사람들이 이러한 아이디어들이 합리적이라고 동의했습니다. 단 이를 실현하는 것은... 어려웠지만요.
현대 기술 열풍의 합리성에 대해선 조금 의심스럽습니다. 이른바 옛날 일들은 주로 일을 처리하는 데 중점을 두었습니다. 중요한 것, 그 무엇보다 중요한 것은 "배달"이었습니다. 항상 완벽하지는 않았고, 이 방식은 종종 작업을 지원할 프레임워크(프로세스, 자동화 등)를 개선하는 데 충분한 시간을 할애하지 못하게 했습니다. 그러나 제가 전달한 가치는 보통 쉽게 측정할 수 있었습니다: 일부 서버 빌드, 환경 설정, 계정 생성 프로세스 자동화 등이 그것이었습니다. "배달"이란 새로운 것을 제공하는 것과는 다르다는 점에 주의하세요. "일을 처리하는" 것이란 제품을 위한 새로운 환경을 구축하거나 기존 환경을 업그레이드하는 것과 같이 여러 가능성이 있습니다.
웹스케일 프로세스
어느 순간, DevOps에 중점을 둔 팀으로 자청하는 조직과 협업하게 되었습니다. 초기 프로젝트 중 하나는 우리의 단일 AWS 계정에 클라우드 모니터링 솔루션을 배포하는 데 도움을 주는 일이었습니다. 구체적인 사항은 기억이 나지 않지만, 이 토론을 위해 Cloud Custodian을 선택한 것으로 가정하겠습니다.
Cloud Custodian을 사용해본 적이 없다면, 이 도구는 클라우드 리소스를 모니터링하고 클라우드 계정을 자동으로 "정리"할 수 있는 훌륭한 도구입니다. 리소스를 삭제하거나 가상 머신을 끄는 등의 작업을 수행하여 클라우드의 건강을 유지하기 위한 다른 조치들을 취할 수 있습니다. 배포 모델은 꽤 간단합니다: VM이나 컨테이너에서 실행할 수 있는 간단한 응용 프로그램입니다. 정책은 코드로 작성되며 이상적으로는 인프라를 코드로 관리하는 방법(IaC)을 최적화합니다.
이 프로젝트의 초기 계획 논의 중에 이루어진 대화를 선명하게 기억합니다:
나: "알겠어, 모두들, Cloud Custodian을 스케줄된 람다 함수로 배포하고 상대적으로 간단한 설치 절차를 문서화할 수 있어. 그럼 우리는 Git 리포에서 정책을 로드하는 프로세스를 자동화할 수 있고 그럼 모든 것이 준비될 거야."
이는 "자동화할 항목"의 계층에서 꽤 합리적으로 보였다. Cloud Custodian을 배포하는 것은 일회성 활동이다. 설치하고 나면 그냥 잊어버리면 되는 것이다. 정책을 로드하는 것은 계속되는 작업이며 자동화하기에 이상적이었다. 우리는 걱정해야 할 AWS 계정이 하나 뿐이었기 때문에 가로 확장 고려 사항이 없었다.
지금까지 있던 사람 중 한 명이 나와 함께 말했다: "음, 우리는 Cloud Custodian 자체의 배포 프로세스도 자동화해야 해."
아, 나는 아직 새로운 사람이었다. 이곳에서는 모든 것이 자동화되어야 했다. "모든 것이 X 용어여야 한다"는 현상은 현재 매우 흔한 일이며 종종 5명의 유료 고객을 위한 자바스크립트 앱을 지원하기 위한 서로 연결된 서비스 미로를 포함한 코믹한 "모든 것이 마이크로서비스로 배포되어야 한다" 아키텍처로 이어진다.
그래서 결과적으로 우리가 한 일은 무엇인가요? 한 번만 수행할 작업에 대해 생각할 수 있는 가장 합리적인 일을 했어요. 우리는 그것을 극도로 자동화했어요. 다음과 같은 지루하고 웹 규모로 확장되지 않는 프로세스를 가져와서:
- IAM 역할 생성
- Cloud Custodian 코드가 포함된 람다 함수 생성
- 함수 배포
- 프로세스 문서화
그리고 이것을 훨씬 더 웹 7.0 수준의 일련의 작업으로 변형했어요:
- 새 저장소 설정
- 저장소에 필요한 모든 권한 구성
- 원하는 IAM 역할 및 람다 함수를 생성하는 코드 작성 (테라폼? 파이썬? 기억이 가물가물해요)
- 필요할 때 코드 문제 해결
- (아무도 관심 없을 미래 고려) AWS가 IAM을 다섯 번째 재발명해야 한다고 결정할 때 필요에 따라 코드 업데이트 및 유지 관리
- 빌드 파이프라인 작성하여 이 코드를 릴리스 아티팩트로 패키징
- 파이프라인 문제 해결. CI/CD 파이프라인을 작성한 사람에게 물어보면 파이프라인 디버깅의 악몽에 대해 들을 수 있어요.
- 배포 파이프라인 작성하여 코드를 람다로 배포
- 파이프라인 문제 해결. CI/CD 파이프라인을 작성한 사람에게 물어보면 파이프라인 디버깅의 악몽에 대해 들을 수 있어요.
- 파이프라인이 AWS와 통신하기 위한 필요한 모든 클라우드 자격 증명이 있는지 확인
- (아무도 관심 없을 미래 고려) 때로는 인증 자료 회전
- (아무도 관심 없을 미래 고려) 클라우드 인증 기법은 아무것도 영원하지 않기 때문에 완전히 인증 메커니즘을 교체하기도 해야 해요.
현재 시스템을 구축하는 매우 흔한 방법입니다. "자동화 우선" 버그는 엔지니어들이 현재 존재하지 않는 문제에 최적화하기 위해 수백 시간을 투자하여 자동화 또는 아키텍처(특히 마이크로서비스)를 구축하는 미친 상황을 초래합니다. 일단 정말 살펴보면 엄청나게 복잡한 빌드 파이프라인이나 마이크로서비스 맵을 보면, 루브 골드버그가 뛰어난 클라우드 아키텍트가 되었을 것이라고 생각할 수밖에 없습니다.
다음은 모자를 청소하는 루브 골드버그 머신의 이미지입니다. 아마도 여러분의 마이크로서비스 애플리케이션을 위한 서비스 호출 그래프와 닮았을 겁니다:
그래, 그러지만...
청중들 사이에서 불안한 움직임이 보이고, 당신의 마음을 엿볼 때, 웹스케일 사고의 표면 아래에서 끓고 있는 이의소리조차 들을 수 있습니다:
"안소니야! 코드를 작성하고 자동화하면 한 번만 하고도 수백 개의 AWS 계정에 배포할 수 있어! 마이크로서비스로 시작하면 스케일 걱정은 안 해도 돼!"
이것이 대부분의 현대 "패턴"의 핵심을 인코딩하고 있습니다: 조기 최적화가 최고의 실천법이 되어버렸습니다. 루브의 모자 세탁기는 아마도 많은 모자를 청소할 수 있겠지만, 그 비용은 무엇일까요? 우리는 이러한 접근법들의 유지보수 부담을 고려하지 못하는데요:
- 어느 순간에는 코드(Terraform 모듈 등)가 오래된 상태가 될 것입니다.
- 어느 순간에는 파이프라인 정의 파일이 오래된 상태가 될 것입니다. 특정 컨테이너 이미지가 폐기될 수도 있고, 파이프라인 구문이 변경될 수도 있으며, 많은 다른 유지보수 문제가 발생할 수 있습니다.
- 어느 순간에는 클라우드 제공업체와의 인증 방법이 변경될 것입니다.
- 실제로 복잡한 시스템을 유지하는 것은... 복잡합니다.
우리는 유지보수에 대한 이의를 매우 획일적으로 대수롭지 않게 대하고 있습니다. 때로는 매우 현실적인 단점을 무시하고 (최신 Kubernetes 버전이 이미 오래된 상태이고 인플레이스 업그레이드가 아마도 작동하지 않을 것입니다.) 어떤 의심스럽고 명확히 양적으로 측정되지 않은 혜택(확장 가능할 것이다!)을 선호하기 때문에 이런 오류가 우리를 휩쓸고 있습니다. 이 헛된 논법은 여러분의 절친이 "아마 언젠가 유료 기술을 제공하게 된다면 더 나은 카메라가 필요할지도 몰라"며 아마추어 사진촬영을 즐겨 하기 위해 3500달러짜리 카메라를 샀던 친구를 떠올려보세요. 이것은 단기 획득을 위한 장기 대비도 아니며 그 반대도 아닙니다. 이것은 장기 및 단기 대비(유지보수성, 복잡성 등)를 만들어 낸 후에 실현되지 않을 수도 있는 이득(확장 가능성, 반복성 등)을 위한 것입니다.
영향
이 모든 것이 최신 유행을 비난하는 고착된 관리자의 발언과 닮은 점이 많다고 생각될 수도 있습니다. 그러나 이러한 변화가 우리 산업에 실제로 부정적인 영향을 미친다고 생각합니다. AWS Well-Architected Framework와 같은 업체 중심의 미관에 빠지거나 웹 앱을 배포하려면 전체 Kubernetes 클러스터를 실행하기 위해 반드시 반 다섯 개의 마이크로서비스가 필요한 복잡성과 같은 부분에서 복잡성이 이어졌습니다. 사실은 점점 더 일반화할 수 있는 시스템을 구축하는 것이 점점 어려워지고 있다는 것입니다. 마치 호텔 캘리포니아처럼 말이죠: 아무 때나 체크아웃할 수 있지만, 결코 떠날 수 없습니다.
이젠 이메일을 보내기 위해 API 바인딩이 필요하고 메시지를 대기열에 놓는데 세바퀴 다섯 개의 마이크로서비스가 필요한 경우, 그리고 클라우드 제공 업체의 멋진 NoSQL 데이터베이스에서 일부 메타데이터로 이메일을 사용자 정의하여 마지막으로 메시지를 보내야 하는 경우, 공용 클라우드를 나간다는 생각은 버리세요. 이런 잘 해체된 마이크로서비스 애플리케이션은 이제 렐피의 혀처럼 Kubernetes에 꽉 붙어 버렸습니다. 우리는 포터블한 애플리케이션을 작성하는 능력을 잃었으며 이제 대부분의 기관이 "멀티클라우드"에 대해 이야기하는 사실에 대해 아주 좋은 유머적 센스를 잃어 버렸습니다.
또한 제 경험상으로는 많은 사람들이 기술의 기초적인 작동 방식을 잃어버린 것 같습니다. 컨테이너는 시스템에서 실행되는 프로세스일 뿐인데 신비롭고 마법 같은 시스템으로 여겨집니다. 느린 데이터베이스 쿼리의 문제 해결은 특히 선별적으로 계획된 어두운 예술로 여겨집니다. 많은 사람들은 누군가에게 그 모든 운영적인 것들을 걱정하게 두고, 당신의 조직이 NoOps의 천국에 도달하도록 해야 한다고 주장할 것입니다. 그러나 이는 비규모 조직의 경우 결코 사실이 되지 않습니다. 전에 경험으로 아는 조직과 함께 일했다가 호스팅된 NoSQL 데이터 저장소를 클라우드 제공 업체의 SaaS로 외주할 때, 이전 내부 전문성이 성능 문제를 해결하는 데 절박히 필요했던 기억이 선명하게 남아 있습니다. 왜냐하면 공급 업체는 자신들의 제공 제품의 행동을 설명할 수 없었기 때문입니다.
우리가 이러한 기술에 대한 실제적인 추론 능력을 잃어버릴수록, 시스템의 상태를 그리기도 어려워집니다. 이미 마이크로서비스의 시대로 인해 어려운데, 때때로 조직은 이를 피하기 위해 그들을 떠나는 것을 볼 수 있습니다. 충분한 추상화 수준은 시스템 전체 상태를 그만큼 더 저장할 필요성을 제거한다고 믿기 쉽습니다. 그러나 이것은 극도로 어려운 일이며 현대 소프트웨어 개발의 "메인에 코드를 넣고 단위 테스트가 작동하는 걸 바라는" 철학과 어울리지 않습니다. 사용자가 거의 의식하지 못하는 견고한 추상화를 유지하는 프로젝트는, 예를 들어 리눅스 커널과 같은 경우, 현대 웹 앱과 비교했을 때 서둘러서 천천히, 체계적으로 움직입니다. 분명히 이것은 두 접근 방식 중 어느 것이나 비판 또는 인정하는 것은 아닙니다. 오히려 제품 팀이 이미 주말에 빠른 언어인 러스트로 전체 코드베이스를 이주하기로 결정했기 때문에 견고하고 장기적인 안정적인 추상화에 대해 논의하는 것이 매우 어렵다는 사실에 대한 지적입니다.
또한 운영적인 부담이 줄이기 위한 재미있는 노력으로 운영적인 부담을 더 많이 더하고 있습니다. 모든 것을 자동화해야 했던 기억이 나시나요? 이로 인해 가장 간단한 애플리케이션도 배포하기 위해 러브크래프트식 파이프라인 정의와 재래식으로 유지되는 Makefile이 있는 거대한 젠킨스 환경을 갖춘 조직이 만들어진 것을 기억하시나요? 왜냐하면 당신이 구축한 시시피안 구성 관리 시스템 때문에 서버에 SSH로 접속해서 파일을 편집할 수 없다고 컴퓨터에 소리치는 것을 기억하시나요? 그냥 공급 업체별 서비스의 이질적인 덤프 트럭을 쌓고 계속 관리해야 하는 상황이 더 악화되어 가고 있다는 사실입니다.
문제 해결 주저하는 곤란
문제 해결의 용이성은 믿기 힘든 만큼 중요하며, 이에 충실한 섹션이 마련되어야 합니다. 복잡한 문제를 해결해 본 적이 없는 사람이라면, 해결과정에서 단순성을 강조하지 않았을 것이라고 확신합니다. 이것은 저의 신념이자 절대적인 원칙입니다. 만약 당신이 도출한 해결책이 극도로 복잡하게 구성돼 있다면, 그것이 좋은 해결책이 아닐 가능성이 높습니다. 이는 당신의 잘못일 수도 있습니다. 당신은 기관의 기술적, 조직적 한계 내에서 활동하고 있을 수 있습니다. 만약 모두가 마이크로서비스를 사용한다면, 당신이 단순한 이메일을 몇백 줄의 코드로 처리할 수 있다고 생각하는 것은 어리석은 행동일 것입니다. 대신 20개의 서로 연결된 JSON 웹 서비스로 처리해야 할지도 모릅니다.
문제 해결과 관련된 도구 제공은 유용하지만, 가장 복잡한 문제 해결에는 충분하지 않습니다. 도구가 실패할 때 깊은 점검이 가능하도록 기반이 충분히 단순해야 합니다. 이 문제는 추상화 수준이 높아질수록 더욱 참된 말로 전해집니다. 대부분의 현대적인 "클라우드 네이티브" 기술은 단순성을 약속하면서 이해하기 어려운 오류 메시지를 특정 클라우드에서만 해독할 수 있는 로깅 채널로 내뿜으며 무심한 주니어 엔지니어들을 고통스럽게 만들고 있습니다.
이 현상은 "클라우드 네이티브" 커뮤니티에서 웃기게 드러납니다. 일반적으로 지원되는 클라우드 아키텍처 다이어그램은 루브 골드버그 카툰과 거의 구별하기 어렵습니다.
간단한 웹사이트를 호스팅하고 사용자 가입 및 로그인을 구현하고 싶으세요? 실제로 해야 할 일은 100가지 함수 모음을 작성하고 함수를 실행할 수 있는 플랫폼에서 실행하는 것입니다. 앞단은 A/B 테스팅을 기반으로 적절한 백엔드 함수로 트래픽을 안내하는 레이어 7 로드 밸런서로 구성된 플랫폼을 사용하면 됩니다. 결과는 무한으로 확장 가능한 NoSQL 데이터베이스에 저장하세요. 사용자에게 이메일을 보내지 마세요. 등록 요청을 대기열에 넣고 다른 서비스가 이를 처리하도록 하여 알림 서비스가 처리할 수 있도록 다른 대기열에 메시지를 생성하세요. 모든 정적 자산은 오브젝트 저장소에 저장하고 전 세계 CDN을 앞단에 두어 최대 속도로 제공하세요 (10MB 싱글페이지 애플리케이션을 서빙할 때 속도가 중요해집니다). 아직 고객이 없다는 사실을 무시하세요. 미래 성장을 위해 지금 설계하세요.
이런 설계를 디버깅해보세요. 클라우드 공급업체의 로깅은 보통 매우 형편없으며 매우 비십니다. 하나의 클라우드 서비스 이상과 상호 작용하기 시작하면 곤란해집니다. 이전에 문제를 해결하기 위해 로그 파일을 확인할 수 있었지만, 사용 중인 서비스가 필요한 데이터를 기록하지 않을 수도 있습니다. 행운을 빕니다!
마무리
평범한 회사는 예전에는 단일 앱을 작성하고 몇 대의 서버에 넣은 후 문제가 발생할 때 해결하는 방식으로 급격한 성장을 이루었습니다. 미래 성장을 염두에 둔 채로 작성할 수는 있지만, 단순한 애플리케이션에 복잡성을 가져오는 것이 거의 들리지 않았습니다. 지금은 업체 락인의 미로와 수백 시간을 새로운 서비스를 배우는 데 소비하며(그리고 아마도 지식 부족으로 인해 제작 버그를 도입할 수도 있습니다) 직면하고 있습니다.
그렇다면 제 주장은 무엇일까요? 이 긴 글을 쓰면서 자주 생각해봤습니다. 제 목표는 누군가를 클라우드, 쿠버네티스 또는 (확실히 아니었지만) 자동화에서 용서시키는 것이 아닙니다. 제 의도는 간단히 말하자면, 이 문제인 업계 트렌드를 가리키는 것입니다: $'기술' 구현이 그 자체가 목적이 되어, 기업이 궁극적으로 가지고 있는 진정한 비즈니스 목표에서의 산만함이 생겨난다는 점입니다. 그리고 저는 엔지니어링 면에서 그것이 깊이 불만스러운 것으로 생각합니다: LAMP 스택 웹 서버를 구축하는 것은 세상에서 가장 만족스럽지만은 않은 작업 중 하나입니다. 하지만 이 작업에서 구체적인 부분이 있습니다. 스케일, 성장, 효율 또는 성능을 심각하게 고민하는 우리는 제품을 실제로 만들고 뭔가를 완성하는 것을 잊고 너무 많은 시간을 운영에 쏟는다는 점을 잊지 말아야 합니다. 그리고 이 때문에 타파되어 버리게 될 것이라고 생각합니다.
그러니 오늘 무언가를 만들어 보세요. 다음에 누군가가 일회성 S3 버킷을 생성하려면 꼭 Git 리포지토리, 파이프라인, 커밋별 아티팩트가 포함된 자동 빌드 단계가 필요하다고 말하면, 그들에게 고요하라고 하세요. 위키 문서를 작성하고, 진정한 일을 해보세요.