운영 준비
코드 작성은 재미있을 수 있지만 안전하고 확장 가능하며 안정적인 방식으로 코드를 실행하는 것은 완전히 다른 기술입니다.
Read or listen to this story on Medium.
애자일 문화 구축 에서 논의한 것처럼 애자일 및 DevOps와 함께 빠르고 역동적인 소프트웨어 개발 시대가 도래했습니다.
이제 빠른 프로토타이핑을 저렴하고 쉽게 수행할 수 있지만 운영 준비 상태와 해당 프로토타입을 "생산 준비" 상태로 만드는 단계를 놓치는 경우가 많습니다. 이해 관계자가 좋아하는 실행 중인 프로토타입을 프로덕션이라고 부르는 것은 너무 쉬운 경우가 많습니다. 프로젝트는 종료되고 개발자는 다음 프로젝트로 이동합니다. 잠깐, 누가 새로운 솔루션을 지원할까요?
첫 번째 과제는 DevOps 서비스 팀 및 제품 소유권의 개념으로 해결될 수 있기를 바랍니다. 조직에서 응용 프로그램이나 서비스가 실행 중인 경우 누군가에게 중요해야 하고 인식하는 소유자가 있어야 합니다. 예, 많은 애플리케이션을 실행하려면 인적 자원이 필요하므로 적절하게 인력을 배치하십시오. 서비스 팀은 둘 이상의 서비스를 절대적으로 지원할 수 있지만 점차적으로 그들의 작업량은 적절하게 지원할 수 있는 것 이상으로 증가할 것이라는 점을 명심하십시오.
운영 준비는 운영 팀이 새로 완성된 솔루션 및 지원 인프라를 운영하고 유지 관리하는 데 필요한 도구, 기술 및 문서를 확보하도록 하는 구조화된 프로세스입니다 . 따라서 프로젝트 계획 및 실행 단계의 초기에 운영 준비 프로세스를 시작하는 것이 중요합니다.
항상 패치가 필요하다는 점을 명심하십시오. 서버리스 솔루션을 사용하더라도 이전 인터프리터 버전은 항상 더 이상 사용되지 않으며 변경 및 테스트가 필요합니다. 현실적입니다. 이것은 마술이 아니며 실제로 서버를 사용하지 않는 것도 아닙니다. 다른 사람의 서버에서 실행되고 있을 뿐입니다. 공동 책임 모델의 기준은 움직일 수 있지만 궁극적으로 솔루션의 사이버 보안 규정 준수에 대한 책임은 귀하에게 있습니다.
DevOps 사례
몇 년 전 저는 회사의 Tomcat 인프라를 유지 관리하는 책임을 맡았고 한 개발자가 배포하도록 제공한 .war 파일이 다른 개발자가 보낸 파일의 약 두 배 크기라는 사실을 알아차리기 시작했습니다. 다른 개발자들과 달리 그의 워크스테이션 컴파일러 설정이 압축되지 않은 것으로 밝혀졌다. 그의 설정에서 다른 것은 무엇이었습니까?
결론은 코드를 로컬로 컴파일하지 마십시오. 빌드 파이프라인을 사용할 수 없다면 최소한 개발자가 공유 시스템에서 코드를 컴파일하도록 하십시오.
규칙 #1: 로컬 워크스테이션에서 프로덕션 코드를 컴파일하지 마십시오.
같은 줄을 따라 코드 한 줄을 변경하지 않아도 상관 없습니다. 새 바이너리를 다시 컴파일하면 이제 완전히 다시 테스트해야 하는 완전히 새로운 릴리스입니다. 이를 위해 특정 환경(예: Dev 빌드가 Prod 빌드와 다름)에 대한 코드 컴파일은 확실히 피해야 하는 안티패턴입니다. 일반 패키지를 컴파일하고 배포 중에 환경별 매개변수를 전달합니다. 모든 환경에 동일한 패키지를 배포해야 합니다.
규칙 #2: 특정 환경에 대한 코드를 컴파일하지 마십시오.
동일한 패키지를 배포하더라도 서버 드리프트는 또 다른 일반적인 문제입니다. 시간이 지남에 따라 OPS 팀이 얼마나 훌륭하고 헌신적이든 Dev 서버는 Prod 서버와 정확히 같지 않을 것입니다. 그들은 다른 시간에, 다른 사람에 의해 패치될 수도 있고, 인프라 구성이 다를 수도 있습니다. 이러한 약간의 차이는 때때로 설명할 수 없는 방식으로 솔루션의 안정성과 동작에 영향을 줄 수 있습니다.
서버 드리프트를 방지하는 가장 좋은 도구는 실제로 배포를 "도커화"하는 것입니다. Docker 이미지(또는 동등한 솔루션) 빌드는 실제로 배포에 라이브러리 및 종속성을 포함하는 가장 좋은 방법 중 하나입니다. Dev 서버에 Prod 서버와 다른 Java 버전이 있는지 여부는 더 이상 중요하지 않습니다. 필요한 Java 버전은 코드와 함께 컨테이너 이미지 내부에 패키징됩니다. 이것은 진정으로 휴대용 배포를 가능하게 하며, 이를 위해 서버는 훨씬 덜 중요합니다. 명명된 서버에 의존해서는 안 됩니다(서버 이름이 'prd_'로 시작하는 경우 ...). 가상 서버는 동적이며 ASG의 일부로 필요에 따라 재구성하거나 확장할 수 있습니다. 마이크로서비스는 동적이며 배포 매개변수는 환경을 하나로 묶는 접착제입니다.
규칙 #3: 서버는 애완 동물이 아니라 소입니다. 이름을 지정할 수 없습니다.
나는 한때 Docker-compose 파일의 시작 부분에 "apt-get update"를 넣은 개발자와 함께 일했습니다. 사이버 보안 관점에서 그의 노력에 박수를 보내지만 DevOps 관점에서는 이 행위가 "한 번 빌드하고 모든 곳에 배포"의 핵심 원칙에 어긋나기 때문에 두려웠습니다. 한 번 빌드되고 Docker 레지스트리에 저장된 똑같은 Docker 이미지가 오늘 Dev에 배포되고 다음 달에는 Production에 배포될 때 동일한 라이브러리를 갖지 않을 것임을 보장할 수 있습니다. 말이 안 되는 것처럼 보일 수 있지만 예측 가능성과 반복 가능성은 운영 준비태세의 두 가지 초석입니다. 그날 누가 코드를 컴파일하고 누가 배포했는지는 중요하지 않습니다. 결과는 동일해야 합니다. 가능하다면 CI/CD(지속적 통합 및 지속적 배포) 파이프라인의 일부로 빌드, 테스트 및 배포를 자동화하십시오.
규칙 #4: 빌드 및 배포 프로세스에서 예측 가능성과 반복성을 위해 노력하십시오.
머피를 탓하지마
"머피의 법칙"은 "잘못될 수 있는 것은 무엇이든 잘못될 것이고 최악의 시간이 될 것입니다."라고 말합니다. 많은 다른 것들에 적용될 수 있는 이 격언은 확실히 프로덕션 환경에서 IT 솔루션을 실행하는 데 적용됩니다.
"희망은 전략이 아니다"
일이 깨지고 실수가 생길 것이라고 예상하십시오. 솔루션을 "프로덕션"이라고 부르기 전에 이해 관계자와 Dev 및 Ops(또는 DevOps) 팀은 솔루션에 대한 공식적인 "Operational Readiness Review"를 개최해야 합니다. 인터넷에서 몇 가지 체크리스트를 사용할 수 있으며 AWS도 고객에게 체크리스트를 제공했습니다 . 간단히 말해서 팀은 제안된 솔루션의 고가용성과 재해 복구 옵션에 대한 결정을 내려야 합니다. 이러한 질문에 대한 "모든 경우에 적용되는" 답변은 없습니다. 해당 솔루션이 조직에 얼마나 중요한지, 다운타임 비용은 어느 정도 주관적이고 해당 문화에 적합합니다. 서버가 다운되고 전체 데이터 센터가 물에 잠길 수 있으며 전체 지역이 핵 공격으로 휩쓸릴 수 있으며 유성 충돌 후 전체 대륙이 오프라인 상태가 될 수 있습니다. 위험 허용 범위와 비용 및 비용 사이의 균형을 찾아야 합니다. 복잡성이 추가되면 위험이 추가된다는 사실을 알고 해결 방법의 복잡성. 답을 얻기는 쉽지 않으며, 이는 반복적인 토론이 필요할 수도 있지만 대화는 충분히 가치가 있습니다.
고가용성은 역경에 직면하여 즉시 장애 조치하거나 확장할 수 있는 솔루션을 설계하는 기술이며, 재해 복구는 백업을 구현하고 수용 가능한 시간 내에 어떤 방식으로든 솔루션을 복원할 수 있는 기술입니다. 둘 다 상호 배타적이지 않습니다. 고가용성 솔루션은 악의적이거나 우발적인 데이터베이스 삭제로부터 사용자를 보호하지 못합니다. 변경 사항은 단순히 모든 노드에 복제됩니다. 이 경우 백업 또는 지연 사이트에서 복원이 필요합니다. 백업 사이에 손실을 감당할 수 있는 데이터의 양은 얼마입니까? 다운타임이 얼마나 귀하의 브랜드에 영향을 미치고 고객을 경쟁에 참여하게 합니까?
안정적이고 잘 정의된 배포 파이프라인, 잘 문서화된 솔루션( 텍스트에서 다이어그램 생성 참조) 및 충분한 인력을 갖춘 지원 구조는 모두 이 방정식에서 매우 중요한 요소입니다.
기능 및 회귀 테스트는 항상 배포 프로세스의 일부여야 하며 부하 테스트 및 내구성 테스트도 있어야 합니다. 정확히 동일한 템플릿에서 배포된 가상 머신이 나머지와 크게 다르게 동작하는 것을 보았지만 불행히도 이것은 정확한 과학이 아니며 새 시스템이 실제 작업 부하를 수용하도록 허용하기 전에 적절한 상태 확인을 구현합니다. 일찍 테스트하고 자주 테스트하되 의미 있는 경고를 생성합니다. 다운스트림 종속성의 연쇄 효과에 주의하십시오. 다른 팀에 의해 발생한 중단으로 인해 장애가 발생한 경우 팀에 경고를 보내야 합니까?
대기 중인 직원을 압도하지 않도록 두 가지 수준의 모니터링 및 경고를 구현하는 방법을 고려하는 것이 좋습니다. 각 구성 요소의 각 인스턴스를 모니터링하는 것은 유용하지만 특히 구성 요소의 여러 인스턴스가 실행 중인 분산 시스템의 경우 한 인스턴스를 잃어도 한밤중에 누군가를 깨울만한 가치가 없을 수 있습니다. 아침이면 충분합니다. 그러나 종단 간 테스트가 실패하는 경우 임의의 사용자가 일상적으로 취하는 작업을 유사하게 모방한 테스트가 적절하므로 경고가 적절합니다.
규칙 #5: 예상치 못한 일을 예상하라
"단순함은 궁극의 정교함이다."
지역 로드 밸런싱 및 캐싱이 포함된 읽기 전용 데이터베이스 복제본을 사용하여 여러 가용 영역 및 데이터 센터에 걸쳐 확장할 수 있는 솔루션의 고가용성을 결정했습니다. 상황은 여전히 잘못될 것입니다.
또한 솔루션과 해당 동작 및 성능에 대한 가시성을 확보하기 위해 메트릭 및 모니터링을 구현해야 합니다. 주요 구성 요소와 종단 간 사용자 경험을 모니터링합니다. 서비스가 매일 반환하는 200, 400 및 500 반환 코드 수에 대한 일일 보고서를 받고 이상 사항을 조사하십시오.
나는 즉시 오류를 던지기 시작한 새로운 버전의 처리 서비스를 배포한 적이 있습니다. 새 버전을 취소하고 오류 로그를 조사했습니다. 처리 컨테이너 중 2개가 중복된 고유 트랜잭션 ID를 발행하여 다른 다운스트림 종속 서비스를 혼동했습니다. 어떻게 이것이 가능했을까요? 개발자는 컨테이너의 배포 시간에 의존하는 고유 ID를 발급하기 위해 알고리즘을 사용했고 두 개의 컨테이너가 정확히 같은 밀리초 내에 배포되었습니다. 솔루션은 간단했습니다. 컨테이너 ID와 배포 타임스탬프를 사용하여 고유한 ID를 발행했지만, 이런 일이 일어날 확률은 얼마나 될까요?
마이크로서비스를 설계할 때는 실패를 대비하여 설계해야 합니다. 의존하는 서비스가 실패할 수 있음을 항상 예상하십시오. 실패보다 더 나쁜 것은 서비스가 시간의 일부만 유효하지 않거나 혼란스러운 응답을 반환할 수 있다는 것입니다. 일이 실패할 것으로 예상하고 재시도를 구현하고 지수 백오프를 구현하십시오. 이미 문제가 있는 서비스를 압도하는 빠른 재시도 문제를 너무 많이 보았습니다. 오랜 시간 동안 재시도하면 종속 서비스의 중단이 며칠은 아니더라도 몇 시간 동안 지속될 수 있습니다. 스트레스 상황에서 모든 요청을 제대로 처리하지 않는 것이 더 나은지 아니면 제한된 수의 요청만 제대로 처리하고 다른 사용자에게 오류 메시지를 제공하는 것이 더 나은지 결정해야 합니다.
규칙 #6: 실패를 대비한 빌드
모든 것이 무너지고 인프라의 병목 현상을 제거하면 다음 병목만 드러날 것이며 팀은 배우고 개선할 것입니다. 그러나 이것은 당신의 문화가 그러한 실패를 허용하고 학습 기회가 되는 경우에만 일어날 수 있습니다. 사람들이 벽에 부딪히고 그 장애물을 극복하고 배우고 성장할 수 있는 흠 없는 문화를 만들어야 합니다. 예방할 수 있든 없든 모든 실수를 개인의 실패로 간주하면 "이런 일은 일어나지 않았다"는 문화가 발생하고 의심이 모든 사람을 압도합니다. 자신의 실패와 실수에 대해 열린 마음을 갖고 취약하고 부족함을 인정하면 모두가 하나의 조직으로 성장할 것입니다. 투명성이 핵심입니다.
물론 모든 정전에 대해 조사하고 적절한 근본 원인 분석(RCA)을 수행해야 하지만 명백하고 고의적인 인간의 실수가 아닌 한 "누가 이것을 했는가?"에 초점을 두어서는 안 됩니다. 그러나 대신 "그 과정이 어떻게 인간이 이런 실수를 하도록 내버려 두었는가?"에 대한 것입니다. RCA의 진정한 목표는 미래에 동일하거나 유사한 실수가 발생하지 않도록 하는 것이며, 이는 지속적인 개선 프로세스의 일부입니다. 물론 중단이 소프트웨어 또는 인프라 버그로 인해 발생한 경우 개발 팀에 피드백을 제공해야 합니다.
규칙 #7: 흠잡을 데 없는 문화 구축
실수를 하지 않는다면 충분히 어려운 문제를 풀고 있지 않은 것입니다. 그리고 그것은 큰 실수입니다.
일이 깨질 것임을 알기에 예상치 못한 것도 포용해야 합니다. Netflix는 무작위 중단에 직면하여 탄력성을 검증하기 위해 의도적으로 실패 및 결함 시나리오를 도입하는 분산 소프트웨어를 테스트하는 방법인 카오스 엔지니어링 을 개척한 것으로 유명합니다. 모든 사람이 Netflix가 하는 방식으로 프로덕션에서 "유인원을 실행할" 수 있는 것은 아닙니다. 그들에게 미치는 영향은 더 낮은 해상도로 영화의 몇 프레임을 제공할 수 있으며 실시간 금융 시스템에 대한 영향은 치명적일 수 있습니다. 자신의 환경에 맞게 조정하십시오.
IT 시스템에 대해 구체적으로 언급하지는 않지만 Nassim Nicholas Taleb의 Antifragile: Things That Gain from Disorder 는 읽을 가치가 있으며 탄력적인 마이크로서비스 구축에 가장 확실히 적용할 수 있습니다.
규칙 #8: 예상치 못한 일을 수용하라
“Antifragility는 탄력성이나 견고성을 넘어선 것입니다. 탄력성은 충격에 저항하고 그대로 유지됩니다. 안티프래그가 좋아집니다."
취약성을 완화하는 것은 선택이 아니라 필수입니다. 당연하게 들릴지 모르지만 요점을 놓치고 있는 것 같습니다. 취약성은 불치병처럼 매우 가혹하기 때문입니다. 패키지는 불리한 조건에서 깨지지 않고 적절한 조건이 복원되면 자체적으로 수정됩니다. 취약성은 래칫과 같은 속성, 손상의 비가역성을 가지고 있습니다.