├── .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 | ![Configmap-GitOps](img.png) 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 | ![img.png](img.png) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/ba32e4a8-28c2-4868-b3b0-cb926052574e) 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 | ![img.png](img.png) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/897a8c6a-4f85-41ab-bf9f-5b3f264c505a) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/0d1747fb-1818-415a-87eb-b42e8119e216) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/34e54dbf-b124-4129-bf48-6512e37174c4) 9 | 10 | 11 | 파드 내부 nameserver 12 | 13 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/652b5fa1-8298-434c-a000-0f0302646f65) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/849f5411-167d-484e-ac62-c65d745a262b) 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 | ![img.png](img.png) # 출처넣기 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 | ![img.png](img.png) 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 | ![img_1.png](img_1.png)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 | ![img_2.png](img_2.png) 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 | ![img_3.png](img_3.png) 102 | 103 | 위 이미지에 보이는것처럼 파드 내부에서 다른 namespace에 있는 nginx pod에 요청을 할 때 coredns 로그에 dns 질의를 하는것을 볼 수 있습니다. 104 | 105 | 106 | #### Istio Cache 미적용 시 107 | 108 | ![img_4.png](img_4.png) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/e19a3e28-366f-4c48-b07a-8478da25f4a8) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/c2cc5413-16e8-455f-a972-9254e6faa0ec) 18 | 19 | 20 | 21 | ## Strict mTLS 22 | - 한쪽 Pod는 sideCar가 주입되어 있지 않는 Pod 다른 한쪽은 sideCar가 주입되어 있는 Pod가 있다고 가정하자. 만약 주입되어 있는 파드에서 envoy sidecar가 주입되어 있지 않는 파드를 호출하게 된다면 호출되지 않는다. 즉 연결거부상태로 된다. 23 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/149599bd-5351-4a0e-a44f-fe87a111efe6) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/4b9a982d-9fc0-437b-8466-42ab98b32740) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/7710fb1d-e6da-47f6-a6c8-3c6eec045f14) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/36092a5b-10fc-490b-be16-a3ce60a702e2) 110 | 111 | api Server는 이보다 더 많은 기능들이 있게지만 짧게 표현을 했다. 112 | 1. 인증 플러그인 113 | - 사용자를 클라이언트 인증서 혹은 http 헤더에서 가져온다. 플러그인은 클라언트의 사용자 이름, 사용자 ID, 속해있는 그룹정보 114 | 그렇다면 우리가 사용하고 있는 GKE에서는 kubectl 명령어를 사용하게 된다면 어떤식으로 흘러가는지 보자 115 | 116 | 117 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/45ff121f-b2f5-46fd-b698-5538abb242c6) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/56465444-8a72-49db-a474-50d3c896d63c) 153 | 154 | 155 | ## 파드의 네트워크 156 | - 파드의 모든 컨테이너가 동일한 네트워크와 리눅스 네임스페이스를 공유하는 법은 퍼즈(pause) 컨테이너가 같이 배포되기 때문이다. 157 | - 즉, 한 파드내에 여러개 컨테이너가 있다고 했을 때 결과적으로 동일한 리눅스 네임스페이스를 공유하는 3개의 컨테이너를 실행하는 것 158 | 159 | 160 | ## 네트워크 동작방식 161 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/8fc6525c-8603-4b26-88d3-99b53b2d2377) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/c37a2eaf-f03b-40e1-92ef-5fb750e69a5d) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/1a336f29-7b3f-4cdd-a8ef-52603b34ee37) 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 | ![img.png](img.png) 7 | 8 | Deployment는 파드를 관리하지않는다. 대신 레플리카셋을 생성하고 이들이 파드를 관리한다. 9 | 10 | ## Deployment 업데이트 전략 11 | Recreate 전략: 레플리케이션컨트롤러의 파드 템플릿을 수정한 후 모든 파드를 삭제하는 것과 마찬가지로 한 번에 기존 모든 파드를 삭제한 뒤 새로운 파드를 만든다. 12 | Recreate를 사용하게된다면, 새 파드를 만들기 전에 이전 파드를 모두 삭제한다. 13 | - 만약에 애플리케이션이 여러 버전을 병렬로 실행하는 것을 지원하지 않고 새 버전을 시작하기 전에 이전 버전을 완전히 중지해야 하는 경우만 이 전략을 사용하자. 이 전략은 잠시 다운타임이 생긴다. 14 | - 만약에 이전 버전과 새 버전을 동시에 실행할 수 있는 경우는 RollingUpdate 전략을 사용하자. 15 | 16 | 디플로이먼트의 파드 템플릿이 Configmap or Secret을 참조하는 경우에는 아무리 configmap을 수정해도 업데이트를 시작하지않는다. 애플리케이션의 설정을 수정해야할 때 업데이트를 시작하는 한 가지 방법은 새 컨피그맵을 만들고 파드 템플릿이 새 컨피그맵을 참조하도록 하는 것이다. 17 | 18 | ![img_1.png](img_1.png) 19 | 20 | ![img_2.png](img_2.png) -------------------------------------------------------------------------------- /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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/2044d3f5-fb16-409e-85b9-b8cdcf89b5b5) 10 | 11 | 12 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/8bdb6e3d-0da4-4e9c-b1c2-7ae9b4b08aac) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/62f3790d-04ec-4b76-9f88-4a2b34046f89) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/067f48fc-2008-4dff-bf92-3fd7353e8353) 35 | 36 | 37 | 팁) 노드의 시스템 파일에 읽기/쓰기를 하는 경우에만 hostPath 볼륨을 사용한다는 것을 기억해야 한다. 여러 파드에 걸쳐 데이터를 유지하기 위해서는 절대 사용하지 말아야 한다. 38 | 39 | 40 | 41 | 퍼시스턴트 스토리지 사용은 파드에서 실행중인 애플리케이션이 디스크에 데이터를 유지해야 하고 파드가 다른 노드로 재 스케줄링된 경우에도 동일한 데이터를 사용해야 한다면 위에서말한 볼륨은 사용하면 안된다. 42 | 이러한 데이터는 어떤 노드에서도 접근이 가능해야한다. 즉 몽고디비같은 영구 데이터를 허용하는 볼륨을 사용 43 | 44 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/8a82eca9-8fb5-43e9-a980-93215dbf21c3) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/99779e91-0500-493f-a1a8-f3e9e5ae0ea7) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/72c8fb75-b604-4405-ba15-71b8773d1e85) 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /troubleshooting/Kiali/README.md: -------------------------------------------------------------------------------- 1 | ## Istio 모니터링을 위한 Kiali 설치하기 2 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/b47876e9-e18b-4da5-b4f5-abe3929a071e) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/9bc34221-eeb0-4c1b-b6d8-ed7dad768742) 10 | 11 | 첫 번째 이슈는 이부분에서 잘못 설정을 해서 배포하고도 Kiali가 제대로 동작하지 않았다. 찾아보니까 Kiali는 istio resource와 관련된 루트 네임스페이스를 사용한다. 그래서 kiali를 제대로 동작하게 하려면 istio의 root namespace를 구성한곳에 12 | 지정해야 한다는 것이다. 즉 istio를 설치할 때 root namespace를 지정하는 부분이 있는데 그 네임스페이스를 작성해야한다는 것 13 | 14 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/10db0cb2-8cf7-464f-8ee0-eb0c40798433) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/18d64693-9dc3-4492-8cb5-5102370ac53c) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/2585b6b6-db62-4ebd-859c-78b2b2ab54df) 5 | 6 | 7 | 8 | ## 해결방법 9 | - 그렇다면 어떤식으로 해결할 수 있을까? Proxy Server를 따로 운영해서 개발자들에게 접근할 수 있게 해주는 방법밖에 없다. 그러면 Proxy Server 생성 위치도 중요하다.Proxy Server 위치는 클러스터 내에 있는 노드와 같은 VPC내에 생성되어야 한다. 그래야지 노드내에 배포된 개발 tool들을 접근할 수 있다. 10 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/50975425-3cd1-4988-ad3a-d39566eaa3cc) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/9561261c-8c69-463e-9a70-f867ede84e97) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/85b43b23-63f8-4135-9f4d-557bc0237aa2) 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 | ![image](https://github.com/youyoungnam/kubernetes-implement/assets/60678531/1cae6d19-6840-4fc5-92cb-0c134fbac61a) 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 | --------------------------------------------------------------------------------