IT STUDY LOG

Sprint - 로그 파이프라인 본문

devops bootcamp 4/pair/team log

Sprint - 로그 파이프라인

roheerumi 2023. 3. 30. 16:52

#최소 요구 사항 (Bare minimum requirements)

스프린트 안내

- nginx 웹 서버의 로그로부터 접속 기록을 추출하여, PostgreSQL에 적재

 

스프린트를 진행하기 전에 먼저 연습할 내용

- PostgreSQL 데이터베이스를 생성하고, SQL문을 이용해 데이터를 넣고, 넣은 결과를 확인합니다.

1. PostgreSQL 다운로드 

 

PostgreSQL: Downloads

 

www.postgresql.org

# 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번 클릭 후 로우 내용을 입력하고 2번을 눌러 저장

 

스프린트의 순서

1. nginx 웹 서버의 로그를 확인합니다.

2. 프로그래밍 언어를 이용해 로그로부터 유의미한 데이터를 추출하여, 각 필드를 구분합니다. (변환) 

> 이 프로그램을 파서(parser)라 지칭하겠습니다.

3. PostgreSQL 데이터베이스 내에 로그를 적재할 테이블을 만듭니다.

4. 프로그래밍 언어를 이용해 PostgreSQL에 접근하고, 데이터를 넣는 프로그램을 만듭니다. (적재)

> 이 프로그램을 수집기(collector)라 지칭하겠습니다.

5. 로그를 추출하고, 파서를 이용해 변환하고, 수집기를 이용해 PostgreSQL에 적재합니다.

출처 : 코드스테이츠 데브옵스 부트캠프 과정

 

#해결 과제

💻 웹 서버에 접속 이벤트를 발생시키고, 로깅이 되는지 확인합니다.

💻 파서를 직접 작성합니다.

💻 데이터 웨어하우스에 로그를 적재할 공간을 준비합니다.

💻 수집기를 직접 작성하여, 데이터 웨어하우스에 로그를 쌓을 수 있도록 합니다.

💻 파이프라인으로 연결하여 스트리밍 되는 로그를 추출/변환/적재합니다.

 

#실습 자료

레파지토리 : repository 주소

 

#과제 항목별 진행 상황

💡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

 

Linux : Nginx 에러, 액세스 로그 구성 방법, 예제, 명령어

Nginx는 인터넷에서 가장 큰 사이트 중 일부를 처리하는 오픈 소스, 고성능 HTTP 및 리버스 프록시 서버입니다. NGINX 웹 서버를 관리할 때 가장 자주 수행할 작업 중 하나는 로그 파일을 확인하는 것

jjeongil.tistory.com

 

'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
Comments