Getting start with Minikube

개발자 환경에서 간단하게 사용할 수 있는 k8s가 있어 시험적으로 사용하고 그 진행 과정을 정리해 보았다. 늘 기억의 한계가 있고 이렇게나마 기록을 해야 반복적인 실수를 줄일 수 있을 것 같아 거칠게라도 끄적여 본다.

Setup for mac os

설치를 편하게 하기 위해서 brew cask 를 사용한다. brew 에 설치할 수 있는 목록에 없는 앱들을 설치할 수 있다. brew-cask 참고 사이트

install docker

brew cask install docker

위의 명령으로 도커를 설치하면 docker, kubectl 명령을 사용할 수 있다.

install VM

맥에서 사용할 수 있는 vm 중에서 virtualbox 가 일반적이어서 이를 설치한다. vmware도 가능하나 유료이다. xhyve 역시 가능했지만 deprecate 되어서 최신 버전에서는 사용할 수 없다.

brew cask install virtualbox

설치 중에 오류가 나는데 맥 설정에서 oracle inc 의 앱들에 대해서 허가해 주고 다시 설치하면 성공적으로 설치가 완료된다.

install minikube

brew cask install minikube
minikube config set vm-driver virtualbox

minikube 설정 명령은 이전에 설치된 cluster 에 대해서 영향을 미치지 않기 때문에 삭제하고 다시 실행하라는 주의 사항이 나온다. 처음 실행 것이라면 흘려 넘기면 된다.

/usr/local/bin 아래에 kubectl, minikube 가 생성이 된다.

아래 명령으로 실행해보자.

$ minikube start
😄  minikube v1.0.1 on darwin (amd64)
🤹  Downloading Kubernetes v1.14.1 images in the background ...
🔥  Creating virtualbox VM (CPUs=2, Memory=2048MB, Disk=20000MB) ...
📶  "minikube" IP address is 192.168.99.100
🐳  Configuring Docker as the container runtime ...
🐳  Version of container runtime is 18.06.3-ce
⌛  Waiting for image downloads to complete ...
✨  Preparing Kubernetes environment ...
💾  Downloading kubelet v1.14.1
💾  Downloading kubeadm v1.14.1
🚜  Pulling images required by Kubernetes v1.14.1 ...
🚀  Launching Kubernetes v1.14.1 using kubeadm ... 
⌛  Waiting for pods: apiserver proxy etcd scheduler controller dns
🔑  Configuring cluster permissions ...
🤔  Verifying component health .....
💗  kubectl is now configured to use "minikube"
🏄  Done! Thank you for using minikube!

기존의 설치된 kubectl 이 버전이 안 맞을 수 있다. kubectl version 명령을 이용해서 클라이언트와 서버의 버전을 비교해 보면 알 수 있다. 안 맞는 경우는 minikube 를 설치하며 기존의 kubectl 을 대체하지 못해서 발생한다. 아래와 같이 이전 버전을 수동으로 대체시키면 된다.

sudo mv /usr/local/bin/kubectl /usr/local/bin/kubectl.org
brew link --overwrite kubernetes-cli

build container image

command line

자바 프로젝트에 아래와 같은 내용으로 Dockerfile 을 생성한다.

FROM openjdk:8-jre-alpine
VOLUME /tmp
ARG JAR_FILE
ADD target/${JAR_FILE} ${JAR_FILE}
ENV JAVA_OPTS=""
ENV JARFILE /${JAR_FILE}
EXPOSE 8080
ENTRYPOINT [ "sh", "-c", "java -Dspring.profiles.active=dev -jar $JARFILE" ]

JDK 는 8버전이고 가장 작은 크기인 jre-alpine 을 선택하였다. ADD 명령으로 jar 파일을 도커 안으로 추가한다. 컨테이너가 로딩되면 바로 실행할 명령을 ENTRYPOINT 에 기록한다. 바로 자바 프로젝트를 개발 환경으로 실행하는 명령이다. 실제 운영환경에서는 profile 을 dev 에서 prd 로 바꾸면 된다.

jar 파일을 JARFILE 변수명으로 처리한 것은 매번 배포할 때마다 바뀌는 버전에 따라 이 파일을 수정하지 않도록 변수로 처리하였다. pom.xml 파일에 지정된 jar 파일명을 이미지 빌드 시에 변수로 전달 받을 수 있다. dockerfile 에서 ARG 로 선언한다. java 실행 명령에도 파일명이 필요한데 sh 환경변수로 정의해서 명령어에 반영되도록 처리하였다.

도커 빌드를 사용해서 위에 정의된 dockerfile 에 따라 컨테이너 이미지를 빌드하기 위해 아래 명령을 실행한다.

docker build --build-arg JAR_FILE=hello-1.0.jar \
--tag demo/hello:1.0 .

이미지가 완성이 되면 아래 명령으로 컨테이너로 실행시킨다.

docker run -p 8080:8080 -d --rm --name hello -t demo/hello:1.0

-d 옵션으로 독립적으로 실행 되므로 터미널 창에서 다른 작업이 가능하다. –rm 옵션으로 컨테이너를 중지시키면 컨테이너 자체가 사라진다. 아니면 docker rm 명령으로 지워야한다. 아래 명령으로 컨테이너 실행 여부를 확인한다.

$ docker ps
CONTAINER ID  IMAGE           COMMAND                  CREATED
      STATUS              PORTS                    NAMES
ccd00eafafb6  demo/hello:1.0  "sh -c 'java -Dsprin…"   14 minutes ago
      Up 14 minutes       0.0.0.0:8080->8080/tcp   hello

컨테이너는 아래 명령으로 중지시킬 수 있다. 위 옵션 때문에 중지 후 바로 삭제가 된다. –rm 옵션이 없다면 STATUS 에 Exit 로 바뀌어 있고 목록에는 계속 나타난다.

docker stop hello

maven build

Maven 빌드를 이용해서 이미지를 생성할 수 있는데 dockerfile-maven-plugin 과 docker-maven-plugin 플러그인을 사용하면 된다. 아래와 같이 pom.xml 파일에 정의하면 된다.

우선 docker registry 에 동일 버전으로 계속 push 하게 되면 tag 명이 없이 이미지들이 쌓이게 된다. 따라서 아래와 같이 clean 단계에서 이미지를 지우는 작업을 추가할 수 있다.

   <build>
        <plugins>
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>remove-image</id>
                        <phase>clean</phase>
                        <goals>
                            <goal>removeImage</goal>
                        </goals>
                        <configuration>
                            <imageName>${docker.prefix}/${project.artifactId}</imageName>
                            <imageTags>
                                <imageTag>${project.version}</imageTag>
                            </imageTags>
                            <verbose>true</verbose>
                        </configuration>
                    </execution>
                </executions>
                </plugin>

다음은 빌드된 jar 파일을 위에서 만든 dockerfile 에 따라 컨테이너 이미지에 넣기 위해 플러그인을 선언한다. 플러그인의 선언 순서는 “spring-boot-maven-plugin” 다음으로 위치해야 정상적으로 빌드된 jar 파일에 작업할 수 있다.

<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>dockerfile-maven-plugin</artifactId>
    <version>1.4.3</version>
    <configuration>
        <repository>${docker.prefix}/${project.artifactId}</repository>
        <tag>${project.version}</tag>
        <buildArgs>
            <JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
        </buildArgs>
    </configuration>
    <executions>
        <execution>
            <id>default</id>
            <phase>package</phase>
            <goals>
                <goal>build</goal>
            </goals>
        </execution>
    </executions>
</plugin>

변수로 선언된 부분에 들어가는 값을 아래와 같이 속성으로 정의해 주어야 합니다.

<properties>
    <java.version>1.8</java.version>
    <docker.prefix>demo</docker.prefix>
</properties>

프로젝트 폴더를 선택하고 마우스 우클릭으로 Run as > Maven build 를 하면 clean compile package 과정을 거치면서 위에 선언한 build goal 을 실행하게 된다. 처리 결과는 docker build 명령의 실행결과와 동일함을 알 수 있다.

run under minikube

minikube 의 동작 환경에 맞게 현재 터미널 세션의 환경 설정을 해야한다. 간단히 다음 명령으로 한번에 설정이 가능하다.

eval $(minikube docker-env)

위에서 생성한 image 를 다음 명령으로 실행할 수 있다. 옵션 중에 image-pull-policy 를 사용하는데 이는 로컬의 컨테이너 이미지를 사용하기 위해서는 Never 로 지정해 주어야 외부 docker 저장소에서 다운 받지 않고 로컬 이미지를 사용하게 되기 때문이다.

kubectl run hello --image=demo/hello:1.0 --port=8080 --image-pull-policy=Never

아래 명령으로 실행 결과를 확인할 수 있다.

$ kubectl get deployments
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello     1         1         1            1           12s
$ kubectl get pods
NAME                   READY     STATUS    RESTARTS   AGE
hello-99f6c69f7-nj86p  1/1       Running   0          2m

주의사항

eclipse 에서 빌드하는 경우 docker 이미지를 찾을 수 없어서 STATUS 항목이 ErrImageNeverPull 로 표시가 된다. docker image list 명령으로 찾아 보면 해당 이름으로 등록된 이미지가 없다. 하지만 터미널에서 mvn 명령으로 빌드한 경우에는 등록이 된다. 이유는 eclipse 실행 환경과 터미널에 설정된 환경이 다르다. 위에서 터미널에서 실행한 환경 설정이 eclipse 에서는 안 되어있기 때문이다. 누락된 환경 설정을 eclipse 에 정의하여야 한다.

프로젝트 폴더 우클릭하고 Rus as > Run Configurations 을 클릭하면 maven 빌드 설정을 할 수 있는 창이 열린다. Environment 탭에 아래와 같이 환경변수와 값을 등록해주어야 한다. 값들이 사용자 환경마다 다르므로 minikube docker-env 명령으로 설정 값을 확인하고 맞춰주어야 한다.

변수명
DOCKER_HOST tcp://192.168.99.100:2376
DOCKER_CERT_PATH /Users/yourname/.minikube/certs

위의 설정이 없는 경우 minikube 에 도커 이미지를 등록할 수 없다. 현재 개발자의 pc 안에만 남기 때문에 minikube 에서는 이 이미지를 가지고 작업을 할 수 없다. 따라서 ErrImageNeverPull 라는 오류가 발생하는 것이다.

컨테이너 이미지가 pod에 배포가 성공적으로 되었다면 외부에서 이 컨테이너로 접근 할 수 있도록 아래 명령으로 노출을 시켜줘야 한다.

$ kubectl expose deployments hello --type=NodePort
service "hello" exposed

아래 명령은 브라우저를 실행해서 해당 웹 페이지를 볼 수 있게 한다.

curl $(minikube service hello-minikube --url)

만일 배포된 컨테이너 버전을 바꾸고 싶다면 (버전이 올라간 경우), 아래와 같이 명령을 실행하면 된다.

kubectl set image deployment/hello hello=demo/hello:1.1

using configuration file

위와 같이 명령을 이용하여 각각 배포와 서비스 노출을 하는 방법도 있으나 설정 파일을 만들고 필요한 설정을 미리 만들어서 한번에 실행하는 것이 더 편하다. 아래와 같이 YAML 파일을 만든다.

kind: Service
apiVersion: v1
metadata:
  name: hello
spec:
  selector:
    app: hello
  ports:
  - protocol: TCP
    port: 8080
    nodePort: 30001
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
spec:
  selector:
    matchLabels:
      app: hello
  replicas: 1
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
        - image: demo/hello-docker:1.0
          imagePullPolicy: Never
          name: hello
          ports:
            - containerPort: 8080

설정 파일을 지정해서 kubectl 을 실행한다.

kubectl create -f hello-docker.yaml

위의 명령으로 배포와 서비스 노출이 한번에 이루어진다. 아래 명령으로 서비스 생성까지 확인이 가능하다.

$ kubectl get services
NAME       TYPE       CLUSTER-IP   EXTERNAL-IP  PORT(S)         AGE
hello      NodePort   10.108.87.36 <none>       8080:30001/TCP  7m38s
kubernetes ClusterIP  10.96.0.1    <none>       443/TCP         5d20h

ending service

아래 명령으로 pod 에 실행되는 컨테이너를 종료할 수 있다.

kubectl delete service hello
kubectl delete deployment hello

만일 yaml 파일을 이용해서 실행한 경우라면 아래 명령으로 중지시킬 수 있다.

kubectl delete -f hello-docker.yaml

이력을 깨끗이 지우고 싶다면 아래와 같이 한다.

docker rmi demo/hello:1.0 -f
minikube stop
eval $(minikube docker-env -u)
minikube delete

Reference

https://howtodoinjava.com/docker/docker-hello-world-example/

https://kubernetes.io/ko/docs/setup/minikube/

Packaging a Java Application in a Docker Image with Maven

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중