본문 바로가기
프로그램 활용/인공지능(AI)

Ubuntu 20.04 + Docker 20.04 + Kubernetes 1.23.6 +Django 4.0.3 + React 18.0 +MySql 8.0.28 +Machine Learning : pytorch 1.11.0 cuda 10.2

by 3604 2023. 8. 3.
728x90

출처: https://d-life93.tistory.com/461?category=1013222

목차

쿠버네티스 설치부터 서비스 배포까지 - 1.도커 설치
쿠버네티스 설치부터 서비스 배포까지 - 2.쿠버네티스 설치
쿠버네티스 설치부터 서비스 배포까지 - 2-1. 쿠버네티스 재설치
쿠버네티스 설치부터 서비스 배포까지 - 3.쿠버네티스 Ingress Nginx 생성
쿠버네티스 설치부터 서비스 배포까지 - 4.NFS 설치
쿠버네티스 설치부터 서비스 배포까지 - 5.데이터베이스 설정
쿠버네티스 설치부터 서비스 배포까지 - 6.프론트엔드 설정
쿠버네티스 설치부터 서비스 배포까지 - 7.백엔드 설정
쿠버네티스 설치부터 서비스 배포까지 - 8.결과화면

1.도커 설치

인트로

들어가기에 앞서 저는 도커, 쿠버네티스를 이렇게 시작했습니다.

도커에 대해자도 모르던 어느 갑작스레 도커를 이용한 컨테이너화를 통해 프로젝트를 진행해야 했습니다. 도커를공식 가이드 통해 공부하면서 순수도커” + “도커 파일” + “도커 컴포즈 이용해 프로젝트 제작까지  1 정도 소요 같습니다.

글을 읽는 분들도 시간을 조금만 투자하면 하실 있다는 것을 말씀드리고 싶었습니다.

느껴본 바로는 우선 쿠버네티스를 이해하고 사용하기 위해서는 적어도 도커 어느 정도 사용 해봤어요! 그리고 어느 정도 알아요!정도는 돼야 하는 같습니다.

해당 글은 도커를 이용한 프로젝트 이후 쿠버네티스를 공부하며 제작해보는 글이며 저는 쿠버네티스 전문가가 아닙니다.

그래도 아예 시작할 엄두도 나지 않는 사람들이 쿠버네티스 + 백엔드 + 프론트엔드 + 데이터베이스 + 머신러닝 (kubernetes + backend + frontend + database + machine learning) 어떻게 연결해야 제가 고민해보며 테스트 하면서 만든 프로젝트를 정리해 놓은 글을 통해 도움이 되길 바랍니다.

백엔드는 장고, 프론트는 리액트를 사용해봤습니다.

가지의 프레임워크도 처음 사용해보는 거라 진행하기 쉽지는 않았네요 ^^;

글은 쿠버네티스에 대해 깊이 파는 방식으로 작성하지 않았습니다.

따라하며 만들어 보는 것에 목적 있으며 따라하면서 중간 중간 이걸 이렇게 했는지 *쿠버네티스 공식 문서 보면서 또는 *구글 검색 통해 채워나가면 좋을 같습니다.

쿠버네티스가 분명 어렵게 느껴질 수도 있기는 하지만 천천히 하나 풀어나가 보니 볼만 같습니다. 물론 깊은 핵심 기술에 대해서는 확실히 공부 해야겠지요 ^^

저도 여러분도 화이팅 입니다.

추가 당부할 사항으로 설치 방법이 무조건 맞다! 생각하지 말고 안되시면 공식 문서나 다른 방법을 찾아보시기 바랍니다.

저도 처음에 다른 사람들이 작성한 쿠버네티스 설치 방법을 여럿 사용해 봤는데 1년도 지나지 않은 대로 해도 계속 오류가 발생했습니다. 쿠버네티스가 버전이 업데이트 되어 설치 방법이 추가 또는 수정되었기 때문이겠죠?

* 그냥 따라하는 타입이 아니라 이것저것 만져보고 다른 방법으로 시도해 보는 타입이라 오래 걸렸네요 ㅎㅎ;

 

글에서 사용한 버전은 다음과 같습니다.

·        Ubuntu : 20.04

·        Docker : 20.04

·        Kubernetes : 1.23.6

·        Django : 4.0.3

·        React : 18.0.0

·        MySql : 8.0.28

·        Machine Learning : pytorch 1.11.0 cuda 10.2

 

환경은 어떻게 구성하나?

클라우드 환경에서 최소 3개의 서버가 있다는 가정 하에 연습 한다면 가장 좋겠지만 ....

실제로 사용하기 위해서는 도커 이미지 레지스트리도 필요하고 이거저거 필요한 사항이 많습니다.

그렇기 때문이 과정의 환경은 하나의 linux os에서 진행됩니다. Linux 환경 on-premise 환경의 또는 윈도우의 Virtualbox 가상환경에서 Linux 설치하셔도 상관없습니다.

그저 여러 개의 서버를 상용 노드의 구성, pod 구성이 어떻게 되는지 이해만 하시면 좋을 같습니다

제가 만든 과정은 그냥 맛만 보기 위한 것이니까요

맛이라도 보시고 제대로 만들어 보세요~

·        Virtual Box 환경에서 진행하고자 경우 다음 URL 참고

·        Virtual Box 설치 생성https://youtu.be/PqgWp7rbqws

·        우분투 설치https://youtu.be/REYVRyXdSKU

django react machine learning 제가 작성해 놓은 git 또는 colab 코드가 제공될 예정입니다.

 

해당 파트 참고 URL

·        https://docs.docker.com/get-started/overview/

 

본문

·        https://docs.docker.com/engine/install/ubuntu/

 

 

Install Docker Engine on Ubuntu

 

docs.docker.com

 

 

도커 설치 Set up the repository

sudo apt-get update

 

sudo apt-get install -y \

     ca-certificates \

     curl \

     gnupg \

     lsb-release

 

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

 

echo \

  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \

  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

 

도커 설치

sudo apt-get update

 

sudo apt-get install -y docker-ce docker-ce-cli containerd.io

 

도커가 올바르게 설치 되었는지 테스트 이미지 실행

sudo docker run hello-world

*참고: docker run --privileged... /sbin/init 으로 실행해야 도커에서 작업하기 편함.(단, 보안상은 적합하지 않음)

도커 실행 루트 권한을 현재 아이디에 부여하기

아무런 조치 없이 도커를 사용하면 계속해서 sudo 쳐야하는데요

다음과 같이 미리 권한을 부여하면 sudo 없이도 사용이 가능합니다

sudo usermod -aG docker ${USER}

sudo service docker restart

sudo su - ${USER}

 

or

 

sudo reboot

 

--------------------------------------------------------------------------------------------------------------------------------

2.쿠버네티스 설치

 *  참고:  rocky9 쿠버네티스 설치 https://3604.tistory.com/660

해당 파트 참고 URL

·        https://kubernetes.io/ko/docs/concepts/overview/what-is-kubernetes/

·        https://kubernetes.io/ko/docs/setup/production-environment/_print/#도커

 

 

프로덕션 환경

프로덕션 수준의 쿠버네티스 클러스터 생성

kubernetes.io

  

본문

Install kubeadm

·        https://kubernetes.io/ko/docs/setup/production-environment/tools/kubeadm/install-kubeadm/

  

kubeadm 설치하기

페이지에서는 kubeadm 툴박스 설치 방법을 보여준다. 설치 프로세스를 수행한 kubeadm으로 클러스터를 만드는 방법에 대한 자세한 내용은 kubeadm 사용하여 클러스터 생성하기 페이지를

kubernetes.io

쿠버네티스를 설치하기 전에 swap 종료

swap 해제는 필수이며 Master Server Node Server 모두 설정해줘야 합니다.

sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

 

쿠버네티스 설치 세팅

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
 
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF

 

쿠버네티스 패키지 설치 kubeadm, kubelet, kubectl

·        kubeadm : 클러스터를 구축하기 위한

·        kubelet : 클러스터의 노드에서 실행되는 에이전트이며 파드에서 컨테이너가 정상적으로 동작하도록 관리

·        kubectl : 클러스터와 통신하기 위한 명령 util

sudo apt-get update
 
sudo apt-get install -y apt-transport-https ca-certificates curl vim
 
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
 
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet=1.23.6-00 kubeadm=1.23.6-00 kubectl=1.23.6-00
sudo apt-mark hold kubelet kubeadm kubectl

 

도커 systemd 사용하도록 한다

·        https://kubernetes.io/ko/docs/setup/production-environment/container-runtimes/

컨테이너 런타임

파드가 노드에서 실행될 수 있도록 클러스터의 각 노드에 컨테이너 런타임을 설치해야 한다. 이 페이지에서는 관련된 항목을 설명하고 노드 설정 관련 작업을 설명한다. 쿠버네티스 1.24에서는

kubernetes.io

 

sudo mkdir /etc/docker
cat <<EOF | sudo tee /etc/docker/daemon.json
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF

 

도커에 코드 적용되도록 재시작

sudo systemctl enable docker

 

sudo systemctl daemon-reload
sudo systemctl restart docker

 

Master Control-plane 구성

kubeadm 실행하기에 앞서 kubeadm 사용이 가능한 선결 조건을 확인해야 합니다.

https://kubernetes.io/ko/docs/setup/production-environment/tools/kubeadm/install-kubeadm/

kubeadm 설치하기

이 페이지에서는 kubeadm 툴박스 설치 방법을 보여준다. 이 설치 프로세스를 수행한 후 kubeadm으로 클러스터를 만드는 방법에 대한 자세한 내용은 kubeadm을 사용하여 클러스터 생성하기 페이지를 참

kubernetes.io

마스터가 서버에서 실행해야 합니다

kubeadm init --pod-network-cidr=192.168.0.0/16 

클러스터 사용을 위한 유저 권한

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

 

아래에 있는 join 토큰은 Node에서 Master 서버로 Join 하기 위해 사용하면 됩니다!

쿠버네티스 클러스터 Network 통신을 위한 Calico 설치

·        https://github.com/containernetworking/cni

GitHub - containernetworking/cni: Container Network Interface - networking for Linux containers

Container Network Interface - networking for Linux containers - GitHub - containernetworking/cni: Container Network Interface - networking for Linux containers

github.com

·        https://projectcalico.docs.tigera.io/getting-started/kubernetes/quickstart

 

Quickstart for Calico on Kubernetes

Install Calico on a single-host Kubernetes cluster for testing or development in under 15 minutes.

projectcalico.docs.tigera.io

 

#kubectl create -f https://projectcalico.docs.tigera.io/manifests/tigera-operator.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/tigera-operator.yaml
#kubectl create -f https://projectcalico.docs.tigera.io/manifests/custom-resources.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/custom-resources.yaml

 

칼리코 설치 확인

watch kubectl get pods -n calico-system

 

포드 예약 있도록 마스터에서 taint 제거

# node/<your-hostname> untainted --> 이것을 반환해야 한다
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
kubectl taint nodes --all node-role.kubernetes.io/master-

 

bash Completion 활성화

sudo apt-get install -y bash-completion
source /usr/share/bash-completion/bash_completion
echo 'source <(kubectl completion bash)' >>~/.bashrc

kubectl 사용시 명령어 또는 Pod Service 명칭이 아주 경우가 있습니다.

이러한 경우 bash Completion 통해 편리하게 사용이 가능합니다.

사용법은 Tab 버튼 누르면 됩니다.

# 예시
pod의 이름이 backend-djhn2jdy1151.jdjvmnejd
 
위와 같은 상황에서 다음과 같이 작성하고
kubectl get pod back
 
Tap을 누를경우
kubectl get pod backend-djhn2jdy1151.jdjvmnejd
 
자동으로 완성이 됩니다

 

Worker Node 구성

하나의 서버에서만 만들면서 진짜 경험만 것이라면 노드 서버를 구성하지 않아도 되겠지만 노드 서버 구축이 가능할 경우 추후 컨테이너를 생성하게 되면 Kubernetes 의해 노드 별로 자동으로 Pod, Deployment, ReplicaSet 등등이 어떻게 나눠지게 되는지 오케스트레이션이 무엇인지 눈으로 확인 있습니다.

실제로 사용하기 위해서는 cloud 도커 이미지가 저장되는 요소를 추가해야 자신이 만든 도커 이미지를 사용이 가능할 것입니다

거기까지는 시간이 너무 오래 걸리기 때문에 과정에서는 하나의 리눅스 시스템에서 먼저 맛보기만 겪어보시기 바랍니다 ^^

그렇기 때문에 워커 노드 구성은 그냥 이런 것이 있구나? 아시면 같습니다

 

kubeadm join실행

# 위에서 저장해 놓은 토큰을 실행합니다.
kubeadm join 10.100.0.10:6443 --token zo0mli.iads9quw4wu8xij1 \
        --discovery-token-ca-cert-hash sha256:8fef81bc6a0f5d7212adfbb37e783554393cdca9f5a35c8a020b33d1e93baffa

·        만약 preflight Running pre-flight checks에서 멈춰있을 경우 방화벽이 실행되고 있지 않은지 확인하시기 바랍니다.
방화벽에 막혀 조인하지 못하고 있는 상태이기 때문에 방화벽을 해제 해줘야 합니다

sudo ufw allow 6443 sudo ufw allow 2379 sudo ufw allow 2380 sudo ufw allow 10250 sudo ufw allow 10251 sudo ufw allow 10252 sudo ufw reload

상태 확인

kubectl get nodes


 

기타

토큰 새로 만들기

토큰은 유효기간이 있습니다

유효기간이 지나면 더이상 join 하지 못하는데요 새로운 토큰을 생성해서 join 있도록 합니다

### kubeadm join token 
 
# 토큰 확인
kubeadm token list
 
# 토큰 생성
kubeadm token create
# bjniqn.n228af9ywbq9o0cq
 
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
# e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
 
# 위에서 생성한 값을 아래 명령과 같이 입력
# kubeadm join 000.000.000.000:6443 --token { create 값 } --discovery-token-ca-cert-hash sha256:{ ssl 값 }
예시
kubeadm join 10.100.0.10:6443 --token bjniqn.n228af9ywbq9o0cq --discovery-token-ca-cert-hash sha256:3e6723b089a00a1acc09134e9eac963eeb5c080482041c33b6dd42b8a50c92e1

 

Unable to connect to the server: x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "kubernetes")

해당 오류가 계속해서 발생할 경우 설정이 꼬여있는 것입니다.

다음 방법을 통해 조치합니다.

unset KUBECONFIG
 
mv  $HOME/.kube $HOME/.kube.bak
 
mkdir $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

 

 

·        만약 preflight Running pre-flight checks에서 멈춰있을 경우 방화벽이 실행되고 있지 않은지 확인하시기 바랍니다.
방화벽에 막혀 조인하지 못하고 있는 상태이기 때문에 방화벽을 해제 해줘야 합니다

sudo ufw allow 6443 sudo ufw allow 2379 sudo ufw allow 2380 sudo ufw allow 10250 sudo ufw allow 10251 sudo ufw allow 10252 sudo ufw reload

 

상태 확인

kubectl get nodes

 


 

2-1. 쿠버네티스 재설치

 

쿠버네티스를 처음 설치하거나 작업하다 보면 재설치 하게 되는 순간이 발생합니다.

부득이 모든 자료가 증발하더라도 재설치 하겠다면 다음과 같이 진행하면 되겠습니다.

그리고 처음에 연습 때는 웬만한 고쳐지지 않는 오류는 재설치 하는 것이 정신 건강에 이로울 있습니다...

저는 설치를 이리저리 다른 방법으로 시도하다 에러에 파묻혀 고치고 재설치하고 반복하느라 진짜 적어도 7일은 날라간 같네요

물론 지금은 재설치만 수십 하다 보니까 이거 하지 말아야지! 저거 설치 해야지! 하는 것이 눈에 보이긴 합니다.

다만 ... 이렇게 하지 않고 쭈욱 제대로 설치해보는 것이 효율적일 있습니다 ^^;

 

kubeadm Master Node 모두 리셋

kubeadm reset

 

쿠버네티스, 도커 정지 쿠버네티스 관련 모든 파일, 네트워크 삭제

systemctl stop kubelet
systemctl stop docker
 
rm -rf /var/lib/cni/
rm -rf /var/lib/kubelet/
rm -rf /run/calico   # 설치한 cni를 삭제
rm -rf /etc/cni/
rm -rf /etc/kubernetes
rm -rf /root/.kube/
rm -rf /root/.k8s/
rm -rf /var/lib/etcd/
 
ip link delete cni0   # 설치한 cni의 네트워크 인터페이스 삭제
ip link delete calico   # 설치한 cni의 네트워크 인터페이스 삭제

 

쿠버네티스 패키지 삭제

sudo apt remove --purge kubelet kubectl kubeadm
 
sudo apt autoremove

 

도커 재시작

systemctl start docker

 

2.쿠버네티스 설치부터 다시 시작

https://d-life93.tistory.com/450

3.쿠버네티스 Ingress Nginx 생성

해당 파트 참고 URL

·        https://kubernetes.io/ko/docs/concepts/services-networking/ingress/

·        https://kubernetes.github.io/ingress-nginx/deploy/#quick-start

·        https://kubernetes.io/ko/docs/tasks/access-application-cluster/ingress-minikube/

 

NGINX 인그레스(Ingress) 컨트롤러로 Minikube에서 인그레스 설정하기

인그레스는 클러스터의 서비스에 대한 외부 액세스를 허용하는 규칙을 정의하는 API 객체이다. 인그레스 컨트롤러는 인그레스에 설정된 규칙을 이행한다. 이 페이지에서는 HTTP URI에 따라 요청을

kubernetes.io

 

인그레스(Ingress)

FEATURE STATE: Kubernetes v1.19 [stable] 클러스터 내의 서비스에 대한 외부 접근을 관리하는 API 오브젝트이며, 일반적으로 HTTP를 관리함. 인그레스는 부하 분산, SSL 종료, 명칭 기반의 가상 호스팅을 제공

kubernetes.io

Installation Guide - NGINX Ingress Controller

Installation Guide There are multiple ways to install the NGINX ingress controller: with Helm, using the project repository chart; with kubectl apply, using YAML manifests; with specific addons (e.g. for minikube or MicroK8s). On most Kubernetes clusters,

kubernetes.github.io

NGINX 인그레스(Ingress) 컨트롤러로 Minikube에서 인그레스 설정하기

인그레스는 클러스터의 서비스에 대한 외부 액세스를 허용하는 규칙을 정의하는 API 객체이다. 인그레스 컨트롤러는 인그레스에 설정된 규칙을 이행한다. 이 페이지에서는 HTTP URI에 따라 요청을

kubernetes.io

인그레스는 클러스터 내부 서비스에 대한 접근을 관리하는 API 오브젝트이며 보안, 라우팅, 로드밸런싱 역할이 가능합니다.

아래 사진은 쿠버네티스 가이드에 있는 사진으로 인그레스가 어떠한 Flow(흐름) 가지고 있는지 상상해 있는 좋은 예시가 되겠습니다.

 

Ingress flow

Ingress Path flow Example

sudo mkdir -p /home/kube
cd /home/kube

 

Ingress-nginx 구성

앞으로 작성할 것들은 모두 Master 서버에서 사용하면 되겠습니다.

ingress-nginx Deploy(배포) 합니다

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.2/deploy/static/provider/baremetal/deploy.yaml

·        다음 명령어를 사용하면 namespace ingress-nginx 공간에
위에서 받은 설정들이 구성되어 있습니다.

kubectl get pod -n ingress-nginx -w

쿠버네티스 ingress 생성

·        위에서 다운 받은 설정들을 이용해 ingress 사용, service별로 path 주소에 따라 로드밸런싱 있습니다

·        예제는 frontend backend 연결할 path 작성해 놓았습니다

$sudo vim toy_ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: toy-ingress
  annotations:
    #kubernetes.io/ingress.class: "nginx"
    spec.ingressClassName: "nginx"
spec:
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend-service
            port:
              number: 80
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: backend-service
            port:
              number: 8000

 

yaml 파일을 실행해줍니다

kubectl apply -f toy_ingress.yaml

 

생성 결과

kubectl get ing

 

kubectl get svc -o wide -n ingress-nginx

Port번호 변경

현재 과정에 맞추기 위해노드 포트 수정하도록 하겠습니다

다음 코드를 실행시켜 service 설정에 대해 수정이 가능합니다

kubectl edit svc ingress-nginx-controller -n ingress-nginx

 

위에 http 위치의노드 포트 31845 수정 합니다.

다시 확인하면 변경된 것을 확인 있습니다

 

kubectl get svc -o wide -n ingress-nginx

 

인그레스 Path 예시

4.NFS 설치

해당 파트 참고 URL

·        https://kubernetes.io/ko/docs/concepts/storage/volumes/

·        https://kubernetes.io/ko/docs/concepts/storage/persistent-volumes/

https://kubernetes.io/ko/docs/concepts/storage/storage-classes/

볼륨

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

kubernetes.io

 

 

 

퍼시스턴트 볼륨

페이지에서는 쿠버네티스의 퍼시스턴트 볼륨 대해 설명한다. 볼륨에 대해 익숙해지는 것을 추천한다. 소개 스토리지 관리는 컴퓨트 인스턴스 관리와는 별개의 문제다. 퍼시스턴트볼륨

kubernetes.io

 

 

스토리지 클래스

문서는 쿠버네티스의 스토리지클래스의 개념을 설명한다. 볼륨과 퍼시스턴트 볼륨에 익숙해지는 것을 권장한다. 소개 스토리지클래스는 관리자가 제공하는 스토리지의 "classes" 설명할

kubernetes.io

* rocky9 리눅스 NFS 설치 참조할 것: How to Set Up an NFS Mount on Rocky Linux 9 (tistory.com)

 

sudo apt-get update
sudo apt-get install -y nfs-kernel-server nfs-common

 

NFS 공유할 디렉토리 생성 권한 부여

sudo mkdir -p /nfs_share
sudo chmod 777 /nfs_share

 

공유할 클라이언트 ip 설정

sudo vim /etc/exports
# /etc/exports: the access control list for filesystems which may be exported
#               to NFS clients.  See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes       hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4        gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes  gss/krb5i(rw,sync,no_subtree_check)
#
#공유할 폴더, 공유할 아이피(권한)
/nfs_share 10.100.0.0/24(rw,fsid=0,async,no_subtree_check,no_auth_nlm,insecure,no_root_squash)

 

nfs-server 시작 활성화

sudo systemctl start nfs-server.service
sudo systemctl enable nfs-server.service
sudo exportfs -a

 

·        nfs-server 재배포시 사용

·        sudo exportfs -a

NFS 허용된 리스트 확인

sudo showmount -e

“Client 사용될 서버에서 사용하기 위해서는 마운트를 합니다

nfs 설치된 server 마운트 client 서버에서 연결해야 합니다.

https://ubuntu.com/server/docs/service-nfs

Service - NFS | Ubuntu

Ubuntu is an open source software operating system that runs from the desktop, to the cloud, to all your internet connected things.

ubuntu.com

sudo apt-get install -y nfs-common
sudo mkdir -p /home/nfs_share
sudo mount 10.100.0.10:/nfs_share /home/nfs_share

 

5.데이터베이스 설정

해당 파트 참고 URL

·        https://kubernetes.io/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/

·        https://kubernetes.io/ko/docs/concepts/configuration/configmap/

·        https://kubernetes.io/ko/docs/concepts/configuration/secret/

예시: WordPress MySQL을 퍼시스턴트 볼륨에 배포하기

이 튜토리얼은 WordPress 사이트와 MySQL 데이터베이스를 Minikube를 이용하여 어떻게 배포하는지 보여준다. 애플리케이션 둘 다 퍼시스턴트 볼륨과 퍼시스턴트볼륨클레임을 데이터를 저장하기 위해

kubernetes.io

 

 

컨피그맵(ConfigMap)

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

kubernetes.io

시크릿(Secret)

시크릿은 암호, 토큰 또는 키와 같은 소량의 중요한 데이터를 포함하는 오브젝트이다. 이를 사용하지 않으면 중요한 정보가 파드 명세나 컨테이너 이미지에 포함될 수 있다. 시크릿을 사용한다

kubernetes.io

cd /home/kube

 

·        도커로 이미지 빌드 생성 다음과 같이 env 파일을 만들어 사용 가능합니다.

MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_DATABASE=toy
MYSQL_USER=user
MYSQL_PASSWORD=password
MYSQL_ROOT_PASSWORD=password

 

·        우리는 쿠버네티스의 방법인 seceret configmap 사용 해보겠습니다.

시크릿 생성 password base64 Encode

·        아래 password 비밀번호이며 기본적으로 쿠버네티스로 시크릿 키를 사용할 경우 자동 디코딩 된다

echo -n password | base64

 

Mysql 시크릿 생성

sudo vim toy_mysql_secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
type: Opaque
data:
  password: cGFzc3dvcmQ=
  root_password: cm9vdA==
kubectl apply -f toy_mysql_secret.yaml
kubectl get secret

 

생성 확인

 

Mysql 컨피그맵 생성

sudo vim toy_mysql_config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
data:
  host: "localhost"
  port: "3306"
  database: "toy"
  user: "user"
kubectl apply -f toy_mysql_config.yaml
kubectl get configmap

생성 확인

 

Mysql PV, PVC

sudo vim toy_mysql_pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv-volume
  labels:
    type: local
spec:
  storageClassName: nfs-client
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/nfs_share"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
spec:
  storageClassName: nfs-client
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
kubectl apply -f toy_mysql_pv.yaml
kubectl get pv,pvc

생성 확인

 

Mysql Service && deployment

sudo vim toy_mysql.yaml
apiVersion: v1
kind: Service
metadata:
  name: mysql-service
spec:
  selector:
    app: mysql
  type: NodePort
  ports:
  - protocol: TCP
    port: 3306
    nodePort: 31003
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-deployment
spec:
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: Recreate
  replicas: 1
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0.28
        ports:
        - containerPort: 3306
        env:
          - name: MYSQL_HOST
            valueFrom:
              configMapKeyRef:
                name: mysql-config
                key: host
          - name: MYSQL_PORT
            valueFrom:
              configMapKeyRef: 
                name: mysql-config
                key: port
          - name: MYSQL_DATABASE
            valueFrom:
              configMapKeyRef:
                name: mysql-config
                key: database
          - name: MYSQL_USER
            valueFrom:
              configMapKeyRef:
                name: mysql-config
                key: user
          - name: MYSQL_ROOT_PASSWORD
            valueFrom:
              secretKeyRef:
                name: mysql-secret
                key: root_password
          - name: MYSQL_PASSWORD
            valueFrom:
              secretKeyRef:
                name: mysql-secret
                key: password
        volumeMounts:
        - name: mysql-config
          mountPath: "/config"
          readOnly: true
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
        - name: mysql-config
          configMap:
            name: mysql-config
            items:
              - key: "host"
                path: "host"
              - key: "port"
                path: "port"
              - key: "database"
                path: "database" 
              - key: "user"
                path: "user"
        - name: mysql-persistent-storage
          persistentVolumeClaim:
            claimName: mysql-pv-claim
kubectl apply -f toy_mysql.yaml
kubectl get deploy,svc,pod

참고---

apiVersion: v1
kind: Service
metadata:
  name: mysql-service
spec:
  selector:
    app: mysql
  type: NodePort
  ports:
    - protocol: TCP
      port: 3306
      nodePort: 31002

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-deployment
spec:
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: Recreate
  replicas: 1
  template:
    metadata:
     labels:
      app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        ports:
        - containerPort: 3306
        env:
        - name: MYSQL_HOST
          valueFrom:
            configMapKeyRef:
              name: mysql-config
              key: host
        - name: MYSQL_PORT
          valueFrom: 
            configMapKeyRef:
              name: mysql-config
              key: port
        - name: MYSQL_DATABASE
          valueFrom: 
            configMapKeyRef:
              name: mysql-config
              key: database
        - name: MYSQL_USER
          valueFrom: 
            configMapKeyRef:
              name: mysql-config
              key: user
        - name: MYSQL_ROOT_PASSWORD
          valueFrom: 
            secretKeyRef:
              name: mysql-secret
              key: root_password
        - name: MYSQL_PASSWORD
          valueFrom: 
            secretKeyRef:
              name: mysql-secret
              key: password
        volumeMounts:
        - name: mysql-config
          mountPath: /config
          readOnly: true
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-config
        configMap:
          name: mysql-config
          items:
          - key: host
            path: host
          - key: port
            path: port
          - key: database
            path: database
          - key: user
            path: user
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim

---

생성 확인

6.프론트엔드 설정

해당 파트 참고 URL

·        https://docs.docker.com/engine/reference/builder/

·        https://kubernetes.io/ko/docs/tasks/access-application-cluster/connecting-frontend-backend/

·        https://ko.reactjs.org/tutorial/tutorial.html

Dockerfile reference

 

docs.docker.com

 

 

서비스를 사용하여 프론트엔드를 백엔드에 연결

작업은 프론트엔드 백엔드 마이크로서비스를 어떻게 생성하는지를 설명한다. 백엔드 마이크로서비스는 인사하기(hello greeter)이다. 프론트엔드는 nginx 쿠버네티스 서비스 오브젝트를

kubernetes.io

 

 

자습서: React 시작하기 – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

프론트엔드는 제가 작성한 React Code 사용했습니다.

돌아가게만 만든 것이기 때문에 퀄리티가 좋지 않긴 한데... 궁금하신 분은 https://github.com/kschoi93/k8s_frontend.git 확인하시면 같습니다

 

 

GitHub - kschoi93/k8s_frontend: k8s_frontend

k8s_frontend. Contribute to kschoi93/k8s_frontend development by creating an account on GitHub.

github.com

 

cd /home/kube

 

도커파일 생성

sudo vim Dockerfile-frontend
FROM ubuntu:20.04
 
EXPOSE 3000
 
RUN apt-get update \
  && apt-get install -y vim curl git
 
RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash -
RUN apt-get update \
  && apt-get install -y nodejs
 
WORKDIR /home
 
RUN git clone https://github.com/kschoi93/k8s_frontend.git
 
WORKDIR /home/k8s_frontend
RUN npm install
 
CMD ["npm","start"]

참고-----

FROM rockylinux:9.0
 
EXPOSE 3000
 
RUN yum -y update \
  && yum install -y vim curl git
 
RUN curl -sLf -o /dev/null 'https://rpm.nodesource.com/pub_0.10/el/9/x86_64/nodesource-release-el9-1.noarch.rpm' | bash -
RUN yum -y update \
  && yum install -y nodejs
 
WORKDIR /home
 
RUN git clone https://github.com/kschoi93/k8s_frontend.git
 
WORKDIR /home/k8s_frontend
RUN npm install
 
CMD ["npm","start"]
----

도커파일 이미지로 빌드

sudo docker build -t toy_frontend:1.0 -f Dockerfile-frontend .

 

이미지 생성 확인

docker images

 

쿠버네티스 service && deployment .yaml 파일 생성

sudo vim toy_frontend.yaml
apiVersion: v1
kind: Service
metadata:
  name: frontend-service
spec:
  selector:
    app: toy
    tier: frontend
  type: NodePort
  ports:
  - protocol: TCP
    port: 80
    nodePort: 31001
    targetPort: 3000
--- 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: front-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: toy
      tier: frontend
  template:
    metadata:
      labels:
        app: toy
        tier: frontend
    spec:
      containers:
      - name: toy
        image: toy_frontend:1.0
        ports:
        - containerPort: 3000

 

쿠버네티스 deployment 생성

kubectl apply -f toy_frontend.yaml

쿠버네티스 파드 접속방법

kubectl exec -it front-deployment-5cc9cd6b67-kpnk5 -- bash

7.백엔드 설정

해당 파트 참고 URL

·        https://docs.docker.com/engine/reference/builder/

·        https://kubernetes.io/ko/docs/tasks/access-application-cluster/connecting-frontend-backend/

·        https://docs.djangoproject.com/ko/4.0/

·        https://docs.djangoproject.com/ko/4.0/ref/databases/#mysql-notes

 

 

Dockerfile reference

 

docs.docker.com

서비스를 사용하여 프론트엔드를 백엔드에 연결

이 작업은 프론트엔드 와 백엔드 마이크로서비스를 어떻게 생성하는지를 설명한다. 백엔드 마이크로서비스는 인사하기(hello greeter)이다. 프론트엔드는 nginx 및 쿠버네티스 서비스 오브젝트를 사

kubernetes.io

Django 문서 | Django 문서 | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com

Databases | Django 문서 | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com

백엔드는 제가 작성한 Django Code 사용했습니다.

돌아가게만 만든 것이기 때문에 퀄리티가 좋지 않긴 한데... 궁금하신 분은 https://github.com/kschoi93/k8s_backend.git
확인하시면 같습니다

 

 

GitHub - kschoi93/k8s_backend: k8s_backend

k8s_backend. Contribute to kschoi93/k8s_backend development by creating an account on GitHub.

github.com

 

cd /home/kube

도커 생성시 위치할 파일

아래 호스트 주소는 반드시 본인 서버 주소를 입력해주세요

sudo vim mysetting.py
DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': 'toy',
    'USER': 'user',

 

    'PASSWORD': 'password',
    'HOST': '10.100.0.10', # 호스트 주소는 본인의 서버 주소를 입력합니다
    'PORT': '31003',
    'OPTIONS': {
      'init_command': 'SET default_storage_engine=INNODB',
    },
  },
}

 

도커파일 생성

sudo vim Dockerfile-backend
FROM nvidia/cuda:11.5.1-cudnn8-devel-ubuntu20.04
 
EXPOSE 8000
 
RUN apt-get update \
  && apt-get install -y vim curl git python3 python3-venv python3-pip libmysqlclient-dev
 
WORKDIR /home
RUN python3 -m venv venv
RUN . venv/bin/activate
RUN git clone https://github.com/kschoi93/k8s_backend.git
 
WORKDIR /home/k8s_backend
COPY mysetting.py /home/k8s_backend/mysetting.py
RUN pip install -r requirements.txt
RUN python3 manage.py makemigrations k8s
RUN python3 manage.py migrate
 
CMD ["python3","manage.py","runserver","0.0.0.0:8000"]

참고---rocky9 버전용-------------------------------->
FROM nvidia/cuda:12.0.1-cudnn8-devel-rockylinux8
 
EXPOSE 8000
 
RUN yum -y  update \
  && yum install -y vim curl git python3 python3-venv python3-pip libmysqlclient-dev
 
WORKDIR /home
RUN python3 -m venv venv
RUN . venv/bin/activate
RUN git clone https://github.com/kschoi93/k8s_backend.git
 
WORKDIR /home/k8s_backend
COPY mysetting.py /home/k8s_backend/mysetting.py
RUN pip install -r requirements.txt
RUN python3 manage.py makemigrations k8s
RUN python3 manage.py migrate
 
CMD ["python3","manage.py","runserver","0.0.0.0:8000"]
--------------------------------------------<

도커파일 이미지로 빌드

sudo docker build -t toy_backend:1.0 -f Dockerfile-backend .

 

생성 확인

sudo docker images

 

쿠버네티스 service && deployment .yaml 파일 생성

sudo vim toy_backend.yaml
apiVersion: v1
kind: Service
metadata:
  name: backend-service
spec:
  selector:
    app: toy
    tier: backend
  type: NodePort
  ports:
  - protocol: TCP
    port: 8000
    nodePort: 31000
    targetPort: 8000
--- 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: toy
      tier: backend
  template:
    metadata:
      labels:
        app: toy
        tier: backend
    spec:
      containers:
      - name: toy
        image: toy_backend:1.0
        ports:
        - containerPort: 8000

 

쿠버네티스 deployment 생성

kubectl apply -f toy_backend.yaml

 

생성 확인

kubectl get pod,svc,deploy

쿠버네티스 파드 접속 방법

kubectl exec -it backend-deployment-5cc9cd6b67-kpnk5 -- bash

최종 생성 확인

kubectl get pod,svc,deploy,pv,pvc -o wide

8.결과화면

지금까지 작성한 결과에 대해서 확인하면 다음과 같습니다

master 서버에 접속하여 다음 주소로 접속합니다

http://127.0.0.1:31845

 

머신러닝 추론 페이지인 ML 메뉴로 이동

모델 생성

머신러닝은 Fashion MNIST 이용한 분류 기능을 만들어 봤습니다

CNN 공부하며 다음과 같이 코드를 작성하여 모델을 생성하였습니다.

# -*- coding: utf-8 -*-

"""CNNTest.ipynb

 

Automatically generated by Colaboratory.

 

Original file is located at

    https://colab.research.google.com/drive/1QbaPiN0k4iEsgCXa-CaqYj0aa5FM2BZ-

"""

 

import torch

import torch.nn as nn

import torch.nn.functional as F

 

import torchvision

import torchvision.transforms as transforms

 

import matplotlib.pyplot as plt

 

"""torch device cuda 사용 있는지 확인을 하고 cuda or cpu 정합니다."""

 

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

device

 

"""datasets 샘플과 정답을 저장하고 있습니다.

 

ex) (image, label)

 

transforms 통해 정규화를 합니다. datasets에서 넘어온 FashionMNIST 데이터셋은 PIL Image 이루어져 있습니다.

 

이를 Tensor 시킵니다.

"""

 

train_dataset = torchvision.datasets.FashionMNIST(root='/', train=True, download=True, transform=transforms.ToTensor())

test_dataset = torchvision.datasets.FashionMNIST(root='/', train=False, download=True, transform=transforms.ToTensor())

print(train_dataset, test_dataset)

print(len(train_dataset[0]))

# plt.imshow(train_dataset[0][0])

print(train_dataset[0][0].shape)

 

"""DataLoader dataset 샘플에 쉽게 접근 있도록 순회 가능한 객체로 감쌉니다.

 

iterable = 순회 가능한 객체

"""

 

train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=100)

test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=100)

print(train_loader, test_loader)

 

class FashionMNIST(nn.Module):

    def __init__(self):

        super(FashionMNIST, self).__init__()

        self.conv2 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, stride=1)

        self.batchNorm2d = nn.BatchNorm2d(32)

        self.relu = nn.ReLU()

        self.maxPool2d = nn.MaxPool2d(kernel_size=2, stride=2)

        self.fc1 = nn.Linear(in_features=169*2*2*2*2*2, out_features=600)

        self.drop = nn.Dropout2d(0.25)

        self.fc2 = nn.Linear(in_features=600, out_features=120)

        self.fc3 = nn.Linear(in_features=120, out_features=10)

 

    def forward(self, x):

        out = self.conv2(x)

        out = self.batchNorm2d(out)

        out = self.relu(out)

        out = self.maxPool2d(out)

        out = out.view(out.size(0), -1)

        out = self.fc1(out)

        out = self.drop(out)

        out = self.fc2(out)

        out = self.fc3(out)

        return out

 

model = FashionMNIST()

model.to(device)

print(model)

 

learning_rate = 0.001

criterion = nn.CrossEntropyLoss()

optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

print(model.parameters())

 

epochs = 10

count = 0

loss_ = []

 

for epoch in range(epochs):

    for images, labels in train_loader:

        images, labels = images.to(device), labels.to(device)

        train = images.view(100, 1, 28, 28)

        outputs = model(train)

        loss = criterion(outputs, labels)

 

        optimizer.zero_grad()

        loss.backward()

        optimizer.step()

        count += 1

 

        if not (count % 500):

            print("epoch: {}, count: {}, loss: {}".format(epoch, count, loss.data))

    loss_.append(loss.item())

print(loss_)

plt.plot(loss_)

plt.title(loss)

plt.xlabel('epoch')

plt.show()

 

dataiter = iter(test_loader)

images, labels = dataiter.next()

print(images.shape)

print(images[0][0].shape)

plt.imshow(images[0][0])

 

correct = 0

total = 0

 

with torch.no_grad():

  for data in test_loader:

    images, labels = data[0].to(device), data[1].to(device)

    outputs = model(images)

 

    _, predicted = torch.max(outputs.data, 1)

 

    total += labels.size(0)

    correct += (predicted == labels).sum()

 

print(f'accuracy : {100*correct/total}%')

 

torch.save(model.state_dict(), '/content/drive/MyDrive/mnist.pt')

 

백엔드에서 모델을 기반으로 추론 코드 작성

class InferenceCnnAPI(APIView):

    def post(self, request):

        # image 파일 추출

        file = request.FILES['cnn_image']

 

        if file is None:

            return '선택된 파일이 없습니다'

        elif os.path.exists('k8s/assets/image/cnn.png'):

            os.remove('k8s/assets/image/cnn.png')

 

        # image 저장

        fs = FileSystemStorage()

        filename = fs.save('k8s/assets/image/cnn.png', file)

 

        # 저장한 image load, 1차원으로 수정

        try:

            im = Image.open(filename).convert('L')

        except Exception as e:

            return Response('')

 

        # PIL Image -> Tensor 변환

        t = transforms.Compose([

            transforms.Resize(size=(28, 28)),

            transforms.ToTensor()

        ])

 

        # model parameter 맞게 차원 조정 ( 1, 1 , 28, 28 )

        test_data = t(im).unsqueeze(0)

 

        # cuda 설정

        device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

 

        model = FashionMNIST()

        model.to(device=device)

        model.load_state_dict(torch.load('k8s/models/cnn.pt'))

        model.eval()

 

        out = model(test_data)

 

        _, predicted = torch.max(out.data, 1)

 

        output_label = {

            0: 'T-shirt/Top',

            1: 'Trouser',

            2: 'Pullover',

            3: 'Dress',

            4: 'Coat',

            5: 'Sandal',

            6: 'Shirt',

            7: 'Sneaker',

            8: 'Bag',

            9: 'Ankle Boot'

        }

 

        result = output_label[predicted.item()]

        return Response(result)

위와 같이 머신러닝 관련해서 모델 생성 추론 코드를 작성하여 다음과 같이 적용했습니다.

리액트에서 이미지를 업로드하고, inference 누르면 백엔드로 이미지를 보내서 결과를 추론하고 결과 값을 반환하여 클라리언트에게 보여주도록 했습니다.

 

드레스 이미지 → inference → Dress

가방 이미지 → inference → Bag

결과를 보니 분류한다는 것을 확인 있습니다

 

데이터베이스 정상 연결 확인

dbeaver 라는 프로그램을 사용해 데이터베이스에 접근해 보면 다음과 같이 k8s_member 라는 테이블이 생성되어 있는 것을 확인 있습니다

 

sign-up 페이지로 이동해서 회원가입은 되는지 확인해보겠습니다

데이터베이스를 확인해보니 데이터베이스로 입력된 것을 확인 있습니다

 

 

이로써 쿠버네티스부터 서비스 배포까지의 제가 작성할 수준의 과정은 모두 작성하였는데요

과정은 기초나 다름없고 실제로 운영하기 위해서는 도커 레지스트리, 스토리 저장소, 머신러닝을 효율적으로 사용하기 위한 쿠브플로우, 쿠버네티스 인증서, 메시지 등등 많은 기능을 덧붙이고 각각의 기능을 이어야 합니다

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90