├── .idea
├── .gitignore
├── misc.xml
├── modules.xml
├── vcs.xml
└── 쿠버네티스-구현.iml
├── ArgoCD
├── ArgoCD_GitOps_reload
│ ├── README.md
│ └── img.png
└── ArgoCD_optimization
│ ├── README.md
│ └── img.png
├── Canary
├── README.md
├── istio-canary
│ ├── README.md
│ ├── istio-canary-rules.yaml
│ ├── istio-session-Affinity.yaml
│ ├── istio.deployment.yaml
│ └── istio.service.yaml
└── standard-canary
│ ├── standard.deployment.yaml
│ └── standard.service.yaml
├── Docker
└── Docker-Root-Dir-Change
│ ├── README.md
│ └── img.png
├── README.md
├── argo_workflow
├── argo-workflow.yaml
├── local-gateway.yaml
└── local-vs.yaml
├── etc
├── README.md
├── configmap.volume.yaml
├── core_dns
│ └── README.md
├── download-api.yaml
├── env.yaml
└── kubernetes-system-layers
│ ├── README.md
│ └── img.png
├── img.png
├── istio
├── Istio-gateway
│ ├── README.md
│ ├── istio-canary-rules.yaml
│ └── istio-gateway.yaml
├── istio-Circuit-Breaking
│ ├── README.md
│ └── istio-circuit-breaking.rules.yaml
├── istio-coredns
│ ├── README.md
│ ├── img.png
│ ├── img_1.png
│ ├── img_2.png
│ ├── img_3.png
│ └── img_4.png
├── istio-envoy
│ ├── README.md
│ └── img.png
├── istio-mtls
│ ├── README.md
│ ├── permissive.mtls.yaml
│ └── strict.mtls.yaml
├── istio-prefix
│ └── istio-prefix-canary.yaml
├── istio-subdomain-routing
│ └── istio-subdomain-routing.yaml
└── istio-virtualService
│ ├── README.md
│ └── istio.virtual-service.yaml
├── k8s-preparation
└── README.md
├── pattern
├── README.md
└── pattern.yaml
├── resources
├── configmap
│ └── README.md
├── deployment
│ ├── README.md
│ ├── img.png
│ ├── img_1.png
│ └── img_2.png
├── namespace
│ ├── README.md
│ ├── istio-injection.namespace.yaml
│ └── namespace.yaml
├── pod
│ └── README.md
├── replicationController
│ └── README.md
├── service
│ └── README.md
└── volume
│ ├── README.md
│ └── git-repogistory.yaml
└── troubleshooting
├── GCP-L7(Load-Balancer)
└── README.md
├── Ingress
└── README.md
├── Kiali
└── README.md
├── Nginx-Proxy
└── README.md
├── Proxy-server
└── README.md
├── README.md
├── amd64-arm64
└── README.md
├── istio-gRpc
├── README.md
└── grpc.service.yaml
├── istio-install
└── README.md
├── kubernetes-resource-report
└── README.md
├── prometheus
├── README.md
├── chart.yaml
└── kafka-exporter-values.yaml
└── redis-sentinel
└── READMD.md
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/쿠버네티스-구현.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ArgoCD/ArgoCD_GitOps_reload/README.md:
--------------------------------------------------------------------------------
1 | # ConfigMap 변경을 자동 반영하는 GitOps 구성하기
2 |
3 |
4 | ### 기존 ConfigMap 관리 방식의 한계
5 | ConfigMap 변경을 자동으로 반영하는 GitOps 구성을 하기 전까지, 우리 팀은 다음과 같은 방식으로 작업을 진행하고 있었습니다.
6 |
7 | 개발자들이 ConfigMap에 추가하거나 수정해야 할 값이 생기면, 제가 ArgoCD와 연결된 Git 저장소 내 ConfigMap 정의 파일을 직접 수정하고, 커밋한 뒤, 관련 파드를 수동으로 재시작(rollout restart)해주는 방식이었죠.
8 |
9 | 이 작업은 표면적으로는 단순해 보이지만, 운영팀 전체 리소스의 반복적인 소모를 유발하고 있었고, 개발자 입장에서도 빈번한 요청을 전달하는 데 부담이 따를 수밖에 없었습니다.
10 | 이러한 불편함을 줄이고, 더 나아가 자율적인 설정 관리가 가능하게 만들 수 없을까 고민하게 되었습니다.
11 |
12 | ### 접근 방식과 해결방법
13 | 그래서 저는 다음과 같은 질문을 중심으로 접근을 시작했습니다:
14 | 1. 우리가 이미 보유한 기술 스택으로 해결할 수 있는 문제인가?
15 | 2. 개발자들이 직접 ConfigMap을 컨트롤할 수 있는 방식은 무엇인가?
16 | 3. ConfigMap이 수정되었을 때, 자동으로 관련 파드를 재시작할 수 있는 툴이나 프로젝트가 존재하는가?
17 |
18 | 여러 대안을 비교해본 결과, 우리 팀의 GitOps 구조에 가장 잘 맞는 해법은 Reloader + Argo CD 조합이었습니다.
19 | 주요 이유는 별도의 커스텀 로직 없이도 단순하게 적용 가능하고, DevOps팀이 직접 개입하지 않아도 개발자들이 설정을 변경했을 때 곧바로 반영된다는 점이었습니다.
20 |
21 | ### 구조 설계 및 도입 배경
22 | Reloader를 간단히 설명드리자면, Reloader는 Kubernetes에서 ConfigMap이나 Secret 리소스에 변경이 감지되면, 해당 리소스를 참조하고 있는 Deployment나 StatefulSet을 자동으로 재시작해주는 컨트롤러입니다.
23 |
24 | 저희 팀은 이미 Kustomize + Argo CD 조합으로 GitOps 기반의 배포 환경을 운영하고 있었고, 애플리케이션 리소스들과 함께 ConfigMap도 하나의 배포 단위로 포함되어 있었습니다.
25 |
26 | 하지만 이 구조에서는 ConfigMap만 수정하려 해도 전체 애플리케이션 리소스를 함께 변경해야 했기 때문에, 설정 관리의 유연성이 떨어지고 커밋 단위도 무거워지는 문제가 있었습니다.
27 |
28 | 그래서 저는 먼저 ConfigMap을 분리했고, ConfigMap만 별도로 관리할 수 있도록 GitOps 구조로 변경했습니다.
29 |
30 | 변경 후 개발자분들은 직접 ConfigMap을 수정하면, Argo CD를 통해 해당 변경이 자동으로 동기화되고, Reloader가 이를 감지하여 관련 Deployment가 자동으로 재시작되는 것을 확인할 수 있었습니다.
31 |
32 |
33 |
34 | ### 아키텍처 설명
35 | 
36 |
37 | 글로만 보면 다소 이해가 안될 수 있기 때문에, 그림을 보면서 다시 설명드리겠습니다.
38 | 저희는 먼저 ConfigMap을 별도의 Git 저장소로 분리했고, Argo CD가 해당 저장소를 바라보도록 설정했습니다.
39 | 그리고 Reloader가 클러스터 내 ConfigMap 리소스를 watch하도록 구성했으며,
40 | 이후에는 ConfigMap 값에 변경이 생기면, 이를 참조하고 있는 리소스를 자동으로 rollout restart하도록 설정했습니다.
41 |
42 |
43 |
44 | ### 구성방법
45 |
46 | ```shell
47 | apiVersion: kustomize.config.k8s.io/v1beta1
48 | kind: Kustomization
49 | namespace: example
50 | resources:
51 | - example-service-cm.yaml
52 | - example2-service-cm.yaml
53 | - example3-service-cm.yaml
54 | ```
55 | example 네임스페이스에서 사용되는 ConfigMap들을 Kustomization으로 관리할 수 있도록 설정합니다.
56 |
57 |
58 |
59 | ```shell
60 | apiVersion: v1
61 | kind: ConfigMap
62 | metadata:
63 | name: example-env
64 | namespace: example
65 | annotations:
66 | reloader.stakater.com/match: "true"
67 | data:
68 | TEST: "A"
69 | ```
70 | ConfigMap에 reloader.stakater.com/match: "true" 어노테이션을 추가하여, Stakater Reloader가 이 ConfigMap의 변경을 감지할 수 있도록 합니다.
71 |
72 | ```shell
73 | apiVersion: argoproj.io/v1alpha1
74 | kind: Application
75 | metadata:
76 | name: example-configmap
77 | namespace: argo
78 | annotations:
79 | argocd.argoproj.io/manifest-generate-paths: .
80 | spec:
81 | project: gitops-cm
82 | destination:
83 | namespace: example
84 | server: https://kubernetes.default.svc
85 | source:
86 | path: config/overlays/dev
87 | repoURL: https://configmap-gitops.git
88 | targetRevision: main
89 | syncPolicy:
90 | automated:
91 | prune: true
92 | ```
93 | ArgoCD에서 ConfigMap 리소스를 관리할 수 있도록 kustomize 경로를 지정하여 자동 동기화가 가능하게 구성합니다.
94 |
95 |
96 |
97 | ```shell
98 | apiVersion: apps/v1
99 | kind: Deployment
100 | metadata:
101 | name: example-collector
102 | annotations:
103 | reloader.stakater.com/search: "true"
104 | ```
105 | 해당 Deployment가 참조 중인 ConfigMap 변경을 감지할 수 있도록 reloader.stakater.com/search: "true" 어노테이션을 추가합니다.
106 |
107 | ### 흐름도
108 |
109 | ```shell
110 | [Developer]
111 | |
112 | v
113 | [Git Push - ConfigMap 변경]
114 | |
115 | v
116 | [ArgoCD]
117 | (Auto Sync)
118 | |
119 | v
120 | [Kustomize]
121 | (Apply ConfigMap)
122 | |
123 | v
124 | +---------------------------+
125 | | ConfigMap (annotated) |
126 | +---------------------------+
127 | |
128 | | +-----------------------------+
129 | |----> | Deployment (annotated too) |
130 | | +-----------------------------+
131 | |
132 | v
133 | +---------------------------+
134 | | Stakater Reloader |
135 | | (감지 후 자동 재시작) |
136 | +---------------------------+
137 | |
138 | v
139 | +---------------------------+
140 | | Pod 재시작 |
141 | +---------------------------+
142 |
143 | ```
144 |
145 |
146 |
147 | ### 결론
148 | 이번 구조 개선을 통해 ConfigMap 변경 작업이 더 이상 번거로운 수작업이 아닌, GitOps 기반으로 자동화되었습니다. 비록 작은 구조적 변화였지만, 개발자와 운영자 모두의 부담을 크게 줄일 수 있었고, GitOps의 진정한 장점을 팀원들과 함께 체감할 수 있는 계기가 되었습니다. 앞으로도 이런 작지만 실용적인 개선을 꾸준히 이어가 보려 합니다.
149 |
150 |
--------------------------------------------------------------------------------
/ArgoCD/ArgoCD_GitOps_reload/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youyoungnam/kubernetes-implement/1a113e9ad0bfb3141753dbac7363626bcec99829/ArgoCD/ArgoCD_GitOps_reload/img.png
--------------------------------------------------------------------------------
/ArgoCD/ArgoCD_optimization/README.md:
--------------------------------------------------------------------------------
1 | # ArgoCD 운영 최적화
2 |
3 |
4 | 최근 운영 중인 클러스터에서 자주 장애가 발생하는 이슈가 있었습니다. 원인을 조사한 결과, ArgoCD가 주요 원인중 하나임을 확인했습니다. 초기에는 기본 구성으로 ArgoCD를 배포하고 운영해 왔지만, 시간이 지나면서 점점 늘어나는 클러스터와 Application 수로 인해 문제가 발생하기 시작했습니다.
5 |
6 | 현재 단일 ArgoCD에 10개 이상의 클러스터가 연결되어 있으며, ArgoCD가 관리하는 Application 수도 300개 + 이상으로 증가한 상태입니다.
7 |
8 |
9 | ## 발견된 문제점
10 | - 단일 application-controller의 CPU 및 메모리 사용량 급증 (스파이크)
11 | - CICD 실행 시 argocd-application, argocd-repo-server의 CPU 사용량 급증
12 |
13 |
14 | ## 적용한 최적화 방식
15 | - Pull 방식에서 Push 방식으로 변경
16 | - application-controller HA 구성
17 | - argocd-repo-server 옵션 최적화
18 |
19 |
20 |
21 |
22 | ### Application Controller 최적화
23 | - HA 구성
24 | - ArgoCD가 관리하는 클러스터가 점차 많아질 수 록 ArgoCD의 Application Controller는 더 많은 cpu와 memory가 소비될 수 있습니다. 특이점이 왔을 때 Replicas를 늘려 관리하는 클러스터를 나눠서 운영할 수 있게 해주는게 좋습니다.
25 | - 단순히 replicas만 늘린다고 해서 해결되지는 않고, Kubernetes 클러스터의 서브셋을 담당하도록 구성해야 합니다. 해당값 조정은 ARGOCD_CONTROLLER_REPLICAS option을 조절하면 됩니다.
26 | ```shell
27 | - name: ARGOCD_CONTROLLER_REPLICAS
28 | value: "2"
29 | ```
30 |
31 |
32 |
33 | ### pull 방식에서 push 방식으로 변경
34 | - ArgoCD는 기본적으로 Pull 방식을 사용하여 매 3분마다 Git 저장소를 체크하고, 변경 사항이 있으면 동기화를 수행합니다. 그러나 단일 Application이 업데이트될 때마다 전체 레포지토리 캐시가 무효화되어 비효율적인 동작이 발생할 수 있습니다.
35 | - 이를 개선하기 위해, Bitbucket Webhook을 활용하여 변경된 Application만 ArgoCD에 알리고, 해당 Application만 동기화하는 Push 방식을 적용하였습니다.
36 |
37 |
38 |
39 |
40 | ```shell
41 | # bitbucket push webhook
42 | k get secret -n argo argocd-secret
43 | # bitbucket webhook Header에 있는 X-Hook-UUID값으로 넣어주기
44 | webhook.bitbucket.uuid: bitbucket webhook X-Hook-UUID
45 |
46 |
47 | # argocd application annotation
48 | apiVersion: argoproj.io/v1alpha1
49 | kind: application
50 | metadata:
51 | name: example-guestbook
52 | namespace: argo
53 | annotations:
54 | # 'guestbook' 디렉토리로 경로
55 | # 동기화될 application 위치를 작성해야합니다.
56 | argocd.argoproj.io/manifest-generate-paths: .
57 | spec:
58 | source:
59 | repoURL: https://argocd-repo.git
60 | targetRevision: HEAD
61 | path: guestbook
62 | ```
63 | ```shell
64 | # 적용되었는지 확인
65 | k describe secret -n argo argocd-secre
66 | ```
67 | 
68 |
69 | 참고자료
70 | - https://argo-cd.readthedocs.io/en/stable/operator-manual/high_availability/
71 |
72 |
73 | ## Argocd repo server option 최적화
74 | ```shell
75 | reposerver.enable.git.submodule: "false"
76 | reposerver.kubectl.parallelism.limit: "3"
77 | reposerver.parallelism.limit: "3" # 애플리케이션이 동기화하는데 영향이 있을 수 있습니다.
78 | reposerver.repo.cache.expiration: 6h
79 | ```
80 |
81 | ## 정리 및 옵션 설명
82 |
83 | ArgoCD Gitops의 기본적인 원리를 간단하게 설명하겠습니다. Git 저장소에 쿠버네티스 리소스를 manifest를 선언하여 단일 진실 공급원(SSOT)방식으로 운영합니다.
84 | ArgoCD는 이 상태를 지속적으로 관찰하며 현재 클러스터에 배포된 애플리케이션 상태와 git의 상태를 비교하여 다르면 Git의 상태에 맞게 배포합니다.
85 |
86 | reposerver.parallelism.limit 옵션은 Git 저장소 동기화 순서를 제어합니다.
87 |
88 | reposerver.kubectl.parallelism.limit: Kubernetes 리소스 병렬 배포 제어합니다.
89 |
90 | reposerver.repo.cache.expiration: Git 저장소 캐시 만료 시간 설정합니다.
91 |
92 | 그렇다면 reposerver.repo.cache.expiration 어떤역할을 할까요? Git의 저장소를 매번 다운로드 하지않습니다. 변경된 부분만 빠르게 배포합니다.
93 |
94 |
95 | 한번 실제로 변경된 부분만 체크하는지 확인해봅시다.
96 | ```shell
97 | argocd app get remote-user
98 |
99 |
100 | Name: argo/remote-user
101 | Project: default
102 | Server: https://kubernetes.default.svc
103 | Namespace: default
104 | URL: https://x.x.x.x/applications/example-remote-app
105 | Target: main
106 | Path: frontend/remote-app/overlays/dev
107 | SyncWindow: Sync Allowed
108 | Sync Policy: Automated (Prune)
109 | Sync Status: Synced to dev (2f97addw)
110 | Health Status: Healthy
111 |
112 | GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
113 | ConfigMap default remote-app-config Synced configmap/example-remote-app-config unchanged
114 | Service default example-remote-app Synced Healthy service/example-remote-app unchanged
115 | apps Deployment default example-remote-app Synced Healthy deployment.apps/example-remote-app configured
116 | ```
117 |
118 | 각 옵션들은 환경에 맞게 테스트를 해야합니다. 추가적으로 ArgoCD를 운영하면서 최적화를 더 할 수 있는 부분이 생긴다면 업데이트하도록 하겠습니다.
119 |
120 |
121 | ### 참고 문서
122 | - https://argo-cd.readthedocs.io/en/release-2.2/operator-manual/server-commands/argocd-repo-server/
123 | - https://argo-cd.readthedocs.io/en/stable/operator-manual/argocd-cmd-params-cm-yaml/
124 | - https://argo-cd.readthedocs.io/en/stable/operator-manual/high_availability/
125 |
126 |
127 |
128 | ### ArgoCD에서 설정할 수 있는 param cm을 확인할 수 있는 공식문서
129 | https://argo-cd.readthedocs.io/en/latest/operator-manual/server-commands/additional-configuration-method/
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/ArgoCD/ArgoCD_optimization/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youyoungnam/kubernetes-implement/1a113e9ad0bfb3141753dbac7363626bcec99829/ArgoCD/ArgoCD_optimization/img.png
--------------------------------------------------------------------------------
/Canary/README.md:
--------------------------------------------------------------------------------
1 | # Canary
2 | - 표준 쿠버네티스 방식으로 Canary 배포 방식 구현하기
3 | - 추후에는 Service Mesh - istio-방식으로 Canary 배포 방식 구현
4 |
5 | ## Standard Canary
6 | - 하나의 서비스는 여러개의 파드를 가질 수 있다.
7 | - 쿠버네티스에서는 하나의 서비스에 다수의 Pod가 존재한다면, 파드를 찾는 방법은 Load Balancing 방식으로 찾아간다.
8 | - 만약 여기서 파드를 10%씩만 전달하게 하고싶다고 가정한다면, 파드를 10개를 만드는 방법도 괜찮은걸까? 심지어 여기에 단 특정 1%정도만 특정 파드에게 가도록 하고싶다면 어떤식으로 구현을 해야할까?
9 | - 만약 이것을 표준 쿠버네티스 방식을 구현하게 된다면 아래와 같이 구현할 수 있을거 같다.
10 |
11 | Example: 내가 이전에 Gitops ArgoCD 테스트한다고 이미지 만들어 놓은게 있는데 여기서 테스트해볼 수 있을거같다.
12 | deployment와 service를 왜 이런식으로 만들었지 라고 생각할 수 있는데 빠르게 테스트하고 싶어서..
13 |
14 | ```
15 | ---
16 | apiVersion: apps/v1
17 | kind: Deployment
18 | metadata:
19 | name: python-web-safe
20 | spec:
21 | selector:
22 | matchLabels:
23 | app: python-service
24 | replicas: 2
25 | template:
26 | metadata:
27 | labels:
28 | app: python-service
29 | version: safe
30 | spec:
31 | containers:
32 | - name: python-service
33 | image: dbdudska113/flask_y:latest
34 | imagePullPolicy: Always
35 | ports:
36 | - containerPort: 8080
37 | ---
38 | apiVersion: apps/v1
39 | kind: Deployment
40 | metadata:
41 | name: python-web-risk
42 | spec:
43 | selector:
44 | matchLabels:
45 | app: python-service
46 | replicas: 1
47 | template:
48 | metadata:
49 | labels:
50 | app: python-service
51 | version: risk
52 | spec:
53 | containers:
54 | - name: vue-service
55 | image: dbdudska113/flask_y:v3
56 | imagePullPolicy: Always
57 | ports:
58 | - containerPort: 8080
59 | ---
60 | apiVersion: v1
61 | kind: Service
62 | metadata:
63 | name: python-service
64 | spec:
65 | selector:
66 | app: python-service
67 | ports:
68 | - name: http
69 | nodePort: 31532
70 | port: 8080
71 | targetPort: 5000
72 | type: NodePort
73 | ```
74 | ## 실험
75 |
76 | ```
77 | while true; do curl http://127.0.0.1:31532/name; echo; sleep 1; done
78 | ```
79 |
80 | 
81 |
82 |
83 |
84 | 이미지를 보면 name이라는 api가 있는 version으로 파드를 호출하거나 api가 없는 version으로 호출하거나 한다.
85 |
86 | ---
87 | ## Istio-Canary
88 | - Istio에서 Canary배포를 어떻게 구현할 수 있을까? 내가 알고 있는 방법이 100% 정답이라고 장담은 할 수 없지만 일단 도전을 해보는걸로
89 | - 회사내에서도 Istio Service Mesh를 사용중이기 때문에 연습이 필요하다.
90 | - Istio를 활용해서 Canary배포를 연습하기 위해서 필요한건 virtual service와 DestinationsRule이다.
91 |
92 | ## Virtual Service
93 | - 처음에 이스티오를 사용한다 했을 때 Virtual Service 단어는 너무나 어려워 보였다. 솔직히 어떤식으로 동작하는지도 전혀 몰랐고.. 쿠버네티스도 어려운데 Service Mesh 사용한다고 하니까 어려웠다.
94 |
95 | - 단어에 겁을 먹지말고, 내가 생각한 Virtual Service는 직관적으로 라우팅 규칙을 구성을 할 수 있는 것이라고 생각하면된다.
96 |
97 |
98 | - 이스티오를 사용한다면 Istio-pilot을 알고 있을 것이다 Istio-pilot은 Virtual Service 정의한 yaml를 가지고 있다고 생각하면 된다. 즉 파일럿은 즉시 실시간으로 Envoy Proxy를 구성하는 역할을 한다. 우리가 VS(Virtual Service)에 큰 변동사항이 있다고 가정하면 이러한 정보들이 파일럿으로 가고 파일럿이 사용자 지정 라우팅 규칙의 결과로서 변경되어야 할 모든 프록시에 전달한다.
99 |
100 | - 사실 모든 Canary를 배포하는건 envoy이다. 이스티오는 구성이 필요한 모든 프록시를 구성할 능력을 우리에게 주는 것이다. 우리는 사실 프록시에 대해 생각할 필요가 없다. 우리는 단지 높은 수준의 Virtual Service 개념에서 작업할 수 있다. 하지만 실제로 우리가 하는 일은 프록시를 구성하는 것이다.
101 |
102 |
103 |
104 |
105 | ### VirtualService
106 | ```
107 | kind: VirtualService
108 | apiVersion: networking.istio.io/v1alpha3
109 | metadata:
110 | name: a-set-of-routing-rules-virtual-service # Virtual Service 이름을 작성한다.
111 | namespace: default
112 | spec:
113 | hosts:
114 | - python-service.default.svc.cluster.local #Service DNS 작성해야 한다.
115 | http:
116 | - route:
117 | - destination:
118 | host: python-service.default.svc.cluster.local
119 | subset: safe
120 | weight: 100
121 | - destination:
122 | host: python-service.default.svc.cluster.local
123 | subset: risky
124 | weight: 0
125 | ```
126 | ### DestinationsRule
127 | ```
128 | # 어떤 파드가 각각의 서브셋에 속할지 정하는 것
129 | kind: DestinationsRule
130 | apiVersion: networking.istio.io/v1alpha3
131 | metadata:
132 | name: python-service-service-destination
133 | namespace: default
134 | spec:
135 | host: python-service # Service
136 | trafficPolicy: ~
137 | subsets:
138 | - labels: # Selector
139 | version: safe # 파드의 label "safe"
140 | name: safe
141 | - labels:
142 | version: risky # 파드의 label "risky"
143 | name: risky
144 | ```
145 |
146 | ---
147 |
--------------------------------------------------------------------------------
/Canary/istio-canary/README.md:
--------------------------------------------------------------------------------
1 | ## 세션 어피니티
2 |
3 | ### 스티키 세션
4 | - 세션이 유지되도록 하는 것
5 | - 주로 로드 밸런싱 환경에서 세션을 유지하도록 하는것을 말한다.
6 | - istio에는 consistent Hashing이라는 옵션이 있다. 이것을 이용하면 스티키 세션을 할 수 있다.
7 | - 예시) A라는 파드와 B라는 파드가 존재한다. Consistent Hashing은 클라이언트에서 들어온 요청이 로드 밸런싱으로 들어왔을 때 이 데이터들을 특정 해싱 알고리즘에 적용해서 출력값을 통해 어떤 파드로 전달할지 구현할 수 있는 옵션이다.
8 | - 예를들어 클라이언트에서 ip를 가지고 들어올 수 있는데 이 ip가 홀수인지 아니면 짝수인지를 가지고 A파드 혹은 B파드로 갈 수 있게 할 수 있다.
9 | - 그렇다면 ip를 가지고 홀수 인지 짝수인지를 구분할 수 있다고 한다면, A파드로 갈지 B파드로 갈지 어디서 정하는가? 그냥 vs에 weigth값을 전달하면 되는건가? 그러면 어디가 짝수이고 어디가 홀수인가? 의문점이 많다. 그냥 weigth를 더 많이 주는 쪽이 짝수인것인가..? 이것은 조금 더 알아볼 필요가 있다.
10 | - 찾아보니까 이스티오 envoy는 가중치 서브셋과 세션 어피니티를 동시에 사용할 수 없다고 한다. 만약 세션어피니티와 가중치를 같이 사용하게 된다면 이런식으로 동작한다
11 | - client -----> weight ------> LoadBalancer -----> POD 이미 weight에서 나눠졌는데 결국 로드벨런서는 하나의 파드만 가게되는 것이다. 즉, 로드벨런서에서 두개의 파드로 또 나눠서 가는게 아니다.
12 | -
13 |
14 | ```
15 | kind: DestinationRule
16 | apiVersion: networking.istio.io/v1alpha3
17 | metadata:
18 | name: python-service-service-destination
19 | namespace: default
20 | spec:
21 | host: python-service # Service
22 | trafficPolicy:
23 | loadBalancer:
24 | consistentHash:
25 | useSourceIp: true
26 | subsets:
27 | - labels: # Selector
28 | version: safe # 파드의 label "safe"
29 | name: safe
30 | - labels:
31 | version: risky # 파드의 label "risky"
32 | name: risky
33 | ```
--------------------------------------------------------------------------------
/Canary/istio-canary/istio-canary-rules.yaml:
--------------------------------------------------------------------------------
1 | kind: VirtualService
2 | apiVersion: networking.istio.io/v1alpha3
3 | metadata:
4 | name: a-set-of-routing-rules-virtual-service # Virtual Service 이름을 작성한다.
5 | namespace: default
6 | spec:
7 | hosts:
8 | - python-service.default.svc.cluster.local #Service DNS 작성해야 한다.
9 | http:
10 | - route:
11 | - destination:
12 | host: python-service.default.svc.cluster.local
13 | subset: safe
14 | weight: 100
15 | - destination:
16 | host: python-service.default.svc.cluster.local
17 | subset: risky
18 | weight: 0
19 | ---
20 | kind: DestinationRule
21 | apiVersion: networking.istio.io/v1alpha3
22 | metadata:
23 | name: python-service-service-destination
24 | namespace: default
25 | spec:
26 | host: python-service # Service
27 | subsets:
28 | - labels: # Selector
29 | version: safe # 파드의 label "safe"
30 | name: safe
31 | - labels:
32 | version: risky # 파드의 label "risky"
33 | name: risky
--------------------------------------------------------------------------------
/Canary/istio-canary/istio-session-Affinity.yaml:
--------------------------------------------------------------------------------
1 | kind: DestinationRule
2 | apiVersion: networking.istio.io/v1alpha3
3 | metadata:
4 | name: python-service-service-destination
5 | namespace: default
6 | spec:
7 | host: python-service # Service
8 | trafficPolicy:
9 | loadBalancer:
10 | consistentHash:
11 | useSourceIp: true
12 | subsets:
13 | - labels: # Selector
14 | version: safe # 파드의 label "safe"
15 | name: safe
16 | - labels:
17 | version: risky # 파드의 label "risky"
18 | name: risky
--------------------------------------------------------------------------------
/Canary/istio-canary/istio.deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: python-web-safe
5 | spec:
6 | selector:
7 | matchLabels:
8 | app: python-service
9 | replicas: 2
10 | template:
11 | metadata:
12 | labels:
13 | app: python-service
14 | version: safe
15 | spec:
16 | containers:
17 | - name: python-service
18 | image: dbdudska113/flask_y:latest
19 | imagePullPolicy: Always
20 | ports:
21 | - containerPort: 8080
22 | ---
23 | apiVersion: apps/v1
24 | kind: Deployment
25 | metadata:
26 | name: python-web-risk
27 | spec:
28 | selector:
29 | matchLabels:
30 | app: python-service
31 | replicas: 1
32 | template:
33 | metadata:
34 | labels:
35 | app: python-service
36 | version: risk
37 | spec:
38 | containers:
39 | - name: vue-service
40 | image: dbdudska113/flask_y:v3
41 | imagePullPolicy: Always
42 | ports:
43 | - containerPort: 8080
--------------------------------------------------------------------------------
/Canary/istio-canary/istio.service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: python-service
5 | spec:
6 | selector:
7 | app: python-service
8 | ports:
9 | - name: http
10 | nodePort: 31532
11 | port: 8080
12 | targetPort: 5000
13 | type: NodePort
--------------------------------------------------------------------------------
/Canary/standard-canary/standard.deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: python-web-safe
5 | spec:
6 | selector:
7 | matchLabels:
8 | app: python-service
9 | replicas: 2
10 | template:
11 | metadata:
12 | labels:
13 | app: python-service
14 | version: safe
15 | spec:
16 | containers:
17 | - name: python-service
18 | image: dbdudska113/flask_y:latest
19 | imagePullPolicy: Always
20 | ports:
21 | - containerPort: 8080
22 | ---
23 | apiVersion: apps/v1
24 | kind: Deployment
25 | metadata:
26 | name: python-web-risk
27 | spec:
28 | selector:
29 | matchLabels:
30 | app: python-service
31 | replicas: 1
32 | template:
33 | metadata:
34 | labels:
35 | app: python-service
36 | version: risk
37 | spec:
38 | containers:
39 | - name: vue-service
40 | image: dbdudska113/flask_y:v3
41 | imagePullPolicy: Always
42 | ports:
43 | - containerPort: 8080
--------------------------------------------------------------------------------
/Canary/standard-canary/standard.service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: python-service
5 | spec:
6 | selector:
7 | app: python-service
8 | ports:
9 | - name: http
10 | nodePort: 31532
11 | port: 8080
12 | targetPort: 5000
13 | type: NodePort
--------------------------------------------------------------------------------
/Docker/Docker-Root-Dir-Change/README.md:
--------------------------------------------------------------------------------
1 | # Docker Root 경로 변경하기
2 |
3 | **Docker Root Dir**은 Docker가 이미지, 컨테이너, 볼륨, 네트워크 등의 데이터를 저장하는 기본 디렉토리 경로입니다.
4 |
5 | 그렇다면, Docker root 경로를 기본 `/var/lib/docker`가 아닌 다른 디스크 경로로 변경하려면, Docker의 데이터 루트를 변경해야 합니다.
6 |
7 | ### **1. Docker 서비스 중지**
8 |
9 | ```bash
10 | bash
11 |
12 | sudo systemctl stop docker
13 |
14 | ```
15 |
16 | ### **2. 새로운 저장 경로 생성 및 마운트 (예: `/mnt/docker` 사용) mount된 경로 있어서 선택사항**
17 |
18 | 만약 이미 디스크를 `/mnt/docker`로 마운트했다면 이 과정은 건너뛰어도 됩니다.
19 |
20 | ```bash
21 | bash
22 |
23 | sudo mkdir -p /mnt/docker
24 |
25 | ```
26 |
27 | 기존 Docker 데이터를 새로운 경로로 복사하려면:
28 |
29 | ```bash
30 | bash
31 |
32 | sudo rsync -aP /var/lib/docker/ /mnt/disk/data/docker
33 |
34 | ```
35 |
36 | ### **3. Docker 데몬 설정 변경**
37 |
38 | Docker의 데이터 저장 경로를 변경하려면 `/etc/docker/daemon.json`을 수정해야 합니다.
39 |
40 | ```bash
41 |
42 | sudo vi /etc/docker/daemon.json
43 |
44 | ```
45 |
46 | 아래 내용을 추가하거나 수정합니다:
47 |
48 | ```json
49 |
50 | {
51 | "data-root": "/mnt/disk/data/docker"
52 | }
53 |
54 | ```
55 |
56 | ### **4. 기존 Docker 데이터 백업 및 제거 (선택 사항)**
57 |
58 | (만약 새로운 경로로 데이터를 복사했다면 기존 데이터 삭제 가능)
59 |
60 | ```bash
61 |
62 | sudo mv /var/lib/docker /var/lib/docker.bak
63 |
64 | ```
65 |
66 | ### **5. Docker 서비스 재시작**
67 |
68 | ```bash
69 |
70 | sudo systemctl daemon-reload (설치 되어 있으면)
71 | sudo systemctl restart docker
72 |
73 | ```
74 |
75 | ### **6. 변경 사항 확인**
76 |
77 | Docker가 정상적으로 새로운 경로를 사용하는지 확인하려면:
78 |
79 | ```bash
80 |
81 | docker info | grep "Docker Root Dir"
82 |
83 | ```
84 |
85 | 출력 예시:
86 |
87 | 
88 |
89 |
90 | 이제 `docker images` 명령어를 실행하면 새로운 경로에 저장된 이미지가 표시됩니다. 🚀
91 |
92 | ### 7. Docker Restart
93 |
94 | ```bash
95 | systemctl restart docker
96 | ```
97 |
98 | ### 8. Docker 재실행 후 문제 없는지 확인하고 기존 경로 제거
99 |
100 | ```bash
101 | rm -r /var/lib/docker/
102 | ```
--------------------------------------------------------------------------------
/Docker/Docker-Root-Dir-Change/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youyoungnam/kubernetes-implement/1a113e9ad0bfb3141753dbac7363626bcec99829/Docker/Docker-Root-Dir-Change/img.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Kubernetes make me interesting
2 | ---
3 |
4 |
5 |
6 |
7 |
8 | ---
9 | ## Kubernetes
10 | - [Kubernetes](https://github.com/youyoungnam/kubernetes-implement/tree/main/k8s-preparation)
11 |
12 |
13 | ## Canary
14 | - [Canary](https://github.com/youyoungnam/kubernetes-implement/tree/main/Canary)
15 | - [istio-Canary](https://github.com/youyoungnam/kubernetes-implement/tree/main/Canary/istio-canary)
16 |
17 |
18 | ## istio-Gateway
19 | - [istio-Gateway](https://github.com/youyoungnam/kubernetes-implement/tree/main/istio/Istio-gateway)
20 | - [istio-prefix](https://github.com/youyoungnam/kubernetes-implement/tree/main/istio/istio-prifx)
21 | - [istio-subdomain-routing](https://github.com/youyoungnam/kubernetes-implement/tree/main/istio/istio-subdomain-routing)
22 |
23 |
24 | ## istio-Circuit Breaking
25 | - [istio-Circuit Breaking](https://github.com/youyoungnam/kubernetes-implement/tree/main/istio/istio-Circuit-Breaking)
26 |
27 |
28 | ## istio-mTLS
29 | - [istio-mTLS](https://github.com/youyoungnam/kubernetes-implement/tree/main/istio/istio-mtls)
30 |
31 |
32 | ## istio- Virtual Service
33 | - [istio-virtualService](https://github.com/youyoungnam/kubernetes-implement/tree/main/istio/istio-virtualService)
34 |
35 | ## istio- istio DNS cache
36 | - [istio DNS cache](https://github.com/youyoungnam/kubernetes-implement/tree/main/istio/istio-coredns)
37 |
38 |
39 | ## Kubernetes-resource
40 | - [namespace](https://github.com/youyoungnam/kubernetes-implement/tree/main/resources/namespace)
41 | - [service](https://github.com/youyoungnam/kubernetes-implement/tree/main/resources/service)
42 | - [pod](https://github.com/youyoungnam/kubernetes-implement/tree/main/resources/pod)
43 | - [deployment](https://github.com/youyoungnam/kubernetes-implement/tree/main/resources/deployment)
44 | - [configmap](https://github.com/youyoungnam/kubernetes-implement/tree/main/resources/configmap)
45 |
46 |
47 | ## Troubleshooting Experience
48 | - [proxy-server](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/Proxy-server)
49 | - [Nginx-server](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/Nginx-Proxy)
50 | - [GCP-L7](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/GCP-L7(Load-Balancer))
51 | - [prometheus](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/prometheus)
52 | - [redis-sentinel](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/redis-sentinel)
53 | - [Kiali](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/Kiali)
54 | - [docker(arm64, amd64)](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/amd64-arm64)
55 | - [Ingress](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/Ingress)
56 | - [istio-gRpc](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/istio-gRpc)
57 | - [kubernetes-resource-report](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/kubernetes-resource-report)
58 | - [istio-install](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/istio-install)
59 |
60 |
61 | ## Docker Experience
62 | - [How to change Docker Root path](https://github.com/youyoungnam/kubernetes-implement/tree/main/Docker/Docker-Root-Dir-Change)
63 |
64 |
65 | ## ArgoCD
66 | - [ArgoCD_optimization](https://github.com/youyoungnam/kubernetes-implement/tree/main/ArgoCD/ArgoCD_optimization)
67 | - [ArgoCD_Configmap_GitOps](https://github.com/youyoungnam/kubernetes-implement/tree/main/ArgoCD/ArgoCD_GitOps_reload)
68 | ## ETC
69 | - [etc](https://github.com/youyoungnam/kubernetes-implement/tree/main/etc)
70 | - docker and kubernetes 팁 등등 configmap volume mounts
71 | - [pattern](https://github.com/youyoungnam/kubernetes-implement/tree/main/pattern)
72 | - [core-dns](https://github.com/youyoungnam/kubernetes-implement/tree/main/etc/core_dns)
73 |
--------------------------------------------------------------------------------
/argo_workflow/argo-workflow.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: argoproj.io/v1alpha1
2 | kind: Workflow
3 | metadata:
4 | name: hello
5 | spec:
6 | entrypoint: main # the first template to run in the workflows
7 | templates:
8 | - name: main
9 | container: # this is a container template
10 | image: docker/whalesay # this image prints "hello world" to the console
11 | command: ["cowsay"]
12 |
13 |
14 |
--------------------------------------------------------------------------------
/argo_workflow/local-gateway.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.istio.io/v1beta1
2 | kind: Gateway
3 | metadata:
4 | name: local-gateway
5 | namespace: istio-system
6 | spec:
7 | selector:
8 | istio: ingressgateway
9 | servers:
10 | - port:
11 | number: 80
12 | name: http2
13 | protocol: HTTP
14 | hosts:
15 | - "*"
16 | - port:
17 | number: 2746
18 | name: argo-workflow
19 | protocol: TCP
20 | hosts:
21 | - "*"
--------------------------------------------------------------------------------
/argo_workflow/local-vs.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.istio.io/v1beta1
2 | kind: VirtualService
3 | metadata:
4 | name: local-vs
5 | namespace: istio-system
6 | spec:
7 | gateways:
8 | - local-gateway
9 | hosts:
10 | - "*"
11 | tcp:
12 | - match:
13 | - port: 2746
14 | route:
15 | - destination:
16 | host: argo-server.argo.svc.cluster.local
17 | port:
18 | number: 2746
--------------------------------------------------------------------------------
/etc/README.md:
--------------------------------------------------------------------------------
1 | ## command와 args
2 | - command와 args는 파드가 생성된 이후에는 업데이트 할 수 없다.
3 | - command는 컨테이너 안에서 실행되는 실행 파일
4 | - args는 실행파일에 전달되는 인자
5 |
6 | TIP) ENTRYPOINT - command, CMD - args
7 |
8 |
9 | ## 컨테이너의 환경변수 설정
10 | - 파드의 각 컨테이너를 우ㅟ한 환경변수 리스트를 지정할 수 있다. 예를들어 A라는 컨테이너가 파이썬 애플리케이션이라고 가정하고 환경변수를 아래처럼 지정한다면 os.environ['INTERVAL']로 불러올 수 있다.
11 | ```agsl
12 | apiVersion: v1
13 | kind: Pod
14 | metadata:
15 | name: appname
16 | labels:
17 | name: appname
18 | spec:
19 | containers:
20 | - name: appname
21 | image: gcr.io/google-containers/busybox
22 | env:
23 | - name: INTERVAL
24 | value: "30"
25 | ports:
26 | - containerPort: 8080
27 | ```
28 |
29 | 이러한 방식의 단점 파드 정의에 하드코딩된 값을 가져오는 것은 효율적이지만, 프로덕션과 개발을 위해 서로 분리된 파드 정의가 필요하다는 것 여러 환경에서 동일한 파드 정의를 재 사용하려면 파드 정의에서 설정을 분리하는게 좋다.
30 | configmap을 사용한다면 환경별로 분리하여 사용할 수 있다.
31 |
32 | command line으로 configmap 만들기
33 | ```agsl
34 | kubectl create configmap app-config --from-literal=sleep-interval=25
35 |
36 | Configmap: app-config
37 | sleep-interval: 25
38 |
39 | # 파일을 가지고 configmap만들기
40 | kubectl create app-config --from-file=customkey=config-file.conf
41 | ```
42 | 경험상 파일을 가지고 configmap만들 때는 나는 주로 사내 IDC 통신에 필요한 사이드카 형태로 만들 때 사용했다. configmap보단 secret으로 만들었다.
43 |
44 |
45 | ### 볼륨안에 있는 컨피그맵 사용
46 | - 컨피그맵의 내용을 가진 볼륨을 생성하는 것은 컨피그맵 이름으로 참조하는 볼륨을 만들고 이 볼륨을 컨테이너에 마운트하는 만큼 간단하다.
47 | ```agsl
48 | apiVersion: v1
49 | kind: Pod
50 | metadata:
51 | name: appname
52 | labels:
53 | name: appname
54 | spec:
55 | containers:
56 | - name: appname
57 | image: gcr.io/google-containers/busybox
58 | ports:
59 | - containerPort: 8080
60 | volumeMounts:
61 | - name: config
62 | mountPath: /etc/nginx/conf.d # configmap 볼륨 마운트하는 위치
63 | readOnly: true
64 | volumes:
65 | - name: config
66 | configMap:
67 | name: ex-config
68 | ```
69 |
70 |
71 | ### 디렉토리 안에 다른 파일을 숨기지 않고 개별 컨피그맵 항목을 파일로 마운트
72 | - 컨피그맵의 항목을 개별 파이로 기존 디렉토리 안에 있는 모든 파일을 숨기지 않고 추가하는 방법은 전체 볼륨을 마운트하는 대신 volumeMount에 subPath를 속성으로 파일이나 디렉토리 하나를 볼륨에 마운트할 수 있다.
73 |
74 |
75 | 
76 |
77 |
78 |
79 |
80 | ### configmap과 secret 둘중 어느것을 사용해야할까
81 | - 민강하지않고 일반 설정 데이터는 configmap을 사용
82 | - 본질적으로는 민감한 데이터는 시크릿을 사용해 키 아래에 보관하는게 필요
83 | - 만약에 설정파일에 민감한 데이터와 민감하지 않은 데이터가 동시에 있다면 시크릿을 사용하는게 좋다.
84 |
85 |
86 |
87 | 시크릿은 컨피그맵과 다르게 yaml 내부를 확인해 보면 바이너리 데이터로 되어 있는것을 확인할 수 있다. 시크릿은 바이너리 데이터도 담을 수 있다. 하지만 시크릿의 최대 크기는 1MB이다.
88 |
89 |
90 | 만약에 특정 파드가 tls인증서를 사용하는지 안하는지 테스트하고 싶다면 아래 방법을 통해 확인할 수 있다.
91 | ```agsl
92 | kubectl port-forward pod-name 8443:8443 & curl https://localhost:8443 -k
93 | ```
94 |
95 |
96 | secret 볼륨은 시크릿 파일을 저장하는 데 인메모리 파일시스템(tmpfs)을 사용한다. 컨테이너에 마운트된 볼륨을 조회하면 알 수 있다.
97 |
98 | TIP) 쿠버네티스에서는 시크릿을 환경변수로 노출할 수 있게 해주지만, 이 기능을 사용하는 것이 가장 좋은 방법은 아니다. 애플리케이션은 일반적으로 error를 보여줄 때 환경변수를 기록하거나 시작하면서 로그에 환경변수를 의도치않게 남길 수 있다
99 | 그리고 자식 프로세스는 상위 프로세스의 모든 환경변수를 상속받는다 그 때 애플리케이션이 타사 바이너리를 실행할 경우 시크릿 데이터를 어떻게 사용하는지 알 방법이 없다.
100 | 즉, 환경변수로 시크릿을 컨테이너에 전달하는 것은 의도치 않게 노출될 수 있다. 그렇기 때문에 생각하고 사용해야한다. 그렇다면 어떻게 사용해야할까? 시크릿 볼륨을 통해 사용해야 한다.
101 | ```agsl
102 | env:
103 | - name: TEST_SECRET
104 | valueFrom:
105 | secretKeyRef:
106 | name: test-https
107 | key: yy
108 | ```
109 |
110 | ### DownLoad API
111 | download API는 파드의 레이블이나 어노테이션과 같이 어딘가에 이미 설정된 데이터를 여러곳에 반복해서 설정하고 싶지않을 때 사용하면좋다. 즉, 환경변수 또는 download API volume 내에 잇는 파일로 파드와 해당 환경의 메타 데이터를 전달할 수 있다.
112 | Download API는 애플리케이션이 호출해서 데이터를 가져오는 REST 엔드포인트와 다르다.
113 |
114 | download API를 사용하면 아래 항목들을 컨테이너에 전달할 수 있다.
115 | - 파드의 이름
116 | - 파드의 ip주소
117 | - 파드가 속한 네임스페이스
118 | - 파드가 실행 중인 노드의 이름
119 | - 파드가 실행 중인 서비스 어카운트 이름
120 | - 각 컨테이너의 cpu와 메모리 요청
121 | - 각 컨테이너의 cpu와 메모리 제한
122 | - 파드의 레이블
123 | - 파드의 어노테이션
124 |
125 | ```agsl
126 | apiVersion: v1
127 | kind: Pod
128 | metadata:
129 | name: appname
130 | labels:
131 | name: appname
132 | spec:
133 | containers:
134 | - name: appname
135 | image: gcr.io/google-containers/busybox
136 | resources:
137 | limits:
138 | memory: "128Mi"
139 | cpu: "500m"
140 | ports:
141 | - containerPort: 8080
142 | env:
143 | - name: POD_NAME
144 | valueFrom:
145 | fieldRef:
146 | fieldPath: metadata.name
147 | - name: POD_NAMESPACE
148 | valueFrom:
149 | fieldRef:
150 | fieldPath: metadata.namespace
151 | - name: POD_IP
152 | valueFrom:
153 | fieldRef:
154 | fieldPath: status.podIP
155 | - name: NODE_NAME
156 | valueFrom:
157 | fieldRef:
158 | fieldPath: spec.nodeName
159 | - name: SERVICE_ACCOUNT
160 | valueFrom:
161 | fieldRef:
162 | fieldPath: spec.serviceAccountName
163 | ```
164 | 파드가 실행되면 파드 스펙에 정의한 모든 환경변수를 조회할 수 있다.
165 |
166 |
167 | ## 쿠버네티스 API 서버와 통신하기
168 | - Download API는 단지 파드 자체의 메타데이터와 모든 파드의 데이터 중 일부만 노출한다. 떄로는 애플리케이션에서 클러스터에 정의된 다른 파드나 리소스에 관한 더 많은 정보가 필요할 수도 있다. 이경우는 download api는 도움되지 않는다.
169 |
170 |
171 | ## 쿠버네티스 API
172 | - kubectl cluster-info를 통해 api서버 주소를 알아낼 수 있다.
173 | ```agsl
174 | kubectl cluster-info
175 | ```
176 | 사실 서버는 HTTPS를 사용중이라 인증이 필요하기 때문에 직접 통신하는 것은 간단하지않다. curl를 통해 접근하고 -k옵션을 사용해서 서버 인증서 확인을 건너뛰도록 할 수 있지만 원하는 결과는 얻을 수 없다.
177 |
178 |
179 | ```agsl
180 | curl https://192.168.99.100:8443 -k
181 | ```
182 |
183 | ## kubectl proxy를 통해서 API 서버 액세스하는 법
184 | kubectl proxy명령어를 통해 로컬 컴퓨터에서 HTTP 연결을 수신하고 이 연결을 인증을 관리하면서 api 서버로 전달하기 때문에 요청할 때마다 인증 토큰을 전달할 필요는 없다.
185 |
186 | ```agsl
187 | kubectl proxy
188 | starting to serve on 127.0.0.1:8001
189 |
190 | curl localhost:8001
191 | {
192 | "paths": [
193 | "/.well-known/openid-configuration",
194 | "/api",
195 | "/api/v1",
196 | "/apis",
197 | "/apis/",
198 | "/apis/admissionregistration.k8s.io",
199 | "/apis/admissionregistration.k8s.io/v1",
200 | "/apis/apiextensions.k8s.io",
201 | "/apis/apiextensions.k8s.io/v1",
202 | "/apis/apiregistration.k8s.io",
203 | "/apis/apiregistration.k8s.io/v1",
204 | "/apis/apps",
205 | ....
206 | ]
207 | }%
208 | ```
209 |
210 | ## 파드 내에서 API 서버와 통신하기
211 | kubectl proxy를 사용해서 로컬 컴퓨터에서 api 서버와 통신하는 방법을 알았는데 그렇다면 kubectl이 없는 pod내에서는 어떤식으로 해야할까? 파드 내에서 api 서버와 통신하는 방법은 3가지를 먼저 처리해야한다
212 | - api 서버 위치알기
213 | - api 서버와 통신하고 있는지 확인
214 | - api 서버로 인증해야한다.
215 |
216 |
217 | curl을 사용할 수 있는 환경이여야 하기 때문에 바이너리가 포함된 컨테이너 이미지를 사용하자. 도커 허브에서 tutum/curl 이미지를 사용하자
218 |
219 | ```agsl
220 | apiVersion: v1
221 | kind: Pod
222 | metadata:
223 | name: appname
224 | labels:
225 | name: appname
226 | spec:
227 | containers:
228 | - name: appname
229 | image: tutum/curl
230 | command: ["sleep", "999999"] # container가 계속 실행되도록 하려고 지연시간이 길게 sleep할 수 있게 만들어야 한다.
231 | ```
232 |
233 | 파드를 만든 후 kubectl exec를 실행하여 컨테이너 내부에서 bash shell을 실행해보자
234 | ```agsl
235 | kubectl exec -it curl bash
236 | ```
237 | api 서버의 ip주소와 포트를 컨테이너 내부의 kubernetes_service_host, kubernetes_service_port변수를 얻을 수 있는지 확인
238 |
239 | ```agsl
240 | env | grep KUBERNETES_SERVICE
241 | ```
242 |
243 | api서버는 https의 기본 포트인 443에서 수신 대기 중이므로 https로 접속할 수 있다. curl https://kubernetes 해당 주소롤 curl 사용한다면 인증하라는 메세지를 확인할 수 있다.
244 | 이 문제를 간단히 해결하는 방법은 -k 옵션을 사용해서 접근하면 해결할 수 있다. 하지만, 실제 애플리케이션에서 사용할 때는 인증을 건너뛰면 안된다.
245 |
246 | API 서버로 인증
247 | ```agsl
248 | TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
249 |
250 | curl -H "Authorization: Bearer $TOKEN" https://kubernetes
251 | ```
252 |
253 | 파드가 실행중인 네임스페이스 얻기
254 |
255 | ```agsl
256 | NS=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
257 |
258 | curl -H "Authorization: Bearer $TOKEN" https://kubernetes/api/v1/namespace/$NS/pods
259 | ```
260 | 같은 방식으로 다른 API 오브젝트를 검색하고 간단한 GET요청 대신 PATCH를 전송해 업데이트할 수 있다.
261 |
262 |
263 |
264 | ## 정리
265 | - Application은 API 서버의 인증서가 인증 기관으로부터 서명됐는지 검증해야 한다. 인증 기관의 인증서는 ca.cart파일에 있다.
266 | - 애플리케이션은 token 파일의 내용을 Authorization HTTP 헤더에 Bearer 토큰으로 넣어 전송해서 자신을 인증해야 한다.
267 |
268 | 
269 |
--------------------------------------------------------------------------------
/etc/configmap.volume.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: appname
5 | labels:
6 | name: appname
7 | spec:
8 | containers:
9 | - name: appname
10 | image: gcr.io/google-containers/busybox
11 | ports:
12 | - containerPort: 8080
13 | volumeMounts:
14 | - name: config
15 | mountPath: /etc/nginx/conf.d
16 | readOnly: true
17 | volumes:
18 | - name: config
19 | configMap:
20 | name: ex-config
--------------------------------------------------------------------------------
/etc/core_dns/README.md:
--------------------------------------------------------------------------------
1 | ## coreDNS란 무엇일까?
2 | - coredns는 쿠버네티스 클러스터 dns서버 역할을 담당한다. k8s 애드온으로 쿠버네티스 실행시 pod로 실행된다.
3 | - 파드, 서비스 도메인을 관리하고 외부 도메인 서버 연결이 필요한 경우 통로역할을 수행
4 | - 파드 내부에 접속해서 etc/resolv.conf파일을 확인하면 nameserver에 kube-dns로 바라보고 있는걸 확인할 수 있다.
5 |
6 | kubedns cluster ip
7 |
8 | 
9 |
10 |
11 | 파드 내부 nameserver
12 |
13 | 
14 |
15 | ## 이게 무슨말일까?
16 | - 파드는 dns 요청할 때 kube-dns service를 먼저 찾는다는 것이다.
17 | - 즉, coredns는 파드 or 서비스를 도메인으로 접근할 수 있다는 것이다.
18 | - 파드나 서비스는 어떠한 변경이 일어나면 cluster ip가 변경되는데 이러한 문제를 coreDNS로 해결가능하다.
19 | - 파드 도메인: pod-ip.namespace.pod.cluster.local
20 | - 서비스 도메인: service-name.namespace.svc.cluster.local
21 |
22 | 
23 | A라는 파드가 B라는 파드를 찾기위해서 이러한 과정이 있을것이다.
24 | - A라는 파드는 먼저 kube-dns service에 요청을 할것이고 kube-dns service는 kube-dns파드에 접근해서 B라는 서비스 dns가 있는지 물어볼 것이고
25 | - 존재한다면 cordns pod는 다시 A라는 파드에게 전달이 될것이고 A라는 파드는 B라는 서비스를 요청해서 B라는 파드에 접근할 수 있는 것이다.
26 |
27 |
--------------------------------------------------------------------------------
/etc/download-api.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: appname
5 | labels:
6 | name: appname
7 | spec:
8 | containers:
9 | - name: appname
10 | image: gcr.io/google-containers/busybox
11 | resources:
12 | limits:
13 | memory: "128Mi"
14 | cpu: "500m"
15 | ports:
16 | - containerPort: 8080
17 | env:
18 | - name: POD_NAME
19 | valueFrom:
20 | fieldRef:
21 | fieldPath: metadata.name
22 | - name: POD_NAMESPACE
23 | valueFrom:
24 | fieldRef:
25 | fieldPath: metadata.namespace
26 | - name: POD_IP
27 | valueFrom:
28 | fieldRef:
29 | fieldPath: status.podIP
30 | - name: NODE_NAME
31 | valueFrom:
32 | fieldRef:
33 | fieldPath: spec.nodeName
34 | - name: SERVICE_ACCOUNT
35 | valueFrom:
36 | fieldRef:
37 | fieldPath: spec.serviceAccountName
38 |
--------------------------------------------------------------------------------
/etc/env.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: appname
5 | labels:
6 | name: appname
7 | spec:
8 | containers:
9 | - name: appname
10 | image: gcr.io/google-containers/busybox
11 | env:
12 | - name: INTERVAL
13 | value: "30"
14 | ports:
15 | - containerPort: 8080
--------------------------------------------------------------------------------
/etc/kubernetes-system-layers/README.md:
--------------------------------------------------------------------------------
1 | # Kubernetes System layers
2 |
3 |
4 | 쿠버네티스를 공부를 하다보면, 쿠버네티스의 원론적인 부분이 궁금해질 때가 생깁니다. 이시스템이 왜 지금 필요한것인가? 또는 어떻게 설계되었는가? 등등..
5 |
6 | 저역시 쿠버네티스를 깊게 알고 있는 상태는 아니기 때문에 문서를 찾아보다가 Kubernetes GitRepo **Kubernetes Design Proposals Archive** 라는 Repo를 발견했는데요. 이 Repo는 쿠버네티스가 어떠한 철학으로 설계했는지 왜 이런구조로 설계할 수 밖에 없는지에 대한 역사적 참고용?레포 인것을 발견했습니다.
7 |
8 |
9 |
10 |
11 |
12 | Kubernetes Design Proposals Archive를 보다가 Kubernetes System layers라는 문서를 봤는데 흥미로워서 번역 + 제가 이해한 바탕으로 작성해봤습니다.
13 |
14 |
15 | ## Kubernetes System Layers
16 |
17 |  # 출처넣기
18 |
19 | 최하위 계증인 Nucleus: API and Execution
20 | 쿠버네티스 시스템을 구성하는 가장 본질적인 API들과 실행 기능들을 의미합니다.
21 |
22 | 여기서 말하는 API와 기능들은 모두 Upstream Kubernetes 코드베이스(공식 커뮤니티 코드) 안에 구현되어 있으며,
23 | **쿠버네티스 전체 구조의 상위 계층(예: 워크로드 관리, 스케줄링, 오토스케일링 등)** 을 쌓아 올리기 위해 반드시 필요한 최소 단위(feature set)입니다.
24 |
25 | 즉, System Layers에서 Nucleus는 쿠버네티스의 심장과도 같은 핵심 계층입니다.
26 |
27 | 여기서 Kubernetes Nucleus는 무엇일까요?
28 | - Kubernetes API Server (Authentication, Authorization, Admission)
29 | - Controller Manager (Garbage Collection, Replication Controllers, etc)
30 | - Scheduler
31 | - Etcd (Persistent Storage for API Objects)
32 | - CRI (Container Runtime Interface: containerd, CRI-O)
33 | - CNI (Container Network Interface)
34 | - CSI (Container Storage Interface)
35 |
36 | Kubernetes 클러스터는 kube-apiserver, kubelet, controller-manager, scheduler, etcd와 같은 핵심 컴포넌트로 구성됩니다. 이 중 하나라도 정상적으로 동작하지 않으면, 클러스터의 기능이 제한되거나 리소스 생명주기 관리가 불가능해집니다.
37 |
38 | 특히, kube-apiserver는 클러스터의 관문 역할을 하며, etcd는 모든 상태 정보를 저장하는 저장소, kubelet은 파드 실행을 담당하는 실행 엔진, controller-manager는 리소스 상태를 지속적으로 유지 관리하는 컨트롤러 집합, scheduler는 파드를 적절한 노드에 배치하는 역할을 수행합니다.
39 |
40 |
41 |
42 |
43 | Application Layer: Deployment and Routing(애플리케이션 계층)
44 |
45 | 이 계층은 애플리케이션 관리 및 구성 레이어로, 자가 복구(self-healing), 스케일링, 애플리케이션 수명주기 관리, 서비스 디스커버리, 로드 밸런싱, 라우팅 등을 제공합니다. 이는 흔히 오케스트레이션이라고 불립니다.
46 |
47 |
48 | 자가복구, 스케일링 애플리케이션 수명주기 관리, 서비스 디스커버리, 로드 밸런싱, 라우팅 없다면 컨테이너기반의 애플리케이션은 실행될 수 없습니다. 컨테이너화된 애플리케이션들은 이 기능들 중 하나 이상을 반드시 사용합니다.
49 |
50 | 기본 스케줄러(Default Scheduler)
51 | - Pod API에 정의된 스케줄링 정책(리소스 요청, nodeSelector, affinity, anti-affinity, taint, tolerations)을 구현합니다.
52 |
53 |
54 |
55 | Continuously running applications(지속적으로 실행되는 애플리케이션)
56 |
57 | 지속적으로 실행되는 애플리케이션 같은 애플리케이션은 모두 다음 기능을 지원해야 합니다.
58 | - 선언적 업데이트(declarative updates)를 통한 롤아웃(배포) 및 롤백
59 | - DaemonSet을 제외하고, 모든 리소스는 수평 확장(horizontal scaling) 을 지원해야 합니다.
60 |
61 |
62 |
63 | Discovery, load balancing, and routing(서비스 디스커버리, 로드 밸런싱 및 라우팅)
64 | - 클러스터 IP 할당
65 | - kubernetes는 Service를 생성할 때 클러스터 내에서만 접근 가능한 고정 IP(ClusterIP) 를 자동으로 할당해준다.
66 | 이 IP는 파드가 재시작되거나 IP가 바뀌어도 변하지 않기 때문에, 내부 통신이 안정적
67 | - 서비스 할당 맵 복구
68 | - 예를 들어 어떤 이유로 service IP 할당이 꼬이거나, Endpoint와 Service 매핑이 깨지면
69 | Kubernetes는 자동으로 이를 탐지하고 복구하는 로직을 내장하고 있습니다.
70 | - kube-proxy 또는 동등한 컴포넌트를 통한 로드밸런싱
71 | - kube-proxy는 클러스터 내부 트래픽을 적절한 파드(Endpoints)로 분산 처리해주는 핵심 컴포넌트입니다.
72 | - iptables, ipvs, userspace
73 | - 서비스에 대한 자동 Endpoints 생성, 유지, 삭제
74 | - Service가 만들어지면, 현재 살아있는 파드 IP 목록(Endpoints) 을 실시간으로 관리한다.
75 | 파드가 죽거나 새로 뜨면 Service에 자동 반영됩니다.
76 | - LoadBalancer 타입 서비스는 선택사항(OPTIONAL) 이지만, 제공하는 경우 호환성 테스트를 통과해야 합니다.
77 |
78 |
79 | 애플리케이션 계층은 다음 구성 요소에 의존할 수 있습니다. 클러스터 내부 인증, ingress Controller(ingress Resource를 선언한다고 해서 끝이아니라, 실제 라우팅을 하는 ingress Controller가 필요), scheduler
80 |
81 | DNS Service
82 | Coredns는 기본적으로 사용하지만, 필요하다면 다른 시스템으로 대체될 수 있습니다 단, Kubernetes가 요구하는 DNS 네이밍 스키마(cluster.local 등) 는 반드시 준수해야 합니다.
83 |
84 |
85 | kube-proxy 대체
86 | kube-proxy 대신 다른 네트워크 트래픽 처리 솔루션이 있습니다.
87 | - cilium
88 | - Calico
89 |
90 | kube-proxy 없이 더 빠르고 강력한 트래픽 라우팅이 가능해질 수도 있습니다.
91 |
92 |
93 | Governance Layer
94 |
95 | Governace Layer의 API 및 기능들은 Container 실행을 위해 필수는 아니지만, 조직적 운영, 보안, 거버넌스를 위해 매우 중요하다고 합니다.
96 |
97 | Governace Layer의 고려해야할 요소는 아래와 같습니다.
98 | - CPU, Memory 자원 사용량
99 | - 노드 간 내부 격리
100 | - 최종 사용(end user) 제약
101 | - 관리자(admin) 접근제어
102 | - Dos(서비스 거부 공격) 방어
103 |
104 | Metrics API
105 | 역할: HPA/VPA와 스케줄러에 메트릭을 제공하는 기반 API
106 |
107 | Kubernetes는 metrics-server 또는 Prometheus 기반 Custom Metrics Adapter를 통해 메트릭을 노출합니다.
108 |
109 | 주로 사용하는 메트릭:
110 |
111 | cpu, memory 사용량
112 |
113 | network, storage, 사용자 정의 메트릭 등
114 |
115 | ```shell
116 | metrics.k8s.io/v1beta1
117 | GET /apis/metrics.k8s.io/v1beta1/pods
118 |
119 | ```
120 |
121 | HorizontalPodAutoscaler (HPA) API
122 | 역할: 파드의 수를 자동으로 조절하여 트래픽이나 리소스 부하에 대응
123 |
124 | CPU 사용률, 메모리 사용률, 사용자 정의 메트릭 기준으로 파드 수를 조정
125 |
126 | 최소/최대 파드 개수와 목표 메트릭 설정 가능
127 |
128 | ````shell
129 | apiVersion: autoscaling/v2
130 | kind: HorizontalPodAutoscaler
131 | spec:
132 | scaleTargetRef:
133 | apiVersion: apps/v1
134 | kind: Deployment
135 | name: my-app
136 | minReplicas: 2
137 | maxReplicas: 10
138 | metrics:
139 | - type: Resource
140 | resource:
141 | name: cpu
142 | target:
143 | type: Utilization
144 | averageUtilization: 70
145 | ````
146 |
147 | Cluster Autoscaler / Node Provisioning
148 | 역할: 파드를 스케줄할 자원이 부족할 경우 노드를 자동으로 확장 또는 축소
149 |
150 | GKE, EKS, KubeSpray, OpenStack 등 다양한 환경에서 지원
151 |
152 | 사용되지 않는 노드는 자동으로 제거 가능 (idle detection)
153 |
154 | ```shell
155 | 🔹 동작 시나리오
156 | Pending 파드가 있을 때 → 새로운 노드 프로비저닝
157 | 일정 시간 리소스를 사용하지 않으면 → 노드 삭제
158 | ```
159 |
160 | PodDisruptionBudget (PDB) API
161 | 역할: 유지보수나 롤링 업데이트 중 파드가 동시에 너무 많이 중단되지 않도록 보장
162 |
163 | 최소 몇 개의 파드를 유지해야 하는지 설정 가능
164 |
165 | 예기치 않은 서비스 중단 방지
166 |
167 | ```shell
168 | apiVersion: policy/v1
169 | kind: PodDisruptionBudget
170 | metadata:
171 | name: web-pdb
172 | spec:
173 | minAvailable: 2
174 | selector:
175 | matchLabels:
176 | app: web
177 | ```
178 |
179 |
180 | 동적 볼륨 프로비저닝 (Dynamic Volume Provisioning)
181 | 역할: PVC가 생성될 때 자동으로 PV를 생성
182 |
183 | 사용자는 PVC만 정의하면 되며, 백엔드에서는 StorageClass에 따라 PV를 생성
184 |
185 | CSI, AWS EBS, GCE PD, NFS 등 다양한 드라이버와 연동 가능
186 |
187 | ```shell
188 | apiVersion: v1
189 | kind: PersistentVolumeClaim
190 | spec:
191 | storageClassName: customStorage
192 | accessModes:
193 | - ReadWriteOnce
194 | resources:
195 | requests:
196 | storage: 10Gi
197 | ```
198 |
199 | StorageClass API
200 | 역할: 어떤 스토리지 타입을 어떤 방식으로 동적으로 생성할지 정의
201 |
202 | 여러 개의 StorageClass를 만들어 다양한 성능/비용 정책 적용 가능
203 |
204 | 기본 StorageClass 하나는 클러스터에 반드시 존재
205 |
206 | ```shell
207 | apiVersion: storage.k8s.io/v1
208 | kind: StorageClass
209 | metadata:
210 | name: fast
211 | provisioner: kubernetes.io/aws-ebs
212 | parameters:
213 | type: gp2
214 |
215 | ```
216 |
217 |
218 | RBAC 권한 정책 (Authorization)
219 |
220 | RBAC (Role-Based Access Control)
221 | **역할(Role)**을 기반으로 사용자 또는 서비스 계정의 접근 권한 제어
222 |
223 | 역할(Role)은 리소스 단위로 "get, list, create, delete, update" 등 세부 권한을 설정 가능
224 |
225 | Role - 네임스페이스 범위의 권한정의
226 |
227 | ClusterRole - 클러스터 전체 범의 권한정의
228 |
229 | RoleBinding - Role을 사용자/그룹/서비스계정에 바인딩 (네임스페이스 범위)
230 |
231 | ClusterRoleBinding - ClusterRole을 클러스터 범위에서 바인딩
232 |
233 | LimitRange API
234 | 역할: 컨테이너/파드의 최소/최대 리소스 요청(requests)과 제한(limits)을 강제
235 |
236 | CPU, Memory 등의 자원 설정이 누락되었을 경우 기본값 적용
237 |
238 | 팀/유저가 과도한 자원 요청을 못 하도록 제한 가능
239 |
240 | ```shell
241 | apiVersion: v1
242 | kind: LimitRange
243 | metadata:
244 | name: resource-limits
245 | namespace: dev
246 | spec:
247 | limits:
248 | - default:
249 | cpu: 500m
250 | memory: 512Mi
251 | defaultRequest:
252 | cpu: 200m
253 | memory: 256Mi
254 | type: Container
255 |
256 | ```
257 |
258 |
259 | ResourceQuota API
260 | 역할: 네임스페이스별 리소스 사용량 제한
261 |
262 | CPU, 메모리, 파드 수, PVC, Service 수 등 제한 가능
263 |
264 | 리소스를 “공정하게” 분배하고 클러스터 자원 남용 방지
265 |
266 | ```shell
267 | apiVersion: v1
268 | kind: ResourceQuota
269 | metadata:
270 | name: dev-quota
271 | namespace: dev
272 | spec:
273 | hard:
274 | requests.cpu: "2"
275 | requests.memory: 4Gi
276 | limits.cpu: "4"
277 | limits.memory: 8Gi
278 | pods: "10"
279 | ```
280 |
281 | PodSecurityPolicy API (PSP)
282 | 역할: 파드의 보안 관련 설정을 정책으로 강제
283 |
284 | 예: root로 실행 금지, hostPath 마운트 금지, 특정 capabilities 제거 등
285 |
286 | Kubernetes 1.25부터 정식 제거됨(deprecated)
287 |
288 | 대안: OPA Gatekeeper, Kyverno 사용 권장
289 |
290 |
291 | ImageReview API
292 | 역할: 파드가 사용할 컨테이너 이미지가 보안 정책에 맞는지 검토
293 |
294 | Admission Webhook으로 동작
295 |
296 | 예: 특정 Registry만 허용, 이미지 서명 확인 등
297 |
298 | 일반적으로 Open Policy Agent (OPA) 또는 Gatekeeper와 함께 사용
299 |
300 |
301 | NetworkPolicy API
302 | 역할: 파드 간 네트워크 통신을 제어 (기본적으로 모두 허용 → 명시적으로 허용할 대상만 지정)
303 |
304 | 동작을 위해 NetworkPolicy를 지원하는 CNI 플러그인 필요
305 |
306 | 예: Calico, Cilium, Antrea, Weave
307 |
308 |
309 | Governance Layer는 클러스터의 안전하고 예측 가능한 운영을 위해, 리소스 제한, 보안 정책, 사용자 권한, 자동화 규칙을 정의하고 강제하는 계층입니다.
310 | 즉, 클러스터 DevOps 엔지니어, 개발자들은 원하는대로 파드를 올리지만, Governance Layer는 1 Core 이상 쓰면안돼, 해당 이미지는 외부에서 가져오는 이미지라서 배포 금지
311 | 와같은 보안 정책 필터 역할을 합니다.
312 |
313 |
314 |
315 | 인터페이스 계층: 라이브러리와 도구 (The Interface Layer: Libraries and Tools)
316 |
317 | 이 계층은 쿠버네티스 배포판에서 권장되는 구성 요소이며, 동시에 사용자가 직접 다운로드하고 설치하여 활용할 수 있는 도구 및 라이브러리를 포함합니다. 여기에는 쿠버네티스 공식 프로젝트에서 개발한 자주 사용하는 라이브러리, 툴, 시스템, 사용자 인터페이스(UI) 등이 포함되며, 유사한 기능을 수행하는 서드파티 도구로 대체 가능하기도 합니다.
318 |
319 | 이 계층의 요소들은 종종 공식 예제나 실습 문서에서 사용되며, 개발자와 운영자 모두가 실무에서 활용하는 쿠버네티스 인터페이스 도구 모음이라 볼 수 있습니다.
320 |
321 |
322 | - Kubectl
323 | - 쿠버네티에서 가장 널리사용되고 있는 CLI도구지만, 핵심은 kubernetes를 사용하는데 있어서 특권의 도구가 아니라 여러 클라이언트 도구중 하나로 바라보고 있습니다.
324 | - 장기적으로 kubectl 복잡한 기능을 사용하지 않고 그런기능들을 쿠버네티스 api로 옮겨 경량화를 하는게 목표라고 합니다.
325 | - Client 라이브러리
326 | - 다양한 언로 작성된 라이브러리
327 | - client-go, client-python
328 | - 이들 라이브러리는 자동화 툴, 연동 시스템, 사용자 정의 컨트롤러 등을 개발할 때 활용됩니다.
329 | - 클러스터 페더레이션 (Federation)
330 | - kubefed 및 관련 API 서버, 컨트롤러 등을 포함
331 | - 여러 쿠버네티스 클러스터를 하나의 논리 단위로 관리하고 싶을 때 사용
332 | - Helm
333 | - 쿠버네티스에서의 패키지 매니저 역할을 수행합니다.
334 | - 복잡한 애플리케이션 배포를 템플릿 기반으로 선언하고, 버전 관리 및 Rollback 등을 제공합니다.
335 |
336 |
337 | 이 계층은 실제 클러스터와 개발자의 접점을 구성하는 **도구 생태계**로 볼 수 있으며, 쿠버네티스를 더 쉽게, 더 강력하게 사용할 수 있게 해주는 사용자 경험 계층입니다.
--------------------------------------------------------------------------------
/etc/kubernetes-system-layers/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youyoungnam/kubernetes-implement/1a113e9ad0bfb3141753dbac7363626bcec99829/etc/kubernetes-system-layers/img.png
--------------------------------------------------------------------------------
/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youyoungnam/kubernetes-implement/1a113e9ad0bfb3141753dbac7363626bcec99829/img.png
--------------------------------------------------------------------------------
/istio/Istio-gateway/README.md:
--------------------------------------------------------------------------------
1 | ## istio-gateway
2 | - 만약에 파드안에 있는 container가 다른 파드에 있는 container를 호출한다면, envoy로 붙어있는 사이드카 프록시를 통해 전달된다. 그리고 우리는 이러한 프록시를 라우팅 규칙으로 관리를 할 수 있다.
3 | - 사용자가 만약에 youngnam.com이라는 사이트를 검색해서 들어온다고 가정해보자. 그런데 youngnam.com은 클러스터 내부에 배포가 되어 있다. 여기서 youngnam.com 개발자들이 특정 기능을 개발을 했고 그것을 이미지를 만들고 레지스트리에 올렸다고 가정해보자.
4 | - 그리고 youngnam app이 NodePort로 외부에서 접근할 수 있다고 하자. 현재 youngnam.com은 클러스터에 배포되어 있고 이스티오를 사용중이라고도 하자.
5 | - youngnam-app ---> original, youngnam-app ---> test 이렇게 카나리아 배포를 해서 기능을 테스트 하려고 하는데 실제로 되지 않는다. 왜일까??
6 | - 이스티오 Service Mesh를 사용중인것이면 모든 네임스페이스에 istio-injection=enabled 되어 있을것이고 모든 파드에 사이드카 형태로 붙어서 통신을 할것이다. 근데 여기서 중요한건 yougnam-app original과 test 두개의 파드도 마찬가지로 이스티오 프록시 형태로 통신하고 있다는 것이다. 여기서 virtual service 와 destination-rule를 적용해도 먹지가 않는다는 것이다.
7 | - 클러스터 맨앞단에 진입할 때 프록시로 전달해 주는 파드가 없어서 그런것이다. 즉, istio-ingress-gateway가 없어서 그런것이다. 해당 파드 서비스는 nodePort로 개방되어 있기때문에 그냥 바로 서비스로 접근하는 것일 뿐인것이다.
8 | - 즉 이스티오 게이트웨이를 맨 앞단에 두고 이 프록시가 virtual service 와 destination rule이 작동할 수 있게 적용을 해줘야 한다는 것
9 | - 쉽게 생각해보면 이스티오 게이트웨이는 일종의 프록시 역할을 하는 것이다.
10 |
11 |
12 |
--------------------------------------------------------------------------------
/istio/Istio-gateway/istio-canary-rules.yaml:
--------------------------------------------------------------------------------
1 | kind: VirtualService
2 | apiVersion: networking.istio.io/v1alpha3
3 | metadata:
4 | name: a-set-of-routing-rules-virtual-service # Virtual Service 이름을 작성한다.
5 | namespace: default
6 | spec:
7 | hosts:
8 | - python-service.default.svc.cluster.local #Service DNS 작성해야 한다.
9 | - "youngnam.com" # gateway DNS를 여기에 copy해서 넣어야한다.
10 | gateways:
11 | - ingress-gateway-configuration
12 | http:
13 | - route:
14 | - destination:
15 | host: python-service.default.svc.cluster.local
16 | subset: safe
17 | weight: 100
18 | - destination:
19 | host: python-service.default.svc.cluster.local
20 | subset: risky
21 | weight: 0
22 | ---
23 | kind: DestinationRule
24 | apiVersion: networking.istio.io/v1alpha3
25 | metadata:
26 | name: python-service-service-destination
27 | namespace: default
28 | spec:
29 | host: python-service # Service
30 | subsets:
31 | - labels: # Selector
32 | version: safe # 파드의 label "safe"
33 | name: safe
34 | - labels:
35 | version: risky # 파드의 label "risky"
36 | name: risky
--------------------------------------------------------------------------------
/istio/Istio-gateway/istio-gateway.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.istio.io/v1alpha3
2 | kind: Gateway
3 | metadata:
4 | name: ingress-gateway-configuration
5 | spec:
6 | selector:
7 | istio: ingressgateway
8 | servers:
9 | - port:
10 | number: 80
11 | name: http
12 | protocol: HTTP
13 | hosts:
14 | - "youngnam.com" # 외부로 노출되는 도메인 네임 DNS
--------------------------------------------------------------------------------
/istio/istio-Circuit-Breaking/README.md:
--------------------------------------------------------------------------------
1 | ## Circuit Breaking
2 | - 쿠버네티스에 파드들이 올라가게 되면 이러한 파드들은 서비스들로 연결되어 있다. 만약에 어떤 이유로 마이크로 서비스에 문제가 생겼다고 한다면 이 문제는 네트워크 문제일 수 도 있고 아니면 컨테이너 내부 문제일 수 도 있고 아니면 잘못된 이미지를 가져와서 파드가 생성이 안될 수 도 있다.
3 | - 예를들어 A라는 마이크로 서비스에서 B라는 마이크로 서비스에 통신이 느려졌다면 어떻게될까? 실패로 이어질 가능성이 높다. 연계고장(Cascading failure)은 예측이 불가하다. 어떠한 문제가 생길지 모른다. 그렇다면 연계고장을 피할 수 있을까? 연계고장에 대한 대비는 서킷 브레이킹이라는 패턴이 존재한다.
4 | - istio-Document에 작성되어 있는 것을 가져와본다면
5 | Circuit breaking is an important pattern for creating resilient microservice applications. Circuit breaking allows you to write applications that limit the impact of failures, latency spikes, and other undesirable effects of network peculiarities.
6 |
7 | 총 쿠버네티스에 파드가 3개가 올라와있다고 가정하자. A라는 파드, B라는 파드, C라는 파드가 존재한다고 했을 때 이러한 파드들은 서비스들이 서로 연결되어 있다. 여기서 기억해야할 것은 B라는 파드가 서비스에 문제있다고 가정하는 것이다. 즉 A라는 파드에서 B라는 파드에 요청을 했을 때 요청시간이 30초 이상이 걸리고 실패한다고 했을 때 서킷 브레이킹 로직은 이러한 것들을 모니터링을 할 수 있다.
8 | 그리고 서킷브레이킹은 이러한 모든 요청 전달을 멈추게 할 수 있다는 것이다. 즉 마이크로 서비스와 연결을 효과적으로 차단할 수 있는 것이고 그 시간동안 서비스를 다시 복구 할 수 있는 시간을 주는 것이다.
9 |
10 |
11 | ## istio-Circuit Breaking
12 | - istio에서 circuit breaking을 설정하는 곳은 Destinationrule에서 적용하면된다.
13 | - 옵션
14 | - maxEjectionPercent 백분율로 표시 만약에 서킷 브레이커가 작동한다면 부하분산을 백분율로 제거한다는 의미
15 | - consecutiveErrors host가 connection pool에서 제외되는 오류수 default 5
16 | - interval 특정 시간동안 연속적으로 오류가 발생한다면 서킷 브레이커가 트리거를 한다는 옵션
17 | - baseEjectionTime circuit break 시간 default 30s
--------------------------------------------------------------------------------
/istio/istio-Circuit-Breaking/istio-circuit-breaking.rules.yaml:
--------------------------------------------------------------------------------
1 | kind: DestinationRule
2 | apiVersion: networking.istio.io/v1alpha3
3 | metadata:
4 | name: python-service-service-destination
5 | namespace: default
6 | spec:
7 | host: python-service.default.svc.cluster.local
8 | trafficPolicy:
9 | outlierDetection:
10 | maxEjectionPercent: 100
11 | consecutiveErrors: 2
12 | interval: 10s
13 | baseEjectionTime: 30s
14 |
--------------------------------------------------------------------------------
/istio/istio-coredns/README.md:
--------------------------------------------------------------------------------
1 | # Istio DNS Proxy Cache를 이용하여 Core DNS 개선하기
2 |
3 |
4 |
5 | ### Kubernetes의 CoreDNS의 역할
6 | - CoreDNS는 경량화된 설계로 클라우드 네이티브 환경에 최적화되어 있습니다.
7 | - 플러그인 기반으로 다양한 기능을 추가할 수 있어 고도로 확장 가능합니다.
8 | - **Pod-to-Pod 통신**: CoreDNS를 통해 IP 주소 대신 **DNS 이름**을 사용하여 다른 서비스와 통신할 수 있습니다.
9 | - **DNS 규칙**: Kubernetes 네임스페이스 및 서비스 이름 규칙에 따라 요청을 처리합니다.
10 | - **가상 네트워크 관리**: Kubernetes 클러스터 내에서 네트워크 요청을 효율적으로 처리합니다.
11 |
12 |
13 | ### 위에서 말하는 DNS 규칙이 무엇일까요?
14 | **서비스 디스커버리**
15 | - 서비스 디스커버리를 짧게 설명해보자면, 쿠버네티스 내에 배포된 서비스들이 존재하고, 해당 서비스들을 통신을 가능하게 하는 중요한 메커니즘 입니다.
16 | - 서비스 디스커버리는 애플리케이션(POD)가 동적으로 생성되고 종료되더라도 안정적이고 일관된 방식으로 통신을 지원합니다.
17 | - 즉, pod는 pod-cidr를 통해 ip를 할당 받고 파드가 죽어서 다른 ip를 할당 받게된다면, 이를 일관된 방식으로 통신을 할 수 있게 해줄 수 있게 해주는 방식입니다.
18 |
19 |
20 | ### Pod가 다른 서비스인 Pod를 찾는 방법
21 |
22 | 
23 |
24 |
25 | 간단하게 그림을 통해 설명해보자면
26 | 1. Worker2번에 올라가 있는 Pod가 Worker1번에 있는 Nginx Pod를 찾을 수 있는 방법은 첫번째로 APP파드가 CoreDNS에게 nginx.default.svc.cluster.local로 질의를 합니다.
27 | 2. CoreDNS는 해당 DNS(FQDN)에 해당하는 service ip를 다시 APP에게 전달합니다.
28 | 3. APP은 service ip를 가지고 nginx와 통신을 하게 됩니다.
29 |
30 | 실제로는 kube-proxy, iptables, CNI 등 더 많은 컴포넌트들이 관여하는 복잡한 과정이 있습니다.
31 |
32 |
33 | ### Istio가 어떻게 CoreDNS 부하를 감소시킬 수 있을까요?
34 |
35 | https://istio.io/latest/blog/2020/dns-proxy/#automatic-vip-allocation-where-possible
36 |
37 | - Istio는 기존에 많이 알려진것처럼, Service Mesh입니다. 그렇다면, Service Mesh는 무엇일까요? Service Mesh는 공식문서를 보면 가시성과 트래픽관리 그리고 보안을 담당하고 있는 인프라스트럭쳐 계층이라고 설명되어 있습니다.
38 | - Istio하면 따라다니는게 있는데 그건 바로 Envoy입니다. istio sidecar인 **Envoy**가 CoreDNS 부하를 감소 시킬 수 있습니다.
39 | - 짧게 설명해보자면, istio sidecar인 Envoy가 이미 Serive Discovery(FQDN)에 대한 servive-ip를 cache처럼 활용하는 것입니다.
40 |
41 |
42 | ### Istio DNS Cache 설정 방법
43 |
44 | 현재 해당기능은 기본적으로 istio를 설치를 진행하면 설정되지는 않습니다. 그래서 istio configmap를 수정 후 istiod pod를 재시작합니다.
45 |
46 | 
47 |
48 |
49 | ### Istio DNS Cache 활성화 확인
50 |
51 | #### ISTIO DNS Cache설정이 적용된 istio sidcar config 상태
52 | Istio DNS Cache가 제대로 활성화되었는지 확인하려면 아래 명령어를 실행합니다
53 | ```shell
54 | #활성화된 경우 출력 예시:
55 | k exec -it -n cmp pod_name -c istio-proxy -- curl localhost:15000/config_dump | grep -i dns
56 |
57 | "ISTIO_META_DNS_CAPTURE": "true",
58 | "DNS_CAPTURE": "true",
59 | "ISTIO_META_DNS_AUTO_ALLOCATE": "true"
60 | "DNS_CAPTURE": "true",
61 | "DNS_AUTO_ALLOCATE": "true",
62 | "name": "envoy.matching.inputs.dns_san",
63 | "envoy.extensions.matching.common_inputs.ssl.v3.DnsSanInput"
64 | "name": "envoy.cluster.logical_dns",
65 | "name": "envoy.cluster.strict_dns",
66 | "name": "envoy.filters.udp.dns_filter",
67 | "envoy.extensions.filters.udp.dns_filter.v3.DnsFilterConfig"
68 | "name": "envoy.network.dns_resolver.cares",
69 | "category": "envoy.network.dns_resolver",
70 | "envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig"
71 | "name": "envoy.matching.inputs.dns_san",
72 | "envoy.extensions.matching.common_inputs.ssl.v3.DnsSanInput"
73 | "name": "outbound|53||coredns.kube-system.svc.cluster.local",
74 | "service_name": "outbound|53||coredns.kube-system.svc.cluster.local"
75 | "name": "coredns",
76 | "host": "coredns.kube-system.svc.cluster.local"
77 | ```
78 | #### ISTIO DNS Cache설정이 적용되지 않은 istio sidcar config 상태
79 |
80 | ```shell
81 | #비활성화된 경우 출력 예시
82 | k exec -it -n cmp pod name -c istio-proxy -- curl localhost:15000/config_dump | grep -i dns
83 |
84 |
85 | "name": "envoy.matching.inputs.dns_san",
86 | "envoy.extensions.matching.common_inputs.ssl.v3.DnsSanInput"
87 | "name": "envoy.filters.udp.dns_filter",
88 | "envoy.extensions.filters.udp.dns_filter.v3.DnsFilterConfig"
89 | "name": "envoy.cluster.logical_dns",
90 | "name": "envoy.cluster.strict_dns",
91 | "name": "envoy.network.dns_resolver.cares",
92 | "category": "envoy.network.dns_resolver",
93 | "envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig"
94 | "name": "envoy.matching.inputs.dns_san",
95 | "envoy.extensions.matching.common_inputs.ssl.v3.DnsSanInput"
96 | ```
97 | ### CoreDNS 로그에서의 차이
98 |
99 | #### Istio Cache 적용 시
100 |
101 | 
102 |
103 | 위 이미지에 보이는것처럼 파드 내부에서 다른 namespace에 있는 nginx pod에 요청을 할 때 coredns 로그에 dns 질의를 하는것을 볼 수 있습니다.
104 |
105 |
106 | #### Istio Cache 미적용 시
107 |
108 | 
109 |
110 | Istio Cache가 istiod에 적용된 뒤 위 방식처럼 다시 파드 내부에서 다른 파드에 요청했을 때 coredns에 들어오지 않는것을 확인할 수 있습니다.
111 |
112 |
113 | ### 결론
114 | Istio의 DNS Proxy Cache는 CoreDNS의 부하를 줄이고, 서비스 디스커버리의 성능을 최적화하는 강력한 도구입니다.
--------------------------------------------------------------------------------
/istio/istio-coredns/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youyoungnam/kubernetes-implement/1a113e9ad0bfb3141753dbac7363626bcec99829/istio/istio-coredns/img.png
--------------------------------------------------------------------------------
/istio/istio-coredns/img_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youyoungnam/kubernetes-implement/1a113e9ad0bfb3141753dbac7363626bcec99829/istio/istio-coredns/img_1.png
--------------------------------------------------------------------------------
/istio/istio-coredns/img_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youyoungnam/kubernetes-implement/1a113e9ad0bfb3141753dbac7363626bcec99829/istio/istio-coredns/img_2.png
--------------------------------------------------------------------------------
/istio/istio-coredns/img_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youyoungnam/kubernetes-implement/1a113e9ad0bfb3141753dbac7363626bcec99829/istio/istio-coredns/img_3.png
--------------------------------------------------------------------------------
/istio/istio-coredns/img_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youyoungnam/kubernetes-implement/1a113e9ad0bfb3141753dbac7363626bcec99829/istio/istio-coredns/img_4.png
--------------------------------------------------------------------------------
/istio/istio-envoy/README.md:
--------------------------------------------------------------------------------
1 | # Istio Envoy에 대해 궁금하다.
2 |
3 |
4 | **Enovy**란 무엇일까요? 재미있는 비유를 해보자면, istio는(조폭 두목)이고 Enovy는(행동대장)관계입니다.
5 | 조폭두목은 직접적으로, 싸우지는 않지만, 전체적으로 전략을 짜고 명령을 내리죠. 그러면 행동대장인 Envoy는 두목의 명령을 받아서 실제로 움직이는 실무자라고 생각하시면 됩니다.
6 |
7 | - **시나리오**
8 | - "A구역을 우리가 앞으로 관리할거야 거기로 지나다니는(트래픽) 사람들 관리해" -> 두목(istio)
9 | - "요새 이상한 사람들이 우리 구역에 들어오는거 같아 외부에서 함부로 못들어오게 막아" -> 두목(istio)
10 | - "알겠습니다. 두목 A구역으로 들어오는 사람들을 관리하겠습니다." -> 행동대장(Envoy)
11 | - "외부에서 이상한사람이 접근(비정상 트래픽)이 오면 출입증 부탁드립니다. 검사" -> 행동대장(Envoy)
12 |
13 |
14 |
15 | **Envoy**의 구조를 한번 봅시다.
16 |
17 |
18 |
19 |
20 | 이미지에 보이는 것처럼 **Envoy Proxy**는 Proxy역할을 하게됩니다. 즉, 외부(클라이언트)로부터 Envoy로 들어오는 요청을 **DownStream** 요청을 받아서 Service(Container)로 전달하는것을 **UpStream**으로 생각하시면 됩니다.
21 |
22 |
23 | **Listener**
24 | - Listener는 Envoy가 클라이언트 요청(Downstream)을 받아들이는 진입점입니다. 여러 개의 Listener를 설정할 수 있으며, 각각 특정 포트에서 트래픽을 수신합니다. 필터 체인을 통해 트래픽을 검사하고, 적절한 Upstream(Cluster)으로 전달합니다.
25 |
26 |
27 | **Network Filter Chain**
28 | - Listener로 들어온 요청에 대해 처리하는것이라고 생각하면 됩니다.(예를들어: 인증, 로깅, 트래픽변환, 요청차단 등등..)
29 | - 비유를 해보자면, TCP Proxy 필터: envoy.filters.network.tcp_proxy → TCP 트래픽을 특정 Cluster로 전달
30 | HTTP Connection Manager: envoy.filters.network.http_connection_manager → HTTP 요청을 처리하고, 라우팅(RDS) 적용
31 |
32 |
33 | **Cluster**
34 | Cluster는 Envoy에서 특정 백엔드 서비스 그룹을 의미하는 논리적인 개념입니다.
35 | 즉, Envoy가 트래픽을 전달할 대상(서버 그룹) 을 정의하는 부분입니다.
36 |
37 | Istio의 Envoy Proxy가 트래픽을 보낼 곳(서비스) 여러 개의 엔드포인트(Endpoints) 로 구성 로드 밸런싱, 서비스 디스커버리, 헬스 체크 등을 수행
38 |
39 | 예를 들어, 특정 서비스(reviews.default.svc.cluster.local)로 트래픽을 보내야 한다면, Envoy는 이 서비스에 대한 Cluster를 설정하고, 해당 클러스터에 포함된 엔드포인트를 통해 요청을 전달합니다.
40 |
41 |
42 | **BlackHoleCluster**는 요청이 어디에도 매칭되지 않았을 때 Envoy가 사용하며, 기본적으로 503(Service Unavailable) 응답을 반환합니다. 이는 정의된 라우팅 경로가 없는 요청을 차단하는 데 사용됩니다.
43 |
44 |
45 |
46 | 글로만보면 이해가 되지만, 실제로 Sidecar로 달려있는 Enovy 설정을 본다면 이해가 더 잘됩니다. 모든 설정은 다보기엔 너무 많으니 일부 설정을 같이함께 봅시다.
47 |
48 | ```shell
49 | - address:
50 | socketAddress:
51 | address: 0.0.0.0
52 | portValue: 15006
53 | continueOnListenerFiltersTimeout: true
54 | filterChains:
55 | - filterChainMatch:
56 | destinationPort: 15006
57 | filters:
58 | - name: istio.metadata_exchange
59 | typedConfig:
60 | '@type': type.googleapis.com/udpa.type.v1.TypedStruct
61 | typeUrl: type.googleapis.com/envoy.tcp.metadataexchange.config.MetadataExchange
62 | value:
63 | enable_discovery: true
64 | protocol: istio-peer-exchange
65 | - name: istio.stats
66 | typedConfig:
67 | '@type': type.googleapis.com/stats.PluginConfig
68 | disableHostHeaderFallback: true
69 | - name: envoy.filters.network.tcp_proxy
70 | typedConfig:
71 | '@type': type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
72 | cluster: BlackHoleCluster
73 | statPrefix: BlackHoleCluster
74 | name: virtualInbound-blackhole
75 | - filterChainMatch:
76 | applicationProtocols:
77 | - istio-http/1.0
78 | - istio-http/1.1
79 | - istio-h2
80 | transportProtocol: tls
81 | ```
82 |
83 | 위 설정은 배포된 파드의 사이드카 listeners중 일부를 가져왔습니다.
84 |
85 | **15006** port는 이스티오의 인바운드 트래픽을 처리하는 것입니다. 15006으로 들어오게되면 iptables rule에 의해 app으로 Redirect가 되고 해당 패킷은 app으로 전달됩니다.
86 |
87 | **continueOnListenerFiltersTimeout: true** Listener 필터가 타임아웃되 요청을 계속 하는지에 대한 옵션입니다.
88 |
89 | **- filterChainMatch:
90 | destinationPort: 15006** 목적지 포트가 15006인 경우에만 이 체인을 적용하는것입니다.
91 | 즉, Inbound 트래픽이 15006으로 접근을하게되면 이 필터 체인이 적용됩니다.
92 |
93 | ```shell
94 | filters:
95 | - name: istio.metadata_exchange
96 | typedConfig:
97 | '@type': type.googleapis.com/udpa.type.v1.TypedStruct
98 | typeUrl: type.googleapis.com/envoy.tcp.metadataexchange.config.MetadataExchange
99 | value:
100 | enable_discovery: true
101 | protocol: istio-peer-exchange
102 |
103 | ```
104 | **metadata_exchange** Istio에서 서비스 간 메타데이터(metadata) 교환을 활성화하는 역할을 합니다.
105 | 이는 Envoy 간 통신에서 메타데이터를 교환하여 트래픽 라우팅 및 정책 적용을 가능하게 합니다. 주로 Telemetry, Authorization, Service Discovery 등에 활용됩니다.
106 |
107 |
108 | Istio mTLS (Mutual TLS) 활성화 시 함께 사용되어 트래픽 측정 및 정책 적용에 활용됩니다.
109 |
110 | Envoy 프록시가 통신할 때 서로 메타데이터를 교환하며, 이를 기반으로 트래픽을 분석하거나 정책을 적용할 수 있습니다.
111 | 보통 Inbound 및 Outbound 필터 체인에 추가되어 사용됩니다.
112 |
113 | ```shell
114 | - name: istio.stats
115 | typedConfig:
116 | '@type': type.googleapis.com/stats.PluginConfig
117 | disableHostHeaderFallback: true
118 |
119 | ```
120 |
121 | Istio의 통계(Stats) 필터를 사용하도록 지정합니다.
122 | Envoy는 Istio를 통해 요청 및 응답 정보를 수집하고, 이를 Prometheus 등의 모니터링 시스템에 전달할 수 있습니다.
123 |
124 |
125 |
126 | ## xDS
127 |
128 | **xDS(eXtensible Discovery Service)**: xDS는 Envoy Proxy가 동적으로 구성을 업데이트할 수 있도록 하는 API 프로토콜입니다. Istio에서도 Envoy를 데이터 플레인으로 사용하며, xDS를 통해 제어 플레인에서 Envoy 설정을 동적으로 관리합니다.
129 |
130 |
131 | #### Envoy와 Istiod는 어떻게 통신을 하며 동적으로 업데이트를할까요?
132 |
133 | Enovy Proxy가 동적으로 업데이트를 할 수 있는 이유는 istiod와 지속적으로 연결을 유지하면서 변경 사항을 동적으로 반영합니다.이를 위해 Evoy는 GRPC 스트리밍 방식 또는 주기적으로 풀링방식으로 xDS 서버(istiod)와 통신을 합니다.
134 |
135 |
136 | ### LDS(Listener Discovery Service)
137 | Envoy가 수신할 네트워크 리스너(Listener) 구성을 제공하는 API이면서, Istio Ingress Gateway나 Sidecar Proxy가 수신하는 포트와 필터 체인을 설정합니다.
138 |
139 | Envoy가 수신할 네트워크 리스너 구성을 제공합니다. 클라이언트(DownStream)을 통해 들어온 트래픽을 어디로 보내야하는지에 대한 결정을 할 수 있을 뿐만 아니라, 필요한 필터체인을 적용하여 요청에 대해 처리할 수 있습니다. 또한 Listerner은 outbound에 대한 요청도 관리합니다.
140 |
141 | 아래는 envoy가 적용된 파드에 대한 listerner 상태입니다.
142 |
143 | ```shell
144 | istioctl pc listener nginx-deployment-f7786fdc7-75lmc.istio-dns-b
145 | ADDRESSES PORT MATCH DESTINATION
146 | 10.233.0.3 53 ALL Cluster: outbound|53||coredns.kube-system.svc.cluster.local
147 | 0.0.0.0 80 Trans: raw_buffer; App: http/1.1,h2c Route: 80
148 | 0.0.0.0 80 ALL PassthroughCluster
149 | .
150 | .
151 | .
152 | .
153 | .
154 | 0.0.0.0 15001 Addr: *:15001 Non-HTTP/Non-TCP
155 | 0.0.0.0 15006 Addr: *:15006 Non-HTTP/Non-TCP
156 | 0.0.0.0 15006 Trans: tls; App: istio-http/1.0,istio-http/1.1,istio-h2 InboundPassthroughCluster
157 | 0.0.0.0 15006 Trans: raw_buffer; App: http/1.1,h2c InboundPassthroughCluster
158 | 0.0.0.0 15006 Trans: tls; App: TCP TLS InboundPassthroughCluster
159 | 0.0.0.0 15006 Trans: raw_buffer InboundPassthroughCluster
160 | 0.0.0.0 15006 Trans: tls InboundPassthroughCluster
161 | 0.0.0.0 15006 Trans: tls; App: istio-http/1.0,istio-http/1.1,istio-h2; Addr: *:80 Cluster: inbound|80||
162 | 0.0.0.0 15006 Trans: raw_buffer; App: http/1.1,h2c; Addr: *:80 Cluster: inbound|80||
163 | 0.0.0.0 15006 Trans: tls; App: TCP TLS; Addr: *:80 Cluster: inbound|80||
164 | 0.0.0.0 15006 Trans: raw_buffer; Addr: *:80 Cluster: inbound|80||
165 | 0.0.0.0 15006 Trans: tls; Addr: *:80 Cluster: inbound|80||
166 | ```
167 | 이스티오 envoy에서는 15001 port와 15006 port는 위에서 언급했듯이, 중요한 기능을 담당하는 포트입니다. 두개의 포트는 리다이렉션을 하기 위한 용도고 15001은 아웃바운드에 대한 포트, 15006은 인바운드에 대한 트래픽을 처리하는 용도입니다.
168 |
169 |
170 | ### RDS(Router Discovery Service)
171 |
172 | RDS(Route Discovery Service)는 Listener에서 받은 요청을 특정 Cluster로 전달하는 라우팅 규칙을 관리합니다. Istio에서 VirtualService를 사용하여 라우팅 규칙을 정의하면, 해당 정보가 RDS를 통해 Envoy에 전달됩니다.
173 |
174 |
175 | ```shell
176 | includeRequestAttemptCount: true
177 | name: istio-gateway.istio-system.svc.cluster.local:80
178 | routes:
179 | - decorator:
180 | operation: istio-gateway.istio-system.svc.cluster.local:80/*
181 | match:
182 | prefix: /
183 | name: default
184 | route:
185 | cluster: outbound|80||istio-gateway.istio-system.svc.cluster.local
186 | maxGrpcTimeout: 0s
187 | retryPolicy:
188 | hostSelectionRetryMaxAttempts: "5"
189 | numRetries: 2
190 | retriableStatusCodes:
191 | - 503
192 | retryHostPredicate:
193 | - name: envoy.retry_host_predicates.previous_hosts
194 | typedConfig:
195 | '@type': type.googleapis.com/envoy.extensions.retry.host.previous_hosts.v3.PreviousHostsPredicate
196 | retryOn: connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes
197 | timeout: 0s
198 | - domains:
199 | - nginx-service.istio-dns-b.svc.cluster.local
200 | - nginx-service
201 | - nginx-service.istio-dns-b.svc
202 | - nginx-service.istio-dns-b
203 | - 10.233.8.23
204 | includeRequestAttemptCount: true
205 | ```
206 |
207 |
208 | ### CDS(Cluster Discovery Service)
209 |
210 | CDS는 Envoy가 트래픽을 라우팅할 대상(클러스터) 을 동적으로 업데이트하는 기능을 합니다.
211 | 즉, Istio의 Pilot(컨트롤 플레인) 이 Envoy 프록시(데이터 플레인) 에게 어떤 클러스터들이 존재하는지 알려주는 서비스입니다.
212 |
213 | istio에서 Cluster의 의미는 Envoy에서 클러스터는 트래픽을 보낼 수 있는 하나 이상의 엔드포인트 그룹을 의미합니다. 여기서 Cluster개념이 잘 이해가 안될 수 가 있는데 CDS는 Kubernetes의 Service에 해당하는 클러스터 목록을 동적으로 관리하지만, 같은 Service라도 여러 개의 클러스터로 나뉠 수 있습니다.
214 |
215 |
216 | ### **같은 서비스라도 여러개의 Envoy Cluster가 생기는 이유**
217 |
218 | ```shell
219 | # 여러개의 포트를 가지는 경우
220 | apiVersion: v1
221 | kind: Service
222 | metadata:
223 | name: my-service
224 | namespace: default
225 | spec:
226 | ports:
227 | - name: http
228 | port: 80
229 | - name: grpc
230 | port: 50051
231 | ```
232 |
233 | 80, 50051 port에 대한 두 개의 클러스터가 생깁니다.
234 |
235 | ```shell
236 | # Istio의 VirtualService를 사용하면, 같은 Kubernetes Service라도 특정 요청을 다른 서비스로 라우팅
237 | apiVersion: networking.istio.io/v1beta1
238 | kind: VirtualService
239 | metadata:
240 | name: my-service
241 | namespace: default
242 | spec:
243 | hosts:
244 | - my-service.default.svc.cluster.local
245 | http:
246 | - match:
247 | - headers:
248 | user-agent:
249 | regex: ".*Mobile.*"
250 | route:
251 | - destination:
252 | host: my-service
253 | subset: mobile-version
254 | - route:
255 | - destination:
256 | host: my-service
257 | subset: default
258 |
259 | ```
260 | Envoy는 라우팅 규칙에 따라 별도의 Cluster를 생성할 수 있습니다. 이밖에도 Destionation rule를 사용하면서 subset를 사용하는경우 등등 있습니다.
261 |
262 |
263 | xDS는 위에서 언급한 LDS, RDS, CDS 이외에도 몇가지가 더 있는데 이부분은 추가적으로 업데이트 하도록 하겠습니다.
264 |
265 | ## 결론
266 |
267 | istio를 사용하지만, Envoy에 대해 많은 부분을 알지 못했는데 위 내용을 정리하면서 Envoy에 역할을 어느정도 감을 잡을 수 있는거 같아서 잘한것 같습니다.
268 |
--------------------------------------------------------------------------------
/istio/istio-envoy/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youyoungnam/kubernetes-implement/1a113e9ad0bfb3141753dbac7363626bcec99829/istio/istio-envoy/img.png
--------------------------------------------------------------------------------
/istio/istio-mtls/README.md:
--------------------------------------------------------------------------------
1 | # 클러스터 내부 암호화가 중요한 이유
2 | - 사실 우리 쿠버네티스 클러스터를 보면 노드들의 집합으로 이루워져 있다. 쿠버네티스 리소스들이 노드에 배포되어 있는것이다. 우리가 클라우드 서비스를 사용해서 쿠버네티스 클러스터를 구성하게 되면 region을 선택할 수 있는데 이 region이 같은 위치에 있으면 괜찮은데 만약 다른 데이터센터에 노드가 배치된다면 과연 안전할까?
3 | 
4 | - 만약에 다른 노드 즉 다른 데이터센터에 있는 노드에서 다른 데이터센터에 위치한 파드에 호출한다면 http통신을 통해서 서로 통신하게 될것인데 그렇다면 이건 외부로 http를 통신하게 되는 것이고 만약 해커가 중간에 데이터를 쉽게 가져갈 수 있을 것이다.
5 |
6 | - 정리하자면, 우리 클러스터는 다중 노드로 이어져 있고 그 노드마다 파드들이 배포되어 있다. 특정 노드에 배포된 파드내에 컨테이너가 다른 노드에 있는 파드에 있는 컨테이너에게 요청을 하게 되면 이 호출은 http로 통신을 하게되고 결국 이것을 통제할 필요가 있다.
7 |
8 | ## istio-citadel
9 | - citadel은 이스티오가 통신할 때 TLS(SSL)암호화를 진행하여 통신을 할 수 있다. citadel은 암호화 또는 사용자인증에 필요한 인증서 관리를 해준다.
10 |
11 |
12 | ## auto mtls 활성화
13 | - pod <----> pod 트래픽으로 tls를 활성화 하는 것이 중요하다. 우리는 istio를 사용하고 있기 때문이 이부분은 걱정안해도 된다. 왜냐하면 istio는 기본적으로 mtls가 활성화 되어 있기 때문이다.
14 |
15 | ## Permissive mTLS
16 | - 한쪽 Pod는 sideCar가 주입되어 있지 않는 Pod 다른 한쪽은 sideCar가 주입되어 있는 Pod가 있다고 가정하자. 만약에 envoy Proxy가 없는 파드에서 있는 파드를 호출하게 된다면 tls가 설정되지 않는 상태로 통신하게 될것이다. tls가 없다는것은 보안이되지 않는 상태로 통신을 하게되는 것이다.
17 | 
18 |
19 |
20 |
21 | ## Strict mTLS
22 | - 한쪽 Pod는 sideCar가 주입되어 있지 않는 Pod 다른 한쪽은 sideCar가 주입되어 있는 Pod가 있다고 가정하자. 만약 주입되어 있는 파드에서 envoy sidecar가 주입되어 있지 않는 파드를 호출하게 된다면 호출되지 않는다. 즉 연결거부상태로 된다.
23 | 
24 |
--------------------------------------------------------------------------------
/istio/istio-mtls/permissive.mtls.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: "security.istio.io/v1beta1"
2 | kind: "PeerAuthentication"
3 | metadata:
4 | name: "default"
5 | namespace: "istio-system"
6 | spec:
7 | mtls:
8 | mode: PERMISSIVE
9 |
--------------------------------------------------------------------------------
/istio/istio-mtls/strict.mtls.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: "security.istio.io/v1beta1"
2 | kind: "PeerAuthentication"
3 | metadata:
4 | name: "default"
5 | namespace: "istio-system"
6 | spec:
7 | mtls:
8 | mode: STRICT
9 |
--------------------------------------------------------------------------------
/istio/istio-prefix/istio-prefix-canary.yaml:
--------------------------------------------------------------------------------
1 | kind: VirtualService
2 | apiVersion: networking.istio.io/v1alpha3
3 | metadata:
4 | name: a-set-of-routing-rules-virtual-service # Virtual Service 이름을 작성한다.
5 | namespace: default
6 | spec:
7 | hosts:
8 | - python-service.default.svc.cluster.local #Service DNS 작성해야 한다.
9 | - "youngnam.com" # gateway DNS를 여기에 copy해서 넣어야한다.
10 | gateways:
11 | - ingress-gateway-configuration
12 | http:
13 | - match:
14 | - uri: # 만약에 prefix가 name이면 risky버전으로
15 | prefix: "/name"
16 | - route: # 그리고 조건이 충족 된다면
17 | - destination:
18 | host: python-service.default.svc.cluster.local
19 | subset: risky
20 | - match:
21 | - uri: # 만약에 prefix가 "/"이면 safe버전으로
22 | prefix: "/"
23 | - route: # 그리고 조건이 충족 된다면
24 | - destination:
25 | host: python-service.default.svc.cluster.local
26 | subset: safe
27 | ---
28 | kind: DestinationRule
29 | apiVersion: networking.istio.io/v1alpha3
30 | metadata:
31 | name: python-service-service-destination
32 | namespace: default
33 | spec:
34 | host: python-service # Service
35 | subsets:
36 | - labels: # Selector
37 | version: safe # 파드의 label "safe"
38 | name: safe
39 | - labels:
40 | version: risky # 파드의 label "risky"
41 | name: risky
--------------------------------------------------------------------------------
/istio/istio-subdomain-routing/istio-subdomain-routing.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.istio.io/v1alpha3
2 | kind: Gateway
3 | metadata:
4 | name: ingress-gateway-configuration
5 | spec:
6 | selector:
7 | istio: ingressgateway
8 | servers:
9 | - port:
10 | number: 80
11 | name: http
12 | protocol: HTTP
13 | hosts:
14 | - "*.youngnam.com"
15 | - "youngnam.com" # 외부로 노출되는 도메인 네임 DNS
16 | ---
17 | kind: VirtualService
18 | apiVersion: networking.istio.io/v1alpha3
19 | metadata:
20 | name: a-set-of-routing-rules-virtual-service # Virtual Service 이름을 작성한다.
21 | namespace: default
22 | spec:
23 | hosts:
24 | - "youngnam.com" # gateway DNS를 여기에 copy해서 넣어야한다.
25 | gateways:
26 | - ingress-gateway-configuration
27 | http:
28 | - route:
29 | - destination:
30 | host: python-service.default.svc.cluster.local
31 | subset: safe
32 | ---
33 | kind: VirtualService
34 | apiVersion: networking.istio.io/v1alpha3
35 | metadata:
36 | name: a-set-of-routing-rules-virtual-service # Virtual Service 이름을 작성한다.
37 | namespace: default
38 | spec:
39 | hosts:
40 | - "*.youngnam.com" # gateway DNS를 여기에 copy해서 넣어야한다.
41 | gateways:
42 | - ingress-gateway-configuration
43 | http:
44 | - route:
45 | - destination:
46 | host: python-service.default.svc.cluster.local
47 | subset: risky
48 | ---
49 | kind: DestinationRule
50 | apiVersion: networking.istio.io/v1alpha3
51 | metadata:
52 | name: python-service-service-destination
53 | namespace: default
54 | spec:
55 | host: python-service # Service
56 | subsets:
57 | - labels: # Selector
58 | version: safe # 파드의 label "safe"
59 | name: safe
60 | - labels:
61 | version: risky # 파드의 label "risky"
62 | name: risky
--------------------------------------------------------------------------------
/istio/istio-virtualService/README.md:
--------------------------------------------------------------------------------
1 | ## istio Virtual Service
2 | - 처음에 이스티오를 사용한다 했을 때 Virtual Service 단어는 너무나 어려워 보였다. 솔직히 어떤식으로 동작하는지도 전혀 몰랐고.. 쿠버네티스도 어려운데 Service Mesh 사용한다고 하니까 어려웠다.
3 |
4 | - 단어에 겁을 먹지말고, 내가 생각한 Virtual Service는 직관적으로 라우팅 규칙을 구성을 할 수 있는 것이라고 생각하면된다.
5 |
6 |
7 | - 이스티오를 사용한다면 Istio-pilot을 알고 있을 것이다 Istio-pilot은 Virtual Service 정의한 yaml를 가지고 있다고 생각하면 된다. 즉 파일럿은 즉시 실시간으로 Envoy Proxy를 구성하는 역할을 한다. 우리가 VS(Virtual Service)에 큰 변동사항이 있다고 가정하면 이러한 정보들이 파일럿으로 가고 파일럿이 사용자 지정 라우팅 규칙의 결과로서 변경되어야 할 모든 프록시에 전달한다.
8 |
9 | - 사실 모든 Canary를 배포하는건 envoy이다. 이스티오는 구성이 필요한 모든 프록시를 구성할 능력을 우리에게 주는 것이다. 우리는 사실 프록시에 대해 생각할 필요가 없다. 우리는 단지 높은 수준의 Virtual Service 개념에서 작업할 수 있다. 하지만 실제로 우리가 하는 일은 프록시를 구성하는 것이다.
10 |
11 |
12 | ### VirtualService
13 | ```
14 | kind: VirtualService
15 | apiVersion: networking.istio.io/v1alpha3
16 | metadata:
17 | name: a-set-of-routing-rules-virtual-service # Virtual Service 이름을 작성한다.
18 | namespace: default
19 | spec:
20 | hosts:
21 | - python-service.default.svc.cluster.local #Service DNS 작성해야 한다.
22 | http:
23 | - route:
24 | - destination:
25 | host: python-service.default.svc.cluster.local
26 | subset: safe
27 | weight: 100
28 | - destination:
29 | host: python-service.default.svc.cluster.local
30 | subset: risky
31 | weight: 0
32 | ```
33 |
34 |
35 |
36 | ### istio https Virtual Service retries options 문제 직면 해결볍
37 | - 일단 retries options을 사용하게 된 이유는 무엇일까?? 회사 서비스에 대해 자세하게 말할 수 없지만, 우리는 개발환경과 운영환경을 두개의 클러스터를 운영하고 있다. 개발 클러스터에서 배포된 프론트엔드가 다른 프론트엔드 모듈을 호출할 때 503 error를 계속 확인되는 것을 보았다. 이유는 아마도 여러가지 일 수 도 있다. 예를들자면, 권한이라던지, 특정 배포 순간에 서비스를 클릭을 했다던지 여러가지 이유가 있었다.
38 | 일단 503 error가 나타나는게 보기 싫었다. Virtual Service에 특정 prefix에 접근 했을 때 에러가 나오면 재시도하는 옵션이 있다. 그게 retries 옵션이다.
39 |
40 | ```
41 | kind: VirtualService
42 | apiVersion: networking.istio.io/v1alpha3
43 | metadata:
44 | name: a-set-of-routing-rules-virtual-service # Virtual Service 이름을 작성한다.
45 | namespace: default
46 | spec:
47 | hosts:
48 | - python-service.default.svc.cluster.local #Service DNS 작성해야 한다.
49 | http:
50 | - match:
51 | - uri: # 만약에 prefix가 name이면 python-service로
52 | prefix: "/name"
53 | timeout: 30s
54 | retries:
55 | attempts: 3
56 | perTryTimeout: 100ms
57 | retryOn: gateway-error,connect-failure,refused-stream
58 | - route: # 그리고 조건이 충족 된다면
59 | - destination:
60 | host: python-service.default.svc.cluster.local
61 | ```
62 |
63 | Retries 옵션에 대한 설명
64 | timeout: 30s: 요청에 대한 최대 대기 시간을 30초로 설정 이는 요청이 완료되기까지 허용되는 최대 시간이다. 만약 요청이 30초 이상 걸릴 경우, 타임아웃으로 간주되고 해당 요청은 실패로 처리된다.
65 |
66 | retries: attempts: 3: 요청이 실패할 경우 최대 3번의 재시도를 수행. 따라서, 최초의 요청을 포함하여 총 4번의 시도가 가능.
67 |
68 | retries: perTryTimeout: 100ms: 각 재시도의 최대 시간을 100밀리초(0.1초)로 설정. 이는 각 재시도가 최대 0.1초까지 소요될 수 있음을 의미. 따라서, 재시도 시간이 0.1초를 초과하면 해당 재시도는 실패로 처리.
69 |
70 | retries: retryOn: gateway-error,connect-failure,refused-stream: 리트라이가 수행될 상태 코드를 지정. 이 경우, 게이트웨이 에러(gateway-error), 연결 실패(connect-failure), 거부된 스트림(refused-stream) 상태 코드가 발생할 때 재시도가 수행될 수 있음 즉, 이러한 상태 코드가 발생하면 Istio는 재시도를 시도할 수 있음.
71 |
72 | 이러한 설정은 주어진 조건에 따라 최대 3번의 재시도를 수행하고, 각 재시도는 최대 0.1초까지 소요될 수 있다. 또한, 특정 상태 코드에 대한 재시도 조건을 지정하여 해당 상태 코드가 발생할 경우 재시도를 수행할 수 있도록 구성되었다.
73 |
74 |
75 | ### 문제
76 | - 그렇다면 어떤문제가 있었을까? 우리는 개발환경 클러스터에서 운영환경 클러스터를 옮기는 작업을 진행중이였다. 모든 사람들이 알고 있겠지만, 운영환경은 https를 적용해야한다. 그래서 개발환경에서 사용되는 인증권한 서비스 등등 관련된 서비스에 https를 다 적용해야했다. 그렇다보니 알 수 없는 에러들이 나왔다. 이스티오에 ssl를 적용하는 것도 처음이라 쉽지 않았다. 솔직히 제대로 된지도 몰랐는데 잘 찾아보고 문서를 읽다보니 적용을 했다. 그 다음이 문제다.
77 | - 인증/권한 관리 및 oauth service사이 문제 등등 생기기 시작했다. 인증/권한 관리 서비스에서 ssl 적용하고 VS를 retries옵션을 개발환경에서 적용했던 것을 그대로 적용하다보니 문제가 생겼던것 이였다. 계정을 처음 생성했는데 이미 존재하는 계정이라고 에러가 발생 한거였다. 알고보니 인증/권한 관리에 ssl를 적용하다보니 retries옵션이 작용했던 것이다.
78 | - retries 옵션 설명을 가져와 보면 retries: Retry policy for HTTP requests. http 요청일 때 작용하는 것이다. 즉 우리는 ssl를 적용시키고 retries를 넣어버리니 한번에 5번씩이나 요청이 들어갔던것이다. 이것을 oauth에도 적용하니 이미 발급된 토큰인데도 불구하고 5번씩 계속 요청하니 500 server error를 만난것이다.
79 | - 이 문제를 3일동안 잡고있다가 결국 해결했다.
--------------------------------------------------------------------------------
/istio/istio-virtualService/istio.virtual-service.yaml:
--------------------------------------------------------------------------------
1 | kind: VirtualService
2 | apiVersion: networking.istio.io/v1alpha3
3 | metadata:
4 | name: a-set-of-routing-rules-virtual-service # Virtual Service 이름을 작성한다.
5 | namespace: default
6 | spec:
7 | hosts:
8 | - python-service.default.svc.cluster.local #Service DNS 작성해야 한다.
9 | http:
10 | - match:
11 | - uri: # 만약에 prefix가 name이면 python-service로
12 | prefix: "/name"
13 | - route: # 그리고 조건이 충족 된다면
14 | - destination:
15 | host: python-service.default.svc.cluster.local
--------------------------------------------------------------------------------
/k8s-preparation/README.md:
--------------------------------------------------------------------------------
1 | # 쿠버네티스와 같은 시스템이 필요한 이유
2 | - 예전에는 애플리케이션이 거대한 모놀리스 방식으로 개발되었다. 즉, 이러한 거대한 모놀리스 애플리케이션이 작은 마이크로 서비스로 세분화함과 동시에 해당 애플리케이션을 실행하는 인프라의 변경으로 인한 것이다.
3 |
4 | ## 거대한 애플리케이션에서 마이크로서비스로 전환
5 | - 모놀리스 애플리케이션은 모든것이 강결합 되어있다. 모든것이 강결합 되어있다는건 어떤 의미일까? 예를들어 어떤 인증 컴포넌트가 있다고 가정해보자 이러한 인증 컴포넌트는 다른곳에서도 사용중하고 있을 가능성이 높다 만약 다른 기능이 변경된다면 인증 컴포넌트도 변경될 수 도 있다. 이런식으로 결합이되어 있다는 의미로 알고 있으면 될거 같다. 그리고 인증부부만 변경 했는데 다른부분까지 다 한번에 재 배포를 해야하는 상황이 온다. 이런식으로 개발을 진행한다면 상호의존성의 제약이 커지고 전체 시스템의 복잡도가 높아질 것이다.
6 | - 이러한 복잡한 모놀리스 애플리케이션을 마이크로 서비스라는 독립적으로 배포할 수 있는 작은 구성 요소로 분할해야 한다. 각 마이크로 서비스는 독립적인 프로세스로 실행되며 단순하고 잘 정의돈 인터페이스로 다른 마이크로 서비스와 통신한다.
7 | - 생각해보면 회사에서도 쿠버네티스로 서비스를 운영중이다. 몸으로 느끼는 단점은 각각에 대한 애플리케이션에 대한 CI/CD를 구축해야한다는 점이다. 즉 애플리케이션이 추가될 때 마다 CI/CD가 추가된다는 점이다. 모놀리스 서비스는 하나의 CI/CD만 구축하면 되는데 마이크로 서비스는 각각에 대한 CI/CD를 구축해야 한다는 점이 존재한다.
8 | - 그리고 뭔가 서비스 처럼 돌아가게 만들려면 누군가는 서비스에 대해 제대로 알고 있어야 한다는 점이다. 예를들어 프론트엔드를 마이크로 서비스로 구축했다면, 메인 서비스에서 다른 마이크로 서비스들을 호출 할 수 있게 엔드포인트 설정을 해줘야 할 것이다.
9 | - 개발 이외에도 협업 즉, 소통이 중요하다. 사람들은 자기만의 성격이나 생각을 가지고 있기 때문에 여러가지 문제가 생길 수 있다..
10 |
11 |
12 | ## 컨테이너
13 | - 컨테이너 내부를 알고 사용하자. 컨테이너가 동작할 수 있는 이유는 첫 번째는 리눅스 네임스페이스로 각 프로세스가 시스템에 대한 독립된 뷰를 볼 수 있어서다.그렇다면 네임스페이스란 무엇일까?
14 | - 마운트(mnt)
15 | - 프로세스ID(pid)
16 | - 네트워크(net)
17 | - 프로세스 간 통신(ipc)
18 | - 호스트와 도메인 이름(uts)
19 | - 사용자 ID(users)
20 | - 기본적으로 리눅스 시스템은 초기 시작할 때 하나의 네임스페이스가 존재하고 파일시스템, 프로세스, 사용자 네트워크 인터페이스 등과 같은 모든 시스템 리소스는 하나의 네임스페이스에 속한다. 프로세스는 동일한 네임스페이스 내에 있는 리소스만 볼 수 있다.
21 | - 두 번째는 Cgroups 프로세스가 사용할 수 있는 리소스의 양을 제한할 수 있다.
22 | - cpu
23 | - memory
24 | - network
25 |
26 | ## 도커 컨테이너 등장
27 | - 컨테이너 기술은 오랫동안 사용돼 왔지만, 도커 칸테이너가 등장으로 널리 알려지게 된것이다. 여러 시스템에 쉽게 이식이 가능하게 하는 최초의 시스템인것이다.
28 | - 애플리케이션 배포에 필요한 라이브러리, 종속성 등등 도커를 실행하는 다른 컴퓨터에 애플리케이션을 배포하는데 사용할 수 있는 것이다.
29 |
30 |
31 | ## 도커 이미지 레이어
32 | - 도커 이미지는 레이어로 구성돼어 있다. 모든 도커 이미지는 다른 이미지 위에 빌드되고 두 개의 다른 이미지는 기본 이미지로 동일한 부모 이미지를 사용할 수 있다. 다른 이미지에는 정확히 동일한 레이어가 포함될 수 있다.
33 | - 첫 번째 이미지의 일부로 전송한 레이어를 다른 이미지를 전송할 때 다시 전송할 필요가 없기 때문에 네트워크로 이미지를 배포하는 속도가 빨라진다.
34 | - 도커 이미지 레이어는 배포를 효율적으로 할 뿐만 아니라 이미지의 스토리지 공간을 줄이는 데 도움된다. 각 레이어는 동일 호스트에 한 번만 저장된다.
35 | - 주의할 점 도커는 도커 자체가 프로세스를 격리하는게 아니다. 컨테이너 격리는 리눅스의 네임스페이스 기술과 cgroup과 같은 커널 수준에서 수행되는 것이다.
36 |
37 |
38 | ## 쿠버네티스 등장
39 | - 쿠버네티스는 오랜 세월 동안 구글 보그 --> 오메가로 변경된 시스템이라는 내부 시스템을 개발해 애플리케이션 개발자와 시스템 관리자가 수천 개의 애플리케이션과 서비스를 관리하는 데 도움을 줬다. 수십만 대의 머신을 우녕할 때, 사용률이 조그만 향상돼도 수백만 달러가 절약되므로 이러한 시스템을 개발할 동기는 분명하다. 구글은 10년동안 보그와 오메가를 비밀로 유지하고 2014년 보그 오메가 내부 구글 시스템으로 얻은 경험 기반으로 쿠버네티스를 출시했다.
40 | - 아마도 구글같은 큰 기업은 서비스가 적어도 수천개의 컨테이너가 존재했을 거다. 이러한 컨테이너 운영하는데 힘든점이 있을 가능성이 높았을거 같다. 진짜 상상도 안된다. 그냥 도커 컨테이너 10개만 해도 운영하기가 힘들텐데 이런게 수천개가 있다고 생각하니 끔찍하다.
41 | - 구글은 아마도 내부에서는 쿠버네티스 이상의 기술을 가지고 있을거 같다.
42 |
43 |
44 | ## 쿠버네티스가 Yaml(디스크립션) 실행하는 방법
45 | - kubernetes api 서버가 애플리케이션 디스크립션을 처리할 때 스케줄러(컨트롤 플레인 포함되어 있음) 각 컨테이너에 필요한 리소스를 계산하고 해당 시점에 각 노드에 할당되지 않은 리소스를 기반으로 사용 가능한 Worker Node에 지정된 컨테이너를 할당한다 그런다음 kubelet(워커노드에 존재)은 컨테이너 런타임에 필요한 컨테이너 이미지를 가져와서 컨테이너를 실행하도록 지시한다.
46 | - 만약에 하나의 파드에 두개의 컨테이너가 있다면 해당 컨테이너들은 같은 노드에 배치될것이다. 이 컨테이너들이 따로 배치되서는 안된다.
47 |
48 |
49 | 
50 |
51 |
52 |
53 |
54 | ## 쿠버네티스 아키텍처
55 | - 쿠버네티스 클러스터를 이루는 구성 요소는 컨트롤플레인과 (워커)노드로 이루워져 있다.
56 |
57 |
58 | ## 컨트롤플레인 구성 요소
59 | - etcd 분산 저장 스토리지
60 | - API 서버
61 | - 스케줄러
62 | - 컨트롤러 매니저
63 | 4가지 구성요소들은 클러스터 상태를 저장하고 관리하지만, Application을 실행하는건 아니다.
64 |
65 | ## 워커노드 구성요소
66 | - Kubelet
67 | - 쿠버네티스 서비스 프록시(kube-proxy)
68 | - 컨테이너 런타임(Docker, rkt...)
69 |
70 |
71 | 
72 |
73 | 위에서 언급한 컨틀롤러 구성요소나 워커노드 구성요소들은 개별 프로세스로 실행되는 것이다.
74 |
75 | 알아야할 점 쿠버네티스 시스템 요소는 오직 API Server와 만 통신을 한다 위 그림처럼 다른 구성요소들은 ectd와 직접 통신할 수 없고 api server와 통신을 진행한다.
76 |
77 | 쿠버네티스에서 다 중요하지만 특별히 중요한 점은 etcd 와 api server다. etcd와 api server는 여러 인스턴스에 할성화해서 작업을 병렬로 처리할 수 있다.
78 |
79 |
80 |
81 | TIP)kubelet은 무조건 시스템 구성요소(Daemon)로 실행해야한다.
82 |
83 |
84 |
85 | ## 쿠버네티스는 etcd를 어떻게 사용할까
86 | - 우리가 애플리케이션을 파드로 배포하던 deployment로 통해 배포를 하던 아니면 다양한 쿠버네티스 resouces를 사용해 애플리케이션을 배포하게 되면 이 배포가 실패를 하던지 성공을 하던지 사용한 yaml 파일은 ectd key value형태로 저장이된다.
87 | - 위에서 말했던것처럼 etcd는 오로지 api server와 통신을 한다. 클러스터 상태와 메타데이터를 저장하는 저장하는 유일한 장소가 etcd이다.
88 |
89 |
90 | ## 낙관적 동시성 제어
91 | - 데이터를 잠금을 설정해 그동안 데이터를 읽거나 업데이트를하지 못하도록 하는 대신 데이터에 버전 번호를 포함하는 방법이다.
92 | 업데이트 될 때 마다 버전 번호는 증가 클라이언트가 데이터를 읽은 시간과 업데이트를 제풀하는 시간 사이에 버전 번호가 증가했는지 여부를 체크
93 |
94 |
95 | ## 리소스를 etcd에 저장하는 방법
96 | - etcd의 각 키는 다른 키를 포함하는 디렉토리이거나 해당 값을 가진 일반 키다. 쿠버네티스는 모든 데이터를 /registry아래에 저장한다.
97 | - /registry/configmap
98 | - /registry/daemonsets
99 | - /registry/events
100 | - /registry/namespace
101 | - ...
102 |
103 | 쿠버네티스는 다른 모든 구성 요소가 api server를 통신하도록 만들어졌다. api server에 낙관성 동시성 제어 메커니즘을 구현해서 클러스터의 상태를 업데이트하기 전에 오류가 발생할 가능성을 줄이고 항상 일관성을 유지할 수 있다.
104 |
105 |
106 |
107 | ### 우리가 자주 사용하는 명령어 kubectl ... 내부에서는 많은 일들이
108 |
109 | 
110 |
111 | api Server는 이보다 더 많은 기능들이 있게지만 짧게 표현을 했다.
112 | 1. 인증 플러그인
113 | - 사용자를 클라이언트 인증서 혹은 http 헤더에서 가져온다. 플러그인은 클라언트의 사용자 이름, 사용자 ID, 속해있는 그룹정보
114 | 그렇다면 우리가 사용하고 있는 GKE에서는 kubectl 명령어를 사용하게 된다면 어떤식으로 흘러가는지 보자
115 |
116 |
117 | 
118 |
119 | 그림에 나오는것처럼 user는 아마도 gcp에서 관리하는 serviceAccount 이면서 iam에는 권한이 있을거같다. 예를들자면 클러스터 관리자 권한 or 클러스터 뷰어 권한처럼 말이다.
120 |
121 |
122 |
123 | ## 스케줄러
124 | - 스케줄러는 api server의 감시 메커니즘을 통해 새로 생성될 파드를 기다리고 있다가 할당된 노드가 없는 새로운 파드를 노드에 할당하기만 한다.
125 | - 스케줄러는 api server로 파드 정의를 갱신하는 것 뿐이다.
126 | - api server는 감시 메커니즘을 통해 kubelet에 파드가 스케줄링된 것을 통보한다. 대상 노드의 kubelet은 파드가 해당 노드에 스케줄링 된것을 확인하자마자 파드의 컨테이너를 생성하고 실행한다.
127 | - 스케줄러는 따로 정리를 해야할거 같다 많은 내용이 있기때문에...
128 |
129 | TIP Application을 배포할 때 파드 내에 schedulerName이라는 옵션을 사용해서 사용할 파드를 스케줄링할 때 사용할 스케줄러를 지정할 수 있다.
130 | 이말은 즉, 사용자가 직접 스케줄러를 구현해서 클러스터에 배포할 수 있고 다른 설정 옵션을 가진 쿠버네티스의 스케줄러를 배포할 수 있다는 것
131 |
132 |
133 | ## 컨트롤러 매니저
134 | - 컨트롤러는 다양한 작업을 수행하지만 모두 api 서버에서 리소스(deployment, pod, service ...)변경되는 것을 감시하고 각 변경 작업(새로운 오브젝트를 생성하거나 이미 있는 오브젝트의 갱신 혹은 삭제)을 수행한다.
135 | - 컨트롤러 역시 api 서버에 연결하고 감시 메커니즘을 통해 컨트롤러가 담당하는 리소스 유형에서 변경이 발생하면 통보해줄 것을 요청한다.
136 |
137 |
138 | ## Kubelet
139 | - kubelet은 워커 노드에서 실행하는 모든 것을 담당하는 요소
140 | - kubelet이 실행중인 노드를 노드 리소스로 만들어서 api 서버에 등록하는 것
141 | - kubelet은 api 서버를 지속적으로 모니터링해 해당 노드에 파드가 스케줄링되면 파드의 컨테이너를 시작
142 | - 실행중인 컨테이너를 계속 모니터링하고 상태 체크하며 이벤트 및 리소스 사용량을 api서버에 보낸다.
143 |
144 |
145 | ## kube-proxy
146 | - kube-proxy는 서비스의 ip와 포트로 들어온 접속을 서비스(혹은 파드가 없는 서비스 엔드포인트)를 지원하는 파드 중 하나와 연결시킨다.
147 | - 서비스가 2개 이상의 파드를 지원하는 경우 프록시는 파드 간에 로드 밸런싱을 수행한다.
148 |
149 |
150 | ## 전체적인 deployment 생성과정
151 |
152 | 
153 |
154 |
155 | ## 파드의 네트워크
156 | - 파드의 모든 컨테이너가 동일한 네트워크와 리눅스 네임스페이스를 공유하는 법은 퍼즈(pause) 컨테이너가 같이 배포되기 때문이다.
157 | - 즉, 한 파드내에 여러개 컨테이너가 있다고 했을 때 결과적으로 동일한 리눅스 네임스페이스를 공유하는 3개의 컨테이너를 실행하는 것
158 |
159 |
160 | ## 네트워크 동작방식
161 | 
162 |
163 | 노드의 파드는 가상 이더넷 인터페이스 쌍을 통해 같은 브리지로 연결된다.
164 |
165 | - 컨테이너가 시작되기 전에, 컨테이너를 위한 가상 이더넷 인터페이스 쌍(veth)가 생성된다. 노드에서 ifconfig를 command실행하면 veth가 남아있는걸 확인할 수 있다.
166 | - 호스트의 네트워크 네임스페이스에 있는 인터페이스는 컨테이너 런타임이 사용할 수 있도록 설정된 네트워크 브리지에 연결된다.
167 | - 컨테이너 eth0 인터페이스는 브리지의 주소 범위 안에서 ip할당 받는다.
168 | - 컨테이너 내부에서 실행되는 애플리케이션은 eth0인터페이스(컨테이너 네임스페이스의 인터페이스)로 전송하면 호스트 네임스페이스의 다른 쪽 veth 인터페이스로 나와 브리지로 전달된다.
169 | - 이의미는 브리지에 연결된 모든 네트워크 인터페이스에서 수신할 수 있다는 것을 의미한다.
170 |
171 | ## kube-proxy가 iptables를 다루는 법
172 | - api server에서 서비스를 생성하게 된다면, 가상 ip 주소를 만든다. 바로 api 서버는 워커 노드에서 실행 중인 모든 kube-proxy 에이전트에 새로운 서비스가 생성되었다고 알린다.
173 | - 각 kube-proxy는 실행중인 노드에 해당 서비스 주소로 접근할 수 있도록 만든다.
174 |
--------------------------------------------------------------------------------
/pattern/README.md:
--------------------------------------------------------------------------------
1 | ## Kubernetes Pattern
2 | - 앰버서더 컨테이너 패턴는 api 서버와 직접 통신하는 대신 메인 컨테이너 옆의 앰버서더 컨테이너에서 kubectl proxy를 실행하고 이를 통해 api 서버와 통신할 수 있는 Pattern이다.
3 | - api 서버와 직접 통신하는 대신 메인 컨테이너의 애플리케이션은 HTTPS 대신 HTTP를 실행하고 통신을 할 수 있다. 즉, 애플리케이션은 앰배서더와 연결하고 앰배서더는 서버에 대한 HTTPS 연결을 처리하는 것이다. 그리하여 보안을 투명하게 관리할 수 있다.
4 |
5 |
6 | 
7 |
8 | ```agsl
9 | apiVersion: v1
10 | kind: Pod
11 | metadata:
12 | name: appname
13 | labels:
14 | name: appname
15 | spec:
16 | containers:
17 | - name: main
18 | image: tutum/curl
19 | - name: ambassador
20 | image: luksa/kubectl-proxy:1.6.2
21 | ```
22 | 현재 파드내 두개의 컨테이너가 존재하며 main container에 접근을 하려면 -c옵션을 사용해 접근해야한다.
23 |
24 | ```agsl
25 | kubectl exec -it appname -c main bash
26 | ```
27 |
28 | 
29 |
--------------------------------------------------------------------------------
/pattern/pattern.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: appname
5 | labels:
6 | name: appname
7 | spec:
8 | containers:
9 | - name: appname
10 | image: tutum/curl
11 | - name: ambassador
12 | image: luksa/kubectl-proxy:1.6.2
13 |
--------------------------------------------------------------------------------
/resources/configmap/README.md:
--------------------------------------------------------------------------------
1 | ## configmap 사용
2 | - 쿠버네티스 안에서 실행되는 애플리케이션에 설정 데이터를 전달하는 방법중 하나가 configmap를 사용하는 것이다.
3 | - 쿠버네티스에서는 설정 옵션을 컨피그맵이라 부르는 별도 오브젝트로 분리할 수 있다.
4 | - configmap은 키/값 쌍으로 구성으로 이루어져있다.
5 | - configmap에 정의한 값을 프로세스의 명령줄 인자로 전달할 수 있다.
6 |
7 |
8 | ## 사용시 주의할 점
9 | - configmap의 키값은 유효한 DNS 서브도메인이어야 한다.
10 | - 영숫자, 대시, 밑줄, 점만 포함할 수 있다.
11 |
12 |
13 | ## command configmap 만들기
14 | ```agsl
15 | kubectl create configmap testconfigmap --from-literal=america=english
16 |
17 | 여러 키값 넣어주기
18 | kubectl create configmap testconfigmap --from-literal=america=english --from-literal=canada=english
19 |
20 | 파일 내용으로 configmap 만들기
21 |
22 | kubectl create configmap fileconfig --from-file=config_file.conf
23 |
24 | 파일을 특정 키값에 넣어주기
25 | kubectl create configmap fileconfig --from-file=nginx.conf=config_file.conf
26 | ```
27 |
28 |
29 | ## pod에서 configmap가져오기
30 | ```agsl
31 | apiVersion: v1
32 | kind: pod
33 | metadata:
34 | name: test-pod
35 | spec:
36 | containers:
37 | - image: test/test
38 | env:
39 | - name: NUMBER ---> NUMBER라는 환경변수에 설정
40 | valueFrom:
41 | configMapKeyRef:
42 | name: test-config ----> 참조하는 configmap name
43 | key: NUMBER -----> configmap에 설정된 키 값을 number에 설정
44 | ```
45 |
46 |
47 | ## 존재하지 않는 configmap을 파드내에 설정하면 파드가 죽을까?
48 | - 맞다 존재하지않는 컨피그맵을 파드가 참조한다면 파드는 당연히 죽을것이다. 그러나 옵션 설정을 해준다면 일단 파드는 운영할 수 있게 할 수 있다.
49 | - configmap configMapKeyRef.optional: true configmap이 존재하지 않아도 컨테이너는 시작한다.
50 |
51 |
52 | ## 하나하나 지정하지 않고 한번에 환경변수 지정하는방법은?
53 | - 필요한 항목을 각각 지정해준다면 오래걸릴 뿐만아니라 실수할 가능성이 있다. 그렇다면 한번에 전달하는 방법은 있을까? 존재한다.
54 |
55 |
56 | ```agsl
57 | apiVersion: v1
58 | kind: pod
59 | metadata:
60 | name: test-pod
61 | spec:
62 | containers:
63 | - image: test/test
64 | envFrom
65 | configMapRef:
66 | name: my-config-map
67 | ```
68 |
69 |
70 | ## 컨피그맵 항목을 명령줄 인자로 전달하자.
71 | ```agsl
72 | apiVersion: v1
73 | kind: pod
74 | metadata:
75 | name: test-pod
76 | spec:
77 | containers:
78 | - image: test/test
79 | env:
80 | - name: NUMBER
81 | valueFrom:
82 | configMapKeyRef:
83 | name: test-config
84 | key: NUMBER
85 | args: [$(NUMBER)]
86 | ```
87 |
88 |
89 |
90 | ## volume내에 존재하는 configmap을 파드에 전달하는방법
91 |
92 | ```agsl
93 | apiVersion: v1
94 | kind: pod
95 | metadata:
96 | name: test-pod
97 | spec:
98 | containers:
99 | - image: test/test
100 |
101 | volumeMounts:
102 | - name; config
103 | mountPath: /etc/nginx/conf.d ----> configmap 볼륨을 마운트하는 위치
104 |
105 | volumes:
106 | - name: config
107 | configMap:
108 | name: my-conf ----> my-conf라는 configmap을 참조한다.
109 |
110 | ```
111 |
112 |
113 | ## 개별 configmap 항목을 마운트하는 방법
114 |
115 | ```agsl
116 | apiVersion: v1
117 | kind: pod
118 | metadata:
119 | name: test-pod
120 | spec:
121 | containers:
122 | - image: test/test
123 |
124 | volumeMounts:
125 | - name; config
126 | mountPath: /etc/test/init.conf 디렉토리가 아닌 파일을 마운트
127 | subPath: init.conf ----> 전체 볼륨을 마운트하는 대신 init.conf항목만 마운트
128 | ```
129 | subPath는 모든 종류의 볼륨을 마운트할 때 사용할 수 있다. 전체 볼륨을 마운트하는 대신에 일부만 마운트할 수 있다.
130 | 그러나 개별 파일을 마운트하는 이 방법은 파일업데이트와 관련해 큰 결함이 존재한다.
131 |
132 |
133 | ## configmap 볼륨 안에 있는 파일 권한 설정
134 | - defaultMode opiton을 사용하자
135 |
136 |
137 |
138 | ## 단일파일에 마운트했을 때 업데이트가 되지 않는다.
139 | 만약 전체 볼륨대신에 단일 파일을 컨테이너에 마운트한 경우에는 업데이트를 해도 업데이트가 되지않는다.
140 | subPath를 사용하는 컨피그맵은 자동으로 업데이트하지 않는다.
141 | 가장 쉬운 방법은 configmap 정보를 업데이트 후 파드를 한번 delete했다가 재 실행 하는것도 하나의 방법이다.
--------------------------------------------------------------------------------
/resources/deployment/README.md:
--------------------------------------------------------------------------------
1 | ## Deployment
2 | - 디플로이먼트는 낮은수준의 개념으로 레플리케이션컨트롤러 or 레플리카셋을 통해 수행하는 대신 애플리케이션을 배포하고 선언적으로 업데이트하기 위한 높은 수준의 리소스다.
3 | - 디플로이먼트를 생성하면 레플리카셋 리소스가 그 아래에 생성이된다. 레플리카셋은 레플리케이션컨트롤러 이므로 레플리케이션컨트롤러 대신 레플리카셋을 사용해야 한다. 레플리카셋도 파드를 복제하고 관리한다.
4 | - 그러나 디플로이먼트를 사용하게된다면 실제 파드는 디플로이먼트가 아닌 디플로이먼트의 레플리카셋에 의해 생성되고 관리된다.
5 |
6 | 
7 |
8 | Deployment는 파드를 관리하지않는다. 대신 레플리카셋을 생성하고 이들이 파드를 관리한다.
9 |
10 | ## Deployment 업데이트 전략
11 | Recreate 전략: 레플리케이션컨트롤러의 파드 템플릿을 수정한 후 모든 파드를 삭제하는 것과 마찬가지로 한 번에 기존 모든 파드를 삭제한 뒤 새로운 파드를 만든다.
12 | Recreate를 사용하게된다면, 새 파드를 만들기 전에 이전 파드를 모두 삭제한다.
13 | - 만약에 애플리케이션이 여러 버전을 병렬로 실행하는 것을 지원하지 않고 새 버전을 시작하기 전에 이전 버전을 완전히 중지해야 하는 경우만 이 전략을 사용하자. 이 전략은 잠시 다운타임이 생긴다.
14 | - 만약에 이전 버전과 새 버전을 동시에 실행할 수 있는 경우는 RollingUpdate 전략을 사용하자.
15 |
16 | 디플로이먼트의 파드 템플릿이 Configmap or Secret을 참조하는 경우에는 아무리 configmap을 수정해도 업데이트를 시작하지않는다. 애플리케이션의 설정을 수정해야할 때 업데이트를 시작하는 한 가지 방법은 새 컨피그맵을 만들고 파드 템플릿이 새 컨피그맵을 참조하도록 하는 것이다.
17 |
18 | 
19 |
20 | 
--------------------------------------------------------------------------------
/resources/deployment/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youyoungnam/kubernetes-implement/1a113e9ad0bfb3141753dbac7363626bcec99829/resources/deployment/img.png
--------------------------------------------------------------------------------
/resources/deployment/img_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youyoungnam/kubernetes-implement/1a113e9ad0bfb3141753dbac7363626bcec99829/resources/deployment/img_1.png
--------------------------------------------------------------------------------
/resources/deployment/img_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youyoungnam/kubernetes-implement/1a113e9ad0bfb3141753dbac7363626bcec99829/resources/deployment/img_2.png
--------------------------------------------------------------------------------
/resources/namespace/README.md:
--------------------------------------------------------------------------------
1 | ## namespace
2 | - 네임스페이스가 쿠버네티스에서 필요한 이유 여러 네임스페이스를 만들게 되면 만흥ㄴ 구성 요소를 가진 복잡한 시스템을 더 작은 개별구룹으로 나눌 수 있다. 또한 멀티 테넌트 환경처럼 리소스를 분리하는 데 사용 할 수 있다.
3 | - 리소스를 프로덕션, 개발, QA환경 혹은 원하는 다른 방법으로 나누어 사용할 수 있다.리소스 이름은 네임스페이스 안에서만 고유하면 된다.
4 | - 네임스페이스는 리소스를 격리하는 것 외에도 특정 사용자가 지정된 리소스에 접근할 수 있도록 허용하고 개별 사용자가 사용할 수 있는 컴퓨팅 리소스를 제한하는 데에도 사용할 수 있다.
--------------------------------------------------------------------------------
/resources/namespace/istio-injection.namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: testing
5 | labels:
6 | istio-injection: enabled
--------------------------------------------------------------------------------
/resources/namespace/namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: testing
--------------------------------------------------------------------------------
/resources/pod/README.md:
--------------------------------------------------------------------------------
1 | # 파드(Pod)
2 | - 파드는 함께 배치된 컨테이너 그룹이고 쿠버네티스의 기본 빌딩 그룹이다. 컨테이너를 개별적으로 배포한다기 보다는 컨테이너를 가진 파드를 배포하고 운영한다.
3 | - 항상 파드가 두 개 이상의 컨테이너를 포함하는 것을 의미하는 것이 아니다. 일반적으로 파드는 하나의 컨테이너만 포함한다. 파드의 핵심은 파드가 여러개의 컨테이너를 가지고 있는 경우에 모든 컨테이너는 항상 하나의 워커 노드에세 실행된다. 즉 하나의 파드내에 있는 컨테이너가 여러 노드에 배치되지 않는 다는 것이다.
4 |
5 |
6 | ## 파드가 필요한 이유
7 | - 파드가 왜 필요할까? 단순하게 쿠버네티스 사용하니까 쿠버네티스에서 애플리케이션을 배포하기 위해서는 파드를 감싸서 배포해야하니까 ?
8 |
9 | ### 여러 프로세스를 실행하는 단일 컨테이너보다 다중 컨테이너가 나은 이유
10 | - 쿠버네티스에서는 프로세스를 항상 컨테이너에서 실행시키고 각 컨테이너는 격리된 머신과 비슷하기 때문에 여러 프로세스를 단일 컨테이너 안에서 실행하는 것이 타당할 수 있지만, 실제로 그렇지않다. 컨테이너 목적은 단일 프로세스를 실행하는 것으로 목적으로 설계되었다.
11 | - 단일 컨테이너에서 관련없는 프로세스를 실행하는 경우 모든 프로세스를 실행하고 로그를 관리하는 것은 모두 사용자 책임이다.
12 | - 따라서 각 프로세스를 자체의 개별 컨테이너로 실행해야 한다.
13 |
14 |
15 | ## 파드 이해하기
16 | - 여러 프로세스를 단일 컨테이너로 묶지 않기 때문에 컨테이너를 함께 묶고 하나의 단위로 관리할 수 있는 상위 구조가 필요한 것 이게 파드가 필요한 것이다.
17 | - 컨테이너 모음을 사용해 밀접하게 연관된 프로세스를 함께 실행하고 단일 컨테이너 안에서 모두 실행되는 것처럼 동일한 환경을 제공할 수 있으면서도 격리된 상태를 유지할 수 있다.
18 | - 즉 컨테이너가 제공하는 모든 기능을 활용하는 동시에 프로세스가 함께 실행되는 것처럼 보이게 할 수 있다는 것
19 |
20 |
21 | ## 파드 구성
22 | - 파드는 상대적으로 가볍다. 오버헤드 없이 필요한 만큼 파드를 가질 수 있다.모든 것을 하나의 파드에 넣는 대신에 애플리케이션을 여러 파드로 구성하고 각 파드에는 밀접하게 관련있는 구성 요소나 프로세스만 포함해야한다.
23 | - 그러면 이렇게 생각할 수 도 있다 프론트엔드 백엔드 백엔드 데이터베이스로 구성된 다 중 계층 애플리케이션을 하나의 파드 또는 두 개의파드로 구성하는게 맞을까?
24 | - 백엔드 서버와 데이터베이스를 하나의 파드로 묶는건 어렵지 않다. 근데 적절한 방법이 아니다. 위에서 말했던 것 처럼 파드내에 있는 컨테이너는 서로 다른 노드에 배치되는게 아니다 즉 하나의 노드에 두개 컨테이너가 배치되는 것이다.
25 | - 만약에 위에서 구성한 방식 백엔드 서버와 데이터베이스를 하나의 파드로 묶는다면 항상 같은 노드에 있을 것이고 만약에 클러스터를 구성했는데 이 클러스터는 두 개의 노드가 있다면 백엔드 서버와 데이터베이스가 있는 파드는 두 개중 하나의 노드가 배치될것이고 하나의 노드에 배치되면 하나의 노드의 자원은 남게되고 자원 낭비를 하는 것이다.
26 |
27 |
28 |
29 | ## 언제? 파드에 두 개 이상 컨테이너를 넣어야하는가?
30 | - 컨테이너를 함께 실행해야 하는가 아니면 서로 다른 호스트에서 실행할 수 있는가?
31 | - 여러 컨테이너가 모여 하나의 구성 요소를 나타내는가? 아니면 개별적인 구성 요소인가?
32 | - 컨테이너가 함께 혹은 개별적으로 스케일링 돼야 하는가?
33 |
34 | 하나의 파드에 두 개 컨테이너를 넣어 배포해야 할 때는 위 질문을 생각해봐야 한다.
35 |
36 |
37 |
38 | ## 파드 안정적으로 운영하는 법
39 | - 쿠버네티스에서 파드는 배포 가능한 기본 단위이다. 우리는 실제로 파드를 배포하게 되면 파드를 수동적으로 개입하지 않고 안정적인 상태로 유지되길 원할 것이다. 레플리케이션 컨트롤러, 디플로이먼트와 같은 리소스를 생성해 실제 파드를 생성하고 관리 할 수 있다.
40 | - 우리가 파드를 배포하게 된다면, 파드는 특정 워커노드에 배치가 되고 해당 노드에서 파드의 컨테이너가 실행 될 수 있게 작업을 진행한다. 만약에 파드에 포함된 컨테이너 중 하나가 죽으면 어떻게 될까? 하나가 아니라 모든 컨테이너가 죽는다면? 파드가 노드에서 스케줄링되는 즉시 해당 노드의 kubelet은 파드의 컨테이너를 실행하고 파드가 존재하는 한 컨테이너가 계속 실행되도록 할 것이다.
41 | - 컨테이너의 주 프로세스 크래시가 발생하면 kubelete이 다시 시작한다. 그래서 우리는 파드가 문제가 생겨 애플리케이션에서 작업을 안하더라도 쿠버네티스는 애플리케이션을 실행하는 것만으로도 자동으로 치유할 수 있다.
42 | - 떄떄로 우리의 애플리케이션이 크래시가 없이도 죽는경우가 생긴다. 예를들어 무한루프나 교착 상태에 빠져서 응답하지 못하는 상황이라면 어떻게 해야할까 이럴땐 내부의 기능에 의존하지 않고 외부에서 애플리케이션 상태를 체크해야한다.
43 |
44 |
45 | ## 정리
46 | - 파드는 일시적이다. 파드가 다른 파드를 위한 공간을 확보하려고 노드에서 제거되거나 누군가의 파드를 줄이거나 클러스터 노드의 장애로 언제든지 다른 노드로 이동할 수 있다.
47 | -
--------------------------------------------------------------------------------
/resources/replicationController/README.md:
--------------------------------------------------------------------------------
1 | ## ReplicationController
2 | - 레플리케이션컨트롤러는 쿠버네티스 리소스로서 파드가 항상 실행하도록 보장한다. 어떤이유에서든 파드가 사라지면, 쉽게말해 클러스터에서 노드가 사라지거나 노드에서 파드가 제거된 경우 레플리케이션컨트롤러는 사라진 파드를 감지해 교체 파드를 생성한다.
3 | - 레플리케이션컨트롤러는 파드의 여러 복제본을 작성하고 관리하기 위한 것이다. 이것이 레플리케이션컨트롤러란 이름의 유래이다.
4 |
5 | ### 동작
6 | - 레플리케이션컨트롤러는 실행중인 파드 목록을 지속적으로 모니터링하고 특정 유형의 실제 파드 수가 의도하는 수와 일치하는지 항상 확인한다. 이런 파드가 너무 적게 실행 중인 경우 파드 템플릿에서 새 복제본을 생성한다. 또한 너무 많은 파드가 생성되면 초과 복제본을 제거한다.
7 | - 레플리케이션컨트롤러는 파드의 유형이 아니라 특정 레이블 셀렉터(label selector)와 일치하는 파드 세트에 작동한다.
8 |
9 | 
10 |
11 |
12 | 
13 |
14 | - 레이블 셀렉터는 레플리케이션컨트롤러의 범위에 있는 파드를 결정
15 | - 레플리카수는 실행할 파드의 의도하는(Desired)수를 지정
16 | - 파드 템플릿은 새로운 파드 레플리카를 만들 때 사용
17 |
--------------------------------------------------------------------------------
/resources/service/README.md:
--------------------------------------------------------------------------------
1 | # service
2 |
3 |
4 | ### 서비스 동작방식
5 | - 우리는 우리가 직접 컨테이너를 동작시키거나 생성하거나 하지않는다. 회사에서 사용하는 것을 생각해보면 우리가 직접 컨테이너를 동작시키지 않는다. 즉, 쿠버네티스가 마스터 서버에서 api와 컨트롤러와 소통을 하고 워커노드와 통신 후 적당한 노드에 배치한 다음에 노드에 존재하는 kube-proxy, kubelet, docker가 이미지를 불러오고 실행한다.
6 | - 만약에 우리가 kubectl run을 한다고 가정했을 때 레플리케이션 컨트롤러를 생성하고 러플리케이션 컨트롤러가 실제 파드를 생성한다. 클러스터 외부에서 파드에 접근케 하기 위해 쿠버네티스에게 레플리케이션 컨트롤러에 의해 관리 되는 모든 파드를 단일 서비스로 노출하도록 명령한다.
7 |
8 |
9 | client(포트 8080) ---------> 서비스: 서비스네임--> youngnam-http 내부ip: 10.x.x.x 외부ip: 104.x.x.x -----> 포트 8080 ----> 파드: application-andy(container) ----> 레플리케이션컨트롤러: 1
10 |
11 | ### 서비스는 왜 필요한 것인가?
12 | - 서비스가 왜 필요한지에 대해서 알려면 파드에 대해서 알아야한다. 파드는 일시적이다. 즉, 죽으면 ip가 변한다. 그리고 언제 어디서든지 갑자기 사라질 수 도 있다. 그래서 레플리케이션은 desired state를 만족하기 위해 다시 생성한다. 이렇게 만들어진 새로운 파드는 새로운 ip를 가지고 있다. 이것이 진짜 서비스가 필요한 이유다. 항상 변경되는 ip 주소 문제와 여러 개의 파드를 단일 ip와 포트의 쌍으로 노출 시키는 문제를 해결한다.
13 | - 서비스가 생성되면 정적 ip를 할당받는다. 서비스가 존속하는 동안은 변경되지 않는다. 파드에 직접 연결하는 대신 클라이언트는 서비스의 ip주소만으로 연결할 수 있다.
14 | - 서비스는 서비스가 존재하는 동안 절대 바뀌지 않는 ip와 포트가 존재한다. 클라이언트는 해당 ip와 포트로 접속한 다음 해당 서비스를 지원하는 파드 중 하나로 연결된다.
15 |
16 | 
17 |
18 | 위 그림을 보면 서비스를 지원하는 파드가 한 개 혹은 그 이상일 수 도 있다. 서비스 연결은 뒷단의 모든 파드로 로드밸런싱된다. 그러나 정확히 어떤 파드가 서비스의 일부분인지 아닌지 정확히 어떻게 정의할까???
19 | 레이블 셀렉터 Label Selector를 기억할 수 있다. 그리고 레이블 셀렉터는 레플리케이션 컨트롤러와 기타 파드 컨트롤러에서 레이블 셀렉터를 사용해 동일한 세트에 속하는 파드를 지정하는 방법을 기억할 것이다.
20 |
21 |
22 | ### 특정 파드내에서 다른서비스 curl 날리는법
23 | ```agsl
24 | kubectl exec pod-name -- curl -s http://service-ip
25 | ```
--------------------------------------------------------------------------------
/resources/volume/README.md:
--------------------------------------------------------------------------------
1 | ## Volume
2 | - 파드 내부의 각 컨테이너는 고유하게 분리된 파일시스템이 존재한다. 왜냐하면 파일시스템은 각 이미지에서 제공되기 때문이다. 만약에 컨테이너가 죽었다가 살아나게 된다면, 컨테이너가 이전에 실행했던 파일시스템의 어떤 파일들을 볼 수 없다.
3 | - 그러나 우리는 실제로 물리 머신에서처럼 새로운 컨테이너가 다시 나와도 이전 데이터가 그대로 보존되고 싶을 때 가 있다. 그럴 때 사용하는게 볼륨이다.
4 |
5 | ### Volume LifeCycle
6 | - 쿠버네티스 스토리지 볼륨은 파드의 일부분으로 정의 되며 파드와 동일한 라이프사이클을 가진다. 즉, 파드가 시작되면 볼륨이 실행되고 파드가 삭제되면 볼륨이 삭제된다는 것을 의미한다. 이 때문에 볼륨의 콘텐츠는 컨테이너를 다시 시작해도 지속된다. 즉, 컨테이너가 다시 시작되면 새로운 컨테이너는 이전 컨테이너가 볼륨에 기록한 모든 파일들을 볼 수 있다.
7 |
8 | ## Volume Type
9 | - emptyDir: 일시적인 데이터를 저장하는 데 사용되는 간단한 빈 디렉토리
10 | - hostPath: 워커 노드의 파일시스템을 파드의 디렉토리로 마운트하는 데 사용
11 | - gitRepo: 깃 레포지토리의 콘텐츠를 체크아웃해 초기화한 볼륨
12 | - nfs: NFS 공유를 파드에 마운트
13 | - gcePersistentDisk, awsElasticBlockStore, azureDisk: 클라우드 제공자의 전용 스토리지를 마운트
14 | - cinder, cephfs, iscsi, flocker, glusterfs, qusterfs, quobyte, rbd, flexVloume, vsphere Volume, photonPersistentDisk, scaleIO: 다른 유형의 네트워크 스토리지 마운트
15 | - configmap, secret, downwareAPI: 쿠버네티스 리소스 및 클러스터 정보 노출하는 데 사용하는 특별한 유형의 볼륨
16 | - persistentVolumeClaim: 사전에 혹은 동적으로 프로비저닝된 퍼시스턴트 스토리지 사용 방법
17 |
18 | 단일 파드는 동시에 여러 유형의 여러 볼륨을 사용할 수 있다. 파드의 각 컨테이너는 볼륨을 마운트할 수 있고 하지 않을 수 있다.
19 |
20 | emptyDir은 파드를 호스팅하는 워커 노드의 실제 디스크에 생성된다. gitRepo 볼륨은 기본적으로 emptyDir 볼륨이며 파드가 시작되면(container가 생성되기 전) git 레포지토리를 복제하고 특정 리비전을 checkout해 데이터를 채운다.
21 |
22 | 1. 개발자가 git 레포지토리를 가진 파드를 생성한다.
23 | 2. 쿠버네티스는 빈 디렉토리를 생성하고 특정 git 레포지토리를 복제한다.
24 | 3. 파드의 컨테이너가 마운트 경로에 볼륨이 마운트된 상태에서 시작한다.
25 |
26 | 단점 매번 git 레포지토리에 변경이 일어나고 그것을 파드에 있는 컨테이너에 적용되길 원한다면, 아마도 파드를 매번 지워줘야한다. git 레포지토리의 볼륨이 생성된 후에는 레포지토리와 동기화하지 않는다는 것이다. 그리고 쿠버네티스 1.27버전부터 볼륨유형에서 사용되지 않는다. 자세한 내용은 공식문서를 확인하면 다른 방식으로 접근할 수 있다.
27 | 만약에 git 레포지토리를 마운트하고 파드에 동기화를 해주길 원한다면 사이트카 방식으로 git sync이미지를 사용하여 동기화를 할 수 있는 방식이 있다.
28 |
29 |
30 | hostpath 볼륨은 노드 파일시스템의 특정 파일이나 디렉토리를 가리킨다. 동일 노드에 실행 중인 파드가 hostpath 볼륨의 동일 경로를 사용 중이면 동일한 파일이 표시된다.
31 | hostpath 볼륨의 콘텐츠는 파드가 죽으면 삭제되는 반면 hostpath 볼륨의 콘텐츠는 삭제되지 않는다. 즉, 파드가 삭제되면 다음 파드가 호스트의 동일 경로를 가리키는 hostpath 볼륨을 사용하고 이전 파드와 동일한 노드에 스케줄링된다는 조건에서 새로운 파드는 이전 파드가 남긴 모든 항목을 볼 수 있다.
32 |
33 |
34 | 
35 |
36 |
37 | 팁) 노드의 시스템 파일에 읽기/쓰기를 하는 경우에만 hostPath 볼륨을 사용한다는 것을 기억해야 한다. 여러 파드에 걸쳐 데이터를 유지하기 위해서는 절대 사용하지 말아야 한다.
38 |
39 |
40 |
41 | 퍼시스턴트 스토리지 사용은 파드에서 실행중인 애플리케이션이 디스크에 데이터를 유지해야 하고 파드가 다른 노드로 재 스케줄링된 경우에도 동일한 데이터를 사용해야 한다면 위에서말한 볼륨은 사용하면 안된다.
42 | 이러한 데이터는 어떤 노드에서도 접근이 가능해야한다. 즉 몽고디비같은 영구 데이터를 허용하는 볼륨을 사용
43 |
44 | 
45 |
46 |
--------------------------------------------------------------------------------
/resources/volume/git-repogistory.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: nginx-deployment
5 | spec:
6 | selector:
7 | matchLabels:
8 | app: nginx
9 | template:
10 | metadata:
11 | labels:
12 | app: nginx
13 | spec:
14 | containers:
15 | - name: nginx
16 | image: nginx
17 | volumeMounts:
18 | - mountPath: /usr/share/nginx/html
19 | name: html
20 | readOnly: true
21 | ports:
22 | - containerPort: 8080
23 | volumes:
24 | - name: hmtml
25 | gitRepo:
26 | repository: https://github.com
27 | revision: master
28 | directory: .
--------------------------------------------------------------------------------
/troubleshooting/GCP-L7(Load-Balancer)/README.md:
--------------------------------------------------------------------------------
1 | ## GCP L7
2 | 
3 | - 회사 내 서비스를 http에서 SSL 적용 후 https가 되었을 때 해당 서비스는 회사 말고 외부에서 접근을 못하게 막아야 했었다. SSL적용 후 GCP 내 방화벽에서 회사 아이피 대역대만 열어주고 나머지 다 막았으나 알고보니 외부에서 쉽게 접근이 가능했다.
4 | - 솔직히 처음에는 어떤 부분이 잘못된지 몰랐다. 분명히 우리는 방화벽에서 사내 아이피만 열어줬는데 외부에서 쉽게 접근이 가능했다는게 이해가 되지않았다.
5 | - 알고보니까 GCP L7 적용하게 되면, 해당 방화벽은 GCP armor 서비스를 이용해야 했다. gcp에 기존 존재하는 방화벽 설정으로는 적용되지 않았던 것이였다.
6 |
7 | ## GCP Armor 설정 후
8 | - L7 방화벽 설정 이후 외부에서 접근은 막았으나, 문제는 그 이후부터다. 사내 서비스 로그인을 했는데 500 error가 나오는 것이였다.(자세하게 설명못하는 점 이해 부탁드립니다.) 사내에서만 접속은 가능하지만, 로그인을 했을 때 500 error가 반응을 했을 때 이해가 되지않았는데 하나씩 생각해봤다.
9 | - 첫 번째 L7의 대역대를 열어줘야하나? 생각했었다. 그래서 방화벽에 L7의 대역대를 열어줬으나 잘못된 생각이였다. 여전히 같은 500 error가 나왔다.
10 | - 두 번째는 성공이였다. 우리는 oauth2-proxy를 사용중인데, oauth2-proxy 설정에서 아마도 cluster 외부로 나갔다가 다시 들어오는 거같은 기분이 들었었다. 즉, oauth2-proxy에서 클러스터 나트 게이트웨이를 타고 다시 들어오는 기분이 들어서 나트 게이트웨이 대역대를 열어주니 성공한 것이였다.
11 |
12 |
--------------------------------------------------------------------------------
/troubleshooting/Ingress/README.md:
--------------------------------------------------------------------------------
1 | # Nginx Ingress Controller + istio 연결 이슈
2 |
3 |
4 | ## Ingress
5 | - 클러스터 외부에서 내부 서비스로 접근하는 HTTP, HTTPS 요청을 어떻게 처리할지 정의
6 | - Ingress를 사용하지 않았을 때 쿠버네티스가 외부 요청을 처리할 수 있는 방법은 NodePort, ExternalIP 방법이 있다.
7 | - NodePort, ExternalIP는 Layer 4 (TCP, UDP) 해당되기 때문에 네트워크에 대한 처리 요청이 한계가 있다.
8 |
9 | ## Ingress Controller
10 | - Ingress Controller는 Ingress가 동작하기 위해 반드시 필요한 Controller다.
11 | - Istio Ingress는 istio 기반 Ingress Controller다.
12 | - Ingress 정의 후 Ingress Controller에 적용함으로 써 추상화 단계에서 서비스로직을 처리할 수 있다.
13 |
14 | ```agsl
15 | kind: Ingress
16 | metadata:
17 | annotations:
18 | "nginx.ingress.kubernetes.io/ssl-redirect":"true"
19 |
20 | spec:
21 | rules:
22 | - hosts: "DNS ex)yooyoungnam.com" 1번
23 | http: 2번
24 | paths:
25 | - path: / 3번
26 | pathType: Prefix
27 | - backend:
28 | service:
29 | name: istio-ingress 4번
30 | port:
31 | number: 80
32 | ```
33 |
34 | ## Ingress 처리과정
35 | - yooyoungnam.com이라는 호스트 명으로 접근하는 네트워크 요청에 대해서 Ingress 규칙을 적용
36 | - http 프로토콜을 통해 / 라는 경로로 접근하는 요청을 istio-ingress라는 서비스 이름의 80 포트로 전달
37 |
38 | ## 중요한 점
39 | - Ingress만 정의하고 배포한다고 해서 Ingress가 작동하는것이 아니다 위에서 말했듯이 Ingress Controller가 존재해야한다.
40 | - Ingress Controller가 외부로부터 네트워크 요청을 수신했을 때, Ingress 규칙에 기반해 이 요청을 어떻게 처리할지를 결정
41 |
42 |
43 | ## 생겼던 이슈
44 | - Ingress에서 백엔드 Service name을 잘못 바라보고 있었음 그렇다보니 아무리 접근해도 정상으로 작동안했음
45 | - istio service 네임을 제대로 설정해야한다. label 확인 필요
46 |
47 | ## Flow
48 | 
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/troubleshooting/Kiali/README.md:
--------------------------------------------------------------------------------
1 | ## Istio 모니터링을 위한 Kiali 설치하기
2 | 
3 |
4 | - istio를 설치하게 되면 istio 폴더 내에 addon에 kiali가 있는것을 확인할 수 있다. addon에 있는 Kiali를 설치하게 되면 yaml에 설정되어 있는대로 설치가 진행된다.
5 | - 아마도 istio-system 네임스페이스에 설치가 될것이고 promethues역시 설치해야하기 때문에 prometheus도 마찬가지로 istio-system에 설치가 될것이다.
6 | - 근데 나는 이것을 이용햇 우리가 구축한 monitoring이라는 네임스페이스에 따로 설치하고 싶은데 그대로 사용하면 안될거 같아서 yaml내부를 보았다.
7 | - 일단 시도했던 방법은 istio-system네임스페이스로 설정되어 있는 부분들을 monitoring으로 변경했는데 하나씩 자세히 봐야한다. 배포하더라도 전혀 동작하지 않는다.
8 |
9 | 
10 |
11 | 첫 번째 이슈는 이부분에서 잘못 설정을 해서 배포하고도 Kiali가 제대로 동작하지 않았다. 찾아보니까 Kiali는 istio resource와 관련된 루트 네임스페이스를 사용한다. 그래서 kiali를 제대로 동작하게 하려면 istio의 root namespace를 구성한곳에
12 | 지정해야 한다는 것이다. 즉 istio를 설치할 때 root namespace를 지정하는 부분이 있는데 그 네임스페이스를 작성해야한다는 것
13 |
14 | 
15 |
16 | 두 번째 이슈는 더이상 kiali에서 istio관련 에러는 나오지가 않았으나, prometheus 에러는 여전히 남아있었다. kiali를 설치할 때 prometheus를 따로 지정하지않으면 prometheus 서비스 디스커버리 주소를 istio-system으로 잡는다.
17 | 그래서 문서를 찾아보니까 prometheus.istio-system:9090으로 되어있는 것을 확인했다. 이부분을 우리 모니터링 네임스페이스에 배포되어 있는 prometheus로 변경해야 한다. 그래야 metrices를 가져올 수 있다.
18 |
19 |
--------------------------------------------------------------------------------
/troubleshooting/Nginx-Proxy/README.md:
--------------------------------------------------------------------------------
1 | ## 클러스터 내에 Nginx Reverse Proxy 구축 경험
2 | - 외부에서 사내 클러스터에 배포된 서비스를 접근해야 하는 로직이 생겼다. 외부에서 사내 클러스터 접근은 단순히 api를 통해서 매번 접근하는 건 어려운 일이다.(인증 서버를 개발하면 되지만, 빠르게 진행해야 하는 일이기 때문)
3 | - 여러가지 방법을 생각했지만, 그중에 가장 괜찮은 방법은 클러스터 내에 하나의 vm을 만드는 것이다. 그래서 외부에서 클러스터 앞단에 nginx Proxy를 두고 클러스터 내에도 nginx proxy를 두는 것이다.
4 |
5 | 
6 |
7 |
8 | ## nginx.conf 간단한 예제
9 | ```agsl
10 | http {
11 | server {
12 | listen 80;
13 | location /install {
14 |
15 | }
16 |
17 | location /delete {
18 |
19 | }
20 |
21 | location /update {
22 |
23 | }
24 | }
25 | }
26 | ```
27 |
28 |
29 |
30 | ## cluster application nginx.conf 간단한 예제
31 | ```agsl
32 | http {
33 | server {
34 | listen 80;
35 | location /api/install {
36 | proxy_pass http:// service-name.namespace.svc.cluster.local/api/install ## 클러스터 내에 배포된 백엔드 파드
37 | }
38 |
39 | location /api/delete {
40 | proxy_pass http:// service-name.namespace.svc.cluster.local/api/delete ## 클러스터 내에 배포된 백엔드 파드
41 | }
42 |
43 | location /api/update {
44 | proxy_pass http:// service-name.namespace.svc.cluster.local/api/update ## 클러스터 내에 배포된 백엔드 파드
45 | }
46 | }
47 | }
48 | ```
49 |
50 | 위 예제는 진짜 간단한 예제고 실제로 해보면 쉽게 구축할 수 있을 것이다. 사실 이방법은 프록시 방화벽을 잘 관리해야 한다는 단점이 있다.
--------------------------------------------------------------------------------
/troubleshooting/Proxy-server/README.md:
--------------------------------------------------------------------------------
1 | # 클러스터 앞단에 Proxy Server를 둔 이유
2 | - 개발환경 클러스터 앞단에 Proxy Server를 둔 이유는 개발환경에 ssl를 적용하면 보통 443 포트만 외부로 노출이된다. 그렇다면 클러스터내에 설치된 개발 tool들은 접근을 할 수 없다.
3 | - 아래 이미지 처럼 443 포트 이외엔 접근할 수 가 없다. 그리고 SSL이 적용 했는데 다른 포트를 노출시킨다는건 이상하다.
4 | 
5 |
6 |
7 |
8 | ## 해결방법
9 | - 그렇다면 어떤식으로 해결할 수 있을까? Proxy Server를 따로 운영해서 개발자들에게 접근할 수 있게 해주는 방법밖에 없다. 그러면 Proxy Server 생성 위치도 중요하다.Proxy Server 위치는 클러스터 내에 있는 노드와 같은 VPC내에 생성되어야 한다. 그래야지 노드내에 배포된 개발 tool들을 접근할 수 있다.
10 | 
11 | - Proxy 구성은 nginx도 괜찮고 squid proxy도 괜찮다.
12 |
13 |
14 | ## 시도한 방법
15 | - 맨 처음 시도한 방법은 proxy server를 클러스터 노드와 같은 vpc에 생성을 하고 proxy server에서 노드들과 연결할 수 있는지 테스트를 시도했을 때 노드들과 연결은 잘 되는것을 확인했다. 그렇다면 이제 노드 내에 배포된 파드들에게 접근이 가능한지 테스트를 했는데 접근이 잘 되었다.
16 | - 모두다 잘 알고 있겠지만 파드는 일시적이다. 파드가 죽으면 파드 ip는 변경된다. 그렇다면 파드를 프록시를 연결한다면 파드가 죽었다가 살아나거나 배포를 다시하게 된다면 프록시 설정을 계속 변경해줘야 한다는 점이 생긴다. 그러면 서비스를 통해 접근을 해야한다.
17 | - 여기서 놓친게 있었다. service ip는 가상의 ip라는 점이다. veth0 즉 클러스터 내 리소스들과 통신할 수 있는 ip지 외부에서 접근할 수 있는 ip가 아니라는 소리다.
18 | - 그렇다면 어떤식으로 해야할까? 그 다음 시도한 방법이 service type를 NodePort로 노출시킨다면 노드 IP로 접근할 수 있겠네? 했으나 연결이 되지않았다 그렇다면 다른 방식으로 접근해야 하는데 쿠버네티스 파드 옵션중에 hostPort라는 옵션이 존재한다. hostPort 옵션을 사용하게 된다면 특정 노드에 배포된 파드가 node의 network namespace를 공유한다는 것이다.
19 | - 그렇다면 서비스를 건들지 않아도 파드의 호스트 포트로 노출시킨다면 node-ip:port를 통해 접근할 수 있다.
20 |
21 | 
22 |
--------------------------------------------------------------------------------
/troubleshooting/README.md:
--------------------------------------------------------------------------------
1 | ## SSL 적용된 cluster 앞단에 Proxy Server
2 | - [proxy-server](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/Proxy-server)
3 |
4 |
5 | ## 클러스터 내부 Nginx Proxy 구현
6 | - [Nginx-server](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/Nginx-Proxy)
7 |
8 |
9 | ## GCP L7 방화벽 이슈
10 | - [GCP-L7](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/GCP-L7(Load-Balancer))
11 |
12 |
13 | ## Prometheus Kafka Exporter 연결 및 수집
14 | - [prometheus](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/prometheus)
15 |
16 | ## Redis Sentinel 구축
17 | - [redis-sentinel](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/redis-sentinel)
18 |
19 | ## kiali 설치
20 | - [Kiali](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/Kiali)
21 |
22 | ## docker(arm64, amd64) 이슈
23 | - [docker(arm64, amd64)](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/amd64-arm64)
24 |
25 |
26 | ## Nginx Ingress Controller Istio 연결 이슈
27 | - [Ingress](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/Ingress)
28 |
29 | ## istio에서 gRpc 통신 이슈
30 | - [istio-gRpc](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/istio-gRpc)
31 |
32 | ## kubernetes Resource Report SA 설정 이슈로 인한 Error 해결
33 | - [kubernetes-resource-report](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/kubernetes-resource-report)
34 |
35 | ## istio operator install
36 | - [istio-install](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/istio-install)
37 |
--------------------------------------------------------------------------------
/troubleshooting/amd64-arm64/README.md:
--------------------------------------------------------------------------------
1 | # AMD64 와 ARM64 이슈
2 | - docker를 자주 사용하는 사람이라면 또는 kubernetes를 자주 사용하는 사람이라면 가끔 한번씩 등장하는 이슈일 것 이다.
3 | - 나 역시 kubernetes에서 amd64 or arm64 이슈가 생겼었다. 처음 쿠버네티스에서 이슈를 보았을 때 이 문제는 아닐 줄 알았는데 애플리케이션을 올릴 때 initcontainer에서 shell script를 실행시키는 command가 있는데 자세히 보니까 해당 이슈였던 것
4 |
5 | ### 특정 컨테이너 로그 보는법
6 | ```agsl
7 | kubectl logs pod name -c container name
8 | ```
9 | 해당 명령어로 initcontainer에 문제가 있다는것을 알았다.
10 |
11 | ## AMD64과 ARM64는 무엇인가 ?
12 | - 자세하게는 설명을 못하지만 한번 찾아봤다.
13 | - AMD64는 64비트 아키텍처이다. 거의 최신 pc와 서버에서 사용한다고 한다. 이점은 64비트 처리와 메모리 주소 공간을 지원 32비트 시스템보다 높은 메모리 용량과 높은 처리 성능을 제공한다고 한다.
14 | - AMD64 x86-64는 무엇일까? x86 아키텍처의 확장 버전 x86 호환코드와 프로그램을 지원
15 | - x86(IA-32) 32비트 아키텍처로 이전 세대의 pc와 서버에서 사용
16 |
17 | ARM(Advanced RISC Machines)
18 | - 저전력 임베디드 시스템이나 모바일 기기에서 사용
19 | - RISC 아키텍쳐로 명령어 세트가 간결
20 | - ARM 프로세서는 다양한 코어 수와 주파수로 제공 특정 애플리케이션에 적합한 최적의 프로세서를 선택할 수 있다.
21 | - ARM 기반 시스템은 최대 64비트 처리와 메모리 주소를 지원 최신 ARM 프로세서는 높은 처리 성능을 제공
22 | - 주로 대규모 데이터베이스, 웹서버 등등에서 사용
23 |
24 | ### 그러면 무슨 어떤 차이가 있는가?
25 | - amd64 아키텍처와 ARM 아키텍처는 서로 다른 설계 철학을 가지고 있다고 한다.
26 | - AMD64는 고성능 서버와 pc에서 사용하고 대부분 소프트웨어가 이 아키텍처를 지원한다고 함.
27 | - ARM 아키텍처는 대부분 모바일 기기와 임베디드 시스템에서 사용 이 아키텍처는 전력 소모가 적고 단순한 명령어 구조를 가지고 있기 때문 그래서 고성능 작업에는 적합하지 않다.
28 |
29 | ### 이슈
30 | - AMD64 64비트 운영체제 Mac os M1칩은 apple에서 개발함 intel과 다른 ARM CPU라는 점
31 | - amd64 x86_64=x64 = 64비트
32 |
33 | ## 그러면 왜 이게 docker에서나 kubernetes에서나 문제가 생기는거지?
34 | - docker에서는 이미지를 빌드할 때 생길 것이다. 아마도 m1은 arm64기반이라서 ubuntu에서 열리지 않는 것이다.
35 | - m1에서 빌드할 때 amd 기반으로 빌드할 수 있게 docker buildx를 사용하자
36 | ```agsl
37 | # 참고 명령어
38 | docker buildx build --platform linux/adm64 --load -t
39 | ```
40 | ### 다시 돌아와서 왜 문제가 생길까
41 | - 내가 생각했을 때 우리 팀에서는 우리가 사용하는 애플리케이션을 이미지를 tar로 만든다. 해당 이미지는 arm64 아키텍처 기반 이미지로 만들어져서 private registry habor로 이미지가 올라가고
42 | 해당 이미지를 amd64 아키텍처 기반인 os에서 실행시키려고 하니 에러가 났을거라고 생각이 든다. 아니면 그와반대로 amd에서 이미지를 말고 도커를 실행하는 환경에서는 arm 환경이기 때문에 실행이 안된거 같다.
43 | - 쿠버네티스도 컨테이너를 워커노드에서 실행을 시키기 때문에 해당 워커노드가 어떤 아키텍처로 운영되고 있는지 확인을 해야한다.
44 | - 쿠버네티스에서 쉘 스크립트를 실행 시킬 때 에러는 아래 내용이였다.
45 | ```agsl
46 | exec /usr/bin/sh: exec format error
47 | ```
48 | 이것도 역시 쉘 스크립트 문제 일거같지만 같은이유이다. amd기반에서 이미지를 말아서 arm 아키텍처에서 실행하거나 arm 기반에서 이미지를 말아서 amd 아키텍처 기반에서 실행시키거나 둘중 하나일것이다.
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/troubleshooting/istio-gRpc/README.md:
--------------------------------------------------------------------------------
1 | ## Istio에서 gRpc 통신이슈 해결하기
2 |
3 | ### 이슈
4 | - 우리 회사 클러스터 내에는 Spring Gateway Application이 하나가 있는데 이 Gateway를 우리 전사 제품을 통과하는 Gateway이다.
5 | - 문제는 이 gateway뒤에 다른 제품 Spring Gateway를 통과하고 backend Application으로 가는 통신이 있다는 것이다
6 |
7 | 
8 |
9 |
10 | 그림을 간단하게 그려보면 이렇게 flow가 흘러 간다는 것이다. 궁금한 점은 이렇게도 gRpc통신이 가능한것인가? spring Gateway가 gRpc를 통신할 수 있는것인가? 다양하게 궁금했다.
11 |
12 | 일단 개발환경 클러스터에 gRpc관련 Application올리고 테스트를 해봤더니 역시나 통신이 끊겨버렸다. 여기서 가장 먼저 든 생각은 Spring Gateway가 양방향 통신을 할 수 있게 잡아 주지 않을것이다.
13 | 생각을 먼저했다. 그래서 테스트 한 방법이 gRpc 통신 path를 인증을 istio AuthorizationPolicy에서 인증을 통과하게 하지 않고 Spring Gateway 역시 통과하게 하지 않고 바로 gRpc Application으로 통신하게 할 수 있게 만들었다.
14 | 그랬더니 connection은 연결을 성공했다.
15 |
16 |
17 | 문제는 그 다음인데 gRpc통신하는 다른 서비스들은 통신을 하지 못했다. 로그를 확인해보니 http 1.x 잘못된 request 요청이라고 하는 것이다. 즉 pod to pod에서는 gRpc를 통신을 하지 못하고 있었던 것이다.
18 | 다음 해결책은 istio에서 gRpc를 지원하는지도 궁금했다. [Protocol Selection](https://istio.io/latest/docs/ops/configuration/traffic-management/protocol-selection/)문서를 확인해보면 istio sidecar 즉, envoy proxy에서 gRpc를 지원하고 있는거 같다.
19 |
20 | 
21 |
22 | 쿠버네티스 resource service name에 grpc를 지정해도 되고 kubernetes 1.18이상이라면 appProtocol: protocol 지정하면된다. gRpc가 필요한 Application service마다 gRpc 옵션을 넣어주니 해결이 되었다.
23 |
--------------------------------------------------------------------------------
/troubleshooting/istio-gRpc/grpc.service.yaml:
--------------------------------------------------------------------------------
1 | kind: Service
2 | metadata:
3 | name: myservice
4 | spec:
5 | ports:
6 | - port: 9083
7 | appProtocol: grpc
8 | ---
9 | kind: Service
10 | metadata:
11 | name: myservice
12 | spec:
13 | ports:
14 | - name: grpc
15 | port: 9083
16 | ---
17 |
--------------------------------------------------------------------------------
/troubleshooting/istio-install/README.md:
--------------------------------------------------------------------------------
1 | ## istio operator를 통해 istio 설치하기
2 |
3 | - 사내에서도 service mesh로 istio로 사용중인데 아무리 개발환경이 존재해도 istio를 막 테스트하기엔 쉽지않다. 그래서 로컬에 istio를 설치해서 여러가지를 테스트해보려고 생겼던 이슈 였다.
4 |
5 | ## istio operator를 통해서 설치하기
6 | - 개발환경 구성할 때도 istio operator를 통해 설치하긴 했지만, 옵션을 조금 더 보고싶었고 설치중에 테스트해보고 싶은게 있었다.
7 | - 사실 istio label를 수정하고 싶었는데 아무리 istio operator를 수정하고 설치해도 내가 원하는 label로 설치되지 않았다.
8 | - 그래서 공식문서에 나와있는 yaml를 참고해서 설치하지 않고 istio 내에 있는 profiles 폴더내에 있는 yaml를 통해서 label를 수정하고 설치하니 내가 원하는 label로 설치되었다.
9 |
10 |
11 | ```agsl
12 | apiVersion: install.istio.io/v1alpha1
13 | kind: IstioOperator
14 | spec:
15 | meshConfig:
16 | accessLogFile: /dev/stdout
17 | extensionProviders:
18 | - name: otel
19 | envoyOtelAls:
20 | service: opentelemetry-collector.istio-system.svc.cluster.local
21 | port: 4317
22 | - name: skywalking
23 | skywalking:
24 | service: tracing.istio-system.svc.cluster.local
25 | port: 11800
26 | - name: otel-tracing
27 | opentelemetry:
28 | port: 4317
29 | service: opentelemetry-collector.otel-collector.svc.cluster.local
30 | components:
31 | egressGateways:
32 | - name: istio-egressgateway
33 | enabled: true
34 | k8s:
35 | resources:
36 | requests:
37 | cpu: 10m
38 | memory: 40Mi
39 |
40 | ingressGateways:
41 | - name: istio-ingressgateway
42 | label:
43 | istio: gateway-local # istio svc istio label 수정하기
44 | enabled: true
45 | k8s:
46 | resources:
47 | requests:
48 | cpu: 10m
49 | memory: 40Mi
50 | service:
51 | ports:
52 | - port: 15021
53 | targetPort: 15021
54 | name: status-port
55 | - port: 80
56 | targetPort: 8080
57 | name: http2
58 | - port: 443
59 | targetPort: 8443
60 | name: https
61 | - port: 31400
62 | targetPort: 31400
63 | name: tcp
64 | - port: 15443
65 | targetPort: 15443
66 | name: tls
67 |
68 | pilot:
69 | k8s:
70 | env:
71 | - name: PILOT_TRACE_SAMPLING
72 | value: "100"
73 | resources:
74 | requests:
75 | cpu: 10m
76 | memory: 100Mi
77 |
78 | values:
79 | global:
80 | proxy:
81 | resources:
82 | requests:
83 | cpu: 10m
84 | memory: 40Mi
85 |
86 | pilot:
87 | autoscaleEnabled: false
88 |
89 | gateways:
90 | istio-egressgateway:
91 | autoscaleEnabled: false
92 | istio-ingressgateway:
93 | autoscaleEnabled: false
94 | ```
--------------------------------------------------------------------------------
/troubleshooting/kubernetes-resource-report/README.md:
--------------------------------------------------------------------------------
1 | ## Kubernetes Resource Report
2 | - kubernetes cluster 내에 application에 대한 resource requests and usage를 report로 보여주는 tool이다.
3 | - 해당 프로젝트의 목표는 kubernetes 리소스 요청을 최적화하는게 목표다.
4 | - 여기서 Slack이라는 단어가 사용되는데 slack은 application resource requests 과 실제 resource 차이이다.
5 | - 예를들어 특정 Application requests memory가 2GiB를 요청중이고 실제 운영할 때 사용중인 memory가 200MiB만 사용하고 있으면
6 | 여유분이 1.8GiB가 발생하게 된다. 그러면 해당 메모리 용량이 사용하고 있지 않지만 비용은 나가고 있다는 것
7 |
8 |
9 | ## install 이슈
10 | - 해당 application를 클러스터 내에 배포하고 port-foward를 통해 접속하게 되면 아래 처럼 Error가 나타나는걸 볼 수 있다.
11 | ```agsl
12 | Not able to setup kube-resource-report in my k8s env and getting 403 Client Error Forbidden for url
13 | ```
14 | 찾아보니까 해당 application을 배포할 때 rbac역시 같이 배포하게 되는데 serviceAccount 배포되는 곳이 default로 설정되어 있어서 특정 네임스페이스에 배포할 때 권한이 없어 정보를 못가져오는 이슈이다.
15 | 즉, serviceAccount를 올바른 곳에 배포하지 않아서 생기는 이슈였다. 나는 monitoring namespace에 배포해야하는데 ServiceAccount혼자 default에 배포되어 문제가 생긴것 그냥 rbac.yaml에 namespace만
16 | 설치가 원하는 곳으로 변경만 해주면 쉽게 해결할 수 있다.
17 |
--------------------------------------------------------------------------------
/troubleshooting/prometheus/README.md:
--------------------------------------------------------------------------------
1 | ## Prometheus + Grafana를 운영하기 시작한 이유
2 | - 우리 회사의 모든 서비스는 쿠버네티스위에서 동작하고 있다. 모든 서비스를 쿠버네티스 위에서 운영하다보니, 다른팀에서 만든 애플리케이션 모니터링할 수 있는 방법이 따로 없었다.
3 | - 다른 팀에서 빠르게 모니터링(서버 로그를 볼 수 있는정도) 할 수 있는 방법이 팀마다 클러스터에 접근할 수 있게 하고 [workload-Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity?hl=ko)를 부여 후 제품이 배포되어 있는 네임스페이스에만 권한을 주는 것이다. 즉 로그만 볼 수 있는게 만들었다.
4 | - 이부분에도 단점이 존재했다. 사내 모든 팀들에게 클러스터를 접근하게 만든것도 문제고 모든 팀에게 workload identity를 만들어야하는 이슈가 존재했다.
5 | - 사실, 팀마다 Service Account IAM은 클러스터 뷰어권한밖에 없지만, 보안상 문제가 있을거라 생각했다.
6 |
7 |
8 | ## 모니터링 도구 Prometheus + Grafana
9 | - prometheus를 따로 설치하고 쿠버네티스를 연결하는것도 하나의 방법이지만, 모든 사내 애플리케이션이 쿠버네티스 위에서 동작하고 있고 설치도 빠르게 할 수 있기 때문에 쿠버네티스 클러스터 위에 배포했다.
10 |
11 | ## Prometheus 설치 및 이슈
12 | - 처음에 helm Chart를 통해서 prometheus를 설치해보면 알겠지만, 기본적인 것들만 수집을 하고있다는것을 볼 수 있다. 우리는 service mash를 istio를 선택하고 사용중인데, istio에 대한 메트릭은 전혀 수집을 하고 있지 않았다.
13 | - kafka 역시 메트릭을 수집하려면 exporter 배포하고 prometheus에 연결해야 하는 이슈가 존재했다.
14 |
15 |
16 | ## 해결법
17 | - [chart](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/prometheus/chart.yaml)
18 | - [kafka-exporter](https://github.com/youyoungnam/kubernetes-implement/tree/main/troubleshooting/prometheus/kafka-exporter.sh)
--------------------------------------------------------------------------------
/troubleshooting/prometheus/chart.yaml:
--------------------------------------------------------------------------------
1 | rbac:
2 | create: true
3 |
4 | podSecurityPolicy:
5 | enabled: false
6 |
7 | imagePullSecrets: []
8 | # - name: "image-pull-secret"
9 |
10 | ## Define serviceAccount names for components. Defaults to component's fully qualified name.
11 | ##
12 | serviceAccounts:
13 | server:
14 | create: true
15 | name: ""
16 | annotations: {}
17 |
18 | ## Monitors ConfigMap changes and POSTs to a URL
19 | ## Ref: https://github.com/prometheus-operator/prometheus-operator/tree/main/cmd/prometheus-config-reloader
20 | ##
21 | configmapReload:
22 | ## URL for configmap-reload to use for reloads
23 | ##
24 | reloadUrl: ""
25 |
26 | ## env sets environment variables to pass to the container. Can be set as name/value pairs,
27 | ## read from secrets or configmaps.
28 | env: []
29 | # - name: SOMEVAR
30 | # value: somevalue
31 | # - name: PASSWORD
32 | # valueFrom:
33 | # secretKeyRef:
34 | # name: mysecret
35 | # key: password
36 | # optional: false
37 |
38 | prometheus:
39 | ## If false, the configmap-reload container will not be deployed
40 | ##
41 | enabled: true
42 |
43 | ## configmap-reload container name
44 | ##
45 | name: configmap-reload
46 |
47 | ## configmap-reload container image
48 | ##
49 | image:
50 | repository: quay.io/prometheus-operator/prometheus-config-reloader
51 | tag: v0.66.0
52 | # When digest is set to a non-empty value, images will be pulled by digest (regardless of tag value).
53 | digest: ""
54 | pullPolicy: IfNotPresent
55 |
56 | # containerPort: 9533
57 |
58 | ## Additional configmap-reload container arguments
59 | ##
60 | extraArgs: {}
61 |
62 | ## Additional configmap-reload volume directories
63 | ##
64 | extraVolumeDirs: []
65 |
66 | ## Additional configmap-reload volume mounts
67 | ##
68 | extraVolumeMounts: []
69 |
70 | ## Additional configmap-reload mounts
71 | ##
72 | extraConfigmapMounts: []
73 | # - name: prometheus-alerts
74 | # mountPath: /etc/alerts.d
75 | # subPath: ""
76 | # configMap: prometheus-alerts
77 | # readOnly: true
78 |
79 | ## Security context to be added to configmap-reload container
80 | containerSecurityContext: {}
81 |
82 | ## configmap-reload resource requests and limits
83 | ## Ref: http://kubernetes.io/docs/user-guide/compute-resources/
84 | ##
85 | resources: {}
86 |
87 | server:
88 | ## Prometheus server container name
89 | ##
90 | name: server
91 |
92 | ## Use a ClusterRole (and ClusterRoleBinding)
93 | ## - If set to false - we define a RoleBinding in the defined namespaces ONLY
94 | ##
95 | ## NB: because we need a Role with nonResourceURL's ("/metrics") - you must get someone with Cluster-admin privileges to define this role for you, before running with this setting enabled.
96 | ## This makes prometheus work - for users who do not have ClusterAdmin privs, but wants prometheus to operate on their own namespaces, instead of clusterwide.
97 | ##
98 | ## You MUST also set namespaces to the ones you have access to and want monitored by Prometheus.
99 | ##
100 | # useExistingClusterRoleName: nameofclusterrole
101 |
102 | ## If set it will override prometheus.server.fullname value for ClusterRole and ClusterRoleBinding
103 | ##
104 | clusterRoleNameOverride: ""
105 |
106 | ## namespaces to monitor (instead of monitoring all - clusterwide). Needed if you want to run without Cluster-admin privileges.
107 | # namespaces:
108 | # - yournamespace
109 |
110 | # sidecarContainers - add more containers to prometheus server
111 | # Key/Value where Key is the sidecar `- name: `
112 | # Example:
113 | # sidecarContainers:
114 | # webserver:
115 | # image: nginx
116 | sidecarContainers: {}
117 |
118 | # sidecarTemplateValues - context to be used in template for sidecarContainers
119 | # Example:
120 | # sidecarTemplateValues: *your-custom-globals
121 | # sidecarContainers:
122 | # webserver: |-
123 | # {{ include "webserver-container-template" . }}
124 | # Template for `webserver-container-template` might looks like this:
125 | # image: "{{ .Values.server.sidecarTemplateValues.repository }}:{{ .Values.server.sidecarTemplateValues.tag }}"
126 | # ...
127 | #
128 | sidecarTemplateValues: {}
129 |
130 | ## Prometheus server container image
131 | ##
132 | image:
133 | repository: quay.io/prometheus/prometheus
134 | # if not set appVersion field from Chart.yaml is used
135 | tag: ""
136 | # When digest is set to a non-empty value, images will be pulled by digest (regardless of tag value).
137 | digest: ""
138 | pullPolicy: IfNotPresent
139 |
140 | ## Prometheus server command
141 | ##
142 | command: []
143 |
144 | ## prometheus server priorityClassName
145 | ##
146 | priorityClassName: ""
147 |
148 | ## EnableServiceLinks indicates whether information about services should be injected
149 | ## into pod's environment variables, matching the syntax of Docker links.
150 | ## WARNING: the field is unsupported and will be skipped in K8s prior to v1.13.0.
151 | ##
152 | enableServiceLinks: true
153 |
154 | ## The URL prefix at which the container can be accessed. Useful in the case the '-web.external-url' includes a slug
155 | ## so that the various internal URLs are still able to access as they are in the default case.
156 | ## (Optional)
157 | prefixURL: ""
158 |
159 | ## External URL which can access prometheus
160 | ## Maybe same with Ingress host name
161 | baseURL: ""
162 |
163 | ## Additional server container environment variables
164 | ##
165 | ## You specify this manually like you would a raw deployment manifest.
166 | ## This means you can bind in environment variables from secrets.
167 | ##
168 | ## e.g. static environment variable:
169 | ## - name: DEMO_GREETING
170 | ## value: "Hello from the environment"
171 | ##
172 | ## e.g. secret environment variable:
173 | ## - name: USERNAME
174 | ## valueFrom:
175 | ## secretKeyRef:
176 | ## name: mysecret
177 | ## key: username
178 | env: []
179 |
180 | # List of flags to override default parameters, e.g:
181 | # - --enable-feature=agent
182 | # - --storage.agent.retention.max-time=30m
183 | defaultFlagsOverride: []
184 |
185 | extraFlags:
186 | - web.enable-lifecycle
187 | ## web.enable-admin-api flag controls access to the administrative HTTP API which includes functionality such as
188 | ## deleting time series. This is disabled by default.
189 | # - web.enable-admin-api
190 | ##
191 | ## storage.tsdb.no-lockfile flag controls BD locking
192 | # - storage.tsdb.no-lockfile
193 | ##
194 | ## storage.tsdb.wal-compression flag enables compression of the write-ahead log (WAL)
195 | # - storage.tsdb.wal-compression
196 |
197 | ## Path to a configuration file on prometheus server container FS
198 | configPath: /etc/config/prometheus.yml
199 |
200 | ### The data directory used by prometheus to set --storage.tsdb.path
201 | ### When empty server.persistentVolume.mountPath is used instead
202 | storagePath: ""
203 |
204 | global:
205 | ## How frequently to scrape targets by default
206 | ##
207 | scrape_interval: 1m
208 | ## How long until a scrape request times out
209 | ##
210 | scrape_timeout: 10s
211 | ## How frequently to evaluate rules
212 | ##
213 | evaluation_interval: 1m
214 | ## https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write
215 | ##
216 | remoteWrite: []
217 | ## https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_read
218 | ##
219 | remoteRead: []
220 |
221 | ## https://prometheus.io/docs/prometheus/latest/configuration/configuration/#tsdb
222 | ##
223 | tsdb: {}
224 | # out_of_order_time_window: 0s
225 |
226 | ## https://prometheus.io/docs/prometheus/latest/configuration/configuration/#exemplars
227 | ## Must be enabled via --enable-feature=exemplar-storage
228 | ##
229 | exemplars: {}
230 | # max_exemplars: 100000
231 |
232 | ## Custom HTTP headers for Liveness/Readiness/Startup Probe
233 | ##
234 | ## Useful for providing HTTP Basic Auth to healthchecks
235 | probeHeaders: []
236 | # - name: "Authorization"
237 | # value: "Bearer ABCDEabcde12345"
238 |
239 | ## Additional Prometheus server container arguments
240 | ##
241 | extraArgs: {}
242 |
243 | ## Additional InitContainers to initialize the pod
244 | ##
245 | extraInitContainers: []
246 |
247 | ## Additional Prometheus server Volume mounts
248 | ##
249 | extraVolumeMounts: []
250 |
251 | ## Additional Prometheus server Volumes
252 | ##
253 | extraVolumes: []
254 |
255 | ## Additional Prometheus server hostPath mounts
256 | ##
257 | extraHostPathMounts: []
258 | # - name: certs-dir
259 | # mountPath: /etc/kubernetes/certs
260 | # subPath: ""
261 | # hostPath: /etc/kubernetes/certs
262 | # readOnly: true
263 |
264 | extraConfigmapMounts: []
265 | # - name: certs-configmap
266 | # mountPath: /prometheus
267 | # subPath: ""
268 | # configMap: certs-configmap
269 | # readOnly: true
270 |
271 | ## Additional Prometheus server Secret mounts
272 | # Defines additional mounts with secrets. Secrets must be manually created in the namespace.
273 | extraSecretMounts: []
274 | # - name: secret-files
275 | # mountPath: /etc/secrets
276 | # subPath: ""
277 | # secretName: prom-secret-files
278 | # readOnly: true
279 |
280 | ## ConfigMap override where fullname is {{.Release.Name}}-{{.Values.server.configMapOverrideName}}
281 | ## Defining configMapOverrideName will cause templates/server-configmap.yaml
282 | ## to NOT generate a ConfigMap resource
283 | ##
284 | configMapOverrideName: ""
285 |
286 | ## Extra labels for Prometheus server ConfigMap (ConfigMap that holds serverFiles)
287 | extraConfigmapLabels: {}
288 |
289 | ingress:
290 | ## If true, Prometheus server Ingress will be created
291 | ##
292 | enabled: false
293 |
294 | # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
295 | # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
296 | # ingressClassName: nginx
297 |
298 | ## Prometheus server Ingress annotations
299 | ##
300 | annotations: {}
301 | # kubernetes.io/ingress.class: nginx
302 | # kubernetes.io/tls-acme: 'true'
303 |
304 | ## Prometheus server Ingress additional labels
305 | ##
306 | extraLabels: {}
307 |
308 | ## Prometheus server Ingress hostnames with optional path
309 | ## Must be provided if Ingress is enabled
310 | ##
311 | hosts: []
312 | # - prometheus.domain.com
313 | # - domain.com/prometheus
314 |
315 | path: /
316 |
317 | # pathType is only for k8s >= 1.18
318 | pathType: Prefix
319 |
320 | ## Extra paths to prepend to every host configuration. This is useful when working with annotation based services.
321 | extraPaths: []
322 | # - path: /*
323 | # backend:
324 | # serviceName: ssl-redirect
325 | # servicePort: use-annotation
326 |
327 | ## Prometheus server Ingress TLS configuration
328 | ## Secrets must be manually created in the namespace
329 | ##
330 | tls: []
331 | # - secretName: prometheus-server-tls
332 | # hosts:
333 | # - prometheus.domain.com
334 |
335 | ## Server Deployment Strategy type
336 | strategy:
337 | type: Recreate
338 |
339 | ## hostAliases allows adding entries to /etc/hosts inside the containers
340 | hostAliases: []
341 | # - ip: "127.0.0.1"
342 | # hostnames:
343 | # - "example.com"
344 |
345 | ## Node tolerations for server scheduling to nodes with taints
346 | ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
347 | ##
348 | tolerations: []
349 | # - key: "key"
350 | # operator: "Equal|Exists"
351 | # value: "value"
352 | # effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)"
353 |
354 | ## Node labels for Prometheus server pod assignment
355 | ## Ref: https://kubernetes.io/docs/user-guide/node-selection/
356 | ##
357 | nodeSelector: {}
358 |
359 | ## Pod affinity
360 | ##
361 | affinity: {}
362 |
363 | ## Pod topology spread constraints
364 | ## ref. https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/
365 | topologySpreadConstraints: []
366 |
367 | ## PodDisruptionBudget settings
368 | ## ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/
369 | ##
370 | podDisruptionBudget:
371 | enabled: false
372 | maxUnavailable: 1
373 |
374 | ## Use an alternate scheduler, e.g. "stork".
375 | ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
376 | ##
377 | # schedulerName:
378 |
379 | persistentVolume:
380 | ## If true, Prometheus server will create/use a Persistent Volume Claim
381 | ## If false, use emptyDir
382 | ##
383 | enabled: true
384 |
385 | ## If set it will override the name of the created persistent volume claim
386 | ## generated by the stateful set.
387 | ##
388 | statefulSetNameOverride: ""
389 |
390 | ## Prometheus server data Persistent Volume access modes
391 | ## Must match those of existing PV or dynamic provisioner
392 | ## Ref: http://kubernetes.io/docs/user-guide/persistent-volumes/
393 | ##
394 | accessModes:
395 | - ReadWriteOnce
396 |
397 | ## Prometheus server data Persistent Volume labels
398 | ##
399 | labels: {}
400 |
401 | ## Prometheus server data Persistent Volume annotations
402 | ##
403 | annotations: {}
404 |
405 | ## Prometheus server data Persistent Volume existing claim name
406 | ## Requires server.persistentVolume.enabled: true
407 | ## If defined, PVC must be created manually before volume will be bound
408 | existingClaim: ""
409 |
410 | ## Prometheus server data Persistent Volume mount root path
411 | ##
412 | mountPath: /data
413 |
414 | ## Prometheus server data Persistent Volume size
415 | ##
416 | size: 8Gi
417 |
418 | ## Prometheus server data Persistent Volume Storage Class
419 | ## If defined, storageClassName:
420 | ## If set to "-", storageClassName: "", which disables dynamic provisioning
421 | ## If undefined (the default) or set to null, no storageClassName spec is
422 | ## set, choosing the default provisioner. (gp2 on AWS, standard on
423 | ## GKE, AWS & OpenStack)
424 | ##
425 | # storageClass: "-"
426 |
427 | ## Prometheus server data Persistent Volume Binding Mode
428 | ## If defined, volumeBindingMode:
429 | ## If undefined (the default) or set to null, no volumeBindingMode spec is
430 | ## set, choosing the default mode.
431 | ##
432 | # volumeBindingMode: ""
433 |
434 | ## Subdirectory of Prometheus server data Persistent Volume to mount
435 | ## Useful if the volume's root directory is not empty
436 | ##
437 | subPath: ""
438 |
439 | ## Persistent Volume Claim Selector
440 | ## Useful if Persistent Volumes have been provisioned in advance
441 | ## Ref: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#selector
442 | ##
443 | # selector:
444 | # matchLabels:
445 | # release: "stable"
446 | # matchExpressions:
447 | # - { key: environment, operator: In, values: [ dev ] }
448 |
449 | ## Persistent Volume Name
450 | ## Useful if Persistent Volumes have been provisioned in advance and you want to use a specific one
451 | ##
452 | # volumeName: ""
453 |
454 | emptyDir:
455 | ## Prometheus server emptyDir volume size limit
456 | ##
457 | sizeLimit: ""
458 |
459 | ## Annotations to be added to Prometheus server pods
460 | ##
461 | podAnnotations: {}
462 | # iam.amazonaws.com/role: prometheus
463 |
464 | ## Labels to be added to Prometheus server pods
465 | ##
466 | podLabels: {}
467 |
468 | ## Prometheus AlertManager configuration
469 | ##
470 | alertmanagers: []
471 |
472 | ## Specify if a Pod Security Policy for node-exporter must be created
473 | ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/
474 | ##
475 | podSecurityPolicy:
476 | annotations: {}
477 | ## Specify pod annotations
478 | ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#apparmor
479 | ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp
480 | ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#sysctl
481 | ##
482 | # seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
483 | # seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default'
484 | # apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default'
485 |
486 | ## Use a StatefulSet if replicaCount needs to be greater than 1 (see below)
487 | ##
488 | replicaCount: 1
489 |
490 | ## Annotations to be added to deployment
491 | ##
492 | deploymentAnnotations: {}
493 |
494 | statefulSet:
495 | ## If true, use a statefulset instead of a deployment for pod management.
496 | ## This allows to scale replicas to more than 1 pod
497 | ##
498 | enabled: false
499 |
500 | annotations: {}
501 | labels: {}
502 | podManagementPolicy: OrderedReady
503 |
504 | ## Alertmanager headless service to use for the statefulset
505 | ##
506 | headless:
507 | annotations: {}
508 | labels: {}
509 | servicePort: 80
510 | ## Enable gRPC port on service to allow auto discovery with thanos-querier
511 | gRPC:
512 | enabled: false
513 | servicePort: 10901
514 | # nodePort: 10901
515 |
516 | ## Prometheus server readiness and liveness probe initial delay and timeout
517 | ## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
518 | ##
519 | tcpSocketProbeEnabled: false
520 | probeScheme: HTTP
521 | readinessProbeInitialDelay: 30
522 | readinessProbePeriodSeconds: 5
523 | readinessProbeTimeout: 4
524 | readinessProbeFailureThreshold: 3
525 | readinessProbeSuccessThreshold: 1
526 | livenessProbeInitialDelay: 30
527 | livenessProbePeriodSeconds: 15
528 | livenessProbeTimeout: 10
529 | livenessProbeFailureThreshold: 3
530 | livenessProbeSuccessThreshold: 1
531 | startupProbe:
532 | enabled: false
533 | periodSeconds: 5
534 | failureThreshold: 30
535 | timeoutSeconds: 10
536 |
537 | ## Prometheus server resource requests and limits
538 | ## Ref: http://kubernetes.io/docs/user-guide/compute-resources/
539 | ##
540 | resources: {}
541 | # limits:
542 | # cpu: 500m
543 | # memory: 512Mi
544 | # requests:
545 | # cpu: 500m
546 | # memory: 512Mi
547 |
548 | # Required for use in managed kubernetes clusters (such as AWS EKS) with custom CNI (such as calico),
549 | # because control-plane managed by AWS cannot communicate with pods' IP CIDR and admission webhooks are not working
550 | ##
551 | hostNetwork: false
552 |
553 | # When hostNetwork is enabled, this will set to ClusterFirstWithHostNet automatically
554 | dnsPolicy: ClusterFirst
555 |
556 | # Use hostPort
557 | # hostPort: 9090
558 |
559 | ## Vertical Pod Autoscaler config
560 | ## Ref: https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler
561 | verticalAutoscaler:
562 | ## If true a VPA object will be created for the controller (either StatefulSet or Deployemnt, based on above configs)
563 | enabled: false
564 | # updateMode: "Auto"
565 | # containerPolicies:
566 | # - containerName: 'prometheus-server'
567 |
568 | # Custom DNS configuration to be added to prometheus server pods
569 | dnsConfig: {}
570 | # nameservers:
571 | # - 1.2.3.4
572 | # searches:
573 | # - ns1.svc.cluster-domain.example
574 | # - my.dns.search.suffix
575 | # options:
576 | # - name: ndots
577 | # value: "2"
578 | # - name: edns0
579 |
580 | ## Security context to be added to server pods
581 | ##
582 | securityContext:
583 | runAsUser: 65534
584 | runAsNonRoot: true
585 | runAsGroup: 65534
586 | fsGroup: 65534
587 |
588 | ## Security context to be added to server container
589 | ##
590 | containerSecurityContext: {}
591 |
592 | service:
593 | ## If false, no Service will be created for the Prometheus server
594 | ##
595 | enabled: true
596 |
597 | annotations: {}
598 | labels: {}
599 | clusterIP: ""
600 |
601 | ## List of IP addresses at which the Prometheus server service is available
602 | ## Ref: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips
603 | ##
604 | externalIPs: []
605 |
606 | loadBalancerIP: ""
607 | loadBalancerSourceRanges: []
608 | servicePort: 80
609 | sessionAffinity: None
610 | type: ClusterIP
611 |
612 | ## Enable gRPC port on service to allow auto discovery with thanos-querier
613 | gRPC:
614 | enabled: false
615 | servicePort: 10901
616 | # nodePort: 10901
617 |
618 | ## If using a statefulSet (statefulSet.enabled=true), configure the
619 | ## service to connect to a specific replica to have a consistent view
620 | ## of the data.
621 | statefulsetReplica:
622 | enabled: false
623 | replica: 0
624 |
625 | ## Prometheus server pod termination grace period
626 | ##
627 | terminationGracePeriodSeconds: 300
628 |
629 | ## Prometheus data retention period (default if not specified is 15 days)
630 | ##
631 | retention: "15d"
632 |
633 | ## Prometheus server ConfigMap entries for rule files (allow prometheus labels interpolation)
634 | ruleFiles: {}
635 |
636 | ## Prometheus server ConfigMap entries
637 | ##
638 | serverFiles:
639 | ## Alerts configuration
640 | ## Ref: https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/
641 | alerting_rules.yml: {}
642 | # groups:
643 | # - name: Instances
644 | # rules:
645 | # - alert: InstanceDown
646 | # expr: up == 0
647 | # for: 5m
648 | # labels:
649 | # severity: page
650 | # annotations:
651 | # description: '{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes.'
652 | # summary: 'Instance {{ $labels.instance }} down'
653 | ## DEPRECATED DEFAULT VALUE, unless explicitly naming your files, please use alerting_rules.yml
654 | alerts: {}
655 |
656 | ## Records configuration
657 | ## Ref: https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/
658 | recording_rules.yml: {}
659 | ## DEPRECATED DEFAULT VALUE, unless explicitly naming your files, please use recording_rules.yml
660 | rules: {}
661 |
662 | prometheus.yml:
663 | rule_files:
664 | - /etc/config/recording_rules.yml
665 | - /etc/config/alerting_rules.yml
666 | ## Below two files are DEPRECATED will be removed from this default values file
667 | - /etc/config/rules
668 | - /etc/config/alerts
669 |
670 | scrape_configs:
671 | - job_name: prometheus
672 | static_configs:
673 | - targets:
674 | - localhost:9090
675 |
676 | # A scrape configuration for running Prometheus on a Kubernetes cluster.
677 | # This uses separate scrape configs for cluster components (i.e. API server, node)
678 | # and services to allow each to use different authentication configs.
679 | #
680 | # Kubernetes labels will be added as Prometheus labels on metrics via the
681 | # `labelmap` relabeling action.
682 |
683 | # Scrape config for API servers.
684 | #
685 | # Kubernetes exposes API servers as endpoints to the default/kubernetes
686 | # service so this uses `endpoints` role and uses relabelling to only keep
687 | # the endpoints associated with the default/kubernetes service using the
688 | # default named port `https`. This works for single API server deployments as
689 | # well as HA API server deployments.
690 | - job_name: 'kubernetes-apiservers'
691 |
692 | kubernetes_sd_configs:
693 | - role: endpoints
694 |
695 | # Default to scraping over https. If required, just disable this or change to
696 | # `http`.
697 | scheme: https
698 |
699 | # This TLS & bearer token file config is used to connect to the actual scrape
700 | # endpoints for cluster components. This is separate to discovery auth
701 | # configuration because discovery & scraping are two separate concerns in
702 | # Prometheus. The discovery auth config is automatic if Prometheus runs inside
703 | # the cluster. Otherwise, more config options have to be provided within the
704 | # .
705 | tls_config:
706 | ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
707 | # If your node certificates are self-signed or use a different CA to the
708 | # master CA, then disable certificate verification below. Note that
709 | # certificate verification is an integral part of a secure infrastructure
710 | # so this should only be disabled in a controlled environment. You can
711 | # disable certificate verification by uncommenting the line below.
712 | #
713 | insecure_skip_verify: true
714 | bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
715 |
716 | # Keep only the default/kubernetes service endpoints for the https port. This
717 | # will add targets for each API server which Kubernetes adds an endpoint to
718 | # the default/kubernetes service.
719 | relabel_configs:
720 | - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
721 | action: keep
722 | regex: default;kubernetes;https
723 |
724 | - job_name: 'kubernetes-nodes'
725 |
726 | # Default to scraping over https. If required, just disable this or change to
727 | # `http`.
728 | scheme: https
729 |
730 | # This TLS & bearer token file config is used to connect to the actual scrape
731 | # endpoints for cluster components. This is separate to discovery auth
732 | # configuration because discovery & scraping are two separate concerns in
733 | # Prometheus. The discovery auth config is automatic if Prometheus runs inside
734 | # the cluster. Otherwise, more config options have to be provided within the
735 | # .
736 | tls_config:
737 | ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
738 | # If your node certificates are self-signed or use a different CA to the
739 | # master CA, then disable certificate verification below. Note that
740 | # certificate verification is an integral part of a secure infrastructure
741 | # so this should only be disabled in a controlled environment. You can
742 | # disable certificate verification by uncommenting the line below.
743 | #
744 | insecure_skip_verify: true
745 | bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
746 |
747 | kubernetes_sd_configs:
748 | - role: node
749 |
750 | relabel_configs:
751 | - action: labelmap
752 | regex: __meta_kubernetes_node_label_(.+)
753 | - target_label: __address__
754 | replacement: kubernetes.default.svc:443
755 | - source_labels: [__meta_kubernetes_node_name]
756 | regex: (.+)
757 | target_label: __metrics_path__
758 | replacement: /api/v1/nodes/$1/proxy/metrics
759 |
760 |
761 | - job_name: 'kubernetes-nodes-cadvisor'
762 |
763 | # Default to scraping over https. If required, just disable this or change to
764 | # `http`.
765 | scheme: https
766 |
767 | # This TLS & bearer token file config is used to connect to the actual scrape
768 | # endpoints for cluster components. This is separate to discovery auth
769 | # configuration because discovery & scraping are two separate concerns in
770 | # Prometheus. The discovery auth config is automatic if Prometheus runs inside
771 | # the cluster. Otherwise, more config options have to be provided within the
772 | # .
773 | tls_config:
774 | ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
775 | # If your node certificates are self-signed or use a different CA to the
776 | # master CA, then disable certificate verification below. Note that
777 | # certificate verification is an integral part of a secure infrastructure
778 | # so this should only be disabled in a controlled environment. You can
779 | # disable certificate verification by uncommenting the line below.
780 | #
781 | insecure_skip_verify: true
782 | bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
783 |
784 | kubernetes_sd_configs:
785 | - role: node
786 |
787 | # This configuration will work only on kubelet 1.7.3+
788 | # As the scrape endpoints for cAdvisor have changed
789 | # if you are using older version you need to change the replacement to
790 | # replacement: /api/v1/nodes/$1:4194/proxy/metrics
791 | # more info here https://github.com/coreos/prometheus-operator/issues/633
792 | relabel_configs:
793 | - action: labelmap
794 | regex: __meta_kubernetes_node_label_(.+)
795 | - target_label: __address__
796 | replacement: kubernetes.default.svc:443
797 | - source_labels: [__meta_kubernetes_node_name]
798 | regex: (.+)
799 | target_label: __metrics_path__
800 | replacement: /api/v1/nodes/$1/proxy/metrics/cadvisor
801 |
802 | # Metric relabel configs to apply to samples before ingestion.
803 | # [Metric Relabeling](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs)
804 | # metric_relabel_configs:
805 | # - action: labeldrop
806 | # regex: (kubernetes_io_hostname|failure_domain_beta_kubernetes_io_region|beta_kubernetes_io_os|beta_kubernetes_io_arch|beta_kubernetes_io_instance_type|failure_domain_beta_kubernetes_io_zone)
807 |
808 | # Scrape config for service endpoints.
809 | #
810 | # The relabeling allows the actual service scrape endpoint to be configured
811 | # via the following annotations:
812 | #
813 | # * `prometheus.io/scrape`: Only scrape services that have a value of
814 | # `true`, except if `prometheus.io/scrape-slow` is set to `true` as well.
815 | # * `prometheus.io/scheme`: If the metrics endpoint is secured then you will need
816 | # to set this to `https` & most likely set the `tls_config` of the scrape config.
817 | # * `prometheus.io/path`: If the metrics path is not `/metrics` override this.
818 | # * `prometheus.io/port`: If the metrics are exposed on a different port to the
819 | # service then set this appropriately.
820 | # * `prometheus.io/param_`: If the metrics endpoint uses parameters
821 | # then you can set any parameter
822 | - job_name: 'kubernetes-service-endpoints'
823 | honor_labels: true
824 |
825 | kubernetes_sd_configs:
826 | - role: endpoints
827 |
828 | relabel_configs:
829 | - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
830 | action: keep
831 | regex: true
832 | - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape_slow]
833 | action: drop
834 | regex: true
835 | - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
836 | action: replace
837 | target_label: __scheme__
838 | regex: (https?)
839 | - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
840 | action: replace
841 | target_label: __metrics_path__
842 | regex: (.+)
843 | - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
844 | action: replace
845 | target_label: __address__
846 | regex: (.+?)(?::\d+)?;(\d+)
847 | replacement: $1:$2
848 | - action: labelmap
849 | regex: __meta_kubernetes_service_annotation_prometheus_io_param_(.+)
850 | replacement: __param_$1
851 | - action: labelmap
852 | regex: __meta_kubernetes_service_label_(.+)
853 | - source_labels: [__meta_kubernetes_namespace]
854 | action: replace
855 | target_label: namespace
856 | - source_labels: [__meta_kubernetes_service_name]
857 | action: replace
858 | target_label: service
859 | - source_labels: [__meta_kubernetes_pod_node_name]
860 | action: replace
861 | target_label: node
862 |
863 | # Scrape config for slow service endpoints; same as above, but with a larger
864 | # timeout and a larger interval
865 | #
866 | # The relabeling allows the actual service scrape endpoint to be configured
867 | # via the following annotations:
868 | #
869 | # * `prometheus.io/scrape-slow`: Only scrape services that have a value of `true`
870 | # * `prometheus.io/scheme`: If the metrics endpoint is secured then you will need
871 | # to set this to `https` & most likely set the `tls_config` of the scrape config.
872 | # * `prometheus.io/path`: If the metrics path is not `/metrics` override this.
873 | # * `prometheus.io/port`: If the metrics are exposed on a different port to the
874 | # service then set this appropriately.
875 | # * `prometheus.io/param_`: If the metrics endpoint uses parameters
876 | # then you can set any parameter
877 | - job_name: 'kubernetes-service-endpoints-slow'
878 | honor_labels: true
879 |
880 | scrape_interval: 5m
881 | scrape_timeout: 30s
882 |
883 | kubernetes_sd_configs:
884 | - role: endpoints
885 |
886 | relabel_configs:
887 | - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape_slow]
888 | action: keep
889 | regex: true
890 | - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
891 | action: replace
892 | target_label: __scheme__
893 | regex: (https?)
894 | - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
895 | action: replace
896 | target_label: __metrics_path__
897 | regex: (.+)
898 | - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
899 | action: replace
900 | target_label: __address__
901 | regex: (.+?)(?::\d+)?;(\d+)
902 | replacement: $1:$2
903 | - action: labelmap
904 | regex: __meta_kubernetes_service_annotation_prometheus_io_param_(.+)
905 | replacement: __param_$1
906 | - action: labelmap
907 | regex: __meta_kubernetes_service_label_(.+)
908 | - source_labels: [__meta_kubernetes_namespace]
909 | action: replace
910 | target_label: namespace
911 | - source_labels: [__meta_kubernetes_service_name]
912 | action: replace
913 | target_label: service
914 | - source_labels: [__meta_kubernetes_pod_node_name]
915 | action: replace
916 | target_label: node
917 |
918 | - job_name: 'prometheus-pushgateway'
919 | honor_labels: true
920 |
921 | kubernetes_sd_configs:
922 | - role: service
923 |
924 | relabel_configs:
925 | - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe]
926 | action: keep
927 | regex: pushgateway
928 |
929 | # Example scrape config for probing services via the Blackbox Exporter.
930 | #
931 | # The relabeling allows the actual service scrape endpoint to be configured
932 | # via the following annotations:
933 | #
934 | # * `prometheus.io/probe`: Only probe services that have a value of `true`
935 | - job_name: 'kubernetes-services'
936 | honor_labels: true
937 |
938 | metrics_path: /probe
939 | params:
940 | module: [http_2xx]
941 |
942 | kubernetes_sd_configs:
943 | - role: service
944 |
945 | relabel_configs:
946 | - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe]
947 | action: keep
948 | regex: true
949 | - source_labels: [__address__]
950 | target_label: __param_target
951 | - target_label: __address__
952 | replacement: blackbox
953 | - source_labels: [__param_target]
954 | target_label: instance
955 | - action: labelmap
956 | regex: __meta_kubernetes_service_label_(.+)
957 | - source_labels: [__meta_kubernetes_namespace]
958 | target_label: namespace
959 | - source_labels: [__meta_kubernetes_service_name]
960 | target_label: service
961 |
962 | # Example scrape config for pods
963 | #
964 | # The relabeling allows the actual pod scrape endpoint to be configured via the
965 | # following annotations:
966 | #
967 | # * `prometheus.io/scrape`: Only scrape pods that have a value of `true`,
968 | # except if `prometheus.io/scrape-slow` is set to `true` as well.
969 | # * `prometheus.io/scheme`: If the metrics endpoint is secured then you will need
970 | # to set this to `https` & most likely set the `tls_config` of the scrape config.
971 | # * `prometheus.io/path`: If the metrics path is not `/metrics` override this.
972 | # * `prometheus.io/port`: Scrape the pod on the indicated port instead of the default of `9102`.
973 | - job_name: 'kubernetes-pods'
974 | honor_labels: true
975 |
976 | kubernetes_sd_configs:
977 | - role: pod
978 |
979 | relabel_configs:
980 | - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
981 | action: keep
982 | regex: true
983 | - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape_slow]
984 | action: drop
985 | regex: true
986 | - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme]
987 | action: replace
988 | regex: (https?)
989 | target_label: __scheme__
990 | - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
991 | action: replace
992 | target_label: __metrics_path__
993 | regex: (.+)
994 | - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port, __meta_kubernetes_pod_ip]
995 | action: replace
996 | regex: (\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})
997 | replacement: '[$2]:$1'
998 | target_label: __address__
999 | - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port, __meta_kubernetes_pod_ip]
1000 | action: replace
1001 | regex: (\d+);((([0-9]+?)(\.|$)){4})
1002 | replacement: $2:$1
1003 | target_label: __address__
1004 | - action: labelmap
1005 | regex: __meta_kubernetes_pod_annotation_prometheus_io_param_(.+)
1006 | replacement: __param_$1
1007 | - action: labelmap
1008 | regex: __meta_kubernetes_pod_label_(.+)
1009 | - source_labels: [__meta_kubernetes_namespace]
1010 | action: replace
1011 | target_label: namespace
1012 | - source_labels: [__meta_kubernetes_pod_name]
1013 | action: replace
1014 | target_label: pod
1015 | - source_labels: [__meta_kubernetes_pod_phase]
1016 | regex: Pending|Succeeded|Failed|Completed
1017 | action: drop
1018 | - source_labels: [__meta_kubernetes_pod_node_name]
1019 | action: replace
1020 | target_label: node
1021 |
1022 | # Example Scrape config for pods which should be scraped slower. An useful example
1023 | # would be stackriver-exporter which queries an API on every scrape of the pod
1024 | #
1025 | # The relabeling allows the actual pod scrape endpoint to be configured via the
1026 | # following annotations:
1027 | #
1028 | # * `prometheus.io/scrape-slow`: Only scrape pods that have a value of `true`
1029 | # * `prometheus.io/scheme`: If the metrics endpoint is secured then you will need
1030 | # to set this to `https` & most likely set the `tls_config` of the scrape config.
1031 | # * `prometheus.io/path`: If the metrics path is not `/metrics` override this.
1032 | # * `prometheus.io/port`: Scrape the pod on the indicated port instead of the default of `9102`.
1033 | - job_name: 'kubernetes-pods-slow'
1034 | honor_labels: true
1035 |
1036 | scrape_interval: 5m
1037 | scrape_timeout: 30s
1038 |
1039 | kubernetes_sd_configs:
1040 | - role: pod
1041 |
1042 | relabel_configs:
1043 | - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape_slow]
1044 | action: keep
1045 | regex: true
1046 | - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme]
1047 | action: replace
1048 | regex: (https?)
1049 | target_label: __scheme__
1050 | - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
1051 | action: replace
1052 | target_label: __metrics_path__
1053 | regex: (.+)
1054 | - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port, __meta_kubernetes_pod_ip]
1055 | action: replace
1056 | regex: (\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})
1057 | replacement: '[$2]:$1'
1058 | target_label: __address__
1059 | - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port, __meta_kubernetes_pod_ip]
1060 | action: replace
1061 | regex: (\d+);((([0-9]+?)(\.|$)){4})
1062 | replacement: $2:$1
1063 | target_label: __address__
1064 | - action: labelmap
1065 | regex: __meta_kubernetes_pod_annotation_prometheus_io_param_(.+)
1066 | replacement: __param_$1
1067 | - action: labelmap
1068 | regex: __meta_kubernetes_pod_label_(.+)
1069 | - source_labels: [__meta_kubernetes_namespace]
1070 | action: replace
1071 | target_label: namespace
1072 | - source_labels: [__meta_kubernetes_pod_name]
1073 | action: replace
1074 | target_label: pod
1075 | - source_labels: [__meta_kubernetes_pod_phase]
1076 | regex: Pending|Succeeded|Failed|Completed
1077 | action: drop
1078 | - source_labels: [__meta_kubernetes_pod_node_name]
1079 | action: replace
1080 | target_label: node
1081 | - job_name: 'istio/envoy-stats'
1082 | scrape_interval: 15s
1083 | metrics_path: /stats/prometheus
1084 | kubernetes_sd_configs:
1085 | - role: pod
1086 | relabel_configs:
1087 | - source_labels: [ __meta_kubernetes_pod_container_port_name ]
1088 | action: keep
1089 | regex: '.*-envoy-prom'
1090 | - source_labels: [ __address__, __meta_kubernetes_pod_annotation_prometheus_io_port ]
1091 | action: replace
1092 | regex: ([^:]+)(?::\d+)?;(\d+)
1093 | replacement: $1:15090
1094 | target_label: __address__
1095 | - action: labelmap
1096 | regex: __meta_kubernetes_pod_label_(.+)
1097 | - source_labels: [ __meta_kubernetes_namespace ]
1098 | action: replace
1099 | target_label: namespace
1100 | - source_labels: [ __meta_kubernetes_pod_name ]
1101 | action: replace
1102 | target_label: pod_name
1103 | - job_name: 'istiod'
1104 | kubernetes_sd_configs:
1105 | - role: endpoints
1106 | namespaces:
1107 | names:
1108 | - istio-system
1109 | relabel_configs:
1110 | - source_labels: [ __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name ]
1111 | action: keep
1112 | regex: istiod;http-monitoring
1113 | # adds additional scrape configs to prometheus.yml
1114 | # must be a string so you have to add a | after extraScrapeConfigs:
1115 | # example adds prometheus-blackbox-exporter scrape config
1116 | extraScrapeConfigs: |
1117 | - job_name: 'kafka-metrics'
1118 | metrics_path: /metrics
1119 | scrape_interval: 15s
1120 | static_configs:
1121 | - targets:
1122 | - kafka-exporter:9308
1123 | # - job_name: "kafka-exporter"
1124 | # static_configs:
1125 | # - targets: ["kafka-exporter.monitoring.svc:9308"]
1126 | # - job_name: 'prometheus-blackbox-exporter'
1127 | # metrics_path: /probe
1128 | # params:
1129 | # module: [http_2xx]
1130 | # static_configs:
1131 | # - targets:
1132 | # - https://example.com
1133 | # relabel_configs:
1134 | # - source_labels: [__address__]
1135 | # target_label: __param_target
1136 | # - source_labels: [__param_target]
1137 | # target_label: instance
1138 | # - target_label: __address__
1139 | # replacement: prometheus-blackbox-exporter:9115
1140 |
1141 | # Adds option to add alert_relabel_configs to avoid duplicate alerts in alertmanager
1142 | # useful in H/A prometheus with different external labels but the same alerts
1143 | alertRelabelConfigs: {}
1144 | # alert_relabel_configs:
1145 | # - source_labels: [dc]
1146 | # regex: (.+)\d+
1147 | # target_label: dc
1148 |
1149 | networkPolicy:
1150 | ## Enable creation of NetworkPolicy resources.
1151 | ##
1152 | enabled: false
1153 |
1154 | # Force namespace of namespaced resources
1155 | forceNamespace: ""
1156 |
1157 | # Extra manifests to deploy as an array
1158 | extraManifests: []
1159 | # - |
1160 | # apiVersion: v1
1161 | # kind: ConfigMap
1162 | # metadata:
1163 | # labels:
1164 | # name: prometheus-extra
1165 | # data:
1166 | # extra-data: "value"
1167 |
1168 | # Configuration of subcharts defined in Chart.yaml
1169 |
1170 | ## alertmanager sub-chart configurable values
1171 | ## Please see https://github.com/prometheus-community/helm-charts/tree/main/charts/alertmanager
1172 | ##
1173 | alertmanager:
1174 | ## If false, alertmanager will not be installed
1175 | ##
1176 | enabled: true
1177 |
1178 | persistence:
1179 | size: 2Gi
1180 |
1181 | podSecurityContext:
1182 | runAsUser: 65534
1183 | runAsNonRoot: true
1184 | runAsGroup: 65534
1185 | fsGroup: 65534
1186 |
1187 | ## kube-state-metrics sub-chart configurable values
1188 | ## Please see https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-state-metrics
1189 | ##
1190 | kube-state-metrics:
1191 | ## If false, kube-state-metrics sub-chart will not be installed
1192 | ##
1193 | enabled: true
1194 |
1195 | ## promtheus-node-exporter sub-chart configurable values
1196 | ## Please see https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus-node-exporter
1197 | ##
1198 | prometheus-node-exporter:
1199 | ## If false, node-exporter will not be installed
1200 | ##
1201 | enabled: true
1202 |
1203 | rbac:
1204 | pspEnabled: false
1205 |
1206 | containerSecurityContext:
1207 | allowPrivilegeEscalation: false
1208 |
1209 | ## pprometheus-pushgateway sub-chart configurable values
1210 | ## Please see https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus-pushgateway
1211 | ##
1212 | prometheus-pushgateway:
1213 | ## If false, pushgateway will not be installed
1214 | ##
1215 | enabled: true
1216 |
1217 | # Optional service annotations
1218 | serviceAnnotations:
1219 | prometheus.io/probe: pushgateway
--------------------------------------------------------------------------------
/troubleshooting/prometheus/kafka-exporter-values.yaml:
--------------------------------------------------------------------------------
1 | # Default values for kafka-exporter.
2 | # This is a YAML-formatted file.
3 | # Declare variables to be passed into your templates.
4 |
5 | replicaCount: 1
6 |
7 | image:
8 | repository: danielqsj/kafka-exporter
9 | tag: latest
10 | pullPolicy: IfNotPresent
11 |
12 | nameOverride: ""
13 | fullnameOverride: ""
14 |
15 | service:
16 | type: ClusterIP
17 | port: 9308
18 |
19 | kafkaExporter:
20 | kafka:
21 | servers:
22 | - "kafka-service.namespace.svc:9092" # kafka가 배포되어 있는 네임스페이스 넣어주기
23 | sasl:
24 | enabled: false
25 | handshake: true
26 | username: ""
27 | password: ""
28 | mechanism: ""
29 |
30 | tls:
31 | enabled: false
32 | insecureSkipTlsVerify: false
33 | caFile: ""
34 | certFile: ""
35 | keyFile: ""
36 |
37 | log:
38 | verbosity: 0
39 | enableSarama: false
40 |
41 | prometheus:
42 | serviceMonitor:
43 | enabled: true
44 | namespace: monitoring
45 | interval: "30s"
46 | additionalLabels:
47 | app: kafka-exporter
48 | metricRelabelings: {}
49 |
50 | labels: {}
51 | podLabels: {}
52 |
53 | # Adds in Datadog annotations needed to scrape the prometheus endpoint.
54 | # prefix is required. If added, will provide a metric such as test.kafka_brokers.
55 | # Example metrics below. map metric name to a potential new metric name in dd.
56 | datadog:
57 | use_datadog: false
58 | prefix:
59 | metrics: [
60 | {"kafka_brokers": "kafka_brokers"},
61 | {"kafka_consumergroup_lag": "kafka_consumergroup_lag"},
62 | {"kafka_consumergroup_current_offset": "kafka_consumergroup_current_offset"}
63 | ]
64 |
65 | resources: {}
66 | # We usually recommend not to specify default resources and to leave this as a conscious
67 | # choice for the user. This also increases chances charts run on environments with little
68 | # resources, such as Minikube. If you do want to specify resources, uncomment the following
69 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
70 | # limits:
71 | # cpu: 100m
72 | # memory: 128Mi
73 | # requests:
74 | # cpu: 100m
75 | # memory: 128Mi
76 |
77 | nodeSelector: {}
78 |
79 | tolerations: []
80 |
81 | affinity: {}
82 |
--------------------------------------------------------------------------------
/troubleshooting/redis-sentinel/READMD.md:
--------------------------------------------------------------------------------
1 | ## k8s 클러스터 내에 redis sentinel 구성하기
2 | - 사내 클러스터내에 배포되어 있는 애플리케이션이 사용중인 Redis가 있는데 이 Redis는 Master & Slave로 구성되어 있었다. 사실 Master & Slave도 괜찮은 방법이지만, 단점은 만약에 마스터가 죽어버린다면 Slave는 읽기밖에 못하기 때문에 서비스가 중단될 수 있다.
3 | - 이 문제점을 해결하기 위한 방식이 Sentinel방식이다. Sentinel 서버는 마스터와 슬레이브를 계속 모니터링하다가 마스터가 죽을 경우 슬레이브를 마스터로 변경해서 데이터 유실이 발생하지 않도록 Fail-over하는 역할이다.
4 |
5 |
6 | ## 이슈
7 | - 우리는 쿠버네티스 환경을 운영하면서 kustomize를 사용하고 있다. 개발환경과 운영환경 두 곳을 클러스터로 운영을 하고 있기 때문에 Redis를 배포할 때 역시 kustomize를 사용해서 배포를 진행하려고 했다.
8 | - Redis Sentinel를 처음 구축하다보니 개발환경에 먼저 테스트를 진행했다. 문서와 구글을 찾아보면서 Sentinel를 구축했으나 Sentinel이 배포될 때마다 계속 죽는 상태를 봤다.
9 | - Sentinel 에러를 봤을 때 sentinel를 배포할 때 스크립트를 실행시키는데 이 스크립트에서 마스터를 지정하는 부분이 있는데 이부분에서 에러가 났다.
10 | - 보니까 Redis master 1대 Slave 2대 총 3대가 먼저 배포가 되는것을 확인 후 sentinel에서 마스터를 찾는 방식으로 진행해야 한다.
11 | - 즉 나는 kustomize를 구성한 후 한번에 배포를 해버리니까 Sentinel에서 redis가 배포를 완료하기 전부터 마스터를 찾으니까 없는 마스터를 찾아서 죽는것이 였다.
12 | - Redis Master & Slave & Sentinel를 구축할 때 순서를 통해 배포를 진행하자
13 | - 순서
14 | - redis.config.yaml
15 | - redis.statefulset.yaml
16 | - redis.sentinel.yaml
17 | - 이런식으로 순서를 정해서 배포해야만 sentinel를 구성할 수 있다.
18 |
19 |
--------------------------------------------------------------------------------