라즈베리파이4에 쿨링팬 제어 모듈을 nodejs로 만들고, 이걸 쿠버네티스 데몬셋으로 상시 동작하도록 꾸미고 있습니다.
이전 글 참조.
2022.07.29 - [Raspberry pi] - 라즈베리파이 온도에 따라 냉각팬 조절하기 : nodejs
2022.08.04 - [Raspberry pi] - 라즈베리파이 쿨링팬 제어 쿠버네티스 데몬셋으로 실행하기 : nodejs, GPIO 접근권한
이어서, 데몬셋으로 동작중인 쿨링팬 제어모듈의 쿨링팬 동작 조건을 변수로 분리하여 환경변수에서 처리하도록 개선했습니다.
10초 간격으로 체크하게 했더니, 임계온도인 55도에서 10초 간격으로 쿨링팬이 돌다 말다를 반복하여 별로 효율적으로 보이지 않았기 때문인데요.
어떤게 적정값인지 찾기는 어려우니 일단 변수로 빼서 설정이 가능하게 하는게 1차 목표였고,
그렇게 분리된 설정파일을 쿠버네티스에서 환경변수로 전달하는게 그다음 목표입니다.
일단 설정해야할 변수값은 3개입니다.
1. 임계 온도 (cri_temp_cels)
2. 온도 체크 시간간격 (interval_sec)
3. 임계 온도를 넘었을 때에 쿨링팬이 돌아가는 동작시간 (running_sec)
그리고 2가지 조건이 있습니다.
1. ConfigMap이 존재하지 않아도 기본 값으로 동작 할 것
2. 데몬이 동작 중에도 변수를 바꾸면 재기동 없이 바로 반영될 것
1번 조건을 위해서는 config 파일을 기본으로 넣어놓으면 될 것 같습니다.
2번 조건을 위해서는 ConfigMap을 바꾸면 위 config 파일을 바꿔주도록 하면 될 것 같네요.
그리고 바뀐 config 파일을 nodejs에서 감지해서 설정값들을 reload 하면 될 것 같습니다.
먼저 nodejs 소스를 수정합니다.
config파일 경로는 현재 동작중인 경로 기준 conf/fan-config 로 정했습니다.
const config_file = __dirname + '/conf/fan-config'
별도 폴더로 분리한 이유는,
아래 나오겠지만 ConfigMap을 볼륨마운트하여 파일로 떨굴 계획인데, 볼륨 마운트 시 별도 폴더를 지정해야 하기 때문입니다.
그다음으로 config 파일을 읽어오는 function을 작성합니다.
var cri_temp_cels = 0;
var running_sec = 0;
var interval_sec = 0;
function read_config(event) {
i('read config file!!');
var JSON_config = fs.readFileSync(config_file, 'utf8');
var config = JSON.parse(JSON_config);
cri_temp_cels = parseInt(config.cri_temp_cels);
running_sec = parseInt(config.running_sec);
interval_sec = parseInt(config.interval_sec);
i('cri_temp_cels', cri_temp_cels);
i('running_sec', running_sec);
i('interval_sec', interval_sec);
}
임계온도, 동작시간, 체크주기 변수값들을 반영해야 하므로 메인 소스 수정도 필요합니다.
async function get_temp() {
try {
const temp = await exe_shell("cat /sys/class/thermal/thermal_zone0/temp");
if(temp/1000 > cri_temp_cels){
fan.writeSync(1);
setTimeout(get_temp, 1000*running_sec);
}
else{
fan.writeSync(0);
setTimeout(get_temp, 1000*interval_sec);
}
i("cpu temperture", temp/1000, fan.readSync());
}catch(error) {
e(error.toString());
}
}
마지막으로,
config 파일에 변경이 발생하면 파일을 다시 읽어오도록 read_config function을 걸어놓습니다.
fs.watchFile(config_file, read_config);
이제 소스는 완성했고,
config 파일을 생성합니다.
$ mkdir conf
$vi conf/fan-config
{
"cri_temp_cels":"55",
"running_sec":"300",
"interval_sec":"40"
}
JSON 포멧으로 작성했습니다.
그다음은 ConfigMap을 생성해줍니다.
편의상 fan-config 파일을 읽어서 만들어줍니다.
$ k create configmap fan-config --from-file conf/fan-config --dry-run=client -o yaml > fan-config.yaml
생성된 yaml 파일을 열어봅니다.
$ cat fan-config.yaml
apiVersion: v1
data:
fan-config: |
{
"cri_temp_cels":"55",
"running_sec":"300",
"interval_sec":"40"
}
kind: ConfigMap
metadata:
creationTimestamp: null
name: fan-config
구동했을 때에 ConfigMap값을 conf 경로에 파일로 썼는지 구분을 위해 interval_sec 값을 30으로 바꿔줍니다.
$ cat fan-config.yaml
apiVersion: v1
data:
fan-config: |
{
"cri_temp_cels":"55",
"running_sec":"300",
"interval_sec":"30"
}
kind: ConfigMap
metadata:
creationTimestamp: null
name: fan-config
그리고 일단 ConfigMap을 생성합니다.
$ k apply -f fan-config.yaml
$ k get cm
NAME DATA AGE
fan-config 1 21m
$ k describe cm fan-config
Name: fan-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
fan-config:
----
{
"cri_temp_cels":"55",
"running_sec":"300",
"interval_sec":"30"
}
BinaryData
====
Events: <none>
잘 생성되었네요.
마지막입니다.
DaemonSet yaml 파일을 수정합니다.
ConfigMap을 conf 경로에 볼륨마운트해서 fan-config 파일로 쓰도록 설정합니다.
$ vi fan_controller_daemon.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
creationTimestamp: null
labels:
app: fan-controller
name: fan-controller
spec:
selector:
matchLabels:
app: fan-controller
template:
metadata:
creationTimestamp: null
labels:
app: fan-controller
spec:
containers:
- name: fan-controller
image: becans/fan-controller:arm7.0.6
securityContext:
privileged: true
volumeMounts:
- name: gpiopath
mountPath: /sys
- name: fanconfig
mountPath: /usr/src/app/conf
volumes:
- name: gpiopath
hostPath:
path: /sys
type: Directory
- name: fanconfig
configMap:
name: fan-config
mountPath가 /usr/src/app/conf 인 이유는,
Dockerfile의 WORKDIR이 /usr/src/app 이기 때문입니다.
이제 수정한 모듈을 도커로 빌드해서 올리고, 쿠버네티스에서 내려받아 구동하겠습니다.
$ sudo docker build -t becans/fan-controller:arm7.0.6 .
Sending build context to Docker daemon 47.62kB
Step 1/6 : FROM node:12
---> 89df41ef0cd7
Step 2/6 : WORKDIR /usr/src/app
---> Using cache
---> 9352facdeab0
Step 3/6 : COPY package*.json ./
---> Using cache
---> 37b4bb72ae02
Step 4/6 : RUN npm install
---> Using cache
---> fdb3f3a065dd
Step 5/6 : COPY . .
---> 671c45afc7f3
Step 6/6 : CMD [ "node", "fan_controller.js" ]
---> Running in 07fa9d887383
Removing intermediate container 07fa9d887383
---> 8caee1f06a38
Successfully built 8caee1f06a38
Successfully tagged becans/fan-controller:arm7.0.6
$ sudo docker push becans/fan-controller:arm7.0.6
The push refers to repository [docker.io/becans/fan-controller]
e9c2c3221e58: Pushed
2cb8d67e3877: Layer already exists
f1298c154221: Layer already exists
13ae017bd412: Layer already exists
793fbcea9e2a: Layer already exists
4945a11d336c: Layer already exists
ac0e08eec46a: Layer already exists
b711f0c07b7c: Layer already exists
3c3c4870574d: Layer already exists
bcf9ec9b83fa: Layer already exists
952036bb3ee8: Layer already exists
e52411dadecd: Layer already exists
37b5ba013286: Layer already exists
$ k apply -f fan_controller_daemon.yaml
daemonset.apps/fan-controller configured
$ k get pod -w
NAME READY STATUS RESTARTS AGE
fan-controller-47zp5 1/1 Terminating 0 15m
fan-controller-47zp5 0/1 Terminating 0 15m
fan-controller-47zp5 0/1 Terminating 0 15m
fan-controller-47zp5 0/1 Terminating 0 15m
fan-controller-gbmkx 0/1 Pending 0 0s
fan-controller-gbmkx 0/1 Pending 0 0s
fan-controller-gbmkx 0/1 ContainerCreating 0 0s
fan-controller-gbmkx 1/1 Running 0 11s
잘 올라갔습니다.
(사실 여기까지 한방에 됐을 리 없고 수많은 시행착오 끝에 성공한 것만 나열하고 있습니다. ㅜㅜ)
이제 pod 안으로 들어가서 ConfigMap 값으로 설정이 먹었는지 확인해보겠습니다.
$ k exec -it fan-controller-gbmkx -- bash
root@fan-controller-gbmkx:/usr/src/app# cat conf/fan-config
{
"cri_temp_cels","55",
"running_sec":"300",
"interval_sec":"30"
}
잘 바뀌어 있네요.
사실 ConfigMap으로 볼륨마운트를 하면 숨어있는 파일이 더 있습니다.
root@fan-controller-gbmkx:/usr/src/app# ls -al conf/
total 12
drwxrwxrwx 3 root root 4096 Aug 4 14:52 .
drwxr-xr-x 1 root root 4096 Aug 4 14:49 ..
drwxr-xr-x 2 root root 4096 Aug 4 14:52 ..2022_08_04_14_52_59.3663318380
lrwxrwxrwx 1 root root 32 Aug 4 14:52 ..data -> ..2022_08_04_14_52_59.3663318380
lrwxrwxrwx 1 root root 17 Aug 4 14:49 fan-config -> ..data/fan-config
이런 모양으로요..
이제 pod가 러닝 중에 변수값이 실시간 변경되는지 확인이 필요합니다.
임계온도를 50도로 바꾸고 반영되는지 보겠습니다.
$ vi fan-config.yaml
apiVersion: v1
data:
fan-config: |
{
"cri_temp_cels":"50",
"running_sec":"300",
"interval_sec":"30"
}
kind: ConfigMap
metadata:
name: fan-config
namespace: default
$ k apply -f fan-config.yaml
configmap/fan-config configured
ConfigMap을 변경했습니다.
root@fan-controller-gbmkx:/usr/src/app# cat conf/fan-config
{
"cri_temp_cels":"55",
"running_sec":"300",
"interval_sec":"30"
}
바로 pod 안으로 들어가보면 값이 안 변해 있습니다.
root@fan-controller-gbmkx:/usr/src/app# cat conf/fan-config
{
"cri_temp_cels":"50",
"running_sec":"300",
"interval_sec":"30"
}
약 2분정도 경과되니 변경되어 있네요.
모듈에도 반영되었는지 로그를 확인해보겠습니다.
root@fan-controller-gbmkx:/usr/src/app# cat logs/fan_controller.2022-08-04.log
{"level":"info","message":{"contents":[["cpu temperture",54.043,0]],"timestamp":"2022-08-04 15:30:14"}}
{"level":"info","message":{"contents":[["cpu temperture",55.504,1]],"timestamp":"2022-08-04 15:30:44"}}
{"level":"info","message":{"contents":[["read config file!!"]],"timestamp":"2022-08-04 15:32:39"}}
{"level":"info","message":{"contents":[["cri_temp_cels",50]],"timestamp":"2022-08-04 15:32:39"}}
{"level":"info","message":{"contents":[["running_sec",300]],"timestamp":"2022-08-04 15:32:39"}}
{"level":"info","message":{"contents":[["interval_sec",30]],"timestamp":"2022-08-04 15:32:39"}}
{"level":"info","message":{"contents":[["cpu temperture",52.095,1]],"timestamp":"2022-08-04 15:35:44"}}
config파일 변경을 감지하고 변수값을 다시 읽었습니다.
그리고 쿨링팬 동작기준이 50도로 바뀌어서 52도인데도 팬을 돌리고 있네요.
끝입니다.
작업했던 소스입니다.
https://github.com/becans/raspberry_fan_controller.git
도커 이미지입니다.
becans/fan-controller Tags | Docker Hub
'Raspberry pi' 카테고리의 다른 글
도커 레지스트리 (nexus3 oss) 만들기 : 커스텀빌드 이미지 올리기 (0) | 2022.08.10 |
---|---|
라즈베리파이4 도커허브에 없는 오픈소스 직접 빌드하기 : mariadb (0) | 2022.08.08 |
라즈베리파이 쿨링팬 제어 쿠버네티스 데몬셋으로 실행하기 : nodejs, GPIO 접근권한 (0) | 2022.08.04 |
라즈베리파이4 라즈비안 쿠버네티스 cni 에러 : failed to find plugin "loopback" in path [/usr/lib/cni] (0) | 2022.08.03 |
라즈베리파이4 쿠버네티스 설치 (0) | 2022.08.03 |