69/120

김건호·2022년 5월 23일
1

Ingress

L7 LB = ALB

인그레스 컨트롤러

인그레스를 구현하기 위한 컨트롤러

vagrant@k8s-node1  ~  kubectl api-resources | grep ingress
ingressclasses   networking.k8s.io/v1     false        IngressClass
ingresses ing    networking.k8s.io/v1     true         Ingress

ing.spec

 vagrant@k8s-node1  ~  kubectl explain ing.spec
KIND:     Ingress
VERSION:  networking.k8s.io/v1

RESOURCE: spec <Object>

FIELDS:
   defaultBackend       <Object>
     

   ingressClassName     <string>
   # ingressClasses 리소스  
   # 인그레스 컨트롤러 한개 지금(여러개 세팅가능)
   # nginx naproxy apaceh 컨트롤러 여러개
   # 하나하나를 클래스로 만들어 둘 수 있음
   # 어떤 클래스를 가지고 만들 것 이냐
   rules        <[]Object>
   # 라우팅 정책

   tls  <[]Object>   

ing.spec.rules

 vagrant@k8s-node1  ~  kubectl explain ing.spec.rules
KIND:     Ingress
VERSION:  networking.k8s.io/v1

RESOURCE: rules <[]Object>

FIELDS:
   host <string>

   http <Object>

ing.spec.rules.http

hostname을 포함하는 www.naver.com 도메인 www호스트 naver.com 도메인
와일드 카드도 가능 *foo.bar.com 앞에 뭐가 붙던 괜찮음
도메인은 실제로 존재해야함

ing.spec.rules.http.paths
vagrant@k8s-node1  ~  kubectl explain ing.spec.rules.http.paths
KIND:     Ingress
VERSION:  networking.k8s.io/v1

RESOURCE: paths <[]Object>



FIELDS:
   backend      <Object> -required-
     

   path <string>
   경로 기본적으로 지정안하면 `/` 원한다면 info -> /info
   PathType with value "Exact" or "Prefix".

   pathType     <string> -required-
   # Exact 정확히 일치 # Prefix 일부분만 일치
   
   ImplementationSpecific
   # 이 경로 유형의 일치 여부는 IngressClass에 따라 달라짐. 
   # 구현할 때 별도 pathType 으로 처리하거나, Prefix 또는 Exact 경로 유형과 같이 동일하게 처리할 수 있음
ing.spec.rules.http.paths.backend
service
어떤종류의 리소스이냐
ing.spec.rules.http.paths.backend.resource
apiGroup     <string>
     APIGroup is the group for the resource being referenced. If APIGroup is not
     specified, the specified Kind must be in the core API group. For any other
     third-party types, APIGroup is required.

   kind <string> -required-
     Kind is the type of resource being referenced

   name <string> -required-
     Name is the name of resource being referenced

ing.spec.rules.host

실제 연결하고자 하는 서비스 rule정책을통해 서비스로 연결할 것인가

 vagrant@k8s-node1  ~  kubectl explain ing.spec.rules.http
KIND:     Ingress
VERSION:  networking.k8s.io/v1

RESOURCE: http <Object>

FIELDS:
   paths        <[]Object> -required-
   

규칙

순서가 중요

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-wildcard-host
spec:
  rules:
  - host: "foo.bar.com"
    http:
      paths:
      - pathType: Prefix
        path: "/bar"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: "*.foo.com"
    http:
      paths:
      - pathType: Prefix
        path: "/foo"
        backend:
          service:
            name: service2
            port:
              number: 80

순서 바꾸면 foo.bar.com은 정책연결이 안됨

예제

노드포트 만들어서 라우팅 시키기. 경로는 프리픽스에 루트로 지정

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myweb-ing
spec:
  rules:
    - host: '*.encore.xyz'
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: myweb-svc-np
                port:
                  number: 80 # 클러스터 IP의 포트

테스트

curl http://192.168.100.100 -v
> 이건 요청이라는뜻
< 이건 응답이라는뜻

kubectl get all 에는 ingress 리소스는 포함되어 있지 않음
kubectl get ing
모든 호스트의 ip가 찍힘 ALB를 쓰면 ALB주소 하나
kubetctl get po -n ingress-nginx
컨트롤러가 모든 노드에 하나씩 다 떠있음
얘들이 L7 로드밸런서 역할을 하고 각노드 아무데나 접속해도 가능
ALB는 하나만 잇을텐데 얘는 모든노드에 걸쳐서 다 만들어져 있어서 어떤노드로 들어와도 상관없음

도메인 없이 테스트 하는 방법

방법1

curl --resolve www.encore.xyz:80:192.168.100.100 http://www.encore.xyz

방법2
/etc/hosts

...
192.168.100.100 www.encore.xyz
curl http://www.encore.xyz

방법3

https://nip.io/
https://sslip.io/

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myweb-ing
spec:
  rules:
    - host: '*.nip.io'
    ...
kubectl replace -f myweb-ing.yaml
curl http://192-168-100-100.nip.io

인그레스 예제

hello:one 이미지
Dockerfile

FROM httpd
COPY index.html /usr/local/apache2/htdocs/index.html

index.html

<h1> Hello One </h1>

hello:two 이미지
Dockerfile

FROM httpd
COPY index.html /usr/local/apache2/htdocs/index.html

index.html

<h1> Hello Two </h1>
docker image build X/hello:one
docker image build X/hello:two
docker login
docker push X/hello:one
docker push X/hello:two

containerd는 이미지 빌드하는 기능은 없음
aws codebuild
소스코드 컴파일, 도커이미지 빌드하는 용도
github action 이미지를 빌드
buildah https://buildah.io/
podman by redhat 컨테이너 실행
buildah by redhat 이미지 빌드

skopeo 원격 레포지토리를 관리

RS
one-rs.yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: one-rs
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-one
  template:
    metadata:
      labels:
        app: hello-one
    spec:
      containers:
        - name: hello-one
          image: c1t1d0s7/hello:one
          ports:
            - containerPort: 80
              protocol: TCP

two-rs.yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: two-rs
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-two
  template:
    metadata:
      labels:
        app: hello-two
    spec:
      containers:
        - name: hello-two
          image: c1t1d0s7/hello:two
          ports:
            - containerPort: 80
              protocol: TCP

one-svc-np.yaml

apiVersion: v1
kind: Service
metadata:
  name: one-svc-np
spec:
  type: NodePort
  selector:
    app: hello-one
  ports:
    - port: 80
      targetPort: 80

two-svc-np.yaml

apiVersion: v1
kind: Service
metadata:
  name: two-svc-np
spec:
  type: NodePort
  selector:
    app: hello-two
  ports:
    - port: 80
      targetPort: 80

mulitpath

hello-ing.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-ing
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: / 
    # URL 재작성, /one -> /, /two -> / -> 쓰지않으면 ip/one처럼 붙기 때문에 에러
spec:
  rules:
    - host: '*.nip.io'
      http:
        paths:
          - path: /one
            pathType: Prefix
            backend:
              service:
                name: one-svc-np
                port:
                  number: 80
          - path: /two
            pathType: Prefix
            backend:
              service:
                name: two-svc-np
                port:
                  number: 80
kubectl create -f .

Readiness Probe

파드의 헬스체크를 통해 서비스의 엔드포인트 리소스에 타겟 등록
->
애플리케이션의 정상확동을 확인하여 엔드포인트에 등록을 시켜주는 개념 건강상태를 체크해서 앱이 정상작동하면 엔드포인트에 등록 비정상이면 등록을 안해서 라우팅을 안하도록 해주는

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myweb-rs
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
      env: dev
  template:
    metadata:
      labels:
        app: web
        env: dev
    spec:
      containers:
        - name: myweb
          image: ghcr.io/c1t1d0s7/go-myweb:alpine
          ports:
            - containerPort: 8080
              protocol: TCP
          readinessProbe:
            exec:
              command:
                - ls
                - /tmp/ready
                # 이파일은 없음 -> 프로브 실패
                # 파일이 생성되면 정상 작동
apiVersion: v1
kind: Service
metadata:
  name: myweb-svc-lb
spec:
  type: LoadBalancer
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080
kubectl create -f .
watch -n1 -d kubectl get po,svc,ep
kubectl exec <POD> -- touch /tmp/ready

Volume

파드 데이터 저장 불가 -> 저장 가능하지만 컨테이너 지우면 지워짐 -> 컨테이너에 볼륨을 생성가능
spec.volumes.*: 볼륨 유형

explain pod.spec.volumes

볼륨 유형들을 나열
https://kubernetes.io/ko/docs/concepts/storage/volumes/#volume-types

emptyDir

임시로 사용할 빈 볼륨, 파드 삭제 시 볼륨 같이 삭제

apiVersion: v1
kind: Pod
metadata:
  name: myweb-pod
spec:
  containers:
    - name: myweb1
      image: httpd
      volumeMounts:
        - name: emptyvol
          mountPath: /empty  # 디렉토리 없으면 자동 생성
    - name: myweb2
      image: ghcr.io/c1t1d0s7/go-myweb:alpine
      volumeMounts:
        - name: emptyvol # volumes.name과 매칭
          mountPath: /empty # 어디에 마운트할 지
  volumes:
    - name: emptyvol
      emptyDir: {} # {} -> 설정없음

마운트 확인

kubectl exec -it myweb-pod -c myweb1 -- bash

> cd /empty
> touch a b c
kubectl exec -it myweb-pod -c myweb2 -- sh

> ls /empty

emptyDir.medium

디폴트는 디스크, 메모리도 지정가능(고속의 임시스토리지)

emptyDir은 임시디렉토리, 파드의 라이프타임까지 공유 -> 파드지우면 같이 지워짐

pods.spec.containers.volumeMounts

readOnly지정 가능. 지정하지 않으면 RW

readOnly     <boolean>
     Mounted read-only if true, read-write otherwise (false or unspecified).
     Defaults to false.

gitRepo(사용 중지) --> initContainer(초기화 컨테이너)

Pod 생성될때 딱한번만 실행됨 -> 실행하고 종료
-> 초기화 컨테이너 종료가 되는 앱이여야함

https://kubernetes.io/ko/docs/concepts/workloads/pods/init-containers/

apiVersion: v1
kind: Pod
metadata:
  name: init-pod
spec:
  initContainers:
    - name: gitpull
      image: alpine/git
      args:
        - clone # git에서 코드를 가져옴
        - -b
        - v2.18.1
        - https://github.com/kubernetes-sigs/kubespray.git
        - /repo
      volumeMounts:
        - name: gitrepo
          mountPath: /repo
  containers:
    - name: gituse
      image: busybox
      args:
        - tail # 셸 계속해서 실행하기 위한 꼼수 tail -f /dev/null
        - -f
        - /dev/null
      volumeMounts:
        - name: gitrepo
          mountPath: /kube # /kube디렉토리로 파일들이 복사가 됨
  volumes:
    - name: gitrepo
      emptyDir: {}

gitclone 하고 종료되고 busybox가 저장을 함

https://hub.docker.com/r/alpine/git
알파인 git 알파인리눅스에 git을 포함 시켜뒀음

hostPath

도커의 바인드방식와 비슷
특정경로를 컨테이너의 볼륨을 제공

pods.spec.volumes.hostPath

vagrant@k8s-node1  ~/volume/hostPath  kubectl explain pods.spec.volumes.hostPath
KIND:     Pod
VERSION:  v1

RESOURCE: hostPath <Object>

FIELDS:
   path <string> -required-

   type <string>

type

/mnt/web_contents/index.html

<h1> Hello hostPath </h1>

참고
로컬 스토리지: 다른 호스트에 스토리지 볼륨을 제공할 수 X

  • emptyDir
  • hostPath
  • gitRepo
  • local

예제

httpd 이미지를 가지고 RS를 만들어보기
복제본은 3개
모든 컨테이너 접근할때 똑같은게 보여야함

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myweb-rs-hp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: myweb
          image: httpd
          volumeMounts:
            - name: web-contents
              mountPath: /usr/local/apache2/htdocs/
      volumes:
        - name: web-contents # 이름 언더바 불가능
          hostPath:
            type: Directory
            path: /web_contents

node1에 있는 파드가 정상실행인데
나머지는 제대로 만들어지고 있지 않음 -> 노드2, 3에는 web_contest 디렉토리가 없기때문

pod만들어지는 순서 볼륨을 지정하니까 스케쥴링이되고 해당되는 볼륨이 있는지 먼저 체크를 함
볼륨이 잇으면 이미지를 풀링함
그리고 컨테이너를 크리에이트
-----> emptyDir, hostPath -> local 스토리지 로컬에 있는 파드에 제공 가능
네트워크 넘어서 파드에 제공 가능은 불가 -> 네트워크 스토리지가 아님

루트밑에 디렉토리만드는건 루트 권한만
파일 sudo 해도 안먹힘
> 입력이니까 안먹힘sudo 는 echo에만
권한이 없는 디렉토리에 파일을 생성하는이 불가능
tee라는 명령어
sudo tee -> cat랑 비슷
echo "hello world" | sudo tee /a/a.txt

PV & PVC

지금까지는 파드의 직접 볼륨을 붙임
파드와 스토리지(볼륨)의 구역을 분리하기 위함

  • PersistentVolume: 스토리지 볼륨 정의
  • PersistentVolumeClaim: PV를 요청

pv, pvc 예제

Pod

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: mypod
      image: httpd
      volumeMounts:
        - name: myvol
          mountPath: /tmp
  volumes:
	- name: myvol
	  persistentVolumeClaim:
	    name: mypvc # pvc의 이름으로 요청하여 PV와 연결

PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc
spec:
  volumeName: mypv
  ...

PV

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv
spec:
  hostPath:
    path: /web_contents
    type: DirectoryOrCreate

PV, PVC 생명주기

PV <--1:1--> PVC 무조건 1대1연결만 가능

  1. 프로비저닝 (스토리지 미리 준비해야함)
  2. 바인딩 (PV PVC만들어서 연결)
  3. 사용 (바인딩하면 계속해서 사용 가능)
  4. 회수/반환(Reclaim)
    PVC삭제하게 되면 PV어떻게 할거냐
    PV리소스 그대로둠 -> PVC새로만들어서 연결하면 쓸수있지않을까 -> 불가능
    한번 사용한건 연결을 끊어버리더라도 다른 PVC 연결 불가
  • Retain: 보존 - PV를 삭제하지 않음(Release <- PVC가 연결 X)
  • Delete: 삭제 - PV를 삭제 / 실제 스토리지 내용 삭제
  • Recycle: 재사용 - 실제 스토리지 내용을 비우고, PV를 사용 가능한 상태(Available)
    사용하지 않음 -> 실제로 스토리지 삭제하는게 스토리지마다 다 달라서 -> 쿠버네티스가 제공하는 영역이 아님

접근 모드(Access Mode)

  • ReadWriteOnce: RWO Once는 하나의 파드만을의미 -> 하나의 노드에서만 연결할 수 있음 다른 파드는 연결 불가
  • ReadWriteMany: RWX Many 들어가면 다른 노드에서도 연결가능
  • ReadOnlyMant: ROW Many는 파드 여러개

스토리지에 따라서 지원되는 명령이 다름
기본적인 원칙은 블록스토리지(DAS)냐 네트워크 스토리지냐
네트워크 스토리지는

  • File -> 목적은 파일공유(NAS)
  • SAN(블록장치)
    블록은 many가 안됨 공유의 개념을 가지고 있는건 대부분 Many가 가능
    EBS SAN

NFS를 사용한 정적 프로비저닝(Static Provision)

node1: NFS 서버

sudo apt install nfs-kernel-server -y
sudo mkdir /nfsvolume
echo "<h1> Hello NFS Volume </h1>" | sudo tee /nfsvolume/index.html
sudo chown -R www-data:www-data /nfsvolume

/etc/exports

/nfsvolume 192.168.100.0/24(rw,sync,no_subtree_check,no_root_squash)
sudo systemctl restart nfs-kernel-server
systemctl status nfs-kernel-server

node들에 nfs 클라이언트 패키지 설치

node1, node2, node3

sudo apt install nfs-common -y 

또는

ansible all -i ~/kubespray/inventory/mycluster/inventory.ini -m apt -a 'name=nfs-common' -b

PV

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv
spec:
  accessModes:
    - ReadWriteMany
  capacity:
    storage: 1G
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /nfsvolume
    server: 192.168.100.100

PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1G
  storageClassName: '' # storageClassName 동적 프로비저닝을 해줌 안할거면 비워놔야함
  # ''로 비워놓기
  volumeName: mypv

RS

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myweb-rs
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: myweb
          image: httpd
          volumeMounts:
            - name: myvol
              mountPath: /usr/local/apache2/htdocs
      volumes:
        - name: myvol
          persistentVolumeClaim:
            claimName: mypvc

SVC

apiVersion: v1
kind: Service
metadata:
  name: myweb-svc-lb
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 80
  selector:
    app: web
profile
Ken, 🔽🔽 거노밥 유튜브(house icon) 🔽🔽

0개의 댓글