블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 

KNative 를 보던중에, Autoscaling 처리를 어떻게 하는지 확인해보니,

기본은 Knative instance (한 Pod 겠지) 당 처리할 수 있는 concurrent request 수를 정해놓고, 이를 넘을 경우에 auto scaling 하는 방식이다. CPU가 아니라 connection 수를 통해서 한다. 

containerConcurrency limits the amount of concurrent requests are allowed into the application at a given time (hard limit), and is configured in the revision template.

스케일링 설정은


spec:
  template:
    metadata:
      autoscaling.knative.dev/minScale: "2"
      autoscaling.knative.dev/maxScale: "10"

min, max 값을 지정하는데, min 이 0 이면 콜드 스타트가 발생할 수 있기 때문에, 0 보다는 큰 수를 주는 것이 좋다. 


디폴트가 이 concurrent connection 수를 이용하는 방식인데, CPU 베이스도 가능하다.

spec:
  template:
    metadata:
      autoscaling.knative.dev/metric: concurrency
      autoscaling.knative.dev/class: hpa.autoscaling.knative.dev

위의 metric 모드를 사용하게 되면, concurrency 모드를 사용하게 되고, class 모드를 사용하게되면, HPA (Horizontal Pod Autoscaler)를 사용하게 된다. 


본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요


1. 클러스터는 Private IP 모드로 생성

이렇게 되면, Node는 External IP를 가지지 못한다. 즉 외부 접근을 막을 수 있다.

  • In bound : Pod로 들어오는 트래픽은 Node에  External IP가 없더라도, Service를 통해서 들어올 수 있다.
  • out bound : Cloud NAT를 설정하면 된다.
2. Master Node에 대한 접근 제안
Master authorized network 를 설정한후, authorized network에 master node를 사용할 (kubectl) 대역을 지정한다.


본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요

효율적인 도커 이미지 만들기

#2 도커 레이어 캐슁을 통한 빌드/배포 속도 높이기

조대협 (http://bcho.tistory.com)


도커는 이미지 단위로 빌드를 하고 배포를 하지만, 도커의 이미지는 여러개의 레이어로 되어 있다. 아래와 같은 자바 애플리케이셔을 패키징한 도커 컨테이너 이미지가 있다고 하자

FROM openjdk:8-jre-alpine

ARG ./target/hellospring-0.0.1-SNAPSHOT.jar

COPY ${JAR_FILE} app.jar

ENTRYPOINT ["java","-jar","/app.jar"]


이 이미지가 어떤 레이어로 구성되어 있는지를 보려면 %docker history {컨테이너 이미지명} 을 실행하면 이미지의 레이어를 볼 수 있는데,   각각의 명령항에 따라서 레이어가 생성된것을 볼 수 있다. 



그리고 각각의 크기를 확인할 수 있다. 위의 history를 보면, 




  • 맨 아래 5.53M가 알파인 리눅스의 베이스 이미지

  • 그리고 위에서 4번째 79.4M가 JRE 설치

  • 위에서 2번째가 33.8M로, 애플리케이션 파일 Jar을 복사한 내용

으로 확인할 수 있다. 계층은 여러개이지만, 주로 용량을 많이 사용하는 이미지는 이 3개의 계층임을 확인할 수 있다.


이 컨테이너에서 애플리케이션을 다시 컴파일 하고 패키징해서 push를 해보면 아래와 같이 33.82M에 해당하는 애플리케이션 Jar 만을 복사하고 나머지는 “Layer already exist”와 함께 별도로 레이어를 푸쉬하지 않는 것을 확인할 수 있다. 


도커 컨테이너는 효과적인 배포를 위해서 pull/push 시에, 레이어별로 캐슁을 해서, 변경이 없는 레이어에 대해서는 다시 pull/push를 하지 않는다

자바 애플리케이션을 여러개의 레이어로 나눈 경우

이 레이어별 캐슁 기능을 잘 활용하면, 애플리케이션 컨테이너의 push/pull 시간을 많이 단축시킬 수 있다. 첫번째 push/pull은 전체 이미지를 올려야하기 때문에 시간 차이는 없겠지만, 그 후 애플리케이션만을 업데이트할 경우에는 애플리케이션에 관련된 파일만 실제로 복사되도록하고, 나머지 레이어는 캐슁된 이미지를 사용하도록 하는 방법이다.


Springboot와 같은 자바 애플리케이션은 애플리케이션 파일은 /classes에 저장되지만, 나머지 참조하는 여러 jar 파일들이 있다. 이러한 jar 파일들은 변경이 없기 때문에, 다시 재배포할 필요가 없기 때문에 캐슁을 하도록 하는 것이 좋다.


그러나 앞의 예제에서는 이 모든 라이브러리 jar 파일들을 하나의 app.jar 에 묶어서 복사하는 구조이기 때문에, 라이브러리 jar 파일만을 별도로 캐슁할 수 없다. 

그래서, 아래와 같이 애플리케이션 jar 파일을 푼 다음에, 각각의 디렉토리를 별도로 복사하는 방법을 사용한다. mvn package 에 의해서 생성된 jar 파일을 target/depdency 라는 디렉토리에 풀고, 각 디렉토리를 Dockerfile에서 각각 복사하도록 설정하였다. 


FROM openjdk:8-jre-alpine

ARG DEPENDENCY=target/dependency

COPY ${DEPENDENCY}/BOOT-INF/lib /app/lib

COPY ${DEPENDENCY}/META-INF /app/META-INF

COPY ${DEPENDENCY}/BOOT-INF/classes /app

COPY ${DEPENDENCY}/org /org


ENTRYPOINT ["java","-cp","app:app/classes/*","com.terry.HellospringApplication"]


이렇게 하게 되면, 사용자가 작성한 코드는 /classes 에 컴파일 된 상태로 저장되고, 나머지 라이브러리들은 /BOOT-INF/lib  등의 디렉토리에 저장된다. 이를 각각 Dockerfile에서 COPY 명령으로 복사하게 되면 별도의 레이어로 생성된다. 

아래는 위의 Dockerfile을 이용해서 빌드한 이미지의 레이어이다. 



앞의 예제의 경우 애플리케이션 jar 파일이 33.82M의 단일 레이어로 생성되었지만, 이 컨테이너는 176k,1.34k,1.84k,16.7M  4개의 레이어로 생성된것을 확인할 수 있다. 




이중에서 1.84k,16.7M 레이어는 Springboot 라이브러리이기 (jar파일) 때문에 변경이 없다. 그래서 캐슁이 가능한데, 


아래는 이 컨테이너를 한번 등록해놓고, 그 다음 애플리케이션 코드를 변경해서 새로 빌드하고 푸슁하는 과정이다. 


보는 것과 같이 위의 2 레이어만 새롭게 푸슁되는 것을 확인할 수 있다. 

이렇게 하면, 아래 OS 레이어, JRE, 그리고 Spring boot의 jar 라이브러리들은 모두 캐슁되고, 배포시에는 실제로 애플리케이션 class 파일만 전송되게 되기 때문에 배포 시간을 많이 단축할 수 있다.


이때 주의 할점은 기존 디렉토리에

BOOT-INF/classes

BOOT-INF/lib

META/lib

org


이런 디렉토리들이 있는데, mvn으로 새롭게 jar를 빌드한후 target/dependecy 파일에 전체 파일을 풀어버리게 되면 4개의 디렉토리가 모두 업데이트가 된다. BOOT-INF/lib,META/lib,org 디렉토리의 실제 파일 내용이 변경이 되지 않았다 하더라도, 새로운 파일로 업데이트하였기 때문에, 파일의 해쉬값이 변경되게 되고, Docker 는 빌드시에, 이 디렉토리가 변경이 되었다고 판단하고 기존의 캐슁된 레이어를 재활용하지 않고 새롭게 레이어를 생성해서 push 하기 때문에, 실제 캐쉬 효과를 볼 수 없다. 

그래서 빌드 과정에서 기존에 변경되지 않은 파일과 디렉토리는 건들지 않고, 변경된 파일만 업데이트 하도록 빌드를 구성해야 한다. 


여기서는 자바 애플리케이션을 기준으로 설명하였지만, Javascript나, 이미지와 같은 정적 파일이 있거나 라이브러리나 드라이브 설치등의 중복되는 부분이 많은 애플리케이션의 경우에는 같은 원리로 각각 레이어를 나눠 놓으면, 캐슁을 통한 push/pull 속도 절약의 효과를 볼 수 있다.


예제 파일은 스프링부트 홈페이지를 참고하였습니다. :)

본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요

효율적인 도커 이미지 만들기

#1 작은 도커 이미지 만들기

조대협 (http://bcho.tistory.com)


일반적으로 도커를 이용해서 자바 애플리케이션 컨테이너를 빌드하면 보통 사이즈가 500~700M 로 배우 큰 이미지가 생성된다. 이는 Ubuntu와 같은 일반 OS 이미지 위에, JDK/JRE를 설치하기 때문인데, 실제로 자바 애플리케이션만을 실행할때는 기타 툴들 (ftp,telnet, 기타 시스템 데몬)이 필요하지 않다.


도커 이미지 사이즈는 빌드와 배포 시간에 많은 영향을 주고, 쿠버네티스와 같은 컨테이너 스케쥴링 솔루션의 경우 도커 이미지가 디스크 공간을 잡아 먹기 때문에, 작은 컨테이너가 여러모로 이점이 많다. 

작은 도커 이미지 만들기

alpine linux는 경량화를 추구하면서 보안을 강화한 이미지로 꼭 필요한 라이브러리와 시스템 데몬이 포함되어 있기 때문에 일반적인 OS이미지에 비해서 그 사이즈가 매우작다.



<그림. 이미지 사이즈별 비교> 

Java alpine 이미지

alpine linux를 기본으로 해서, 애플리케이션 구동을 위한 이미지들이 이미 많이 있는데, java의 경우 openjdk 기반의 alpine 이미지가 있다. 이미지 명은 openjdk:<자바 버전> 식으로 되고, 만약 java-8인 경우 openjdk:8 식으로 정의된다. alpine 리눅스용 openjdk 이미지는 openjdk:<자바버전>-alpine 이 된다. 


아래는 openjdk:8과, openjdk:8-alpine 이미지로 만든 컨테이너의 사이즈 비교이다. 간단한 Hello World Spring boot jar 파일 (17M정도)를 포함하였다. 



사이즈는 openjdk:8 이미지가 552M, openjdk:8-alpine은 139M가 나오는 것을 확인할 수 있다.


JDK보다는 JRE

흔히들 하는 실수중의 하나가 자바 런타임용 컨테이너를 만들때, 컴파일러가 포함된 JDK 환경을 사용한다는 것이다. 보통 자바 런타임은 JDK 없이 JRE 만 있어도 충분하다. 아래는 JRE 8 Alpine 리눅스 이미지를 이용해서 만든 컨테이너 이다.  베이스 이미지 명은 openjdk:<자바 버전>-jre-alpine 을 사용한다. 




OpenJDK 8-alpine은 139M, OpenJDK 8 JRE alpine은 119M가 되는 것을 확인할 수 있다. (20M정도 더 적다)

그러면 항상 OpenJDK에 대한 alpine JRE 이미지를 사용할 수 있는가? 답은 아니다. https://hub.docker.com/_/openjdk?tab=tags 에 들어가면 공식적으로 배포되어 있는 이미지를 확인할 수 있는다. JDK 버전에 따라서 alpine 리눅스를 안정적으로 지원하지 않을 경우에는 해당 이미지가 제공되지 않고, 다른 Linux를 사용하기 때문에, 이미지 사이즈가 200M가 넘는다. 이럴 경우에는 대안으로 Docker slim 이미지를 사용하면 된다. 


그러면 이러한 이미지들은 믿을만 한가? 도커 컨테이너 리파지토리인 hub.docker.com에서 openjdk를 찾아보면 다음과 같이 “Docker Official Images” 라는 마크가 나온다. 


이 이미지는 도커에서 관리하는 이미지로, 도커환경에 최적화 되어 있고, 또한 보안 위협에 대한 내용을 스캔해서 안전하게 제거되는 이미지이다. 

“Each of the images in the Official Images is scanned for vulnerabilities. The results of these security scans provide valuable information about which images contain security vulnerabilities, and allow you to choose images that align with your security standards.”

출처 : https://docs.docker.com/docker-hub/official_images/


결론적으로 이야기 하자면, 도커 허브에서 제공되는 Official 이미지를 사용하되, alpine 리눅스 기반으로 되어 있는 이미지를 사용하는 것이 가장 좋다.

본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요