본문 바로가기
kubernetes

Kubernetes 환경에서의 spring boot 개발 workflow 익히기

by tango0415 2020. 9. 8.

git repo: https://github.com/jaekwonHa/practice-spring-on-k8s-workflow

kubernetes 환경에서 동작하는 Spring boot 어플리케이션을 개발할 때, 특히 kubernetes 를 이제 막 시작하는 경우 너무 많은 도구들이 존재해 뭐부터 사용해야 할 지 막막한 경우가 있습니다.

이 글에서는 intellij + spring boot + local kubernetes cluster 환경에서 내가 수정한 코드를 kubernetes 에 빠르게 배포, 테스트하고자 할 때 유용한 도구들에 대해서 소개해봅니다.

  • jib
  • docker-credential
  • cloud code
  • stern
  • kustomize
  • skafold

jib

https://github.com/GoogleContainerTools/jib

jib 는 java 어플리케이션을 도커 혹은 OCI 이미지로 최적화해주는 maven, gradle plugin 입니다.

maven, gradle plugin 이라는 점에서 감이 오셨겠지만, 작성 중인 코드를 빌드 시에 도커 이미지로 만들어 주는 과정을 수행할 수 있고, docker hub 혹은 private registry 에 push 하는 것도 가능합니다. 이 과정에서 docker daemon 이 필요하지 않습니다.

https://cloudplatform.googleblog.com/2018/07/introducing-jib-build-java-docker-images-better.html

plugins {
    id 'com.google.cloud.tools.jib' version '2.1.0'
}

build.gradle 에 위와 같이 추가해주면 아래 세가지 명령어를 추가로 사용할 수 있습니다.

  • jib
    • container image 를 빌드하고 원격 registry 에 이미지를 push 합니다.
  • jibBuildTar
    • container image 를 빌드하고, tar 형태로 압축합니다.
  • jibDockerBuild
    • local docker deamon 을 이용하여 container image 를 빌드합니다. local docker daemon 을 사용하기에 local 에만 image 가 올라갑니다.
> docker history myapp:0.0.1-SNAPSHOT
IMAGE               CREATED             CREATED BY                SIZE                COMMENT
c586959dbfe3        50 years ago        jib-gradle-plugin:2.1.0   1.41kB              classes
<missing>           50 years ago        jib-gradle-plugin:2.1.0   1B                  resources
<missing>           50 years ago        jib-gradle-plugin:2.1.0   18.3MB              dependencies
<missing>           50 years ago        bazel build ...           100MB               
<missing>           50 years ago        bazel build ...           8.41MB              
<missing>           50 years ago        bazel build ...           1.93MB              
<missing>           50 years ago        bazel build ...           15.1MB              
<missing>           50 years ago        bazel build ...           1.79MB              

docker image layer 를 보면 class, resources, dependencies 로 layer 가 나뉘어 어느정도 최적화됨을 알 수 있습니다.

docker-credential

https://docs.docker.com/engine/reference/commandline/login/

jib 를 사용하여 원격 registry 에 이미지를 push 하려다보면 당연히 registry 에 대한 인증이 필요합니다.

docker-credential 은 docker login 명령어로 생성할 수 있지만 jib 에서 docker hub 로 이미지를 올려주기 위해서는 아래와 같은 명령어가 필요합니다.

> docker login registry.hub.docker.com -u {{ USER NAME }} -p {{ PASSWORD }}
> docker-credential-desktop list
> docker-credential-osxkeychain list

이렇게 생긴 docker-credential 중 특정하게 사용하고 싶은게 있다면 build.gradle 에 jib.to.credHelper 를 선언해주면 편리합니다.

jib {
  from {
    image = 'openjdk:alpine'
  }
  to {
    image = 'localhost:5000/my-image/built-with-jib'
    credHelper = 'osxkeychain'
    tags = ['tag2', 'latest']
  }
  container {
    jvmFlags = ['-Dmy.property=example.value', '-Xms512m', '-Xdebug']
    mainClass = 'mypackage.MyApp'
    args = ['some', 'args']
    ports = ['1000', '2000-2003/udp']
    labels = [key1:'value1', key2:'value2']
    format = 'OCI'
  }
}

Cloud Code

https://plugins.jetbrains.com/plugin/8079-cloud-code

Cloud Code 란 intellij, vs code 에서 사용할 수 있는 kubernetes 파일 작성, 배포, 모니터링을 도와주는 ide plugin 입니다.

intellij 로 clode code plugin 을 설치하게 되면 다양한 기능들을 사용할 수 있습니다.

yaml 파일 작성 시 자동완성

위 스크린샷은 deployment.yaml 파일 작성 시 자동완성 해주는 부분인데, 옵션이 다양하다보니 딱 원하는 대로 생성해주진 않고, 생성 후에 수정이 필요합니다.

Kubernetes Cluster Monitoring

kubeconfig 파일을 불러와 cluster 의 전체적인 형상을 보여주는 화면입니다. 위 화면은 로컬에서 만들어진 kubernetes cluster 입니다.

Run Configuration

gradle + spring boot 어플리케이션을 Run/Debug 할때 ./gradlew bootRun -Dspring.profiles.active=dev 와 같은 명령어를 사용하듯, kubernetes + spring boot 어플리케이션을 Run/Debug 할 수 있는 Run Configuration 입니다.

소스 코드가 변경되었을때 자동으로 re-deploy 해준다거나, 특정 파라미터를 주어 실행시킨다거나, 브레이킹 포인트를 걸어 디버깅할 수도 있습니다.

우리가 gradlew 명령어를 사용할 수 있듯이, 이런 기능은 skafold 명령어를 사용해서 직접 실행할 수도 있습니다.

stern

https://github.com/wercker/stern

cluster 에 여러개의 pod를 띄웠을때, 로그를 보기 위해서는 각 pod에 접근해서 로그를 보거나, 터미널을 화면 분할하여 모든 pod에 tail을 걸어둬야 할 겁니다.

stern 명령어는 정규표현식으로 작성된 쿼리에 대해 일치하는 name 의 pod 로그를 모두 출력해줍니다.

> stern myapp
+ myapp-55c6d5c79f-p2cjk › myapp
myapp-55c6d5c79f-p2cjk myapp 
myapp-55c6d5c79f-p2cjk myapp   .   ____          _            __ _ _
myapp-55c6d5c79f-p2cjk myapp  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
myapp-55c6d5c79f-p2cjk myapp ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
myapp-55c6d5c79f-p2cjk myapp  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
myapp-55c6d5c79f-p2cjk myapp   '  |____| .__|_| |_|_| |_\__, | / / / /
myapp-55c6d5c79f-p2cjk myapp  =========|_|==============|___/=/_/_/_/
myapp-55c6d5c79f-p2cjk myapp  :: Spring Boot ::        (v2.3.3.RELEASE)
myapp-55c6d5c79f-p2cjk myapp 
...

kustomize

https://kustomize.io/

kustomize 란 쿠버네티스 구성을 환경에 따라 사용자가 원하는대로 설정을 변경하고, 기존코드의 재사용성을 높일 수 있는 도구입니다.

예를 들면 아래와 같이 deployment, service 구성을 가지고 있는 클러스터가 있을 때

  • 환경별로 쿠버네티스 리소스의 이름 앞에 붙여줄 prefix 를 다르게 한다던가
  • spring boot 어플리케이션 구동 시 profiles 을 다르게 한다던가
  • pod 개수를 다르게 유지한다던가
    하는 등의 구체적인 설정을 다르게 주어야 하는 니즈가 있을 수 있습니다.

이런 경우에 kustomize 를 사용한다면, base/ 하위 코드로 쿠버네티스를 구성하고, 환경별로 설정을 나누어 관리할 수 있습니다.

build 명령어를 수행해보면 아래와 같이 완성된 리소스들의 yaml 파일이 출력되고, 이를 바로 실행하게 되면 클러스터 구성이 시작됩니다.

> kustomize build overlays/production
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: myapp
  name: myapp
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: myapp
status:
  loadBalancer: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: myapp
  name: myapp
spec:
  replicas: 5
  selector:
    matchLabels:
      app: myapp
  strategy: {}
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - env:
        - name: spring.profiles.active
          value: production
        image: hazxz/myapp
        name: myapp
        resources: {}
status: {}

> kustomize build overlays/production | k apply -f -

skafold

https://skaffold.dev/

skafold 란 쿠버네티스 기반에서의 개발, 테스트, 디버깅을 도와주는 도구입니다.

개발 도중 수정된 코드를 쿠버네티스에 반영하기 위해서는, 컴파일-컨테이너 이미지 빌드-태그 추가-변경된 이미지 반영...등 반복적인 작업이 필요합니다.

이런 과정을 자동화해주어 수정된 코드를 바로 쿠버네티스 환경에서 테스트 해볼 수 있게 해줍니다.

만약 kustomize 와 같이 사용한다면 아래와 같은 skaffold.yaml 파일을 만들어서 쿠버네티스 환경에서 빠르게 개발,테스트 할 수 있습니다.

각 파일들의 내용은 블로그 상단의 git repo 에서 참고하실 수 있습니다.

apiVersion: skaffold/v2beta7
kind: Config
metadata:
  name: myapp
build:
  artifacts:
    - image: hazxz/myapp
      jib: {}
deploy:
  kustomize:
    paths:
      - k8s/base
profiles:
  - name: development
    deploy:
      kustomize:
        paths:
          - k8s/overlays/development
  - name: production
    deploy:
      kustomize:
        paths:
          - k8s/overlays/production
> skaffold init --skip-build
> skaffold dev --port-forward=true --profile=production
Listing files to watch...
 - hazxz/myapp
Generating tags...
 - hazxz/myapp -> hazxz/myapp:71c040e
Checking cache...
 - hazxz/myapp: Found. Tagging
Tags used in deployment:
 - hazxz/myapp -> hazxz/myapp:d3a0814108063745f985eb32ef82d5e4569e8999bf7fe1a5de6e6af1a67abf0d
Starting deploy...
 - service/myapp created
 - deployment.apps/myapp created
Waiting for deployments to stabilize...
 - deployment/myapp is ready.
Deployments stabilized in 3.827892089s
Port forwarding service/myapp in namespace default, remote port 80 -> address 127.0.0.1 port 4503
Press Ctrl+C to exit
Watching for changes...
[myapp] 
[myapp]   .   ____          _            __ _ _
[myapp]  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
[myapp] ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
[myapp]  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
[myapp]   '  |____| .__|_| |_|_| |_\__, | / / / /
[myapp]  =========|_|==============|___/=/_/_/_/
[myapp]  :: Spring Boot ::        (v2.3.3.RELEASE)
[myapp] 
[myapp] 
[myapp]   .   ____          _            __ _ _
[myapp]  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
[myapp] ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
[myapp]  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
[myapp]   '  |____| .__|_| |_|_| |_\__, | / / / /
[myapp]  =========|_|==============|___/=/_/_/_/
[myapp]  :: Spring Boot ::        (v2.3.3.RELEASE)
[myapp] 
[myapp] 
[myapp]   .   ____          _            __ _ _
[myapp]  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
[myapp] ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
[myapp]  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
[myapp]   '  |____| .__|_| |_|_| |_\__, | / / / /
[myapp]  =========|_|==============|___/=/_/_/_/
[myapp]  :: Spring Boot ::        (v2.3.3.RELEASE)
...
...

production 구성으로 띄워서 총 5개의 파드가 생성되어 로그가 중복되어 보입니다.

skaffold dev --port-forward=true --profile=production 명령어 수행시에 코드를 수정하면 다시 빌드, 배포가 이뤄지는 것을 볼 수 있고, port-forward true 로 주었기 때문에, 로그 중에 port 4503 라는 부분을 참고하여 해당 포트로 API 를 호출해볼 수도 있습니다.

또한 직접 명령어를 수행할 수도 있지만, Cloud Code 의 Run Configuration 을 이용하여 IDE 를 통해 실행하는 것도 가능합니다.

참고