Kubernetes는 컨테이너 오케스트레이션 툴로, 가용성 있는 서비스를 운영하는 데에 적합한 기능을 가지고 있으며, 필자 역시도 직무상 운영하는 서비스에 Kubernetes 를 애용하고 있다. 컨테이너 기반 서비스 운영에 한번 맛을 들이니, Rolling Update, Versioning, 그리고 Scaling 등 유용한 기능이 많아, 계속 Kubernetes 를 사용하게 되었는데, 실제 Node 들을 구성해서 클러스터를 구축하기에는 너무 시간과 노력이 많이 소모되고, EKS 와 같은 클라우드 툴을 사용하자니 비용이 너무 많이 들어서, 여러가지 실습을 해볼 만한 플랫폼이 마뜩치 않았다. 이럴 때 minikube 를 사용하면 간편하게 local 에서 클러스터를 구성할 수 있어서 애용하고 있다.
minikube
사실 minikube는 꽤나 자주 볼 수 있는 툴이다. k8s 공식 문서에서도 학습 환경으로 minikube 를 소개하고 있다. minikube는 기본적으로 docker in docker 스타일로 local 에서 k8s (kubernetes 가 k와 s 사이에 8 글자가 있다고 해서 k8s라고 줄여 부른다.) 클러스터를 구성하는데, 다시 말해 도커 컨테이너 하나를 node 하나라고 생각하고 클러스터를 구성할 수 있다.
minikube 를 설치하고 클러스터를 실행하는 방법은 공식 문서 를 따라하면 금방 할 수 있다. 먼저 minikube 를 설치한다. 필자는 OSX 위에서 작업을 했기 때문에, homebrew 를 이용해서 설치했다.
brew install minikube
도커 기반으로 작동하기 때문에, 당연히 docker daemon 이 실행되고 있어야 한다. docker 가 실행 중인 상태에서 기본 설정으로 클러스터를 실행하려면 다음 커맨드를 실행하면 된다.
minikube start
그러면 minikube 라는 이름의 컨테이너 하나가 생성되는 것을 볼 수 있다.
kubectl 역시 사용할 수 있는데, 만약 kubectl 명령어를 찾지 못한다면, minikube kubectl 명령어를 사용할 수 있다. 편의상 ~/.bashrc 같은 파일에
alias kc="minikube kubectl --"
와 같이 추가해 두면, 좀 더 편리하게 사용할 수 있다.
Kubernetes Dashboard 역시 사용할 수 있다.
minikube dashboard
를 실행하면, k8s dashboard 를 열 수 있다.
실행 중인 컨테이너를 완전히 삭제하기 위해서는
minikube delete
를 실행하면 된다. 실행 후 컨테이너가 완전히 삭제되었는지 확인하자.
minikube 클러스터 구성
minikube 는 노드 한 대를 이용해서도 control plane 과 data plane 를 동시에 구성할 수 있다. 하지만 노드 한 대로는 재미가 없으므로, control plane 노드 한 대와, worker node 2대를 구성해 보자. minikube 로 구성할 클러스터는 다음과 같다.
다음 커맨드를 실행해서 3개의 컨테이너를 생성한다.
minkube start --nodes 3
클러스터 생성이 완료되고, 노드를 확인해보면, control-plane 이라는 role 을 가진 node 한 대와 추가 node 2대가 생성된 것을 확인할 수 있다.
kubectl get nodes
를 실행하면, 다음과 유사한 결과가 나와야 한다.
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 55s v1.27.3
minikube-m02 Ready <none> 33s v1.27.3
minikube-m03 Ready <none> 12s v1.27.3
minikube 라는 이름의 node 가 control-plane 이고, minikube-m02 와 minikube-m03 을 worker node 로 사용할 것이다.
여기까지 하면 cluster 가 준비된 것이지만, 몇 가지 설정을 더 해보자. 먼저, nginx-ingress-controller를 사용하기 위해서 minikube addon 을 활성화 해보자.
minikube addons enable ingress
명령어 실행이 끝나고 ingress-nginx 라는 네임스페이스의 pod 을 확인해 보면
kubectl get pods -n ingress-nginx
다음과 같이 pod 가 실행중이어야 한다.
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-rkwnd 0/1 Completed 0 42s
ingress-nginx-admission-patch-pqb7k 0/1 Completed 0 42s
ingress-nginx-controller-7799c6795f-mkdzz 1/1 Running 0 42s
다음으로, 우리는 minikube node 를 control plane 으로 설정하기로 했으므로, 해당 node 에는 pod 가 생성되지 못하게 설정해 보자. minikube node 에 taint 를 설정해 준다.
kubectl taint nodes minikube node-role.kubernetes.io/control-plane=:NoSchedule
여기까지 하면, 실습을 진행하기 위한 클러스터는 준비되었다.
클러스터 위에 nginx 와 httpd 서버 배포하기
잘 구성된 우리의 클러스터 위에, nginx 와 httpd 서버를 배포해 보자. 실습을 마치면 구성될 아키텍쳐는 다음과 같다.
k8s ingress 를 통해서, /nginx path 로 들어오는 요청은 nginx 서버로 라우팅하고, /httpd 로 들어오는 요청은 httpd 서버로 라우팅할 계획이다. 먼저, nginx 와 httpd 서버를 실행할 pod 들을 배포해 보자.
Deployment 생성
nginx-deployment.yaml 과 http-deployment.yaml 파일을 생성하고 다음과 같이 작성한다.
# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
labels:
app: nginx
spec:
replicas: 3
strategy:
type: RollingUpdate
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- name: http
containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
# httpd-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpd-app
labels:
app: httpd
spec:
replicas: 3
strategy:
type: RollingUpdate
selector:
matchLabels:
app: httpd
template:
metadata:
labels:
app: httpd
spec:
containers:
- name: httpd
image: httpd:2.4
ports:
- name: http
containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
배포를 위해서 다음 명령어를 실행한다.
kubectl create -f nginx-deployment.yaml
kubectl create -f httpd-deployment.yaml
명령어 실행이 완료되고, pod 가 생성될 때까지 잠시 기다리면, 다음과 같이 pod 6개가 생성되어야 한다.
kubectl get pods -o wide
를 실행하면,
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
httpd-app-7d579f65c-6szxg 1/1 Running 0 21s 10.244.1.3 minikube-m02 <none> <none>
httpd-app-7d579f65c-7xxp7 1/1 Running 0 21s 10.244.2.4 minikube-m03 <none> <none>
httpd-app-7d579f65c-9fs9q 1/1 Running 0 21s 10.244.1.4 minikube-m02 <none> <none>
nginx-app-55f4f85675-4gzmv 1/1 Running 0 25s 10.244.1.2 minikube-m02 <none> <none>
nginx-app-55f4f85675-fcjv5 1/1 Running 0 25s 10.244.2.3 minikube-m03 <none> <none>
nginx-app-55f4f85675-twkdk 1/1 Running 0 25s 10.244.2.2 minikube-m03 <none> <none>
nginx pod 가 3개, httpd pod 가 3개씩 생성되었고, 모두 우리가 설정한 worker node 위에 생성된 것을 확인할 수 있다. 실제로 pod 이
잘 실행되는지 확인해 보기 위해서 직접 요청을 보내보자. 위 출력에서 IP 주소는 클러스터 내부에서만 유의미한 IP 이기 때문에, master node 로 ssh 해서 접속한 후 httpd pod 중 하나의 IP 주소로 요청을 보내보자. minikube 에서 노드로 ssh 할 수 있는 기능을 제공한다.
minikube ssh
접속이 완료되면 요청을 보내 보자.
curl 10.244.1.3
그러면 다음과 같이 응답이 잘 와야 한다.
<html><body><h1>It works!</h1></body></html>
exit 명령어를 통해 ssh 에서 빠져나올 수 있다.
exit
Service 생성
이제 pod 에 직접 요청을 보내는 것이 아니라 service 를 통해 pod 에 요청을 전달할 수 있도록, ClusterIP Service 를 각각 생성해 보도록 하자.
nginx-svc.yaml 과 httpd-svc.yaml 파일을 생성하고 다음과 같이 작성한다.
# nginx-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: ClusterIP
selector:
app: nginx
ports:
- protocol: TCP
port: 8080
targetPort: http
# httpd-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: httpd
spec:
type: ClusterIP
selector:
app: httpd
ports:
- protocol: TCP
port: 3000
targetPort: http
해당 service 들을 생성한다.
kubectl create -f nginx-svc.yaml
kubectl create -f httpd-svc.yaml
생성된 service 들을 확인해보기 위해 다음과 같이 명령을 입력하면
kubectl get svc
생성한 service 들을 확인할 수 있다.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd ClusterIP 10.108.190.145 <none> 3000/TCP 3s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 31m
nginx ClusterIP 10.107.207.191 <none> 8080/TCP 7s
kubernetes 라는 이름의 서비스는 기본으로 생성되어 있는 것이기 때문에 신경쓰지 않아도 된다. post 3000번으로 요청하면 httpd pod 로 요청을 전달하는 httpd 서비스와 port 8080번으로 요청하면 nginx pod 로 요청을 전달하는 nginx 서비스를 생성했다. 무작위로 고른 port 이지만, 주로 로컬 개발시에 사용하는 port 들이라서 서로 다르게 구성해보았다.
service 로 요청을 보내서 응답이 제대로 오는지 확인하자. 다시 master node 로 접속한 후, httpd 의 cluster ip 로 요청을 보내보자.
minikube ssh
curl 10.108.190.145:3000
위에서 했던 것과 마찬가지로 응답이 잘 와야 한다.
Ingress 생성
이제 외부 요청을 path 에 따라 알맞은 서비스로 라우팅해 줄 수 있도록 Ingress 를 생성해 보자.
nginx-ingress.yaml 파일과 httpd-ingress.yaml 파일을 생성하고 다음과 같이 작성한다.
# nginx-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: "nginx"
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /nginx
pathType: Prefix
backend:
service:
name: nginx
port:
number: 8080
# httpd-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: httpd-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /httpd
pathType: Prefix
backend:
service:
name: httpd
port:
number: 3000
/nginx path 로 요청이 오면, nginx 서비스의 포트 8080의 path / 로 전달하고, /httpd 역시 마찬가지로 알맞게 전달하도록 설정했다. 해당 ingress 를 생성해 보자.
kubectl create -f nginx-ingress.yaml
kubectl create -f httpd-ingress.yaml
Ingress 를 확인하기 위해서 다음과 같이 실행하면
kubectl get ingress
두 개의 ingress 가 생성된 것을 바로 확인할 수 있다.
NAME CLASS HOSTS ADDRESS PORTS AGE
httpd-ingress nginx * 80 9s
nginx-ingress nginx * 80 14s
우리가 ingressClassName 을 nginx 로 설정함으로써 nginx-ingress-controller를 통해서 ingress 를 구성하기로 했는데, ingress 요청이 서비스로 전달되는 과정을 살펴보자. ingress-nginx 네임스페이스의 서비스를 확인해 보면
$ kc get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.98.132.246 <none> 80:31547/TCP,443:30043/TCP 33m
ingress-nginx-controller-admission ClusterIP 10.104.149.253 <none> 443/TCP 33m
이렇게 ingress-nginx-controller 로 향하는 NodePort 타입의 서비스가 생성되어 있음을 확인할 수 있다. master node 로 접속해서 해당 서비스의 IP 주소로 요청을 보내보면, 우리가 ingress 를 설정한 대로 라우팅이 되는 것을 확인할 수 있다.
$ minikube ssh
$ curl 10.98.132.246/nginx
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
$ curl 10.98.132.246/httpd
<html><body><h1>It works!</h1></body></html>
서비스가 NodePort 이기 때문에 master node 에서 해당 포트로 바로 요청을 보내도 같은 결과를 얻을 수 있다.
$ minikube ssh
$ curl localhost:31547/nginx
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
$ curl localhost:31547/httpd
<html><body><h1>It works!</h1></body></html>
Ingress 는 결국 클러스터 밖에서 들어오는 요청을 핸들링 해 주어야 그 빛을 발할 수 있는데, cluster 안으로 접속하지 않아도 호스트 머신에서 클러스터로 요청을 보낼 수 있도록 minikube tunnel 명령어를 사용해 보자.
minikube tunnel
명령어를 실행한 상태로 브라우저에 각각 http://localhost/nginx 와 http://localhost/httpd 를 입력해 보면, 다음과 같이 클러스터 밖에서도 pod 에서 응답을 받을 수 있다.
결론
minikube 를 이용해서, k8s 배포에 필요한 여러가지 실습과 실험들을 해볼 수 있다. addon 으로 여러가지 기능들을 제공하니, k8s 를 공부하는 데에도 유용하게 사용할 수 있을 것이다.
Appendix
전체 코드는 다음에서 확인할 수 있습니다.
GitHub - k2sebeom/minikube-k8s-demo: Demo projects for k8s on minikube
Demo projects for k8s on minikube. Contribute to k2sebeom/minikube-k8s-demo development by creating an account on GitHub.
github.com
'개발 일지' 카테고리의 다른 글
[k8s] Kafka Connect 를 이용해서 MQTT 메세지를 Kafka Broker 로 Produce 하기 (0) | 2024.02.13 |
---|---|
[k8s] MQTT Broker Cluster 와 Kafka Cluster 를 이용한 Scalable 아키텍쳐 구성 (0) | 2024.01.25 |
[Windows] NSIS 를 이용해서 Forms Application 배포하기 (0) | 2024.01.08 |
[Windows] NSIS 를 이용해서 설치 파일 패키징하기 (0) | 2024.01.08 |
[C#] .NET 프레임워크로 윈도우에서 Bluetooth 사용하기 (2) (0) | 2024.01.04 |