본문 바로가기

메가존 클라우드 2기 교육/실무 특화

Kubernetes - Ingress, metallb, Volume

Ingress란?

클러스터 내의 서비스에 대한 외부 접근을 관리하는 API 오브젝트이며, 일반적으로 HTTP를 관리함.
인그레스는 부하 분산(L7 Switch 로드밸런싱), SSL 종료, 명칭 기반의 가상 호스팅을 제공할 수 있다.
인그레스는 클러스터 외부에서 클러스터 내부 서비스로 HTTP와 HTTPS 경로를 노출한다. 트래픽 라우팅은 인그레스 리소스에 정의된 규칙에 의해 컨트롤된다.


Ingress

Ingress 실습을 위한 인프라 세팅

# master1에 git 설치
yum install -y git

# git에서 ingress를 쓰기위한 파일을 가져온다.
git clone https://github.com/hali-linux/_Book_k8sInfra.git

# 가져온 yaml파일 적용
kubectl apply -f /root/_Book_k8sInfra/ch3/3.3.2/ingress-nginx.yaml

# 생성된 파드 확인 ('-n': namespace)
kubectl get pods -n ingress-nginx

## docker에서
# 실습용 폴더 생성 후 이동
mkdir test-home && cd $_

## test-home에 index.html과 images 업로드 
## 업로드한 index.hmtl의 배경색과 h1태그 변경 (home)

# tar 파일로 묶기
tar cvf food.tar index.html images

# 도커 데몬 수정
vi /etc/docker/daemon.json
//
{ "insecure-registries":["192.168.1.158:5000"] }
//

# 도커 재시작
systemctl restart docker

# 도커에서 이미지 가져오기
docker pull 192.168.1.158:5000/nginx:latest

# 도커파일 생성
vi Dockerfile
//
FROM nginx:latest
ADD food.tar /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]
//

# 도커파일 빌드
docker build -t 192.168.1.158:5000/test-home:v1.0 .

# 이미지 전송
docker push 192.168.1.158:5000/test-home:v1.0

# 컨테이너를 만들어서 이미지 확인
docker run -d -p 80:80 --name test-home 192.168.1.158:5000/test-home:v1.0




# 웹페이지 수정 (sales)
vi index.html
//
배경색: green, h1태그: sales-deploy
//

# tar파일 생성
tar cvf sales.tar images index.html

# 도커파일 수정
vi Dockerfile
//
FROM nginx:latest
ADD sales.tar /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]
//

# 도커파일 빌드 
docker build -t 192.168.1.158:5000/test-home:v2.0

# 도커 전송
docker push 192.168.1.158:5000/test-home:v2.0

# index파일 수정 (home)
vi index.html
//
배경: pink, h1태그:home-deploy
//

# tar 파일 생성
tar cvf home.tar images index.html

# 도커파일 수정
vi Dockerfile
//
FROM nginx:latest
ADD home.tar /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]
//

# 도커파일 빌드
docker build -t 192.168.1.158:5000/test-home:v0.0 .

# 도커 전송
docker push 192.168.1.158:5000/test-home:v0.0
이렇게 3개의 태그의 test/home 이미지가 있어야 한다.

## 다시 master1
# 폴더 생성 후 이동
mkdir ingress && cd $_

# ingress-deploy.yaml 생성
vi ingress-deploy.yaml
//
apiVersion: apps/v1
kind: Deployment
metadata:
  name: foods-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: foods-deploy
  template:
    metadata:
      labels:
        app: foods-deploy
    spec:
      containers:
      - name: foods-deploy
        image: 192.168.1.158:5000/test-home:v1.0
---
apiVersion: v1
kind: Service
metadata:
  name: foods-svc
spec:
  type: ClusterIP
  selector:
    app: foods-deploy
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sales-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sales-deploy
  template:
    metadata:
      labels:
        app: sales-deploy
    spec:
      containers:
      - name: sales-deploy
        image: 192.168.1.158:5000/test-home:v2.0
---
apiVersion: v1
kind: Service
metadata:
  name: sales-svc
spec:
  type: ClusterIP
  selector:
    app: sales-deploy
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: home-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: home-deploy
  template:
    metadata:
      labels:
        app: home-deploy
    spec:
      containers:
      - name: home-deploy
        image: 192.168.1.158:5000/test-home:v0.0
---
apiVersion: v1
kind: Service
metadata:
  name: home-svc
spec:
  type: ClusterIP
  selector:
    app: home-deploy
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
//    

# kubectl apply -f ingress-deploy.yaml

Ingress 사용

# ingress-config.yaml 생성
vi ingress-config.yaml
//
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ingress-nginx
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /		# rewrite: redirect 경로 재설정
spec:
  rules:	# 라우팅 규칙
  - http:
      paths:
      - path: /foods			# http 주소 경로에 '/foods'가 있다면
        backend:
          serviceName: foods-svc	# food-svc라벨인 서비스로 80포트 연결
          servicePort: 80
      - path: /sales
        backend:
          serviceName: sales-svc
          servicePort: 80
      - path:					# 아무 경로도 없는 경우
        backend:
          serviceName: home-svc
          servicePort: 80
//

# kubectl apply -f ingress-config.yaml
# kubectl get ingress ingress-nginx
# kubectl describe ingress ingress-nginx
여기서의 warning은 최신 버전이 있다는 경고창이므로 무시해도 된다.
nginx 컨트롤러를 이용해서 인그레스를 사용 중.
컨트롤러 파드가 존재한다.

# ingress-service.yaml 생성
vi ingress-service.yaml
//
apiVersion: v1
kind: Service
metadata:
  name: nginx-ingress-controller-svc
  namespace: ingress-nginx
spec:
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 80
  - name: https
    protocol: TCP
    port: 443
    targetPort: 443
  selector:
    app.kubernetes.io/name: ingress-nginx    # nginx 컨트롤러
  type: LoadBalancer
  externalIPs:
  - 192.168.2.95    # master1의 아이피
//

# kubectl apply -f ingress-service.yaml

sales
미입력

metallb

metallb 사용

# metallb.yaml 수정 (기존 이미지가 존재하지 않기 때문)
vi /root/_Book_k8sInfra/ch3/3.3.4/metallb.yaml
//
        image: 192.168.1.158:5000/metallb-speaker:0.9.3
//
        image: 192.168.1.158:5000/metallb-controller:0.9.3
//

# 도커 이미지를(speaker, controller) 내려받고 사설 레지스트리에 업로드
docker pull bitnami/metallb-speaker:0.9.3
docker pull bitnami/metallb-controller:0.9.3
docker tag bitnami/metallb-speaker:0.9.3 192.168.1.158:5000/metallb-speaker:0.9.3
docker push 192.168.1.158:5000/metallb-speaker:0.9.3
docker tag bitnami/metallb-controller:0.9.3 192.168.1.158:5000/metallb-controller:0.9.3
docker push 192.168.1.158:5000/metallb-controller:0.9.3

# 위에서 받아놨던 yaml 파일 적용
cd
kubectl apply -f /root/_Book_k8sInfra/ch3/3.3.4/metallb.yaml

# metallb-l2config.yaml 생성
vi metallb-l2config.yaml
//
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: nginx-ip-range
      protocol: layer2
      addresses:
      - 192.168.2.95    # 마스터1
      - 192.168.2.76    # 워커1
      - 192.168.2.82    # 워커2
//

# kubectl apply -f metallb-l2config.yaml
# kubectl describe configmaps -n metallb-system

태그를 달고 push한 이미지가 있는지 확인



# metallb-test.yaml 생성
vi metallb-test.yaml
//
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx-pod
spec:
  containers:
  - name: nginx-pod-container
    image: 192.168.1.158:5000/nginx:latest
---
apiVersion: v1
kind: Service
metadata:
  name: loadbalancer-service-pod
spec:
  type: LoadBalancer
#  externalIPs:
#  -
  selector:
    app: nginx-pod
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
//

# kubectl apply -f metallb-test.yaml

로드밸런서의 외부 아이피로 접속하면 nginx 웹 페이지가 뜬다. (작성자는 index.html을 변경해서 다르게 나옴)

# 이름을 다르게 하면 하나 더 배포할 수 있다
cp metallb-test.yaml metallb-test1.yaml

# vi metallb-test1.yaml
//
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod1
  labels:
    app: nginx-pod1
spec:
  containers:
  - name: nginx-pod-container1
    image: 192.168.1.158:5000/nginx:latest
---
apiVersion: v1
kind: Service
metadata:
  name: loadbalancer-service-pod1
spec:
  type: LoadBalancer
#  externalIPs:
#  -
  selector:
    app: nginx-pod1
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
//

# kubectl apply -f metallb-test1.yaml
한 개 더 배포 완료.
워커2 아이피로도 접속이 가능해졌다.

 

Volume

 Volume 관리

컨테이너 내의 디스크에 있는 파일은 임시적이며, 컨테이너에서 실행될 때 애플리케이션에 적지 않은 몇 가지 문제가 발생한다.

한 가지 문제는 컨테이너가 크래시될 때 파일이 손실된다는 것이다. kubelet은 컨테이너를 다시 시작하지만 초기화된 상태이다.

두 번째 문제는 Pod에서 같이 실행되는 컨테이너 간에 파일을 공유할 때 발생한다.

쿠버네티스는 다양한 유형의 불륨을 지원한다. 파드는 여러 불륨 유형을 동시에 사용할 수 있다. 임시 볼륨 유형은 파드의 수명을 갖지만, 퍼시스턴트 볼륨은 파드의 수명을 넘어 존재한다.


pv(Persistent Volume) / pvc

# 폴더 생성 후 이동
cd
mkdir volume && cd $_

# pv-pvc-pod.yaml 생성
vi pv-pvc-pod.yaml
//
apiVersion: v1
kind: PersistentVolume
metadata:
  name: task-pv-volume
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 10Mi    # 10MB
  accessModes:
    - ReadWriteOnce    # ReadWriteOnce(RWO) : 하나의 노드가 볼륨을 Read/Write 가능하도록 마운트
  hostPath:
    path: "/mnt/data"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: task-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Mi    # PV에 1MB만큼 요구
      
  selector:
    matchLabels:
      type: local    # PV의 라벨
---
apiVersion: v1
kind: Pod
metadata:
  name: task-pv-pod
  labels:
    app: task-pv-pod
spec:
  volumes:
    - name: task-pv-storage
      persistentVolumeClaim:
        claimName: task-pv-claim    #PVC의 이름
  containers:
    - name: task-pv-container
      image: 192.168.1.158:5000/nginx:latest
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: task-pv-storage
//

# 라벨 확인
kubectl get svc -o wide
kubectl get po --show-labels

# 라벨 수정
kubectl edit svc loadbalancer-service-pod
//
    app: task-pv-pod
//
로드밸런서의 라벨을 새로 생성한 'task-pv-pod'로 수정하여 연결되는 파드를 변경해준다.

## worker1에서
# 마운트 폴더가 잘 만들어졌는지 확인
ls /mnt/data/

# 테스트를 위해 마운트된 폴더에 index.html 파일 생성
echo "HELLO" > /mnt/data/index.html
이제 로드밸런서의 외부 아이피로 접속하면 위와 같이 페이지가 뜬다.

## master1에서
# task-pv-pod에 80포트의 노드 포트 부여 (현재 서비스가 없으므로)
kubectl expose pod task-pv-pod --name nodeport --type=NodePort --port 80

## 마운트된 폴더에 파일이 생겼으니, 파드가 지워져도 남아야한다.
# task-pv-pod 삭제
kubectl delete pod task-pv-pod

## worker1에서
# 마운트 폴더에 파일이 그대로 잇는지 확인
ls /mnt/data/
task-pv-pod 파드 삭제됨.
파드를 지워도 그대로 남아있다.

## master1에서 파드만 생성하는 템플릿 새로 생성
vi task-pv-pod.yaml
// 
apiVersion: v1
kind: Pod
metadata:
  name: task-pv-pod
  labels:
    app: task-pv-pod
spec:
  volumes:
    - name: task-pv-storage
      persistentVolumeClaim:
        claimName: task-pv-claim    #PVC의 이름
  containers:
    - name: task-pv-container
      image: 192.168.1.158:5000/nginx:latest
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: task-pv-storage
//

# 템플릿 적용
kubectl apply -f task-pv-pod.yaml

# pv, pvc 정보 확인
kubectl get pv,pvc

 RECLAIM POLICY가 "Retain"인 경우에는 PVC가 지워져도 PV의 데이터들을 남기지만, "Delete"인 경우네는 같이 사라진다.

 STATUS가 "BOUND"인 경우는 잘 연결된 상태이다.

## 확인을 위해 pvc를 삭제

# protection 해제
kubectl patch pvc task-pv-claim -p '{"metadata":{"finalizers":null}}'

# pvc 삭제
kubectl delete pvc task-pv-claim
삭제 완료.