출처: 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 코드가 제공될 예정입니다.
· https://docs.docker.com/get-started/overview/
· https://docs.docker.com/engine/install/ubuntu/
Install Docker Engine on Ubuntu
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/#도커
본문
Install kubeadm
· https://kubernetes.io/ko/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
쿠버네티스를 설치하기 전에 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/
인그레스(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
* 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
A JavaScript library for building user interfaces
프론트엔드는 제가 작성한 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.
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.
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
머신러닝은 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를 누르면 백엔드로 이미지를 보내서 결과를 추론하고 결과 값을 반환하여 클라리언트에게 보여주도록 했습니다.
결과를 보니 잘 분류한다는 것을 확인 할 수 있습니다
dbeaver 라는 프로그램을 사용해 데이터베이스에 접근해 보면 다음과 같이 k8s_member 라는 테이블이 생성되어 있는 것을 확인 할 수 있습니다
sign-up 페이지로 이동해서 회원가입은 잘 되는지 확인해보겠습니다
데이터베이스를 확인해보니 데이터베이스로 잘 입력된 것을 확인 할 수 있습니다
이로써 쿠버네티스부터 서비스 배포까지의 제가 작성할 수준의 과정은 모두 작성하였는데요
이 과정은 기초나 다름없고 실제로 운영하기 위해서는 도커 레지스트리, 스토리 저장소, 머신러닝을 효율적으로 사용하기 위한 쿠브플로우, 쿠버네티스 인증서, 메시지 큐 등등 수 많은 기능을 덧붙이고 각각의 기능을 이어야 합니다
'프로그램 활용 > 인공지능(AI)' 카테고리의 다른 글
Vector Database (0) | 2023.11.17 |
---|---|
[AI][기고] Stable Diffusion: 델파이로 내 PC에서 구현되는 생성형 AI (0) | 2023.09.05 |
ChatGPT4 (챗GPT4, 챗지피티4) 무료 사용방법 (0) | 2023.04.05 |
딥러닝 서버 PC 구축 (0) | 2023.03.30 |
인공지능 알아가기 (0) | 2023.02.13 |