라즈베리파에4에 쿠버네티스를 설치하고 mysql 커스텀 이미지 올리는 작업을 했습니다.
2022.08.08 - [Raspberry pi] - 라즈베리파이4 도커허브에 없는 오픈소스 직접 빌드하기 : mariadb
2022.08.10 - [Raspberry pi] - 도커 레지스트리 (nexus3 oss) 만들기 : 커스텀빌드 이미지 올리기
사설 레포지토리를 설치해서, 빌드한 도커 이미지를 올렸고,
쿠버네티스에서 다운로드받아 동작시키는데까지 성공은 했는데,
퍼시스턴스 볼륨 설정을 하면 mysql이 정상적으로 올라오지 않아 Pod가 반복 재기동하는 문제가 발생했습니다.
마지막 포스팅에서 "잘 동작하네요" 라는 멘트를 작성하고 포스팅을 올리고 나니 바로 아래와 같은 문제가 보였습니다.
$ k get pod -w
NAME READY STATUS RESTARTS AGE
fan-controller-spgm8 1/1 Running 0 7h32m
mariadb-custom-794865cbbd-w4ngl 1/1 Running 0 4s
mariadb-custom-794865cbbd-w4ngl 0/1 Error 0 37s
mariadb-custom-794865cbbd-w4ngl 1/1 Running 1 (4s ago) 40s
mariadb-custom-794865cbbd-w4ngl 0/1 Error 1 (36s ago) 72s
mariadb-custom-794865cbbd-w4ngl 0/1 CrashLoopBackOff 1 (16s ago) 87s
mariadb-custom-794865cbbd-w4ngl 1/1 Running 2 (18s ago) 89s
디스크립션에서는 이렇다 할 단서가 보이지 않았구요.
$ k get desdescribe pod mariadb-custom-794865cbbd-w4ngl
Name: mariadb-custom-794865cbbd-w4ngl
Namespace: default
Priority: 0
Node: raspberrypi4/192.168.0.49
Start Time: Wed, 10 Aug 2022 14:20:47 +0100
Labels: app=mariadb-custom
pod-template-hash=794865cbbd
Annotations: <none>
Status: Running
IP: 10.244.0.68
IPs:
IP: 10.244.0.68
Controlled By: ReplicaSet/mariadb-custom-794865cbbd
Containers:
mariadb-arm7:
Container ID: containerd://d7c28e6e1573ac3b3e4215fe8964d558d27476e2b26c376146d18700e21ea8bd
Image: private.repo:8099/mariadb-arm7:0.3
Image ID: private.repo:8099/mariadb-arm7@sha256:845eb2faf3a1e3d076827a0c4bb131ba7ed688e685999a919281cb77848dd95e
Port: 3306/TCP
Host Port: 0/TCP
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Error
Exit Code: 1
Started: Wed, 10 Aug 2022 14:26:32 +0100
Finished: Wed, 10 Aug 2022 14:27:04 +0100
Ready: False
Restart Count: 5
Environment: <none>
Mounts:
/var/lib/mysql from sqldb (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-9x459 (ro)
Conditions:
Type Status
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
sqldb:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: pvc-sqldb
ReadOnly: false
kube-api-access-9x459:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 6m53s default-scheduler Successfully assigned default/mariadb-custom-794865cbbd-w4ngl to raspberrypi4
Normal Pulled 3m14s (x5 over 6m52s) kubelet Container image "private.repo:8099/mariadb-arm7:0.3" already present on machine
Normal Created 3m13s (x5 over 6m50s) kubelet Created container mariadb-arm7
Normal Started 3m13s (x5 over 6m49s) kubelet Started container mariadb-arm7
Warning BackOff 108s (x11 over 5m41s) kubelet Back-off restarting failed container
마지막 로그는 그냥 fail 입니다.
$ k logs --previous mariadb-custom-794865cbbd-w4ngl
[2022-08-10 22:32:34.149] Starting MariaDB database server: mariadbd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . failed!
그런데 희한한건, 디버그를 위해 이미지를 떠서 들어가면 mysql을 이상없이 동작시킬 수 있었습니다.
$ k debug mariadb-custom-794865cbbd-n6lj6 -it --copy-to=maria-debug --container=mariadb-custom-794865cbbd-n6lj6 --image=private.repo:8099/mariadb-arm7 -- bash
root@maria-debug:/var/lib# cd /etc/init.d/
root@maria-debug:/etc/init.d# ./mariadb start
Starting MariaDB database server: mariadbd . . . . . . . . . ..
root@maria-debug:/etc/init.d# ps -ef|grep mysql
root 39 1 0 14:30 pts/0 00:00:00 /bin/sh /usr/bin/mysqld_safe
mysql 154 39 5 14:30 pts/0 00:00:01 /usr/sbin/mariadbd --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/mysql/plugin --user=mysql --skip-log-error --pid-file=/run/mysqld/mysqld.pid --socket=/run/mysqld/mysqld.sock
root 155 39 0 14:30 pts/0 00:00:00 logger -t mysqld -p daemon error
단서를 찾은 건, 퍼시스턴스 볼륨을 마운트한 경로에 아무런 파일이 생기지 않는다는 점이었습니다.
cmlee@raspberrypi4:/dataspace/pv-sqldb $ cd ll
total 8
drwxr-xr-x 2 cmlee cmlee 4096 Aug 10 09:05 .
drwxr-xr-x 3 root root 4096 Aug 5 06:10 ..
처음엔 mysql이 올라오지 못했으니 아무런 파일이 생기지 않는거라 생각을 했지만,
혹시 권한이 없어 파일 생성을 못하는 것인가 싶어 유심히 보니, 쓰기 권한이 cmlee 유저 외에는 없었습니다.
일단 권한을 모두 주고 기다려봤습니다. Pod가 계속 반복재기동을 하니까요.
cmlee@raspberrypi4:/dataspace/pv-sqldb $ ll
total 110628
drwxrwxrwx 2 root root 4096 Aug 10 15:45 .
drwxr-xr-x 3 root root 4096 Aug 5 06:10 ..
-rw-rw---- 1 systemd-resolve systemd-journal 16384 Aug 10 15:45 aria_log.00000001
-rw-rw---- 1 systemd-resolve systemd-journal 52 Aug 10 15:45 aria_log_control
-rw-rw---- 1 systemd-resolve systemd-journal 864 Aug 10 15:45 ib_buffer_pool
-rw-rw---- 1 systemd-resolve systemd-journal 12582912 Aug 10 15:45 ibdata1
-rw-rw---- 1 systemd-resolve systemd-journal 100663296 Aug 10 15:45 ib_logfile0
오오~ 그랬더니 파일이 뭔가 생깁니다.
역시 권한 문제였나 싶었죠.
소유자 이름이 systemd-resolve 인 이유는, 우연히 겹치는 userid 라 그렇습니다.
컨테이너 내부에서 보면 이렇게 보입니다.
cmlee@raspberrypi4:/dataspace/pv-sqldb $ k exec -it mariadb-custom-794865cbbd-w4ngl -- ls -al /var/lib/mysql
total 110628
drwxrwxrwx 2 root root 4096 Aug 10 14:48 .
drwxr-xr-x 1 root root 4096 Aug 6 15:28 ..
-rw-rw---- 1 mysql mysql 16384 Aug 10 14:48 aria_log.00000001
-rw-rw---- 1 mysql mysql 52 Aug 10 14:48 aria_log_control
-rw-rw---- 1 mysql mysql 864 Aug 10 14:48 ib_buffer_pool
-rw-rw---- 1 mysql mysql 100663296 Aug 10 14:48 ib_logfile0
-rw-rw---- 1 mysql mysql 12582912 Aug 10 14:48 ibdata1
하지만 그래도 문제는 해결되지 않았습니다.
그래서 퍼시스턴스 볼륨을 주지 않았을 때에 저 경로에 어떤 파일들이 생기는지 확인해 보았습니다.
root@maria-debug:/var/lib/mysql# ls -al
total 122944
drwxr-xr-x 1 mysql mysql 4096 Aug 10 14:30 .
drwxr-xr-x 1 root root 4096 Aug 6 15:28 ..
-rw-rw---- 1 mysql mysql 24576 Aug 10 14:30 aria_log.00000001
-rw-rw---- 1 mysql mysql 52 Aug 10 14:30 aria_log_control
-rw-r--r-- 1 root root 0 Aug 6 15:28 debian-10.5.flag
-rw-rw---- 1 mysql mysql 972 Aug 6 15:28 ib_buffer_pool
-rw-rw---- 1 mysql mysql 100663296 Aug 10 14:30 ib_logfile0
-rw-rw---- 1 mysql mysql 12582912 Aug 6 15:28 ibdata1
-rw-rw---- 1 mysql mysql 12582912 Aug 10 14:30 ibtmp1
-rw-rw---- 1 mysql mysql 0 Aug 6 15:32 multi-master.info
drwx------ 1 mysql mysql 4096 Aug 6 15:28 mysql
-rw-r--r-- 1 root root 15 Aug 6 15:28 mysql_upgrade_info
drwx------ 2 mysql mysql 4096 Aug 6 15:28 performance_schema
훨씬 더 많은 파일들이 보이네요.
그리하여 곰곰히 생각해본 결과,
/var/lib/mysql 이라는 경로에는 mysql의 db data들이 저장되는데,
통상 db data는 mysql이 설치되는 때에 상당량의 db data 관련 파일들이 이미 생성됩니다.
Docker파일을 다시 봅니다.
$ cat Dockerfile
FROM debian
RUN apt update -y && apt install mariadb-server -y
RUN sed -i 's/bind-address/bind-address = 0.0.0.0 #/i' /etc/mysql/mariadb.conf.d/50-server.cnf
RUN mkdir /mysql_scripts
COPY mySqlScript.sql /mysql_scripts/
RUN /etc/init.d/mariadb start && mysql -uroot --password="" -e "source /mysql_scripts/mySqlScript.sql"
CMD /etc/init.d/mariadb start && tail -f /dev/null
RUN은 도커이미지를 빌드할 때에 실행됩니다.
CMD는 이미지가 올라올때에 실행되구요.
즉,
mariadb-server를 설치한 도커이미지라면, 위에 마운트한 /var/lib/mysql 경로에는 상당량의 db data 파일들이 이미 생성된 상태입니다.
그 상태에서, 쿠버네티스 퍼시스턴스 볼륨을 동일한 경로에 마운트하면, 기존에 설치한 db data들은 가려지고, 비어있는 폴더가 되는 겁니다.
이게 Pod가 정상적으로 올라오지 않는 원인이었습니다.
그래서 해결 방법은?
Dockerfile을 아래와 같이 수정했습니다.
$ cat Dockerfile
FROM debian
RUN apt update -y && apt install mariadb-server -y
RUN sed -i 's/bind-address/bind-address = 0.0.0.0 #/i' /etc/mysql/mariadb.conf.d/50-server.cnf
RUN mkdir /mysql_scripts
COPY mySqlScript.sql /mysql_scripts/
RUN /etc/init.d/mariadb start && mysql -uroot --password="" -e "source /mysql_scripts/mySqlScript.sql"
RUN /etc/init.d/mariadb stop
RUN mv /var/lib/mysql /var/lib/mysql_temp && mkdir /var/lib/mysql
CMD mv /var/lib/mysql_temp/* /var/lib/mysql/ && /etc/init.d/mariadb start && tail -f /dev/null
mariadb-server를 설치하는 과정은 매우 오래 걸립니다.
따라서 Pod 실행 시점에 새로 설치는 올바른 방법은 아닌 것 같고,
/var/lib/mysql에 설치된 파일들을 그대로 보존하다가, 퍼시스턴스 볼륨이 마운트된 후에 다시 넣어주면 될 것으로 판단하여,
mariadb-server를 다 설치하고 초기화 스크립트를 실행한 후에,
mariadb를 멈추고,
RUN /etc/init.d/mariadb stop
/var/lib/mysql 경로를 /var/lib/mysql_temp로 바꿔줍니다. 그리고 /var/lib/mysql 빈폴더를 만들어 줍니다.
RUN mv /var/lib/mysql /var/lib/mysql_temp && mkdir /var/lib/mysql
/var/lib/mysql 빈폴더를 만들어주는 이유는, 퍼시스턴스 볼륨이 마운트되지 않더라도 동작하게 하기 위함입니다.
마지막으로 Pod가 올라와서 mariadb를 기동하기 전에, /var/lib/mysql_temp/ 밑에 있는 모든 파일을 /var/lib/mysql 밑으로 이동시킵니다.
CMD mv /var/lib/mysql_temp/* /var/lib/mysql/ && /etc/init.d/mariadb start && tail -f /dev/null
CMD는 Pod가 올라올때마다 실행할 내용이지만, /var/lib/mysql_temp/ 밑에 모든 파일을 move 시키는 최초 시점에만 시간이 걸릴 뿐, 그 다음부터는 빈 폴더이므로 반복실행되어도 부담은 없습니다.
이렇게 하고, 다시 이미지를 빌드하여, 쿠버네티스에서 퍼스스턴스 볼륨을 할당하고 기동해보았습니다.
cmlee@raspberrypi4:/dataspace/pv-sqldb $ ll
total 122932
drwxrwxrwx 4 root root 4096 Aug 10 16:44 .
drwxr-xr-x 3 root root 4096 Aug 5 06:10 ..
-rw-rw---- 1 systemd-resolve systemd-journal 24576 Aug 10 16:44 aria_log.00000001
-rw-rw---- 1 systemd-resolve systemd-journal 52 Aug 10 16:44 aria_log_control
-rw-r--r-- 1 root root 0 Aug 10 16:26 debian-10.5.flag
-rw-rw---- 1 systemd-resolve systemd-journal 972 Aug 10 16:26 ib_buffer_pool
-rw-rw---- 1 systemd-resolve systemd-journal 12582912 Aug 10 16:26 ibdata1
-rw-rw---- 1 systemd-resolve systemd-journal 100663296 Aug 10 16:44 ib_logfile0
-rw-rw---- 1 systemd-resolve systemd-journal 12582912 Aug 10 16:44 ibtmp1
-rw-rw---- 1 systemd-resolve systemd-journal 0 Aug 10 16:27 multi-master.info
drwx------ 2 systemd-resolve systemd-journal 4096 Aug 10 16:26 mysql
-rw-r--r-- 1 root root 15 Aug 10 16:26 mysql_upgrade_info
drwx------ 2 systemd-resolve systemd-journal 4096 Aug 10 16:26 performance_schema
퍼시스턴스 볼륨이 할당된 경로에 파일들이 제대로 생성되어 있네요.
$ k get pod
NAME READY STATUS RESTARTS AGE
fan-controller-spgm8 1/1 Running 0 19h
mariadb-custom-545bdbb445-9m4gk 1/1 Running 0 9h
9시간 째 중단없이 잘 동작하고 있습니다.
퍼시스턴스 볼륨이 이론적으로는 단순하지만, 실제 적용시켜보면 디테일이 다르네요.
고려할 사항:
퍼시스턴스 볼륨은 Pod와 라이프사이클이 다릅니다. 통상 데이터베이스 컨테이너에서 퍼시스턴스 볼륨을 사용하는 목적은, Pod의 불시 종료, 업그레이드, 교체 등의 상황이 발생하더라도, db data는 이와 상관없이 보존하기 위함인데요. 이럴 경우 위 Dockerfile에 작성된 바와 같이 Pod 기동 시 내부에 있던 초기화된 db data가 퍼시스턴스 볼륨 내의 데이터를 무조건 덮어쓰게 하는 동작은 상용 환경에서는 위험할 수 있습니다.
학습용, 개인용으로만 참고하시기 바랍니다.
'Raspberry pi' 카테고리의 다른 글
라즈베리파이 2대 쿠버네티스 클러스터링 구성 완료 (0) | 2022.08.17 |
---|---|
라즈베리파이2 쿠버네티스 워커노드 만들기 (0) | 2022.08.15 |
도커 레지스트리 (nexus3 oss) 만들기 : 커스텀빌드 이미지 올리기 (0) | 2022.08.10 |
라즈베리파이4 도커허브에 없는 오픈소스 직접 빌드하기 : mariadb (0) | 2022.08.08 |
라즈베리파이 쿠버네티스 ConfigMap으로 변수 전달하기 : 동적으로 적용하기 (0) | 2022.08.05 |