1. Issue Description
카테고리별로 식재료를 조회하는 기능에서 과일 카테고리의 식재료를 가져오되, name 기준으로 오름차순 하는 요청을 했는데 다음과 같은 결과가 나왔다.
{
"data": {
"getIngredientsByCategory": [
{
"name": "배",
...
},
{
"name": "딸기",
...
},
{
"name": "사과",
...
},
{
"name": "자몽",
...
},
{
"name": "포도",
...
},
{
"name": "복숭아",
...
}
]
}
}
결과를 보면 name 순이 이상함을 알 수 있다.
배
딸기
사과
자몽
포도
복숭아
PostgreSQL DB에서 다른 카테고리도 포함 시켜서 정렬을 해 본 결과 문자열 수대로 정렬이 되고, 그 다음에 name 별로 정렬이 되는 이상한 방식으로 정렬이 되고 있었다.
2. 원인 추론
1) Postgres sort not working 으로 검색
결과 : Postgresql ORDER BY not working as expected
나랑 비슷한 느낌의 문제를 겪고 있는 사람의 글이었는데 collate 라는 키워드가 있어서 알아보았다.
2) Postgres collate 로 검색
검색 결과 Postgres, 한글 정렬, collate 키워드가 많이 보였다.
Postgres의 경우 처음 DB를 생성할 때, 별다른 설정을 하지 않는다면 en_US.utf-8이 collate로 default 설정이 되어 버리는데, 이 설정을 해주면 한글에 대한 정렬이 이상해진다고 한다.
- 한글 정렬을 바로 하려면 두 가지 방법이 존재했다.
- DB를 밀고 처음부터 collate 설정을 ko_KR.utf-8로 해주기
- 정렬을 해줄 때마다 다음과 같이 요청하기
SELECT * FROM test_table ORDER BY name COLLATE "ko_KR.utf8";
- 애플리케이션 배포 시 DB를 설정해 줄 때는 COLLATE 설정을 해 줄 것이고, 그러므로 SQL 문은 쓰이지 않을 것이다.
- Docker에서 정렬 테스트를 해 보려면 DB를 밀고 새롭게 DB 설정을 해주는 것이 올바른 해결책이다.
3. 해결
1) Custom Postgres 이미지 빌드
Docker 공식 Postgres 이미지는 ko_KR.utf8을 지원하지 않기 때문에, Postgres의 collate를 변경하려면, 공식 이미지를 사용하지 않고, Custom한 Dockerfile로 Postgres 이미지를 만들어 써야 한다.
Dockerfile을 만들 때는 다음 블로그 링크를 참고하였다.
공식 PostgreSQL Docker 이미지에 한글 적용하기
2) 커스텀한 이미지로 Docker에서 Postgres를 build 했을 때 collate 잘 변경되었는지 확인하기
Dockerfile-postgres 코드
FROM postgres
RUN ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime && \
echo 'ko_KR.UTF-8 UTF-8' >> /etc/locale.gen && \
locale-gen
ENV LC_COLLATE=ko_KR.UTF-8
- FROM postgres
- PostgreSQL의 공식 이미지를 기반 이미지로 사용합니다. PostgreSQL의 최신 버전이 기본적으로 사용됩니다.
- ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
- 서울 시간대를 로컬 시스템의 시간대로 설정합니다. 심볼릭 링크를 생성하여 시스템 시간대 설정을 올바르게 맞춥니다
- -s: 심볼릭 링크 생성, -f: 기존에 /etc/localtime 파일이 있을 경우 덮어쓴다.
- 심볼릭 링크란?
- 파일 시스템에서 특정 파일이나 디렉토리를 가리키는 특별한 유형의 파일. 윈도우의 바로 가기와 유사한 개념
- ⇒ /etc/localtime 파일이 서울 시간대 정보를 가리키도록 설정. 시스템의 기본 시간대를 서울 시간으로 설정하는 역할을 함
- echo 'ko_KR.UTF-8 UTF-8' >> /etc/locale.gen
- 한국어 UTF-8 로케일을 /etc/locale.gen 파일에 추가합니다. 이 파일은 로케일을 설정하는 데 필요한 구성 파일입니다.
- 인코딩을 UTF-8로 지정해줍니다.
- locale-gen
- locale-gen 명령어를 사용하여 설정된 로케일을 생성합니다. 이로써 시스템에서 한국어 UTF-8 로케일을 사용할 수 있게 됩니다.
- LC_COLLATE=ko_KR.UTF-8
- 문자열 정렬에 사용되는 로케일을 한국어 UTF-8로 설정합니다.
Docker에 Custom한 Dockerfile로 Postgres 띄워보기
1) Dockerfile로 Postgres 이미지 build
docker build -t {이미지명 지정} -f {Dockerfile 이름} .
docker build -t custom-postgres -f Dockerfile-postgres .
2) 만들어진 이미지 확인

3) 만들어진 이미지로 Docker Container에 Postgres 띄우기
docker run -d --name {Container 이름} \
-e POSTGRES_USER={USERNAME} \
-e POSTGRES_PASSWORD={PASSWORD} \
-e POSTGRES_DB={DB명} \
-p 5432:5432 {이미지명}
docker run -d --name my_postgres \
-e POSTGRES_USER=user \
-e POSTGRES_PASSWORD=1234 \
-e POSTGRES_DB=mydb \
-p 5432:5432 custom-postgres

4) Postgres collate 확인
# Docker 컨테이너에서 명령어를 실행하기 위해 사용하는 명령어
docker exec -it my_postgres bash
# PostgreSQL 데이터베이스에 접속하기 위한 명령어
psql -h localhost -p 5432 -U user -d mydb
# PostgreSQL의 mydb 데이터베이스의 collation과 character type 설정을 확인하는 데 사용
select datname, datcollate, datctype from pg_database where datname = 'mydb';

Docker Compose Script 변경
version: "3"
services:
postgres:
container_name: postgres
build: # postgres 공식 이미지를 사용하지 않고 custom dockerfile로 build
context: .
dockerfile: Dockerfile-postgres
env_file: ./.env
volumes:
- bobJoyingDBVolume:/var/lib/postgresql/data
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- ${POSTGRES_LOCAL_PORT}:${POSTGRES_DOCKER_PORT}
4. 결과
같은 요청을 보냈을 때 다음과 같은 결과를 얻을 수 있었다.
딸기
배
복숭아
사과
자몽
포도
{
"data": {
"getIngredientsByCategory": [
{
"name": "딸기", ...
},
{
"name": "배", ...
},
{
"name": "복숭아", ...
},
{
"name": "사과", ...
},
{
"name": "자몽", ...
},
{
"name": "포도", ...
}
]
}
}
'STUDY > Trouble Shooting' 카테고리의 다른 글
WebMvcTest 403 Forbidden 해결하기(feat. CSRF) (1) | 2024.09.27 |
---|---|
CORS란? Spring Security에 따른 CORS 설정 (1) | 2024.09.16 |
Timestamped ZonedDateTime 오류 (0) | 2024.05.22 |
Redis Docker Container와 Spring Boot 연결이 안 되는 오류 (0) | 2024.05.22 |
만료된 토큰에서 토큰에 저장된 정보를 가져올 수 없는 오류 (0) | 2024.05.22 |