IT STUDY LOG
Sprint - 로그 파이프라인 본문
#최소 요구 사항 (Bare minimum requirements)
스프린트 안내
- nginx 웹 서버의 로그로부터 접속 기록을 추출하여, PostgreSQL에 적재
스프린트를 진행하기 전에 먼저 연습할 내용
- PostgreSQL 데이터베이스를 생성하고, SQL문을 이용해 데이터를 넣고, 넣은 결과를 확인합니다.
# os에 설치된 패키지 최신화(업데이트 및 업그레이드)
sudo apt update
# 파일 리포지토리 구성
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
# 저장소 서명키 가져오기
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
# apt 업데이트
sudo apt-get update
# 최신 postgreSQL 설치
sudo apt-get -y install postgresql
# postgre 정상 설치 확인
# 프로세스 확인
$ ps -ef | grep post
postgres 6451 1 0 10:38 ? 00:00:00 /usr/lib/postgresql/15/bin/postgres -D /var/lib/postgresql/15/main -c config_file=/etc/postgresql/15/main/postgresql.conf
postgres 6452 6451 0 10:38 ? 00:00:00 postgres: 15/main: checkpointer
postgres 6453 6451 0 10:38 ? 00:00:00 postgres: 15/main: background writer
postgres 6455 6451 0 10:38 ? 00:00:00 postgres: 15/main: walwriter
postgres 6456 6451 0 10:38 ? 00:00:00 postgres: 15/main: autovacuum launcher
postgres 6457 6451 0 10:38 ? 00:00:00 postgres: 15/main: logical replication launcher
# 서비스 소켓 정보 확인
$ sudo netstat -antp | grep "post"
tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN 8615/postgres
# 서비스 확인
$ sudo service postgresql status
● postgresql.service - PostgreSQL RDBMS
Loaded: loaded (/lib/systemd/system/postgresql.service; enabled; vendor preset: enabled)
Active: active (exited) since Thu 2023-03-30 10:41:05 KST; 5min ago
Main PID: 8632 (code=exited, status=0/SUCCESS)
Tasks: 0 (limit: 4613)
Memory: 0B
CGroup: /system.slice/postgresql.service
3월 30 10:41:05 devops systemd[1]: Starting PostgreSQL RDBMS...
3월 30 10:41:05 devops systemd[1]: Finished PostgreSQL RDBMS.
# postgresql 버전 확인
$ psql --version
psql (PostgreSQL) 15.2 (Ubuntu 15.2-1.pgdg20.04+1)
2. ubuntu에서 postgresql 계정 접속
# -i : 로그인 옵션 / -u : user 옵션
$ sudo -i -u postgres
# 계정 로그인 후 PostgreSQL에 접속
$ psql
psql (15.2 (Ubuntu 15.2-1.pgdg20.04+1))
도움말을 보려면 "help"를 입력하십시오.
# 서비스에서 나오려면 \q 입력 후 개행
3. 관리상의 편리함을 위해 pgadmin4 설치
##### 레파지토리 설정 #####
# 레파지토리를 위한 공개키 설치(이전에 공개키를 설치하지 않았다면)
curl -fsS https://www.pgadmin.org/static/packages_pgadmin_org.pub | sudo gpg --dearmor -o /usr/share/keyrings/packages-pgadmin-org.gpg
# 레파지토리 설정 파일 생성
sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/packages-pgadmin-org.gpg] https://ftp.postgresql.org/pub/pgadmin/pgadmin4/apt/$(lsb_release -cs) pgadmin4 main" > /etc/apt/sources.list.d/pgadmin4.list && apt update'
##### pgAdmin 설치 #####
# 데스크롭 및 웹 모드 모두 설치하는 경우
sudo apt install pgadmin4
# 데스크톱 모드만 설치하는 경우
sudo apt install pgadmin4-desktop
# 웹 모드만 설치하는 경우
sudo apt install pgadmin4-web
# 웹 모드를 설치했을 경우 웹서버 설정
sudo /usr/pgadmin4/bin/setup-web.sh
4. pgadmin4 접속
- 브라우저에서 http://localhost/pgadmin4 입력
5. Ubuntu에서 postgresql 사용자 및 데이터베이스 생성
# 유저 생성 후 조회
postgres=# create role roheerumi superuser;
CREATE ROLE
postgres=# \du
롤 목록
롤 이름 | 속성 | 소속 그룹:
-----------+------------------------------------------------+------------
postgres | 슈퍼유저, 롤 만들기, DB 만들기, 복제, RLS 통과 | {}
roheerumi | 슈퍼유저, 로그인할 수 없음 | {}
# DB 생성 및 조회
postgres=# create database devops;
CREATE DATABASE
postgres=# \l
# 생성한 DB에 접속해 테이블 생성 및 조회
postgres=# \c devops
접속정보: 데이터베이스="devops", 사용자="postgres".
devops=# create table devops_test_01 (id int primary key, content varchar);
CREATE TABLE
devops=# \dt
릴레이션(relation) 목록
스키마 | 이름 | 종류 | 소유주
--------+----------------+--------+----------
public | devops_test_01 | 테이블 | postgres
(1개 행)
6. pgadmin 에서 ubuntu 서버와 연결
7. ubuntu postgresql에서 insert
devops=# insert into devops_test_01(id, content) values (2, 'miruheero');
INSERT 0 1
devops=# insert into devops_test_01(id, content) values (3, 'test');
INSERT 0 1
devops=# select * from devops_test_01 ;
id | content
----+-----------
1 | roheerumi
2 | miruheero
3 | test
(3개 행)
8. ubuntu postgresql에서 update
devops=# update devops_test_01 set content = 'retest' where id = 3;
UPDATE 1
devops=# select * from devops_test_01 ;
id | content
----+-----------
1 | roheerumi
2 | miruheero
3 | retest
(3개 행)
9. ubuntu postgresql에서 delete
devops=# delete from devops_test_01 where id = 3;
DELETE 1
devops=# select * from devops_test_01 ;
id | content
----+-----------
1 | roheerumi
2 | miruheero
(2개 행)
10. pgadmin4에서 insert
- table 명 우클릭 -> view/edit data -> All rows로 아래 화면 진입
스프린트의 순서
1. nginx 웹 서버의 로그를 확인합니다.
2. 프로그래밍 언어를 이용해 로그로부터 유의미한 데이터를 추출하여, 각 필드를 구분합니다. (변환)
> 이 프로그램을 파서(parser)라 지칭하겠습니다.
3. PostgreSQL 데이터베이스 내에 로그를 적재할 테이블을 만듭니다.
4. 프로그래밍 언어를 이용해 PostgreSQL에 접근하고, 데이터를 넣는 프로그램을 만듭니다. (적재)
> 이 프로그램을 수집기(collector)라 지칭하겠습니다.
5. 로그를 추출하고, 파서를 이용해 변환하고, 수집기를 이용해 PostgreSQL에 적재합니다.
#해결 과제
💻 웹 서버에 접속 이벤트를 발생시키고, 로깅이 되는지 확인합니다.
💻 파서를 직접 작성합니다.
💻 데이터 웨어하우스에 로그를 적재할 공간을 준비합니다.
💻 수집기를 직접 작성하여, 데이터 웨어하우스에 로그를 쌓을 수 있도록 합니다.
💻 파이프라인으로 연결하여 스트리밍 되는 로그를 추출/변환/적재합니다.
#실습 자료
#과제 항목별 진행 상황
💡1. nginx 로그 분석
# 리눅스는 데몬 로그를 /var/log 디렉토리에 기록
# nginx 데몬 로그는 /var/log/nginx에 존재하며 access.log와 error.log가 있음
# access.log를 실시간으로 모니터링
$ tail -F access.log
# nginx 웹서버가 떠있는 호스트 주소로 접속
127.0.0.1 - - [30/Mar/2023:13:24:56 +0900] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
127.0.0.1 - - [30/Mar/2023:13:24:56 +0900] "GET /static/css/main.dec85a0c.css HTTP/1.1" 304 0 "<http://localhost:10024/>" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
127.0.0.1 - - [30/Mar/2023:13:24:56 +0900] "GET /static/js/main.0d51c5de.js HTTP/1.1" 304 0 "<http://localhost:10024/>" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
127.0.0.1 - - [30/Mar/2023:13:24:59 +0900] "GET /logo.svg HTTP/1.1" 304 0 "<http://localhost:10024/>" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
127.0.0.1 - - [30/Mar/2023:13:25:00 +0900] "GET /manifest.json HTTP/1.1" 304 0 "<http://localhost:10024/>" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
여기엔 어떤 정보들이 담겨있나요?
- $remote_addr 127.0.0.1 - 요청을 하는 클라이언트의 IP 주소
- $remote_user - - - HTTP 인증 사용자입니다. 사용자 이름이 설정되지 않은 경우 이 필드에는 -가 표시
- [$time_local] - [30/Mar/2023:13:25:00 +0900]- 로컬 서버 시간
- "$request" - "GET /manifest.json HTTP/1.1" - 요청 유형, 경로 및 프로토콜
- $status - 304 - 서버 응답 코드
- $body_bytes_sent - 0 - 서버 응답 크기(바이트)
- "$http_referer" - "http://localhost:10024/" - 조회 URL
- "$http_user_agent" - Mozilla/5.0 ... - 클라이언트의 사용자 에이전트(웹 브라우저)
.
💡 2. 파서(parser) 작성
// parser.js
const dayjs = require('dayjs')
const customParseFormat = require('dayjs/plugin/customParseFormat')
dayjs.extend(customParseFormat)
process.stdin.on("data", data => {
let raw = data.toString()
let regex = /\\[(.+)\\]/g
let match = regex.exec(raw)[1]
let timestamp = dayjs(match, 'DD/MMM/YYYY:hh:mm:ss +ZZ').toISOString()
let info = raw.split(" ");
let source_ip = info[0]
let method = info[5].replace("\\"", "") // 'POST'
let status_code =info[8] // 404
let path =info[6] // '/replace-me'
let jsonString = `
{
"source_ip": "${source_ip}",
"method": "${method}",
"status_code": ${status_code},
"path": "${path}",
"timestamp": "${timestamp}"
}`
process.stdout.write(jsonString)
})
# 실행 결과물
$ cat sample.log | ./parser.js
{
"source_ip": "10.0.210.17",
"method": "GET",
"status_code": 200,
"path": "/hello",
"timestamp": "2022-11-28T02:33:28.000Z"
}
💡 3. 데이터 웨어하우스 준비
1. ElephantSQL 회원가입
2. 로그인
3. 팀 만들기
4.Create New Instance 데이터베이스 인스턴스를 생성, 인스턴스 이름을 클릭하면 상세 정보 출력
💡 4. 데이터베이스 연결 테스트
- vim.env : 환경변수 설정, 데이터베이스 정보 설정
HOSTNAME=<호스트 이름>
USERNAME=<아이디>
PASSWORD=<비밀번호>
DATABASE=<데이터베이스 이름>
- ./sql-runner.js < sql/1_reset.sql (관리자 권한으로 동작함) : 테이블 삭제 후 생성
$ sudo ./sql-runner.js < ./sql/1_reset.sql
DROP TABLE IF EXISTS public.nginx;
CREATE TABLE public.nginx (
id serial4 NOT NULL,
source_ip varchar NULL,
"method" varchar NULL,
status_code varchar NULL,
"path" varchar NULL,
"timestamp" timestamptz NULL,
CONSTRAINT nginx_pk PRIMARY KEY (id)
);
undefined
데이터베이스 연결 닫는 중...
데이터베이스 연결 종료
- ./sql-runner.js < sql/2_describe_table.sql : 테이블 정보 확인
$ sudo ./sql-runner.js < sql/2_describe_table.sql
SELECT column_name, udt_name, is_nullable FROM information_schema.columns WHERE table_name = 'nginx'
┌─────────┬───────────────┬───────────────┬─────────────┐
│ (index) │ column_name │ udt_name │ is_nullable │
├─────────┼───────────────┼───────────────┼─────────────┤
│ 0 │ 'id' │ 'int4' │ 'NO' │
│ 1 │ 'timestamp' │ 'timestamptz' │ 'YES' │
│ 2 │ 'source_ip' │ 'varchar' │ 'YES' │
│ 3 │ 'method' │ 'varchar' │ 'YES' │
│ 4 │ 'status_code' │ 'varchar' │ 'YES' │
│ 5 │ 'path' │ 'varchar' │ 'YES' │
└─────────┴───────────────┴───────────────┴─────────────┘
데이터베이스 연결 닫는 중...
데이터베이스 연결 종료
💡 5. 수집기(collector) 작성
./sql-runner.js < sql/3_display_table_data.sql : 테이블 데이터 확인
$ sudo ./sql-runner.js < ./sql/3_display_table_data.sql
SELECT * FROM nginx;
┌─────────┐
│ (index) │
├─────────┤
└─────────┘
데이터베이스 연결 닫는 중...
데이터베이스 연결 종료
- cat sample.json | ./collector.js : sample.json의 데이터를 테이블에 입력
$ cat sample.json | sudo ./collector.js
{ source_ip: '127.0.0.1',
method: 'POST',
status_code: 404,
path: '/replace-me',
timestamp: '2022-11-28T02:33:28.000Z' }
INSERT INTO public.nginx (source_ip, method, status_code, path, timestamp)
VALUES (
'127.0.0.1', 'POST', '404', '/replace-me', to_timestamp('2022-11-28T02:33:28.000Z', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')
);
{ source_ip: '1.0.0.1',
method: 'POST',
status_code: 404,
path: '/replace-me',
timestamp: '2022-11-28T02:33:28.000Z' }
INSERT INTO public.nginx (source_ip, method, status_code, path, timestamp)
VALUES (
'1.0.0.1', 'POST', '404', '/replace-me', to_timestamp('2022-11-28T02:33:28.000Z', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')
);
{ source_ip: '127.0.0.1',
method: 'POST',
status_code: 404,
path: '/replace-me',
timestamp: '2022-11-28T02:33:28.000Z' }
INSERT INTO public.nginx (source_ip, method, status_code, path, timestamp)
VALUES (
'127.0.0.1', 'POST', '404', '/replace-me', to_timestamp('2022-11-28T02:33:28.000Z', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')
);
^C
데이터베이스 연결 닫는 중...
데이터베이스 연결 종료
- ./sql-runner.js < sql/3_display_table_data.sql : 테이블 데이터 확인
$ sudo ./sql-runner.js < ./sql/3_display_table_data.sql
SELECT * FROM nginx;
┌─────────┬────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬────────┬─────────────┬───────────────┬──────────────────────────┐
│ (index) │ id │ source_ip │ method │ status_code │ path │ timestamp │
├─────────┼────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────┼─────────────┼───────────────┼──────────────────────────┤
│ 0 │ 1 │ '{"source_ip":"127.0.0.1","method":"POST","status_code":404,"path":"/replace-me","timestamp":"2022-11-28T02:33:28.000Z"}' │ null │ null │ null │ null │
│ 1 │ 2 │ '\n{\n "source_ip": "10.0.210.17",\n "method": "GET",\n "status_code": 200,\n "path": "/hello",\n "timestamp": "2022-11-28T02:33:28.000Z"\n}' │ null │ null │ null │ null │
│ 2 │ 3 │ '127.0.0.1' │ 'POST' │ '404' │ '/replace-me' │ 2022-11-28T02:33:28.000Z │
│ 3 │ 4 │ '10.0.210.17' │ 'GET' │ '200' │ '/hello' │ 2022-11-28T02:33:28.000Z │
│ 4 │ 10 │ '127.0.0.1' │ 'POST' │ '404' │ '/replace-me' │ 2022-11-28T02:33:28.000Z │
│ 5 │ 11 │ '1.0.0.1' │ 'POST' │ '404' │ '/replace-me' │ 2022-11-28T02:33:28.000Z │
│ 6 │ 12 │ '127.0.0.1' │ 'POST' │ '404' │ '/replace-me' │ 2022-11-28T02:33:28.000Z │
└─────────┴────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴────────┴─────────────┴───────────────┴──────────────────────────┘
데이터베이스 연결 닫는 중...
데이터베이스 연결 종료
- collection.js 파일
// sprint-data-pipeline/collector.js
#!/usr/bin/env node
const dotenv = require('dotenv')
const { Client } = require('pg')
dotenv.config()
const { HOSTNAME, USERNAME, PASSWORD, DATABASE } = process.env
const client = new Client({
host: HOSTNAME,
user: USERNAME,
password: PASSWORD,
database: DATABASE
})
client.connect().then(() => {
process.stdin.on("data", async data => {
let raw = data.toString()
let json = JSON.parse(raw)
console.log(json)
console.log(raw)
let queryString = `
INSERT INTO public.nginx (source_ip, method, status_code, path, timestamp)
VALUES (
'${json.source_ip}', '${json.method}', '${json.status_code}', '${json.path}', to_timestamp('${json.timestamp}', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')
);
`
console.log(queryString)
try {
await client.query(queryString)
}
catch(e) {
console.log(e)
}
})
}).catch(err => console.log('연결 오류', err.stack))
// Ctrl+C가 입력되면, 데이터베이스를 닫습니다
process.on('SIGINT', async (sig) => {
console.log('\n데이터베이스 연결 닫는 중...')
await client.end()
console.log('데이터베이스 연결 종료')
process.exit(1)
})
💡 6. 잘못 쌓인 데이터 지우기 (optional)
- sprint-data-pipeline/sql/4_clean_up_table.sql 파일 작성
# sprint-data-pipeline/sql/4_clean_up_table.sql
TRUNCATE table nginx;
- 해당 스크립트 실행 결과
$ sudo ./sql-runner.js < ./sql/4_clean_up_table.sql
-- TODO
TRUNCATE table nginx;
┌─────────┐
│ (index) │
├─────────┤
└─────────┘
데이터베이스 연결 닫는 중...
데이터베이스 연결 종료
💡 7. 파이프라인 완성
- 실시간으로 로그 수집하는 파이프라인 실행
$ tail -F /var/log/nginx/access.log | ./parser.js | sudo ./collector.js
{ source_ip: '::1',
method: 'POST',
status_code: 404,
path: '/pgadmin4/misc/cleanup',
timestamp: '2023-03-30T06:51:32.000Z' }
{
"source_ip": "::1",
"method": "POST",
"status_code": 404,
"path": "/pgadmin4/misc/cleanup",
"timestamp": "2023-03-30T06:51:32.000Z"
}
INSERT INTO public.nginx (source_ip, method, status_code, path, timestamp)
VALUES (
'::1', 'POST', '404', '/pgadmin4/misc/cleanup', to_timestamp('2023-03-30T06:51:32.000Z', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')
);
{ source_ip: '127.0.0.1',
method: 'GET',
status_code: 200,
path: '/',
timestamp: '2023-03-30T07:03:16.000Z' }
{
"source_ip": "127.0.0.1",
"method": "GET",
"status_code": 200,
"path": "/",
"timestamp": "2023-03-30T07:03:16.000Z"
}
INSERT INTO public.nginx (source_ip, method, status_code, path, timestamp)
VALUES (
'127.0.0.1', 'GET', '200', '/', to_timestamp('2023-03-30T07:03:16.000Z', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')
);
# ... 하략 ...
# 로그가 추가되면 계속해서 DB에 입력된다
- 정상적으로 로그가 DB에 입력되었는지 확인 후 로그 파일 생성
$ sudo ./sql-runner.js < ./sql/3_display_table_data.sql > stdout.log
$ cat stdout.log
SELECT * FROM nginx;
┌─────────┬────┬─────────────┬────────┬─────────────┬─────────────────────────────────┬──────────────────────────┐
│ (index) │ id │ source_ip │ method │ status_code │ path │ timestamp │
├─────────┼────┼─────────────┼────────┼─────────────┼─────────────────────────────────┼──────────────────────────┤
│ 0 │ 13 │ '127.0.0.1' │ 'POST' │ '404' │ '/replace-me' │ 2022-11-28T02:33:28.000Z │
│ 1 │ 14 │ '1.0.0.1' │ 'POST' │ '404' │ '/replace-me' │ 2022-11-28T02:33:28.000Z │
│ 2 │ 15 │ '127.0.0.1' │ 'POST' │ '404' │ '/replace-me' │ 2022-11-28T02:33:28.000Z │
│ 3 │ 16 │ '127.0.0.1' │ 'GET' │ '304' │ '/' │ 2023-03-30T06:55:32.000Z │
│ 4 │ 17 │ '127.0.0.1' │ 'GET' │ '304' │ '/' │ 2023-03-30T06:56:24.000Z │
│ 5 │ 18 │ '127.0.0.1' │ 'GET' │ '304' │ '/' │ 2023-03-30T06:56:38.000Z │
│ 6 │ 19 │ '127.0.0.1' │ 'GET' │ '304' │ '/manifest.json' │ 2023-03-30T04:25:00.000Z │
│ 7 │ 20 │ '::1' │ 'POST' │ '404' │ '/pgadmin4/misc/cleanup' │ 2023-03-30T06:51:32.000Z │
│ 8 │ 21 │ '127.0.0.1' │ 'GET' │ '200' │ '/' │ 2023-03-30T07:03:16.000Z │
│ 9 │ 22 │ '127.0.0.1' │ 'GET' │ '200' │ '/static/js/main.0d51c5de.js' │ 2023-03-30T07:03:16.000Z │
│ 10 │ 23 │ '127.0.0.1' │ 'GET' │ '200' │ '/static/css/main.dec85a0c.css' │ 2023-03-30T07:03:16.000Z │
│ 11 │ 24 │ '127.0.0.1' │ 'GET' │ '200' │ '/logo.svg' │ 2023-03-30T07:03:17.000Z │
└─────────┴────┴─────────────┴────────┴─────────────┴─────────────────────────────────┴──────────────────────────┘
데이터베이스 연결 닫는 중...
데이터베이스 연결 종료
💡 8. 제출
$ git add .
$ git commit -m "실시간 로그 수집"
$ git push origin
#TROUBLE SHOOTING LOG
📝 문제 1 : DB와 연결하는 실행파일 기동 시 권한 문제 발생
$ ./sql-runner.js < ./sql/1_reset.sql
연결 오류 error: no pg_hba.conf entry for host "호스트 IP 주소", user "유저명", database "DB명", SSL off
at Parser.parseErrorMessage (/home/roheerumi/devops/database_study/sprint-data-pipeline/node_modules/pg-protocol/dist/parser.js:287:98)
at Parser.handlePacket (/home/roheerumi/devops/database_study/sprint-data-pipeline/node_modules/pg-protocol/dist/parser.js:126:29)
at Parser.parse (/home/roheerumi/devops/database_study/sprint-data-pipeline/node_modules/pg-protocol/dist/parser.js:39:38)
at Socket.<anonymous> (/home/roheerumi/devops/database_study/sprint-data-pipeline/node_modules/pg-protocol/dist/index.js:11:42)
at Socket.emit (node:events:513:28)
at addChunk (node:internal/streams/readable:324:12)
at readableAddChunk (node:internal/streams/readable:297:9)
at Readable.push (node:internal/streams/readable:234:10)
at TCP.onStreamRead (node:internal/stream_base_commons:190:23)
원인
postgresql 환경 파일에 해당 호스트, 해당 사용자명, 해당 DB명으로 접속할 수 있는 엔트리가 없다고 나옴
해결 시도
1) postgresql의 설정 파일(/etc/postgresql/pb_hba.conf, /etc/postgresql/postgresql.conf) 수정
- 해당 방법을 사용할 경우 모든 호스트에서 모든 DB에 접속이 가능하도록 수정하므로 보안상 위험이 있다고 사료됨
2) sudo 권한으로 실행
- 에러 내용을 보면 TCP나 Socket 등의 에러 확인 가능
- 에러가 발생한 js 파일의 경우 외부에 위치한 DB와 connection을 하는 코드가 존재하는데 소켓 연결을 하는 게 일반 유저 권한으로 수행되지 않아서인가? 추측
- sudo 권한으로 실행 시 정상 작동
3) DB 연결 부분 수정
- elephantSQL node.js 연결 방법 도큐먼트 참조해서 실행 시 정상 수행
4) linux 쉘 환경변수와 pg 객체 내용 확인 후 .env 수정
- pg 객체 내용을 콘솔로 찍어보니 user가 elephantSQL user명이 아닌 리눅스 계정명으로 넘어가는 것 확인
Client {
...생략...
connectionParameters: ConnectionParameters {
user: 'roheerumi',
database: '내 db명',
port: 5432,
host: '내 url',
binary: false,
ssl: false,
...생략....
- 리눅스 터미널에서 쉘 환경변수 조회해보니 .env 파일에 환경변수명으로 지정한 USERNAME 변수가 이미 선언되어 있는 것 확인
$ export
# ... 생략 ...
declare -x USER="roheerumi"
declare -x USERNAME="roheerumi"
$ echo USERNAME
roheerumi
- .env 파일과 .js 파일 변수명을 쉘 환경 변수명과 겹치지 않도록 수정하니 정상 연결됨
$ cat .env
ELEPHANT_HOSTNAME=어쩌구.db.elephantsql.com
ELEPHANT_USERNAME=유저명
ELEPHANT_PASSWORD=비밀번호
ELEPHANT_DATABASE=디비명
ELEPHANT_SSL=true
$ cat sql-runner.js
#... 상략 ...
const { ELEPHANT_HOSTNAME, ELEPHANT_USERNAME, ELEPHANT_PASSWORD, ELEPHANT_DATABASE, ELEPHANT_SSL } = process.env
const client = new Client({
host: ELEPHANT_HOSTNAME,
user: ELEPHANT_USERNAME,
password: ELEPHANT_PASSWORD,
database: ELEPHANT_DATABASE,
ssl: ELEPHANT_SSL
})
#... 하략 ...
$ ./sql-runner.js < ./sql/3_display_table_data.sql
Client {
# ... 상략 ....
user: 'elephantuser',
database: 'elephantuser',
port: 5432,
host: 'elephantuser.db.elephantsql.com',
ssl: false,
# ... 하략 ...
}
SELECT * FROM nginx;
┌─────────┬────┬─────────────┬────────┬─────────────┬─────────────────────────────────┬──────────────────────────┐
│ (index) │ id │ source_ip │ method │ status_code │ path │ timestamp │
├─────────┼────┼─────────────┼────────┼─────────────┼─────────────────────────────────┼──────────────────────────┤
│ 0 │ 13 │ '127.0.0.1' │ 'POST' │ '404' │ '/replace-me' │ 2022-11-28T02:33:28.000Z │
│ 1 │ 14 │ '1.0.0.1' │ 'POST' │ '404' │ '/replace-me' │ 2022-11-28T02:33:28.000Z │
│ 2 │ 15 │ '127.0.0.1' │ 'POST' │ '404' │ '/replace-me' │ 2022-11-28T02:33:28.000Z │
│ 3 │ 16 │ '127.0.0.1' │ 'GET' │ '304' │ '/' │ 2023-03-30T06:55:32.000Z │
│ 4 │ 17 │ '127.0.0.1' │ 'GET' │ '304' │ '/' │ 2023-03-30T06:56:24.000Z │
│ 5 │ 18 │ '127.0.0.1' │ 'GET' │ '304' │ '/' │ 2023-03-30T06:56:38.000Z │
│ 6 │ 19 │ '127.0.0.1' │ 'GET' │ '304' │ '/manifest.json' │ 2023-03-30T04:25:00.000Z │
│ 7 │ 20 │ '::1' │ 'POST' │ '404' │ '/pgadmin4/misc/cleanup' │ 2023-03-30T06:51:32.000Z │
│ 8 │ 21 │ '127.0.0.1' │ 'GET' │ '200' │ '/' │ 2023-03-30T07:03:16.000Z │
│ 9 │ 22 │ '127.0.0.1' │ 'GET' │ '200' │ '/static/js/main.0d51c5de.js' │ 2023-03-30T07:03:16.000Z │
│ 10 │ 23 │ '127.0.0.1' │ 'GET' │ '200' │ '/static/css/main.dec85a0c.css' │ 2023-03-30T07:03:16.000Z │
│ 11 │ 24 │ '127.0.0.1' │ 'GET' │ '200' │ '/logo.svg' │ 2023-03-30T07:03:17.000Z │
└─────────┴────┴─────────────┴────────┴─────────────┴─────────────────────────────────┴──────────────────────────┘
데이터베이스 연결 닫는 중...
데이터베이스 연결 종료
#References
'devops bootcamp 4 > pair/team log' 카테고리의 다른 글
Sprint - YAML 작성 (0) | 2023.04.11 |
---|---|
Sprint - Proxy Server (0) | 2023.04.07 |
Sprint - Cozstory WAS 개발 (0) | 2023.03.28 |
Mini WAS 개발 hands-on (0) | 2023.03.28 |
CozStory 클라이언트 호스팅 (0) | 2023.03.27 |