Scala 확장: Kubernetes를 사용하여 Dockerize하는 방법
게시 됨: 2022-03-11Kubernetes는 애플리케이션을 클라우드에 배포하고 더 빠르게 확장하는 데 도움이 될 것을 약속하는 블록체인의 새로운 아이입니다. 오늘날 마이크로서비스 아키텍처용으로 개발할 때 API 서버를 생성하기 위해 Scala를 선택하는 것이 표준입니다.
계획에 Scala 애플리케이션이 있고 이를 클라우드로 확장 하려는 경우 올바른 위치에 있습니다. 이 기사에서는 일반 Scala 애플리케이션을 사용하고 애플리케이션의 여러 인스턴스를 시작하기 위해 Docker로 Kubernetes를 구현하는 방법을 단계별로 보여줄 것입니다. 최종 결과는 단일 애플리케이션이 여러 인스턴스로 배포되고 Kubernetes에 의해 로드 밸런싱되는 것입니다.
이 모든 것은 Scala 애플리케이션에서 Kubernetes 소스 키트를 가져오기만 하면 구현됩니다. 이 키트에는 설치 및 구성과 관련된 복잡한 세부 정보가 많이 숨겨져 있지만 키트가 수행하는 작업을 분석하려는 경우 읽을 수 있을 만큼 작고 이해하기 쉽습니다. 단순화를 위해 모든 것을 로컬 컴퓨터에 배포합니다. 그러나 Kubernetes의 실제 클라우드 배포에는 동일한 구성이 적합합니다.
쿠버네티스란?
구현의 세부 사항으로 들어가기 전에 Kubernetes가 무엇이며 왜 중요한지 논의해 보겠습니다.
Docker에 대해 이미 들어보셨을 것입니다. 어떤 의미에서는 가벼운 가상 머신입니다.
이러한 이유로 이미 클라우드에 애플리케이션을 배포하는 데 가장 널리 사용되는 도구 중 하나입니다. Docker 이미지는 VMWare, VirtualBox 또는 XEN과 같은 기존 가상 머신보다 훨씬 쉽고 빠르게 구축하고 복제할 수 있습니다.
Kubernetes는 Docker를 보완하여 Docker화된 애플리케이션을 관리하기 위한 완벽한 환경을 제공합니다. Kubernetes를 사용하면 수백 또는 수천 개의 Docker 애플리케이션을 쉽게 배포, 구성, 오케스트레이션, 관리 및 모니터링할 수 있습니다.
Kubernetes는 Google에서 개발한 오픈 소스 도구이며 다른 많은 공급업체에서 채택했습니다. Kubernetes는 기본적으로 Google 클라우드 플랫폼에서 사용할 수 있지만 다른 공급업체는 OpenShift 클라우드 서비스에도 이를 채택했습니다. Amazon AWS, Microsoft Azure, RedHat OpenShift 및 더 많은 클라우드 기술에서 찾을 수 있습니다. 클라우드 애플리케이션 배포의 표준이 되기에 적합한 위치에 있다고 말할 수 있습니다.
전제 조건
이제 기본 사항을 다루었으므로 필수 소프트웨어가 모두 설치되었는지 확인하겠습니다. 먼저 Docker가 필요합니다. Windows 또는 Mac을 사용하는 경우 Docker 도구 상자가 필요합니다. Linux를 사용하는 경우 배포판에서 제공하는 특정 패키지를 설치하거나 단순히 공식 지침을 따라야 합니다.
우리는 JVM 언어인 스칼라로 코딩할 것입니다. 물론 전역 경로에서 사용 가능한 Java Development Kit와 scala SBT 도구가 필요합니다. 이미 Scala 프로그래머라면 해당 도구가 이미 설치되어 있을 가능성이 있습니다.
Windows 또는 Mac을 사용하는 경우 Docker는 default
라는 가상 머신을 생성합니다. 이는 Kubernetes를 실행하기에는 너무 작을 수 있습니다. 제 경험상 기본 설정에 문제가 있었습니다. VirtualBox GUI를 열고 가상 머신 default
을 선택하고 메모리를 최소 2048MB로 변경하는 것이 좋습니다.
클러스터화할 애플리케이션
이 튜토리얼의 지침은 모든 Scala 애플리케이션 또는 프로젝트에 적용할 수 있습니다. 이 기사에서 작업할 일부 "고기"를 사용하기 위해 Akka HTTP라고 하는 Scala의 간단한 REST 마이크로 서비스를 시연하는 데 매우 자주 사용되는 예를 선택했습니다. 애플리케이션에서 사용하기 전에 제안된 예제에 소스 키트를 적용하는 것이 좋습니다. 데모 응용 프로그램에 대해 키트를 테스트했지만 코드와 충돌이 없을 것이라고 보장할 수 없습니다.
따라서 먼저 데모 애플리케이션을 복제하여 시작합니다.
git clone https://github.com/theiterators/akka-http-microservice
다음으로 모든 것이 올바르게 작동하는지 테스트합니다.
cd akka-http-microservice sbt run
그런 다음 http://localhost:9000/ip/8.8.8.8
에 액세스하면 다음 이미지와 같은 내용이 표시됩니다.
소스 키트 추가
이제 Git 매직으로 소스 키트를 추가할 수 있습니다.
git remote add ScalaGoodies https://github.com/sciabarra/ScalaGoodies git fetch --all git merge ScalaGoodies/kubernetes
이것으로 소스 키트가 포함된 데모가 있고 사용해 볼 준비가 된 것입니다. 또는 거기에서 코드를 복사하여 애플리케이션에 붙여넣을 수도 있습니다.
프로젝트의 파일을 병합하거나 복사하면 시작할 준비가 된 것입니다.
쿠버네티스 시작하기
키트를 다운로드했으면 다음을 실행하여 필요한 kubectl
바이너리를 다운로드해야 합니다.
bin/install.sh
이 설치 프로그램은 시스템에 따라 OSX, Linux 또는 Windows용 올바른 kubectl
바이너리를 다운로드할 수 있을 만큼 충분히 똑똑합니다. 설치 프로그램은 내가 소유한 시스템에서 작동했습니다. 키트를 고칠 수 있도록 문제를 보고해 주십시오.
kubectl
바이너리를 설치했으면 로컬 Docker에서 전체 Kubernetes를 시작할 수 있습니다. 그냥 실행:
bin/start-local-kube.sh
처음 실행될 때 이 명령은 전체 Kubernetes 스택의 이미지와 이미지를 저장하는 데 필요한 로컬 레지스트리를 다운로드합니다. 다소 시간이 소요될 수 있으니 조금만 기다려주세요. 또한 인터넷에 직접 액세스해야 합니다. 프록시 뒤에 있으면 키트가 프록시를 지원하지 않기 때문에 문제가 됩니다. 이를 해결하려면 프록시를 사용하도록 Docker, curl 등과 같은 도구를 구성해야 합니다. 임시 무제한 액세스 권한을 얻는 것이 좋습니다.
모든 것을 성공적으로 다운로드할 수 있다고 가정하고 Kubernetes가 제대로 실행되고 있는지 확인하려면 다음 명령을 입력할 수 있습니다.
bin/kubectl get nodes
예상 답변은 다음과 같습니다.
NAME STATUS AGE 127.0.0.1 Ready 2m
물론 연령은 다를 수 있습니다. 또한 Kubernetes를 시작하는 데 시간이 걸릴 수 있으므로 응답을 보기 전에 명령을 몇 번 호출해야 할 수 있습니다. 여기에서 오류가 발생하지 않으면 축하합니다. Kubernetes가 로컬 시스템에서 실행되고 있는 것입니다.
Scala 앱 Docker화
이제 Kubernetes를 시작하고 실행했으므로 여기에 애플리케이션을 배포할 수 있습니다. 예전에는 Docker 이전에는 애플리케이션을 실행하기 위해 전체 서버를 배포해야 했습니다. Kubernetes를 사용하면 애플리케이션을 배포하기 위해 다음 작업을 수행하기만 하면 됩니다.
- 도커 이미지를 생성합니다.
- 시작할 수 있는 레지스트리에 푸시합니다.
- Kubernetes로 인스턴스를 시작하면 레지스트리에서 이미지를 가져옵니다.
운 좋게도, 특히 많은 사람들이 사용하는 것처럼 SBT 빌드 도구를 사용하는 경우 훨씬 덜 복잡합니다.
키트에는 Scala 애플리케이션을 실행할 수 있는 이미지를 만드는 데 필요한 모든 정의 또는 최소한 Akka HTTP 데모를 실행하는 데 필요한 모든 정의가 포함된 두 개의 파일이 포함되어 있습니다. 다른 Scala 응용 프로그램과 함께 작동한다고 보장할 수는 없지만 좋은 출발점이며 다양한 구성에서 작동해야 합니다. Docker 이미지 빌드를 위해 찾을 파일은 다음과 같습니다.
docker.sbt project/docker.sbt
그 안에 무엇이 들어 있는지 살펴보겠습니다. project/docker.sbt
파일에는 sbt-docker
플러그인을 가져오는 명령이 포함되어 있습니다.
addSbtPlugin("se.marcuslonnberg" % "sbt-docker" % "1.4.0")
이 플러그인은 SBT를 사용하여 Docker 이미지 빌드를 관리합니다. Docker 정의는 docker.sbt
파일에 있으며 다음과 같습니다.
imageNames in docker := Seq(ImageName("localhost:5000/akkahttp:latest")) dockerfile in docker := { val jarFile: File = sbt.Keys.`package`.in(Compile, packageBin).value val classpath = (managedClasspath in Compile).value val mainclass = mainClass.in(Compile, packageBin).value.getOrElse(sys.error("Expected exactly one main class")) val jarTarget = s"/app/${jarFile.getName}" val classpathString = classpath.files.map("/app/" + _.getName) .mkString(":") + ":" + jarTarget new Dockerfile { from("anapsix/alpine-java:8") add(classpath.files, "/app/") add(jarFile, jarTarget) entryPoint("java", "-cp", classpathString, mainclass) } }
이 파일의 의미를 완전히 이해하려면 이 정의 파일을 이해할 수 있을 만큼 Docker에 대해 잘 알고 있어야 합니다. 그러나 Docker 정의 파일에 대한 자세한 내용은 이미지를 빌드하기 위해 완전히 이해할 필요가 없기 때문에 다루지 않습니다.

SBT가 모든 파일 수집을 처리합니다.
클래스 경로는 다음 명령에 의해 자동으로 생성됩니다.
val classpath = (managedClasspath in Compile).value
일반적으로 애플리케이션을 실행하기 위해 모든 JAR 파일을 수집하는 것은 매우 복잡합니다. SBT를 사용하여 Docker 파일은 add(classpath.files, "/app/")
로 생성됩니다. 이런 식으로 SBT는 모든 JAR 파일을 수집하고 애플리케이션을 실행하기 위해 Dockerfile을 구성합니다.
다른 명령은 누락된 조각을 수집하여 Docker 이미지를 만듭니다. 이미지는 기존 이미지 APT를 사용하여 빌드되어 Java 프로그램( anapsix/alpine-java:8
, Docker Hub에서 인터넷 사용 가능)을 실행합니다. 다른 지침은 응용 프로그램을 실행하기 위해 다른 파일을 추가하는 것입니다. 마지막으로 진입점을 지정하여 실행할 수 있습니다. 또한 이름은 의도적으로 localhost:5000
으로 시작합니다. localhost:5000
은 내가 start-kube-local.sh
스크립트에서 레지스트리를 설치한 곳이기 때문입니다.
SBT를 사용하여 Docker 이미지 빌드
Docker 이미지를 빌드하기 위해 Dockerfile의 모든 세부 정보를 무시할 수 있습니다. 다음을 입력하기만 하면 됩니다.
sbt dockerBuildAndPush
그런 다음 sbt-docker
플러그인은 인터넷에서 필요한 모든 조각을 다운로드하여 Docker 이미지를 빌드한 다음 localhost
의 Kubernetes 애플리케이션과 함께 이전에 시작된 Docker 레지스트리로 푸시합니다. 따라서 이미지가 요리되고 준비될 때까지 조금 더 기다리면 됩니다.
문제가 발생하면 다음 명령을 실행하여 모든 것을 알려진 상태로 재설정하는 것이 가장 좋습니다.
bin/stop-kube-local.sh bin/start-kube-local.sh
이러한 명령은 모든 컨테이너를 중지하고 올바르게 다시 시작하여 레지스트리가 sbt
에 의해 빌드 및 푸시된 이미지를 수신할 준비가 되도록 해야 합니다.
Kubernetes에서 서비스 시작
이제 애플리케이션이 컨테이너에 패키징되고 레지스트리에 푸시되었으므로 사용할 준비가 되었습니다. Kubernetes는 명령줄 및 구성 파일을 사용하여 클러스터를 관리합니다. 명령줄이 매우 길어질 수 있고 단계를 복제할 수도 있으므로 여기에서 구성 파일을 사용하고 있습니다. 소스 키트의 모든 샘플은 kube
폴더에 있습니다.
다음 단계는 이미지의 단일 인스턴스를 시작하는 것입니다. Kubernetes 언어에서는 실행 중인 이미지를 pod 라고 합니다. 다음 명령을 호출하여 포드를 생성해 보겠습니다.
bin/kubectl create -f kube/akkahttp-pod.yml
이제 다음 명령을 사용하여 상황을 검사할 수 있습니다.
bin/kubectl get pods
넌 봐야 해:
NAME READY STATUS RESTARTS AGE akkahttp 1/1 Running 0 33s k8s-etcd-127.0.0.1 1/1 Running 0 7d k8s-master-127.0.0.1 4/4 Running 0 7d k8s-proxy-127.0.0.1 1/1 Running 0 7d
상태는 실제로 다를 수 있습니다(예: "ContainerCreating"). "실행 중"이 되기까지 몇 초 정도 걸릴 수 있습니다. 또한 예를 들어 이전에 이미지를 만드는 것을 잊어버린 경우 "오류"와 같은 다른 상태를 얻을 수 있습니다.
다음 명령을 사용하여 포드가 실행 중인지 확인할 수도 있습니다.
bin/kubectl logs akkahttp
다음과 같이 끝나는 출력이 표시되어야 합니다.
[DEBUG] [05/30/2016 12:19:53.133] [default-akka.actor.default-dispatcher-5] [akka://default/system/IO-TCP/selectors/$a/0] Successfully bound to /0:0:0:0:0:0:0:0:9000
이제 서비스가 시작되어 컨테이너 내부에서 실행됩니다. 그러나 아직 서비스에 연결할 수 없습니다. 이 동작은 Kubernetes 설계의 일부입니다. 포드가 실행 중이지만 명시적으로 노출해야 합니다. 그렇지 않으면 서비스는 내부용입니다.
서비스 생성
서비스를 만들고 결과를 확인하는 것은 다음을 실행하는 문제입니다.
bin/kubectl create -f kube/akkahttp-service.yaml bin/kubectl get svc
다음과 같이 표시되어야 합니다.
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE akkahttp-service 10.0.0.54 9000/TCP 44s kubernetes 10.0.0.1 <none> 443/TCP 3m
포트는 다를 수 있습니다. Kubernetes는 서비스에 대한 포트를 할당하고 시작했습니다. Linux를 사용하는 경우 브라우저를 직접 열고 http://10.0.0.54:9000/ip/8.8.8.8
을 입력하여 결과를 볼 수 있습니다. Docker Toolbox와 함께 Windows 또는 Mac을 사용하는 경우 IP는 Docker를 실행하는 가상 머신에 로컬이며 불행히도 여전히 연결할 수 없습니다.
여기서 나는 이것이 Kubernetes의 문제가 아니라 Docker Toolbox의 제한이라는 점을 강조하고 싶습니다. 이는 차례로 다른 컴퓨터 내에서 컴퓨터처럼 작동하는 VirtualBox와 같은 가상 머신에 의해 부과되는 제약 조건에 따라 달라집니다. 이 한계를 극복하려면 터널을 만들어야 합니다. 일을 더 쉽게 하기 위해 우리가 배포한 모든 서비스에 도달하기 위해 임의의 포트에서 터널을 여는 또 다른 스크립트를 포함했습니다. 다음 명령을 입력할 수 있습니다.
bin/forward-kube-local.sh akkahttp-service 9000
터널은 백그라운드에서 실행되지 않습니다. 필요한 동안 터미널 창을 열어 두고 더 이상 터널이 필요하지 않을 때 닫아야 합니다. 터널이 실행되는 동안 http://localhost:9000/ip/8.8.8.8
을 열고 마지막으로 Kubernetes에서 실행 중인 애플리케이션을 볼 수 있습니다.
파이널 터치: 스케일
지금까지 우리는 애플리케이션을 Kubernetes에 "단순히" 넣었습니다. 이는 흥미로운 성과지만 배포에 너무 많은 가치를 추가하지는 않습니다. 서버에 업로드 및 설치하고 이에 대한 프록시 서버를 구성하는 수고에서 벗어났습니다.
Kubernetes가 빛나는 곳은 확장성입니다. 구성 파일의 복제본 수만 변경하여 애플리케이션의 인스턴스를 2개, 10개 또는 100개 배포할 수 있습니다. 그럼 해봅시다.
단일 포드를 중지하고 대신 배포를 시작하겠습니다. 따라서 다음 명령을 실행해 보겠습니다.
bin/kubectl delete -f kube/akkahttp-pod.yml bin/kubectl create -f kube/akkahttp-deploy.yaml
다음으로 상태를 확인합니다. 다시 한 번, 배포를 수행하는 데 시간이 걸릴 수 있으므로 몇 번 시도할 수 있습니다.
NAME READY STATUS RESTARTS AGE akkahttp-deployment-4229989632-mjp6u 1/1 Running 0 16s akkahttp-deployment-4229989632-s822x 1/1 Running 0 16s k8s-etcd-127.0.0.1 1/1 Running 0 6d k8s-master-127.0.0.1 4/4 Running 0 6d k8s-proxy-127.0.0.1 1/1 Running 0 6d
이제 하나가 아닌 두 개의 포드가 있습니다. 이는 내가 제공한 구성 파일에 시스템에서 생성된 두 개의 다른 이름과 함께 값 replica: 2
가 있기 때문입니다. 이 기사의 범위는 단순히 스칼라 프로그래머가 쿠버네티스로 뛰어드는 소개에 불과하기 때문에 구성 파일에 대한 자세한 내용은 다루지 않겠습니다.
어쨌든 이제 두 개의 포드가 활성화되었습니다. 흥미로운 점은 서비스가 이전과 동일하다는 것입니다. akkahttp
레이블이 지정된 모든 팟(Pod) 간에 로드 밸런싱하도록 서비스를 구성했습니다. 즉, 서비스를 다시 배포할 필요가 없지만 단일 인스턴스를 복제된 인스턴스로 교체할 수 있습니다.
프록시를 다시 시작하여 이를 확인할 수 있습니다(Windows를 사용 중이고 닫은 경우).
bin/forward-kube-local.sh akkahttp-service 9000
그런 다음 두 개의 터미널 창을 열고 각 포드에 대한 로그를 볼 수 있습니다. 예를 들어, 첫 번째 유형에서:
bin/kubectl logs -f akkahttp-deployment-4229989632-mjp6u
그리고 두 번째 유형에서:
bin/kubectl logs -f akkahttp-deployment-4229989632-s822x
물론 시스템에 있는 값에 따라 명령줄을 편집하십시오.
이제 두 개의 다른 브라우저로 서비스에 액세스해 보십시오. 다음 이미지와 같이 사용 가능한 여러 서버 간에 요청이 분할될 것으로 예상해야 합니다.
결론
오늘 우리는 표면을 거의 긁지 않았습니다. Kubernetes는 자동화된 확장 및 다시 시작, 증분 배포 및 볼륨을 포함하여 훨씬 더 많은 가능성을 제공합니다. 게다가 우리가 예제로 사용한 애플리케이션은 매우 간단하고 다양한 인스턴스가 서로를 알 필요가 없는 상태 비저장입니다. 현실 세계에서 분산 응용 프로그램 은 서로를 알아야 하며 다른 서버의 가용성에 따라 구성을 변경해야 합니다. 실제로 Kubernetes는 새 인스턴스가 배포될 때 서로 다른 애플리케이션이 서로 통신할 수 있도록 분산 키 저장소( etcd
)를 제공합니다. 그러나 이 예제는 핵심 기능에 중점을 두고 진행하는 데 도움이 되도록 의도적으로 충분히 작고 단순화되었습니다. 튜토리얼을 따르면 많은 세부 사항에 혼란스러워하고 복잡성에 길을 잃지 않고 시스템에서 Scala 애플리케이션을 위한 작업 환경을 얻을 수 있을 것입니다.
- 클라우드에서 클라우드용 개발: AWS에서 Docker를 사용한 빅데이터 개발
- K8s/Kubernetes: AWS 대 GCP 대 Azure
- Kubernetes 서비스 메시 비교