쿠버네티스나 도커와 같이 컨테이너 안으로 어플리케이션을 넣으면
WOL 처럼 내부 네트워크에서만 동작되는 기능은 동작하지 않습니다.
처음부터 알고 있었던건 아니구요.
잡다한 홈서버를 라즈베리파이에 Nodejs 로 운용하다가 쿠버네티스에 넣었더니
2가지 기능이 안되더라구요.
첫번째는 GPIO 컨트롤,
두번째는 WOL 이었습니다.
GPIO 컨트롤은 아래와 같이 해결하였구요.
2022.07.31 - [Raspberry pi] - 라즈베리파이 쿨링팬 제어 nodejs 도커로 실행하기 :GPIO 접근권한
이번에 할 이야기가 WOL 입니다.
아시겠지만 컨테이너환경에서 어플리케이션을 구동하게 되면,
이 어플리케이션은 비록 호스트의 자원을 빌려쓰는 신세지만 그럼에도 마치 별개의 또다른 호스트처럼 취급됩니다.
특히 네트워크의 경우 가상의 별도 네트워크를 생성하기 때문에,
원칙상 호스트의 네트워크와 통신이 되지 않습니다.
그러니까 내부 네트워크에서만 호출 할 수 있는 WOL 같은 기능은 동작하지 않았던 것입니다.
컨테이너를 외부 네트워크라고 인식하는 거죠.
저의 경우도 그러했습니다.
집에 내부적으로 꾸며놓은 네트워크 대역은 192.168.x.x 대역입니다.
그리고 쿠버네티스에 flannel을 통해 구성한 네트워크 대역은 10.244.x.x 이구요.
아마 쿠버네티스 컨테이너를 생성한 상태라면,
호스트에서 ifconfig를 쳤을 때에 아래와 같이 보일껍니다.
eht0는 호스트의 IP입니다.
그리고 맨 아래에 vethxxxxxxxx 가 있습니다.
아마도 virtual ethernet 의 약자일텐데요.
이렇게 호스트 입장에서 컨테이너는 본인의 네트워크대역이 아닌 별도의 네트워크 IP 대역으로 취급되니,
당연히 WOL의 매직패킷은 전달이 안됐던 겁니다.
그럼 방법은?
docker나 kubernetes나 호스트의 네트워크로 컨테이너를 생성할 수 있는 기능은 있습니다.
docker의경우 --net=host 옵션을 주고 run하면 됩니다.
kubernetes의 경우는 아래와 같이 yaml파일에 기술해주면 됩니다.
apiVersion: apps/v1 kind: Deployment metadata: labels: app: wol name: wol spec: selector: matchLabels: app: wol template: metadata: labels: app: wol spec: hostNetwork: true . . . |
hostNetwork: true는 생성할 Pod를 가상네트워크가 아닌 호스트의 네트워크를 이용하겠다는 설정입니다.
실행하면 아래와 같이 보입니다.
$ k get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coin-gather-675dfd9486-cj4q7 1/1 Running 0 18h 10.244.0.120 raspberrypi4 <none> <none>
coin-trader-7cbd7d447-6mfjt 1/1 Running 0 18h 10.244.0.121 raspberrypi4 <none> <none>
fan-controller-chftl 1/1 Running 0 7d12h 10.244.1.3 raspberrypi2 <none> <none>
fan-controller-spgm8 1/1 Running 0 12d 10.244.0.55 raspberrypi4 <none> <none>
home-server-54959467d4-zrtcf 1/1 Running 0 10h 10.244.0.122 raspberrypi4 <none> <none>
mariadb-custom-5dbf65bc5b-65bhz 1/1 Running 0 5d10h 10.244.0.117 raspberrypi4 <none> <none>
plug-controller-6764f8c8b4-db7wb 1/1 Running 0 5d10h 10.244.1.10 raspberrypi2 <none> <none>
testshell 1/1 Running 0 16h 10.244.1.18 raspberrypi2 <none> <none>
wol-597cd6f6b7-c94rk 1/1 Running 0 10h 192.168.0.20 raspberrypi2 <none> <none>
IP 열을 보시면 맨 밑에 wol Pod만 192.168.x.x 대역입니다. 호스트의 IP 대역을 할당 받았습니다.
당연히 WOL 기능은 정상적으로 동작하게 되었구요.
원래는 wol이 home-server 내에 있었지만, 호스트 네트워크 자원을 사용하는게 여러모로 부담이기 때문에 wol 기능만 잘라서 별도 Pod로 만들었습니다.
home-server가 wol을 호출하는 구조입니다.
wol 메인소스는 아래와 같습니다.
const WOL = 1;
const server = net.createServer(function(client){
logger.info('Client connected');
client.on('data', function(data){
var msg = JSON.parse(data);
if(msg.type = WOL){
logger.info('call wol:'+ msg.value);
wol.wake(msg.value,{}, function(err){
if(err) {
logger.error(err);
}
});
var res = {'type':WOL,'value':'WOL Sent'};
client.write(JSON.stringify(res));
}
});
client.on('end', function(){
logger.info('Client disconnected');
});
});
server.listen(8107, function(){
logger.info('Server listening for connections');
});
yaml 은 아래와 같이 기술되어 있습니다.
apiVersion: v1
kind: Service
metadata:
name: wol-svc
spec:
selector:
app: wol
ports:
- port: 8107
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: wol
name: wol
spec:
selector:
matchLabels:
app: wol
template:
metadata:
labels:
app: wol
spec:
hostNetwork: true
containers:
- name: wol
image: private.repo:8888/wol:0.1
env:
- name: TZ
value: Asia/Seoul
여기서 궁금한 점이 있을 수 있는데요.
home-server는 가상네트워크에 있습니다.
그리고 wol은 호스트 네트워크를 사용하죠.
서로 네트워크 망이 다른데 과연 호출이 될까? 싶습니다.
결론만 말씀드리면, home-server에서는 wol-svc:8107로 호출을 하면, 정상적으로 호출이 됩니다.
어찌되었든, 코딱지만한 어플리케이션들도 시간이 지나면서 자연스럽게 MSA로 가고있네요.
.
.
.
좀더 심오한 삽질을 해봅니다.
Kubernetes의 컨테이너 네트워크 구성이 궁금합니다.
우선 컨테이너 내부의 네트워크 인터페이스를 확인해봅니다.
$ k exec -it testshell -- ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
3: eth0@if23: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.244.1.18/24 brd 10.244.1.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::ac44:97ff:fe6d:810c/64 scope link
valid_lft forever preferred_lft forever
eth0@if23 이라는 인터페이스가 보입니다.
그냥 eth0가 아니라 뒤에 @가 붙는 것이 뭔가 링크를 뜻하는것 같네요.
다시 해당 컨테이너가 있는 호스트에서 네트워크 인터페이스를 확인해봅니다.
$ ip addr
.
.
.
23: vethd78c2f43@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP group default
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff link-netns cni-63fab09e-02e2-8dd9-7369-04562e9c3ab7
inet 169.254.189.81/16 brd 169.254.255.255 scope global noprefixroute vethd78c2f43
valid_lft forever preferred_lft forever
.
.
.
23번 index에 vethd78c2f43@if3 이라고 있네요.
아하~
컨테이너에서는 3번 인터페이스에 eth0@if23
호스트에서는 23번 인터페이스에 vethd78c2f43@if3
서로 링크되어 있네요.
즉, testshell 이라는 pod는 호스트에 vethd78c2f43 라는 가상 인터페이스를 생성해서, 컨테이너 안에서 그걸 eth0으로 사용하고 있습니다.
그냥 서로 한 쌍으로 링크되어 있다. 라고 얘기하더라구요.
그럼 또 의문점이 있습니다.
Pod 하나당 이렇게 가상 인터페이스 하나씩이 할당되어 있으면,
Pod 끼리의 통신은 어떻게 하는걸까?
분명 home-server 에서 wol-svc 라는 서비스이름으로 바로 호출이 됩니다.
이것 역시 cni 인터페이스가 bridge하여 서로를 연결시켜준다고 합니다.
bridge-utils를 설치하면, 쉽게 확인이 됩니다.
$ apt install bridge-utils
$ brctl show cni0
bridge name bridge id STP enabled interfaces
cni0 8000.325c2abceef8 no veth120d9d2c
veth19ef9a07
veth816e63b2
veth841caf25
vetha561f213
vethab01d4d5
vethb6cd6ed0
vethedbdc1e5
cni0 인터페이스가 가상 인터페이스 8개를 브릿지 시켜주고 있네요.
뭐 아주 깊이 파보지는 않았지만, 대략 어떤 느낌으로 네트워크를 구성하고 있는지는 감이 좀 옵니다.
컨테이너 안에서 wol 한번 해보겠다고 멀리도 왔네요.
'Miscellaneous' 카테고리의 다른 글
Grafana 멀티 데이터소스 하나의 차트에 같이 표시하기 (0) | 2022.09.07 |
---|---|
[삽질의 추억] Loki 32bit 환경 설치 안될 때 해결방법 : panic: unaligned 64-bit atomic operation (0) | 2022.09.06 |
[삽질의 추억] 쿠버네티스 추가 볼륨, 추가 콘피그맵이 안붙을 때 (0) | 2022.08.22 |
시놀로지 git 서버 최초 레포지토리 생성 (0) | 2022.08.11 |
Teraterm collector 나만 허접하게 느끼는건가? (0) | 2022.07.29 |