Skip to content

Part 9: Calico 운영 가이드 ​

검토 기준: Calico 3.32.2 / Operator 1.42.6 / Calico의 Kubernetes 테스트 범위 1.34–1.36. 마지막 업데이트: 2026년 9월 12일

개요 ​

이 문서에서는 Calico의 설치, 모니터링, 문제 해결, 업그레이드 및 백업/복구에 대한 운영 가이드를 제공합니다. 프로덕션 환경에서 Calico를 안정적으로 운영하기 위한 모범 사례를 다룹니다.

설치 가이드 ​

플랫폼에 맞는 구성과 하나의 설치 소유 경로를 사용하세요. 다음 예제는 전체 Calico CNI를 사용하는 새 자체 관리 Linux 클러스터의 Iptables/VXLAN 구성입니다. 중복되지 않는 Pod CIDR, 호환 노드 OS/커널, Kubernetes API 접근, 대상 노드 사이 underlay UDP 4789 연결을 준비해야 합니다. VPC CNI policy-only 구성이 아니며 EKS는 Part 8을 사용하세요. 다른 overlay/BGP 설계는 네트워킹 모드를 먼저 검토하세요.

Tigera Operator 매니페스트 ​

Calico 3.32에서는 operator 매니페스트와 별도로 Calico CRD가 필요합니다.

bash
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.32.2/manifests/v1_crd_projectcalico_org.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.32.2/manifests/tigera-operator.yaml
kubectl wait --for=condition=Available deployment/tigera-operator \
  -n tigera-operator --timeout=300s

다음을 installation.yaml로 저장하고 예제 Pod CIDR을 준비한 클러스터에 맞게 변경하세요. Operator의 자동 감지를 사용하려면 MTU를 생략합니다. 실제 경로 측정을 임의 MTU 값으로 대체하지 마세요.

yaml
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
  name: default
spec:
  variant: Calico
  cni:
    type: Calico
  calicoNetwork:
    bgp: Disabled
    linuxDataplane: Iptables
    ipPools:
    - cidr: 10.244.0.0/16
      blockSize: 26
      encapsulation: VXLAN
      natOutgoing: Enabled
      nodeSelector: all()
    nodeAddressAutodetectionV4:
      kubernetes: NodeInternalIP
  nodeUpdateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
---
apiVersion: operator.tigera.io/v1
kind: APIServer
metadata:
  name: default
spec: {}
---
apiVersion: operator.tigera.io/v1
kind: Goldmane
metadata:
  name: default
spec: {}
---
apiVersion: operator.tigera.io/v1
kind: Whisker
metadata:
  name: default
spec: {}
bash
kubectl apply -f installation.yaml

이 VXLAN 예제는 BGP를 비활성화합니다. 선택한 구성에서 BGP를 활성화한 경우에만 BGP 진단이 의미가 있습니다. Calico API 서버와 Goldmane/Whisker는 OSS 컴포넌트입니다. 현재 OSS flow log 가이드는 관측성 기능을 tech preview로 표시하므로 운영 의존성을 결정하기 전에 이 상태를 평가하세요.

측정으로 지원되는 override가 필요하다고 판단하기 전까지 컴포넌트 자원과 Typha 규모는 operator가 관리하도록 두세요. 임의 메모리 제한, 지원되지 않는 typhaDeployment.spec.replicas/minReadySeconds, 레거시 componentResources 목록의 KubeControllers 항목은 프로덕션 구성이 아닙니다. 버전별 Installation API와 아키텍처, 확장을 참고하세요.

대안: Helm ​

Helm 차트는 같은 operator를 설치합니다. 다음을 calico-values.yaml로 저장하고 매니페스트로 두 번째 operator를 설치하는 대신 이 경로를 사용하세요.

yaml
installation:
  enabled: true
  variant: Calico
  cni:
    type: Calico
  calicoNetwork:
    bgp: Disabled
    linuxDataplane: Iptables
    ipPools:
    - cidr: 10.244.0.0/16
      blockSize: 26
      encapsulation: VXLAN
      natOutgoing: Enabled
      nodeSelector: all()
    nodeAddressAutodetectionV4:
      kubernetes: NodeInternalIP
  nodeUpdateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
apiServer:
  enabled: true
goldmane:
  enabled: true
whisker:
  enabled: true
manageCRDs: true
bash
helm repo add projectcalico https://docs.tigera.io/calico/charts
helm repo update projectcalico
helm template calico projectcalico/tigera-operator \
  --namespace tigera-operator --version v3.32.2 \
  -f calico-values.yaml > calico-rendered.yaml

# 준비한 클러스터와 렌더링 결과를 검토한 후에만 적용합니다.
helm install calico projectcalico/tigera-operator \
  --namespace tigera-operator --create-namespace --version v3.32.2 \
  -f calico-values.yaml

최상위 podAnnotations는 operator Pod에 적용됩니다. Felix 메트릭을 활성화하거나 모든 컴포넌트의 Prometheus 수집을 설정하지 않습니다. 아래 모니터링 절에서 명시적으로 설정하세요. manageCRDs: true에서는 operator가 시작 후 CRD를 관리합니다. 새 필드에 필요한 업그레이드 순서는 뒤에서 설명합니다.

대안: 직접 매니페스트 ​

직접 매니페스트로 관리하는 기존 설치에는 일치하는 릴리스/구성을 사용하고 사용자 변경을 보존하세요. 다운로드한 파일을 적용 전에 검토합니다.

bash
curl -fL https://raw.githubusercontent.com/projectcalico/calico/v3.32.2/manifests/calico.yaml \
  -o calico.yaml

Pod CIDR과 활성 네트워킹 모드 등 실제 설정을 수정하세요. 전역 sed 치환은 예제나 주석만 바꾸고 실제 IP pool을 설정하지 않을 수 있습니다. kube-system의 직접 매니페스트 리소스와 calico-system의 operator 설치를 혼합하지 마세요.

설치 검증 ​

bash
kubectl get tigerastatus
kubectl get installation default -o yaml
kubectl rollout status daemonset/calico-node -n calico-system --timeout=300s
kubectl get pods -n calico-system -o wide
kubectl get nodes -o wide

직접 매니페스트 설치라면 실제 네임스페이스와 리소스 이름을 확인하세요. 컴포넌트 Ready만으로 정책 적용이나 애플리케이션 접근이 검증되지는 않습니다. Controller가 관리하는 워크로드로 필요한 Service/DNS 경로와 허용·거부 애플리케이션 연결을 모두 테스트하세요. API 접근을 확인할 때는 실제 API 서버 HTTPS 엔드포인트와 적절한 인증을 사용합니다. kubernetes.default에 대한 HTTP 요청은 인증된 API 상태 검사가 아닙니다.

calicoctl 명령어 레퍼런스 ​

공식 릴리스에서 일치하는 3.32.2 바이너리를 설치하고 설치 장의 방식으로 체크섬을 확인하세요. Linux AMD64/ARM64, macOS AMD64/ARM64, Windows AMD64 자산이 있으므로 실제 호스트 아키텍처를 선택합니다. PowerShell 다운로드 명령을 Bash에서 실행하거나 호환성 경고를 확인하지 않고 업그레이드 후 이전 클라이언트를 사용하지 마세요.

Kubernetes 데이터스토어에 접근하는 일반적인 Unix shell 설정은 다음과 같습니다.

bash
export DATASTORE_TYPE=kubernetes
export KUBECONFIG="$HOME/.kube/config"
calicoctl version
calicoctl get nodes -o wide
calicoctl get networkpolicy -A
calicoctl get globalnetworkpolicy
calicoctl get tier
calicoctl get networkset -A
calicoctl get globalnetworkset
calicoctl get workloadendpoint -A
calicoctl get hostendpoint
calicoctl get ippool -o yaml
calicoctl get bgpconfiguration default -o yaml
calicoctl get bgppeer -o wide
calicoctl get felixconfiguration default -o yaml

Kubeconfig는 의도한 클러스터와 필요한 RBAC 권한을 선택해야 합니다. Calico API 설정 파일은 --config로 명시할 수 있습니다. ~/.config 아래 임의 경로가 자동 탐색된다고 가정하지 마세요. 직접 etcdv3 데이터스토어에 접근할 때는 해당 배포의 지원 설정과 인증서 검증을 사용합니다. 별도 배포 방식이며 EKS 관리 etcd에 접근할 수 있다는 뜻은 아닙니다.

로컬 노드 진단 ​

calicoctl node status는 로컬 노드의 BGP 상태를 보여줍니다. Kubeconfig가 있다고 원격 클러스터 전체 readiness 검사로 바뀌지는 않습니다. 문서화된 접근 조건으로 대상 노드에서 실행하거나 아래와 같이 해당 노드의 BIRD 소켓을 조회하세요.

calicoctl node diags는 선택한 노드에서 진단 아카이브를 수집합니다. 지원되는 --log-dir은 입력 로그 디렉터리이며 3.32.2에는 --output-dir이 없습니다. 구현은 root 권한을 요구하며 privileged 진단 컨테이너 실행과 Felix 상태 덤프 signal을 수행할 수 있습니다. 수동적 상태 프로브가 아닌 의도적인 근거 수집으로 취급하세요. 아카이브를 보호하고 명령이 출력하는 실제 경로를 사용합니다.

Calico IPAM ​

주소를 Calico IPAM이 할당하는 경우에만 다음을 사용합니다. VPC CNI, host-local 등 다른 IPAM은 실제 할당자를 조사해야 합니다.

bash
calicoctl ipam show
calicoctl ipam show --show-blocks
calicoctl ipam show --show-borrowed
calicoctl ipam show --show-configuration
calicoctl ipam show --ip=10.244.0.15
calicoctl ipam check --show-problem-ips -o ipam-report.json

--show-blocks는 블록 사용률을 보여줍니다. 블록과 노드의 연결은 BlockAffinity로 확인하며 Kubernetes Node PodCIDR과 동일하지 않습니다. --ip는 읽기 전용 할당 조회입니다. 보고서는 조사 후보를 제시하지만 Pod가 없다는 사실만으로 주소를 안전하게 해제할 수 있다고 판단해서는 안 됩니다.

검토한 CLI에는 ipam release --block 또는 --handle이 없습니다. 보고서 기반 해제에는 할당 sequence 검사가 있지만 고급 IPAM의 정리 절차도 필요합니다. ipam split NUMBER --cidr=...는 실제 명령이지만 할당 블록이 아닌 IP pool을 분할하며 datastore lock과 2의 거듭제곱 분할 개수가 필요합니다. 멈춘 Pod의 일반적인 해결책이 아닌 계획된 마이그레이션 작업입니다.

리소스 변경과 내보내기 ​

get, create, apply, replace, patch, delete는 지원 리소스 타입에 적용됩니다. 타입/네임스페이스를 명확히 하고 전체 정책을 검토하며 patch에서 다른 필드를 보존하세요. 예를 들어 로깅 변경은 기존 FelixConfiguration 또는 GitOps 소유 설정에 반영하며 새 필드만 있는 오브젝트로 교체하지 않습니다.

calicoctl get all은 모든 리소스의 백업이 아닙니다. 필요한 타입을 나열하고 Kubernetes 정책과 operator 리소스도 별도로 포함해야 합니다. calicoctl get ... --export는 존재하지만 검토한 CLI는 리소스 이름이 없으면 이 플래그를 무시합니다. 목록 내보내기를 완전하고 이식 가능한 재해 복구 백업으로 바꾸지는 않습니다. 아래 백업 절을 참고하세요.

Prometheus 메트릭 ​

설치한 버전의 /metrics 출력에서 이름, 타입, 레이블을 확인하세요. 데이터플레인별 series가 모든 구성에 존재한다고 보장할 수 없으며 누락은 0이 아닙니다. 아래 이름은 Calico 3.32.2 소스와 공식 메트릭 참조를 대조했습니다.

컴포넌트 메트릭 활성화 ​

Felix 메트릭은 기본 비활성화이며 기본 포트는 9091입니다. Typha도 기본 비활성화이며 바이너리의 기본 메트릭 포트는 9091입니다. 이 operator 예제는 9093을 명시적으로 선택합니다. kube-controllers 메트릭은 기본적으로 9094에서 활성화됩니다.

기존 operator 설치에서는 설정 소유 경로에서 다음을 merge합니다.

bash
kubectl patch felixconfiguration default --type=merge \
  -p '{"spec":{"prometheusMetricsEnabled":true,"prometheusMetricsPort":9091}}'
kubectl patch installation default --type=merge \
  -p '{"spec":{"typhaMetricsPort":9093}}'
kubectl get service calico-typha-metrics -n calico-system
kubectl get service calico-kube-controllers-metrics -n calico-system

typhaMetricsPort를 설정하면 operator가 Typha 메트릭 Service를 생성합니다. 충돌하는 Service로 교체하지 마세요. 직접 매니페스트 설치에는 자체 Typha 환경변수와 Service 설정이 필요합니다. 메트릭 접근을 제한해야 하며 host-network 엔드포인트에는 워크로드 NetworkPolicy 외의 호스트/네트워크 제어가 필요할 수 있습니다.

메트릭 이름과 의미 ​

메트릭타입 / 의미
felix_active_local_endpointsGauge, 로컬 워크로드 및 호스트 엔드포인트 수, 0도 정상일 수 있어 readiness 검사가 아님
felix_active_local_policiesGauge, 해당 노드에서 활성인 정책 수, 합산하면 클러스터 고유 정책 수가 아닌 노드별 정책 인스턴스 수
felix_cluster_num_hosts, felix_cluster_num_policies각 Felix가 관측한 클러스터 범위 Gauge, 노드별 같은 값을 합산하지 않음
felix_int_dataplane_failuresCounter, 재시도할 데이터플레인 업데이트 실패, 검토한 이름에는 _total 접미사 없음
felix_int_dataplane_apply_time_seconds증분 업데이트 시간의 Summary, histogram bucket 대신 quantile·_sum·_count 제공
felix_iptables_restore_calls, felix_iptables_restore_errorsiptables 데이터플레인의 iptables-restore 호출/오류 Counter
felix_log_errors, felix_logs_dropped프로세스 로그 출력 오류/출력 막힘으로 버린 로그, ERROR 레벨 항목이나 거부 패킷 개수가 아님
typha_connections_activeGauge, handshake 중인 연결을 포함한 열린 연결
typha_connections_streaming{syncer="..."}Gauge, handshake를 마치고 streaming 중인 클라이언트
typha_connections_acceptedCounter, 수락한 연결 수
typha_connections_dropped재분배를 위해 끊은 연결 Counter, 일반적인 네트워크 실패 개수가 아님
typha_cache_size{syncer="..."}Gauge, 캐시의 key/value 항목 수
typha_updates_total{syncer="..."}데이터스토어 syncer로부터 받은 업데이트 Counter
ipam_allocations_in_use{ippool="...",node="..."}kube-controllers Gauge, 워크로드/인터페이스에 할당된 Calico IPAM 주소
ipam_ippool_size{ippool="..."}kube-controllers Gauge, pool CIDR 전체 주소 수
ipam_allocations_gc_candidates조사 중인 잠재적 누수, 주소 해제 허가가 아님

BIRD 제어 소켓은 Prometheus exporter가 아닙니다. bird_protocol_up, calico_bgp_peer_status 같은 이름은 레이블과 의미를 검증한 별도 exporter/collector가 필요하며 이 설치가 해당 series를 제공하지 않습니다. 아래 BGP 진단 또는 CalicoNodeStatus 방식을 사용하고 실제 출력 확인 후에만 exporter 알람을 추가하세요.

ServiceMonitor 연결 ​

Prometheus Operator CRD와 monitoring 네임스페이스가 이미 있다고 가정합니다. ServiceMonitor 레이블을 Prometheus의 serviceMonitorSelector에 맞추고 serviceMonitorNamespaceSelector가 해당 네임스페이스를 포함하는지 확인하세요. PrometheusRule 레이블도 ruleSelector와 일치해야 합니다. 스키마가 유효해도 선택되지 않은 리소스에서는 수집/규칙이 생성되지 않습니다.

아래 별도 Service는 operator 소유 Service를 변경하지 않고 모두 http-metrics라는 포트 이름을 제공합니다. 이미 해당 엔드포인트를 수집한다면 중복 scrape를 추가하지 말고 기존 설정을 사용하세요. ServiceMonitor의 jobLabel이 아래 쿼리에서 사용하는 calico-felix, calico-typha, calico-kube-controllers job을 만듭니다.

yaml
apiVersion: v1
kind: Service
metadata:
  name: calico-audit-felix-metrics
  namespace: calico-system
  labels:
    audit.calico/component: calico-felix
spec:
  clusterIP: None
  selector:
    k8s-app: calico-node
  ports:
  - name: http-metrics
    port: 9091
    targetPort: 9091
    protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  name: calico-audit-typha-metrics
  namespace: calico-system
  labels:
    audit.calico/component: calico-typha
spec:
  clusterIP: None
  selector:
    k8s-app: calico-typha
  ports:
  - name: http-metrics
    port: 9093
    targetPort: 9093
    protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  name: calico-audit-kube-controllers-metrics
  namespace: calico-system
  labels:
    audit.calico/component: calico-kube-controllers
spec:
  clusterIP: None
  selector:
    k8s-app: calico-kube-controllers
  ports:
  - name: http-metrics
    port: 9094
    targetPort: 9094
    protocol: TCP
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: calico-components
  namespace: monitoring
  labels:
    app.kubernetes.io/part-of: calico-monitoring
spec:
  jobLabel: audit.calico/component
  selector:
    matchExpressions:
    - key: audit.calico/component
      operator: Exists
  namespaceSelector:
    matchNames:
    - calico-system
  endpoints:
  - port: http-metrics
    interval: 30s
    scrapeTimeout: 10s
    path: /metrics

엔드포인트 탐색/RBAC, 네트워크 접근, Prometheus Targets 화면을 확인하세요. ServiceMonitor의 endpoints.port는 컨테이너 포트 번호가 아닌 Service 포트 이름을 선택합니다. 부하 분산되는 Service 주소 하나를 수집하며 모든 노드를 수집한다고 가정하지 말고 개별 탐색 target을 확인하세요.

Grafana 대시보드 ​

설정한 Prometheus datasource와 현재 time-series/stat 패널을 사용합니다. 다음은 완성된 import용 대시보드가 아닌 패널 쿼리입니다. 하나의 클러스터 메트릭을 선택해야 하며 여러 클러스터를 모은 datasource는 selector와 집계에 cluster 레이블을 유지해야 합니다.

패널PromQL
노드별 엔드포인트felix_active_local_endpoints{job="calico-felix"}
노드별 활성 정책felix_active_local_policies{job="calico-felix"}
관측한 클러스터 정책 수max(felix_cluster_num_policies{job="calico-felix"})
초당 데이터플레인 재시도rate(felix_int_dataplane_failures{job="calico-felix"}[5m])
Typha streaming 연결typha_connections_streaming{job="calico-typha"}
로컬 summary p99felix_int_dataplane_apply_time_seconds{job="calico-felix",quantile="0.99"}

프로세스별 Summary quantile은 클러스터 전체 p99가 아니며 histogram_quantile로 합칠 수 없습니다. 업데이트가 발생하는 구간의 평균 증분 적용 시간은 다음과 같습니다.

promql
rate(felix_int_dataplane_apply_time_seconds_sum{job="calico-felix"}[5m])
/ rate(felix_int_dataplane_apply_time_seconds_count{job="calico-felix"}[5m])

관측값이 없으면 평균은 정의되지 않으며(0/0) 지연 0의 근거가 아닙니다. 이 Summary에 존재하지 않는 _bucket series를 만들거나 검증되지 않은 felix_iptables_restore_time_seconds 쿼리를 유지하지 마세요. 실제 제공하는 작업 Counter와 데이터플레인 시간 메트릭을 사용합니다.

Calico IPAM 주소 사용률은 다음과 같이 볼 수 있습니다.

promql
sum by (ippool) (
  max by (ippool, node) (ipam_allocations_in_use{job="calico-kube-controllers",ippool!="no_ippool"})
)
/ max by (ippool) (ipam_ippool_size{job="calico-kube-controllers",ippool!="no_ippool"})

pool/node별 max로 컨트롤러의 같은 관측값 중복을 피한 뒤 노드별 할당량을 합산합니다. 주소 사용률이며 블록 소비율이나 특정 노드의 실제 할당 가능 용량을 보장하지 않습니다. Pool selector, strict affinity, 블록 상한, 예약/tunnel 주소 등도 확인해야 합니다. VPC CNI 할당량을 설명하는 메트릭이 아니며 비어 있거나 누락된 series, 용량 0은 별도 조사 대상입니다.

Alert 규칙 ​

예제는 위 job, 하나의 선택한 클러스터, DaemonSet 메트릭을 위한 kube-state-metrics를 전제로 합니다. 실제 실행해야 하는 컴포넌트에만 target 누락 규칙을 활성화하세요. 기존 모니터링을 재사용하면 selector를 조정하고 임계값·지속시간은 워크로드에 맞게 설정합니다.

yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: calico-alerts
  namespace: monitoring
  labels:
    app.kubernetes.io/part-of: calico-monitoring
spec:
  groups:
  - name: calico.rules
    rules:
    - alert: CalicoDaemonSetUnavailable
      expr: kube_daemonset_status_number_unavailable{namespace="calico-system",daemonset="calico-node"}
        > 0
      for: 5m
      labels:
        severity: critical
      annotations:
        summary: Calico DaemonSet has unavailable Pods
        description: Inspect the affected node, rollout and kube-state-metrics data.
    - alert: CalicoMetricsScrapeFailed
      expr: up{job=~"calico-(felix|typha|kube-controllers)"} == 0
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: Calico scrape failed for {{ $labels.job }} on {{ $labels.instance
          }}
    - alert: CalicoMetricsTargetsMissing
      expr: |-
        absent(up{job="calico-felix"})
        or absent(up{job="calico-typha"})
        or absent(up{job="calico-kube-controllers"})
      for: 10m
      labels:
        severity: warning
      annotations:
        summary: No discovered metrics targets for {{ $labels.job }}
    - alert: CalicoDataplaneRetries
      expr: rate(felix_int_dataplane_failures{job="calico-felix"}[5m]) > 0
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: Dataplane updates are being retried on {{ $labels.instance }}
    - alert: CalicoDataplaneMeanSlow
      expr: |-
        (rate(felix_int_dataplane_apply_time_seconds_sum{job="calico-felix"}[5m])
        / rate(felix_int_dataplane_apply_time_seconds_count{job="calico-felix"}[5m])) > 0.5
        and (rate(felix_int_dataplane_apply_time_seconds_count{job="calico-felix"}[5m]) > 0)
      for: 10m
      labels:
        severity: warning
      annotations:
        summary: Mean dataplane update time exceeds 0.5s on {{ $labels.instance }}
    - alert: CalicoIPAMHighAddressUsage
      expr: |-
        (sum by (ippool) (
          max by (ippool, node) (ipam_allocations_in_use{job="calico-kube-controllers",ippool!="no_ippool"})
        )
        / max by (ippool) (ipam_ippool_size{job="calico-kube-controllers",ippool!="no_ippool"})) > 0.8
        and on (ippool)
        (max by (ippool) (ipam_ippool_size{job="calico-kube-controllers",ippool!="no_ippool"}) > 0)
      for: 10m
      labels:
        severity: warning
      annotations:
        summary: High address utilization in Calico IP pool {{ $labels.ippool }}
        description: Address utilization is {{ $value | humanizePercentage }}; inspect
          per-node eligibility and block constraints.

up == 0은 탐색된 target의 scrape 실패를 감지하지만 target 자체가 사라지면 감지하지 못합니다. absent 규칙은 예상 컴포넌트의 모든 target이 사라진 경우를 감지합니다. 정상 노드 사이에서 한 노드만 누락된 상황은 기대 노드/DaemonSet 목록과 비교해야 합니다. 메트릭이나 규칙이 로드되지 않았다면 알람이 보이지 않는다고 정상이라고 판단할 수 없습니다.

Typha 연결 감소나 재분배 Counter 증가는 확장 중 정상적으로 발생할 수 있습니다. 지속되는 streaming/client 지연과 컴포넌트 가용성을 함께 보고 장애를 판단하세요. 로컬 엔드포인트 수 0도 Felix unready를 뜻하지 않습니다. 실제 readiness/rollout 상태와 별도 합성 허용·거부 테스트를 사용하세요.

로그 분석과 트러블슈팅 ​

영향받은 워크로드와 노드부터 확인 ​

Pending Pod는 CNI 호출 전에 스케줄링에서 막혔을 수 있습니다. 먼저 이벤트와 spec.nodeName을 확인하세요. CNI/IP 할당 오류라면 실제 할당자를 식별하고 해당 노드의 kubelet/CNI 로그를 조사합니다. 모든 Pod IPAM 오류가 Felix 프로세스 로그에 있는 것은 아닙니다.

bash
CALICO_NAMESPACE=calico-system
WORKLOAD_NAMESPACE=calico-demo
WORKLOAD_POD=replace-with-actual-pod

kubectl describe pod "$WORKLOAD_POD" -n "$WORKLOAD_NAMESPACE"
CALICO_NODE=$(kubectl get pod "$WORKLOAD_POD" -n "$WORKLOAD_NAMESPACE" \
  -o jsonpath='{.spec.nodeName}')
test -n "$CALICO_NODE" || { echo "Pod is not scheduled to a node" >&2; exit 1; }
kubectl get pods -n "$CALICO_NAMESPACE" -l k8s-app=calico-node \
  --field-selector "spec.nodeName=$CALICO_NODE" -o wide

# Rollout 중에도 이 노드의 실제 에이전트 Pod를 선택합니다.
CALICO_POD=replace-with-actual-calico-node-pod
kubectl logs -n "$CALICO_NAMESPACE" "$CALICO_POD" -c calico-node \
  --since=15m --tail=200 --timestamps

시간 범위와 tail 제한을 명시하세요. Selector를 사용하면 kubectl logs의 기본 tail이 짧을 수 있으므로 시간 범위를 지정했다고 그 구간의 모든 로그를 받았다고 가정하면 안 됩니다. 컨테이너가 재시작했다면 가능한 경우 이전 로그도 확인합니다. 조회 오류를 “오류 없음”으로 바꾸지 말고 보존하세요.

Felix 프로세스 로그는 규칙 설정과 컴포넌트 동작을 설명합니다. logSeverityScreen을 Debug로 바꿔도 패킷별 정책 결정 로그가 생성되지는 않습니다. 임시 변경 전에 기존 필드 값과 설정 소유자를 기록하고, 이전 값이 Info였다고 가정하지 말고 정확한 값 또는 필드 부재를 복원하세요. 파일/syslog 출력도 설정 경로와 런타임에 따라 달라집니다.

주소 할당과 연결 ​

증상상태 변경 전에 확인할 사항
스케줄링된 노드 없음Scheduler 이벤트, 용량, affinity, taint 확인, 아직 IPAM 진단 단계가 아님
CNI 할당 실패실제 할당자 로그, pool/주소 용량, selector 적격성, 블록/affinity 제한, API 접근
Pod IP는 연결되지만 Service 실패Endpoints/EndpointSlices, Service 포트, kube-proxy 또는 BPF Service 처리, DNS, 정책
작은 패킷만 성공Underlay/overlay MTU, fragmentation/PMTUD, 반환 경로
정책이 의도대로 차단하지 않음실제 엔드포인트 identity/레이블, 방향, namespace selector, tier/order, 앞선 allow, host-network/추가 인터페이스 제약, 기존 연결
bash
kubectl exec -n "$CALICO_NAMESPACE" "$CALICO_POD" -c calico-node -- ip route show
kubectl exec -n "$CALICO_NAMESPACE" "$CALICO_POD" -c calico-node -- ip -d link show
calicoctl get networkpolicy -n "$WORKLOAD_NAMESPACE" -o yaml
calicoctl get globalnetworkpolicy -o yaml
calicoctl get tier -o yaml
calicoctl get workloadendpoint -n "$WORKLOAD_NAMESPACE" -o yaml
kubectl get pod "$WORKLOAD_POD" -n "$WORKLOAD_NAMESPACE" --show-labels

클러스터의 첫 번째 calico-node Pod를 골라 문제가 있는 워크로드의 노드라고 가정하지 마세요. ICMP 성공/실패만으로 TCP나 HTTP 정책이 검증되지는 않습니다. 도구가 확인된 승인 진단 워크로드와 애플리케이션의 실제 프로토콜/포트를 사용하세요.

Calico IPAM에서는 위의 읽기 전용 명령과 IPAM 정리 절차를 사용합니다. Pool CIDR과 blockSize는 변경할 수 없습니다. 겹치지 않는 적격 pool 추가는 계획된 용량 변경이며 기존 CIDR의 직접 확장이 아닙니다. 원인을 확인하기 전에 주소를 해제하거나 에이전트를 재시작하지 마세요.

Operator 설치의 MTU와 주소 자동 감지는 Installation.spec.calicoNetwork에 설정하며 문서화된 경우 터널별 Felix 필드를 사용합니다. FelixConfiguration.spec.mtu와 ipAutoDetectionMethod는 검토한 API가 아닙니다. MTU/네트워킹 안내를 따르며 다른 설정을 보존하고 신규/기존 Pod를 각각 검증하세요.

BGP 진단 ​

BGP를 사용하는 구성에서만 BGP를 검사합니다. 선택한 calico-node Pod에서 실제 BIRD 소켓을 사용하세요.

bash
kubectl exec -n "$CALICO_NAMESPACE" "$CALICO_POD" -c calico-node -- \
  birdcl -s /var/run/calico/bird.ctl show protocols all
kubectl exec -n "$CALICO_NAMESPACE" "$CALICO_POD" -c calico-node -- \
  birdcl -s /var/run/calico/bird.ctl show route
calicoctl get bgpconfiguration -o yaml
calicoctl get bgppeer -o yaml
calicoctl get bgpfilter -o yaml

IPv6 데몬이 있다면 해당 bird6.ctl을 사용합니다. 로컬/피어 ASN, 선택한 출발지 주소, 양방향 TCP 179, 인증/TTL, 라우트 필터, 기대하는 광고 경로를 확인하세요. TCP 연결 성공만으로 세션 Established나 필요한 prefix 수용이 검증되지는 않습니다. 파일이 있다고 가정하기 전에 패키지의 로그 설정을 확인하세요. 릴리스 컨테이너의 BIRD run/log 스크립트가 출력 위치를 결정합니다. BGP 심화를 참고하세요.

헬스체크 자동화 ​

다음 operator 설치 상태 검사는 Bash, jq, 호환 kubectl이 있는 관리 환경에서 실행합니다. 읽기 전용 API/로그 요청으로 DaemonSet의 관측 generation과 복제본 가용성을 확인하고 요청이 실패하면 실패를 반환합니다. BGP 소켓, 패킷 전달, 모든 정책의 정확성을 검사하는 스크립트는 아닙니다.

bash
#!/usr/bin/env bash
# calico-status-check.sh: operator 컴포넌트 상태와 제한된 로그 수집.
set -euo pipefail
CALICO_NAMESPACE=${CALICO_NAMESPACE:-calico-system}

if ! calico_ds_json=$(kubectl get daemonset calico-node -n "$CALICO_NAMESPACE" \
  --request-timeout=20s -o json); then
  echo "Unable to read calico-node DaemonSet status" >&2
  exit 2
fi
if ! jq -e '
  .status.desiredNumberScheduled as $desired
  | ($desired > 0)
    and (.status.observedGeneration >= .metadata.generation)
    and (.status.updatedNumberScheduled == $desired)
    and (.status.numberReady == $desired)
    and (.status.numberAvailable == $desired)
    and ((.status.numberUnavailable // 0) == 0)
' <<<"$calico_ds_json" >/dev/null; then
  echo "Calico DaemonSet is not fully observed, updated and available" >&2
  exit 1
fi

if ! calico_status_json=$(kubectl get tigerastatus --request-timeout=20s -o json); then
  echo "Unable to read operator component status" >&2
  exit 2
fi
if ! jq -e '
  (.items | length) > 0 and all(.items[];
    any(.status.conditions[]?; .type == "Available" and .status == "True")
    and any(.status.conditions[]?; .type == "Progressing" and .status == "False")
    and any(.status.conditions[]?; .type == "Degraded" and .status == "False")
  )
' <<<"$calico_status_json" >/dev/null; then
  echo "Operator components are unavailable, progressing, degraded or missing conditions" >&2
  exit 1
fi

if ! calico_logs=$(kubectl logs -n "$CALICO_NAMESPACE" -l k8s-app=calico-node \
  -c calico-node --since=15m --tail=200 --timestamps --prefix \
  --request-timeout=20s); then
  echo "Unable to retrieve selected Calico logs; do not report no errors" >&2
  exit 2
fi
printf '%s\n' "$calico_logs"
echo "Component status checks passed; review these bounded logs and test application policy separately."

비어 있거나 스케줄링되지 않은 DaemonSet, 오래된 상태, 누락된 컴포넌트 condition은 성공이 아닙니다. 로그는 선택한 시간/tail 범위로 제한되며 해석이 필요합니다. Counter나 ERROR 단어 하나가 실제 장애와 같은 의미는 아닙니다.

CronJob으로 예약하려면 먼저 필요한 도구와 스크립트를 승인 이미지에 패키징하고 검증하세요. DaemonSet, Pod/Pod 로그, TigeraStatus 읽기 권한을 가진 전용 ServiceAccount를 사용하며 권한이 큰 calico-node identity를 재사용하지 마세요. 동시 실행, deadline, 실패 보고도 설정합니다. calico/ctl 이미지는 범용 Bash/kubectl 진단 환경이 아니며 일반 Job은 의도적으로 추가 접근을 제공하지 않으면 다른 노드의 BIRD 소켓을 조사할 수 없습니다. 이 로컬 스크립트가 작동하는 클러스터 내부 CronJob까지 제공한다는 뜻은 아닙니다.

버전 업그레이드와 복구 ​

전환 준비 ​

bash
calicoctl version
kubectl version --output=yaml
kubectl get deployment tigera-operator -n tigera-operator \
  -o jsonpath='{.spec.template.spec.containers[*].image}'
kubectl get tigerastatus
kubectl get daemonset calico-node -n calico-system -o wide
helm get values calico -n tigera-operator -o yaml

Helm 명령은 Helm 관리 설치에만 적용됩니다. 실제 이미지, CRD, 데이터스토어, 노드 OS/커널, 데이터플레인, Kubernetes 호환성을 확인하세요. 소유 매니페스트/values, 정책, 검증된 복구 계획을 보존합니다. kubectl version --short는 현재 명령 옵션이 아닙니다.

실제 출발 버전과 설치 방식에 맞는 3.32 업그레이드 절차를 따릅니다. 해당 릴리스를 거칠 때 OwnerReference/UID 마이그레이션 주의사항을 검토하세요. 목표 버전을 고정하고 calicoctl도 맞춥니다.

Helm에서는 새 operator보다 먼저 소유 경로로 일치하는 Calico CRD를 적용하거나, manageCRDs: true로 operator의 CRD 설치를 기다린 뒤 새 필드를 사용합니다. Operator 변경만을 이유로 --force-conflicts로 필드 소유권을 덮어쓰지 마세요. 검토한 변경 후 operator, calico-node, 설정한 다른 컴포넌트를 관찰하고 rollout 중·이후 허용/거부 경로를 테스트합니다.

Operator는 자신이 관리하는 DaemonSet을 조정합니다. Affinity patch로 “canary” 노드에서 에이전트를 제거한다고 안전한 canary가 배포되는 것은 아니며 해당 노드가 정책 없이 남을 수 있습니다. 대표성 있는 격리 환경에서 버전/설정을 검증하고 지원되는 rollout 제어를 사용하세요. 경쟁하는 두 번째 노드 DaemonSet을 임의로 만들지 마세요.

복구 한계 ​

helm rollback, 이전 operator 적용, 설정 export 적용은 CRD/데이터 마이그레이션이나 패킷 처리 상태를 자동으로 되돌리지 않습니다. 출발/목표 릴리스의 지원 다운그레이드 경로와 저장 데이터를 확인한 후 복구를 선택하세요. Installation 리소스가 남아 있다고 데이터 손실이 없다는 뜻은 아닙니다.

EKS 컨트롤 플레인 복구는 Part 8의 현재 자격과 7일 롤백 한계를 따릅니다. Calico/애드온과 애플리케이션 호환성은 별도 책임입니다.

백업 및 재해 복구 ​

설정 목록과 상태 복구 구분 ​

자료목적과 한계
Git 관리 매니페스트/Helm values, 버전 기록원하는 설정과 소유권, 일치하는 CRD 정의와 이미지 보존
Calico 정책, tier, set, pool, BGP/filter, controller 설정실제 사용한 namespaced/staged/global 리소스를 포함한 설정 목록
Kubernetes NetworkPolicy, namespace/ServiceAccount 레이블, 관련 RBACCalico 리소스만 export하면 빠지는 정책 identity/의존성
Host/node/endpoint와 IPAM 상태런타임/토폴로지에 의존하므로 이전 노드 주소와 할당을 다른 클러스터에 그대로 적용하지 않음
데이터스토어 백업과 애플리케이션 데이터일관된 복구 수단과 별도로 보호할 자격증명/데이터, YAML 목록은 원자적 데이터스토어 snapshot이 아님

kubectl export 명령은 없습니다. calicoctl get TYPE -o yaml은 리소스 export이며 --export에는 앞서 설명한 이름 지정 제한이 있습니다. 자체 관리 Kubernetes/etcd는 일치하는 버전과 복구 테스트를 포함한 Kubernetes etcd 백업/복구 절차를 따르세요. 관리형 서비스는 해당 서비스의 지원 복구 방식을 사용하며 이 절차로 EKS etcd에 접근할 수는 없습니다.

보호된 설정 목록 예제 ​

다음은 Calico IPAM을 사용하는 3.32 operator 설치에서 명시한 일부 리소스를 내보내는 스크립트입니다. Bash, calicoctl, kubectl, sha256sum이 필요합니다. 대상 디렉터리는 없어야 하며 부분 실패에는 STATE=incomplete가 남습니다. Secret, 외부 IAM/네트워크 장비, 모든 operator 사용자 정의 리소스, 전체 IPAM 할당 상태를 수집하지 않습니다. 실제 기능에 맞게 목록을 확장하고 자격증명은 별도 안전한 백업으로 보호하세요.

bash
#!/usr/bin/env bash
# calico-config-inventory.sh: 보호된 설정 목록, 데이터스토어 snapshot이 아님.
set -euo pipefail
umask 077
CALICO_EXPORT_DIR=${1:?Usage: calico-config-inventory.sh NEW_EXPORT_DIRECTORY}
mkdir -m 700 -- "$CALICO_EXPORT_DIR"
printf '%s\n' incomplete > "$CALICO_EXPORT_DIR/STATE"

for calico_kind in node ippool ipreservation bgpconfiguration bgppeer bgpfilter \
  globalnetworkpolicy stagedglobalnetworkpolicy globalnetworkset \
  felixconfiguration kubecontrollersconfiguration ipamconfiguration \
  tier hostendpoint profile; do
  calicoctl get "$calico_kind" -o yaml > "$CALICO_EXPORT_DIR/$calico_kind.yaml"
done
for calico_kind in networkpolicy stagednetworkpolicy stagedkubernetesnetworkpolicy \
  networkset workloadendpoint; do
  calicoctl get "$calico_kind" -A -o yaml > "$CALICO_EXPORT_DIR/$calico_kind.yaml"
done
kubectl get installation default -o yaml > "$CALICO_EXPORT_DIR/installation.yaml"
kubectl get networkpolicies.networking.k8s.io -A -o yaml \
  > "$CALICO_EXPORT_DIR/kubernetes-networkpolicies.yaml"
kubectl get namespaces -o yaml > "$CALICO_EXPORT_DIR/namespaces.yaml"
kubectl get serviceaccounts -A -o yaml > "$CALICO_EXPORT_DIR/serviceaccounts.yaml"
(
  cd -- "$CALICO_EXPORT_DIR"
  sha256sum ./*.yaml > SHA256SUMS
)
printf '%s\n' complete > "$CALICO_EXPORT_DIR/STATE"
echo "Configuration inventory completed: $CALICO_EXPORT_DIR"

complete는 명시한 조회와 체크섬 작성이 완료되었다는 뜻이며 트랜잭션 일관성이나 재해 복구 테스트 완료를 의미하지 않습니다. Export를 민감한 인프라 자료로 취급하세요. 체크섬을 확인하고 장애 영역 밖에 보관하며 실제 데이터스토어/버전으로 복구를 연습합니다.

복구 계획 ​

  1. 선택한 방식으로 호환 컨트롤 플레인/데이터스토어와 필요한 CRD/operator를 복구합니다. 새 클러스터 이전과 같은 클러스터 복구의 identity/IPAM 요건은 다릅니다.
  2. Namespace/ServiceAccount identity, 레이블, RBAC를 검토하고 tier/set을 의존 정책보다 먼저 복구하는 등 소유 선언적 설정의 의존 순서를 따릅니다.
  3. 클러스터별 metadata, 생성형/controller 소유 오브젝트, 이전 노드 주소/할당을 검토합니다. 원본 dump를 이식 가능한 desired-state 매니페스트로 그대로 적용하지 마세요.
  4. 정상 변경을 재개하기 전에 IP 할당 중복, 경로, 암호화, Service/DNS, 허용·거부 트래픽을 검증합니다.

calicoctl datastore migrate export/import는 datastore lock과 rollback 경계가 있는 실제 etcd→Kubernetes 마이그레이션 기능입니다. 기존 Kubernetes 데이터스토어의 일반 백업 단축 명령이 아닙니다. Lock은 새 Pod에 영향을 주며 문서화된 마이그레이션은 Kubernetes 데이터스토어 unlock 후 되돌릴 수 없습니다. 마이그레이션 절차를 참고하세요.

운영 모범 사례 ​

정책과 접근 ​

선택한 테스트 네임스페이스에서 DNS, API, identity, 모니터링, 애플리케이션 의존성을 준비한 후 default-deny를 검증하세요. 빈 전역 all() 정책이나 존재하지 않는 API-server/노드 레이블 selector는 필수 트래픽을 끊을 수 있습니다. Pod와 host endpoint의 정책 경로도 다릅니다. Part 5의 제한된 예제, tier 의미, host endpoint 제어를 사용하세요. 독립적으로 사용할 수 있는 복구 경로를 유지하고 범위를 넓히기 전에 거부 사례를 테스트합니다.

Flow 관측성 ​

현재 OSS operator/Helm 설치는 Goldmane와 Whisker를 사용할 수 있습니다. OSS flow log 가이드는 이 기능을 tech preview로 표시하며 패킷/연결 하나당 한 레코드가 아닌 집계 flow를 설명합니다. 이전 파일/DNS logger 필드와 존재하지 않는 FlowLogsFileReporter 이름은 유효한 OSS 설정이 아닙니다.

bash
kubectl get goldmane,whisker
kubectl port-forward -n calico-system service/whisker 8081:8081

Port-forward는 기본적으로 로컬에 바인딩합니다. Whisker/Goldmane에는 민감한 워크로드/네트워크 자료가 있으므로 외부 노출 전 인증과 접근 제어를 설정하세요. 이 컴포넌트가 없던 버전에서 업그레이드했다면 해당 사용자 정의 리소스를 의도적으로 활성화해야 합니다. 프로세스 debug 로그, 정책 Log action, 집계 flow log, Prometheus 메트릭은 서로 다른 질문에 답합니다.

성능과 자원 ​

엔드포인트/정책 변경량, 데이터플레인 설정 시간, 대기열, 메모리, 실제 애플리케이션 트래픽을 측정하세요. Resync/refresh 주기는 Kubernetes API polling 주기가 아니며 늘린다고 보편적인 API 부하 최적화가 되지는 않습니다. 이전 ...Secs 철자 대신 실제 duration 필드 iptablesPostWriteCheckInterval을 사용합니다. 설치 소유자의 지원 resource override와 operator 규모 조절을 보존하세요.

BPF, DSR, 추측한 인터페이스 패턴을 일반적인 튜닝 프리셋으로 활성화하지 마세요. Part 6에서 커널/플랫폼, Service 처리, kube-proxy 충돌, 복구를 다룹니다. Conntrack map을 키우면 메모리를 사용하며 모든 병목이 사라지는 것은 아닙니다. 데이터플레인이나 자원 변경이 필요하면 관련 워크로드·실패 테스트를 다시 수행하세요.

이 문서의 검사는 오프라인 스키마, 쿼리, 스크립트 fixture 검증입니다. 프로덕션 용량, 성공적인 클러스터 업그레이드나 재해 복구를 입증하지 않습니다.

참고 자료 ​

다음 단계와 퀴즈 ​

용어집, 고급 주제, EKS 통합을 복습하고 운영 퀴즈를 풀어보세요.