쿠버네티스 전문가 양성과정 10주차 1일(2/20)

최수환·2023년 2월 20일
0

Kubernetes

목록 보기
42/75
post-thumbnail

스토리지

  • 컨테이너는 stateless, 즉 상태가 없기 때문에 항상 일정하다.
    따라서 이미지를 통해 컨테이너를 생성할 수 있는 것이다.
  • 컨테이너 = Immutable Infrastructure
  • 컨테이너는 stateless이지만 데이터는 state가 존재한다.
    따라서 컨테이너에 데이터를 저장하고 컨테이너를 없애면 데이터도 같이 날아간다. 하지만 데이터는 매우중요하다. 따라서 이러한 데이터를 저장하기 위해서 컨테이너에 스토리지를 사용하는 것이다.

볼륨

📒 볼륨 개념 참조

EmptyDir

  • 파드의 라이프사이클이 끝나면 데이터도 같이 사라진다.
  • 따라서 데이터의 저장 목적이 아닌, 하나의 파드 내에서 컨테이너들이 서로 공유하는 것을 목적으로 할 때 사용한다
  • 네트워크 기반의 스토리지가 아니다.

1 . emptydir 사용 예시

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myapp-rs-fortune
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp-rs-fortune
  template:
    metadata:
      labels:
        app: myapp-rs-fortune
    spec:
      containers: 
      - name: web-server # 주기능을 하는 웹 서버 컨테이너
        image: nginx:alpine 
        volumeMounts:
        - name: web-fortune # 생성한 볼륨 마운트
          mountPath: /usr/share/nginx/html # 볼륨과 디렉터리 링크
          readOnly: true
        ports:
        - containerPort: 80 
        # 요청이 들어왔을때 웹서버에 접속해야하기 때문에 해당 컨테이너의 포트만 뚫는다
      - name: html-generator # 보조기능을 하는 이미지 생성 컨테이너
        image: ghcr.io/c1t1d0s7/fortune
        volumeMounts:
        - name: web-fortune # 생성한 볼륨 마운트
          mountPath: /var/htdocs # 볼륨과 디렉터리 링크
        # 요청이 보조기능을 하는 컨테이너에 들어가면 안되기때문에 포트를 안뚫는다
      volumes:
      - name: web-fortune # 마운트할 볼륨 생성
        emptyDir: {}

-> emptydir은 파드안에 컨테이너들이 같은 볼륨을 바라보게 할 때 사용한다.
📗 nginx:alpine은 기본 이미지와 동일하게 작동하는데 용량은 훨씬 작다.

1 -1. 서비스 구성

apiVersion: v1
kind: Service
metadata:
  name: myapp-svc-fortune
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: myapp-rs-fortune

-> 외부에 노출시키기 위해 구성

kubectl logs myapp-rs-fortune-llkvx -c html-generator
kubectl logs myapp-rs-fortune-llkvx -c web-server
# 한 파드내의 각 컨테이너의 로그 기록 

kubectl exec myapp-rs-fortune-llkvx -c web-server -- hostname
# 원하는 컨테이너에 exec 명령

kubectl exec myapp-rs-fortune-llkvx -it -c html-generator -- sh
# 원하는 컨테이너에 셸로 접속

-> 멀티 컨테이너인 경우 -c 옵션을 사용하여 파드안에서 컨테이너를 구분해서 정보를 확인하거나 접속한다.

-> curl 외부용ip를 통해 파드에 80번포트가 뚫려있는 webserver컨테이너에 도달한다. webserver컨테이너의 index.html내용을 curl의 결과로 보여줄텐데, index.html을 갖고있는 해당 디렉터리는 볼륨을 통해 보조기능을 하는 컨테이너의 htdocs디렉터리에 연결되어있다. 따라서 보조기능을 하는 컨테이너의 htdocs디렉터리의 index.html의 내용이 볼륨에 저장되고, 해당 index.html은 주기능을 하는 컨테이너의 볼륨이 연결된 디렉터리에 전달된다.

2 . gitRepo를 대안으로 사용하는 emptydir 사용 예시

  • gitRepo볼륨은 앞으로 없어지는 볼륨이다. 따라서 기존에 gitRepo를 사용했다면 대안이 필요하다.

<초기화 컨테이너>

  • job처럼 반드시 종료되어야 하는 컨테이너를 생성한다.
  • 초기화 컨테이너가 완료되지 않으면 뒤에 오는 컨테이너들은 실행되지 않는다.
  • probe를 설정할 수 없다.

📒 초기화 컨테이너 개념 참조

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod-git
spec:
  initContainers:
    - name: git-clone3
      image: alpine/git
      args:
        - clone
        - --single-branch
        - --
        - https://github.com/kubernetes/kubernetes
        - /repo
      volumeMounts:
        - name: git-repository
          mountPath: /repo
  containers:
    - name: git-container
      image: busybox
      args: ['tail', '-f', '/dev/null']
      volumeMounts:
        - name: git-repository
          mountPath: /repo
  volumes:
    - name: git-repository
      emptyDir: {}

HostPath

  • EmptyDir처럼 네트워크 기반의 스토리지가 아니다
  • 호스트(노드)의 특정 경로를 지정해서 볼륨으로 사용하기 때문에 EmptyDir과 다르게 파드의 라이프사이클과 독립적이다.
    -> 따라서 데이터를 영구적으로 보존할때 사용한다.

hostpath볼륨을 설정할 떄 사용하는 type의 필드 값 종류

📒 파일도 마운트할 수 있다.

1 . hostpath 예시

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myapp-rs-hp
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp-rs-hp
  template:
    metadata:
      labels:
        app: myapp-rs-hp
    spec:
      #nodeName: kube-node1
      containers:
      - name: web-server
        image: nginx:alpine
        volumeMounts: # 볼륨 마운트 
        - name: web-content
          mountPath: /usr/share/nginx/html # 볼륨과 링크할 디렉터리 경로 지정 
        ports:
        - containerPort: 80
      volumes:
      - name: web-content
        hostPath:
          type: Directory # 타입 지정 
          path: /srv/web_contents # 볼륨의 경로 지정

1-1 . 서비스 구성

apiVersion: v1
kind: Service
metadata:
  name: myapp-svc-hp
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: myapp-rs-hp

-> 노드의 특정 경로에 type= 디렉터리를 볼륨으로 지정하고 해당 볼륨을 마운트한다.
-> 만일 파드를 두개 만들었는데 node1,node2에 배치된 상태였다면, node1,node2에 /srv/web_contents 디렉터리가 존재해야 한다. 존재하지 않다면 파드는 만들어지지 않는다.

kubectl describe pod 파드명 

-> 디렉터리가 존재하지 않아 파드 생성이 실패했음을 확인

kubectl logs 파드명

-> 애초에 파드가 만들어지지 않았기 때문에 로그확인을 하지 못한다

  • 만일 해당 노드에 지정한 경로의 디렉터리를 생성하면 파드는 생성된다

Persistent Volume

  • 스토리지 관리는 컴퓨트 인스턴스 관리와는 별개의 문제다. 퍼시스턴트볼륨 서브시스템은 사용자 및 관리자에게 스토리지 사용 방법에서부터 스토리지가 제공되는 방법에 대한 세부 사항을 추상화하는 API를 제공한다. 이를 위해 퍼시스턴트볼륨 및 퍼시스턴트볼륨클레임이라는 두 가지 새로운 API 리소스를 소개한다.

  • 기존의 볼륨은 파드에 볼륨을 생성하여 사용한다. 즉, 파드내에서 볼륨을 어떻게 사용할 것인가를 정의한 것이다. 다시말해, 파드를 삭제하면 결국에는 볼륨도 삭제된다는 것이다
    = 파드의 생명주기에 볼륨이 분리되지 못하고 포함된다.

  • 따라서 관리자영역에 스토리지를 구성하고, 개발자영역에 pod를 배치한다. 스토리지 앞에는 pv가 존재하고 pod앞에는 pvc가 존재한다. pod는 pvc를 통해 pv를 요청한다.
    = 파드의 리소스와 볼륨의 리소스의 라이프 사이클을 분리시킨다.
    📌 pv가 곧 스토리지랑 같다고 생각하면 된다

  • 쿠버네티스는 볼륨으로 persistent Volume 사용을 권장한다.

💡 pv와 pvc를 연결하는 방법은 label or 이름이 있다.

  • 프로비저닝 : pv 생성 (정적, 동적)
    바인딩 : pvc생성 및 pv와 연결
    반환(Reclaiming) : retain, delete, recycle 세가지가 있다.
    -> pvc를 지우면 pv를 어떻게 할 것인가에 대한 방법이다.
    • retain : pvc를 삭제한 후 pv가 남아있을 때 재사용을 할 수 없기 때문에 pv와 관련된 리소스를 반환(삭제)한다.
      = 정적 프로비전에서 default정책
    • delete : pv를 포함한 스토리지 관련 모든 리소스 삭제
      = 권장 하는 방식 , 동적 프로비전에서 dafault 정책
    • recycle : 더이상 사용하지 않는 정책이다

📘 접근모드 참조

📗 퍼시스턴트 볼륨 개념 참조

NFS 서버 설치

  • 네트워크 기반의 공유 스토리지
  • 원래는 새로운 노드를 만들어서 nfs서버를 구성해야하지만 이번 실습은 컨트롤 플레인에 nfs서버를 만들 것이다.

1 . nfs 서버 구성

sudo apt install nfs-kernel-server -y
# 컨트롤 플레인에 nfs서버 설치

sudo mkdir /srv/nfs-volume
# 디렉터리 생성

echo "/srv/nfs-volume *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee /etc/exports
# export할 디렉터리 생성

cat /etc/exports
# export할 디렉터리 확인

sudo exportfs -arv
# 디렉터리 export

ansible kube_node -i ~/kubespray/inventory/mycluster/inventory.ini -m apt -a 'name=nfs-common' --become
# 각 노드에 ansible ad-hoc명령으로 nfs시스템 설치 

정적 프로비저닝

  • PV를 프로비저닝 할 수 있는 두 가지 방법이 있다 : 정적(static) 프로비저닝과 동적(dynamic) 프로비저닝.
    -> 동적을 더 추천하는 방시이다.

  • 클러스터 관리자는 여러 PV를 만든다. 클러스터 사용자가 사용할 수 있는 실제 스토리지의 세부 사항을 제공한다. 이 PV들은 쿠버네티스 API에 존재하며 사용할 수 있다

  • 정적 프로비저닝 = 관리자가 직접 pv를 만든다

    kubetl get pv,pvc # 생성한 pv,pvc 확인 

    -> 용량, 접근모드, 반환 정책, 상태, pv가 어디에 부착되어있는지 확인 가능하다.

1 . pv 생성

echo "hello static nfs" | sudo tee /srv/nfs-volume/index.html
# nfs볼륨 생성 = 관리자 영역에 스토리지(nfs) 구축  

apiVersion: v1
kind: PersistentVolume
metadata:
  name: myapp-pv-nfs
spec:
  capacity:
    storage: 1Gi # 용량 설정 
  accessModes: # 접근모드 설정 
    - ReadWriteMany # RWX(= 읽기,쓰기,many)
  persistentVolumeReclaimPolicy: Retain # 반환정책 설정
  nfs:
    path: /srv/nfs-volume # 관리자영역에서 생성한 nfs볼륨 설정 
    server: 192.168.56.11 # 관리자영역 설정

-> 관리자 영역에서 생성한 nfs볼륨을 기타설정과 함께 pv생성 및 연결한다

1-1 . pvc생성

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myapp-pvc-nfs
spec:
  accessModes:
    - ReadWriteMany # 
  resources:
    requests:
      storage: 1Gi # pv가 가진 capacity중 특정 자원만큼 요청 
  volumeName: myapp-pv-nfs # pvc와 pv를 연결(= bind)
  storageClassName: '' # 정적에서는 지정 x 

1-2 . 파드 생성

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myapp-rs-nfs
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp-rs-nfs
  template:
    metadata:
      labels:
        app: myapp-rs-nfs
    spec:
      containers:
      - name: myapp
        image: nginx
        volumeMounts:
        - name: nfs-share # 파드에 볼륨 마운트
          mountPath: /usr/share/nginx/html # 볼륨과 특정 디렉터리 링크
        ports:
        - containerPort: 80
      volumes:
      - name: nfs-share
        persistentVolumeClaim:
          claimName: myapp-pvc-nfs # pvc와 파드 연결 

1-3 . 서비스 생성

apiVersion: v1
kind: Service
metadata:
  name: myapp-svc-nfs
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: myapp-rs-nfs

-> pv와 pvc, 파드와 서비스를 생성 한 후 curl을 통해 볼륨이 마운트되서 링크된 것을 확인
-> pvc에 연결되어 있는 파드들을 삭제 한 후 다시 파드를 생성해도 마찬가지로 링크되어 curl이 보내지는 것을 확인
-> 만약 pvc를 삭제하면 pv와의 연결이 끊어지고 다시 pvc를 생성해도 절대 pv와 다시 연결되지 않는다.
= 한번 bind된 pv는 더이상 pvc와 연결을 하지 못한다. 즉, pv는 재사용이 불가능하다.

동적 프로비저닝

  • pv를 자동으로 만들어주는 것
  • 정적 프로비저닝은 pv를 재사용하지 못하기 때문에 일일이 pv를 계속 만들어야한다. 따라서 비효율적이다.

📒 스토리지 클래스 개념 참조

  • pv에 대한 정보를 가지고 있는 것이 스토리지 클래스이다.
    -> pv를 자동으로 만들기 위한 프로파일이다

📒 NFS Subdir External Provisioner설치 방법 참조

  • 쿠버네티스에는 내장 NFS 프로비저너가 없다. NFS를 위한 스토리지클래스를 생성하려면 외부 프로비저너를 사용해야 한다.
git clone https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner.git
  • 외부프로비저너를 설치하기 위한 방법중 Kustomize 방법을 사용할 것이다.
kubectl apply -k .
  • 생성한 Kustomize 적용

1 . pvc생성

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myapp-pvc-dynamic
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs-client # 스토리지 클래스 이름 지정 

-> 정적 프로비저닝과 다르게 스토리지 클래스 네임을 지정한다.
-> 스토리지 클래스 네임 : pv를 만들기 위한 프로파일
-> pvc를 생성하면 pv가 자동으로 같이 생성되서 바인드되는 것을 알 수 있다.

1-1 . 파드 생성

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myapp-rs-dynamic
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp-rs-dynamic
  template:
    metadata:
      labels:
        app: myapp-rs-dynamic
    spec:
      containers:
      - name: web-server
        image: nginx:alpine
        volumeMounts:
        - name: web-content
          mountPath: /usr/share/nginx/html
        ports:
        - containerPort: 80
      volumes:
      - name: web-content
        persistentVolumeClaim:
          claimName: myapp-pvc-dynamic

2 . default 스토리지 클래스

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myapp-pvc-dynamic
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
# 스토리지 클래스 이름 지정 x

-> 스토리지 클래스 이름을 지정하지 않고 사용
-> 대신 기존의 설치한 스토리지 클래스를 default 스토리지 클래스로 지정해서 일일이 스토리지 클래스를 지정하지 않고도 사용이 가능해진다
-> default 스토리지 클래스는 하나만 지정이 가능하다

kubectl patch storageclasses.storage.k8s.io nfs-client -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
# kubectl edit sc sc이름 으로도 수정 가능 


-> default 스토리지 클래스 적용

📒 동적 볼륨 프로비저닝 개념 참조


app_custom

configmap

  • 컨피그맵은 키-값 쌍으로 기밀이 아닌 데이터를 저장하는 데 사용하는 API 오브젝트이다. 파드는 볼륨에서 환경 변수, 커맨드-라인 인수 또는 구성 파일로 컨피그맵을 사용할 수 있다.

  • 컨피그맵을 사용하면 컨테이너 이미지에서 환경별 구성을 분리하여, 애플리케이션을 쉽게 이식할 수 있다.

kubectl get cm # configmap확인 

📕 컨피그맵 개념 참조

1 . 키/벨류를 이용한 config맵 생성

kubectl create cm my-config1 --from-literal=key1=value1
# 키:벨류값이 들어간 컨피그맵 생성 
kubectl describe cm my-config1

kubectl create cm my-config2 --from-literal=key1=value1 --from-literal=key2=value2
# 여러 키:벨류값이 들어간 컨피그맵 생성 
kubectl describe cm my-config1

2 . 파일명을 지정한 config맵 생성

echo value3 > key3
# 파일 생성 

kubectl create cm my-config3 --from-file=key3
# 파일명을 지정한 컨피그맵 생성
kubectl describe cm my-config3
# 파일명이 키값이 되고, 벨류값으로 파일의 내용이 들어간다

kubectl create cm my-config4 --from-file=key3-tree=key3
# 파일명을 지정하되 다른 이름으로 지정
kubectl describe cm my-config4
# 지정한 파일명이 키값이 되고 벨류값으로 파일 내용이 들어간다

3 . yaml파일로 config맵 생성

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config4
data:
  key4: value4 # 키:벨류 작성 

4 . config맵 사용하기

  • config맵을 참조하는 방법은 볼륨과 환경변수 두개가 있다.
#볼륨을 이용한 컨피그맵 참조     
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo # 볼륨 마운트 
      mountPath: "/etc/foo"
      readOnly: true
  volumes: 
  - name: foo # 컨피그맵을 참조한 볼륨 생성 
    configmap: 
      name: myconfigma

-> 주로 위의 방식처럼 볼륨을 이용한 config맵 참조를 한다

secret

  • 시크릿은 컨피그맵과 유사하지만 특별히 기밀 데이터를 보관하기 위한 것이다.
  • 개별 시크릿의 크기는 1MiB로 제한된다.
    📒 컨피그맵도 대용량은 아니지만 시크릿처럼 제한이 없다


-> 보통 기업에서는 도커허브의 퍼블릭 레포지터리같은 퍼블릭 이미지는 사용하지 않는다(보안 위험). 따라서 주로 프라이빗 레포지터리에서 이미지를 사용하는데 이것은 인증을 받아야 이용할 수 있다. 매번 인증하는 것은 비효율적이므로 인증서를 등록해 인증을 받는다.
인증서는 시크릿을 통해 제작할 수 있다.

📕 시크릿 개념 참조

1 . Opaque타입의 시크릿 생성

kubectl create secret generic my-secret --from-literal=key1=value1
# 임의의 값으로 시크릿 생성 

kubectl get secret
# 생성한 시크릿 정보 보기 

kubecrtl describe secret my-secret 
# 컨피그맵과 다르게 벨류값을 보여주지 않는다


kubectl get secret my-secret -o yaml


-> yaml형식으로 보면 key값이 암호화된거처럼 보인다.
-> 사실 이것은 암호화가 아닌 인코딩 된거 뿐이고 실제로 이것을 디코딩 해보면 쉽게 값을 얻을 수 있다.
-> 즉, 쿠버네티스에서는 시크릿을 통해서 etcd에 저장할때 인코딩과 보여주지 않을 뿐 암호화를 통해 저장하는 것이 아니다.
-> 따라서 실제로 시크릿을 암호화 하기 위해서는 암호화 소프트웨어와 함께 사용하여야 한다

echo dmFsdWUx | base64 -d
# 디코딩을 통해 실제 값 보기 

📒 명령어를 통해 시크릿을 생성할때는 벨류값이 자동으로 인코딩되지만, yaml파일로 시크릿을 생성할때는 자동으로 인코딩되지 않기 때문에 반드시 인코딩된 값을 넣어주어야 한다.

2 . 자체 서명 인증서 생성 예시

  • letsencrypt or 가비아 같은데서 CA를 통해 인증서를 받아야하지만 도메인이 있어야하므로 자체 서명 인증서를 생성한다.

    mkdir nginx-tls/
    # 키 및 인증서 보관할 디렉터리 생성 
    openssl genrsa -out nginx-tls/nginx-tls.key 2048
    # 키 생성 
    openssl req -new -x509 -key nginx-tls/nginx-tls.key -out nginx-tls/nginx-tls.crt -days 365 -subj /CN=myapp.example.com
    # 인증서 생성 
    base64 nginx-tls.crt -w 0
    # 인증서 인코딩
    base64 nginx-tls.key -w 0
    # 키 인코딩

2-1 . 시크릿 생성

apiVersion: v1
kind: Secret
metadata:
  name: nginx-tls-secret
type: kubernetes.io/tls
data:
  tls.crt: # 인코딩한 인증서 복사
  tls.key: # 인코딩한 키 복사 

2-2 . 파드 생성

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-https
  labels: 
    suhwan: good
spec:
  containers:
  - image: nginx
    name: nginx-https
    volumeMounts:
    - name: nginx-tls-config
      mountPath: /etc/nginx/conf.d
    - name: https-cert
      mountPath: /etc/nginx/ssl
      readOnly: true
    ports:
    - containerPort: 80
      protocol: TCP
    - containerPort: 443
      protocol: TCP
  volumes:
  - name: nginx-tls-config
    configMap:
      name: nginx-tls-config
  - name: https-cert
    secret:
      secretName: nginx-tls-secret

-> 생성한 컨피그맵과 시크릿을 볼륨으로 만들어 마운트한다
-> 외부에서 접속하기 위해 label을 서비스의 label과 일치

2-3 . 컨피그맵 생성

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-tls-config
data:
  nginx-tls.conf: |
    server {
    listen              80;
    listen		          443 ssl;
    server_name         myapp.example.com;
    ssl_certificate	    /etc/nginx/ssl/tls.crt;
    ssl_certificate_key	/etc/nginx/ssl/tls.key;
    ssl_protocols	      TLSv1.2 TLSv1.3;
    ssl_ciphers		      HIGH:!aNULL:!MD5;
    location / {
        root   /usr/share/nginx/html;
        index  index.html;
      }
    }

2-4 . 서비스 생성

apiVersion: v1
kind: Service
metadata:
  name: myapp
spec: 
  type: LoadBalancer
  ports:
  - name: http
    port: 80
    targetPort: 80
  - name: https
    port: 443
    targetPort: 443
  selector:
    suhwan: good


-> 로드밸런서의 외부용 ip를 브라우저에 입력했을 때 https로 통신이 되는 것을 확인

TLS-Termination

  • ingress가 중간에서 클라이언트와 통신할때는 https(암호화 통신)을 하고 내부에서 서버와 통신할때는 http(평문 통신)하는 방식이다.
  • 만약 서비스의 규모가 커져서 파드의 개수가 많아지면 파드마다 인증서를 일일이 관리하는 것은 매우 비효율적이다.
    -> ingress에 인증서를 두어 관리하기 때문에 훨씬 효율적이다.
  • 원래는 구현이 어렵지만 쿠버네티스에서는 매우 쉽게 구현이 가능하다.

📒 TLS-Termination개념 참조

1 . 인증서 생성

mkdir ingress-tls/
# 키와 인증서 보관할 디렉터리 생성
openssl genrsa -out ingress-tls/ingress-tls.key 2048
# 키 생성
openssl req -new -x509 -key ingress-tls/ingress-tls.key -out ingress-tls/ingress-tls.crt -days 365 -subj /CN=myapp.example.com
# 인증서 생성

base64 ingress-tls.crt -w 0
# 인증서 인코딩
base64 ingress-tls.key -w 0
# 키 인코딩

2 . 시크릿 생성

apiVersion: v1
kind: Secret
metadata:
  name: myapp-tls-secret
type: kubernetes.io/tls
data:
  tls.crt: # 인코딩한 인증서 복사
  tls.key: # 인코딩한 키 복사 

3 . 인그레스 생성

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ing-tls-term
spec:
  tls:
  - secretName: myapp-tls-secret # 생성한 시크릿 
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend: 
          service:
            name: myapp-svc-np # 내부에서 서비스와 연결 
            port: 
              number: 80
              

4 . 서비스 생성

apiVersion: v1
kind: Service
metadata:
  name: myapp-svc-np
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 31111
  selector:
    app: myapp-rs

5 . 파드 생성

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myapp-rs
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp-rs
  template:
    metadata:
      labels:
        app: myapp-rs
    spec:
      containers:
      - name: myapp
        image: ghcr.io/c1t1d0s7/go-myweb:alpine
        ports:
        - containerPort: 8080
        

  • 외부에서 클라이언트가 노드의 호스트ip를 입력해서 요청하면 인그레스는 인증서를 가지고 암호화 통신(https)을 한다. 이후 tls-termination에 의해 내부에서 평문통신으로 아무 노드의 nodeport(31111)에 들어와서 clusterip가 서비스를 찾아준다.
    서비스는 프록시 역할을 통해 80을 8080으로 포트포워딩 및 엔드포인트 정보를 반영하면서 로드밸런싱으로 파드(서버)에 연결해준다
profile
성실하게 열심히!

0개의 댓글