Incident Library
적용된 필터 원인운영 실수모두 풀기검색어 없이 필터만 적용한 목록입니다. 최근 사례부터입니다.
추천 필터 검색하면 검색어에서 찾은 분류 값이 여기에 나옵니다.

그래프

  • 원인
  • 구성 요소
  • 증상
  • 기여 요인
  • 사례

사례7건

7건 중 1~5번째

  1. 증상

    새 temple 클러스터에 허브를 배포하던 엔지니어가 NFS 문제를 만나 prod 네임스페이스를 지웠는데 삭제가 멈춘 채 끝나지 않았다. 파드 목록을 보니 다른 클러스터의 사용자 파드가 잔뜩 있었다.

    촉발

    2i2c 엔지니어가 새 허브의 NFS 배포 버그를 우회하던 중, kubectl 이 LEAP 클러스터를 가리키고 있는 줄 모르고 prod 네임스페이스를 지웠다.

    원인
    구성 요소
    기여 요인
    감지

    네임스페이스를 지운 엔지니어가 삭제가 멈춘 것을 보고 파드 목록을 확인하다 다른 클러스터의 사용자 파드를 발견했고, 17:00 BST 에 장애를 선언했다. 모니터링 알림보다 먼저였다. 업타임 검사 실패 알림은 17:32 에 왔고 사용자의 404 제보는 17:37 에 들어왔다.

    조치
    • prod 네임스페이스에 남아 있던 사용자 파드 하나를 지워 멈춰 있던 네임스페이스 삭제를 끝냈다.
    • 재배포를 막고 있던 nfs-share-creator 잡을 종료했다.
    • 바뀐 NFS 서버 IP 주소로 prod 허브를 다시 배포했다.
    • 배포 도중 사용자가 서버를 띄우지 못하게 prod 인그레스를 지웠다.
    후속 조치
    • 장애 보고서를 쓴다.
    • "I deleted prod, what next?" 같은 상황에서 바로 볼 수 있는 짧은 장애 대응 문서를 쓴다.
    • jupyterhub-home-nfs 를 업그레이드하고 nfs-share-creator 잡을 없앤다.
    • deployer 시스템에 kubeconfig 컨텍스트가 중첩되는 것을 막는 보호 장치를 넣었다. 기본으로는 꺼져 있고 쓰는 사람이 켜야 동작한다.
    • 해당 엔지니어의 셸 설정을 바꿔 kubeconfig 컨텍스트를 더 쉽게 구분하게 했다.
    교훈

    쿠버네티스 리소스를 잃는 경우에 대비해 영구 스토리지를 Terraform 으로 따로 프로비저닝해 둔 설계 덕분에 사용자 데이터가 살아남았다. 반면 엔지니어에게 지금 어느 클러스터를 다루고 있는지 알려 주는 단서가 없었던 것이 실수로 이어졌다. 복구 방법을 알고 있어도 데이터 손실 위험을 확인해 줄 사람이 다른 시간대에 있어 재배포가 늦어졌다. NFS 배포의 순환 의존과 nfs-share-creator 잡도 복구를 늦췄다.

  2. 증상

    2023-01-11 14:22, Cloud Platform 팀원 한 명이 DockerHub 로그인이 실패하는 오류를 발견했다.

    촉발

    LastPass 대응 작업의 하나로 DockerHub 비밀번호를 바꿨는데, EKS 클러스터 노드와 Concourse 는 예전 비밀번호로 계속 로그인하고 있었다.

    원인
    구성 요소
    기여 요인
    감지

    14:22 에 Cloud Platform 팀원이 DockerHub 로그인 실패 오류를 직접 발견했다. 14:52 에는 Kuberhealthy 데몬셋 점검에서 클러스터도 이미지를 받지 못한다는 것이 드러났고, 14:54 에 사용자 보고가 들어왔다. 장애 선언은 15:17 이었다.

    조치
    • DockerHub 비밀번호를 EKS 클러스터 노드와 Concourse 가 아직 쓰던 예전 값으로 되돌렸다.
    • 보고한 사용자에게 물어 파드가 배포되는 것을 확인했고, 클러스터가 다시 이미지를 받는 것도 확인했다.
    후속 조치
    • DockerHub 사용자 이름과 비밀번호 대신 Cloud Platform 전용으로 만든 DockerHub 토큰을 쓰도록 바꿨다.
    • 업무 시간 밖에 DockerHub 자격 증명을 새 값으로 바꾸고 노드를 차례로 교체한다.
    교훈

    이 글은 교훈을 따로 적지 않았다. 후속 조치로는 DockerHub 사용자 이름과 비밀번호 대신 Cloud Platform 전용으로 만든 DockerHub 토큰을 쓰도록 바꿨다.

  3. 증상

    모니터링과 알림이 곧바로 울렸다. 알림 하나는 Patroni 페일오버를 가리켰다. GitLab.com 으로 가는 트래픽은 모두 5XX 오류로 끝났다.

    촉발

    엔지니어가 로컬 개발 환경에서 사내 도구로 일상적인 작업을 돌렸다. 로컬 배포나 롤백 도중 컨텍스트가 로컬 개발에서 운영으로 바뀌었고, 이때 잘 알려진 오픈소스 도구가 예상하지 못한 동작을 해 운영 환경에 변경이 들어갔다.

    원인
    구성 요소
    기여 요인
    감지

    모니터링과 알림 인프라가 곧바로 경보를 보냈다. 팀은 Consul 클러스터가 내려가 Patroni 클러스터에 영향을 주자마자 큰 장애가 난 것을 알았고, 근본 원인도 몇 분 안에 찾았다.

    조치
    • 지워진 Consul 릴리스를 운영에 다시 적용했다. Consul 클러스터가 올라오자 데이터베이스 클러스터가 회복했다.
    후속 조치
    • Kubernetes 배포 방식을 개선해 로컬 환경에서 운영 환경을 대상으로 위험한 배포 작업이 돌아갈 가능성을 줄인다. 개념 검증은 reliability 이슈 16875 에서 진행한다.
    • Teleport 를 Kubernetes 클러스터와 연동한다. 이렇게 하면 SRE 에게 기본으로 읽기 전용 역할을 줄 수 있어 실수로 운영 환경을 바꿀 위험이 줄어든다.
    교훈

    로컬 개발 환경에서 운영 클러스터에 접근할 수 있으면 도구가 컨텍스트를 예상과 다르게 바꾸는 순간 일상 작업이 운영 장애가 된다. GitLab 은 Kubernetes 배포 방식을 개선하고, Teleport 로 SRE 의 기본 권한을 읽기 전용으로 둘 수 있게 하면 이런 위험이 크게 줄어든다고 봤다. 알림과 원인 파악은 빨랐다. 지워진 릴리스를 다시 배포하는 데는 손으로 해야 할 일이 있었지만 비교적 빨리 끝났다.

  4. 증상

    2022년 6월 23일 18시 56분 PDT, UTC 로는 6월 24일 01시 56분에 여러 모델이 한꺼번에 오프라인이 됐다. 일부 파인튜닝 모델인 curie 와 davinci, 일부 Codex 베타 모델인 code-davinci-001 과 code-cushman-001, 일부 구형 GPT 모델인 curie, babbage, ada, 그리고 모든 Embeddings 모델이 응답하지 않았다.

    촉발

    사람의 실수로 운영 클러스터 하나에 파괴적인 작업이 실행돼 클러스터가 완전히 내려갔다. 안전장치에 예상하지 못한 구멍이 있었고, 그 작업이 어떤 영향을 주는지 알려 주는 정보가 미묘하게 빠져 있었다.

    원인
    구성 요소
    기여 요인
    조치
    • 내려간 클러스터가 맡던 모델을 남은 두 운영 클러스터에 다시 배치했다.
    • 클러스터 구성 중 AKS 연결이 끊기자 Azure 지원팀과 함께 VPN 링크를 다시 만들었다.
    • Azure Private Link 연결이 다시 끊기자 Azure 지원팀과 우회 방법을 만들었다.
    • 업그레이드한 쿠버네티스 버전이 인그레스와 호환되지 않자 클러스터를 지우고 처음부터 다시 만들었다.
    • 05시 30분부터 06시 30분 PDT 사이에 다시 만든 클러스터로 트래픽을 옮겼다.
    후속 조치
    • 이번 클러스터처럼 운영에 꼭 필요한 인프라가 실수로 바뀌지 않도록 검사와 잠금을 더한다. 기존 보호 장치는 범위가 좁아 이번 같은 클러스터 장애를 막지 못했다.
    • 실행 중인 작업이 더 잘 보이게 하고, 시스템 구성 요소의 이름이 글자만 봐도 서로 확실히 구별되도록 바꾼다.
    • AKS 네트워크 연결 문제를 Azure 와 계속 조사해 새 클러스터 작업이 다시 방해받지 않게 한다.
    • 이번에 드러난 클러스터 장애 유형을 플레이북에 넣고, 새 클러스터와 인프라를 구성하는 절차를 고친다.
    • 쿠버네티스를 체계적으로 업그레이드하고, 앞으로 버전이 뒤처지지 않도록 업그레이드할 시간을 따로 확보한다.
    • 파인튜닝 모델을 여러 클러스터에 나눠 배치하고, 클러스터 사이 복제를 더 자동으로 하는 방법을 만든다.
    • Azure Blob Storage 를 분산하고 복제해 파인튜닝 모델을 더 빠르고 안정적으로 불러올 수 있게 한다.
    • Azure Blob Storage 병목을 덜어 줄 노드 간 캐시의 배포를 마무리한다.
    • 모델 가중치를 저장하는 방식을 바꿔 더 효율적이고 빠르게 불러올 수 있게 한다.
    교훈

    클러스터 하나를 통째로 잃으면 평소의 여유 용량이 한 번에 바닥난다. GPU 처럼 몇 시간 안에 늘릴 수 없는 자원을 쓰는 서비스는 남은 클러스터만으로 완전히 되살릴 수 없다. 운영 클러스터를 지울 수 있는 작업에는 그 영향을 분명히 보여 주는 정보와 잠금이 있어야 한다. 쿠버네티스 버전이 뒤처져 있으면 급하게 하는 업그레이드가 인그레스 호환성 같은 새 문제를 만든다. AKS 는 다운그레이드가 되지 않아 되돌릴 수도 없었다. 대용량 모델을 처음부터 다시 올리는 상황에서는 스토리지 대역폭과 캐시 무효화가 복구 시간을 좌우했다.

  5. 증상

    옛 노드 세 개를 하나씩 새 StorageClass 의 볼륨으로 바꾸다가 마지막으로 elasticsearch-0 파드를 지우고 다시 띄웠다. elasticsearch-0 안에서 `_cat/nodes` 를 조회하자 자기 자신 하나만 마스터로 나왔다.

    촉발

    옛 PVC 와 파드를 지운 뒤 elasticsearch-0 이 새 StorageClass 의 빈 볼륨을 받아 다시 시작했다.

    원인
    구성 요소
    기여 요인
    감지

    마지막으로 0번 파드를 교체한 뒤 엔지니어가 elasticsearch-0 과 elasticsearch-1 안에서 각각 `_cat/nodes` 를 조회했다. 두 결과가 서로 다른 노드 목록과 다른 마스터를 보여 스플릿 브레인을 알아챘다.

    조치
    • 데이터를 실시간으로 쓰는 워커의 디플로이먼트 세 개를 0으로 줄여 새 데이터가 갈라진 클러스터로 들어가지 않게 했다.
    • ConfigMap 의 initial_master_nodes 를 elasticsearch-0, elasticsearch-1, elasticsearch-2 로 바꾸고 StatefulSet 에서 cluster.initial_master_nodes 환경 변수를 지웠다.
    • 롤링 업데이트가 도는 동안 디스커버리용 elasticsearch Service 를 YAML 로 저장한 뒤 지우고, 0번 파드의 PVC 도 지웠다.
    • ConfigMap 의 initial_master_nodes 를 elasticsearch-3, elasticsearch-4, elasticsearch-5 로 바꾸고, 0번 파드의 빈 PVC 를 만든 뒤 파드 6개를 모두 지워 다시 띄웠다.
    • 저장해 둔 YAML 로 Service 를 다시 만들었다. 노드 6개가 한 클러스터로 모였고 green 이 아닌 인덱스는 0개였다.
    후속 조치
    • ConfigMap 의 initial_master_nodes 를 원래 값으로 되돌리고 모든 파드를 한 번 더 재시작한다.
    • 모든 샤드를 0, 1, 2번 노드로 옮기고 클러스터를 노드 6개에서 3개로 줄인다.
    • 손으로 바꾼 내용을 모두 저장소에 커밋한다.
    교훈

    운영 데이터를 옮길 때는 설정 오류, 데이터센터 장애, 네트워크 단절처럼 무언가 잘못될 수 있다는 전제로 준비해야 한다. 이번에 쓴 다운타임 없는 절차는 예상하지 못한 문제에 약했다. 팀은 ConfigMap 을 꼼꼼히 확인했지만 Helm 차트 템플릿이 StatefulSet 에 넣는 환경 변수는 보지 않았다. cluster.initial_master_nodes 가 파드 하나로 고정된 상태에서 그 파드가 빈 볼륨으로 다시 뜨면 기존 클러스터에 합류하지 않고 새 클러스터를 만든다.

내 클러스터에도 있는지 확인하기

이 7건에서 가장 많이 나오는 구성 요소: 인그레스 컨트롤러, 노드 풀. kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이런 틈을 점검합니다. 점검 항목의 근거는 이 라이브러리와 같은 공개 보고서입니다.

원인별1

운영 실수7건

  1. IL-0095 엔지니어가 kubectl 이 다른 클러스터를 가리키는 줄 모르고 prod 네임스페이스를 지워 LEAP JupyterHub 가 약 1시간 동안 멈췄다.
    2i2c2025
  2. IL-0018 DockerHub 비밀번호를 바꾼 뒤 Concourse 와 EKS 클러스터 노드가 Docker Hub 에서 이미지를 받지 못했다
  3. IL-0207 로컬 개발 환경에서 돌린 작업이 운영 컨텍스트로 넘어가 Kubernetes 클러스터의 Consul 릴리스를 통째로 지웠고, Patroni 가 무너져 GitLab.com 전체가 5XX 오류를 냈다.
    GitLab2022
  4. IL-0115 OpenAI 의 운영 AKS 클러스터 세 개 중 하나가 사람의 실수로 통째로 내려가 Codex, Embeddings, 구형 GPT 모델과 파인튜닝 모델이 최대 12시간 동안 제대로 응답하지 못했다
    OpenAI2022
  5. IL-0197 Elasticsearch StatefulSet 을 새 퍼시스턴트 볼륨으로 옮기던 중 빈 볼륨으로 다시 뜬 elasticsearch-0 이 혼자 새 클러스터를 만들어 스플릿 브레인이 났다.
    Palark2021
  6. IL-0089 테스트 클러스터 삭제 스크립트가 운영 클러스터 live-1 을 대상으로 실행돼 인그레스 컨트롤러, 모니터링, 인증서 구성 요소가 지워지고 사용자 서비스에 접속할 수 없게 됐다.
  7. IL-0054 GKE 에서 옛 노드 풀을 드레인하자 로드밸런서가 ingress-nginx 파드가 없는 새 노드만 가리켜 클러스터의 모든 인그레스 트래픽이 끊겼다