로컬 서버에 k8s cluster 환경 구성하기 part 1 (kind, nginx)

Published: by Creative Commons Licence

Intro

이제까지 저는 이미 잘 구성된 k8s cluster환경에서 어떻게 활용할 수 있는지에 대해서만 다뤄 왔습니다. 하지만 사용하면서 계속 언젠가는 직접한번 구축해보고 모르는 개념들을 다뤄보고 싶었습니다. 이번에 큰맘 먹고 한번 작업해보려고 합니다. k8s cluster를 구성하는데에서 시작하여 airflow를 k8s 환경에서 동작하도록 구성하는것이 목표입니다. part1, 이번 포스트에는 k8s를 구축하는 부분부터 docker container로 관리하던 nginx를 k8s로 옮겨낸 과정까지 담아보겠습니다.

  • ☑ k8s cluster 설치
  • ☑ nginx 구성
  • ☐ rancher 구성
  • ☐ ceph storage 구성
  • ☐ airflow (iceberg, hive, spark, trino) 구성…

kind install

먼저 on-premise환경에서 k8s를 구성하는 방법이 몇가지가 있는데 크게 고민하지 않고 docker container 수준에서 관리 할 수 있는 kind를 사용하기로 정했습니다. 일단 설치부터 진행했습니다.

curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.24.0/kind-linux-amd64
chmod +x ./kind
mv ./kind /usr/local/bin/kind

kubectl install

k8s를 쉽게 관리할 수 있는 도구 kubectl 을 또한 설치합니다.

curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
mv kubectl /usr/local/bin

create cluster

설치 하였던 kind를 이용하여 cluster를 아래와 같이 띄웁니다. image는 https://github.com/kubernetes/ingress-nginx 의 표를 참고하여 정하였습니다. stable한 ingress-nginx는 v1.11.3까지 였고, k8s supported version이 1.30입니다. ingress-nginx는 무엇이고 왜 사용하는지 천천히 살펴보겠습니다.

kind create cluster --name 000namc --image kindest/node:v1.30.0
kubectl get nodes

helm

k8s를 사용하면 많은 yaml파일들을 관리하게되는데, 이를 효율적으로 사용할 수 있도록 도와주는게 helm이라고 합니다. https://github.com/helm/helm 에서 확인할 수 있고, cicd를 구성할때 잘 활용하면 좋겠다 싶고 k8s를 많이 활용하는 분들은 기본적으로 쓰는듯 보여서 일단 사용하기로 마음먹었습니다.

curl -LO https://get.helm.sh/helm-v3.16.2-linux-amd64.tar.gz
tar -C /tmp/ -zxvf helm-v3.16.2-linux-amd64.tar.gz
rm helm-v3.16.2-linux-amd64.tar.gz
mv /tmp/linux-amd64/helm /usr/local/bin/helm
chmod +x /usr/local/bin/helm

nodeport : loadbalencer : ingress

nodeport, loadbalencer, ingress는 container들을 외부에서 접근할 수 있게 도와주는 설정입니다. 여러가지 선택지가 있었는데, 이 중 ingress를 활용하려합니다. nodeport는 설정은 간단해보이지만 각 pod마다 설정해줘야한다는 불편함이 있어보였고, loadbalencer는 클라우드 환경에서 활용하는 방법으로 보였습니다. ingress의 경우, 초반 설정은 좀 복잡할 수 있으나 도메인을 효율적으로 관리할 수 있고 특히 리버스 프록시의 형태로 활용할 수 있다는점에서 채택하였습니다.

ingress는, ingress와 ingress controller로 나뉩니다. 우선 ingress는 외부 요청을 k8s내 서비스로 라우팅하는 규칙을 정의하는 API객체 라고 설명할 수 있겠습니다. ingress controller는 이러한 ingress 규칙을 기준으로 실제 동작을 수행해주는 도구 입니다.

install and deploy controller with helm

아래와 같이 먼저 controller를 helm을 이용하여 install 및 deploy 하였습니다.

kubectl create namespace ingress-nginx

CHART_VERSION="4.11.3"
# APP_VERSION="1.11.3"

helm install ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --version ${CHART_VERSION} \
  --namespace ingress-nginx \
  --set controller.ingressClass=nginx

kubectl -n ingress-nginx get pods
kubectl -n ingress-nginx get svc

secret 생성

ingress의 HTTPS 포트를 사용하기 위해 secret을 생성하였습니다.

kubectl create secret tls 1st-secret \
  --key /app/nginx/letsencrypt/live/000namc.xyz/privkey.pem \
  --cert /app/nginx/letsencrypt/live/000namc.xyz/cert.pem

deploy nginx service

nginx를 구동시키기 위한 service.yaml과, 외부와의 라우팅 규칙을 정의하는 ingress.yaml를 각각 작성하고 아래와같이 deploy 하였습니다.

kubectl apply -f /app/k8s/nginx/service.yaml  
kubectl apply -f /app/k8s/nginx/ingress.yaml
# kubectl get ingress 
# kubectl delete -f /app/k8s/nginx/service.yaml  
# kubectl delete -f /app/k8s/nginx/ingress.yaml
  • service.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: nginx-svc.conf
    data:
      nginx.conf: |   
        user nginx;
        worker_processes 1;
        pid /var/run/nginx.pid;
    
        events {
    	worker_connections 1024;
        }
    
        http {
    
    	sendfile on;
    	keepalive_timeout 65;
    
    	server {
    	    listen 80;
    
    	server_name localhost;
    
    	location /nginx {
    	    alias /app/data/nginx;
    	    autoindex on;
    	}
    	}
        }
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-svc
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
    	app: nginx
        spec:
          containers:
          - name: nginx
    	image: nginx:1.25.5
    	ports:
    	- containerPort: 80
    	volumeMounts:
    	- name: nginx-config
    	  mountPath: /etc/nginx/
    	- name: nginx-data
    	  mountPath: /app/data/nginx
          volumes:
          - name: nginx-config
    	configMap:
    	  name: nginx-svc.conf
          - name: nginx-data
    	hostPath:
    	  path: /app/data/nginx
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-svc  
    spec:
      selector:
        app: nginx      
      ports:
        - protocol: TCP
          port: 80      
          targetPort: 80 
    
  • ingress.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: nginx-svc
    spec:
      ingressClassName: nginx
      tls:
      - hosts:
        - 000namc.xyz
        secretName: 1st-secret
      rules:
      - host: 000namc.xyz
        http:
          paths:
          - path: /nginx
    	pathType: Prefix
    	backend:
    	  service:
    	    name: nginx-svc
    	    port:
    	      number: 80
    

port-forwarding

마지막으로 ingress controller를 외부에서 접근 가능하도록 port-forwarding을 설정했습니다.

kubectl -n ingress-nginx port-forward --address 0.0.0.0 svc/ingress-nginx-controller 443
# kubectl port-forward --address 0.0.0.0 svc/nginx-svc 80:80
# kubectl cp /app/data/nginx (pod name):/app/data

이렇게해서 docker container로 관리하던 nginx를 새롭게 구축한 k8s cluster위에 성공적으로 deploy하였습니다. 새롭게 동작하는 nginx는 여전히 https://000namc.xyz/nginx/ 에서 확인 가능합니다!