'MariaDB'에 해당되는 글 2건
- 2025.12.31 [시놀로지 NAS] Docker로 Redmine 설치 (DSM 7.3, ds218+)
- 2022.10.12 [mysql/mariadb] 자주 사용 쿼리 & 메타데이터 (continue)
[시놀로지 NAS] Docker로 Redmine 설치 (DSM 7.3, ds218+)
Posted on 2025. 12. 31. 21:07
Filed Under 시놀로지NAS활용
[시놀로지 NAS] Docker로 Redmine 설치하기 (삽질기 포함)
안녕하세요! 오늘은 시놀로지 NAS에 프로젝트 관리 도구인 Redmine을 설치하는 과정을 정리해보려 합니다. 처음 시도하면서 꽤 많은 시행착오(삽질)를 겪었는데, 저처럼 고생하지 마시라고 A부터 Z까지 상세하게 기록해 둡니다. 나중에 저도 다시 볼 겸요. ^^;
0. 전체 구조 이해하기 (우리가 만들 집의 설계도)
Redmine을 설치하려면 총 3가지의 컨테이너(방)가 필요합니다.
- MariaDB (금고): Redmine의 모든 데이터(회원 정보, 일감, 게시글 등)를 안전하게 보관하는 데이터베이스입니다. 가장 중요합니다.
- phpMyAdmin (창문): 터미널의 검은 화면 대신, 웹 브라우저에서 마우스로 편하게 MariaDB 금고 안을 들여다보고 관리할 수 있게 해주는 관리 도구입니다.
- Redmine (장부): 우리가 실제로 사용할 프로젝트 관리 프로그램입니다. MariaDB 금고에 데이터를 저장하고 불러옵니다.
🤔 Web Station, 꼭 설치해야 할까? (중요!)
많은 블로그에서 Web Station을 먼저 설치하라고 하지만, 결론부터 말하면 Docker로 설치할 때는 필수가 아닙니다. 오히려 저처럼 포트 충돌(특히 80번 포트) 문제로 삽질하게 만드는 원인이 될 수 있습니다.
- 설치 목적: Web Station은 NAS 자체를 하나의 웹 서버로 만들 때 사용합니다.
- 결론: Docker 컨테이너는 그 자체로 독립된 서버 역할을 하므로 Web Station 없이도 충분히 운영 가능합니다. 굳이 설치해서 포트 문제를 일으킬 필요가 없습니다.
1. 준비물 및 사전 작업 (폴더 만들기)
가장 먼저, 데이터가 저장될 '실제 창고'(폴더)를 만들어야 합니다. 이 단계를 건너뛰면 컨테이너가 실행되지 않거나, 열심히 작업한 데이터가 날아갈 수 있습니다.
1. File Station에서 폴더 생성:docker 폴더 아래에 다음과 같이 폴더를 만들어 주세요.
/docker/mariadb(DB 데이터 저장용)/docker/redmine/files(Redmine 첨부파일 저장용)/docker/redmine/plugins(Redmine 플러그인 저장용)
2. 권한 설정 (매우 중요! ⭐⭐⭐):
만든 폴더 각각에 대해 읽기/쓰기 권한을 주어야 합니다. (저는 이것 때문에 한참 고생했습니다 ㅠㅠ)
- 각 폴더 우클릭 -> [속성] -> [권한] 탭으로 이동.
- [생성] 클릭 -> 사용자/그룹에
Everyone선택 -> [읽기] 및 [쓰기] 체크. - 하단의 '이 폴더, 하위 폴더 및 파일에 적용' 체크 후 저장.
2. Step 1: MariaDB (데이터베이스 금고) 설치
1. 이미지 다운로드:Container Manager -> [레지스트리]에서 mariadb 검색. 가장 상단의 공식 이미지(latest 또는 11.4)를 다운로드합니다. (저는 ubi 버전을 받았다가 권한 문제로 고생했으니 일반 버전을 추천합니다.)
2. 컨테이너 생성 및 설정:
- 포트 설정: 로컬 포트
3306, 컨테이너 포트3306(기본값 그대로 사용). - 볼륨 설정:
- 파일/폴더:
/docker/mariadb(아까 만든 폴더 선택) - 마운트 경로:
/var/lib/mysql(직접 입력)
코멘트: 이 설정이 있어야 컨테이너를 삭제해도 데이터가 안전하게 남습니다.
- 환경 변수 설정 (필수):
- 변수:
MARIADB_ROOT_PASSWORD(또는MYSQL_ROOT_PASSWORD) - 값: (사용할 강력한 비밀번호 입력)
3. 설치 확인:
컨테이너 실행 후 [로그] 탭에 ready for connections 문구가 뜨면 성공!
3. Step 2: phpMyAdmin (DB 관리 도구) 설치
1. 이미지 다운로드: phpmyadmin 검색 후 다운로드.
2. 컨테이너 생성 (Web Station 충돌 해결!):
첫 화면에서 'Web Station을 통해 웹 포털 설정' 체크를 반드시 해제하세요. 이걸 해제해야 포트 충돌 없이 원하는 포트를 설정할 수 있습니다.

3. 상세 설정:
- 포트 설정: 로컬 포트
8080(웹 주소창에 쓸 번호), 컨테이너 포트80(고정). - 링크 설정: 아까 만든 MariaDB 컨테이너 선택, 별칭(Alias)에
db입력. - 환경 변수 설정:
- 변수:
PMA_HOST - 값:
db(링크 별칭 입력)
코멘트:
PMA_HOST에 링크 별칭을 적어주면 IP 주소가 바뀌어도 알아서 MariaDB를 찾아갑니다.
- 볼륨 설정: 필요 없음 (데이터 저장 안 함).

4. 접속 확인: 웹 브라우저에 http://NAS아이피:8080 입력. ID는 root, 비밀번호는 MariaDB에서 설정한 값을 넣고 로그인해 봅니다.
4. Step 3: Redmine용 데이터베이스 생성
Redmine을 설치하기 전에 Redmine이 사용할 빈 금고(데이터베이스)를 미리 만들어줘야 합니다.
- phpMyAdmin에 접속합니다.
- 상단 [데이터베이스] 탭 클릭.
- 새 데이터베이스 이름에
redmine입력, 문자 집합은utf8mb4_general_ci선택 후 [만들기] 클릭.
5. Step 4: Redmine (프로젝트 관리 도구) 설치
1. 이미지 다운로드: redmine 검색 후 공식 이미지 다운로드.
2. 컨테이너 생성 및 설정:
- 포트 설정: 로컬 포트
3000, 컨테이너 포트3000. - 볼륨 설정:
/docker/redmine/files↔/usr/src/redmine/files/docker/redmine/plugins↔/usr/src/redmine/plugins(필요시)
- 링크 설정: MariaDB 컨테이너 선택, 별칭
db입력.
3. 환경 변수 설정 (가장 중요! ⭐⭐⭐):
이 부분을 정확히 입력해야 Redmine이 MariaDB와 연결됩니다.
REDMINE_DB_MYSQL:db(링크 별칭)REDMINE_DB_DATABASE:redmine(아까 만든 DB 이름)REDMINE_DB_USERNAME:rootREDMINE_DB_PASSWORD: (MariaDB 비밀번호)
4. 설치 확인:
Redmine은 처음 실행 시 DB 테이블을 만드느라 시간이 꽤 걸립니다(3~5분). [로그] 탭에 Listening on http://0.0.0.0:3000 문구가 뜰 때까지 느긋하게 기다려 주세요.
또는 아래이미지와 같이 [터미널]로 접속하여 명령어로 확인하는 방법도 있습니다.

6. 마무리
이제 모든 설치가 끝났습니다!
- 내부 접속 테스트: 같은 네트워크(집) 안에서 브라우저에
http://NAS아이피:3000을 입력해 보세요. Redmine 초기 화면이 뜬다면 성공입니다! (초기 계정: admin / admin) - 외부 접속 (집 밖에서): 카페나 회사에서 접속하려면 사용 중인 공유기 설정 페이지에서
3000(Redmine),8080(phpMyAdmin),3306(MariaDB) 포트에 대한 포트포워딩 설정이 필요합니다. (이 부분은 각자 공유기 매뉴얼을 참고해주세요!)
긴 글 따라오시느라 고생 많으셨습니다. 저의 삽질 기록이 여러분의 성공적인 설치에 도움이 되기를 바랍니다! 😊
7. 참고
- [Container Manager] MariaDB와 레드마인 구축하는 방법, 쉽게 따라하기 | 2025.01.31
- Redmine User Manual | 2021.02.01
"이 글은 사람(Human)이 설정을 진행하며 질답한 내용을 기반으로 Google Gemini 3에 의해 작성되었습니다(이미지 제외)"
[mysql/mariadb] 자주 사용 쿼리 & 메타데이터 (continue)
Posted on 2022. 10. 12. 10:03
Filed Under DB
-- DBMS Version 확인
select @@version; --또는 select version();
-- 모든 시스템 변수 리스트
SHOW GLOBAL VARIABLES;
-- SHOW GLOBAL VARIABLES LIKE 'char%';
-- SHOW GLOBAL VARIABLES LIKE 'collation%';
-- database(=schema) 목록
SELECT DISTINCT table_schema FROM INFORMATION_SCHEMA.TABLES;
-- 현재 DB스미마
SET @current_db = DATABASE();
SELECT @current_db;
-- 사용자 정보
SELECT * FROM INFORMATION_SCHEMA.USER_PRIVILIEGES;
-- 실행중인 커맨드
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
-- 테이블 구조/설명 조회
DESC INFORMATION_SCHEMA.TABLES;
-- 테이블/컬럼 구조
SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'XXX'
SELECT * FROM INFORMATION_SCHEMA.COLUMNS;
-- 간단히 변수 선언해서 사용하기
SET @PARAM1 = 1; -- 변수명 앞에 @골뱅이 필수!!
SELECT @PARAM1;
-- 날짜 다루기
SELECT CAST(NOW()) as DATE);
SELECT STR_TO_DATE('20230111', '%Y%m%d');
SELECT DATE_ADD(NOW(), INTERVAL 1 DAY); // MINUTE, MONTH, YEAR
SELECT DATE_SUB(NOW(), INTERVAL 1 DAY); // 또는 DATE_ADD의 INTERVAL 값을 음수로 넣으면 같은 결과
SELECT DATE_FORMAT(CURRENT_TIMESTAMP(), '%Y%m%d%H%i%s');
-- 유효체크
SELECT CASE WHEN STR_TO_DATE('2023XXXX') IS NOT NULL THEN '정상' ELSE '비정상' END; // 날짜문자열인지 체크
SELECT CASE WHEN '99' REGEXP '^[0-9]+$ = 1 THEN '숫자' ELSE '숫자아닌문자열포함' END;
MariaDB 레퍼런스: https://mariadb.com/kb/en/ (MariaDB Server > Tutorials)
-- 현재 설정 확인
SHOW VARIABLES LIKE 'max_connections'; -- Too many connection 확인.
-- 임시 증가 (재시작시 초기화됨)
-- SET GLOBAL max_connections = 200;
SHOW PROCESSLIST;
SHOW FULL PROCESSLIST;
-- 오래된 연결만 확인
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
-- WHERE TIME > 3600 -- 1시간
ORDER BY TIME DESC;
SELECT ID, USER, HOST, STATE, TIME
,CONCAT(
IF(TIME >= 3600, CONCAT(FLOOR(TIME/3600), 'h '), ''),
IF(TIME >= 60, CONCAT(FLOOR((TIME % 3600)/60), 'm '), ''),
(TIME % 60), 's'
) AS time_formatted
FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE 1=1
and COMMAND = 'Sleep' -- 1. Sleep: 유휴 상태/2. Query: 쿼리 실행 중/3. Connect: 연결 중/4. Binlog Dump: 복제 중/5. Killed: 종료 중
and user = 'she_admin'
-- AND TIME > 1800 -- 30분 이상
and HOST like '%10.10.10.10%'
ORDER by TIME DESC;
kill 8197;
▼ DB테이블 상세설계 조회
-- 테이블 목록
SELECT TABLE_NAME AS 테이블ID, TABLE_COMMENT AS 테이블명
,DATE_FORMAT(CREATE_TIME, '%Y-%m-%d') AS 생성일
FROM information_schema.TABLES
WHERE 1=1
AND TABLE_TYPE = 'BASE TABLE' -- SYSTEM VIEW, BASE TABLE, VIEW, SEQUENCE
AND TABLE_SCHEMA in ('XXX','YYY')
AND TABLE_NAME NOT LIKE '!_%' ESCAPE '!' /*미사용(prefix: _) 테이블 제거*/
ORDER BY TABLE_SCHEMA, TABLE_NAME;
-- 컬럼 목록 추출
SELECT
t.TABLE_SCHEMA,
t.TABLE_NAME AS 테이블ID, t.TABLE_COMMENT AS 테이블명,
c.ORDINAL_POSITION as COL_ORD, c.COLUMN_NAME AS 컬럼ID, c.COLUMN_COMMENT AS 컬럼명,
CONCAT(c.COLUMN_TYPE) AS 데이터타입,
CASE WHEN c.IS_NULLABLE = 'NO' THEN 'Y' ELSE '' END AS NOT_NULL,
COALESCE(c.COLUMN_DEFAULT, '') AS 디폴트값,
-- LEFT JOIN으로 외래 키 정보를 가져와서, k.REFERENCED_TABLE_NAME이 NULL이 아니면 'Y'
CASE WHEN k.REFERENCED_TABLE_NAME IS NOT NULL THEN 'Y' ELSE '' END AS FK
FROM
information_schema.COLUMNS c
INNER JOIN
information_schema.TABLES t ON c.TABLE_NAME = t.TABLE_NAME AND c.TABLE_SCHEMA = t.TABLE_SCHEMA
LEFT JOIN
information_schema.KEY_COLUMN_USAGE k
ON k.TABLE_SCHEMA = c.TABLE_SCHEMA
AND k.TABLE_NAME = c.TABLE_NAME
AND k.COLUMN_NAME = c.COLUMN_NAME
AND k.REFERENCED_TABLE_NAME IS NOT NULL -- 외래 키 조건
WHERE 1=1
AND t.TABLE_TYPE = 'BASE TABLE' -- SYSTEM VIEW, BASE TABLE, VIEW, SEQUENCE
AND t.TABLE_SCHEMA in ('xxx','ttt')
GROUP BY t.TABLE_SCHEMA, t.TABLE_NAME, c.COLUMN_NAME -- 중복 제거 (FK 정보가 여러 번 잡힐 수 있으므로)
ORDER BY c.TABLE_SCHEMA, t.TABLE_NAME, c.COLUMN_NAME;
▼ DB프로시저,함수 조회
-- DB프로시저/함수 목록 조회(본문 스크립트 포함)
SELECT
routine_schema AS '데이터베이스명'
,routine_name AS '루틴명'
,routine_type AS '타입'
,data_type AS '반환_데이터타입'
,routine_definition AS 'DDL스크립트'
,created AS '생성일시',last_altered AS '최종수정일시'
FROM
information_schema.ROUTINES
WHERE 1=1
AND routine_schema IN ('스키마1', '스키마2')
ORDER BY
routine_type, routine_name;
-- DB프로시저/함수 전문(선언문+본문) 스크립트 조회
SHOW CREATE FUNCTION db_schema.함수이름;
SHOW CREATE PROCEDURE db_schema.프로시저이름;
▼ 백업테이블 생성
-- CREATE TABLE
CREATE TABLE 생성할_테이블명
AS
SELECT * FROM 원본_테이블명
WHERE 복사할_데이터_조건;
▼ 쉼표(,)로 연결된 값 목록 뽑기
-- 코드명(값), ...
SELECT GROUP_CONCAT(
CONCAT(TRIM(cl_nm), '(', cl_cd, ')')
SEPARATOR ', '
) AS combined_text
FROM comn_code where grp_cd = '공통코드그룹ID'
-- [MIG] AS-IS vs TO-BE 컬럼 목록
-- (필수조건: AS-IS/TO-BE 컬럼 순서를 동일하게 만들었을때)
SELECT
COALESCE(T1.ORDINAL_POSITION, T2.ORDINAL_POSITION) AS ORD,
T1.COLUMN_NAME AS COL_2,
T1.COLUMN_COMMENT AS COMMT_2,
T2.COLUMN_NAME AS COL_1,
T2.COLUMN_COMMENT AS COMMT_1
FROM (SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'TOBE테이블' AND TABLE_SCHEMA = 'db스키마'
) T1
LEFT JOIN
(SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'ASIS테이블' AND TABLE_SCHEMA = 'db스키마'
) T2
ON T1.ORDINAL_POSITION = T2.ORDINAL_POSITION
WHERE 1=1
UNION
SELECT
COALESCE(T1.ORDINAL_POSITION, T2.ORDINAL_POSITION) AS ORD,
T1.COLUMN_NAME AS COL_2,
T1.COLUMN_COMMENT AS COMMT_2,
T2.COLUMN_NAME AS COL_1,
T2.COLUMN_COMMENT AS COMMT_1
FROM (SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'TOBE테이블' AND TABLE_SCHEMA = 'db스키마'
) T1
RIGHT JOIN
(SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'ASIS테이블' AND TABLE_SCHEMA = 'db스키마'
) T2
ON T1.ORDINAL_POSITION = T2.ORDINAL_POSITION
WHERE 1=1