# 기초 개념 정리

## 쿠버네티스

### 개념

* 컨테이너 관리를 위한 구글에서 만든 오케스트레이션.&#x20;
* 컨테이너를 이용한 애플리케이션 배포 외에도 다양한 운영관리 업무를 자동화
* 도커호스트 관리, 컨테이너 배치, 스케일링, 여러 개의 컨테이너 그룹 → 로드밸런싱, 헬스체킹 등 기능
* GCP → GKE, AWS → EKS, Azure → AKS

### 로컬환경 설치 (윈도우, Mac)

* 근래는 연동이 가능. 이전에는 mini kube를 사용했음
* 도커아이콘 → Preference → Kubernetes → Install , Kubernetes is running 확인

```bash
# kubectl 설치 (Mac, Linux)
$ curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.10.4/bin/darwin/amd64/kubectl \
&& chmod +x kubectl \
&& mv kubectl /usr/local/bin/

# 대시보드 설치
$ kubecgtl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v1.8.3/src/deploy/recommended/kubernetes-dashboard.yml

# 상태확인
$ kubectl get pod --namespace=kube-system -l k8s-app=kubernetes-dashboard

# 웹 브라우저로 대시보드 볼 수 있기 프록시서버 설정
$ kubectl proxy # 127.0.0.1:8001
```

### Minikube

* 윈도우/맥용 도커에 쿠버네티스 연동 전까지는 Minikube 를 사용 했음.
* 로컬환경에 dockerd를 새로 띄워 → 쿠버네티스 환경을 구축할 수 있도록 ...
* 로컬에서 dockerd를 2개 다루기 때문에 데탑용 도커보다 더 까다롭긴함
* 윈도우 → 하이퍼바이저, 맥 → 하이퍼바이저.프레임워크 환경에서 실행, minikube → 하이퍼바이저, Virtualbox 에서도 실행이 가능

### 리소스

* 리소스 → 컴포넌트 같은 개념
  * 노드 : 컨테이너가 배치 되는 서버
  * 네임스페이스 : 쿠베 클러스터 안의 `가상 클러스터`
  * 파드 : 컨테이너의 그룹, 집합 등의 `가장 작은 단위`. `컨테이너 실행 방법 정의`
  * 레플리카셋 : `파드 복사`. 파드는 한개만 실행이 가능하나. 이걸 이용하면 여러개의 파드를 복사해서 사용이 가능
  * 디플로이먼트 : `레플리카 리비전`(버전)을 관리
  * 서비스 : `파드의 집합`에 접근하기 위한 경로를 정의
  * 컨피그맵 : **설정 정보를 정의하고 파드에 전달**
  * 스테이트풀셋 : 같은 스펙으로 모두 **동일한 파드를 여러 개 생성하고 관리**

이외 다양한 리소스, 시크릿, 롤 , 롤바인딩...

### 쿠버네티스 클러스와 노드

* 리소스 중 가장 큰 개념 -> `node`
* 서버에 두는데 보통 노드를 3개 구성해서 SPOF 를 방지
* 클러스터 전체를 관리하는 서버인 마스터노드가 한개는 꼭 존재해야됨&#x20;

![](https://1162853276-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M1ciKJvsGgeAKQBeHlJ%2F-M3RKMHkbuY_NQ8Ab1dd%2F-M3RMCklx-oDpuFy_GkH%2FIMG_6A4B4C4F4075-1.jpeg?alt=media\&token=52a5e26a-fc2a-4c53-a929-213787f5a094)

```bash
# 노드 확인
$ kubectl get nodes
```

### Namespace

* 클러스터 안의 `가상클러스터`

  ```bash
  # 확인
  $ kubectl get namespace
  ```
* 첫 구성시, default, docker, kube-public, kube-system 네임스페이스 4깨가 만들어져 있음
* 네임스페이스는 `개발팀이 일정 규모 이상일 때 유용`
* 네임스페이스 마다 권한 설정이 가능

### Pod

* `컨테이너 집합`, 하나 이상의 컨테이너들로 구성

![](https://1162853276-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M1ciKJvsGgeAKQBeHlJ%2F-M3RKMHkbuY_NQ8Ab1dd%2F-M3RMkTd6KqMpxc_AFBu%2FIMG_317D23072FC2-1.jpeg?alt=media\&token=ccbff13b-0b60-44c0-bc50-ce8248b08f65)

* **노드에 배치 해야됨**
* 같은 파드를  여러노드에 배치 할 수도 있고, 한 노드에 여러개 배치 할 수도 있음
* 그러나, **한 파드 안의 컨테이너는 한 노드에 배치 해야 됨**
* 파드 하나가 여러 노드에 걸쳐 배치 될 수 없음

![](https://1162853276-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M1ciKJvsGgeAKQBeHlJ%2F-M3RKMHkbuY_NQ8Ab1dd%2F-M3RMsChaQ3rv0eYwnya%2FIMG_3D51D238542D-1.jpeg?alt=media\&token=8cbeaeec-e2e0-4774-9471-8651e59b1e97)

#### 파드 생성 및 배포하기

* **\*.yaml 설정파일로 관리**하여 배포하는게 효율적

  ```yaml
  # file name : simple-pod.yaml
  apiVersion: v1
  kind: Pod                # 종류에 따라 아래 spec의 스키마가 변화
  metadata:
    name: simple-echo    # 이 서비스의 이름, 즉 여기서는 pod의 이름 정의    
  spec:
    containers:
    - name: nginx    # 컨테이너 이름
      image: gihyodocker/nginx:latest # 이미지 이름, 레지스트리에 등록
      env:
      - name: BACKEND_HOST        # 환경 변수 이름 -> 컨테이너에서 사용
        value: localhost:8080    # 환경 변수 값
      ports:
      - containerPort: 80
    - name: echo
      image: gihyodocker/echo:latest    # 이미지 이름
      ports:
      - containerPort: 8080
  ```

```bash
# 실행 -> -f : 파일명 지정 옵션
$ kubectl apply -f simple-pod.yaml

# 확인 -> 실행 중인 pod 확인
$ kubectl get pod

# 파드 내부의 컨테이너 접속 -> pod명, -c 옵션 : 컨테이너 이름 지정하기
$ kubectl exec -it simple-echo -c nginx
$ kubectl exec -it simple-echo -c echo

# kubectl delete 리소스명 -> kubectl 도구로 리소스를 삭제하려고 하는 경우
# 파드 삭제하기 : kubectl delete pod 파드명 
$ kubectl delete pod simple-echo

# 파드 삭제하기2 : -f 옵션 [파일명]
$ kubectl delete -f simple-pod.yaml
```

* pod의 IP는 내부적으로 컨테이너 끼리 공유,&#x20;
* 서로 접근이 가능, `ip:port` 형식으로
* 그리고 `Pod끼리도 서로 접근이 가능`
* Pod는 `사실상 컨테이너를 담는 가상머신`이나 마찬가지

![](https://1162853276-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M1ciKJvsGgeAKQBeHlJ%2F-M3RKMHkbuY_NQ8Ab1dd%2F-M3RMz4H6KQjr3Myvyc3%2FIMG_FFC09E0C13C7-1.jpeg?alt=media\&token=c3140b57-5924-45dc-97ff-f9d29862dd6e)

### 레플리카세트

* `Pod를 정의하는 매니페스트 파일`. 파드는 `파드를 하나 밖에 생성할 수 없는`데, `같은 파드를 여러개 실행`해 가용성을 확보해야 하는 경우에 활용

```yaml
# 파일명 : simple-replicaset.yaml
apiVersion: apps/v1
kind: ReplicaSet    # 리소스 종류 , 레플리카셋
metadata:
    name: echo        # 리소스 이름, 레플리카 이름 -> echo
    labels:
        app: echo
spec:
    replicas: 3 # pod 복제 수, 즉 생성수
    selector:
        matchLabels:
            app: echo
    template: # template 아래는 파드 리소스 정의와 같음
        metadata:
            labels:
                app: echo
        spec:
            containers:
            - name: nginx
              image: gihyodocker/nginx/latest
              env:
              - name: BACKEND_HOST
                value: localhost:8080
              ports:
              - containerPort: 80
            - name: echo
              image: gihyodocker/echo:latest
              ports:
              - containerPort: 8080
```

* 실행시, pod이름은 echo라는 이름 뒤에 접미사로 랜덤하게 붙는다
* 레플리카 갯수로 설정한것 만큼 생성 되고 실행 됨
* 파드의 수를 줄이면 줄인 개수만큼 파드가 삭제 됨 -> **파드 삭제는 복원 불가** 이므로 유의해야 하고, **stateless** 한 상태로  사용을 하기 때문에 **멱등성이 보장됨**

```bash
# 실행
$ kubectl apply -f simple-replicaset.yaml

# 확인
$ kubectl get pod

# 출력 내용
NAME            READY    STATUS    RESTARTS    AGE
echo-bmca        ...
echo-무작위        ...
echo-무작위2    ...

# 삭제
$ kubectl delete -f simple-replicaset.yaml
```

### 디플로이먼트

* 레플리카의 상위 개념의 리소스
* 애플리케이션 **배포의 기본단위**
* 레플리카셋 -> 같은 파드의 레플리케이션 개수관리, 디플로이먼트 -> `레플리카셋 관리 및 다루기 위한 리소스`

![](https://1162853276-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M1ciKJvsGgeAKQBeHlJ%2F-M3RKMHkbuY_NQ8Ab1dd%2F-M3RN2nS1KOaHihad0o_%2FIMG_5F0020CBCDA4-1.jpeg?alt=media\&token=7a10dd59-40a5-4d16-a42a-94be669b6026)

```yaml
# 파일명 : simple-deployment.yaml
apiVersion: apps/v1        # 버전
kind: Deployment            # 리소스 종류
metadata:
    name: echo
    labels:
        app: echo
spec:                    # 레플리카셋의 설정과 동일
    replicas: 3            
    selector:            # ?
        matchLabels:
            app: echo
    template:
        metadata:
            labels:
                app: echo
        spec:
            containers:
            - name: nginx
              image: 아무거나/nginx:latest
              env:
              - name: BACKEND_HOST
                value: localhost:8080
              ports:
              - containerPort: 80
            - name: echo
              image: 아무거나/echo:latest
              ports:
              - containerPort: 8080
```

```bash
# 실행 -> —-record 옵션 : 어떤 kubectl의 명령어를 실행했는지 기록을 남김
$ kubectl apply -f simple-deployment.yaml —-record

# 리소스 확인
$ kubectl get pod,replicaset,deployment —selector app=echo

# 디플로이먼트 리비전 확인
$ kubectl rollout history deployment echo
```

* 쿠버네티스는 **디플로이먼트 단위로 배포**를 함
* 실제 운영 -> 레플리카세트를 직접 다루기 보다는 **디플로이먼트 매니페스트 파일을 통해 다루는 경우가 대부분**
* 디플로이먼트 안의 레플리카세트를 어떻게 작동하는지 파악할 줄 알아야함
* 수정시, 레플리카세트가 새로 생성되고, 기존 레플리카세트와 교체가 됨
* **파드 개수만 수정하면** 레플리카가가 새로 생성되지는 않음
* **컨테이너 수정** -> 새로운 파드가 생성되고 기존파드는 단계적으로 정지됨

```bash
# 확인 -> 리비전 변화 확인 1->2
$ kubectl get pod —-selector app=echo

# 롤백 -> 최신 배포가 문제 있을 경우 이전상태로 돌아갈 때 꼭 필요함
$ kubectl rollout undo deployment echo

# 삭제 -> 레플리카, 파드 함께 삭제됨
$ kubectl delete -f simple-deployment.yaml
```

### 서비스

클러스터 안에서 **파드의 집합**(주로 레플리카세트)에 대한 `경로`나 `서비스 디스커버리를 제공`하는 리소스

```yaml
apiVersion: apps/v1
kind ReplicaSet
metadata
    name: echo-spring
    labels:
        app: echo
        release: spring
spec:
    replicas: 1
    selector:
        mathLabels:
            app: echo
            release: spring
        template:
            metadata:
                labels:
                    app: echo
                    release: spring
            spec:
                containers:
                - name: nginx
                  image: ~/nginx:latest
                  env:
                  - name: BACKEND_HOST
                    value: localhost:8080
                  ports:
                  - containerPort: 80
apiVersion: apps/v1
kind: ReplicaSet
metadata:
    name: echo-summer
    labels:
        app: echo
        release: summer
spec:
    replicas: 2
    selector:
        matchLabels:
            app: echo
            release: summer
        spec:
            containers:
            - name: nginx
              image: ~/nginx:latest
              env:
              - name: BACKEND_HOST
                  value: localhost:8080
              ports:
              - containerPort: 80
            - name: echo
              image: ~/echo:latest
              ports:
              - containerPort: 8080
```

```bash
# 확인
$ kubectl apply -f simple-replicaset-with-label.yaml

# l 옵션 : label 
$ kubectl get pod -l app=echo -l release=spring
$ kubectl get pod -l app=echo -l release=summer
```

```yaml
# simple-service.yaml
apiVersion: v1
kind: Service
metadata:
    name: echo    # 서비스명
spec:
    selector:     # 파드의 레이블 == 셀렉터 값 일치 -> 해당파드 서비스의 대상
        app: echo            # pod의 labels : app=echo 와 일치
        release: summer        # pod의 labels : release=summer 와 일치
    ports:
        - name: http
          port: 80
```

![](https://1162853276-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M1ciKJvsGgeAKQBeHlJ%2F-M3RKMHkbuY_NQ8Ab1dd%2F-M3RNdo5L9n9GES7w_pi%2FIMG_FBC7BF7F7916-1.jpeg?alt=media\&token=31e1931e-3d6d-4f2c-98e3-66155fc84807)

```bash
# 실행
$ kubectl apply -f simple-service.yaml

# 확인 : service 이름이 echo인 것 출력
$ kubectl get svc echo

# 서비스-> 기본적으로 쿠버네티스 클러스터 안에서 실행됨
# 따라서 외부서 요청을 받기 위해 쿠베 디버깅용 임시컨테이너 배포 -> curl 실행
$ kubectl run -i —-rm —-tty debug —-image=gihyodocker/fundametal:0.1.0 —-restart=Never —-bash -il

# 다음명령어로 로그출력을 확인
$ kubectl logs -f echo-summer-dtblk -c echo
```

#### 서비스의 네임 리졸브

* 쿠버네티스 클러스터의 **DNS 서비스**를 `서비스명.네임스페이스명.svc.local`로 연결
* ex) echo -> default네임스페이스에 배치돼 있으므로

```bash
# 확인
$ curl http://echo.default.svc.local

# svc.local은 생략 가능. 다른 네임스페이스에 있는 서비스를 참조
$ curl http://echo.default

# 같은 네임스페이스 -> 네임스페이스 생략 가능
$ curl http://echo
```

#### ClusterIP 서비스

* 서비스에도 여러 가지 종류가 존재.
* 그 종류를 yaml파일에 지정할 수 있음
* ClusterIP를 사용하면 **쿠버네티스 클러스터의 내부 IP 주소에 서비스를 공개 할 수 있음**
* 이를 이용하면 어떤 파드에서 다른 파드 그룹으로 접근할 때 서비스를 거쳐 가도록 할 수 있고, **서비스명으로 네임 리졸브가 가능**. 그러나 **외부로는 접근 안됨**

#### NodePort 서비스

* NodePort 서비스는 클러스터 외부에서 접근할 수 있는 서비스
* ClusterIP와 생성은 간ㅌ지만, 각노드에서 서비스 포트로 접속하기 위한 `글로벌 포트`를 개방한다는 점이 차이점

```yaml
apiVersion: v1
kind: Service
metadata:
    name: ehco
spec:
    type: NodePort    # 서비스의 한 종류,
    selector:
        app: echo    # 앞에서 살펴 본 바, 파드의 라벨과 매칭
    ports:
        - name: http
          port: 80
```

```bash
# 실행
$ kubectl get svc echo

# 출력
# echo NodePort a.b.c.d <node> 80:31058/TCP ~~~~ # 노드의 31058포트를 통해 접근 -> 이를 이용해 서비스를 쿠버네티스 클러스터 외부로 공개

# 요청확인, L4레벨에서 노출
$ curl http://127.0.0.1:31058 # -> 서비스로 접근
```

#### LoadBalancer 서비스

* **로컬 쿠버네티스 환경에서는 불가능**
* 주로 각 **클라우드 플랫폼에서 제공하는 로드밸런서와 연동하기 위해 사용**

#### ExternalName 서비스

* 셀렉터도, 포트 정의도 없는 서비스
* **쿠버네티스 클러스터에서 외부 호스트를 네임 리졸브하기 위한 별명을 제공**

```yaml
apiVersion: v1
kind: Service
metadata:
    name: gihyo                    # 연결, 참조 : gihyo.jp
spec:
    type: ExternalName
    externalName: gihyo.jp        # 별명 외부에서 다음 정보가 노출
```

### 인그레이스

* 가장 중요함. 쿠버네티스 클러스터 외부로 서비스를 공개. L7 까지 다룸
* 외부노출, 가상호스트 및 **경로 기반의 정교한 HTTP 라우팅** 가능
* HTTP/HTTPS 서비스를 노출 하려는 경우 -> 무조건 빼박으로 **인그레이 사용** 해야됨
* 역시 인그레이스도 로컬환경에서는 불가능

```bash
# 클렇스터 외부 -> HTTP 요청 -> 라우팅하기 위해, nginx_ingress_controller 배포
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.16.2/deploy/mandatory.yaml

$ kubectl apply -f https://raw.githubusercontent.com/ingress-nginx/nginx-0.16.2/deploy/cloud-generic.yaml

# 서비스와 파드가 생성 된 후... 인그레스 리소스 사용하기
$ kubectl -n ingress-nginx get service,pod
```

#### 인그레스를 통해 접근

```yaml
# simple-service.yaml 작성
apiVersion: v1
kind: Service
metadata:
    name: echo
spec:
    selector:
        app: echo
    ports:
    - name: http
    port: 80
```

```bash
# 실행
$ kubectl apply -f simple-service.yaml
```

```yaml
# simple-ingress.yaml 작성
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
    name: echo
spec:
    rules:
    - host: ch05.gihyo.lcoal
      http:
        paths:
        - path: /
        backend:
            serviceName: echo
      servicePort: 80
```

```bash
# 실행
$ kubectl apply -f simple-ingress.yaml

# 확인
$ kubectl get ingress

$ curl http://localhost -H ‘Host: ch05.gihyo.local’
```

* 지정된 호스트 혹은 경로와 일치하는 서비스로 **요청을 전달**

```yaml
apiVersion: extensoins/v1beta1
kind: Ingress
metadata:
    name: echo
    annotaions:
        nginx.ingress.kubernetes.io/server-snippet: |
            set $agentflag 0;

            if ($http_user_agent ~* “(Mobile)”) {
                set $agentflag 1;
            }

            if ($agentflag=1) {
                return 301 http://gihyo.jp/;
            }
spec:
    rules:
    - host: ch05.gihyo.local
      http:
        paths:
        - path: /
          backend:
            serviceName: echo
            servicePort: 80
```

```bash
# User-Agent 값에 Mobile이 포함된 경우 다른 url로 리다이렉트
$ curl http://localhost \
-H ‘Host: ch05.gihyo.local’ \
-H ‘User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_...)a AppleWebKit/604.1.38 ~~~~~ Mobile/15A372 Safari/604.1’
```

#### freshpod 로 이미지 업데이트 탐지, 파드 업데이트하기

* **freshpod** 는 쿠버네티스로 배포된 **컨테이너의 이미지가 업데이트 됐는지 탐지**
* 탐지 후 **파드를 자동으로 다시 배포**하는 도구
* Minikube의 애드온으로 개발된 것. 윈/mac용 도커에서도 사용 가능. 로컬환경에서 쿠버네티스 개발 환경에서 빼놓을 수 없는 도구

```bash
# 설치
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/minikube/master/deploy/addons/freshpod/freshpod-rc.yaml
```

```yaml
# 파일 작성
apiVersion: apps/v1
kind: Deployment
metadata:
    name: echo
    labels:
        app: nginx
spec:
    replicas: 1
    selector:
        app: nginx
    template:
        metadata:    
        labels:
            app: nginx
        spec:
            containers:
            - name: nginx
              image: ch04/nginx:latest
              imagePullPolicy: IfNotPresent #
            env:
            - name: BACKEND_HOST
              value: 127.0.0.1:8080
```

```bash
# freshpod로 컨테이너를 -> imagePullPolicy: Always(항상 최신 이미지 받음)가 아니라 IfNotPresent(전에 받아둔 이미지가 있으면 재사용)으로 설정해야함
$ kubectl get pod -l app=nginx -w

# 이미지 수정 후 빌드 -> 확인, 이미지 생성후 파드 교체
$ docker image build -t ch04/nginx:latest
```

* 로컬 환경에서 효율적인 개발이 가능하게 해주는 도구

#### kube-prompt

* kubectl 명령 및 리소스 이름의 자동완성 기능 제공

#### 쿠버네티스 API

* 쿠버네티스 리소스를 `생성, 수정, 삭제` 하는 작업은 쿠버네티스 클러스터에 배포된 API가 수행
* 이 API를 하나로 묶은 형태로 구성되고, 아 `apiVersion`은 **해당 작업에 사용 되는 API 종류를 나타내는 값**
* 리소스마다 다름.&#x20;
* **쿠버네티스 API 리포지토리를 통해 어떤 api가 리소스를 지원하는지 확인 필요**
* 쿠버네티스 레파지토리 : <https://github.com/kubernetes/api>
* 서비스 or 파드 핵심 api : `v1` / 디플로이먼트는ㄴ 파드 생성 및 제어 api: `apps/v1`
* 인그레스 api : `extension/v1beta1`

```bash
# 사용가능한 api 목록 확인
$ kubectl api-versions
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ssosso.gitbook.io/study/os-and-infra-and-system/kubernetes/basic-summary.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
