[일간에러] Different lower_case_table_names settings for server ('2') and data dictionary ('0').

Development/Daily Error

📝 최초작성 : 2023.01.07  ⏱ 수정 : 
반응형

문제

신년을 맞아 처음으로 올리는 일간 에러. 토요일 아침부터 참으로 통곡이 절로 나는 에러를 메시지를 맞이해 정말 기쁘다.

문제 상황은 간단한데, 기존에 토이프로젝트로 운영하던 서버의 데이터베이스를 복제하는 과정에서 위의 에러가 발생했다. 지금부터 에러가 발생하게 된 경위를 간단하게 브리핑 해 보겠다.

상황

기존에 토이프로젝트로 진행하던 프로젝트의 데이터베이스가, 운영서버의 DB를 개발환경에서도 바로 붙어서 테스트 및 반영까지 하던 상황. 지금까지는 개발서버나 운영서버나 어차피 개발환경이라는게 마찬가지였지만 모두 가족들이긴 해도 활발이 사용해주는 사용자들도 있고 거기에 사용자들이 사용하며 쌓은 데이터베이스를 나도 소중히 다루어야한다는 책임감이 생기며 개발환경과의 분리가 필요하다고 생각이 듬.

처음에 DB 서버를 실행 할 때 부터 볼륨을 걸었어야 되는데, 그 땐 이 데이터베이스 컨테이너가 테스트를 넘어 운영에서까지 쓰일꺼라고 생각을 못했었음.

docker inspect 컨테이너명

image-20230107112510740

docker inspect 명령으로 Docker가 알아서 생성한 볼륨을 확인하니, 위와 같이 "/var/lib/docker/volumes/47a16e90aaaddc239c082d3ecfa090801fc5c451dd88da1d61f51ddfbfc5bf5b/_data 경로에 생성이 되어 있음.

해당 경로로 찾아가서 파일들을 확인 해 보니, 이 폴더를 쓰면 되겠다고 생각이 든다.

cd /var/lib/docker/volumes/47a16e90aaaddc239c082d3ecfa090801fc5c451dd88da1d61f51ddfbfc5bf5b/_data

image-20230107112647714

해당 폴더 복사는 컨테이너를 멈추고 위의 경로를 통쨰로 카피 하거나, 아니면 아래의 명령어를 이용 하면 멈춰있는 컨테이너에서도 파일 복사가 가능 하다.

docker container cp dutypark-db:/var/lib/mysql ./data

우분투 서버에서 저렇게 챙겨온 폴더를, 내 로컬 환경(Mac) 에서 scp로 그대로 다시 떠갔다.

image-20230107112935734

이제 위에 보이는 것 처럼 /Users/shane/Documents/dev/_dutypark_dev_db 경로에 볼륨설정할 폴더가 존재하는 상태.

이제 컨테이너를 실행 한다.

docker run -d --name dutypark_dev_db \
  --restart unless-stopped \
  -v /Users/shane/Documents/dev/_dutypark_dev_db:/var/lib/mysql \
  -p 3306:3306 \
  mysql

그런데 예상과 달리 컨테이너가 바로 죽어버린다.

로그를 확인 해 보자

docker logs -f dutypark_dev_db

image-20230107113144745

바로 죽었는데 아래의 로그가 핵심으로 보인다

2023-01-07T02:31:25.105383Z 1 [ERROR] [MY-011087] [Server] Different lower_case_table_names settings for server ('2') and data dictionary ('0').

지금까지가 문제 상황이다.

원인

분명 볼륨을 통째로 가져오기 때문에 환경설정도 기존의 컨테이너와 다를게 없는데 설정에서 에러가 난다는게 참 이해가 되지 않는 상황이지만 어쨌든 우분투에서 Mac으로 환경이 변경된 건 사실이다.

그렇다면 제일 먼저 공식문서에서 lower_case_table_names 관한 내용을 체크 해 본다.

image-20230107113732415

https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_lower_case_table_names

가장 먼저, 문서에 따르면 lower_case_table_names 값은

  • 0으로 설정되어 있다면, 테이블 이름은 대/소문자를 구분(case-sensitive) 한다고 되어 있다.
  • 1로 설정되어 있다면 테이블명은 디스크에 소문자로 저장되지만 비교는 대소문자 구분을 하지 않는다고 한다.
  • 2로 설정되어 있다면 테이블명은 주어진대로 저장이 되지만, 소문자로 구분된다고 한다.

무엇보다 눈에 띄는 대목은 아래에 있다.

image-20230107114057311

윈도우나 MacOS 처럼 대소문자 구분을 못하는 파일 시스템에서는 해당 설정이 0이 될 수 없다고 한다.

기본 값 또한 Unix 시스템은 0 이며 Windows 는 1, 그리고 MacOS 는 2로 설정 되어 있다. 이제 에러 메시지로 돌아와서

Different lower_case_table_names settings for server ('2') and data dictionary ('0').

이제 에러 메시지가 눈에 들어오기 시작하지 않는가? 데이터는 0으로(Linux) 설정되어 있는데 지금 설정이 2로(MacOS) 되어 있다고 한다.

해결

1차 시도: 실패

이제 문제도 파악했고, 원인도 찾아내었으니 해결을 해 보자.

일단 lower_case_table_names 를 강제로 0 으로 부여 해 보겠다.

docker run -d --name dutypark_dev_db \
  -v /Users/shane/Documents/dev/_dutypark_dev_db:/var/lib/mysql \
  -p 3306:3306 \
  mysql \
  mysqld --lower_case_table_names=0

해결이 되었는지 확인 해 보자.

image-20230107115040758

lower_case_table_names를 0으로 설정 하셨는데요, 파일 시스템이 영 아니시네요? 안돼. 돌아가. 바꿔줄 생각 없어.

안된다.

2차 시도: 절반의 성공

이번에는 구글링을 통해 해결 방안을 찾아 보았다. 요즘엔 구글보다 ChatGPT에 먼저 물어보는 경우가 많은데, ChatGPT의 경우에는 이런 예외적인 상황에 대해서는 아직은 약한 모습을 보인다. 다행히 StackOverflow에서 비슷한 문제를 겪은 사람들이 많았는데 대다수의 경우에는 Docker Desktop 2.3 버전을 사용할 때는 괜찮다가 Docker Desktop 2.4 버전으로 업데이트 한 이후 부터 이런 문제를 겪었다고 한다.

그리고 Docker Desktop 2.4 버전은 gRPC FUSE가 file sharing으로 추가된 버전이기도 하다. 이를 위해 도커 데스크탑 버전을 낮춰 사용하기도 했다지만 이미 Docker Desktop은 4.15.0 버전 까지 나왔는데 그러기엔 많이 왔다.

Preferences -> General 에 가서 Choose file sharing implementation 을 osxfs(Legacy)로 변경 해 주자.

image-20230107124737626

이후 Apply & restart 를 해서 재시작을 한 뒤 다시 컨테이너를 실행 하면

docker run -d --name dutypark_dev_db \
  --restart unless-stopped \
  -v /Users/shane/Documents/dev/_dutypark_dev_db:/var/lib/mysql \
  -p 3306:3306 \
  mysql

image-20230107125322778

정상적으로 뜬다.

Tips

만약 변경 후 아래와 같은 오류가 나올 경우

2023-01-07 12:30:31 chown: changing ownership of '/var/lib/mysql/mysql.sock': No such file or directory

이는 불필요한 심볼릭 링크인 mysql.sock 까지 복사가 되어기 때문인데, 아래와 같이 확인을 해 보면

mysql.sock 파일은 필요가 없다. 볼륨을 걸 폴더에서 mysql.sock 파일을 제거하면 문제가 해결된다.

3차시도: 깔끔한 성공

이걸로 모든 해결이 끝났다고 생각 할 수 있지만, 어쨌든 기본 설정을 변경하는건 찝찝함이 남아있다. 그리고 심지어 VirtioFS 를 쓰면 마운트를 바인딩하는데 퍼포먼스 향상 효과가 있다고까지 한다. DB를 덤프해서 새로운 볼륨 폴더를 생성 해 보자.

mysqldump

이를 위해 mysqldump를 사용할 것이다.

Docker 컨테이너로 진입한다.

docker exec -it dutypark_dev_db bash

mysqldump 사용법은 아래와 같다.

mysqldump -u {사용자 계정} -p {원본 데이터베이스명} > {생성할 백업 데이터베이스명}.sql
# 예시
 mysqldump -u root -p dutypark > dutypark.sql

처음에는 DB에 접속하는 계정으로 시도했는데, 권한이 없다하여 root 계정으로 덤프 했다.

image-20230107130339556

dutypark.sql 파일이 생성된 것이 확인 됨.

dutypark.sql 파일을 로컬로 가져온다.

docker container cp dutypark_dev_db:/dutypark.sql .

image-20230107130546753

정상적으로 덤프가 끝났으니 이제 방금 컨테이너는 미련 없이 제거 해 준다.

docker stop dutypark_dev_db
docker rm dutypark_dev_db

image-20230107130839727이번에는 설정을 VirtioFS 로 해보았다. gRPC FUSE로 설정해도 되지만 얼마전부터 도커 가상화 머신이 qemu 대신 Virtualization.Framework 로 변경 되면서 궁금하기도 했었기 때문에 VirtioFS 를 테스트 해 보기로 했다. 다시 Apply & Restart를 하고

볼륨을 걸 폴더에 있는 모든 파일을 삭제한다. 그러면 이제 mysql이 실행 될 때 초기화가 진행 될 것이다.

rm -rf _dutypark_dev_db/*
# 이후 다 삭제된 것 확인
ls -al _dutypark_dev_db

rm -rf 명령을 할 때는 항상 조심

이제 컨테이너를 다시 실행 해 준다. 이번에는 기존 데이터가 없으니 루트 비밀번호까지 지정해서 띄우도록 한다.

docker run -d --name dutypark_dev_db \
  --restart unless-stopped \
  -v /Users/shane/Documents/dev/_dutypark_dev_db:/var/lib/mysql \
  -p 3306:3306 \
  -e MYSQL_ROOT_PASSWORD=pass \
  mysql

이후 로그를 확인 해 보면 당연히 잘 떴다.

 docker logs -f dutypark_dev_db

image-20230107132021375

이제 덤프해둔 데이터베이스를 복구 할 차례. 로컬에서 아까 저장해둔 sql 파일을 역으로 복사한다.

docker container cp ./dutypark.sql dutypark_dev_db:/.

image-20230107132138491

복사 후 컨테이너 내에 dutypark.sql 파일이 정상적으로 저장된 상태

root 계정으로 mysql 접속 후

docker exec -it dutypark_dev_db bash
mysql -u root -p
# 컨테이너를 띄울때 설정한 비밀번호를 입력해 접속

가장 먼저 사용자를 추가 해 준다.

create user 'dutypark'@'%' identified by '비밀번호';

이제 데이터 베이스를 생성 후 sql 파일을 밀어 넣는다.

create database dutypark;

# mysql 종로 휴
mysql -u root -p dutypark < dutypark.sql

image-20230107132538681

순서에 주목

이제 미리 생성한 유저에게 방금 만든 데이터베이스에 대한 권한을 부여 한다.

mysql -u root -p

GRANT ALL PRIVILEGES ON dutypark.* TO 'dutypark'@'%';

드디어 모든 DB 이전도 끝났고, 성공적으로 설정도 원래상태로 돌릴 수 있었다.

결론

애초에 볼륨 폴더 긁어올 필요 없이 처음부터 dump 했으면 오히려 간단하게 해결 되었을 것이다.

어쨌든 덕분에 재밌는 오류도 발견했고 파일시스템의 대소문자 구분때문에 이런 일도 있구나 하는걸 겪어 재밌었다.

끝.

References

반응형