728x90
반응형
SMALL
SMALL

 

mysql> pager less -SFX
mysql> SELECT * FROM sometable;

 

또 다른 옵션은 조회할 때 "\G"를 끝에 추가하는 것이다.

SELECT * FROM employee\G;

 

728x90
반응형
LIST
728x90
반응형
SMALL
SMALL

 

우선, 나는 스프링 부트로 만든 애플리케이션을 MySQL과 Docker Compose로 컨테이너를 구동한다. 내 docker-compose.yml 파일은 다음과 같다.

 

version: '3.8'

services:
  app:
    image: 'tbell-mm-backend:latest'
    build: .
    env_file:
      - ".env"
    ports:
      - ${SERVICE_PORT}:${SERVICE_PORT}
    container_name: tbell-mm-backend
    depends_on:
      - db
    environment:
      - SPRING_DATASOURCE_URL=jdbc:mysql://db:${MYSQLDB_PORT}/${MYSQLDB_DATABASE}?useSSL=false
      - SPRING_DATASOURCE_USERNAME=${MYSQLDB_USER}
      - SPRING_DATASOURCE_PASSWORD=${MYSQLDB_ROOT_PASSWORD}
      - SPRING_JPA_PROPERTIES.HIBERNATE.DIALECT=org.hibernate.dialect.MySQLDialect
      - SPRING_JPA_HIBERNATE_DDL_AUTO=none
      - TZ=Asia/Seoul
      - _JAVA_OPTIONS=-Xmx15g
    volumes:
      - ./log:/app/log
    networks:
      mm-network:

  db:
    container_name: tbell-mm-mysql
    image: mysql:5.7
    restart: always
    env_file: ./.env
    environment:
      - MYSQL_ROOT_PASSWORD=$MYSQLDB_ROOT_PASSWORD
      - MYSQL_DATABASE=$MYSQLDB_DATABASE
    ports:
      - ${MYSQLDB_PORT}:${MYSQLDB_PORT}
    volumes:
      - mysqldb-volume:/var/lib/mysql
      - ./bak:/var/lib/backup
    networks:
      mm-network:

  backup:
    image: mysql:5.7
    container_name: tbell-mm-mysql-backup
    env_file:
      - ".env"
    depends_on:
      - db
    volumes:
      - ./bak:/var/lib/backup
    command: >
      bash -c "
      while true; do
        sleep 60
        mysqldump -h mysqldb -u$$MYSQLDB_USER -p$$MYSQLDB_ROOT_PASSWORD $$MYSQLDB_DATABASE > /var/lib/backup/$$(date +%Y-%m-%d-%H-%M-%S).sql
        echo ""Backup done at $$(date +%Y-%m-%d_%H:%M:%S)""
        sleep 14400
      done
      "
    environment:
      MYSQLDB_USER: ${MYSQLDB_USER}
      MYSQLDB_ROOT_PASSWORD: ${MYSQLDB_ROOT_PASSWORD}
      MYSQLDB_DATABASE: ${MYSQLDB_DATABASE}
      TZ: Asia/Seoul
    networks:
      mm-network:

volumes:
  mysqldb-volume:

networks:
  mm-network:
    driver: bridge

 

 

위 설정으로 Docker Compose를 실행하면 마주하는 MySQL과 Spring과의 연결 에러가 나타난다. 최초에는 어떤 작업을 해줘야 하냐면 MySQL 유저를 생성하고 내가 연결하려는 데이터베이스에 접근 권한을 허용해야 한다.

 

다음은 모든 외부 접근을 허용하게 하는 유저를 만드는 것이다. 사실 좋은 방법은 아니다. 정확히 어디서 접근할지 판단 후 그 IP만 허용해주는게 더 좋은 방식일 것.

create user 'username'@'%' identified by 'password';

grant all privileges on dbname.* TO 'username'@'%';

flush privileges;

 

이렇게 유저를 만들면 이제 해당 유저를 통해 스프링에서 데이터베이스로 접근할 수 있게 된다.

 

다음은, 가끔 이상한 MySQL 에러가 발생하는데 이러한 에러가 그 경우 중 하나다.

java.sql.SQLException: Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8mb4_general_ci,COERCIBLE) for operation '='

 

이건 이제 테이블 별로 인코딩이 서로 다르기 때문에 발생하는 에러라고 하는데 이를 해결하는 방법은 인코딩을 설정해주는 것.

SET collation_connection = 'utf8_general_ci';

ALTER DATABASE your_database_name CHARACTER SET utf8 COLLATE utf8_general_ci;

ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;

 

마지막 테이블에 적용하는 건 테이블 전체에 해줘야 한다.

728x90
반응형
LIST
728x90
반응형
SMALL
SMALL

작업 공간의 JDK과 서버의 JDK가 서로 달라서 빌드 시 문제가 발생했다. 

작업했던 공간의 JDK는 21, 서버의 JDK는 17을 사용중이었고 그러다보니 Gradle로 빌드 시 빌드 호환 문제로 빌드가 안된다.

 

이럴 땐, build.gradle 파일과 같은 경로에 gradle.properties 파일을 만들고 이 파일에 다음 라인을 추가한다.

org.gradle.java.home=/home/app/mm/jdk-21.0.2

 

JAVA_HOME 경로를 이 프로젝트 한정 변경하는 방법. JDK 21을 설치한 경로는 위 경로와 같다.

이렇게 환경변수로 JAVA_HOME을 설정해놓은 것을 변경하지 않고 프로젝트 별로 JAVA_HOME을 지정할 수 있다.

728x90
반응형
LIST
728x90
반응형
SMALL
반응형
SMALL

 

Spring Boot + Spring Data JPA + Hibernate + PostgreSQL + Docker를 이용해서 프로젝트를 진행하고 있는데, 지속적으로 내 데이터베이스가 사라지는 현상이 나타났다.

 

처음에는 원인을 DB 과부하라고 생각했어서 쿼리 튜닝부터 커넥션 수 변경, 커넥션 지속 시간 변경, 커넥션 타임아웃 시간 변경, 간헐적으로 시간이 오래 걸릴 가능성이 있는 서비스 로직과 트랜잭션 분리 등 정말 갖가지 방법을 동원해서 유지보수를 진행했는데도 터진다.. 

 

데이터베이스가 그렇다고 무거운것도 아니다.. 기껏해봐야 데이터베이스 덤프 사이즈는255.4K..

아무래도 이건 다른 원인이 있을까 싶어 구글링부터 ChatGPT, Postgresql 매뉴얼까지 검토를 했는데 한가지 의심가는 문구를 봤다.

Postgres database getting hacked multi times.
How To Secure PostgreSQL Against Automated Attacks
 

 

설마라고 생각을 하면서도 당연하게 그럴 수 있다는 사실을 간과하고 있었던거 같은데 우선은 postgresql 로그를 찾아봤다.

그런데 이게 뭐지? 알수도 없는 이름의 유저로 접근하려는 로그가 계속 찍히고 있었다.

2023-12-04 13:17:37.490 KST [73] DETAIL:  Role "q" does not exist.
        Connection matched pg_hba.conf line 136: "host all all all md5"
2023-12-04 13:21:27.365 KST [22] LOG:  could not parse file name "pg_logical/snapshots/cpu_hu"
2023-12-04 13:22:22.404 KST [112] FATAL:  password authentication failed for user "mc"
2023-12-04 13:22:22.404 KST [112] DETAIL:  Role "mc" does not exist.
        Connection matched pg_hba.conf line 136: "host all all all md5"
2023-12-04 13:26:27.672 KST [22] LOG:  could not parse file name "pg_logical/snapshots/cpu_hu"
2023-12-04 13:27:02.437 KST [138] FATAL:  password authentication failed for user "e"
2023-12-04 13:27:02.437 KST [138] DETAIL:  Role "e" does not exist.
        Connection matched pg_hba.conf line 136: "host all all all md5"
2023-12-04 13:28:27.259 KST [147] FATAL:  pg_hba.conf rejects connection for host "78.153.140.30", user "postgres", database "postgres", SSL off
2023-12-04 13:31:44.040 KST [165] FATAL:  password authentication failed for user "tecnico"
2023-12-04 13:31:44.040 KST [165] DETAIL:  Role "tecnico" does not exist.
        Connection matched pg_hba.conf line 136: "host all all all md5"
2023-12-04 13:36:28.199 KST [190] FATAL:  password authentication failed for user "eshop"
2023-12-04 13:36:28.199 KST [190] DETAIL:  Role "eshop" does not exist.
        Connection matched pg_hba.conf line 136: "host all all all md5"
2023-12-04 13:41:08.902 KST [215] FATAL:  password authentication failed for user "ricardo"
2023-12-04 13:41:08.902 KST [215] DETAIL:  Role "ricardo" does not exist.
        Connection matched pg_hba.conf line 136: "host all all all md5"
2023-12-04 13:45:50.217 KST [240] FATAL:  password authentication failed for user "marc"
2023-12-04 13:45:50.217 KST [240] DETAIL:  Role "marc" does not exist.
        Connection matched pg_hba.conf line 136: "host all all all md5"
2023-12-04 13:50:33.655 KST [294] FATAL:  password authentication failed for user "admin01"
2023-12-04 13:50:33.655 KST [294] DETAIL:  Role "admin01" does not exist.
        Connection matched pg_hba.conf line 136: "host all all all md5"
2023-12-04 13:55:17.143 KST [319] FATAL:  password authentication failed for user "project"
2023-12-04 13:55:17.143 KST [319] DETAIL:  Role "project" does not exist.
        Connection matched pg_hba.conf line 136: "host all all all md5"
2023-12-04 13:59:57.796 KST [343] FATAL:  password authentication failed for user "biblioteca"
2023-12-04 13:59:57.796 KST [343] DETAIL:  Role "biblioteca" does not exist.
        Connection matched pg_hba.conf line 136: "host all all all md5"
2023-12-04 14:04:38.642 KST [368] FATAL:  password authentication failed for user "anonymous"
2023-12-04 14:04:38.642 KST [368] DETAIL:  Role "anonymous" does not exist.
        Connection matched pg_hba.conf line 136: "host all all all md5"
2023-12-04 14:09:22.720 KST [394] FATAL:  password authentication failed for user "auditor"
2023-12-04 14:09:22.720 KST [394] DETAIL:  Role "auditor" does not exist.
        Connection matched pg_hba.conf line 136: "host all all all md5"
2023-12-04 14:14:07.191 KST [420] FATAL:  password authentication failed for user "bill"
2023-12-04 14:14:07.191 KST [420] DETAIL:  Role "bill" does not exist.
        Connection matched pg_hba.conf line 136: "host all all all md5"
2023-12-04 14:18:49.173 KST [473] FATAL:  password authentication failed for user "devops"
2023-12-04 14:18:49.173 KST [473] DETAIL:  Role "devops" does not exist.
        Connection matched pg_hba.conf line 136: "host all all all md5"
2023-12-04 14:21:28.269 KST [22] LOG:  could not parse file name "pg_logical/snapshots/cpu_hu"
2023-12-04 14:21:33.406 KST [495] FATAL:  password authentication failed for user "postgres"
2023-12-04 14:21:33.406 KST [495] DETAIL:  Password does not match for user "postgres".
        Connection matched pg_hba.conf line 136: "host all all all md5"

....

 

내가 근데 외부 접근 가능 Address를 all로 하고 있었나? 싶어서 pg_hba.conf 파일을 열어보았다.

그런데 실제로 host all all all md5로 설정이 되어있었다. 아마 내가 dev 환경에서 컨테이너를 띄워 작업하는 중에 이렇게 설정을 해두고 바꾸지 않았나보다..

 

 

아차 싶었다. 우선 가장 빠르게 한 작업은 Docker Compose로 애플리케이션 서버, 디비 서버, 디비 백업 서버를 띄울 때 네트워크를 붙였다. 그리고 딱 세개의 네트워크만 접근 허용을 가능하도록 pg_hba.conf 파일을 변경했다.

 

이제 다른 Address에서 접속하더라도 Reject된다. 이 나쁜 놈들.

 

그리고 한가지 더 변경해줄 사항이 있다. postgresql.conf 파일에 'CONNECTIONS AND AUTHENTICATION' 섹션이 있다.

그 부분에서 listen_addresses = "애플리케이션 컨테이너 ip, 디비 컨테이너 ip, 디비 백업 컨테이너 ip" 로 설정해줘야 한다.

 

 

이제 내가 열어둔 주소가 아닌 주소는 모든지 다 들어올 수 없다. 이렇게 하고 나서 데이터베이스가 아직까지 터지지 않고 있다.. 진짜 해킹인가..? 

 

2023-12-11
이 글을 작성하고 현재 2023-12-11 여전히 데이터베이스는 멀쩡히 살아있다.. 진짜 해킹이었고 어마무시하게 자동화된 해킹 공격을 하더라..

 

2023-12-14
이 글을 작성하고 현재 2023-12-14 여전히 멀쩡히 살아있다. 확실하다.
728x90
반응형
LIST
728x90
반응형
SMALL
반응형
SMALL

결국은 한번 만나버린 OutofMemoryError.

회사에서 자바로 플러그인 개발을 하고 사용을 쭉 하다가 이런 에러가 생겼다.

 

우선, 어떻게 해결할지 난감해서 구글링을 계속 하면서 해결해보고자 했는데 아무리 해도 안된다.

처음 해본 방법은 다음과 같이 실행 명령어에 최대 크기를 늘리는것.

mvn clean package -DskipTests -DactivatedProperties=prod -Dspring-boot.run.jvmArguments="-Xmx8192m"

 

그러나 해결되지 않았다. 왜 해결되지 않는지 모르겠는데 왜 해결되지 않는지 구글링을 해보니 이러이러한 이유가 있다고 한다.

애플리케이션 실행에만 영향을 주는 옵션, 이 애플리케이션을 구동하는 JVM 자체에는 영향을 주지 않는다. (JVM의 최대 크기가 이것보다 작기 때문에 의미가 없다)

 

이 말은, 결국 JVM의 최대 크기 자체를 늘려야 한다는 것인데.. 어떻게 해야하나 ? 다시 검색 ! 

"export JAVA_OPTS="-Xmx512m"
 "export CATALINA_OPTS=-Xmx512m"

 

이 방법도 실패. 이유는 모든 JVM이 이를 인지하는 것이 아니라는 가능성.

 

마지막 방법을 찾았다. 내 경우에는 CentOS 배포판으로 된 Linux 서버에 올려놓은 플러그인이고 여기서 JVM 최대 Heap Size를 늘리는 방법은 /etc/profile에 맨 위에(어디에든 상관없긴 하다만) 다음과 같이 설정을 하면 된다.

export _JAVA_OPTIONS=-Xmx6g

 

그 후 파일 변경을 적용하기 위해 다음 명령어를 실행

source /etc/profile

 

그럼 적용한 값을 확인할 수 있는데 다음 명령어로 확인해보자.

java -XshowSettings:vm

 

다음과 같은 화면을 볼 수 있다. 내가 적용한 설정값이 반영된 상태로 Max Heap Size가 적용됐다. 

 

 

그런데, 나는 Docker Container 환경에서 서버를 구동중이다.. 그러니까 내 Linux 서버에서 JVM heap size를 늘리나 마나 아무런 의미가 없다. 그래서 만약 Container의 JVM heap size를 늘리고 싶으면 !

 

docker compose를 사용할 때와 이미지를 가지고 실행하는 경우 두 가지 방법이 있다.

나 같은 경우 docker compose를 사용하는데 그럴 경우에는 이렇게 적용하면 된다.

 

docker-compose.yml

environment:
	- _JAVA_OPTIONS=-Xmx8g

 

(tomcat) image를 가지고 컨테이너를 실행하는 경우 (이미지는 원하는 대로)

docker run -e JAVA_OPTS='-Xmx1g' tomcat

 

 

728x90
반응형
LIST
728x90
반응형
SMALL

 

서버에 Docker를 사용해서 Containerized app을 실행중이었는데, 어떤 이유에선지 실행중인 컨테이너가 다 내려가는 이상한 일이 발생했다. 그래서 다시 컨테이너를 마운트하는데 내가 사용하려는 포트를 이미 사용중이라고 나온다.

6e4b0ce8199e3364a9a979e07a611ae912aa0cad06fac0508d2c32df8a4a83d7
docker: Error response from daemon: driver failed programming external connectivity on endpoint katech-web (e2869131fb101ad044163633db6a1f72a8057a6bb39f9e42ce2f6684f1ac0cf3): Error starting userland proxy: listen tcp4 0.0.0.0:8824: bind: address already in use.

 

뭐지 싶어서 프로세스를 다 띄워 봤다.

❯ netstat -lntp                                                                                                                                                                                                                            ─╯
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 192.168.0.2:9000        0.0.0.0:*               LISTEN      4177698/java
tcp        0      0 192.168.0.2:9870        0.0.0.0:*               LISTEN      4177698/java
tcp        0      0 0.0.0.0:8824            0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:8829            0.0.0.0:*               LISTEN      968191/python3
tcp        0      0 0.0.0.0:8822            0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:8820            0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:44053         0.0.0.0:*               LISTEN      3623312/node
tcp        0      0 0.0.0.0:8088            0.0.0.0:*               LISTEN      4178189/java
tcp        0      0 0.0.0.0:8032            0.0.0.0:*               LISTEN      4178189/java
tcp        0      0 0.0.0.0:8033            0.0.0.0:*               LISTEN      4178189/java
tcp        0      0 0.0.0.0:8030            0.0.0.0:*               LISTEN      4178189/java
tcp        0      0 0.0.0.0:8031            0.0.0.0:*               LISTEN      4178189/java
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:45927         0.0.0.0:*               LISTEN      2354740/node
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:2306            0.0.0.0:*               LISTEN      -
tcp6       0      0 :::8824                 :::*                    LISTEN      -
tcp6       0      0 :::8822                 :::*                    LISTEN      -
tcp6       0      0 :::8820                 :::*                    LISTEN      -
tcp6       0      0 :::80                   :::*                    LISTEN      -
tcp6       0      0 :::22                   :::*                    LISTEN      -
tcp6       0      0 :::3306                 :::*                    LISTEN      -
tcp6       0      0 :::2375                 :::*                    LISTEN      -
tcp6       0      0 :::2306                 :::*                    LISTEN      -

8824를 LISTEN중이라는데 PID가 없다. 뭐지? 종료하고 싶은데..

이럴 땐, sudo를 사용해야했다.

sudo netstat -antlp | grep 8824

tcp        0      0 0.0.0.0:8824            0.0.0.0:*               LISTEN      2519703/docker-prox
tcp6       0      0 :::8824                 :::*                    LISTEN      2519715/docker-prox

pID가 다 보이고 KILL 성공

 

반응형
SMALL
728x90
반응형
LIST
728x90
반응형
SMALL
반응형
SMALL

이제 H2 Database가 버전이 올라가면서 데이터베이스가 없는 경우 자동으로 데이터베이스를 만들어주지 않는다.

그래서 콘솔에서 다음과 같은 에러를 볼 수 있다.

정말 간단하게 해결할 수 있는데, 우선 데이터베이스를 만들고자하는 경로는 나같은 경우 다음과 같다.

"~/h2/test" 이 경로에 "test"라는 데이터베이스를 만들거면 해당 경로에 이런 파일 하나를 만들어주면 된다.

"test.mv.db"

// ~/h2
touch test.mv.db

 

그러고 다시 Connect를 해보면 정상적으로 데이터베이스 접근할 수 있다. 

 

728x90
반응형
LIST
728x90
반응형
SMALL
반응형
SMALL

회사에서 새로운 프로젝트를 진행할 때 이번엔 Maven말고 Gradle을 사용해보고 싶어서 로컬에서는 아무 문제가 없었는데 물리서버에 코드를 옮기고 빌드할 때 이러한 에러가 발생했다.

java.lang.UnsupportedClassVersionError:  
org/springframework/boot/gradle/plugin/SpringBootPlugin 
has been compiled by a more recent version of the Java Runtime (class file version 61.0),
this version of the Java Runtime only recognizes class file versions up to 52.0

이 에러 내용만을 읽어봤을 땐 현재 사용하는 JRE가 클래스 파일의 버전 52까지만 수용할 수 있는듯하고 이 경로 org/springframework/boot/gradle/plugin/SpringBootPlugin의 클래스 파일의 버전은 61이라 버전 미스매치가 된 것 같다.

 

해결하는 방법은 그냥 현재 물리서버에서 사용중인 JRE 버전이 로컬에서 사용한 JRE 버전보다 낮고 허용가능한 범위를 벗어났으니 JRE 버전을 높이면 된다. 아래는 클래스 파일의 버전과 호환 가능한 JRE 버전이다.

49 = Java 5
50 = Java 6
51 = Java 7
52 = Java 8
53 = Java 9
54 = Java 10
55 = Java 11
56 = Java 12
57 = Java 13
58 = Java 14
59 = Java 15
60 = Java 16
61 = Java 17
62 = Java 18
63 = Java 19
64 = Java 20
65 = Java 21

 

 

728x90
반응형
LIST
728x90
반응형
SMALL
반응형
SMALL

회사 JIRA, Confluence 서비스를 관리하고 있는데 어느날 서버가 내려가 있길래 확인해보니 이런 에러가 발생했었다.

No space left on device: AH00023 ...(생략)

일단 여유 공간이 없다는 에러인 거 같은데 왜?

 

우선 아래 명령어로 상태를 확인해봤다.

systemctl status httpd.service

별 내용 없고 아래 명령어를 실행해봐도 별 내용이 없었다.

journalctl -xe

 

일단 httpd.conf 파일에 Syntax 문제가 없는지 확인을 하기 위해 다음 명령어를 실행했다.

apachectl configtest

문제가 없다면 Syntax OK라는 결과가 나와야한다. 당연히 나온다. 파일 수정은 내가 안했으니까.

 

 

이럴 땐 아파치 로그를 봐야한다. 나 같은 경우 로그 경로는 아래와 같다.

/var/log/httpd/error_log

여기서 이제 이 페이지의 에러 내용인 아래 내용이 나왔다.

No space left on device: AH00023 ...(생략)

 

뭔지 알아내기 위해 또 서치!

결과는 다음과 같다:

"Semaphore"라는 프로세스가 생성되었다가 없어지지 않아서...?

엄밀히 말하면, "Semaphore" 프로세스 생성 가능한 숫자를 이미 초과해서(No space left on device)

apache(httpd)가 시작시 새로운 "Semaphore"를 생성하지 못하면서 apache(httpd) 실행이 안된다고 한다.

이건, "Semaphore"가 아파치의 여러 프로세스간 데이타 동기화를 위해 필요한데..

apache(httpd)가 비정상적으로 종료될때 이미 생성된 "Semaphore"를 초기화 되지 못해 그렇다고 한다.

 

그래서 해당 프로세스가 얼마나 있는지 다음 명령어로 확인을 해보자.

ipcs -s | wc -l

132개가 있다고 한다. 

 

이거 최대 가능 수를 확인해보자.

ipcs -ls

최대 128개가 가능하다고 나온다. 그래서 안되는건가 보다.

그래서 현재 생성되어 있는 걸 다 죽여버렸다. 

ipcrm -a

다시 몇 개 있는지 확인!

ipcs -s | wc -l

4개가 있다고 나온다.

 

아파치를 다시 실행해보니 정상적으로 실행됐다. 어렵다 ..

728x90
반응형
LIST
728x90
반응형
SMALL
반응형
SMALL

Typescript를 사용하여 개발 중 아래 에러를 만났다.

SyntaxError: Cannot use import statement outside a module
    at internalCompileFunction (node:internal/vm:73:18)
    at wrapSafe (node:internal/modules/cjs/loader:1178:20)
    at Module._compile (node:internal/modules/cjs/loader:1220:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1310:10)
    at Module.load (node:internal/modules/cjs/loader:1119:32)
    at Module._load (node:internal/modules/cjs/loader:960:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:86:12)
    at node:internal/main/run_main_module:23:47

 

뭔지는 당연히 몰랐기에 구글링 시도!

우선 require로 패키지를 가져오지 않고 import를 사용하니 이런 에러를 마주했는데, package.json 파일에서 "type": "module"을 추가하면 해결할 수 있다고 한다. 추가한 후 다시 실행하니 다른 에러가 발생한다.

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/cw.choiit/mongo/tutorial/src/api/client.ts
    at new NodeError (node:internal/errors:405:5)
    at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:79:11)
    at defaultGetFormat (node:internal/modules/esm/get_format:124:36)
    at defaultLoad (node:internal/modules/esm/load:89:20)
    at nextLoad (node:internal/modules/esm/loader:163:28)
    at ESMLoader.load (node:internal/modules/esm/loader:603:26)
    at ESMLoader.moduleProvider (node:internal/modules/esm/loader:457:22)
    at new ModuleJob (node:internal/modules/esm/module_job:64:26)
    at ESMLoader.#createModuleJob (node:internal/modules/esm/loader:480:17)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:434:34) {
   code: 'ERR_UNKNOWN_FILE_EXTENSION'
  }

.ts 파일을 못 읽는 것 같은데 역시 뭔지 모르니 다시 서치!

Typescript를 사용하고 있고, ts-node로 typescript 파일을 실행하기 위해서 tsconfig.json 파일을 수정해야 한다.

compilerOptions의 module을 commonjs로 target을 es2016으로 설정하고 다음과 같이 ts-node의 esm을 true로 설정한다.

 

하고 나서 다시 실행하니 또 다른 에러.. 에러 지옥에 갇혔지만 끝까지 가면 내가 다 이긴다.

ReferenceError: exports is not defined in ES module scope
    at file:///Users/cw.choiit/mongo/tutorial/src/api/client.ts:14:23
    at ModuleJob.run (node:internal/modules/esm/module_job:194:25)

이건 알 거 같다. 제일 처음 package.json 파일에서 "type": "module"을 추가했는데 저 부분을 다시 지워야 할 것 같다.

그래서 package.json 파일에서 "type": "module"을 지우고 아래와 같은 package.json 파일로 저장했다.

 

마침내 정상 실행이 됐다. 

 

 

정리를 하자면

 

1. Typescript를 사용 중이라면 tsconfig.json에서 다음과 같은 설정이 필요

"compilerOptions": {
	"target": "es2016",
    "module": "commonjs"
},
"ts-node": {
	"esm": true
}

 

728x90
반응형
LIST

+ Recent posts