[Production] 쿠버네티스 Addon 설정
목차
들어가기 전에
처음 쿠버네티스를 공부할 때는 쿠버네티스만 하면 끝날 줄 알았습니다.
하지만 인기 있는 오픈소스가 애드온이 없을 리가 없지요.
한 번에 익혀야 할 지식이 너무 많아서 버거운 것이 사실입니다.
또한 교육자료에서는 샘플 코드를 기준으로 가르치기 때문에 실제 환경에서 어떻게 구성해야 하는지 시행착오를 많이 겪어야 했습니다.
때문에 오늘은 쿠버네티스 애드온의 Production환경 구축에 대해서 하나하나 풀어가보겠습니다.
가능한 helm을 이용해서 설치합니다. helm을 먼저 설치해주시기 바랍니다.
https://helm.sh/docs/intro/install/
이 글에서 작성할 파일의 폴더 구조는 아래와 같습니다.
1. Jaeger
1-1. Elasticsearch
jaeger는 DB로서 Elasticsearch, Cassandra, Kafka를 사용할 수 있습니다.
elasticsearch.yaml
- replicas, storage class는 자신의 환경에 맞게 설정해주세요.
clusterName: elasticsearch
nodeGroup: master
replicas: 1
minimumMasterNodes: 1
volumeClaimTemplate:
accessModes: ["ReadWriteOnce"]
storageClassName: gp2
resources:
requests:
storage: 10Gi
1-2. jaeger
jaeger.yaml
apiVersion: jaegertracing.io/v1
kind: Jaeger
metadata:
name: jaeger
namespace: istio-system
spec:
strategy: production
collector:
maxReplicas: 5
resources:
limits:
cpu: 100m
memory: 128Mi
storage:
type: elasticsearch
options:
es:
server-urls: http://elasticsearch-master.istio-system.svc.cluster.local:9200
sampling:
options:
default_strategy:
type: probabilistic
param: 1.0
1-3. Helm install Jaeger
저는 istio-system 네임스페이스에 설치했습니다.
원하는 네임스페이스에 설치하시면 되는데 다른 애드온 설치할 때 svc주소에 주의해주세요.
helm repo add elastic https://helm.elastic.co
helm repo add jaegertracing https://jaegertracing.github.io/helm-charts
helm repo update
helm upgrade -i -f elasticsearch.yaml elasticsearch elastic/elasticsearch -n istio-system --wait
helm upgrade -i jaeger-operator jaegertracing/jaeger-operator -n istio-system --wait
kubectl apply -f jaeger.yaml
2. Istio
2-1. values.yaml
global:
tracer:
zipkin:
address: "jaeger-collector.istio-system.svc:9411" # jaeger collector 주소
pilot:
traceSampling: 100.0 # jaeger의 샘플링 빈도를 조절합니다. 실제 환경에 맞게 조절해주세요.
2-2. Helm install Istio
kubectl create namespace istio-system
helm repo add istio https://istio-release.storage.googleapis.com/charts
helm repo update
helm upgrade -i istio-base istio/base -n istio-system
helm upgrade -i -f values.yaml istiod istio/istiod -n istio-system --wait
3. Prometheus & Grafana
3-1. values.yaml
Istio, prometheus, grafana, Kiali가 연동이 잘 안 돼서 고생을 많이 했었습니다.
- storageclass는 자신의 환경에 맞게 조절해주세요
- additionalScrapeConfigs에서 istio를 스크랩하는 설정이 들어갑니다.
- kiali는 특정 grafana 대시보드를 요구합니다.
namespaceOverride: "istio-system"
alertmanager:
alertmanagerSpec:
retention: 120h
resources:
requests:
memory: 400Mi
limits:
memory: 1Gi
storage:
volumeClaimTemplate:
spec:
storageClassName: gp2
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
# https://github.com/grafana/helm-charts/blob/main/charts/grafana/values.yaml
grafana: # 메트릭 시각화
namespaceOverride: "istio-system"
defaultDashboardsTimezone: Asia/Seoul
resources:
requests:
memory: 400Mi
limits:
memory: 1Gi
persistence:
type: pvc
enabled: true
storageClassName: gp2
accessModes:
- ReadWriteOnce
size: 10Gi
dashboardProviders:
dashboardproviders.yaml:
apiVersion: 1
providers:
- name: 'default'
orgId: 1
folder: ''
type: file
disableDeletion: false
editable: true
options:
path: /var/lib/grafana/dashboards/default
dashboards:
default:
istio-control-plane-dashboard:
gnetId: 7645
revision: 110
datasource: Prometheus
istio-mesh-dashboard:
gnetId: 7639
revision: 110
datasource: Prometheus
istio-performance-dashboard:
gnetId: 12153
revision: 1
datasource: Prometheus
istio-service-dashboard:
gnetId: 7636
revision: 110
datasource: Prometheus
istio-wasm-extension-dashboard:
gnetId: 13277
revision: 67
datasource: Prometheus
istio-workload-dashboard:
gnetId: 7630
revision: 110
datasource: Prometheus
kube-state-metrics: # 쿠버네티스 클러스터의 메트릭 수집
namespaceOverride: "istio-system"
prometheus-node-exporter: # 노드의 메트릭 수집
namespaceOverride: "istio-system"
hostRootFsMount:
enabled: false
prometheus:
prometheusSpec:
retention: 10d
retentionSize: "10GB"
replicas: 2
resources:
requests:
memory: 400Mi
limits:
memory: 2Gi
# https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/storage.md
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: gp2
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
# https://istio.io/latest/docs/ops/integrations/prometheus/#option-1-quick-start
# https://raw.githubusercontent.com/istio/istio/release-1.7/manifests/charts/istio-telemetry/prometheus/templates/configmap.yaml
# 형식: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config
# istio Standard Metrics https://istio.io/latest/docs/reference/config/metrics/
additionalScrapeConfigs:
- job_name: 'istiod'
kubernetes_sd_configs:
- role: endpoints
namespaces:
names:
- istio-system
relabel_configs:
- source_labels: [ __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name ]
action: keep
regex: istiod;http-monitoring
- job_name: 'istio-mesh'
kubernetes_sd_configs:
- role: endpoints
namespaces:
names:
- istio-system
relabel_configs:
- source_labels: [ __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name ]
action: keep
regex: istio-telemetry;prometheus
- job_name: 'envoy-stats'
metrics_path: /stats/prometheus
kubernetes_sd_configs:
- role: pod
# relabel_config 설정 https://grafana.com/docs/grafana-cloud/metrics-control-usage/control-prometheus-metrics-usage/usage-reduction/?src=grafana&mdm=rss
relabel_configs:
- source_labels: [ __meta_kubernetes_pod_container_port_name ]
action: keep # 일치하는 대상 유지, 나머지 삭제
regex: '.*-envoy-prom'
- source_labels: [ __address__, __meta_kubernetes_pod_annotation_prometheus_io_port ]
action: replace # 일치하는 label 을 replacement에 지정된 새 label 로 변경
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:15090
target_label: __address__
- action: labeldrop
regex: __meta_kubernetes_pod_label_(.+)
- source_labels: [ __meta_kubernetes_namespace ]
action: replace
target_label: namespace
- source_labels: [ __meta_kubernetes_pod_name ]
action: replace
target_label: pod_name
- job_name: 'istio-policy'
kubernetes_sd_configs:
- role: endpoints
namespaces:
names:
- istio-system
relabel_configs:
- source_labels: [ __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name ]
action: keep
regex: istio-policy;http-policy-monitoring
- job_name: 'istio-telemetry'
kubernetes_sd_configs:
- role: endpoints
namespaces:
names:
- istio-system
relabel_configs:
- source_labels: [ __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name ]
action: keep
regex: istio-telemetry;http-monitoring
- job_name: 'galley'
kubernetes_sd_configs:
- role: endpoints
namespaces:
names:
- istio-system
relabel_configs:
- source_labels: [ __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name ]
action: keep
regex: istio-galley;http-monitoring
- job_name: 'citadel'
kubernetes_sd_configs:
- role: endpoints
namespaces:
names:
- istio-system
relabel_configs:
- source_labels: [ __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name ]
action: keep
regex: istio-citadel;http-monitoring
- job_name: 'sidecar-injector'
kubernetes_sd_configs:
- role: endpoints
namespaces:
names:
- default
- istio-system
- traefik
relabel_configs:
- source_labels: [ __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name ]
action: keep
regex: istio-sidecar-injector;http-monitoring
# kubernetes API 스크랩
- job_name: 'kubernetes-apiservers'
kubernetes_sd_configs:
- role: endpoints
namespaces:
names:
- default
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
action: keep
regex: kubernetes;https
# kubelet 수집
- job_name: 'kubernetes-nodes'
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
- role: node
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
- target_label: __address__
replacement: kubernetes.default.svc:443
- source_labels: [__meta_kubernetes_node_name]
regex: (.+)
target_label: __metrics_path__
replacement: /api/v1/nodes/${1}/proxy/metrics
# 컨테이너 수집
- job_name: 'kubernetes-cadvisor'
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
- role: node
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
- target_label: __address__
replacement: kubernetes.default.svc:443
- source_labels: [__meta_kubernetes_node_name]
regex: (.+)
target_label: __metrics_path__
replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor
# node 정보 수집
- job_name: 'kube-dns'
static_configs:
- targets: [ 'kube-dns.kube-system.svc.cluster.local:9153' ]
# 서비스 수집
- job_name: 'kubernetes-service-endpoints'
kubernetes_sd_configs:
- role: endpoints
relabel_configs:
- source_labels: [ __meta_kubernetes_service_annotation_prometheus_io_scrape ]
action: keep
regex: true
- source_labels: [ __meta_kubernetes_service_annotation_prometheus_io_scheme ]
action: replace
target_label: __scheme__
regex: (https?)
- source_labels: [ __meta_kubernetes_service_annotation_prometheus_io_path ]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [ __address__, __meta_kubernetes_service_annotation_prometheus_io_port ]
action: replace
target_label: __address__
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
- action: labelmap
regex: __meta_kubernetes_service_label_(.+)
- source_labels: [ __meta_kubernetes_namespace ]
action: replace
target_label: kubernetes_namespace
- source_labels: [ __meta_kubernetes_service_name ]
action: replace
target_label: kubernetes_name
3-2. Helm install prometheus
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm upgrade -i -f values.yaml monitoring prometheus-community/kube-prometheus-stack -n istio-system --wait
4. Kiali
4-1. values.yaml
- auth strategy는 입맛에 맞게 설정해주세요.
cr:
create: true
name: kiali-operator
namespace: istio-system
spec:
auth:
strategy: "anonymous" # 로그인 없이 kiali 접근 가능
# strategy: "token" # kubernetes 의 sa token 을 이용해 로그인
# strategy: "openid" # 타사 아이디(ex. google) 인증을 통해 로그인
deployment:
installation_tag: "Kiali in istio-system"
view_only_mode: false
accessible_namespaces:
- '**'
logger:
# "trace", "debug", "info", "warn", "error", "fatal"
log_level: info
# "text", "json".
log_format: text
time_field_format: "2006-01-02T15:04:05Z07:00"
log_sampler_rate: 1
external_services:
istio:
istiod_pod_monitoring_port: 15014
component_status:
components:
- app_label: istiod
is_core: true
prometheus:
url: "http://monitoring-kube-prometheus-prometheus.istio-system:9090/"
cache_enabled: true
cache_duration: 10 # 쿼리당 캐시 만료 시간(초)
cache_expiration: 300 # 전역 캐시 만료 시간(초)
tracing:
enabled: true
use_grpc: false
whitelist_istio_system: ["jaeger-query"]
in_cluster_url: 'http://jaeger-query.istio-system:16686'
url: "<traefik의 external 주소>:<jaeger entryPoint포트번호>"
grafana:
enabled: true
auth:
type: "basic"
username: "admin"
password: "prom-operator"
dashboards:
- name: "Istio Service Dashboard"
- name: "Istio Workload Dashboard"
- name: "Istio Mesh Dashboard"
- name: "Istio Control Plane Dashboard"
- name: "Istio Performance Dashboard"
- name: "Istio Wasm Extension Dashboard"
in_cluster_url: 'http://monitoring-grafana.istio-system/'
url: "<traefik의 external 주소>:<그라파나 entryPoint포트번호>"
istio_namespace: istio-system
4-2. Helm install Kiali
helm upgrade -i -f values.yaml kiali-operator kiali/kiali-operator -n kiali-operator --wait
5. Traefik ingress controller
서비스 메시인 Istio를 접하신 분들은 왜 Istio ingressgateway를 사용하지 않는지 의아하게 생각하실 수도 있습니다.
처음에는 Istio만으로 행복 코딩을 했으나 맥의 M1칩에서 동작하지 않는다는 사실을 알게 되었습니다.
비공식적으로 빌드된 M1용 Istio가 있지만 검증되지 않은 빌드는 사용하고 싶지 않았기에 Traefik을 도입했습니다.
개발환경에서는 Traefik, 서버에서는 Istio + Traefik을 사용하는 구조이지요.
Traefik은 helm을 이용해서 설치합니다.
5-1. values.yaml
- annotation 설정은 AWS 환경에서 사용하실 분만 해주시면 됩니다.
- ports 부분의 포트는 입맛에 맞게 변경하거나 수정해주시면 됩니다.
# https://github.com/traefik/traefik-helm-chart/blob/master/traefik/values.yaml
ingressRoute:
dashboard:
enabled: false # 대시보드를 비활성화 합니다.
providers:
kubernetesCRD:
allowCrossNamespace: true # Traefik이 다른 네임스페이스의 서비스에 라우팅할 수 있도록 합니다.
service:
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb # AWS의 network loadbalancer를 활성화합니다. 설정하지 않으면 classic으로 생성됩니다.
ports: # port는 외부에 개방하는 포트이며 traefik내에서 entryPoint라고 불립니다.
preview: # blue/green 배포를 위한 포트입니다. 나중에 다시 다루겠습니다.
port: 8888
expose: true
exposedPort: 8888
protocol: TCP
jaeger:
port: 9991
expose: true
exposedPort: 9991
protocol: TCP
grafana:
port: 9992
expose: true
exposedPort: 9992
protocol: TCP
prometheus:
port: 9993
expose: true
exposedPort: 9993
protocol: TCP
kiali:
port: 9994
expose: true
exposedPort: 9994
protocol: TCP
autoscaling:
enabled: true
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 60
- type: Resource
resource:
name: memory
targetAverageUtilization: 60
5-2. Ingressroute
kubectl get svc -n traefik
Traefik 서비스를 확인하면 values에서 개봉한 port를 확인할 수 있습니다.
이 포트를 통해서 각 애드온들에 접속하는 설정을 해봅시다.
Ingressroute의 상세 설정은 링크를 참조하세요.
https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#kind-ingressroute
ingressroute/grafana.yml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingress-route-grafana
namespace: traefik
spec:
entryPoints:
- grafana
routes:
- kind: Rule
match: PathPrefix(`/`)
services:
- name: monitoring-grafana
port: 80
namespace: istio-system
ingressroute/jaeger.yml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingress-route-jaeger
namespace: traefik
spec:
entryPoints:
- jaeger
routes:
- match: PathPrefix(`/`)
kind: Rule
services:
- name: jaeger-query
namespace: istio-system
port: 16686
ingressroute/kiali.yml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingress-route-kiali
namespace: traefik
spec:
entryPoints:
- kiali
routes:
- match: PathPrefix(`/`)
kind: Rule
services:
- name: kiali
namespace: istio-system
port: 20001
5-3. Helm install Traefik
# Traefik 네임스페이스 생성
kubectl create ns traefik
# istio-injection 설정
kubectl label namespace traefik istio-injection=enabled --overwrite
# Helm 설치
helm repo add traefik https://helm.traefik.io/traefik
helm repo update
helm upgrade -i -f values.yaml traefik traefik/traefik -n traefik
# ingressroute 설치
kubectl apply -f ingressroute/jaeger.yml
kubectl apply -f ingressroute/kiali.yml
kubectl apply -f ingressroute/grafana.yml
6. 통합 설치 스크립트
위에서 작성한 커맨드를 한 번에 설치하는 쉘 스크립트를 만듭시다.
script/init.sh
- repo_path는 현재 레포지토리의 절대 주소입니다.
- helm upgrade -i 옵션이 참 편리합니다. 이미 설치되어 있다면 업데이트 아니라면 설치합니다.
- istio-system에 jaeger, elasticsearch, prometheus, kiali를 모두 같은 네임스페이스에 설치했습니다만 다른 네임스페이스에 설치하셔도 됩니다.
#!/bin/bash
repo_path=$(git rev-parse --show-toplevel)
echo "👉 네임스페이스 설치 👈"
kubectl create namespace istio-system
kubectl create namespace traefik
kubectl create namespace kiali-operator
kubectl label namespace traefik istio-injection=enabled --overwrite
kubectl label namespace default istio-injection=enabled --overwrite
echo "👉 Helm repo 추가 👈"
helm repo add elastic https://helm.elastic.co
helm repo add jaegertracing https://jaegertracing.github.io/helm-charts
helm repo add istio https://istio-release.storage.googleapis.com/charts
helm repo add traefik https://helm.traefik.io/traefik
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo add kiali https://kiali.org/helm-charts
echo "👉 Helm 업데이트 👈"
helm repo update
echo "👉 Elasticsearch 설치 👈"
helm upgrade -i -f ${repo_path}/jaeger/elasticsearch.yaml elasticsearch elastic/elasticsearch -n istio-system --wait
echo "👉 Jaeger 설치 👈"
helm upgrade -i jaeger-operator jaegertracing/jaeger-operator -n istio-system --wait
kubectl apply -f ${repo_path}/jaeger/jaeger.yaml
echo "👉 Istio 설치 👈"
helm upgrade -i istio-base istio/base -n istio-system --wait
helm upgrade -i -f ${repo_path}/istio/values.yaml istiod istio/istiod -n istio-system --wait
echo "👉 Traefik 설치 👈"
helm upgrade -i -f ${repo_path}/traefik/values.yaml traefik traefik/traefik -n traefik --wait
kubectl apply -f ${repo_path}/traefik/ingressroute/jaeger.yml
kubectl apply -f ${repo_path}/traefik/ingressroute/kiali.yml
kubectl apply -f ${repo_path}/traefik/ingressroute/grafana.yml
echo "👉 Prometheus 설치 👈"
helm upgrade -i -f ${repo_path}/prometheus/values.yaml monitoring prometheus-community/kube-prometheus-stack -n istio-system --wait
echo "👉 Kiali 설치 👈"
helm upgrade -i -f ${repo_path}/kiali/values.yaml kiali-operator kiali/kiali-operator -n kiali-operator --wait
마무리
지금 정리하고 보니 이렇게 간단한데 몇 주를 팀원과 고생했었습니다.
인프라는 yaml과의 긴 싸움이군요.
마지막 팁은 helm의 values 기본값을 확인하는 방법입니다.
helm show values istio/istiod
일일이 레포지토리를 찾아가지 않아도 돼서 편리합니다.