성공한 케이스를 그대로 적으면 짧은 내용이지만 혹시나 나중에 다시 쓸모가 있을지도 모르는 삽질 과정을 기록하기 위해서 mysql 설치 과정만 별도로 정리한다.
cannot execute binary file: Exec format error
일단, 기존에 x86 환경에서 정리해놓은 스크립트로 mysql 바이너리를 그냥 다운 받아 실행했는데 위 에러가 발생해서 잠깐 동안 고민에 빠졌었다. 몇번이고 그냥 실행해보다가 보니 바이너리(mysql-8.0.18-linux-glibc2.12-x86_64.tar.xz
)에 x86_64 라고 적힌게 갑자기 눈에 들어왔고 그제서야 내가 라즈베리 파이 arm64 에서 작업하고 있다는 사실을 알아차렸다. 어쨋든 mysql.com 에서 제공하는 x86 바이너리는 아키텍처가 달라서 그냥 가져다가 쓸 수가 없는데, mysql 8.0 버전은 apt 로 바로 설치할 수 있는 레포도 없는 것 같아서(5.7은 apt로 받을 수 있다) 직접 빌드해서 쓰기로 결정하게 되었는데 이 잘못된 판단으로 삽질의 늪에 빠지게 되었다.
mysql 소스 설치
일단 컴파일 도구인 cmake
를 먼저 설치한 뒤
apt install cmake
mysql.com 에서 소스 코드를 다운받으면 되는데, 다음과 같이 boost 헤더가 포함된 것으로 받는다. 소스코드만 200메가바이트 가까이 된다 ㄷㄷ
Generic Linux (Architecture Independent), Compressed TAR Archive
Includes Boost Headers
curl https://cdn.mysql.com/archives/mysql-8.0/mysql-boost-8.0.18.tar.gz
| tar -xz && cd mysql-8.0.18
이 상태에서 원래라면 몇가지 옵션만 설정한 뒤 바로 빌드하면 됐을텐데, 8.0.18 버전에서 문제가 되는 것인지 arm64 이어서 문제가 되는 것인지는 모르겠지만 client 쪽에서 다음과 같이 seg fault 가 발생했다.
mysql
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Segmentation fault (core dumped)
gdb 로 보니 다음과 같은 위치에서 문제가 발생했는데
Program received signal SIGSEGV, Segmentation fault.
0x0000aaaaaab99a44 in terminal_alloc (el=el@entry=0xaaaaab1fd910, t=t@entry=0xaaaaaaea6820 <tstr>,
cap=0xffffffffffffe7f8 <error: Cannot access memory at address 0xffffffffffffe7f8>)
at /app/src/mysql-8.0.18/extra/libedit/terminal.c:334
334 if (cap == NULL || *cap == '\0') {
(gdb)
stackexchange 에서 비슷한 경우가 있어 따라했더니 해결 됐다. 혹시 그냥 빌드 해보고 위와 같은 문제가 발생하는 경우 똑같이 해보면 좋을 것 같은데 빌드하는데 시간이 엄청 들기 때문에 미리 설정하는 것도 ..
./mysql-8.0.18/extra/libedit/terminal.c
에서 termcap.h
라이브러리가 원래는 HAVE_TERMCAP_H
매크로 안에 들어있는데 그냥 무조건 참조하도록 밖으로 빼주었다. 8.0.18 버전 기준, 56라인에 있다.
AS-IS
#if 0 /* TODO: do we need this */
#ifdef HAVE_TERMCAP_H
#include <termcap.h>
#endif
TO-BE
#include <termcap.h>
#if 0 /* TODO: do we need this */
#ifdef HAVE_TERMCAP_H
#include <termcap.h>
#endif
빌드
여기까지 완료되었으면 이제 본격적으로 빌드를 진행할 수 있다. 다시 다운받은 소스코드 경로로 이동한 뒤 build 디렉토리를 만들고 작업을 진행한다.
cd ./mysql-8.0.18
mkdir build && cd build
cmake ../ \
-DCMAKE_INSTALL_PREFIX=/app/serv/mysql/8.0.18 \
-DMYSQL_DATADIR=/app/data/mysql \
-DSYSCONFDIR=/etc \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_FEDERATED_STORAGE_ENGINE=1 \
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
-DMYSQL_UNIX_ADDR=/tmp/mysql.sock \
-DENABLED_LOCAL_INFILE=1 \
-DENABLE_DOWNLOADS=1 \
-DWITH_EXTRA_CHARSETS=all \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DWITH_DEBUG=0 \
-DMYSQL_MAINTAINER_MODE=0 \
-DDOWNLOAD_BOOST=1 \
-DWITH_BOOST=../boost
다음과 같이 빌드 파일이 다 생성되었으면
...
-- CMAKE_EXE_LINKER_FLAGS
-- CMAKE_MODULE_LINKER_FLAGS
-- CMAKE_SHARED_LINKER_FLAGS
-- Configuring done
-- Generating done
-- Build files have been written to: /app/src/for-blog/mysql-8.0.18/build
make install
명령으로 마무리 작업에 들어가면 되는데 -j
옵션으로 job 개수를 늘려서 하면 좀 더 빨리 끝낼 수 있다.
make install -j 4
대신, 무슨 이유에선지는 모르겠지만, 쓰레드 수를 늘리면 다음과 같이 도중에 빌드 실패하는 경우가 종종 있는데
[ 87%] Built target sql_main
[ 87%] Building CXX object sql/CMakeFiles/sql_gis.dir/gis/difference.cc.o
[ 87%] Building CXX object sql/CMakeFiles/sql_gis.dir/gis/distance_sphere.cc.o
[ 87%] Building CXX object sql/CMakeFiles/sql_gis.dir/gis/equals.cc.o
[ 87%] Building CXX object sql/CMakeFiles/sql_gis.dir/gis/gc_utils.cc.o
[ 87%] Building CXX object sql/CMakeFiles/sql_gis.dir/gis/geometries.cc.o
[ 87%] Building CXX object sql/CMakeFiles/sql_gis.dir/gis/intersects.cc.o
[ 87%] Building CXX object sql/CMakeFiles/sql_gis.dir/gis/is_simple.cc.o
c++: internal compiler error: Killed (program cc1plus)
Please submit a full bug report,
with preprocessed source if appropriate.
See <file:///usr/share/doc/gcc-7/README.Bugs> for instructions.
sql/CMakeFiles/sql_gis.dir/build.make:158: recipe for target 'sql/CMakeFiles/sql_gis.dir/gis/difference.cc.o' failed
make[2]: *** [sql/CMakeFiles/sql_gis.dir/gis/difference.cc.o] Error 4
make[2]: *** Waiting for unfinished jobs....
CMakeFiles/Makefile2:23637: recipe for target 'sql/CMakeFiles/sql_gis.dir/all' failed
make[1]: *** [sql/CMakeFiles/sql_gis.dir/all] Error 2
Makefile:162: recipe for target 'all' failed
make: *** [all] Error 2
job 수를 한 개로 낮춰서, 이 막혔던 부분을 통과할때 까지만 진행하고 킬 한 뒤 다시 -j 4
옵션으로 이어서 진행하는 과정을 반복하면 빠르게 빌드할 수 있다.
중간중간 확인하기 번거롭고 시간이 많다면 그냥 맘 편히 -j
옵션 없이 돌려놓으면 된다. 자기 직전에 걸어놓고 자고 일어나면 되는 것 같다.
make install
바이너리 빌드가 끝났으면 다른 것들과 마찬가지로 심볼릭 링크를 생성해주고
cd /app/serv/mysql && ln -s ./8.0.18/* .
지금까지 설치한 소프트웨어들의 소유권한을 root에서 변경하고
chown -R ubuntu:ubuntu /app
su - ubuntu
vim ~/.profile
APM 바이너리와 라이브러리 경로를 환경변수에 추가해주면 설치 끝.
PATH=\
/app/serv/httpd/bin:\
/app/serv/mysql/bin:\
/app/util/php/bin:\
$PATH
export PATH
LD_LIBRARY_PATH=\
/app/serv/httpd/lib:\
/app/serv/mysql/lib:\
/app/util/php/lib:\
$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
mysql 데이터베이스 생성
APM 설치는 위 단계까지가 끝이고 이제 서비스를 위해 데이터베이스를 생성한다. ubuntu 계정에서 vim /tmp/my.cnf
파일을 열어 다음과 같이 적어주고
[mysqld]
user = ubuntu
port = 3306
basedir=/app/serv/mysql
datadir=/app/data/mysql
socket=/tmp/mysql.sock
innodb_data_file_path=ibdata1:12M:autoextend
innodb_log_files_in_group=3
innodb_log_file_size=64M
innodb_buffer_pool_size=1024M
innodb_io_capacity=4000
collation-server = utf8_unicode_ci
init-connect = "SET NAMES utf8"
character-set-server = utf8
[mysqld_safe]
log-error=/app/logs/mysql/mysqld.log
[client]
default-character-set = utf8
[mysql]
default-character-set = utf8
mysqld --initialize
명령을 수행하면
2020-03-12T16:26:49.872195Z 0 [System] [MY-013169] [Server] /app/serv/mysql/8.0.18/bin/mysqld (mysqld 8.0.18) initializing of server in progress as process 10158
2020-03-12T16:26:55.382392Z 5 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: A,-Yi-a9rz!h
위와 같이 기본 시스템 데이터베이스가 생성되고 초기 로그인을 위한 임시 비밀번호를 알려주는데
mysqld_safe --user=ubuntu &
명령으로 서버를 실행하고
mysql -u root -p"A,-Yi-a9rz!h"
이렇게 임시 비밀번호로 로그인한 뒤 다음 SQL로 비밀번호를 바꿔주면 이후 정상적으로 DB 를 사용할 수 있다.
ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPassword';
데이터베이스는 이후 WordPress와 Nextcloud 에서 사용할 수 있도록 하나 정도는 별도로 생성해두어야 하는데, 사용자는 선택사항이지만 필요에 따라 추가해서 사용해도 된다.
CREATE USER 'newusername'@'localhost' IDENTIFIED BY 'MyNewPassword';
CREATE DATABASE new_db;
GRANT ALL PRIVILEGES ON new_db.* TO 'newusername'@'localhost';