Raspberry pi

라즈베리파이 쿨링팬 제어 nodejs 도커로 실행하기 :GPIO 접근권한

[혜안] 2022. 7. 31. 23:48
728x90

쿨링팬 제어하는 nodejs 모듈을 열심히 만들었고,

이제 상시 돌아가도록 쿠버네티스 daemon으로 등록해야 합니다.

그 전에 일단 도커 이미지화를 해야 쿠버네티스에 올릴 수 있으니

도커 이미지부터 만드는게 순서입니다.

 

우선 도커파일을 만들어줍니다.

Dockerfile

FROM node:12
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
CMD [ "node", "fan_controller.js" ]

전형적인 nodejs용 도커파일입니다.

 

도커이미지를 빌드합니다.

$ sudo docker build -t becans/fan_controller ./
Sending build context to Docker daemon  6.373MB
Step 1/6 : FROM node:12
12: Pulling from library/node
a41fbedfa4b1: Pull complete
6a94d3b1a91a: Pull complete
dad88c3c2eed: Pull complete
67f90700f585: Pull complete
48979b276d7f: Pull complete
9520e1bb28ad: Pull complete
b2423df69002: Pull complete
8a1e736bfbf6: Pull complete
5e56b5666dd9: Pull complete
Digest: sha256:01627afeb110b3054ba4a1405541ca095c8bfca1cb6f2be9479c767a2711879e
Status: Downloaded newer image for node:12
 ---> 212cfb481ff8
Step 2/6 : WORKDIR /usr/src/app
 ---> Running in 03ca3938a9e0
Removing intermediate container 03ca3938a9e0
 ---> 9a340dc5f17a
Step 3/6 : COPY package*.json ./
 ---> 7aaa5dfa9def
Step 4/6 : RUN npm install
 ---> Running in 1f5f46116fde
npm WARN read-shrinkwrap This version of npm is compatible with lockfileVersion@1, but package-lock.json was generated for lockfileVersion@2. I'll try to do my best with it!

> epoll@4.0.1 install /usr/src/app/node_modules/epoll
> node-gyp rebuild

make: Entering directory '/usr/src/app/node_modules/epoll/build'
  CXX(target) Release/obj.target/epoll/src/epoll.o
  SOLINK_MODULE(target) Release/obj.target/epoll.node
  COPY Release/epoll.node
make: Leaving directory '/usr/src/app/node_modules/epoll/build'
npm WARN app No description
npm WARN app No repository field.
npm WARN app No license field.

added 37 packages from 33 contributors and audited 37 packages in 11.444s

2 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Removing intermediate container 1f5f46116fde
 ---> 8122511ec4d1
Step 5/6 : COPY . .
 ---> 9807b5206531
Step 6/6 : CMD [ "node", "fan_controller.js" ]
 ---> Running in 231941c18886
Removing intermediate container 231941c18886
 ---> ddea6c660670
Successfully built ddea6c660670
Successfully tagged becans/fan_controller:latest

 

알아서 잘 만드네요.

 

한가지 주지할 점은,

도커 이미지로 돌지만, 호스트인 라즈베리파이의 CPU 온도를 알아야 하고,

GPIO를 제어해야 합니다.

 

때문에 도커를 실행할 때에 아래와 같이 볼륨공유 설정을 해주어야 합니다.

sudo docker run -v /sys:/sys -d becans/fan_controller

 

CPU온도를 알아내는 명령어는

cat /sys/class/thermal/thermal_zone0/temp

이고,

GPIO를 제어는

/sys/class/gpio

이 경로의 엑세스 권한이 있어야 하기 때문입니다.

 

이제 도커 이미지를 만들었으니, 위 명령으로 돌려봅니다. 

그런데,

뭔 일인지 바로 죽어버립니다.

 

디버깅을 해보니,

Error: EROFS: read-only file system, open '/sys/class/gpio/gpio26/value'
    at Object.openSync (fs.js:462:3)
    at /usr/src/app/node_modules/onoff/onoff.js:68:23
    at Array.forEach (<anonymous>)
    at waitForGpioAccessPermission (/usr/src/app/node_modules/onoff/onoff.js:62:27)
    at new Gpio (/usr/src/app/node_modules/onoff/onoff.js:174:5)
    at Object.<anonymous> (/usr/src/app/fan_controller.js:2:8)
    at Module._compile (internal/modules/cjs/loader.js:999:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14) {
  errno: -30,
  syscall: 'open',
  code: 'EROFS',
  path: '/sys/class/gpio/gpio26/value'

docker 안에서는 호스트의 gpio 쓰기 권한이 없답니다.

 

다시 구글링해보니 권한을 더 주어야 하네요.

sudo docker run --privileged -v /sys:/sys -d becans/fan_controller

privileged 옵션을 추가했습니다.

$ sudo docker ps
CONTAINER ID   IMAGE                   COMMAND                  CREATED        STATUS        PORTS     NAMES
0ffe0b9fa8b4   becans/fan_controller   "docker-entrypoint.s…"   22 minutes ago   Up 22 minutes             hardcore_solomon

잘 동작하네요.

 

도커안에서 로그를 확인해봅니다.

$ sudo docker exec -it 0ffe0b9fa8b4 bash
root@0ffe0b9fa8b4:/usr/src/app# tail -f logs/fan_controller.2022-07-31.log
{"level":"info","message":{"contents":[["cpu temperture",55.017,1]],"timestamp":"2022-07-31 14:34:22"}}
{"level":"info","message":{"contents":[["cpu temperture",51.608,0]],"timestamp":"2022-07-31 14:39:22"}}
{"level":"info","message":{"contents":[["cpu temperture",52.095,0]],"timestamp":"2022-07-31 14:39:52"}}
{"level":"info","message":{"contents":[["cpu temperture",52.095,0]],"timestamp":"2022-07-31 14:40:22"}}
{"level":"info","message":{"contents":[["cpu temperture",52.582,0]],"timestamp":"2022-07-31 14:40:52"}}
{"level":"info","message":{"contents":[["cpu temperture",52.582,0]],"timestamp":"2022-07-31 14:41:22"}}
{"level":"info","message":{"contents":[["cpu temperture",54.043,0]],"timestamp":"2022-07-31 14:41:52"}}
{"level":"info","message":{"contents":[["cpu temperture",54.043,0]],"timestamp":"2022-07-31 14:42:22"}}
{"level":"info","message":{"contents":[["cpu temperture",54.043,0]],"timestamp":"2022-07-31 14:42:52"}}
{"level":"info","message":{"contents":[["cpu temperture",55.017,1]],"timestamp":"2022-07-31 14:43:22"}}

 

잘 동작합니다.

 

호스트의 하드웨어를 접근하기 때문에, 이런 컨테이너는 데몬으로 한 개씩만 돌려야 하겠습니다.

 

이제 쿠버네티스 환경에서 도커를 데몬셋으로 만들어야 합니다.

일단 도커허브에 올려놓았습니다.

https://hub.docker.com/repository/docker/becans/fan_controller

 

Docker Hub

 

hub.docker.com

 

 

728x90