Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 2개 있습니다.)

Docker Desktop for Windows 기반의 Kubernetes 구성 - WSL 2 인스턴스에 kind 도구로 k8s 클러스터 구성

이전 글을 통해 "Docker Desktop for Windows" 환경에서 쉽게 k8s 구성을 실습할 수 있었는데요,

Docker Desktop for Windows에서 DockerDesktopVM 기반의 Kubernetes 구성
; https://www.sysnet.pe.kr/2/0/12575

위의 글은 DockerDesktopVM 기반이었지만, 새롭게 WSL 2로의 통합 환경에서 k8s를 구성하는 것도 가능합니다.

하지만 아쉽게도 제 경우에 아래의 이유로 실패를 했는데요,

WSL 2 기반으로 "Enable Kubernetes" 활성화 시 초기화 실패
; https://www.sysnet.pe.kr/2/0/12571

^^ 상관없습니다. 그냥 k8s를 구성해도 되기 때문입니다. (아마도 저 문제가 해결되면 저 방법으로 하는 것이 더 좋겠지만!) 어차피 Docker Desktop for Windows의 목적 자체가 로컬 개발 환경인데다, k8s 클러스터를 그런 환경으로 빠르게 구축해 주는 kind라는 도구가 있으므로 환경 구성이 매우 쉽습니다.

WSL+Docker: Kubernetes on the Windows Desktop
; https://kubernetes.io/blog/2020/05/21/wsl-docker-kubernetes-on-the-windows-desktop/

Kind를 이용한 쿠버네티스 클러스터 만들기
; https://jupilhwang.github.io/post/kind%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4-%ED%81%B4%EB%9F%AC%EC%8A%A4%ED%84%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0/

kind를 이용해 직접 WSL 2 환경에서 k8s를 운영하면 좋은 한 가지 이점이라면, Hyper-V에서 더 이상 "DockerDesktopVM" 인스턴스가 (필요가 없으므로) 올라오지 않는다는 점입니다.

반면 kind를 이용해 k8s를 구성할 때 한 가지 단점이라면 DockerDesktopVM을 사용할 때와는 달리 WSL 2를 사용하는 경우 약간 혼란스러울 수 있다는 점입니다. DockerDesktopVM을 사용하면 해당 VM에 설치된 리눅스 인스턴스에 (공식적으로) 접근할 수 있는 방법이 없으므로 모든 구성을 윈도우 측의 kubectl.exe, docker.exe를 이용해 통합/구성하게 됩니다. 반면 WSL 2를 이용해 docker/k8s + kind로 구성하면 docker/kubectl 명령을 WSL 2와 윈도우 호스트 측 모두에서 사용 가능하다는 차이점이 발생합니다.

여기서 문제는, docker의 경우 "Use the WSL 2 based engine" 옵션 덕분에 잘 통합이 되어서 WSL 2와 윈도우 호스트 측에서 실행할 때 단일한 docker 인스턴스로 작업을 하는 반면, kind의 경우에는 WSL 2와 윈도우 호스트 측에서 실행할 때 각기 별개의 k8s 클러스터를 생성한다는 것입니다.

이게 어떤 상황인지 좀 더 자세하게 살펴보겠습니다.




이미 언급한 대로 kind 구성은, 1) WSL 2 인스턴스 내에서 할 수도 있고, 2) 윈도우 호스트 측에서 실행하는 것도 가능합니다. 우선, WSL 2 내에서 kind를 실행해 k8s 클러스터를 구성해 보겠습니다.

/* kind 실행 모듈 다운로드 */
$ curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.10.0/kind-linux-amd64
$ chmod +x ./kind
$ sudo mv ./kind /usr/local/bin/

/* kind로 클러스터 구성 */
$ kind create cluster --name mycluster1
Creating cluster "mycluster1" ...
 ✓ Ensuring node image (kindest/node:v1.17.0) 🖼
 ✓ Preparing nodes 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
Set kubectl context to "kind-mycluster1"
You can now use your cluster with:

kubectl cluster-info --context mycluster1

Not sure what to do next? 😅 Check out https://kind.sigs.k8s.io/docs/user/quick-start/

저게 끝입니다. kind는 "create cluster ..." 명령어로 이미 k8s 클러스터 관련한 모든 구성을 완료합니다. 이렇게 구성한 "mycluster1" 클러스터에 대한 정보는 이렇게 알아낼 수 있습니다.

$ kubectl cluster-info
Kubernetes master is running at https://127.0.0.1:39339
KubeDNS is running at https://127.0.0.1:39339/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

$ kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://127.0.0.1:39339
  name: kind-mycluster1
contexts:
- context:
    cluster: kind-mycluster1
    user: kind-mycluster1
  name: kind-mycluster1
current-context: kind-mycluster1
kind: Config
preferences: {}
users:
- name: kind-mycluster1
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

즉, kind가 하는 일은 k8s 클러스터를 위한 모든 서비스를 구성하고, 현재 사용자의 프로파일 디렉터리($HOME/.kube)에 config 파일을 만들어 해당 클러스터에 대한 연결 정보를 구성합니다.

참고로, WSL 2에서 실행한 kind는 윈도우 호스트 환경을 인식하지는 않으므로 kubectl.exe 명령을 윈도우 호스트 측에서 실행하면 다음과 같은 출력이 나옵니다.

c:\temp\knd> kubectl config view
apiVersion: v1
clusters: null
contexts: null
current-context: ""
kind: Config
preferences: {}
users: null

c:\temp\knd> kubectl get pods
Unable to connect to the server: dial tcp [::1]:8080: connectex: No connection could be made because the target machine actively refused it.

그래서 이런 경우에는 WSL 2 인스턴스 측에서 kubectl proxy를 실행해 두면,

$ kubectl proxy -p=8080
Starting to serve on 127.0.0.1:8080

(WSL 2의 네트워크 구성의 특징에 따라) 윈도우 호스트 측에서 kubectl이 정상적으로 실행됩니다.

C:\temp> kubectl run nginx-app --image nginx --port=80
pod/nginx-app created

C:\temp> kubectl get pods
NAME        READY   STATUS    RESTARTS   AGE
nginx-app   1/1     Running   0          16s

C:\temp> kubectl expose pod nginx-app --type=NodePort
service/nginx-app exposed

C:\temp> kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP        16h
nginx-app    NodePort    10.96.199.21   <none>        80:32539/TCP 6s

/* 삭제
kubectl delete svc nginx-app
kubectl delete pod nginx-app

kind delete cluster --name mycluster1
*/




위에서는 WSL 2 인스턴스 환경 내에서 kind를 실행해 클러스터를 생성했지만, 윈도우 호스트 측에서 하는 것도 가능합니다. 이를 위해 PowerShell을 이용해 chocolatey 패키지 관리자를 먼저 설치한 후,

Running kind in Windows
; https://blog.nillsf.com/index.php/2020/08/28/running-kind-in-windows/

Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

이것을 이용해 kind 도구를 구성할 수 있습니다.

choco install kind -y

이후 클러스터 생성 방법은 WSL 2에서의 실행과 동일합니다.

c:\temp> kind create cluster --name cluster2

c:\temp> kubectl cluster-info
Kubernetes master is running at https://127.0.0.1:43574
KubeDNS is running at https://127.0.0.1:43574/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

위의 출력 결과에서 볼 수 있듯이, kind는 WSL 2 환경을 인식하지 않으므로 윈도우 명령행에서 실행하면 또다시 새롭게 k8s 클러스터를 만듭니다. 그리고, 역시 윈도우 사용자의 프로파일 디렉터리(%USERPROFILE%\.kube)에 새롭게 생성한 k8s 클러스터를 바라보는 config 파일을 구성하게 됩니다.




이런 식으로 따로 구성을 하기 때문에 혼란스러운 점이 하나 있는데요.

WSL 2에서 구성했을 때는 이후 윈도우 호스트 측에서 WSL 2로 kubectl proxy를 이용해 접속하는 것이 가능했지만, 그 반대인 이번 경우에는 WSL 2에서 호스트 측으로의 "localhost"를 이용한 통신이 안 되므로, 윈도우 호스트 환경 내에서만 kubectl로 해당 클러스터를 사용할 수 있다는 차이가 있습니다. (물론, kubectl proxy를 이용한 방법은 안 되지만 "kubectl 수행 시 다른 k8s 클러스터로 접속하는 방법"를 이용하면 WSL 2 측의 kubectl로 윈도우 호스트에 구성한 클러스터를 접근하는 것이 가능합니다.)

개인적인 의견인데, 저렇게 2개의 클러스터를 사용하면 자칫 실수를 할 수 있기 때문에 제 생각에는 (docker desktop for windows에서 "Use the WSL 2 based engine" 옵션을 켜고 kind를 이용해 구성할 때는) 어느 한 쪽에서 클러스터를 만든 다음 .kube 디렉터리에 생성한 config 파일을,

[WSL 2]
$HOME/.kube/config

[윈도우]
%USERPROFILE\.kube\config

다른 한 쪽에 복사하는 것을 권장합니다. 그럼 같은 클러스터를 바라보게 되므로 사용 중의 혼란을 없앨 수 있습니다. (아마도 이 부분은 "Enable Kubernetes" 옵션이 WSL 2와의 문제없이 잘 실행이 되었다면 config 파일을 양쪽 모두 동일한 클러스터를 바라보도록 공유하지 않았을까... 추측해 봅니다.)




그런데, Docker Desktop for Windows 구성을 DockerDesktopVM에 하는 경우와는 달리 WSL 2에 kind를 이용해 구성하면 불편한 점이 하나 더 있습니다. 일례로 다음과 같이 서비스를 생성한 경우,

c:\temp\knd> kubectl run nginx-app --image nginx --port=80
pod/nginx-app created

c:\temp\knd> kubectl expose pod nginx-app --type=NodePort
service/nginx-app exposed

c:\temp\knd> kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP        8m45s
nginx-app    NodePort    10.96.56.220   <none>        80:30814/TCP   9s

기존에 DockerDesktopVM을 이용해 구성한 k8s 환경의 경우 curl을 이용해 저 서비스로 곧바로 접속할 수 있었습니다. 하지만, ("Use the WSL 2 based engine" 옵션을 켜고) kind로 구성한 경우에는 curl로 접속이 안 됩니다.

c:\temp\knd> curl localhost:31739
curl: (7) Failed to connect to localhost port 30814: Connection refused

이에 대해서는 다음의 문서에서 다루고 있는데요,

Accessing a Kubernetes Service running in WSL2
; https://kind.sigs.k8s.io/docs/user/using-wsl2/#accessing-a-kubernetes-service-running-in-wsl2

실습을 위해 이전에 생성해 둔 클러스터를 삭제하고, 새롭게 다음의 config으로 클러스터를 생성한 후,

# cluster-config.yml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30000
    hostPort: 30000
    protocol: TCP

c:\temp> kind create cluster --config=cluster-config.yml

nginx 서비스를 deployment를 이용해 구성하면,

c:\temp> kubectl create deployment nginx --image=nginx --port=80

c:\temp> kubectl create service nodeport nginx --tcp=80:80 --node-port=30000

curl 명령어로 nginx로의 접근이 가능합니다.

c:\temp> curl localhost:30000

(왜 이런 차이가 발생하는지에 대한 자세한 설명은 "Docker Desktop for Windows 기반의 Kubernetes 구성 (2) - WSL 2 인스턴스에 kind가 구성한 k8s 서비스 위치" 글을 참고하세요.)




WSL 2 인스턴스 내에서 kind로 클러스터 생성 시 다음과 같은 오류가 발생한다면?

$ kind create cluster --name wslkind
ERROR: failed to list clusters: command "docker ps -q -a --no-trunc --filter label=io.x-k8s.kind.cluster=wslkind --format '{{.Names}}'" failed with error: exit status 1

실제로 문제가 되는 명령어를 직접 실행해 보면 답이 나옵니다.

$ docker ps -q -a --no-trunc --filter label=io.x-k8s.kind.cluster-wslkind --format '{{.Names}}'
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json?all=1&filters=%7B%22label%22%3A%7B%22io.x-k8s.kind.cluster-wslkind%22%3Atrue%7D%7D: dial unix /var/run/docker.sock: connect: permission denied

따라서, docker 그룹에 현재 로그인 사용자를 등록해 주면 됩니다. (혹은, 권한에 걸리지 않는 root 계정으로 전환 후 실행해도 됩니다.)




간혹, kubectl run 했을 때 다음과 같은 오류가 발생한다면?

c:\temp\knd> kubectl run nginx-app --image nginx --port=80
Error from server (Forbidden): pods "nginx-app" is forbidden: error looking up service account default/default: serviceaccount "default" not found

오류 메시지의 의미는, default 네임스페이스에 default 서비스 계정이 없다는 것입니다. 이에 대한 확인은 다음과 같이 할 수 있는데,

c:\temp\knd> kubectl get serviceaccount -n default
NAME      SECRETS   AGE
default   1         3m50s

저렇게 나오면 다시 "kubectl run ..."을 실행해 보면 됩니다. (만약 실제로 서비스 계정이 없다면 오류가 발생하는 것이 맞습니다.)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 3/29/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




1  2  3  4  5  6  7  8  9  10  11  [12]  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13320정성태4/13/20233739개발 환경 구성: 675. Windows Octave 8.1.0 - Python 스크립트 연동
13319정성태4/12/20234171개발 환경 구성: 674. WSL 2 환경에서 GNU Octave 설치
13318정성태4/11/20233987개발 환경 구성: 673. JetBrains IDE에서 "Squash Commits..." 메뉴가 비활성화된 경우
13317정성태4/11/20234144오류 유형: 855. WSL 2 Ubuntu 20.04 - error: cannot communicate with server: Post http://localhost/v2/snaps/...
13316정성태4/10/20233471오류 유형: 854. docker-compose 시 "json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)" 오류 발생
13315정성태4/10/20233666Windows: 245. Win32 - 시간 만료를 갖는 컨텍스트 메뉴와 윈도우 메시지의 영역별 정의파일 다운로드1
13314정성태4/9/20233742개발 환경 구성: 672. DosBox를 이용한 Turbo C, Windows 3.1 설치
13313정성태4/9/20233834개발 환경 구성: 671. Hyper-V VM에 Turbo C 2.0 설치 [2]
13312정성태4/8/20233818Windows: 244. Win32 - 시간 만료를 갖는 MessageBox 대화창 구현 (개선된 버전)파일 다운로드1
13311정성태4/7/20234305C/C++: 163. Visual Studio 2022 - DirectShow 예제 컴파일(WAV Dest)
13310정성태4/6/20233878C/C++: 162. Visual Studio - /NODEFAULTLIB 옵션 설정 후 수동으로 추가해야 할 library
13309정성태4/5/20234032.NET Framework: 2107. .NET 6+ FileStream의 구조 변화
13308정성태4/4/20233922스크립트: 47. 파이썬의 time.time() 실숫값을 GoLang / C#에서 사용하는 방법
13307정성태4/4/20233716.NET Framework: 2106. C# - .NET Core/5+ 환경의 Windows Forms 응용 프로그램에서 HINSTANCE 구하는 방법
13306정성태4/3/20233563Windows: 243. Win32 - 윈도우(cbWndExtra) 및 윈도우 클래스(cbClsExtra) 저장소 사용 방법
13305정성태4/1/20233895Windows: 242. Win32 - 시간 만료를 갖는 MessageBox 대화창 구현 (쉬운 버전)파일 다운로드1
13304정성태3/31/20234248VS.NET IDE: 181. Visual Studio - C/C++ 프로젝트에 application manifest 적용하는 방법
13303정성태3/30/20233557Windows: 241. 환경 변수 %PATH%에 DLL을 찾는 규칙
13302정성태3/30/20234176Windows: 240. RDP 환경에서 바뀌는 %TEMP% 디렉터리 경로
13301정성태3/29/20234312Windows: 239. C/C++ - Windows 10 Version 1607부터 지원하는 /DEPENDENTLOADFLAG 옵션파일 다운로드1
13300정성태3/28/20233946Windows: 238. Win32 - Modal UI 창에 올바른 Owner(HWND)를 설정해야 하는 이유
13299정성태3/27/20233732Windows: 237. Win32 - 모든 메시지 루프를 탈출하는 WM_QUIT 메시지
13298정성태3/27/20233675Windows: 236. Win32 - MessageBeep 소리가 안 들린다면?
13297정성태3/26/20234345Windows: 235. Win32 - Code Modal과 UI Modal
13296정성태3/25/20233689Windows: 234. IsDialogMessage와 협업하는 WM_GETDLGCODE Win32 메시지 [1]파일 다운로드1
13295정성태3/24/20233952Windows: 233. Win32 - modeless 대화창을 modal처럼 동작하게 만드는 방법파일 다운로드1
1  2  3  4  5  6  7  8  9  10  11  [12]  13  14  15  ...