1. 알고자 하는 것
2. 주요 환경
3. Spring Boot Starter 를 만든다
4. local Docker repository 만들기
5. Script 만들기
6. Apply 해제 및 재 실행
1. 알고자 하는 것
alpine os를 기반으로 하는 docker image가 kubernetes에서 실행되면서 이미지 내 cpu와 memory를 각 프로세스가 얼마나 점유하는지를 확인 하고자 한다.
2. 주요 환경
kubeadm 및 kubectl이 설치가 완료 되어있고 node는 한개 이상이 있다고 전제한다.
k9s의 기초 이야기는 여기서 하지 않을 예정이다.
3. Spring Boot Starter 를 만든다
alpine os에 어떤 프로세스가 cpu와 memory를 얼마나 먹는지 알아보기 위해서, java를 사용하는 spring boot sample app을 만들어 보고자 한다.
curl https://start.spring.io/starter.tgz \
-d dependencies=web,actuator \
-d language=java \
-d type=gradle-project \
-d applicationName=HelloApplication \
-d groupId=example.hello \
-d name=hello \
-d baseDir=hello \
| tar -xzvf -
bash
상기는 spring initializer로써 좋은 Spring Boot 시작점이 될 수 있다.
hello/
hello/.gitignore
hello/settings.gradle
hello/src/
hello/src/main/
hello/src/main/java/
hello/src/main/java/example/
hello/src/main/java/example/hello/
hello/src/main/java/example/hello/demo/
hello/src/main/java/example/hello/demo/HelloApplication.java
hello/src/main/resources/
hello/src/main/resources/templates/
hello/src/main/resources/application.properties
hello/src/main/resources/static/
hello/src/test/
hello/src/test/java/
hello/src/test/java/example/
hello/src/test/java/example/hello/
hello/src/test/java/example/hello/demo/
hello/src/test/java/example/hello/demo/HelloApplicationTests.java
hello/gradlew
hello/HELP.md
hello/gradle/
hello/gradle/wrapper/
hello/gradle/wrapper/gradle-wrapper.properties
hello/gradle/wrapper/gradle-wrapper.jar
hello/build.gradle
hello/gradlew.bat
bash
위와 같이 hello 폴더에 소스가 다운로드 받아진다.
이제 해당 프로젝트를 Dockerfile로 빌드하고 이미지화 할 수 있도록 해야한다.
FROM gradle:6.9.0-jdk11-openj9 as builder
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle build
FROM openjdk:14-alpine3.10
COPY --from=builder /home/gradle/src/build/libs/demo-0.0.1-SNAPSHOT.jar demo.jar
EXPOSE 8080
CMD ["java", "-jar", "demo.jar"]
shell
순서데로 jdk11 이미지로 source를 artifact로 만들어 준다.
만들어진 artifact를 실행할 alpine 이미지를 이용해서 실행 가능하도록
artifact이름을 "demo.jar"로 변경해 주고 alpine 이미지의 root에 해당 jar를 copy해준다.
마지막으로 8080포트를 열어주고 java -jar demo.jar 가 실행 될 수 있도록 entrypoint를 만들어 준다.
docker build -t hello
shell
Dockerfile이 있는 폴더에서 상기 명령어를 입력하면 hello 이미지가 docker에 등록 된다.
만들어진 이미지를 아래와 같이 hello.yaml을 만들어서 deploy 시키면 된다.
apiVersion: v1
kind: Service
metadata:
name: hello
spec:
ports:
- name: web
nodePort: 32500
port: 8080
protocol: TCP
selector:
app: hello
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
labels:
app: hello
spec:
selector:
matchLabels:
app: hello
replicas: 1
template:
metadata:
labels:
app: hello
spec:
containers:
- name: hello
image: hello:latest
ports:
- containerPort: 8080
shell
위 파일을 이제 k9s에 아래의 명령어로 등록해 주면된다.
kubectl apply -f hello.yaml
shell
상기 명령어가 정상적으로 이루어졌다면 다음과 같은 글이 나오게 된다.
service/hello created
deployment.apps/hello created
shell
kubectl get deployments,pods,services
shell
get 명령어를 통해서 pods와 services등록이 완료 된것을 확인 할 수 있다.
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/hello 0/1 1 0 111s
NAME READY STATUS RESTARTS AGE
pod/hello-577c59484f-7z8tw 0/1 ImagePullBackOff 0 111s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/hello NodePort 10.106.236.40 <none> 8080:32500/TCP 111s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23m
shell
이제 hello가 잘 작동하는지 확인해 보자.
두번재 pod를 보면 Status가 ImagePullBackOff상태이다.
앞서서 만든 hello이미지를 public docker repository 또는 local docker repository에서 갖어 오지 못하는 이유 때문이다.
minikube를 사용할 경우
https://stackoverflow.com/a/42564211
위 아티클을 보면 된다.
4. local Docker repository 만들기
helm을 install 하자
https://helm.sh/docs/intro/install/#from-apt-debianubuntu
curl https://baltocdn.com/helm/signing.asc | sudo apt-key add -
sudo apt-get install apt-transport-https --yes
echo "deb https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt-get update
sudo apt-get install helm
shell
install이 완료 되었다면 로컬 repository를 다음과 같이 만들어준다.
helm repo add twuni https://helm.twun.io
shell
helm install registry twuni/docker-registry \
--version 1.10.0 \
--namespace kube-system \
--set service.type=NodePort \
--set service.nodePort=31500
shell
정상적으로 등록이 되었다면 다음과 같이 확인이 가능하다.
get service --namespace kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dash-kubernetes-dashboard NodePort 10.100.109.37 <none> 80:30000/TCP 38m
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 38m
registry-docker-registry NodePort 10.107.199.93 <none> 5000:31500/TCP 28m
shell
마지막에 registry-docker-registry가 등록 된 것을 확인 할 수 있다.
$ curl localhost:31500/v2/_catalog
{"repositories":["hello"]}
shell
cur을 31500포트를 이용해 실행하면 위와 같이 레파지토리가 등록 되면 된다.
해당 repository에 등록을 위해서는 docker를 build할때 이름을 push대상과 일치 시켜줘야 한다.
$ docker build -t localhost:31500/hello .
shell
빌드가 완료 되면 아래와 같이 image가 local에 등록된다.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost:31500/hello latest 289934149f67 9 seconds ago 360MB
shell
해당 이미지를 local repository에 등록해 주자.
$ docker push localhost:31500/hello
The push refers to repository [localhost:31500/hello]
1571079e3f46: Layer already exists
f199ad476e12: Layer already exists
531743b7098c: Layer already exists
latest: digest: sha256:23694be6e320daffceccb5f78e4ba4801351bdb83db9c47838a8e211c13ed26c size: 953
controlplane $
shell
이제 거의다 되었다.
다시 yaml을 apply 시켜보자.
$kubectl apply -f hello-resolved.yaml
service/hello created
deployment.apps/hello created
shell
$ kubectl get deployments,pods,services
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/hello 1/1 1 1 11s
NAME READY STATUS RESTARTS AGE
pod/hello-8445fd55cb-g8bqk 1/1 Running 0 11s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/hello NodePort 10.111.55.187 <none> 8080:32500/TCP 11s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 50m
shell
이제 Status가 Running상태가 되었다.
$ curl localhost:32500/
{"timestamp":"2022-01-12T15:33:38.128+00:00","status":404,"error":"Not Found","path":"/"}
shell
curl을 해보면 루트 path가 없다는 내용이 나오는데 이 자체만으로 was가 작동한다고 보면 된다.
이젠 해당 인스턴스가 실행한 후로 cpu와 memory가 어떻게 사용되는지 알아보자.
5. Script 만들기
alpine os에서 java가 실행되기전에 os의 top을 주기적으로 실행시키면서 파일에 로그를 남기도록 하려고 한다.
이를 이를 위해서는 간단한 script가 필요한데, 다음과 같이 작성 하였다.
abc.sh
#!/bin/sh
top -b > top.log &
java -jar demo.jar
shell
이미지 내에서 top을 주기적으로 top.log에 담고, java로 was를 실행 시킨다는 의미이다.
Dockerfile에서 entry point는 하나임으로 해당 부분을 수정해 해야한다.
FROM gradle:6.9.0-jdk11-openj9 as builder
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle build
FROM openjdk:14-alpine3.10
# Copy JAR into container image
COPY --from=builder /home/gradle/src/build/libs/demo-0.0.1-SNAPSHOT.jar demo.jar
COPY abc.sh abc.sh
EXPOSE 8080
# Run application using executable jar application
CMD ["sh","abc.sh"]
shell
다시 docker를 build하자.
$ docker build -t localhost:31500/hello .
Sending build context to Docker daemon 93.18kB
Step 1/9 : FROM gradle:6.9.0-jdk11-openj9 as builder
---> 8e83f98d5588
Step 2/9 : COPY --chown=gradle:gradle . /home/gradle/src
---> 9e370ca3e7e9
Step 3/9 : WORKDIR /home/gradle/src
---> Running in 5e12399a00b7
Removing intermediate container 5e12399a00b7
---> 27b9a4a4e905
Step 4/9 : RUN gradle build
---> Running in 7de5dbc5c6c8
Welcome to Gradle 6.9!
Here are the highlights of this release:
- This is a small backport release.
- Java 16 can be used to compile when used with Java toolchains
- Dynamic versions can be used within plugin declarations
- Native support for Apple Silicon processors
For more details see https://docs.gradle.org/6.9/release-notes.html
Starting a Gradle Daemon (subsequent builds will be faster)
> Task :compileJava
> Task :processResources
> Task :classes
> Task :bootJarMainClassName
> Task :bootJar
> Task :jar
> Task :assemble
> Task :compileTestJava
> Task :processTestResources NO-SOURCE
> Task :testClasses
> Task :test
> Task :check
> Task :build
BUILD SUCCESSFUL in 35s
7 actionable tasks: 7 executed
Removing intermediate container 7de5dbc5c6c8
---> aef7d468fd2a
Step 5/9 : FROM openjdk:14-alpine3.10
---> 8273876b08aa
Step 6/9 : COPY --from=builder /home/gradle/src/build/libs/demo-0.0.1-SNAPSHOT.jar demo.jar
---> 7267df16b644
Step 7/9 : COPY abc.sh abc.sh
---> a953f0e98a6e
Step 8/9 : EXPOSE 8080
---> Running in e90c8ccf8cf0
Removing intermediate container e90c8ccf8cf0
---> 22e45dde75b9
Step 9/9 : CMD ["sh","abc.sh"]
---> Running in e19e6e284609
Removing intermediate container e19e6e284609
---> 364a1f655000
Successfully built 364a1f655000
Successfully tagged localhost:31500/hello:latest
shell
이미지가 잘 빌드 되었다. 다시 레파지토리에 등록하자.
docker push localhost:31500/hello:latest
The push refers to repository [localhost:31500/hello]
61808d9147b4: Pushed
123cb3333dd3: Pushed
f199ad476e12: Layer already exists
531743b7098c: Layer already exists
latest: digest: sha256:91a64110c666cd336ba4fa4c38c346b4fac803696917c76c1176ce276a622628 size: 1160
shell
6. Apply 해제 및 재 실행
이제 해당 이미지를 다시 실행해야 한다. 이를 위해 앞선 yaml을 해제 하고 다시 등록 해야한다.
kubectl delete -f hello-resolved.yaml
service "hello" deleted
deployment.apps "hello" deleted
shell
kubectl apply -f hello-resolved.yaml
service/hello created
deployment.apps/hello created
shell
잘 동작 하는지 확인하자.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-8445fd55cb-s9bps 1/1 Running 0 14s
shell
$ curl localhost:32500/
{"timestamp":"2022-01-12T15:48:02.523+00:00","status":404,"error":"Not Found","path":"/"}
shell
이제 마지막 단계이다.
해당 인스턴스가 실행되면서 어떤 프로세스가 cpu와 메모리를 얼마나 사용했는지 확인하자.
$ kubectl exec --stdin --tty hello-8445fd55cb-s9bps -- /bin/sh
/ # ls
abc.sh demo.jar etc lib mnt proc run srv tmp usr
bin dev home media opt root sbin sys top.log var
shell
상기는 hello pod에 sh로 접근해서 top.log가 root write된것을 확인 할 수 있다.
아... log잘찍힌 것 까지 여기 붙이고 싶었는데, 테스트 서버 사용시간이 완료 되어서.. 끝나 버렸다.
그래도... 로그찍어야 겠지...
다시 !
abc.sh demo.jar etc lib mnt proc run srv tmp usr
bin dev home media opt root sbin sys top.log var
/ # cat top.log
Mem: 2458124K used, 1580980K free, 1380K shrd, 115460K buff, 1866268K cached
CPU: 68% usr 15% sys 0% nic 15% idle 0% io 0% irq 0% sirq
Load average: 0.32 0.21 0.12 3/311 20
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
8 1 root S 2449m 61% 1 74% java -jar demo.jar
1 0 root S 1620 0% 1 0% sh abc.sh
7 1 root R 1560 0% 0 0% top -b
Mem: 2561480K used, 1477624K free, 1400K shrd, 115480K buff, 1866392K cached
CPU: 57% usr 2% sys 0% nic 40% idle 0% io 0% irq 0% sirq
Load average: 0.54 0.25 0.14 1/316 25
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
8 1 root S 2512m 63% 1 58% java -jar demo.jar
1 0 root S 1620 0% 1 0% sh abc.sh
7 1 root R 1564 0% 0 0% top -b
Mem: 2566960K used, 1472144K free, 1400K shrd, 115488K buff, 1866400K cached
CPU: 5% usr 0% sys 0% nic 94% idle 0% io 0% irq 0% sirq
Load average: 0.49 0.25 0.14 1/320 29
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
8 1 root S 2518m 63% 1 4% java -jar demo.jar
1 0 root S 1620 0% 1 0% sh abc.sh
7 1 root R 1564 0% 0 0% top -b
Mem: 2565296K used, 1473808K free, 1400K shrd, 115504K buff, 1866400K cached
CPU: 2% usr 0% sys 0% nic 97% idle 0% io 0% irq 0% sirq
Load average: 0.45 0.24 0.14 1/320 29
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
8 1 root S 2518m 63% 1 0% java -jar demo.jar
1 0 root S 1620 0% 1 0% sh abc.sh
7 1 root R 1564 0% 0 0% top -b
Mem: 2565248K used, 1473856K free, 1400K shrd, 115512K buff, 1866400K cached
CPU: 1% usr 0% sys 0% nic 97% idle 0% io 0% irq 0% sirq
Load average: 0.42 0.24 0.14 1/320 29
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
8 1 root S 2518m 63% 1 0% java -jar demo.jar
1 0 root S 1620 0% 1 0% sh abc.sh
7 1 root R 1564 0% 0 0% top -b
Mem: 2565184K used, 1473920K free, 1400K shrd, 115520K buff, 1866400K cached
CPU: 1% usr 0% sys 0% nic 97% idle 0% io 0% irq 0% sirq
Load average: 0.38 0.24 0.13 1/320 29
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
8 1 root S 2518m 63% 1 0% java -jar demo.jar
1 0 root S 1620 0% 1 0% sh abc.sh
7 1 root R 1564 0% 0 0% top -b
Mem: 2568148K used, 1470956K free, 1404K shrd, 115524K buff, 1866548K cached
CPU: 2% usr 0% sys 0% nic 97% idle 0% io 0% irq 0% sirq
Load average: 0.35 0.23 0.13 2/323 36
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
8 1 root S 2518m 63% 1 0% java -jar demo.jar
30 0 root S 1628 0% 0 0% /bin/sh
1 0 root S 1620 0% 1 0% sh abc.sh
7 1 root R 1564 0% 0 0% top -b
shell
상기와 같이 alpine os가 실행된 시점이후로 cpu의 사용량을 확인 가능해 졌다.
일반적인 metrics로는 인스턴스내의 프로세스별 모니터링이 안되다 보니까 이상한 행위를 하긴 했는데
누군가에는 도움이 되길 바란다~
'AWS' 카테고리의 다른 글
AWS CLI 명령어 모음 (계속) (0) | 2022.02.06 |
---|---|
windows aws cli update (0) | 2022.01.14 |
EKS cluster Management (0) | 2021.03.13 |
EKS setup and make clustering (0) | 2021.03.13 |
Cloud9 Ports 오픈 하기 (0) | 2021.03.01 |