개인적으로 뭘 해보고자 하는게 있어서 요즘 잠깐 잠깐 만들고 있는 프로젝트가 있다.

- NAVER API를 이용해서 블로그 검색하기 (with Python)

 

그런데, 검색된 블로그 포스팅들을 화면에 출력만 할 것이 아니라 저장을 해놓고 싶은데,

그냥 JSON 형태로 저장하거나 CSV 형태로 저장하기엔 싫어서 SQLite를 이용해보려고 한다.

 

SQLite에 대한 기본적인 사항은 다음 포스팅을 참고하기 바란다.

- SQLite에 대해서 알아보자

 

 

0. 개발 환경

- OS: Ubuntu 20.04

- Lang: Python 3.10.9

 

 

1. 기본 코드

블로그 포스팅을 검색하는 코드는 이미 아래와 같이 살펴봤다.

- NAVER API를 이용해서 블로그 검색하기 (with Python)

 

 

2. SQLite 활용

기본 작성한 코드에서 이것 저것 좀 많이 업그레이드 시켰다.

 

에러메시지는 log로 남기도록 했고,

태그를 지우는 것은 BeautifulSoup 패키지를 활용하도록 했다.

 

import requests
import os
import sqlite3
from bs4 import BeautifulSoup
import logging

# 로깅 설정
logging.basicConfig(level=logging.ERROR)

class BlogPost:
    def __init__(self, title, description, link, postdate):
        self.title = self.clean_html(title)
        self.description = self.clean_html(description)
        self.link = link
        self.postdate = postdate

    def clean_html(self, text):
        if text:
            return BeautifulSoup(text, "html.parser").get_text()
        return ""

    def __str__(self):
        return f"Title: {self.title}\nDescription: {self.description}\nURL: {self.link}\nPost Date: {self.postdate}\n"

class NaverBlogSearcher:
    def __init__(self):
        self.client_id = os.getenv("NAVER_CLIENT_ID")  # 환경변수에서 Client ID 읽어오기
        self.client_secret = os.getenv("NAVER_CLIENT_SECRET")  # 환경변수에서 Client Secret 읽어오기

        # 환경변수 값이 없을 때 예외 처리
        if not self.client_id or not self.client_secret:
            logging.error("NAVER_CLIENT_ID and NAVER_CLIENT_SECRET must be set as environment variables.")
            raise ValueError("NAVER_CLIENT_ID and NAVER_CLIENT_SECRET must be set as environment variables.")

    def get_blog_posts(self, query, display=10):
        # 요청 URL 및 헤더 구성
        url = f"https://openapi.naver.com/v1/search/blog.json?query={query}&display={display}&sort=date"
        headers = {
            "X-Naver-Client-Id": self.client_id,
            "X-Naver-Client-Secret": self.client_secret,
        }

        # 네이버 API에 요청 보내기
        try:
            response = requests.get(url, headers=headers)
            response.raise_for_status()
        except requests.exceptions.RequestException as e:
            logging.error(f"Network error occurred: {e}")
            return []
        
        if response.status_code == 200:
            return self.parse_response(response.json())
        else:
            print(f"Error: {response.status_code}, {response.text}")
            return []

    def parse_response(self, data):
        # 응답 데이터 파싱
        blogs = data.get("items", [])
        blog_posts = [BlogPost(blog.get("title"), blog.get("description"), blog.get("link"), blog.get("postdate")) for blog in blogs]
        return blog_posts

class BlogPostDBHandler:
    def __init__(self, db_name="blog_posts.db"):
        self.db_name = db_name
        self.create_table()

    def create_table(self):
        # SQLite 데이터베이스 연결
        with sqlite3.connect(self.db_name) as conn:
            cursor = conn.cursor()

            # 테이블 생성
            cursor.execute('''
                CREATE TABLE IF NOT EXISTS BlogPosts (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    title TEXT,
                    description TEXT,
                    link TEXT UNIQUE,
                    postdate TEXT
                )
            ''')

    def save_to_db(self, blog_posts):
        # SQLite 데이터베이스 연결
        with sqlite3.connect(self.db_name) as conn:
            cursor = conn.cursor()

            # 데이터 삽입 (중복 확인)
            for post in blog_posts:
                cursor.execute('''
                    SELECT COUNT(*) FROM BlogPosts WHERE link = ?
                ''', (post.link,))
                if cursor.fetchone()[0] == 0:
                    cursor.execute('''
                        INSERT INTO BlogPosts (title, description, link, postdate) 
                        VALUES (?, ?, ?, ?)
                    ''', (post.title, post.description, post.link, post.postdate))

    def get_all_posts(self):
        # SQLite 데이터베이스 연결
        with sqlite3.connect(self.db_name) as conn:
            cursor = conn.cursor()

            # 저장된 블로그 포스팅의 모든 필드 가져오기
            cursor.execute('''
                SELECT title, description, link, postdate FROM BlogPosts
            ''')
            rows = cursor.fetchall()

        # 필드명을 갖는 dict 형태로 변환
        posts = [
            {"title": row[0], "description": row[1], "link": row[2], "postdate": row[3]} 
            for row in rows
        ]
        return posts

if __name__ == "__main__":
    # "동탄" 검색어로 최신 블로그 정보 가져오기
    try:
        searcher = NaverBlogSearcher()
        blog_posts = searcher.get_blog_posts("동탄")
        
        # 검색 결과 출력
        # for post in blog_posts:
        #     print(post)
        
        # 검색 결과를 SQLite 데이터베이스에 저장
        db_handler = BlogPostDBHandler()
        db_handler.save_to_db(blog_posts)

        # 저장된 블로그 포스팅의 제목 출력
        posts = db_handler.get_all_posts()
        for post in posts:
            print(f"Title: {post['title']}")
    except ValueError as e:
        print(e)

 

TABLE이 존재하지 않으면 create 하도록 했으며,

블로그 포스팅을 insert 하기 전에 기존에 있는지 미리 확인한 후에 없을 때에만 insert 하도록 했다.

 

아직은 PoC 성격의 스크립트 이기에,

SQLite에 저장한 이후에 전체 포스팅 목록을 SQLite로부터 읽어와서 제목들을 출력하도록 했다.

 

그리고,

추가 설치해야할 패키지들이 있기에 requirements.txt 파일도 업데이트 되었다.

 

beautifulsoup4==4.12.3
requests==2.32.3

 

 

3. Execute

실행 결과도 확인 해보고, database 내용도 살펴보자.

 

> dotenvx run -f .env -- python main.py

 

 

이렇게 저장을 하면 database 파일이 하나 생성되는 것을 확인할 수 있다.

- blog_posts.db

 

 

 

4. Check

db 파일을 확인해보기 위해서 "DB Browser for SQLite"를 사용해보겠다.

 

 

설치는 그냥 패키지 설치하면 된다.

 

> sudo apt-get install sqlitebrowser

 

잘 설치되어 있는 것을 볼 수 있다.

 

 

실행하고, "데이터베이스 열기" 하고 db 파일을 선택해주면 된다.

 

 

"데이터 보기" 탭을 선택하면 저장된 내역을 볼 수 있다.

 

 

 

오늘은 여기까지~

반응형

IT 뉴스를 읽다가 발견한 재미난 뉴스가 하나 있었다.

  - https://news.hada.io/topic?id=16044

출처: GeekNews

 

 

어!? SQLite는 그냥 가벼운 맛에 사용하는 database 아니었나!?

 

SQLite에서 발표한 내용이라 믿지 못할 수 있지만, 테스트한 내용을 보면 믿을만한 것 같다.

  - https://sqlite.org/fasterthanfs.html

출처: SQLite

 

그런데, 정말 드라마틱한 속도 차이를 보이는 것은

read latency 그래프에서 보이는 것처럼 Win10과의 비교이다. 빠르다 !!!

 

하지만, 어디까지나 제한적인 상황에서만 SQLite 사용을 추천하고,

대용량이거나 MSA와 같은 상황에서는 Postgres를 사용하는 것이 훨 나은 선택이다.

  - https://news.hada.io/topic?id=6498

 

가만히 생각해보니 SQLite라는 것을 내가 처음 들어본 것은

Android 초창기에 플랫폼 컴파일 및 App 개발해본답시고 깔짝 깔짝 거릴 때이다.

그렇다! Android에서 지금도 사용하는

튼튼한 안정성을 갖고 있는 훌륭한데이터베이스인 것은 분명하다.

  - https://www.epicweb.dev/why-you-should-probably-be-using-sqlite

  - https://news.hada.io/topic?id=11561

 

SQLite에 대한 재미있는 히스토리를 알고 싶으신 분은 다음 인터뷰 내용을 한 번 살펴보기 바란다.

  - https://corecursive.com/066-sqlite-with-richard-hipp/

  - https://news.hada.io/topic?id=4558

 

재미있는 사실 중 하나는

토발즈 아저씨(?)가 Linux Kernel 개발을 위해 Git이라는 소스코드 버전관리 도구를 만든 것처럼

리차드 힙(Richard Hipp) 아저씨도 SQLite 개발을 위해 Fossil이라는 소스코드 버전관리 도구를 만들었다!!!

  - https://fossil-scm.org/

 

 

이제 SQLite를 직접 건드려보자.

 

 

1. SQLite 확인

어떤 버전을 어떻게 설치하면 되는지 공식 사이트를 통해서 확인해보자.

https://www.sqlite.org/

 

Download 메뉴에서 제일 앞에 Android를 위한 binary 파일부터 확인된다는 것이 조금 재미있었다 ^^

https://www.sqlite.org/download.html

 

 

2. Serverless Architecture

SQLite는 Server-Client Architecture가 아닌 Serverless Architecture 방식이다.

  - https://www.sqlite.org/serverless.html

출처: https://www.whatwant.com

 

그렇기 때문에 별도의 Server 설치 과정이 없다.

 

어!? 그러면 위에서 살펴본 SQLite의 다운로드 페이지는 뭐지!?

그냥 Command-Line Tool이다.

 

 

3. SQLite Tools in Ubuntu

① Install

Ubuntu 환경에서는 그냥 패키지 설치를 하면 된다.

> sudo apt install sqlite3

출처: https://www.whatwant.com

 

② Create database

설치된 tool 버전 확인 및 database 생성은 다음과 같이 실행할 수 있다.

> sqlite3 --version

> sqlite3 test.db

 

 

 

③ Create table and example

TABLE 생성 및 간단한 사용 예시는 다음과 같다.

sqlite> CREATE TABLE TEMP (
   ...> id INTEGER PRIMARY KEY,
   ...> name VARCHAR(10),
   ...> number VARCHAR(10));


sqlite> INSERT INTO TEMP(name, number) VALUES('whatwant', '123456789');


sqlite> SELECT * FROM TEMP;

1|whatwant|123456789


sqlite> .exit

 

 

생성된 database file도 확인할 수 있다.

 

④ command

중요한 명령어 몇 가지를 보자면 다음과 같다.

Command Comments
sqlite3 {database filename} 데이터 베이스 생성하면서 접속 (기존 데이터베이스가 있으면 읽어들임)
.open {database filename} 접속된 상태에서 데이터베이스 생성. 읽기 또는 변경
.help 도움말
.database 데이터베이스 파일 위치 보기
.table 테이블 목록 보기
.show 현재 설정 보기
.clone {database filename} 데이터베이스 복제
.mode {option} select 결과 출력 방식 (list / column) column 방식 추
.quit / .exit 프롬프트 종료

 

 

4. SQLite Tools in Python

Python을 이용해서 SQLite 사용하는 예시를 확인해보자.

 

일단 패키지 관리를 위해서 가상환경 설정부터 해놓자.

> python -m venv .venv

> source .venv/bin/activate

 

 

소스코드는 다음과 같이 작성했다.

import sqlite3

conn = sqlite3.connect('test.db')
cursor = conn.cursor()

cursor.execute('SELECT * FROM TEMP')
print(cursor.fetchall())

cursor.close()

 

실행해보면 다음과 같이 예쁘게 잘 나온다.

 

 

SQLite 활용에 대해서 공부하고 싶으신 분은 다음 링크 자료를 참조하면 좋다.

  - https://wikidocs.net/book/1530

 

file-system 사용해서 데이터를 처리하는 경우

SQLite 사용에 대해서도 같이 검토해보면 좋을 것 같다.

반응형

▶ ChatGPT

출처: https://www.nature.com/immersive/d41586-023-03919-1

 

국제학술지 '네이처(Nature)'에서 올 한 해 과학계에 큰 화제를 불러일으킨 10명의 인물을 선정하는 '네이처 10(Nature's 10)'을 발표했는데, 역대 최초로 인간이 아닌 생성형 인공지능(AI) 챗봇 '챗GPT(ChatGPT)'를 포함시켰다.

 

ChatGPT라고는 하지만, 크게 바라보면 '생성형 인공지능' 자체가 우리 생활에 정말 큰 영향을 미치게 된 것이다.

지금은 시작일 것이다. 앞으로는 정말 생활 이곳 저곳에서 우리와 함께하게 될 것이다.

 

▶ RAG

 

ChatGPT는 정말 대단한 기능 및 성능을 보여주고 있지만, 한계점도 분명히 있다.

 

일단 ChatGPT가 이것 저것 골고루 많이 아는 똑똑한 아이이긴 하지만,

특정 분야에 대해서 전문적인 지식을 갖고 있다고 하기에는 조금 부족하다.

 

그리고 최신 정보를 알지 못한다는 점도 있고 장기 기억을 유지하기에 어렵다는 점도 있고,

할루시네이션(Hallucination)과 같은 문제도 있는 등

 

ChatGPT는 여러가지 한계점이 분명히 있고 이러한 한계점을 다양한 방법으로 해결하고자 발전하고 있다.

 

이러한 ChatGPT의 한계점을 극복하는 방법 중 하나로

RAG(Retrieval-Augmented Generation, 검색 증강 생성)이라는 것이 최근 엄청난 화두가 되고 있다.

 

출처: https://docs.aws.amazon.com/sagemaker/latest/dg/jumpstart-foundation-models-customize-rag.html

 

위 그림에서 오른쪽 위를 잘 살펴보기 바란다.

'Knowledge Source'를 별도로 구성하고 이를 일종의 보조 기억장치처럼 사용하는 것이다.

 

어?! 뭔가 떠오르지 않는가!?

그렇다!!! 바로 "데이터베이스(Database)"이다.

 

▶ Embedding

ChatGPT의 경우 기본적으로 사용되는 데이터는 '자연어(Natural Language)'이다.

 

이러한 자연어를 문자 그대로 사용한다고 하면 그 안에 담겨있는 의미나 가치를 다루기가 어렵기 때문에

단어 또는 문장들을 다른 방식으로 표현을 해야하는데

현재 가장 보편적인 표현 방식이 바로 'Vector Embedding'이다.

 

출처: https://www.pinecone.io/learn/vector-embeddings/

 

Vector 형식으로 데이터가 저장이 되기 때문에

Vector 연산을 통해 검색을 한다거나 "king + queen = princess or prince"와 같은 연산도 가능하게 된다.

 

이제 이렇게 임베딩된 데이터들을 데이터베이스에 저장해놓고 쿼리를 해서 사용을 하면 되는데,

PostgreSQL이나 MySQL과 같은 기존 RDB를 이용하기에는 좀 어려움과 불편함이 한 가득이다.

 

▶ Vector Database

그렇다. 말 그대로 Vector 데이터들을 저장하고 제공하는데에 특화된 데이터베이스이다.

예전에도 있었던 데이터베이스 유형이지만, 최근 AI 시대가 되면서 엄청난 대박이 났다.

 

출처: https://techcrunch.com/2023/04/27/pinecone-drops-100m-investment-on-750m-valuation-as-vector-database-demand-grows/?utm_source=oneoneone

 

2021년도에 출시된 Pinecone은 1억 달러 규모의 시리즈 B 투자를 받았다고 한다. 기업 가치는 무려 7억 5천만 달러.

그 외에도 Weaviate, Chroma, Qdrant 等 다양한 Vector Database들이 모두 다 많은 투자를 받았다.

 

이렇게 돈이 쏠린다는 것은 이 분야에 대해서 많은 분들이 성공할거라 믿는다라는 의미일 것이고

그렇다면 우리는 이 부분에 대해서 공부해볼 가치가 충분히 있다!!!

 

▶ Pinecone

최근 가장 많은 인기를 얻고 있는(돈을 투자 받은?!) Pinecone에 대해서 알아보자.

 

출처: https://www.pinecone.io/

 

비용은 어떻게 될까!? (너무 돈! 돈! 하는 것 같아서 조금 그렇지만... 현실이... ^^)

 

출처: https://www.pinecone.io/pricing/

 

비용 부분을 살펴보면서 눈치 챘어야 한다.

그렇다! Pinecone은 On-Premise 형태로 제공되지 않는다. 무조건 SaaS 이다!

그나마 다행인 것은 Free 제공 부분이 있다는 점! ^^

 

출처:  https://www.pinecone.io/

 

Sign-Up은 편하게 되어있다.

 

출처:  https://www.pinecone.io/

 

무료 요금제에서는 Index 1개를 사용할 수 있다.

기존 RDB에서 table 정도로 생각하면 될 것 같다.

 

출처:  https://www.pinecone.io/

 

Python을 이용해서 접근하기 위해서는 API Key 값을 알아야 한다.

왼쪽 메뉴탭에서 'API Keys'를 눌러보면 하나 이미 만들어진 것을 확인할 수 있다.

 

출처:  https://www.pinecone.io/

 

▶ Hello-whatwant

이제 Pinecone을 사용해보자.

 

출처: https://www.pinecone.io/learn/vector-database/

 

Knowledge를 임베딩해서 저장을 하고,

질문을 다시 임베딩해서 쿼리를 던지면 그와 유사도가 높은 것들을 답해주는 과정을 해보고자 한다.

 

기본적인 간단한 workflow이지만, 그래도 다음의 두 가지 사항은 미리 확인/준비 해야 한다.

 

① Python에서 Pinecone을 사용하기 위한 방법

② Embedding Model 선정 및 사용 방법

 

 

 Python에서 Pinecone을 사용하기 위한 방법

  - 앞에서 이미 Pinecone API Key 및 Env 값은 확보(?)했으니 이 부분은 Pass

  - 그리고, 친절하게도 Pinecone 라이브러리를 제공해주니 이를 사용하면 OK

    . https://docs.pinecone.io/docs/quickstart

 

> pip install pinecone-client

 

② Embedding Model 선정 및 사용 방법

  - 이 부분은 정해진 것이 없기에 필요에 따라 각자의 취향/상황에 맞춰서 하면 된다.

    . 지금은 보통 적은 리소스로 괜찮은 성능을 보여준다고 하는 all-MiniLM-L6-v2 모델을 사용해보겠다.

 

출처: https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2

 

 

이제 코드로 풀어보자.

설명을 위해 Colab 환경에서 진행한 내용으로 진행하겠다.

  - https://colab.research.google.com/

 

Colab

 

CPU 환경에서도 실행 가능하긴 하지만, 이왕이면 GPU 환경이 빠르니... 선택하자.

 

 

pinecone-client, sentence-transformer 2개의 패키지 설치가 필요하다.

 

 

앞에서 확인한 pinecone API key 값 및 Env 값을 넣어주면 된다.

warning은 가뿐히 무시하자 ^^

 

 

굳이 torch를 import까지 할 것은 아닌 것 같아서 주석처리했고 ^^

all-MiniLM-L6-v2 모델을 불러왔는데, 출력된 내역을 보면 간단하게나마 spec을 확인할 수 있다.

 

잠시 현재 Pinecone의 Index 상태를 살펴보자면 다음과 같이 아무 것도 없다.

 

 

그러면, 우리는 Index를 하나 만들어보자.

 

 

이렇게 만들면 Pinecone에서는 다음과 같이 결과가 보인다.

 

 

내용물을 살펴보면 다음과 같이 아무 것도 없다 ^^

 

 

테스트하기 위해 넣어줄 데이터는 ChatGPT로 만들어봤다.

프로그래밍 언어를 한 문장으로 정리해달라고 했다.

 

출처: ChatGPT

 

입력을 열심히 해주면 된다.

 

 

그 다음에는 Pinecone으로 넣어줄 형태로 변환을 해야 한다.

'일련번호, 임베딩된 내용, 원본 내용'의 조합으로 생각하면 된다.

 

 

준비가 되었으면 upsert 해주면 된다.

upsert가 뭐냐고? update or insert !!!

 

 

Pinecone에서 확인해보자.

 

 

Pinecone의 상태를 직접 확인해볼 수도 있다.

 

 

query를 요청할 용도의 function을 하나 만들어 보자.

 

 

이제 질문을 해보자.

 

 

잘 나온다 !!!

다른 식으로 질문을 해볼까?

 

 

잘 찾아준다 !!!

 

 

여기까지~~~~ ^^

반응형

 

간단한 웹을 만들어야 하는데,

간단하게 데이터를 다뤄야 할 때 종종 언급이 되는 Redis에 대해서 살펴보려고 한다.

 

"Key-Value 형식의 in-memory 데이터베이스"

 

기존에 내가 알고 있는 Redis에 대한 정보인데

공식 홈페이지에서 다시 한 번 확인해봤다.

 

- https://redis.io/

 

redis.io

 

"The opensource, in-memory data store used by millions ..."

어?! 'database'라고 하지 않고 'data store'라고 설명을 하네?! 라고 느끼는 순간! 사이트 중간에 다시 설명을 해주고 있다.

 

"A vibrant, open source database"

 

뭐, 결국은 내가 알고 있던 "key-value 형식의 in-memory databse"가 맞기는 하지만

스스로는 "data store"라는 정체성을 더 소중히 여기는 것이 아닌가 싶다.

 

서론이 너무 길었는데,

Redis에 대해서 너무나 잘 설명해주고 있는 좋은 아티클 링크 공유하면서 서두를 마치고자 한다.

 

- 6편의 아티클로 Redis에 대해서 심도있게 다루고 있음

  . https://insanelysimple.tistory.com/343

 

- Redis에 대해 소개하면서 "Redis vs Memcached" 비교

  . https://kdhyo98.tistory.com/89

 

 

이제 본론으로 들어가봅시다~!!

 

 

[ Redis 맛보기 ]

 

0. Background

개인적인 취향일 수도 있겠지만,

S/W 개발을 위한 기본적인 환경은 Linux 기반이 좋다고 생각하기 때문에

이번 실습 역시 Linux 배포판 中 Ubuntu 운영체제에서 진행한다.

 

또한, 최근 유행하고 있는 MSA 기조에 맞춰서

Application의 구성은 Container를 기반으로 하며

가장 대중적인 Docker를 활용하도록 하겠다.

 

- 테스트 환경 (필자가 이하 내용을 진행한 환경)

  . Host OS : Windows 10 Pro 21H1

  . VM : VirtualBox v6.1.34 r150636 (Qt5.6.2)

  . Guest OS : Ubuntu 18.04.6 LTS

  . Docker version 20.10.17, build 100c701

 

역시 개인적인 취향이 듬뿍 들어 있는 방식이긴 한데,

Server를 운영할 때 패키지의 버전관리 측면과 더불어 폐쇄망에서의 제약으로 인해

패키지들을 설치 할 때 직접 다운로드 받아서 진행하는 것을 선호한다.

 

- Docker 설치

  . Ubuntu 16.04 / 18.04 : https://www.whatwant.com/entry/Docker-Install-Ubuntu-16041804-64bit-using-Download

  . Ubuntu 20.04 : https://www.whatwant.com/entry/Docker-Install-Ubuntu-Server-2004

 

 

위와 같이 환경을 제시하긴했지만,

Windows/macOS 환경에서도 docker를 사용하기 때문에 비슷하게 동작하지 않을까 한다.

 

 

1. Persistent Volume

Redis가 in-memory data-store 솔루션이지만,

안정적 운영을 위해 메모리에 있는 데이터를 디스크에 쓰는 2가지 옵션을 제공한다.

 

① RDB (Redis Database) : 지정된 시간 간격으로 스냅샷을 파일로 저장

② AOF (Append Only File) : 모든 작업을 기록, 서버가 시작할 때 이 기록을 읽어서 데이터 재구성

 

어떤 옵션을 사용하더라도 데이터 저장이 되는 곳이 필요하고

보다 수월한 백업 등의 작업을 위해 docker volume 공간을 따로 구성하도록 하겠다.

 

# 리스트 확인
$ docker volume ls

# 생성
$ docker volume create [name]

# 상세 조회
$ docker volume inspect [name]

volume

 

2. Redis Config

접근 가능한 IP를 지정하고, 인증을 위한 패스워드를 넣는 등의 환경 설정을 위한 config 파일을 작성해보자.

또한 config 파일은 host에서 관리할 수 있도록 하겠다.

 

# 어떤 네트위크 인터페이스로부터 연결할 수 있도록 할 것인지 관리 (여기에서는 Anywhere)
bind 0.0.0.0

# 사용 포트 관리
port 6379

# Master 노드의 기본 사용자(default user)의 비밀번호 설정
requirepass [사용하고자 하는 비밀번호]

# Redis 에서 사용할 수 있는 최대 메모리 용량. 지정하지 않으면 시스템 전체 용량
maxmemory 2gb

# maxmemory 에 설정된 용량을 초과했을때 삭제할 데이터 선정 방식
# - noeviction : 쓰기 동작에 대해 error 반환 (Default)
# - volatile-lru : expire 가 설정된 key 들중에서 LRU algorithm 에 의해서 선택된 key 제거
# - allkeys-lru : 모든 key 들 중 LRU algorithm에 의해서 선택된 key 제거
# - volatile-random : expire 가 설정된 key 들 중 임의의 key 제거
# - allkeys-random : 모든 key 들 중 임의의 key 제거
# - volatile-ttl : expire time(TTL)이 가장 적게 남은 key 제거 (minor TTL)
maxmemory-policy volatile-ttl

# DB 데이터를 주기적으로 파일로 백업하기 위한 설정입니다.
# Redis 가 재시작되면 이 백업을 통해 DB 를 복구합니다.

save 900 1      # 15분 안에 최소 1개 이상의 key 가 변경 되었을 때
save 300 10     # 5분 안에 최소 10개 이상의 key 가 변경 되었을 때
save 60 10000   # 60초 안에 최소 10000 개 이상의 key 가 변경 되었을 때

 

redis.conf

 

redis.conf

 

3. Redis Image

Redis의 공식 Image 중에서 사용하고자 하는 버전을 찾아보자

- https://hub.docker.com/_/redis?tab=tag

 

Redis Image

 

현재 시점에서는 v7.0.2 가 최신이다.

 

 

4. Run

이제 Redis를 실행시켜 보자.

 

$ docker run \
-d \
--restart=always \
--name=redis \
-p 6379:6379 \
-e TZ=Asia/Seoul \
-v /srv/workspace/redis/redis.conf:/etc/redis/redis.conf \
-v redis_data:/data \
redis:7.0.2 redis-server /etc/redis/redis.conf

 

docker run

 

잘 실행이 되었는지도 확인해 보자.

 

docker logs

 

 

5. Redis Client

Redis에서 실제 값을 입력 해보자.

Redis Client의 실행 명령어는 'redis-cli' 이다.

 

$ docker exec -it redis redis-cli

 

NO AUTH

 

어?! 키 값 저장이 안된다.

redis.conf 작성할 때 명시한 패스워드를 사용하지 않았기 때문이다.

 

패스워드를 넣어서 client를 실행하면 정상 동작 한다.

 

AUTH

 

키 값 저장 및 조회가 잘 되는 것을 볼 수 있다.

 

여기까지~

 

반응형

 

보통 개발 단계에서는

Superuser 권한을 갖고 있는 계정으로 database를 사용하곤 한다. (나만 그런가?)

 

당연히 그 누구도 추천하지 않는, 바람직하지 않은 계정 사용법이다.

 

그러면 적절한 권한을 갖고 있는 개발용 계정을 생성해서 사용해야하고

그래서 지금은 계정 생성 및 삭제, 권한 부여 방법 등에 대해서 살펴볼 시간이다.

 

 

0. Environment

  - [PostgreSQL을 Docker로 설치하자](https://www.whatwant.com/entry/PostgreSQL-Docker)

 

 

1. psql

  - docker 환경에 특화된 내역이긴 하지만, 기록 차원에서 남긴다.

 

❯ docker exec -it postgres /bin/bash

root@d0b1fa1bb2b1:/# psql -U postgres

psql (14.2 (Debian 14.2-1.pgdg110+1))
Type "help" for help.

postgres=# 

 

 

2. 계정 및 권한 확인

  - `\du`

 

postgres=# \du
                                   List of roles
 Role name |                         Attributes                         | Member of 
-----------+------------------------------------------------------------+-----------
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS | {}

 

 

3. 계정 생성

  - `CREATE USER [username] WITH LOGIN PASSWORD '[password]';`

 

postgres=# CREATE USER whatwant WITH LOGIN PASSWORD 'xxxxxxxx';

CREATE ROLE


postgres=# \du
                                   List of roles
 Role name |                         Attributes                         | Member of 
-----------+------------------------------------------------------------+-----------
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
 whatwant  |                                                            | {}

 

 

  ▶ Attributes of ROLE

     - 기본값은 `NO-` 속성들이다.

 

SUPERUSER or NOSUPERUSER SUPERUSER 여부
CREATEDB or NOCREATEDB DATABASE를 만들 수 있는 권한
CREATEROLE or NOCREATEROLE ROLE을 만들 수 있는 권한
LOGIN or NOLOGIN LOGIN 허용 여부
INHERIT or NOINHERIT 상속 가능 여부
REPLICATION or NOREPLICATION 복제 권한
BYPASSRLS or NOBYPASSRLS RLS(Row-Level Security) 무시 여부
PASSWORD [password] 패스워드
 VALID UNTIL [timestamp] 패스워드의 유효기간
IN ROLE [role_name] or IN GROUP [role_name] 지정한 ROLE의 구성원으로 포함
ROLE [role_name] or GROUP [role_name] 지정한 ROLE 부여
ADMIN [role_name] 윗 줄의 ROLE 속성 + WITH ADMIN

 

 

4. 권한 부여

  - DATABASE를 하나 생성하고 그에 따른 권한을 부여해보자

 

postgres=# CREATE DATABASE my_db WITH OWNER whatwant ENCODING 'UTF8';

CREATE DATABASE



postgres=# GRANT ALL PRIVILEGES ON DATABASE my_db TO whatwant;
GRANT

 

  ▶ Permission

     - 잘 모르는 내용도 있지만, 일단 리스트업 해본다.

 

SELECT 데이터 조회. UPDATE/DELETE 하려면 포함 필요
INSERT 데이터 추가
UPDATE 데이터 수정
DELETE 데이터 삭제
TRUNCATE 데이터 모두 삭제
REFERENCES 외래키 제약 조건 생성
TRIGGER 트리거
CREATE 스키마 생성
CONNECT 데이터베이스 연결
TEMPORARY 임시 테이블 생성
EXECUTE 함수/프로시저 연산자 허용
USAGE 스키마 객체 접근 허용
ALL PRIVILEGES 모든 권한

 

 

 

pgAdmin4로 확인해보자.

 

 

여기까지...

 

반응형

 

PostgreSQL을 시스템에 직접 붙어서 `psql`을 이용해서 다루는 것도 좋지만,

개인적으로 Web Interface를 통해서 database의 현황을 살펴보는 것을 좋아하기에

PostgreSQL을 설치하고 난 다음에 바로 찾아본 것이 바로 `pgAdmin4`이다.

 

깔끔한 설치를 위해 Docker로 한 번 설치해봤다.

 

 

0. PostgreSQL 설치

  - [PostgreSQL을 Docker로 설치하자](https://www.whatwant.com/entry/PostgreSQL-Docker)

 

 

1. pgAdmin4 설치

  - 그냥 바로 실행하자.

  - email 주소와 password는 각자 취향에 다라 지정해주면 된다.

 

❯ sudo docker run -p 5050:80 -e 'PGADMIN_DEFAULT_EMAIL=abc@email.com' \
                        -e 'PGADMIN_DEFAULT_PASSWORD=password' -d dpage/pgadmin4

Unable to find image 'dpage/pgadmin4:latest' locally
latest: Pulling from dpage/pgadmin4
59bf1c3509f3: Pull complete 
6e9ec7ad2b67: Pull complete 
a0e18fcb2977: Pull complete 
fd2b27e2842d: Pull complete 
51136bc64bc0: Pull complete 
f64eecb587f3: Pull complete 
9cb5237d6528: Pull complete 
facb2de54b7c: Pull complete 
2c30d334d2ee: Pull complete 
27b8ff406ea1: Pull complete 
b87dab9776e7: Pull complete 
3e9a234b4839: Pull complete 
160949aa8885: Pull complete 
02526e9b4604: Pull complete 
Digest: sha256:3a2f4533b0e33baa09260ce02d0912058881c55cef800b73219e19b0a9d75658
Status: Downloaded newer image for dpage/pgadmin4:latest
4fb11f1a591ed35244b6db9045b844cae781ca3b59c54006b172805567dd1326

 

 

2. Connect

  - http://127.0.0.1:5050/

  - 실행할 때 입력한 email 주소와 password를 이용해서 로그인 하면 된다.

 

 

 

3. Add New Server

  - PostgreSQL 서버를 등록해주자.

 

 

  - name 하나 지어주고,

 

 

  - Connection 정보를 입력해주자.

  - `localhost`, `127.0.0.1`로 지정하면 연결이 안된다. IP 적어주자.

  - `Username`과 `Password` 제대로 입력하고 Save 하면 된다.

 

 

  - 이제 짠~

 

 

 

일단 여기까지~

 

반응형

 

개발을 하는 중에 PostgreSQL을 개발PC에 설치할 필요가 생겼는데

그냥 설치하기에는 개발PC가 지저분해질까봐 Docker를 이용해서 설치하려고 한다.

 

[ 개발PC 환경 ]

  - 운영체제: Ubuntu 18.04.6 LTS

  - docker: Docker version 20.10.12, build e91ed57

 

 

사실 포스팅을 굳이 해야할까 싶을 정도로 너무 간단하게 설치가 된다.

 

 

1. Docker Volume 생성

  - 데이터를 조금이라도 안전하게 보관하기 위해서 별도 volume으로 관리하자.

  - 실제 저장 위치도 확인해 볼 수 있다.

 

❯ docker volume create postgres_data

postgres_data


❯ sudo ls -al /var/lib/docker/volumes/

합계 40
drwx-----x  4 root root  4096  3월 21 21:14 .
drwx--x--- 13 root root  4096  3월 21 20:12 ..
brw-------  1 root root  8, 1  3월 21 20:12 backingFsBlockDev
-rw-------  1 root root 32768  3월 21 21:14 metadata.db
drwx-----x  3 root root  4096  2월 13 03:22 portainer_data
drwx-----x  3 root root  4096  3월 21 21:14 postgres_data

 

 

2. run PostgreSQL

  - 실행은 한 줄이면 된다 ^^

  - password는 각자 취향에 맞게 작성하면 된다.

 

❯ docker run -d -p 5432:5432 --name postgres -e POSTGRES_PASSWORD=password \
                 -v postgres_data:/var/lib/postgresql/data postgres

Unable to find image 'postgres:latest' locally
latest: Pulling from library/postgres
ae13dd578326: Pull complete 
723e40c35aaf: Pull complete 
bf97ae6a09b4: Pull complete 
2c965b3c8cbd: Pull complete 
c3cefa46a015: Pull complete 
64a7315fc25c: Pull complete 
b9846b279f7d: Pull complete 
ed988fb8e7d9: Pull complete 
ed4bb4fd8bb5: Pull complete 
ead27f1733c8: Pull complete 
7d493bacd383: Pull complete 
0920535e8417: Pull complete 
db76d5bdbf2c: Pull complete 
Digest: sha256:d1db54eade17ebfaa6cfdca90c83f8cb0d54bcceb1270a0848e0b216d50c325c
Status: Downloaded newer image for postgres:latest
d0b1fa1bb2b1b580e96e1790b6f7bebfcfdc88c885c35e1af57d82379e5df7b7

 

 

3. psql

  - 이대로 끝내면 서운하니까 psql 까지만 접속해보자.

 

❯ docker exec -it postgres /bin/bash

root@d0b1fa1bb2b1:/# psql -U postgres

psql (14.2 (Debian 14.2-1.pgdg110+1))
Type "help" for help.

postgres=# 

 

 

 

여기까지~

반응형

 

어떤 도구를 설치해보려고 했는데,

필요 조건이 MongoDB가 이미 설치되어 있어야 한단다.

 

그래서 부랴부랴 MongoDB 설치를 해보고자 한다.

 

 

# Environment

 

  - 기본 환경은 아래와 같다.

 

$ lsb_release -a

No LSB modules are available.

Distributor ID: Ubuntu

Description:    Ubuntu 18.04.4 LTS

Release:        18.04

Codename:       bionic

 

$ uname -a

Linux chani1804 4.15.0-88-generic #88-Ubuntu SMP Tue Feb 11 20:11:34 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

 

 

 

# install

 

  - 그냥 바로 apt-get으로 설치하면 된다.

 

$ sudo apt-get install mongodb

Reading package lists... Done

Building dependency tree

Reading state information... Done

The following additional packages will be installed:

  libboost-filesystem1.65.1 libboost-iostreams1.65.1 libboost-program-options1.65.1 libboost-system1.65.1 libgoogle-perftools4 libpcrecpp0v5 libsnappy1v5 libstemmer0d

  libtcmalloc-minimal4 libyaml-cpp0.5v5 mongo-tools mongodb-clients mongodb-server mongodb-server-core

The following NEW packages will be installed:

  libboost-filesystem1.65.1 libboost-iostreams1.65.1 libboost-program-options1.65.1 libboost-system1.65.1 libgoogle-perftools4 libpcrecpp0v5 libsnappy1v5 libstemmer0d

  libtcmalloc-minimal4 libyaml-cpp0.5v5 mongo-tools mongodb mongodb-clients mongodb-server mongodb-server-core

0 upgraded, 15 newly installed, 0 to remove and 0 not upgraded.

Need to get 53.5 MB of archives.

After this operation, 217 MB of additional disk space will be used.

Do you want to continue? [Y/n]

 

 

 

# check status

 

  - 설치를 완료하게 되면 바로 서비스로 실행이 된다.

  - 서비스 상태를 확인해보자.

 

$ systemctl status mongodb.service

● mongodb.service - An object/document-oriented database

   Loaded: loaded (/lib/systemd/system/mongodb.service; enabled; vendor preset: enabled)

   Active: active (running) since Tue 2020-03-10 22:58:24 KST; 4min 31s ago

     Docs: man:mongod(1)

 Main PID: 3334 (mongod)

    Tasks: 23 (limit: 2318)

   CGroup: /system.slice/mongodb.service

           └─3334 /usr/bin/mongod --unixSocketPrefix=/run/mongodb --config /etc/mongodb.conf

 

 3월 10 22:58:24 chani1804 systemd[1]: Started An object/document-oriented database.

 

 

  - 버전과 접근 정보를 확인해보자.

 

$ mongo --eval 'db.runCommand({ connectionStatus: 1 })'

MongoDB shell version v3.6.3

connecting to: mongodb://127.0.0.1:27017

MongoDB server version: 3.6.3

{

        "authInfo" : {

                "authenticatedUsers" : [ ],

                "authenticatedUserRoles" : [ ]

        },

        "ok" : 1

}

 

 

 

# 자동 실행

 

  - 재부팅할 때 자동으로 실행되도록 설정해보자.

 

$ sudo systemctl enable mongodb.service

Synchronizing state of mongodb.service with SysV service script with /lib/systemd/systemd-sysv-install.

Executing: /lib/systemd/systemd-sysv-install enable mongodb

 

 

 

# 간단한 사용

 

  - 동작을 하는 것인지 확인만 해보자.

 

$ mongo

MongoDB shell version v3.6.3

connecting to: mongodb://127.0.0.1:27017

MongoDB server version: 3.6.3

Welcome to the MongoDB shell.

For interactive help, type "help".

For more comprehensive documentation, see

        http://docs.mongodb.org/

Questions? Try the support group

        http://groups.google.com/group/mongodb-user

Server has startup warnings:

2020-03-15T04:12:20.040+0900 I STORAGE  [initandlisten]

2020-03-15T04:12:20.040+0900 I STORAGE  [initandlisten] ** WARNING: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine

2020-03-15T04:12:20.040+0900 I STORAGE  [initandlisten] **          See http://dochub.mongodb.org/core/prodnotes-filesystem

2020-03-15T04:12:26.952+0900 I CONTROL  [initandlisten]

2020-03-15T04:12:26.952+0900 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.

2020-03-15T04:12:26.952+0900 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.

2020-03-15T04:12:26.952+0900 I CONTROL  [initandlisten]

 

> show dbs

admin   0.000GB

config  0.000GB

local   0.000GB

 

> use tutorial

switched to db tutorial

 

> show dbs

admin   0.000GB

config  0.000GB

local   0.000GB

 

> db.book.insert({"name": "Tutorial", "author": "whatwant"});

WriteResult({ "nInserted" : 1 })

 

> show dbs

admin     0.000GB

config    0.000GB

local     0.000GB

tutorial  0.000GB

 

> ^C

bye

 

 

반응형

+ Recent posts