Compare commits
15 Commits
7225e53760
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| a851025e43 | |||
| 722d5dbfaf | |||
| c35c042afa | |||
| d3de1706be | |||
| bf1c660ed9 | |||
| 3087d9cc11 | |||
| a403850ca2 | |||
| b10a88d5d2 | |||
| ae069f460f | |||
| 2e101e6d9d | |||
| f03c11f53a | |||
| 2476953a4b | |||
| d24254fffc | |||
| 4f2c886825 | |||
| 4510784946 |
@@ -34,7 +34,7 @@ jobs:
|
|||||||
username: ${{ secrets.GCE_USERNAME }}
|
username: ${{ secrets.GCE_USERNAME }}
|
||||||
key: ${{ secrets.GCE_SSH_KEY }}
|
key: ${{ secrets.GCE_SSH_KEY }}
|
||||||
source: "deploy.tar.gz"
|
source: "deploy.tar.gz"
|
||||||
target: "/home/dihwang/white-smith-blog"
|
target: "/var/www/white-smith-blog"
|
||||||
|
|
||||||
- name: Extract Archive on GCE
|
- name: Extract Archive on GCE
|
||||||
uses: appleboy/ssh-action@master
|
uses: appleboy/ssh-action@master
|
||||||
@@ -43,9 +43,17 @@ jobs:
|
|||||||
username: ${{ secrets.GCE_USERNAME }}
|
username: ${{ secrets.GCE_USERNAME }}
|
||||||
key: ${{ secrets.GCE_SSH_KEY }}
|
key: ${{ secrets.GCE_SSH_KEY }}
|
||||||
script: |
|
script: |
|
||||||
cd /home/dihwang/white-smith-blog/public
|
# 1. 대상 폴더가 없으면 미리 생성 (cd 실패 방지)
|
||||||
# 3. 서버에 남아있는 유령 파일들 싹 제거 (매우 중요)
|
mkdir -p /var/www/white-smith-blog/public
|
||||||
find . -mindepth 1 -delete
|
|
||||||
# 4. 압축 해제
|
# 2. 폴더 이동에 성공했을 때만(&&) 내부 파일 삭제 및 압축 해제 진행
|
||||||
tar -xzf ../deploy.tar.gz
|
cd /var/www/white-smith-blog/public && {
|
||||||
rm ../deploy.tar.gz
|
# 현재 폴더(public) 내의 모든 파일/폴더 삭제 (점 파일 포함)
|
||||||
|
find . -mindepth 1 -delete
|
||||||
|
|
||||||
|
# 상위 폴더에 전송된 압축 파일 해제
|
||||||
|
tar -xzf ../deploy.tar.gz
|
||||||
|
|
||||||
|
# 작업 완료 후 압축 파일 삭제
|
||||||
|
rm ../deploy.tar.gz
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
[[꼭 알아둬야 할 것들]]
|
||||||
|
|
||||||
|
[[AWS Architecture로의 전환이 필요한 이유]] (As-Is)
|
||||||
|
|
||||||
|
[[온프레미스에서 EC2 기반으로]]
|
||||||
|
|
||||||
|
[[컨테이너 기반의 아키텍처]] (To-Be)
|
||||||
|
|
||||||
|
[[ECS와 EKS]]
|
||||||
|
|
||||||
|
[[EKS Cluster]]
|
||||||
|
|
||||||
|
[[AWS ECS 구성하기]]
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
id: "CMMS 마이그레이션 20260319"
|
||||||
|
created: "2026-03-19 12:58"
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
마이그레이션: 신규 고객의 셋업작업 진행 시 필요한 데이터를 DB로 밀어넣는 과정
|
||||||
|
|
||||||
|
|
||||||
|
엑셀파일로 된 마이그레이션 필요 문서 작성 (담당자가 따로있나봄)
|
||||||
|
(원본엑셀 -> 마이그레이션 할 데이터 엑셀 )
|
||||||
|
|
||||||
|
/auth/fullmigration
|
||||||
|
( CMMS 엔터프라이즈형은 /auth/mig )
|
||||||
|
마이그레이션 페이지가 따로 만들어져있음.
|
||||||
|
|
||||||
|
여기서 엑셀파일들을 전부 다 execute migration 진행해줘야 함
|
||||||
|
너무 많은 데이터를 한번에 시도하면 문제가 될 수 있어서
|
||||||
|
분리해서 진행해야함.
|
||||||
|
|
||||||
|
|
||||||
|
파일 마이그레이션은 암호화(확장자없는) 파일을 먼저 만들고 (엑셀파일부터 작성)
|
||||||
|
...? 그다음에 뭘 또 해야한다는데 이건 이해 못함
|
||||||
|
|
||||||
|
|
||||||
|
shared-service: 마이그레이션, open API (우리는 일단 신경x) 등등의 기능들을 처리해주는 서비스
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[[VPN으로 외부 DB에 접근]]
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[[마력과 토크, RPM]]
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[[Gitea & Quartz 배포 자동화 트러블슈팅]]
|
||||||
|
|
||||||
|
[[gitea, qurtz 설치]]
|
||||||
|
|
||||||
|
[[kui-vault]]
|
||||||
|
|
||||||
|
[[WebHook]]
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
[[안드로이드 스튜디오 무선디버깅]]
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[[전표처리]]
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
title: 1. 프로젝트
|
||||||
|
---
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
### Coding Agent
|
||||||
|
[[Aider 사용기]]
|
||||||
|
[[Aider 프로젝트 생성]]
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[[Functional Domain Modeling]]
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[[파이썬(python) 통찰]]
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[[VPN으로 외부 DB에 접근]]
|
||||||
|
|
||||||
|
[[Pc끼리 Lan선으로 Direct 연결]]
|
||||||
|
|
||||||
|
[[RS-232와 이더넷 통신]]
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[[리눅스(Linux)]]
|
||||||
|
[[리눅스의 파일시스템]]
|
||||||
|
|
||||||
|
[[유닉스(Unix)]]
|
||||||
|
[[유닉스 철학 (The Unix Philosophy)]]
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
### Server
|
||||||
|
[[어플리케이션(서비스) 실행 시 계정 구분하는 이유]]
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
1. [[단순함의 노하우(Introduction)]]
|
||||||
|
|
||||||
|
2. [[80대20 원칙(The Pareto Principle)]]
|
||||||
|
|
||||||
|
3. [[최소 기능 제품 (MVP)]]
|
||||||
|
|
||||||
|
4. [[코딩 원칙 (YAGNI, KISS, DRY)]]
|
||||||
|
|
||||||
|
5. [[유닉스 철학 (The Unix Philosophy)]]
|
||||||
|
|
||||||
|
6. [[설계와 추상화]]
|
||||||
|
|
||||||
|
7. [[디버깅과 테스트]]
|
||||||
|
|
||||||
|
8. [[협업과 지속 가능한 개발]]
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
id: "Aider 단축키 20260413"
|
||||||
|
created: "2026-04-13 13:35"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
| **명령어** | **설명** | **비고** |
|
||||||
|
| --------------- | --------------------------------- | ----------------------------------- |
|
||||||
|
| **/undo** | **AI가 방금 수정한 코드를 취소하고 직전 상태로 복구** | 가장 자주 쓰임 |
|
||||||
|
| **/add <파일>** | 수정하거나 참고할 파일을 채팅창에 추가 | 파일명 일부만 쳐도 자동완성 |
|
||||||
|
| **/drop <파일>** | 채팅창에서 특정 파일 제외 | 실제 파일이 삭제되지는 않음 |
|
||||||
|
| **/ls** | 현재 채팅창에 포함된 파일 목록 확인 | |
|
||||||
|
| **/diff** | 마지막 수정 사항의 변경 전/후 차이점 표시 | |
|
||||||
|
| **/test <명령어>** | 테스트 명령을 실행하고 실패 시 AI가 자동 수정 | 예: `/test pytest` |
|
||||||
|
| **/model <모델>** | 사용 중인 AI 모델을 즉시 변경 | 예: `/model gemini/gemini-2.5-flash` |
|
||||||
|
| **/tokens** | 현재 세션의 토큰 사용량과 비용 정보 확인 | |
|
||||||
|
| **/run <명령어>** | 에이더를 나가지 않고 터미널 명령어 실행 | 예: `/run ls -al` |
|
||||||
|
| **/exit** | 에이더 종료 | `/quit`과 동일 |
|
||||||
|
| **/help** | 모든 명령어 목록과 상세 도움말 확인 | |
|
||||||
|
| **명령어** | **용도** | **특징** |
|
||||||
|
| **/ask <질문>** | 코드에 대해 질문하기 | 코드를 **직접 수정하지 않고** 설명만 해줍니다. |
|
||||||
|
| **/chat <메시지>** | 일반적인 대화/토론 | 파일 수정 없이 구현 방법이나 구조에 대해 논의할 때 씁니다. |
|
||||||
|
| **/code <명령>** | 코드 수정 요청 | 기본 모드입니다. 지시한 대로 파일을 직접 수정합니다. |
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
---
|
||||||
|
id: Aider 20260409
|
||||||
|
created: 2026-04-09 15:19
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
시작은 단순했다.
|
||||||
|
> [!question]
|
||||||
|
> Q. ai agent가 뭐야
|
||||||
|
>
|
||||||
|
> A. **AI 에이전트(AI Agent)**는 단순히 질문에 답하는 챗봇을 넘어, 사용자가 설정한 **목표(Goal)**를 달성하기 위해 스스로 계획을 세우고, 도구를 사용하며, 실행까지 완료하는 **자율적 소프트웨어**를 의미합니다.
|
||||||
|
|
||||||
|
난 이정도까지 바란건 아니었는데
|
||||||
|
|
||||||
|
|
||||||
|
> [!question]
|
||||||
|
> Q. 내가원하는건 너랑 대화하듯이 cli 같은 환경을 통해 대화하는데 ai가 내가 원하는 방향대로 실제 내 파일을 수정해주는거야 내가 복사 붙여넣기 해야하는게 아니고
|
||||||
|
>
|
||||||
|
> A. 지금 말씀하신 방식은 단순한 채팅을 넘어선 **코딩 에이전트(Coding Agent)** 혹은 **엔지니어링 에이전트**의 전형적인 모습이네요. 복사 붙여넣기 없이 AI가 직접 파일을 수정하고 실행하려면, AI에게 내 PC의 파일 시스템에 접근할 수 있는 **권한(Capability)**과 **도구(Tools)**가 있어야 합니다.
|
||||||
|
>
|
||||||
|
> 현재 이런 경험을 제공하는 대표적인 도구들과 작동 원리를 정리해 드릴게요.
|
||||||
|
|
||||||
|
## 1. 지금 바로 사용할 수 있는 대표적인 도구
|
||||||
|
|
||||||
|
### **Cursor (커서)**
|
||||||
|
|
||||||
|
가장 대중적이고 완성도가 높습니다. VS Code를 포크(Fork)해서 만든 에디터라 사용법이 익숙합니다.
|
||||||
|
|
||||||
|
- **작동 방식:** 채팅창에서 `Command + K`나 `L`을 눌러 수정 요청을 하면, AI가 코드를 직접 작성하고 사용자가 **[Accept]** 버튼만 누르면 파일에 바로 반영됩니다.
|
||||||
|
|
||||||
|
- **장점:** 에디터와 일체화되어 있어 흐름이 매우 매끄럽습니다.
|
||||||
|
|
||||||
|
|
||||||
|
### **Aider (에이더)**
|
||||||
|
|
||||||
|
질문하신 **CLI 환경**에 가장 부합하는 강력한 도구입니다. 터미널(Terminal)에서 직접 실행합니다.
|
||||||
|
|
||||||
|
- **작동 방식:** 터미널에서 `aider`를 실행하고 대화하면, AI가 로컬 파일을 읽고 직접 수정(Edit)한 뒤 자동으로 **Git Commit**까지 남겨줍니다.
|
||||||
|
|
||||||
|
- **장점:** 복사 붙여넣기가 전혀 필요 없고, 터미널 기반이라 개발 환경에 통합하기 좋습니다.
|
||||||
|
|
||||||
|
|
||||||
|
### **Cline (구 Claude Dev)**
|
||||||
|
|
||||||
|
VS Code의 확장 프로그램(Extension)으로, 최근 가장 핫한 오픈소스 에이전트입니다.
|
||||||
|
|
||||||
|
- **작동 방식:** 파일 읽기/쓰기, 터미널 명령 실행, 브라우저 실행 권한을 AI에게 부여합니다. "이 프로젝트 빌드해보고 에러 나면 고쳐줘"라고 하면 스스로 파일을 수정하고 터미널에서 테스트까지 돌려봅니다.
|
||||||
|
|
||||||
|
## 추천하는 시작 방법
|
||||||
|
|
||||||
|
==만약 **CLI 환경**을 선호하신다면 **Aider**를 먼저 써보시는 걸 강력 추천합니다.==
|
||||||
|
|
||||||
|
Aider를 써보기로 함
|
||||||
|
|
||||||
|
이거 설치방법같은건 못적겠다.
|
||||||
|
변수도 너무 많고 내용도 너무 길고 그냥 ai한테 물어보면 알아서 잘 설명해주는데..
|
||||||
|
|
||||||
|
|
||||||
|
> [!warning] 파이썬은 3.12.10 을 설치하자
|
||||||
|
|
||||||
|
처음에 3.14가 깔려있었는데 에이더가 제대로 설치가 안되고 에러가 났었음.
|
||||||
|
Stable 버전인 3.13으로 다시 설치했는데 이것도 에러났음
|
||||||
|
3.12로 설치하니까 에러가 발생되지 않았음.
|
||||||
|
파이썬 버전은 3.12.13까지 있지만 3.12.10까지만 설치 installer가 제공되니까 3.12.10을 설치하자.
|
||||||
|
(이게 마음이 편할거 같음)
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
C:\Users\Administrator\MyFolder\test\aider
|
||||||
|
```
|
||||||
|
이 경로에 설치했음 나는
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Administrator@DESKTOP-UUOTCE2 MINGW64 ~/MyFolder/test/aider (master)
|
||||||
|
$ aider --version
|
||||||
|
aider 0.86.2
|
||||||
|
```
|
||||||
|
진짜 힘들게설치함;
|
||||||
@@ -0,0 +1,689 @@
|
|||||||
|
---
|
||||||
|
id: "Aider 최초 사용 20260413"
|
||||||
|
created: "2026-04-13 14:01"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
Gemini를 채찍질해서 아래의 명세를 가지는 VaultKeeper 어플리케이션 구상을 함.
|
||||||
|
( kui-veil 서버의 auth 관리 어플리케이션임 )
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 🏗️ VaultKeeper 프로젝트 상세 설계도 (Ver 2.0)
|
||||||
|
|
||||||
|
### 1. 개요
|
||||||
|
|
||||||
|
- **목적**: Nginx의 `.htpasswd` 파일을 웹 GUI를 통해 관리하는 초경량 도구.
|
||||||
|
|
||||||
|
- **타겟 환경**: Google Cloud e2-micro (저사양 서버).
|
||||||
|
|
||||||
|
- **주요 언어**: **Go** (백엔드), **Vanilla JS** (프론트엔드).
|
||||||
|
|
||||||
|
|
||||||
|
### 2. 보안 전략 (핵심)
|
||||||
|
|
||||||
|
- **인증 분리**: 백엔드 자체에 로그인 로직을 구현하지 않고, Nginx의 `auth_basic` 모듈에 인증을 위임함.
|
||||||
|
|
||||||
|
- **접근 권한**: 서버 관리자가 터미널에서 직접 생성한 계정으로만 웹 UI에 접근 가능.
|
||||||
|
|
||||||
|
- **입력값 검증**: `os/exec` 실행 시 쉘 인젝션을 방지하기 위해 사용자 이름에 특수문자 입력을 제한함.
|
||||||
|
|
||||||
|
|
||||||
|
### 3. 구성 요소
|
||||||
|
|
||||||
|
- **Backend (`main.go`)**:
|
||||||
|
|
||||||
|
- 환경 변수 `HTPASSWD_PATH`를 통해 대상 파일 경로 지정.
|
||||||
|
|
||||||
|
- 표준 패키지 `net/http`를 사용하여 메모리 점유 최소화.
|
||||||
|
|
||||||
|
- `htpasswd` 시스템 명령어를 서브프로세스로 호출하여 계정 추가/삭제.
|
||||||
|
|
||||||
|
- **Frontend (`index.html`)**:
|
||||||
|
|
||||||
|
- 단일 파일 SPA 구조.
|
||||||
|
|
||||||
|
- Tailwind CSS(CDN)를 활용한 직관적인 대시보드.
|
||||||
|
```
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
|
||||||
|
## 🤖 에이더(Aider)를 위한 최종 지시서
|
||||||
|
|
||||||
|
아래 내용을 에이더 채팅창에 입력하시면 됩니다.
|
||||||
|
|
||||||
|
**프로젝트: VaultKeeper (Nginx .htpasswd 관리 도구)**
|
||||||
|
|
||||||
|
**1. 백엔드 구현 (`main.go`)**
|
||||||
|
|
||||||
|
- **언어**: Go (표준 라이브러리 위주로 매우 가볍게).
|
||||||
|
|
||||||
|
- **기능**:
|
||||||
|
|
||||||
|
- `GET /api/users`: `.htpasswd` 파일을 읽어 유저 목록을 JSON으로 반환.
|
||||||
|
|
||||||
|
- `POST /api/users`: `username`, `password`를 받아 `htpasswd -b` 실행.
|
||||||
|
|
||||||
|
- `DELETE /api/users/{username}`: `htpasswd -D` 실행.
|
||||||
|
|
||||||
|
- **보안**: 사용자 이름 입력값에서 쉘 인젝션이 발생하지 않도록 유효성 검사 로직 포함.
|
||||||
|
|
||||||
|
- **설정**: `.htpasswd` 경로를 환경 변수 `HTPASSWD_PATH`에서 읽어오도록 설정.
|
||||||
|
|
||||||
|
|
||||||
|
**2. 프론트엔드 구현 (`index.html`)**
|
||||||
|
|
||||||
|
- 단일 파일 SPA로 작성하고 Tailwind CSS를 사용하여 깔끔한 UI 제공.
|
||||||
|
|
||||||
|
- 유저 목록 표시, 추가 폼, 삭제 버튼 구현.
|
||||||
|
|
||||||
|
|
||||||
|
**3. 배포 가이드 (`deployment.md`) 생성**
|
||||||
|
|
||||||
|
- `go build`를 이용한 경량 바이너리 빌드 방법 (`-s -w` 옵션 포함).
|
||||||
|
|
||||||
|
- 터미널에서 최초 관리자 계정을 생성하는 명령어 안내.
|
||||||
|
|
||||||
|
- 이 서비스를 Nginx `auth_basic` 뒤에 배치하기 위한 `location` 블록 설정 예시. (8000번 포트 기준)
|
||||||
|
|
||||||
|
|
||||||
|
**주의**: 모든 코드와 문서에서 특정 개인의 이름이나 개인정보를 절대 포함하지 말고 `Admin` 또는 `User`와 같은 공용 용어만 사용해줘.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
이걸 aider에게 먹이고 (add)
|
||||||
|
```bash
|
||||||
|
────────────────────────────────────────────────────────────────────────────────
|
||||||
|
> /add "doc/vault-keeper 상세 설계도.txt" "doc/지시서.txt"
|
||||||
|
|
||||||
|
Added doc\vault-keeper 상세 설계도.txt to the chat
|
||||||
|
Added doc\지시서.txt to the chat
|
||||||
|
────────────────────────────────────────────────────────────────────────────────
|
||||||
|
```
|
||||||
|
|
||||||
|
진행해보라고 했다.
|
||||||
|
```bash
|
||||||
|
doc\vault-keeper 상세 설계도.txt doc\지시서.txt
|
||||||
|
> 내가 추가한 상세 설계도와 지시서를 바탕으로 어플리케이션을 만들어봐
|
||||||
|
```
|
||||||
|
|
||||||
|
과연.. 결과는?
|
||||||
|
어.. 뭔가 만들어지긴 했다..
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
아래는 콘솔에 찍힌 내용 전체
|
||||||
|
|
||||||
|
|
||||||
|
요청하신 내용에 따라 애플리케이션을 만들겠습니다. main.go, index.html, deployment.md 파일을 새로 생성합니다.
|
||||||
|
|
||||||
|
다음은 필요한 SEARCH/REPLACE 블록입니다:
|
||||||
|
|
||||||
|
|
||||||
|
main.go
|
||||||
|
<<<<<<< SEARCH
|
||||||
|
=======
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// User는 .htpasswd 파일의 사용자 정보를 나타냅니다.
|
||||||
|
type User struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddUserRequest는 새 사용자 추가 요청에 사용됩니다.
|
||||||
|
type AddUserRequest struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
htpasswdPath string
|
||||||
|
htpasswdMutex sync.Mutex // htpasswd 명령 실행 시 동시성 문제를 방지하기 위한 뮤텍스
|
||||||
|
usernameRegex *regexp.Regexp // 사용자 이름 유효성 검사를 위한 정규식
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// HTPASSWD_PATH 환경 변수 설정
|
||||||
|
htpasswdPath = os.Getenv("HTPASSWD_PATH")
|
||||||
|
if htpasswdPath == "" {
|
||||||
|
log.Fatal("환경 변수 HTPASSWD_PATH가 설정되지 않았습니다.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 사용자 이름 유효성 검사 정규식 초기화: 영문, 숫자, 하이픈, 언더스코어만 허용
|
||||||
|
usernameRegex = regexp.MustCompile("^[a-zA-Z0-9_-]+$")
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
|
// 정적 파일(index.html) 제공
|
||||||
|
mux.HandleFunc("/", serveFrontend)
|
||||||
|
|
||||||
|
// API 엔드포인트
|
||||||
|
mux.HandleFunc("/api/users", handleUsers)
|
||||||
|
mux.HandleFunc("/api/users/", handleDeleteUser) // DELETE 요청 처리
|
||||||
|
|
||||||
|
log.Println("VaultKeeper 서버가 8000 포트에서 시작됩니다.")
|
||||||
|
log.Printf("HTPASSWD_PATH: %s\n", htpasswdPath)
|
||||||
|
log.Fatal(http.ListenAndServe(":8000", mux))
|
||||||
|
}
|
||||||
|
|
||||||
|
// serveFrontend는 index.html 파일을 제공합니다.
|
||||||
|
func serveFrontend(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.URL.Path == "/" || r.URL.Path == "/index.html" {
|
||||||
|
http.ServeFile(w, r, "index.html")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.NotFound(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleUsers는 GET /api/users 및 POST /api/users 요청을 처리합니다.
|
||||||
|
func handleUsers(w http.ResponseWriter, r *http.Request) {
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodGet:
|
||||||
|
getUsers(w, r)
|
||||||
|
case http.MethodPost:
|
||||||
|
addUser(w, r)
|
||||||
|
default:
|
||||||
|
http.Error(w, "허용되지 않는 메소드입니다.", http.StatusMethodNotAllowed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getUsers는 .htpasswd 파일에서 사용자 목록을 읽어 JSON으로 반환합니다.
|
||||||
|
func getUsers(w http.ResponseWriter, r *http.Request) {
|
||||||
|
htpasswdMutex.Lock()
|
||||||
|
defer htpasswdMutex.Unlock()
|
||||||
|
|
||||||
|
file, err := os.Open(htpasswdPath)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
// 파일이 없으면 빈 목록 반환 (처음 생성 시)
|
||||||
|
json.NewEncoder(w).Encode([]User{})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error opening .htpasswd file: %v", err)
|
||||||
|
http.Error(w, "사용자 파일을 읽을 수 없습니다.", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
var users []User
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if len(line) > 0 && !strings.HasPrefix(line, "#") { // 주석 및 빈 줄 무시
|
||||||
|
parts := strings.SplitN(line, ":", 2)
|
||||||
|
if len(parts) > 0 {
|
||||||
|
users = append(users, User{Username: parts[0]})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
log.Printf("Error scanning .htpasswd file: %v", err)
|
||||||
|
http.Error(w, "사용자 파일을 스캔할 수 없습니다.", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(users)
|
||||||
|
}
|
||||||
|
|
||||||
|
// addUser는 새 사용자를 .htpasswd 파일에 추가합니다.
|
||||||
|
func addUser(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req AddUserRequest
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
http.Error(w, "유효하지 않은 요청 본문입니다.", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 사용자 이름 유효성 검사
|
||||||
|
if !usernameRegex.MatchString(req.Username) {
|
||||||
|
http.Error(w, "사용자 이름은 영문, 숫자, 하이픈, 언더스코어만 포함할 수 있습니다.", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if req.Username == "" || req.Password == "" {
|
||||||
|
http.Error(w, "사용자 이름과 비밀번호는 필수입니다.", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
htpasswdMutex.Lock()
|
||||||
|
defer htpasswdMutex.Unlock()
|
||||||
|
|
||||||
|
// htpasswd -b <file> <username> <password>
|
||||||
|
// 파일이 없으면 -c 옵션이 필요하지만, 첫 생성은 터미널에서 하도록 가이드하므로 여기서는 -b만 사용.
|
||||||
|
// -b는 파일이 없으면 생성하고, 있으면 추가/수정합니다.
|
||||||
|
cmd := exec.Command("htpasswd", "-b", htpasswdPath, req.Username, req.Password)
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error executing htpasswd -b: %v, Output: %s", err, output)
|
||||||
|
http.Error(w, fmt.Sprintf("사용자 추가 실패: %s", strings.TrimSpace(string(output))), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusCreated)
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"message": "사용자가 성공적으로 추가되었습니다."})
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleDeleteUser는 DELETE /api/users/{username} 요청을 처리합니다.
|
||||||
|
func handleDeleteUser(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodDelete {
|
||||||
|
http.Error(w, "허용되지 않는 메소드입니다.", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
username := strings.TrimPrefix(r.URL.Path, "/api/users/")
|
||||||
|
if username == "" {
|
||||||
|
http.Error(w, "사용자 이름을 지정해야 합니다.", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 사용자 이름 유효성 검사 (삭제도 동일하게 적용)
|
||||||
|
if !usernameRegex.MatchString(username) {
|
||||||
|
http.Error(w, "유효하지 않은 사용자 이름 형식입니다.", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
htpasswdMutex.Lock()
|
||||||
|
defer htpasswdMutex.Unlock()
|
||||||
|
|
||||||
|
// htpasswd -D <file> <username>
|
||||||
|
cmd := exec.Command("htpasswd", "-D", htpasswdPath, username)
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
// htpasswd -D는 사용자가 존재하지 않을 경우에도 에러를 반환합니다.
|
||||||
|
// 그러나 사용자 삭제 요청 자체는 성공했다고 간주할 수 있습니다 (해당 사용자가 없는 상태이므로).
|
||||||
|
// 실제 htpasswd의 에러 메시지를 확인하여 사용자 부재인지 다른 에러인지 구분할 수 있으나,
|
||||||
|
// 간단하게 사용자 부재 메시지가 아니라면 서버 에러로 처리합니다.
|
||||||
|
if strings.Contains(strings.ToLower(string(output)), "not found") {
|
||||||
|
http.Error(w, fmt.Sprintf("사용자 '%s'를 찾을 수 없습니다.", username), http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("Error executing htpasswd -D: %v, Output: %s", err, output)
|
||||||
|
http.Error(w, fmt.Sprintf("사용자 삭제 실패: %s", strings.TrimSpace(string(output))), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"message": fmt.Sprintf("사용자 '%s'가 성공적으로 삭제되었습니다.", username)})
|
||||||
|
}
|
||||||
|
>>>>>>> REPLACE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
index.html
|
||||||
|
<<<<<<< SEARCH
|
||||||
|
=======
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>VaultKeeper - Nginx .htpasswd 관리</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #f3f4f6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="font-sans antialiased text-gray-900">
|
||||||
|
<div class="min-h-screen flex flex-col items-center justify-center p-4">
|
||||||
|
<div class="w-full max-w-2xl bg-white rounded-lg shadow-xl p-8 space-y-8">
|
||||||
|
<h1 class="text-3xl font-bold text-center text-gray-800">VaultKeeper</h1>
|
||||||
|
<p class="text-center text-gray-600">Nginx .htpasswd 파일 관리</p>
|
||||||
|
|
||||||
|
<!-- 사용자 추가 폼 -->
|
||||||
|
<div class="border-t border-gray-200 pt-8">
|
||||||
|
<h2 class="text-2xl font-semibold text-gray-800 mb-4">새 사용자 추가</h2>
|
||||||
|
<form id="addUserForm" class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label for="username" class="block text-sm font-medium text-gray-700">사용자 이름</label>
|
||||||
|
<input type="text" id="username" name="username" required
|
||||||
|
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none
|
||||||
|
focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="password" class="block text-sm font-medium text-gray-700">비밀번호</label>
|
||||||
|
<input type="password" id="password" name="password" required
|
||||||
|
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none
|
||||||
|
focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
|
||||||
|
</div>
|
||||||
|
<button type="submit"
|
||||||
|
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm
|
||||||
|
font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||||
|
사용자 추가
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
<div id="addMessage" class="mt-3 text-center font-medium"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 사용자 목록 -->
|
||||||
|
<div class="border-t border-gray-200 pt-8">
|
||||||
|
<h2 class="text-2xl font-semibold text-gray-800 mb-4">현재 사용자 목록</h2>
|
||||||
|
<div id="userListContainer">
|
||||||
|
<ul id="userList" class="divide-y divide-gray-200 bg-white rounded-md shadow-sm">
|
||||||
|
<!-- 사용자는 여기에 동적으로 로드됩니다. -->
|
||||||
|
</ul>
|
||||||
|
<p id="noUsersMessage" class="text-center text-gray-500 mt-4 hidden">등록된 사용자가 없습니다.</p>
|
||||||
|
</div>
|
||||||
|
<div id="listMessage" class="mt-3 text-center font-medium"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const addUserForm = document.getElementById('addUserForm');
|
||||||
|
const usernameInput = document.getElementById('username');
|
||||||
|
const passwordInput = document.getElementById('password');
|
||||||
|
const addMessageDiv = document.getElementById('addMessage');
|
||||||
|
const userList = document.getElementById('userList');
|
||||||
|
const noUsersMessage = document.getElementById('noUsersMessage');
|
||||||
|
const listMessageDiv = document.getElementById('listMessage');
|
||||||
|
|
||||||
|
async function fetchUsers() {
|
||||||
|
listMessageDiv.textContent = '';
|
||||||
|
userList.innerHTML = '';
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/users');
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
const users = await response.json();
|
||||||
|
if (users.length === 0) {
|
||||||
|
noUsersMessage.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
noUsersMessage.classList.add('hidden');
|
||||||
|
users.forEach(user => {
|
||||||
|
const li = document.createElement('li');
|
||||||
|
li.className = 'flex items-center justify-between p-4 hover:bg-gray-50';
|
||||||
|
li.innerHTML = `
|
||||||
|
<span class="text-lg font-medium">${user.username}</span>
|
||||||
|
<button data-username="${user.username}"
|
||||||
|
class="delete-btn bg-red-500 hover:bg-red-600 text-white font-bold py-1 px-3 rounded text-sm">
|
||||||
|
삭제
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
userList.appendChild(li);
|
||||||
|
});
|
||||||
|
addDeleteEventListeners();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching users:', error);
|
||||||
|
listMessageDiv.textContent = `사용자 목록을 불러오는 데 실패했습니다: ${error.message}`;
|
||||||
|
listMessageDiv.className = 'mt-3 text-center font-medium text-red-600';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addUser(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
addMessageDiv.textContent = '';
|
||||||
|
|
||||||
|
const username = usernameInput.value;
|
||||||
|
const password = passwordInput.value;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/users', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ username, password }),
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(data.message || '사용자 추가 실패');
|
||||||
|
}
|
||||||
|
|
||||||
|
addMessageDiv.textContent = data.message;
|
||||||
|
addMessageDiv.className = 'mt-3 text-center font-medium text-green-600';
|
||||||
|
usernameInput.value = '';
|
||||||
|
passwordInput.value = '';
|
||||||
|
fetchUsers(); // 사용자 목록 새로 고침
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error adding user:', error);
|
||||||
|
addMessageDiv.textContent = `사용자 추가 실패: ${error.message}`;
|
||||||
|
addMessageDiv.className = 'mt-3 text-center font-medium text-red-600';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteUser(username) {
|
||||||
|
listMessageDiv.textContent = '';
|
||||||
|
if (!confirm(`사용자 '${username}'을(를) 정말 삭제하시겠습니까?`)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/users/${username}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(data.message || '사용자 삭제 실패');
|
||||||
|
}
|
||||||
|
|
||||||
|
listMessageDiv.textContent = data.message;
|
||||||
|
listMessageDiv.className = 'mt-3 text-center font-medium text-green-600';
|
||||||
|
fetchUsers(); // 사용자 목록 새로 고침
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting user:', error);
|
||||||
|
listMessageDiv.textContent = `사용자 삭제 실패: ${error.message}`;
|
||||||
|
listMessageDiv.className = 'mt-3 text-center font-medium text-red-600';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addDeleteEventListeners() {
|
||||||
|
document.querySelectorAll('.delete-btn').forEach(button => {
|
||||||
|
button.onclick = () => deleteUser(button.dataset.username);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addUserForm.addEventListener('submit', addUser);
|
||||||
|
|
||||||
|
// 페이지 로드 시 사용자 목록 가져오기
|
||||||
|
fetchUsers();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
>>>>>>> REPLACE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
deployment.md
|
||||||
|
<<<<<<< SEARCH
|
||||||
|
=======
|
||||||
|
# VaultKeeper 배포 가이드
|
||||||
|
|
||||||
|
이 문서는 VaultKeeper 애플리케이션의 빌드, 초기 설정 및 Nginx 연동 방법을 안내합니다.
|
||||||
|
|
||||||
|
## 1. 백엔드 빌드
|
||||||
|
|
||||||
|
Go 바이너리를 가볍게 빌드하려면 다음 명령어를 사용합니다. 이 명령어는 디버그 정보를 제거하고 심볼 테이블을 생략하여 최종 바이너리
|
||||||
|
크기를 줄입니다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build -o vaultkeeper -ldflags "-s -w" main.go
|
||||||
|
|
||||||
|
|
||||||
|
빌드가 완료되면 현재 디렉토리에 vaultkeeper 실행 파일이 생성됩니다.
|
||||||
|
|
||||||
|
|
||||||
|
2. .htpasswd 파일 경로 설정
|
||||||
|
|
||||||
|
VaultKeeper는 .htpasswd 파일의 경로를 환경 변수 HTPASSWD_PATH를 통해 설정합니다. 애플리케이션을 실행하기 전에 이 환경 변수를 설정해야
|
||||||
|
합니다.
|
||||||
|
|
||||||
|
예시:
|
||||||
|
|
||||||
|
|
||||||
|
export HTPASSWD_PATH="/etc/nginx/.htpasswd"
|
||||||
|
|
||||||
|
|
||||||
|
또는
|
||||||
|
|
||||||
|
|
||||||
|
export HTPASSWD_PATH="/usr/local/etc/htpasswd"
|
||||||
|
|
||||||
|
|
||||||
|
주의: 지정된 경로에 Nginx가 실제로 사용하는 .htpasswd 파일이 있어야 합니다. 쓰기 권한도 필요합니다.
|
||||||
|
|
||||||
|
|
||||||
|
3. 최초 관리자 계정 생성 (터미널)
|
||||||
|
|
||||||
|
VaultKeeper는 자체 로그인 로직을 포함하지 않으며, Nginx auth_basic 모듈에 인증을 위임합니다. 웹 UI에 접근하려면 Nginx를 통해 인증할 수
|
||||||
|
있는 계정이 필요합니다. 최초 관리자 계정은 VaultKeeper가 실행되기 전에 터미널에서 htpasswd 명령어를 사용하여 생성해야 합니다.
|
||||||
|
|
||||||
|
.htpasswd 파일이 아직 없는 경우:
|
||||||
|
|
||||||
|
|
||||||
|
htpasswd -c /etc/nginx/.htpasswd adminuser
|
||||||
|
|
||||||
|
|
||||||
|
adminuser를 원하는 관리자 사용자 이름으로 바꾸세요. 이 명령어는 /etc/nginx/.htpasswd 파일을 생성하고 adminuser를 추가합니다.
|
||||||
|
|
||||||
|
.htpasswd 파일이 이미 있는 경우 (새 사용자를 추가하거나 기존 사용자의 비밀번호를 변경):
|
||||||
|
|
||||||
|
|
||||||
|
htpasswd /etc/nginx/.htpasswd anotheruser
|
||||||
|
|
||||||
|
|
||||||
|
-c 옵션을 사용하면 기존 파일이 덮어쓰여지므로 절대 이미 존재하는 파일에 -c 옵션을 다시 사용하지 마세요.
|
||||||
|
|
||||||
|
|
||||||
|
4. VaultKeeper 실행
|
||||||
|
|
||||||
|
환경 변수 설정 및 .htpasswd 파일 준비가 완료되면, 빌드된 VaultKeeper 바이너리를 실행합니다.
|
||||||
|
|
||||||
|
|
||||||
|
./vaultkeeper
|
||||||
|
|
||||||
|
|
||||||
|
기본적으로 VaultKeeper는 8000번 포트에서 수신 대기합니다.
|
||||||
|
|
||||||
|
|
||||||
|
5. Nginx 설정 예시
|
||||||
|
|
||||||
|
Nginx의 auth_basic 모듈 뒤에서 VaultKeeper를 실행하여 접근을 제한할 수 있습니다. 다음은 Nginx 설정 파일 (/etc/nginx/nginx.conf 또는
|
||||||
|
conf.d 내부 파일)에 추가할 수 있는 location 블록 예시입니다.
|
||||||
|
|
||||||
|
이 설정은 /vaultkeeper/ 경로로 들어오는 요청을 VaultKeeper 백엔드(8000번 포트)로 프록시하고, auth_basic을 통해 .htpasswd 파일로 인증을
|
||||||
|
요구합니다.
|
||||||
|
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name your_domain.com; # 도메인 또는 IP 주소로 변경
|
||||||
|
|
||||||
|
location /vaultkeeper/ {
|
||||||
|
auth_basic "Restricted Access";
|
||||||
|
auth_basic_user_file /etc/nginx/.htpasswd; # .htpasswd 파일 경로를 정확히 지정
|
||||||
|
|
||||||
|
proxy_pass http://127.0.0.1:8000/;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_redirect off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 다른 Nginx 설정...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Nginx 설정을 변경한 후에는 반드시 Nginx를 재로드하거나 재시작하여 변경사항을 적용해야 합니다.
|
||||||
|
|
||||||
|
|
||||||
|
sudo nginx -t # 설정 파일 유효성 검사
|
||||||
|
sudo systemctl reload nginx # Nginx 재로드
|
||||||
|
|
||||||
|
|
||||||
|
이제 http://your_domain.com/vaultkeeper/ (또는 http://your_server_ip/vaultkeeper/)로 접근하여 VaultKeeper 웹 UI를 사용할 수 있습니다.
|
||||||
|
접근 시 Nginx가 사용자 이름과 비밀번호를 요청할 것입니다.
|
||||||
|
|
||||||
|
▌ ▌ ▌ ▌ ▌ ▌ ▌ REPLACE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
새로 생성된 파일을 확인하고 싶으시다면, 다음 명령어를 실행하여 바이너리를 빌드하고 서버를 시작할 수 있습니다:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build -o vaultkeeper -ldflags "-s -w" main.go
|
||||||
|
export HTPASSWD_PATH="/tmp/.htpasswd" # 테스트용 임시 경로, 실제 경로로 변경 필요
|
||||||
|
htpasswd -c /tmp/.htpasswd adminuser # 최초 관리자 계정 생성
|
||||||
|
./vaultkeeper
|
||||||
|
|
||||||
|
|
||||||
|
index.html을 브라우저에서 열거나, Nginx를 설정한 후 http://localhost:8000 (또는 Nginx 프록시 설정에 따른 URL)으로 접속하여 프론트엔드를
|
||||||
|
확인할 수 있습니다.
|
||||||
|
|
||||||
|
|
||||||
|
Tokens: 3.3k sent, 5.0k received. Cost: $0.01 message, $0.01 session.
|
||||||
|
|
||||||
|
main.go
|
||||||
|
Create new file? (Y)es/(N)o [Yes]: y
|
||||||
|
|
||||||
|
index.html
|
||||||
|
Create new file? (Y)es/(N)o [Yes]: y
|
||||||
|
|
||||||
|
deployment.md
|
||||||
|
Create new file? (Y)es/(N)o [Yes]: y
|
||||||
|
Applied edit to main.go
|
||||||
|
Applied edit to index.html
|
||||||
|
Applied edit to deployment.md
|
||||||
|
Commit bd414ad feat: 새로운 htpasswd 관리 애플리케이션 VaultKeeper 구현
|
||||||
|
|
||||||
|
go build -o vaultkeeper -ldflags "-s -w" main.go
|
||||||
|
export HTPASSWD_PATH="/tmp/.htpasswd" # 테스트용 임시 경로, 실제 경로로 변경 필요
|
||||||
|
htpasswd -c /tmp/.htpasswd adminuser # 최초 관리자 계정 생성
|
||||||
|
./vaultkeeper
|
||||||
|
Run shell commands? (Y)es/(N)o/(D)on't ask again [Yes]: y
|
||||||
|
|
||||||
|
Running go build -o vaultkeeper -ldflags "-s -w" main.go
|
||||||
|
|
||||||
|
Running export HTPASSWD_PATH="/tmp/.htpasswd" # 테스트용 임시 경로, 실제 경로로 변경 필요
|
||||||
|
'export'��(��) ���� �Ǵ� �ܺ� ����, ������ �� �ִ� ���α�, �Ǵ�
|
||||||
|
��ġ ������ �ƴմϴ�.
|
||||||
|
|
||||||
|
Running htpasswd -c /tmp/.htpasswd adminuser # 최초 관리자 계정 생성
|
||||||
|
'htpasswd'��(��) ���� �Ǵ� �ܺ� ����, ������ �� �ִ� ���α�, �Ǵ�
|
||||||
|
��ġ ������ �ƴմϴ�.
|
||||||
|
|
||||||
|
Running ./vaultkeeper
|
||||||
|
'.'��(��) ���� �Ǵ� �ܺ� ����, ������ �� �ִ� ���α�, �Ǵ�
|
||||||
|
��ġ ������ �ƴմϴ�.
|
||||||
|
Add command output to the chat? (Y)es/(N)o/(D)on't ask again [Yes]: y
|
||||||
|
Added 11 lines of output to the chat.
|
||||||
|
You can use /undo to undo and discard each aider commit.
|
||||||
|
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
deployment.md doc\vault-keeper 상세 설계도.txt doc\지시서.txt index.html main.go
|
||||||
|
> /ls
|
||||||
|
|
||||||
|
|
||||||
|
Files in chat:
|
||||||
|
|
||||||
|
deployment.md
|
||||||
|
index.html
|
||||||
|
main.go
|
||||||
|
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
deployment.md doc\vault-keeper 상세 설계도.txt doc\지시서.txt index.html main.go
|
||||||
|
>
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
id: "Aider 프로젝트 생성 20260413"
|
||||||
|
created: "2026-04-13 13:31"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
새로운 프로젝트를 만든다고 가정
|
||||||
|
|
||||||
|
만들고싶은 디렉토리에서
|
||||||
|
|
||||||
|
### 1단계: 프로젝트 폴더 생성 및 이동
|
||||||
|
|
||||||
|
먼저 프로젝트별로 방을 나눠야 합니다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir my-new-project # 원하는 프로젝트 이름으로 생성
|
||||||
|
cd my-new-project
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2단계: Git 초기화 (매우 중요)
|
||||||
|
|
||||||
|
에이더는 작업 내용을 자동으로 기록하고 커밋하기 위해 **Git**을 기반으로 움직입니다. 폴더를 만들자마자 가장 먼저 해야 할 일입니다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git init
|
||||||
|
```
|
||||||
|
|
||||||
|
- 이 과정을 거쳐야 나중에 에이더가 사고를 쳐도 `git checkout` 등으로 안전하게 코드를 복구할 수 있습니다.
|
||||||
|
|
||||||
|
### 3단계: API 키 및 기본 설정 확인
|
||||||
|
|
||||||
|
매번 키를 입력하기 귀찮다면, 아까 논의했던 대로 **환경 변수**나 **설정 파일**이 준비되어 있는지 확인합니다.
|
||||||
|
|
||||||
|
- 이미 윈도우 환경 변수에 `GEMINI_API_KEY`를 등록하셨다면 이 단계는 건너뛰셔도 됩니다.
|
||||||
|
|
||||||
|
- 만약 특정 모델을 고정하고 싶다면 이 폴더에 `.aider.conf.yml` 파일을 만드세요.
|
||||||
|
|
||||||
|
|
||||||
|
### 4단계: 에이더(Aider) 실행
|
||||||
|
|
||||||
|
이제 준비가 끝났습니다. 에이더를 깨웁니다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
aider
|
||||||
|
```
|
||||||
|
|
||||||
|
- 만약 별칭(alias)이나 설정 파일을 만들지 않았다면 직접 모델명을 적어줍니다: `aider --model gemini/gemini-1.5-pro`
|
||||||
|
- pro는 비싸니까 그냥 flash로 하는게 정신건강과 지갑건강상 좋음
|
||||||
|
|
||||||
|
|
||||||
|
### 5단계: 첫 번째 파일 생성 요청
|
||||||
|
|
||||||
|
에이더가 실행되면 AI에게 첫 작업을 시켜보세요.
|
||||||
|
|
||||||
|
- 예: `Hello! 파이썬으로 간단한 계산기 로직이 담긴 calculator.py 파일을 만들어줘.`
|
||||||
|
|
||||||
|
### 최종 결과물 구조
|
||||||
|
|
||||||
|
이렇게 순서대로 진행하면 폴더 안이 아래와 같이 예쁘게 정렬됩니다.
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
workspaces/
|
||||||
|
└── my-new-project/
|
||||||
|
├── .git/ (2단계에서 생성)
|
||||||
|
├── .aider.chat.history.md (4단계 실행 후 생성)
|
||||||
|
├── .aider.tags.cache.v4/ (4단계 실행 후 생성)
|
||||||
|
└── calculator.py (5단계에서 생성됨)
|
||||||
|
```
|
||||||
|
|
||||||
|
**꿀팁:** 작업을 하다가 마음에 안 들면 에이더 채팅창 안에서 `/undo`를 입력하세요. 그러면 에이더가 방금 한 커밋을 취소하고 코드를 직전 상태로 돌려놓습니다.
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
As-Is
|
||||||
|
![[Pasted image 20260227093328.png]]https://wk.wecmms.com
|
||||||
|
https://innox.wecmms.com
|
||||||
|
|
||||||
|
### EC2기반의 아키텍처에는 다음의 한계들을 가짐
|
||||||
|
![[EC2기반 아키텍처의 한계점]]
|
||||||
|
|
||||||
|
|
||||||
|
### 한계를 극복하기 위해 나아가야 할 방향
|
||||||
|
[[서버리스(Serverless)]] 구성
|
||||||
|
: AWS가 제공해주는 [[파게이트(Fargate)]]로 구성한다.
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
id: "AWS ECS 구성하기 20260305"
|
||||||
|
created: "2026-03-05 13:29"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
### ECS
|
||||||
|
![[ECS와 EKS#ECS(Elastic Container Service)]]
|
||||||
|
|
||||||
|
|
||||||
|
[[태스크(Task)]] 구성
|
||||||
|
1) 고객이 완벽한 물리적인 격리를 원할 경우: 3. ECS 클러스터 만들기부터 진행
|
||||||
|
2) 고객이 별도의 물리적인 격리를 원하지 않을 경우: 4. ECS 서비스 만들기부터 진행
|
||||||
|
|
||||||
|
## 🔢 목록
|
||||||
|
|
||||||
|
#### 1. [[ECS와 EKS]]
|
||||||
|
|
||||||
|
#### 2. [[ECS의 구성]]
|
||||||
|
|
||||||
|
#### 3. [[ECS 클러스터 만들기]]
|
||||||
|
|
||||||
|
#### 4. [[ECS 서비스 만들기]]
|
||||||
|
|
||||||
|
만약 [[ECR(Elastic Container Registry)]]에 등록된 컨테이너 이미지가 없다면?
|
||||||
|
이미지부터 만들어야 합니다. (도커에 대한 이해가 필요)
|
||||||
|
|
||||||
|
#### 5. [[테넌시(Tenancy)]]
|
||||||
|
- [[테넌시 구성 가이드]]
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
VPC
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
## 1.
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
---
|
||||||
|
id: 서비스 만들기 20260305
|
||||||
|
created: 2026-03-05 08:38
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
> [!abstract]
|
||||||
|
> [[클러스터(Cluster)]] 내부에서 동작하는 서비스를 만듭니다.
|
||||||
|
> ECS 서비스는 **"데이터 플레인 위에서 태스크가 잘 돌아가게 감시하는 역할"**을 합니다.
|
||||||
|
|
||||||
|
> [!check]
|
||||||
|
> - **개수 유지:** "태스크 3개를 항상 띄워줘"라고 설정하면, 하나가 죽었을 때 데이터 플레인(서버) 위에 새로운 태스크를 다시 올립니다.
|
||||||
|
>
|
||||||
|
> - **로드 밸런싱:** 들어오는 트래픽을 여러 태스크에 골고루 나눠줍니다.
|
||||||
|
>
|
||||||
|
> - **배포 관리:** 새로운 버전의 태스크 정의가 나오면, 기존 태스크를 하나씩 끄고 새 버전으로 교체합니다.
|
||||||
|
>
|
||||||
|
|
||||||
|
## 🔢 목록
|
||||||
|
|
||||||
|
#### 1. 서비스의 [[태스크(Task)]] 정의
|
||||||
|
![[Pasted image 20260305084812.png]]
|
||||||
|
만약 정의한 [[태스크(Task)]]가 없다면 태스크부터 정의해야 합니다.
|
||||||
|
[[ECS 태스크 만들기]]
|
||||||
|
태스크를 기반으로 ECS의 서비스가 가동되어집니다.
|
||||||
|
|
||||||
|
> [!question]
|
||||||
|
> [[태스크 정의 패밀리]]가 뭐지?
|
||||||
|
|
||||||
|
태스크 정의 패밀리를 선택하면 그 패밀리의 최신 버전이 자동으로 태스크 정의 개정에 등록됩니다.
|
||||||
|
서비스 이름을 마저 지정합니다.
|
||||||
|
|
||||||
|
#### 2. 컴퓨팅 구성 선택
|
||||||
|
![[Pasted image 20260305102304.png]]
|
||||||
|
클러스터명은 변경할 수 없어서 비활성화 되어있는 것
|
||||||
|
[[시작 유형(Launch Type)과 용량 공급자 전략(Capacity Provider Strategy)의 차이]]
|
||||||
|
참고해서 설정하면 됩니다.
|
||||||
|
|
||||||
|
|
||||||
|
#### 3. 문제 해결 구성 설정
|
||||||
|
> [!info] 개발(Dev)이나 스테이징(Staging) 환경에서는 무조건 켜두시고, 운영(Prod) 환경에서는 보안 승인을 받은 사람만 쓸 수 있게 [[IAM(Identity and Access Management)]]으로 꽉 잠가두고 켜두시는 것을 추천
|
||||||
|
|
||||||
|
![[Pasted image 20260305104853.png]]
|
||||||
|
|
||||||
|
|
||||||
|
#### 4. 배포 구성은 그대로 놔둡니다.
|
||||||
|
정확한 사용법을 확인하지 못했음.
|
||||||
|
|
||||||
|
|
||||||
|
#### 5. 네트워킹
|
||||||
|
[[VPC(Virtual Private Cloud)]]와 [[서브넷(Subnet)]], [[보안 그룹(Security Group)]]을 설정합니다.
|
||||||
|
필요한대로, 원하는대로 설정해줍니다.
|
||||||
|
|
||||||
|
#### 6. 로드밸런싱 선택
|
||||||
|
태스크로의 로드밸런싱이 필요한 경우 체크하고 사용합니다.
|
||||||
|
여기서 추가해주지 않으면 중간에 추가할 수 없어서 태스크를 새로 만들어야 합니다.
|
||||||
|
![[Pasted image 20260305110136.png]]
|
||||||
|
**자동 등록 (Target Group):** 새로운 태스크가 실행되면 ECS 서비스가 알아서 로드 밸런서의 **'대상 그룹(Target Group)'**에 해당 태스크의 IP를 등록해줍니다.**
|
||||||
|
로드 밸런싱 사용을 체크하지 않을 경우 자동 등록이 되지 않습니다.
|
||||||
|
|
||||||
|
|
||||||
|
서비스를 만들고 나면 서비스 태스크가 정상적으로 실행되기를 기다려야합니다.
|
||||||
|
![[Pasted image 20260305110258.png]]
|
||||||
|
만약 태스크 실행이 실패하였다면 태스크정보에서 로그 탭을 확인해야 합니다.
|
||||||
|
![[Pasted image 20260305111038.png]]
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
id: 클러스터 만들기 20260305
|
||||||
|
created: 2026-03-05 08:30
|
||||||
|
tags:
|
||||||
|
- cluster
|
||||||
|
- ecs
|
||||||
|
---
|
||||||
|
> [[!]]
|
||||||
|
## 🔢 목록
|
||||||
|
|
||||||
|
#### 1. [[클러스터(Cluster)]] 이름을 정한다.
|
||||||
|
![[Pasted image 20260305083155.png]]
|
||||||
|
#### 2. 인프라를 선택해준다.
|
||||||
|
![[Pasted image 20260305083442.png]]
|
||||||
|
> [!note]
|
||||||
|
> 진정한 [[서버리스(Serverless)]] 환경구축을 위해서는 [[파게이트(Fargate)]]전용으로 해준다.
|
||||||
|
>
|
||||||
|
|
||||||
|
#### 3. 나머지는 일단 그대로 둔다.
|
||||||
|
모니터링, 암호화, 태그는 우선 그대로 둡니다. (추후 필요할 경우 확인 후 설정 필요)
|
||||||
|
|
||||||
|
|
||||||
|
클러스터를 생성하고 서비스를 생성합니다.
|
||||||
|
[[ECS 서비스 만들기]]
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
id: ECS 태스크 vs k8s 파드 20260304
|
||||||
|
created: 2026-03-04 17:22
|
||||||
|
tags:
|
||||||
|
- ecs
|
||||||
|
- container
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
결국 태스크와 파드는 같다고 보면된다. 태스크는 ECS에서 쓰고 파드는 EKS에서 쓴다.
|
||||||
|
|
||||||
|
## 🤝 ECS 태스크 vs K8s 포드: 공통점
|
||||||
|
|
||||||
|
1. **컨테이너의 집합체:** 두 개념 모두 하나 이상의 컨테이너를 포함할 수 있습니다. (예: 메인 앱 + 로그 수집기)
|
||||||
|
|
||||||
|
2. **네트워크 공유:** 태스크/포드 내의 컨테이너들은 동일한 IP 주소를 공유하며 `localhost`를 통해 서로 통신합니다.
|
||||||
|
|
||||||
|
3. **스토리지 공유:** 태스크/포드 수준에서 정의된 볼륨을 내부 컨테이너들이 함께 마운트해서 쓸 수 있습니다.
|
||||||
|
|
||||||
|
4. **생명 주기:** 태스크나 포드가 죽으면 그 안의 컨테이너들도 운명을 같이 합니다.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 🧐 굳이 차이점을 찾자면? (한 끗 차이)
|
||||||
|
|
||||||
|
개념은 같지만, 그것을 **관리하는 방식**에서 이름표가 달라집니다.
|
||||||
|
|
||||||
|
- **ECS ([[파게이트(Fargate)]] 기준):** AWS가 서버를 대신 관리해주기 때문에, 사용자가 "난 이만큼의 자원이 필요해"라고 **태스크 단위로 주문서**를 써야 합니다. 그래야 AWS가 그에 딱 맞는 가상 머신을 뒤에서 빌려줄 수 있으니까요.
|
||||||
|
|
||||||
|
- **[[쿠버네티스(Kubernetes)]]:** 보통 이미 떠 있는 **노드(Node/서버) 덩어리**가 있고, 파드는 그 안에서 자원을 조금씩 나눠 쓰는 '세입자' 같은 느낌입니다. 그래서 리소스 설정이 '실행 기준'이라기보다 '최대/최소 가이드라인'처럼 느껴질 수 있습니다.
|
||||||
|
|
||||||
|
### ECS 태스크 (Task)
|
||||||
|
|
||||||
|
ECS는 특히 **Fargate** 모드를 쓸 때, 태스크 전체가 사용할 CPU와 메모리를 **태스크 수준**에서 딱딱하게 결정해야 합니다.
|
||||||
|
|
||||||
|
- 예: "이 태스크는 무조건 0.5 vCPU와 1GB 메모리를 점유한다."
|
||||||
|
|
||||||
|
- 이 기준이 틀리면 아예 실행이 안 되거나 설정 오류가 납니다. 그래서 질문자님 말씀처럼 "태스크 = 리소스 기준이 명확히 박힌 단위"라는 인상이 강합니다.
|
||||||
|
|
||||||
|
|
||||||
|
### 쿠버네티스 파드 (Pod)
|
||||||
|
|
||||||
|
파드도 YAML 설정(Spec) 안에 각 컨테이너가 사용할 `requests`(최소 보장)와 `limits`(최대 제한)를 적습니다.
|
||||||
|
|
||||||
|
- 예: "이 컨테이너는 최소 256MB, 최대 512MB 메모리를 쓴다."
|
||||||
|
|
||||||
|
- **차이점:** 쿠버네티스는 여러 컨테이너의 합산 리소스를 보고 노드(서버)의 남는 자리에 파드를 '스케줄링'하는 데 집중합니다. ECS보다 설정이 좀 더 유연하고 복잡하게 느껴질 수 있습니다.
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
---
|
||||||
|
id: ECS 태스크 만들기 20260305
|
||||||
|
created: 2026-03-05 08:49
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
ECS 클러스터의 서비스가 [[태스크(Task)]]를 실행해서 서비스가 구동될 수 있습니다.
|
||||||
|
|
||||||
|
|
||||||
|
## 🔢 목록
|
||||||
|
|
||||||
|
#### 1. 태스크 정의하기
|
||||||
|
태스크는 Amazon **E**lastic **C**ontainer **S**ervice의 태스크 정의 탭에서 정의 가능합니다.
|
||||||
|
![[Pasted image 20260305085256.png]]
|
||||||
|
|
||||||
|
#### 2. [[태스크 정의 패밀리]] 이름 지정
|
||||||
|
![[Pasted image 20260305085241.png]]
|
||||||
|
|
||||||
|
#### 3. 인프라 요구 사항 지정
|
||||||
|
![[Pasted image 20260305091259.png]]
|
||||||
|
진정한 [[서버리스(Serverless)]] 환경 구축을 위해서는 AWS [[파게이트(Fargate)]]를 선택합니다.
|
||||||
|
물론 [[EC2(Elastic Compute Cloud)]]로 지정할수도 있습니다.
|
||||||
|
|
||||||
|
#### 4. OS, 아키텍처, 네트워크 모드 지정
|
||||||
|
[[ECS 태스크 정의]]
|
||||||
|
![[ECS 태스크 정의#📑 개념]]
|
||||||
|
![[Pasted image 20260305091749.png]]
|
||||||
|
여기서는 기본값으로 설정하고 진행했습니다.
|
||||||
|
|
||||||
|
#### 5. 태스크 역할 - 조건부 지정
|
||||||
|
[[태스크 역할과 태스크 실행 역할]]
|
||||||
|
![[Pasted image 20260305093459.png]]
|
||||||
|
> [!note] ecsTaskExecutionRole ?
|
||||||
|
> 사실상 default 역할인 **AmazonECSTaskExecutionRolePolicy**가 연결되어있음
|
||||||
|
![[Pasted image 20260305094500.png]]
|
||||||
|
|
||||||
|
작업 배치 - (선택 사항)
|
||||||
|
결함 주입 - 선택 사항
|
||||||
|
는 일단 지정하지 않았습니다. (아직 뭔지 모름)
|
||||||
|
|
||||||
|
#### 6. 컨테이너 생성 (1)
|
||||||
|
컨테이너의 이름과 도커 이미지의 위치를 지정합니다.
|
||||||
|
![[Pasted image 20260305094813.png]]
|
||||||
|
도커 이미지는 [[ECR(Elastic Container Registry)]]에 저장되어 있는 것을 가져다가 사용할 수 있고 (추천)
|
||||||
|
프라이빗 공간의 이미지를 가져다가 쓸 수도 있습니다 (만 추가적인 설정이 필요해 보입니다.)
|
||||||
|
|
||||||
|
#### 7. 컨테이너 생성(2)
|
||||||
|
컨테이너 포트정보를 입력합니다. [[파게이트(Fargate)]]의 경우 컨테이너 포트가 호스트 포트와 반드시 동일해야합니다. (별도로 맞춰줄 필요 없이 컨테이너 포트만 입력하면 알아서 맞춰집니다.)
|
||||||
|
![[Pasted image 20260305100339.png]]
|
||||||
|
|
||||||
|
읽기 전용 루트 파일 시스템
|
||||||
|
리소스 할당 제한 - 조건부
|
||||||
|
두가지는 일단 설정하지 않습니다. (아직 잘 모름)
|
||||||
|
|
||||||
|
#### 8. 환경 변수 설정
|
||||||
|
필요한 환경 변수가 있을 경우 추가해줍니다.
|
||||||
|
![[Pasted image 20260305100917.png]]
|
||||||
|
추가예시
|
||||||
|
![[Pasted image 20260305101005.png]]
|
||||||
|
|
||||||
|
#### 9. 로그 수집 설정
|
||||||
|
![[Pasted image 20260305101051.png]]
|
||||||
|
별도의 로그 수집 정책이 있을 경우 다른 것으로 지정 가능
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
---
|
||||||
|
id: ECS 태스크 정의 20260305
|
||||||
|
created: 2026-03-05 09:20
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
> [!abstract]
|
||||||
|
> **"실제로 어떤 하드웨어 환경에서 돌아갈지"**와 **"비용 청구서가 어떻게 나올지"**를 결정하는 핵심 데이터
|
||||||
|
|
||||||
|
## 1. 운영 체제 및 아키텍처 (OS & Architecture)
|
||||||
|
|
||||||
|
여기서 가장 중요한 건 **ARM64(AWS Graviton)**를 선택하느냐 아니냐입니다.
|
||||||
|
|
||||||
|
- **설정 내용:** `X86_64` (인텔/AMD 계열) vs `ARM64` (AWS Graviton 계열)
|
||||||
|
|
||||||
|
- **무엇이 달라지나:** * **호환성:** 내 도커 이미지를 어떤 CPU용으로 빌드했느냐에 따라 선택해야 합니다. (잘못 선택하면 실행 시 `exec format error`가 나며 죽습니다.)
|
||||||
|
|
||||||
|
- **성능:** ARM64(Graviton) 기반 인스턴스는 최신 세대 가상 머신을 사용하여 가성비가 매우 좋습니다.
|
||||||
|
|
||||||
|
- **💰 비용 차이:** **매우 중요합니다.** 일반적으로 **ARM64 아키텍처를 선택하면 x86보다 약 20% 정도 저렴**합니다. 똑같은 태스크를 돌려도 아키텍처 설정만 바꾸면 돈을 아낄 수 있습니다. (단, 이미지 빌드도 ARM용으로 해야 함)
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 네트워크 모드 (Network Mode)
|
||||||
|
|
||||||
|
[[파게이트(Fargate)]]를 사용하신다면 사실상 `awsvpc` 모드로 고정되지만, [[EC2(Elastic Compute Cloud)]] 기반에서는 선택지가 나뉩니다.
|
||||||
|
|
||||||
|
- **awsvpc 모드 (Fargate 기본):** * **특징:** 각 태스크가 자신만의 **고유한 Private IP**를 가집니다. 마치 VPC 안에 EC2 인스턴스가 하나 더 들어온 것처럼 행동합니다.
|
||||||
|
|
||||||
|
- **장점:** 보안 그룹(Security Group)을 태스크 단위로 촘촘하게 걸 수 있습니다. (A 태스크는 DB 접근 가능, B 태스크는 불가 등)
|
||||||
|
|
||||||
|
- **Bridge / Host 모드 (EC2 전용):** * **특징:** 호스트 EC2의 IP와 포트를 공유해서 씁니다.
|
||||||
|
|
||||||
|
- **💰 비용 차이:** 네트워크 모드 자체로 돈을 더 받지는 않지만, `awsvpc` 모드 사용 시 발생하는 **데이터 전송 비용(Data Transfer Out)**이나 가용 영역(AZ) 간 통신 비용이 실질적인 비용 차이를 만듭니다.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 리소스 할당 (CPU & Memory)
|
||||||
|
|
||||||
|
[[파게이트(Fargate)]] 비용의 핵심입니다. "사용량만큼 낸다"는 말의 정확한 의미는 **"내가 설정한 CPU/메모리 사양만큼 예약해서 낸다"**입니다.
|
||||||
|
|
||||||
|
- **착각하기 쉬운 점:** 태스크가 실제로 CPU를 1%만 쓰고 있어도, 설정(예약)을 1 vCPU로 했다면 **1 vCPU만큼의 비용이 꼬박꼬박 나갑니다.** * **차이:** * **설정값:** 0.25 vCPU / 0.5 GB 로 설정하면 가장 저렴합니다.
|
||||||
|
|
||||||
|
- **비용 구조:** `(vCPU 가격 * 시간) + (GB당 메모리 가격 * 시간)`.
|
||||||
|
|
||||||
|
- 따라서 실제 사용량보다 너무 과하게 설정하면 서버리스인데도 돈이 많이 나올 수 있습니다.
|
||||||
|
|
||||||
|
## 📝 노트
|
||||||
|
> [!note]
|
||||||
|
> 무엇을 선택해야 유리할까?
|
||||||
|
|
||||||
|
| **설정 항목** | **추천 선택지** | **비용/효율 영향** |
|
||||||
|
| ----------- | ---------- | ------------------------------ |
|
||||||
|
| **아키텍처** | **ARM64** | **약 20% 저렴**하며 성능도 우수 (강력 추천) |
|
||||||
|
| **네트워크 모드** | **awsvpc** | 보안 관리가 쉬워지나, ENI 할당 등 관리 요소 발생 |
|
||||||
|
| **CPU/메모리** | **최소 필요량** | 설정한 수치에 비례해서 초 단위로 과금됨 |
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
### ECS(Elastic Container Service)
|
||||||
|
: AWS가 제공해주는 [[컨테이너 오케스트레이션]] 서비스입니다.
|
||||||
|
### EKS(Elastic kubernetes Service)
|
||||||
|
: [[쿠버네티스(Kubernetes)]]를 AWS의 다른 서비스들과 연동해서 사용할 수 있게 해주는 AWS 서비스입니다.
|
||||||
|
|
||||||
|
> [!note]
|
||||||
|
>
|
||||||
|
> - ECS와 EKS는 둘 다 [[컨테이너 오케스트레이션]]을 지원해주는 서비스입니다.
|
||||||
|
> - 컴퓨팅 자원으로 [[파게이트(Fargate)]]를 지정할 수 있습니다.
|
||||||
|
> - 표준화된 [[배포 파이프라인(Deployment Pipeline)]]을 사용할 수 있습니다.
|
||||||
|
|
||||||
|
ECS와 EKS의 핵심 목표는 ==‘컨테이너 기술의 안정적 운영’==임.
|
||||||
|
|
||||||
|
![[ECS와 EKS의 차이점]]
|
||||||
|
|
||||||
|
ECS는 AWS기반에서는 비교적 쉽고 빠르게 사용 가능 하지만 다른 환경으로의 이식이 어렵고,
|
||||||
|
EKS는 러닝커브가 가파르고 복잡도가 높지만 이식성이 매우 높음.
|
||||||
|
|
||||||
|
ECS와 EKS는 모두 [[클러스터(Cluster)]] 형태로 구현됨.
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
id: ECS의 구성 20260304
|
||||||
|
created: 2026-03-04 16:57
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
![[ECS와 EKS#ECS(Elastic Container Service)]]
|
||||||
|
|
||||||
|
### ECS는 [[클러스터(Cluster)]] 형태로 구성되어집니다.
|
||||||
|
![[Pasted image 20260304165810.png]]
|
||||||
|
#### [[클러스터(Cluster)]]
|
||||||
|
![[클러스터(Cluster)#📑 개념]]
|
||||||
|
|
||||||
|
### ECS Cluster는
|
||||||
|
> [!note]
|
||||||
|
> 하나의 서버에서 구동중인 [[쿠버네티스(Kubernetes)]] 엔진을 사용하는 것 같은 느낌을 주기위해서 만듭니다.
|
||||||
|
|
||||||
|
### Cluster에서 서비스가 동작됩니다.
|
||||||
|
![[Pasted image 20260304170925.png]]
|
||||||
|
|
||||||
|
### 서비스에는 [[태스크(Task)]]가 동작합니다.
|
||||||
|
![[Pasted image 20260304171641.png]]
|
||||||
|
> [!note]
|
||||||
|
> ECS의 태스크에는 태스크가 실행되기 위해 필요한 정보들, 어떤 컨테이너들을 실행해야하는지 등이 정의되어있음.
|
||||||
|
|
||||||
|
![[Pasted image 20260304171851.png]]
|
||||||
|
위와같이 태스크가 어떤 구성으로 동작해야하는지가 기록되어있고
|
||||||
|
![[Pasted image 20260304171939.png]]
|
||||||
|
어떤 컨테이너들이 실행되어야 하는지 기재되어있다.
|
||||||
|
|
||||||
|
## 💡 생각
|
||||||
|
즉, 태스크는 쿠버네티스에서 말하는 Pod를 실체화시킨 것
|
||||||
|
[[ECS 태스크 vs k8s 파드]]
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
## 📑 개념
|
||||||
|
> [!abstract]
|
||||||
|
> AWS에서 사용할 수 있는 [[컨테이너 오케스트레이션]] 엔진
|
||||||
|
> 클러스터 형태로 구현해놓았고 그걸 EKS라고 함.
|
||||||
|
|
||||||
|
|
||||||
|
## 📝 노트
|
||||||
|
> [!note]
|
||||||
|
>
|
||||||
|
>EKS Cluster의 구조는 크게 Control Plane과 Data Plane 둘로 나눠집니다.
|
||||||
|
> Control Plane은 전체적인 지휘소 역할을 하며 오케스트레이션에 필요한 모듈들이 위치하고, Data Plane은 실제 서비스가 돌아가는 자원들이 위치합니다.
|
||||||
|
>
|
||||||
|
> 이미지를 보면 5개의 Node가 보이는데 각 노드들을 컨테이너를 담고 있는 가상서버이며 그 위에 실제 서비스 단위인 컨테이너가 구동됩니다.
|
||||||
|
>
|
||||||
|
> 각 노드들에는 core-운, swing-cmms, load-balancer 컨테이너들이 구동되고 있습니다.
|
||||||
|
>
|
||||||
|
> 로드밸런서는 앞서봤던 Elastic Load Balancer를 가리키는 포인터 역할의 서비스이며 CoreDNS는 클러스터 내부의 통신을 위해 필요한 필수 서비스입니다
|
||||||
|
>
|
||||||
|
> Aws에 구현해놓은 cmms 서비스는 현재 이 다섯개의 컨테이너들로 구성되어서 실행되고 있습니다.
|
||||||
|
>
|
||||||
|
![[Pasted image 20260227162406.png]]
|
||||||
|
|
||||||
|
## EKS Cluster 기반의 아키텍처 구조도
|
||||||
|
![[Pasted image 20260227163046.png]]
|
||||||
|
## VPC 범위까지 확대
|
||||||
|
![[Pasted image 20260227163118.png]]
|
||||||
|
## 🔗 지식 연결
|
||||||
|
- **태그:** #cluster #container #kubernetes
|
||||||
|
- 관련 문서: [[ECS와 EKS의 차이점]] [[쿠버네티스(Kubernetes)]]
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
### CMMS의 SaaS 플랫폼화를 해야합니다.
|
||||||
|
|
||||||
|
##### 플랫폼화를 할 경우 장점
|
||||||
|
> [!check]
|
||||||
|
> - **운영 효율 극대화 및 비용 최적화**
|
||||||
|
>
|
||||||
|
> : 기존 EC2 기반의 1:1 관리 방식에서 벗어나 하나의 클러스터에서 여러 테넌트(고객사)를 관리함으로써 운영 공수를 획기적으로 줄입니다.
|
||||||
|
>
|
||||||
|
> - **시장 대응 속도(Time-to-Market) 가속화**
|
||||||
|
>
|
||||||
|
> : 새로운 고객사가 추가될 때마다 서버를 새로 구축할 필요가 없습니다. 미리 구성된 멀티 테넌시 환경과 커스텀 라우팅을 통해 클릭 몇 번만으로 신규 고객 전용 환경을 즉시 제공(On-boarding)할 수 있어, 비즈니스 기회를 놓치지 않고 빠르게 시장을 확대할 수 있습니다.
|
||||||
|
>
|
||||||
|
> - **서비스 안정성 및 보안성 고도화**
|
||||||
|
>
|
||||||
|
> : 파드 자동 복구기능을 통해 장애 발생 상황 대응에 인력의 투입이 필요 없어지도록 해줍니다. (관리 포인트가 줄어듦)
|
||||||
|
|
||||||
|
> [!note]
|
||||||
|
>
|
||||||
|
> - CMMS의 경우 SaaS 플랫폼화가 이미 진행되어있는 상태
|
||||||
|
> - Enterprize 요금제를 요구하는 고객을 위한 '설치형 구독형' 모델 구축을 위한 Cloud Architecture 화를 진행한 것임
|
||||||
|
> - 기본형의 SaaS CMMS는 이미 존재함
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
## [[EC2(Elastic Compute Cloud)]]
|
||||||
|
![[EC2(Elastic Compute Cloud)#📑 개념]]
|
||||||
|
|
||||||
|
## [[컨테이너(Container)]]
|
||||||
|
![[컨테이너(Container)#📑 개념]]
|
||||||
|
|
||||||
|
## [[파게이트(Fargate)]]
|
||||||
|
![[파게이트(Fargate)#📑 개념]]
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
id: 시작 유형(Launch Type)과 용량 공급자 전략(Capacity Provider Strategy)의 차이 20260305
|
||||||
|
created: 2026-03-05 10:24
|
||||||
|
tags:
|
||||||
|
- ecs
|
||||||
|
- fargate
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
그냥 용량 공급자 전략을 써야한다고만 기억하면 됨. (기본값도 용량 공급자 전략으로 되어있음)
|
||||||
|
|
||||||
|
> [!note]
|
||||||
|
> ECS 서비스에서 **시작 유형(Launch Type)**과 **용량 공급자 전략(Capacity Provider Strategy)**은 "내 컨테이너를 어디에 띄울 것인가"를 결정하는 두 가지 방식입니다.
|
||||||
|
>
|
||||||
|
> 과거에는 '시작 유형'만 있었지만, 현재는 더 유연한 관리를 위해 '용량 공급자 전략'을 권장하는 추세입니다. 두 방식의 핵심적인 차이를 정리해 드릴게요.
|
||||||
|
|
||||||
|
## 1. 시작 유형 (Launch Type) : "단순한 선택"
|
||||||
|
|
||||||
|
가장 직관적인 방식입니다. 태스크를 띄울 인프라를 **딱 하나만** 고정해서 선택하는 것입니다.
|
||||||
|
|
||||||
|
- **방식:** "나는 무조건 **Fargate**만 쓸 거야" 혹은 "무조건 **EC2**만 쓸 거야"라고 선언합니다.
|
||||||
|
|
||||||
|
- **특징:** 설정이 매우 간단하지만, 여러 종류의 인프라를 섞어서 쓰는 것이 불가능합니다.
|
||||||
|
|
||||||
|
- **비유:** 식당에 가서 "무조건 소고기 메뉴만 주세요"라고 고정 주문을 하는 것과 같습니다.
|
||||||
|
|
||||||
|
|
||||||
|
## 2. [[용량 공급자 전략 (Capacity Provider Strategy)]] : "유연한 배분"
|
||||||
|
> [!note] 하나 이상의 인프라(용량 공급자)를 **어떤 비율로 섞어서 쓸지** 결정하는 고도화된 방식입니다.
|
||||||
|
|
||||||
|
![[Pasted image 20260305103056.png]]
|
||||||
|
![[용량 공급자 전략 (Capacity Provider Strategy)#💡 왜 '용량 공급자 전략'을 써야 할까요? (핵심 이유)]]
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
순서
|
||||||
|
## 1. [[VPC(Virtual Private Cloud)]] 생성
|
||||||
|
|
||||||
|
## 2. VPC에 [[서브넷(Subnet)]] 생성
|
||||||
|
: 필요에 따라 퍼블릭,프라이빗 서브넷을 생성하면 됨.
|
||||||
|
[[Pod를 Private subnet에 두는 이유]]
|
||||||
|
## 3. 라우팅 테이블 생성
|
||||||
|
|
||||||
|
## 4. 인터넷 게이트웨이 생성
|
||||||
|
|
||||||
|
## 5. EC2 생성
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
To-Be
|
||||||
|
![[Pasted image 20260227094154.png]]
|
||||||
|
|
||||||
|
EC2기반의 아키텍처를 클라우드 컴퓨팅 환경에 맞게 변경한 아키텍처입니다.
|
||||||
|
다른 부분은 모두 동일하고 [[파게이트(Fargate)]]라고 적혀있는 이 부분만 달라진 것을 확인할 수 있습니다.
|
||||||
|
[[파게이트(Fargate)의 장점]]
|
||||||
|
|
||||||
|
컨테이너 기반의 아키텍처로 변경했을떄의 장점
|
||||||
|
[[가용성(Availability)]] [[보안성(Security)]]이 확보되고 프로젝트의 [[생산성(Productivity)]]이 증가되고, 프로젝트의 [[유연성(Flexibility)]]과 [[확장성(Scalability)]]확보에 유리해진다.
|
||||||
|
|
||||||
|
각각을 현재 상황에맞게 풀어서 설명해보면
|
||||||
|
|
||||||
|
[[가용성(Availability)]]: 초기설정을 잘 해 놓으면 [[컨테이너 오케스트레이션]]에 의해 서비스의 자가복구가 가능하다.
|
||||||
|
[[유연성(Flexibility)]]: 로드밸런서가 컨테이너 단위로의 접근이 가능해서 동일한 내부 포트(예: 80)를 사용하는 여러 서비스를 띄워도, 각 컨테이너가 고유 IP를 가지므로 충돌 없이 동적 라우팅이 가능하다.
|
||||||
|
[[보안성(Security)]]: [[파게이트(Fargate)]] 이용 시 OS 업데이트, 보안패치 등의 OS/인프라 레벨의 보안을 AWS가 책임져준다.
|
||||||
|
[[생산성(Productivity)]]: 서버관리 포인트가 줄어들어서 인프라 관리 등의 인프라 운영에 들어가는 반복적인 공수(Heavy Lifting)를 제거하여, 비즈니스 로직 개발 및 서비스 고도화에 인력을 집중 투입할 수 있다.
|
||||||
|
|
||||||
|
## 📝 노트
|
||||||
|
> [!note]
|
||||||
|
EC2는 가상 컴퓨팅 환경이기 때문에 장애 복구에 많은 시간이 필요하지만 fargate는 컨테이너이므로 수초내에 복구할 수 있습니다.
|
||||||
|
>
|
||||||
|
> 컨테이너 자체는 자가복구의 기능이 없지만 뒤에서 설명드릴 ECS나 EKS에서는 가능합니다.
|
||||||
|
>
|
||||||
|
> 그리고 로드밸런서가 EC2같은 서버가 아닌 컨테이너를 가리킬 수 있습니다. 그로인해 자주 사용되는 80포트등의 포트들이 중복사용으로 충돌을 일으킬 가능성이 없습니다.
|
||||||
|
>
|
||||||
|
> A컨테이너의 80포트, B컨테이너의 80포트 이런식으로 상세하게 설정할 수 있기 떄문입니다.
|
||||||
|
>
|
||||||
|
> 그리고 AWS가 보안과 서버인프라 문제를 모두 책임져주기 때문에 생산성 향상이 될 수 있습니다.
|
||||||
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
id: "태스크 역할과 태스크 실행 역할 20260305"
|
||||||
|
created: "2026-03-05 09:38"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
[[태스크 역할(Task Role)]] vs [[태스크 실행 역할(Task Execution Role)]]
|
||||||
|
|
||||||
|
|**구분**|**태스크 실행 역할 (Execution Role)**|**태스크 역할 (Task Role)**|
|
||||||
|
|---|---|---|
|
||||||
|
|**누가 쓰는가?**|**ECS 에이전트 / 인프라**|**내 앱 소스 코드 (Container)**|
|
||||||
|
|**언제 쓰는가?**|태스크를 **준비하고 띄울 때**|태스크가 **실행 중일 때**|
|
||||||
|
|**필수 여부**|대부분 필수 (이미지 풀, 로그 때문)|선택 (AWS 서비스를 안 쓰면 필요 없음)|
|
||||||
|
|**예시 정책**|`AmazonECSTaskExecutionRolePolicy`|`AmazonS3FullAccess`, `AmazonDynamoDBReadOnly` 등|
|
||||||
|
### 💡 실무에서는 어떻게 설정하나용?
|
||||||
|
|
||||||
|
1. **실행 역할(Execution Role):** AWS에서 기본으로 제공하는 `AmazonECSTaskExecutionRolePolicy`를 연결해 주는 것이 국룰입니다. (이거 안 하면 로그가 안 남거나 이미지를 못 가져와서 태스크가 무한 재시작됩니다.)
|
||||||
|
|
||||||
|
2. **태스크 역할(Task Role):** 기본값은 비어있습니다. 내 앱이 S3나 DynamoDB를 써야 할 일이 생길 때만 필요한 권한을 콕 집어서 추가해 주면 됩니다.
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
---
|
||||||
|
id: 테넌시 선택 20260305
|
||||||
|
created: 2026-03-05 13:18
|
||||||
|
tags:
|
||||||
|
- tenancy
|
||||||
|
- cluster
|
||||||
|
- ecs
|
||||||
|
- ecr
|
||||||
|
- saas
|
||||||
|
---
|
||||||
|
[[싱글 테넌시(Single-tenancy)]] vs [[멀티 테넌시(Multi-tenancy)]]
|
||||||
|
: 결정적인 차이는 **물리적으로 격리되어있는지** 여부
|
||||||
|
|
||||||
|
### [[멀티 테넌시(Multi-tenancy)]]
|
||||||
|
멀티 테넌시를 선택할 때 가장 중요한 것은 **인프라를 공유한다**는 것입니다.
|
||||||
|
순수 멀티 테넌시는 하나의 어플리케이션 인스턴스와 하나의 DB를 여러 고객들이 공유해서 사용합니다.
|
||||||
|
|
||||||
|
> [!note] 설정값, 환경변수 등의 차이만으로 고객간의 구분을 하고 모든 인프라는 하나를 공유해서 사용
|
||||||
|
|
||||||
|
고객간의 요구사항 편차가 적을 경우에는 효율이 좋음
|
||||||
|
편차가 클 경우 대응이 매우 어렵거나 거의 불가능에 가깝습니다. (고객 수가 적으면 되긴 함)
|
||||||
|
|
||||||
|
**SaaS 솔루션:** 완전한 멀티 테넌시 (공통 기능 + DB 설정 기반 커스텀)
|
||||||
|
즉 SaaS 솔루션은 모든 고객들이 하나의 인프라를 공유해서 사용하는 경우를 의미합니다.
|
||||||
|
|
||||||
|
|
||||||
|
> [!warning] 이렇게 되면 고객간의 요구사항 편차가 클 경우 대응이 불가능함
|
||||||
|
|
||||||
|
이 문제를 해결하기 위해 하이브리드 방식을 채택합니다.
|
||||||
|
**"인프라는 공유하되 애플리케이션은 격리하는 방식"** 같은 경우입니다.
|
||||||
|
이를 **가상 싱글 테넌시(Virtual Single Tenancy)** 또는 **격리형 멀티 테넌시**라고 부르기도 합니다.
|
||||||
|
|
||||||
|
격리형 테넌시 형태로 엔터프라이즈 솔루션 형태로 구성을 해야함.
|
||||||
|
**엔터프라이즈 솔루션:** 고객별 컨테이너/네임스페이스 분리 + 이미지 커스텀
|
||||||
|
|
||||||
|
테넌시별로 별도의 컨테이너 이미지를 확보해야함
|
||||||
|
코드레벨에서 독립되어지기 때문에 클라우드형 싱글테넌시 구조와 유사한 형태의 서비스가 가능
|
||||||
|
|
||||||
|
### 엔터프라이즈 솔루션의 구조도
|
||||||
|
(고객사별 독립된 어플리케이션 인스턴스 사용 + 하나의 DB 인프라 사용)
|
||||||
|
![[Pasted image 20260305140832.png]]
|
||||||
|
VPC레벨까지도 격리를 원하는 고객사의 경우에는 위의 이미지대로 별도의 ECS Cluster를 구성
|
||||||
|
그정도까지 아니면 하나의 공용 ECS Cluster에 [[태스크(Task)]]만 별도로 추가
|
||||||
|
|
||||||
|
## 🔗 관련 노트
|
||||||
|
- [[클러스터(Cluster)]]
|
||||||
|
- [[ECR(Elastic Container Registry)]]
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
id: "마력과 토크, RPM 20260504"
|
||||||
|
created: "2026-05-04 14:12"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
[[마력]]은 엔진이 일정시간동안 얼마나 많은 일을 할 수 있는지에 대한 지표임.
|
||||||
|
즉 마력이 높다 = 엔진이 많은 일을 할 수 있다(혹은 했다) 가 된다.
|
||||||
|
|
||||||
|
'근데 엔진이 많은 일을 했다'는 이 엔진이 장착된 차량의 속도가 빠르다는 말과 같다고 볼 순 없다.
|
||||||
|
일을 많이 할 수 있는 건 맞지만 엔진이 일을 많이 했다고 해서 반드시 차량의 속도가 빠르다고 볼 순 없기 때문
|
||||||
|
|
||||||
|
슈퍼카나 스포츠카들의 경우 엔진의 마력이 높은걸로 표시가 되어있는 이것만 보고 '아, 마력이 높으면 차가 빠른거구나?' 라고 하면 안된단 거임.
|
||||||
|
|
||||||
|
마력의 정의에서 적혀있듯 마력은 엔진이 할 수 있는 일의 양을 의미함.
|
||||||
|
이 일을 차량의 가속에 최대한 많이 사용하면 차가 빠르게 달리는거고
|
||||||
|
일을 차량이 큰 힘을 내는데 사용하면 차가 빠른건 아니지만 힘이 좋아서 무거운걸 나른다던가 할 수 있는 것임.
|
||||||
|
|
||||||
|
즉, **마력은 차량의 속도와 직접적인 관계가 있는 것은 아니다.**
|
||||||
|
차가 빠르게 달리기 위해서는 현재 속도에서 가속이 되기 위한 최적의 기어를 물리고 힘을 주는 것임.
|
||||||
|
최적의 기어를 선택해주는게 바로 [[변속기(Transmission)]]의 역할이다.
|
||||||
|
엔진이 낼 수 있는 힘은 정해져 있는데 이 정해진 힘을 적절하게 사용해서 자동차를 효율적으로 움직일 수 있도록 한 것.
|
||||||
|
|
||||||
|
엔진이 회전하면서 힘을내는 과정([[연료가 연소되면서 회전력이 발생되는 원리]]) 에서 필연적으로 엔진은 빠르게 회전하게 되는데 이 때 회전속도를 [[RPM]]이라는 수치로 표현한다.
|
||||||
|
엔진에는 회전할 수 있는 회전속도의 한계가 있는데 이걸 [[최대 RPM]]이라고 표현한다.
|
||||||
|
|
||||||
|
마력이나 토크가 높으려면 필연적으로 엔진이 빠르게 회전해야 한다.
|
||||||
|
[[출력을 높이는 방법]] 참고
|
||||||
|
|
||||||
|
스포츠카나 스포츠드라이빙의 경우 자세히보면 굉장히 상당히 고RPM (4,000~7,000RPM 사이)에서 주행하는것을 볼 수 있는데 여기서 착각하면 안되는게 차량이 큰 토크를 내거나(힘이 쌔거나) 속도가 빠르기 위해서 RPM이 높아야한다. 이건 잘못된 생각이다.
|
||||||
|
|
||||||
|
RPM이 높아서 힘이 쌘게 아니고 큰 힘을 내려고 엔진이 빠르게 회전했고 그로인해 RPM이 높은것임.
|
||||||
|
엔진이 큰 힘을 내거나 빠른 속도를 내기 위해서는 엔진의 회전보다 [[기어비(Gear Ratio)]]가 더 중요함.
|
||||||
|
상황에 맞는 기어를 물리고 엔진이 강하게 일을해서 큰 힘을 내는 것이고 그럴려다보니 RPM이 올라간 것 뿐임.
|
||||||
|
|
||||||
|
큰 토크(강한 힘)를 내기 위해서는 구동측 기어는 작은 것(저단 기어)를 쓰고 힘을 주는것이 좋음.
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
id: 80대20 원칙(The Pareto Principle) 20260318
|
||||||
|
created: 2026-03-18 10:08
|
||||||
|
tags:
|
||||||
|
- 클린코드
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
코드를 단순화하는 것은 어려운 일이기 때문에 모든 코드를 단순화하는 것은 엄청난 낭비가 될 수 있다.
|
||||||
|
그렇기 때문에 전체 가치의 80%를 창출해내는 20%의 자주 쓰이는 코드를 단순화하는 것에 집중해야 한다.
|
||||||
|
|
||||||
|
## 🔗 관련 노트
|
||||||
|
- [[단순한 코드]], [[파레토의 법칙]](80:20의 법칙)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 저자가 80:20의 법칙을 언급하는 이유
|
||||||
|
### 1. 노력 대 결과의 불균형
|
||||||
|
|
||||||
|
프로그래밍에서 80%의 가치는 전체 노력의 20%만 들여도 달성할 수 있다는 점을 강조합니다.
|
||||||
|
|
||||||
|
- **핵심 기능 우선:** 사용자에게 진짜 필요한 핵심 기능(20%)을 먼저 완벽하게 만드는 것이, 나머지 잔기능(80%)에 매달리는 것보다 훨씬 가치 있습니다.
|
||||||
|
|
||||||
|
- **복잡성의 함정:** 나머지 20%의 가치(예외 케이스, 아주 희귀한 최적화 등)를 채우기 위해 전체 노력의 80%를 쏟아붓는 순간, 코드는 급격히 복잡해지고 유지보수가 불가능해집니다.
|
||||||
|
|
||||||
|
### 2. '충분히 좋은(Good Enough)' 코드
|
||||||
|
|
||||||
|
저자는 **완벽함은 단순함의 적**이라고 말합니다.
|
||||||
|
|
||||||
|
- [[파레토의 법칙]]에 따르면, 100% 완벽한 코드를 만들려는 노력은 비효율적입니다.
|
||||||
|
|
||||||
|
- 대신 **80%의 성능과 안정성**을 보장하는 [[단순한 코드]]를 빠르게 작성하고, 실제 문제가 발생하는 지점만 나중에 정밀하게 타격(최적화)하는 것이 훨씬 똑똑한 전략입니다.
|
||||||
|
|
||||||
|
### 3. 기능 구현에서의 80/20
|
||||||
|
|
||||||
|
새로운 기능을 추가할 때도 이 법칙이 적용됩니다.
|
||||||
|
|
||||||
|
- [[YAGNI(You Ain't Gonna Need It)]]와의 연결: "혹시 필요할지 모르는" 기능들을 다 넣으려 하지 마세요. 실제 사용자는 제공된 기능의 20%만 주로 사용합니다.
|
||||||
|
|
||||||
|
- 그 20%의 기능을 **가장 단순하고 견고하게** 만드는 데 집중하는 것이 이 장의 핵심 레슨입니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> [!note] 왜 자꾸 20%의 코드에 집중해야한다고 강조하느냐면 단순한 코드를 작성하는 것은 쉬운일이 아니기 떄문입니다.
|
||||||
|
|
||||||
|
- "모든 곳을 단순하게 만들려고 애쓰는 것 자체가 복잡함의 시작이다. 진짜 중요한 20%만 단순하게 유지하고 나머지는 최소한의 노력만 들여라."
|
||||||
|
|
||||||
|
- "단순함은 기술(Skill)이고, 파레토 법칙은 그 기술을 사용할 전략(Strategy)이다. 전략 없는 기술은 개발자를 지치게 만든다."
|
||||||
|
|
||||||
|
- "단순함은 복잡함보다 어렵다. 생각을 명확히 해서 단순하게 만들려면 정말 열심히 노력해야 한다." - 스티브잡스
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
---
|
||||||
|
id: 단순함의 노하우 20260317
|
||||||
|
created: 2026-03-17 10:53
|
||||||
|
tags:
|
||||||
|
- 클린코드
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
> [!note] 코드는 무조건 단순해야 한다. 단순한 코드란 읽기 쉽고 명확한(가독성이 좋은) 코드다.
|
||||||
|
|
||||||
|
[[단순한 코드]] ?
|
||||||
|
[[파레토의 법칙]]을 프로그래밍에 응용
|
||||||
|
|
||||||
|
##### - 모든 코드를 100%의 노력으로 완벽하고 좋은 성능으로 만들려고 하면 많은 리소스 (인력이든 시간이든 뭐든..)를 필요로 하게 됨.
|
||||||
|
프로그램 실행 시간의 80%는 단 20%의 코드(핵심 알고리즘, 반복문 등)에서 소비됩니다. 따라서 나머지 80%의 코드는 성능을 위해 복잡하게 짤 필요 없이, **최대한 단순하고 읽기 쉽게** 유지하는 것이 이득입니다.
|
||||||
|
##### - 80% 의 자주 쓰지 않는 코드에 집중하고 자원을 낭비하지 말라.
|
||||||
|
훌륭한 구조를 가지고 좋은 성능을 보이는 코드라고 하더라도 **자주 쓰이지 않고** **코드 작성에 너무 많은 시간을 들였다면** 그것은 과도한 낭비가 될 가능성이 높다.
|
||||||
|
[[YAGNI(You Ain't Gonna Need It)]]
|
||||||
|
- 지금 필요 없는 건 하지 마라.
|
||||||
|
|
||||||
|
### 선택과 집중이 필요하다.
|
||||||
|
- **불필요한 최적화 거부:** 병목 지점이 아닌 나머지 80%의 코드를 최적화하느라 코드를 꼬아놓지 마세요. 그 부분은 그냥 **단순함** 그 자체로 두는 것이 유지보수에 훨씬 유리합니다.
|
||||||
|
|
||||||
|
- **복잡성 격리:** 정말 성능이 중요해서 복잡한 로직이 들어가야 한다면, 그 20%의 영역만 따로 분리(격리)하고 나머지는 깨끗하게 유지하세요.
|
||||||
|
|
||||||
|
> [!note] "80%의 효과를 내는 20%의 단순한 로직을 먼저 작성하라."
|
||||||
|
|
||||||
|
|
||||||
|
### 결국 저자가 하고 싶은 말은
|
||||||
|
1. 불필요한 단계를 최대한 제거하고
|
||||||
|
2. 사람이 읽기 좋은 형태로 바꿔주고
|
||||||
|
3. 알고리즘 최적화하는것
|
||||||
|
|
||||||
|
저자인 크리스티안 마이어가 경계하라고 강조하는 것
|
||||||
|
> [!warning] "0.001초를 줄이려고 코드 10줄을 50줄로 늘리며 가독성을 해치는 행위"
|
||||||
|
|
||||||
|
이런 경우는 최적화가 단순화를 **방해**하는 상황이 됩니다. 반대로 **복잡한 계산식을 수학적으로 정리해 한 줄로 줄이는 것**은 최적화이자 동시에 완벽한 단순화가 되는 것이죠.
|
||||||
|
|
||||||
|
## 사람이 읽기 좋은 코드...? [[코드의 가독성]]
|
||||||
|
> [!question]
|
||||||
|
> Q. 사람이 읽기 좋은 형태의 코드라는건 어떤걸 의미하는거야?
|
||||||
|
> A. 사람이 읽기 좋은 코드, 즉 **가독성이 높은 코드**는 단순히 "예쁜 코드"를 넘어 **코드를 읽는 사람의 뇌가 에너지를 최소한으로 쓰게 만드는 코드**를 의미합니다.
|
||||||
|
|
||||||
|
## 그리고 데이터가 늘어나도 잘 버티는 코드
|
||||||
|
데이터가 늘어나도 잘 버티는 코드는 보통 **확장성(Scalability)** 이 좋은 코드라고 부릅니다.
|
||||||
|
|
||||||
|
데이터가 10건일 때는 0.001초 만에 끝나던 로직이, 데이터가 100만 건으로 늘어났을 때도 서비스가 죽지 않고 합리적인 시간 내에 결과를 내놓는 것을 의미합니다.
|
||||||
|
|
||||||
|
> [!question]
|
||||||
|
> Q. 일단은 단순하게 만들고 나중에 문제가 생길경우에 집중해서 개선하라고 앞에서 계속 그러다가 갑자기 업스케일링을 염두해둬야한다는 말을 하면 앞뒤가 잘 안맞는거 아니야? 업스케일링에 유리한 코드를 미리 설계하고 개발하는거 자체도 일일텐데?
|
||||||
|
> A. 정말 날카롭고 합리적인 지적입니다! "일단 단순하게 만들라"는 말과 "나중에 커질 것을 대비(확장성/업스케일링)하라"는 말이 얼핏 들으면 서로 충돌하는 것처럼 느껴질 수 있습니다.
|
||||||
|
>
|
||||||
|
> 하지만 이 책과 클린 코드의 철학이 말하는 핵심은 [[유연한 단순함]]에 있습니다.
|
||||||
|
|
||||||
|
"지금 당장 필요하지 않은 기능(Over-engineering)은 넣지 않되, 나중에 그 기능을 넣고 싶을 때 코드 전체를 부수지 않아도 되게 끔 '문(Interface/Module)'만 잘 만들어 두는 것"
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
id: 유닉스 철학 (The Unix Philosophy) 20260330
|
||||||
|
created: 2026-03-30 15:20
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
# 개념
|
||||||
|
[[유닉스(Unix)]] 개발자들 사이에서 내려오는 유명한 원칙이 있습니다. 바로 **작고 단순한 것이 아름답다**는 점입니다.
|
||||||
|
|
||||||
|
1. **각 프로그램은 한 가지 일만 잘해야 한다.**
|
||||||
|
|
||||||
|
2. **여러 프로그램을 조합해서 복잡한 문제를 해결한다.** (이때 사용하는 것이 **파이프(|)** 기능입니다.)
|
||||||
|
|
||||||
|
3. **모든 것은 파일이다.** (텍스트 파일로 설정을 관리하고 데이터를 주고받습니다.)
|
||||||
|
|
||||||
|
> [!note] 단순히 운영체제를 만드는 기술적 규칙이 아니라, 소프트웨어를 설계하고 문제를 해결하는 일종의 **미니멀리즘 예술**에 가깝습니다.
|
||||||
|
|
||||||
|
: 1970년대 벨 연구소의 더글러스 매킬로이(Douglas McIlroy)가 정립한 이 철학의 핵심은 **작고 단순하며, 서로 협력하는 도구**를 만드는 것입니다.
|
||||||
|
|
||||||
|
|
||||||
|
## 1. 핵심 3원칙
|
||||||
|
|
||||||
|
더글러스 매킬로이는 유닉스 철학을 다음 세 문장으로 요약했습니다.
|
||||||
|
|
||||||
|
- **한 가지만 하되, 아주 잘하라 (Do One Thing and Do It Well):** 하나의 프로그램은 오직 하나의 기능에만 집중해야 합니다. 기능이 많아지면 복잡해지고 버그가 생기기 쉽기 때문입니다.
|
||||||
|
|
||||||
|
- **함께 작동하도록 만들어라 (Expect the output of every program to become the input to another):** 프로그램은 서로 연결될 것을 예상하고 만들어야 합니다.
|
||||||
|
|
||||||
|
- **텍스트 스트림을 표준 인터페이스로 사용하라:** 데이터는 가공하기 가장 쉬운 **텍스트** 형태로 주고받아야 합니다. 그래야 서로 다른 프로그램끼리 쉽게 대화할 수 있습니다.
|
||||||
|
|
||||||
|
|
||||||
|
## 2. 파이프(Pipe)와 필터
|
||||||
|
|
||||||
|
유닉스 철학을 시각적으로 가장 잘 보여주는 것이 바로 **파이프(|)** 기호입니다. 작은 도구들을 파이프로 연결하여 복잡한 일을 수행하는 방식이죠.
|
||||||
|
|
||||||
|
> **예시:** `ls | grep "test" | sort`
|
||||||
|
>
|
||||||
|
> 1. `ls`: 파일 목록을 출력한다. (한 가지 일)
|
||||||
|
>
|
||||||
|
> 2. `grep`: 그중 "test"가 포함된 것만 골라낸다. (한 가지 일)
|
||||||
|
>
|
||||||
|
> 3. `sort`: 결과를 알파벳 순으로 정렬한다. (한 가지 일)
|
||||||
|
>
|
||||||
|
|
||||||
|
각각은 단순한 도구일 뿐이지만, 연결하면 강력한 기능을 수행합니다. 이는 마치 레고 블록을 조립하는 것과 비슷합니다.
|
||||||
|
|
||||||
|
## 3. 에릭 레이먼드의 룰 (Rule of...)
|
||||||
|
|
||||||
|
오픈소스 전도사인 에릭 레이먼드는 그의 저서에서 유닉스 철학을 더 구체적인 규칙으로 확장했습니다.
|
||||||
|
|
||||||
|
- **단순함의 법칙 (Rule of Simplicity):** 복잡해지기 전까지 최대한 단순하게 설계하라.
|
||||||
|
|
||||||
|
- **명확함의 법칙 (Rule of Clarity):** 코드는 컴퓨터가 읽기 쉬운 것보다 사람이 읽기 쉬운 것이 더 중요하다.
|
||||||
|
|
||||||
|
위의 두 법칙을 지킴으로써 코드가 [[KISS (Keep It Simple, Stupid)]]해진다.
|
||||||
|
|
||||||
|
- **조합의 법칙 (Rule of Composition):** 프로그램이 다른 프로그램과 쉽게 연결될 수 있도록 설계하라.
|
||||||
|
|
||||||
|
조합의 법칙을 지키다 보면 코드가 [[DRY (Don't Repeat Yourself)]]해진다.
|
||||||
|
|
||||||
|
- **침묵의 법칙 (Rule of Silence):** 프로그램이 정말로 할 말이 없을 때는 아무것도 출력하지 마라. (그래야 다른 프로그램이 출력을 가공하기 좋습니다.)
|
||||||
|
|
||||||
|
유닉스 철학을 구체화 한 규칙들을 지킴으로써 [[클린코드의 기술]]들을 지키게 된다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 왜 유닉스 철학이 중요한가요?
|
||||||
|
|
||||||
|
오늘날 현대적인 소프트웨어 개발 방법론인 **마이크로서비스 아키텍처(MSA)** 나 [[함수형 프로그래밍(Functional Programming)]]의 뿌리도 이 유닉스 철학에 닿아 있습니다.
|
||||||
|
|
||||||
|
- **유지보수 용이:** 작고 단순한 코드는 고치기 쉽습니다.
|
||||||
|
|
||||||
|
- **재사용성:** 잘 만들어진 작은 도구는 여기저기서 다시 쓰일 수 있습니다.
|
||||||
|
|
||||||
|
- **확장성:** 새로운 기능을 추가할 때 기존 프로그램을 수정하는 대신, 새로운 도구를 만들어 연결하면 됩니다.
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
id: 최소 기능 제품 (MVP) 20260320
|
||||||
|
created: 2026-03-20 14:00
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
**M**inimum **V**iable **P**roduct , 최소 기능 제품
|
||||||
|
![[MVP(Minimum Viable Product)#📑 개념]]
|
||||||
|
|
||||||
|
### MVP의 핵심: "완벽함보다 실행"
|
||||||
|
|
||||||
|
저자는 개발자가 빠지기 쉬운 가장 큰 함정이 **모든 기능을 다 갖춰야 출시할 수 있다**는 생각이라고 지적합니다.
|
||||||
|
|
||||||
|
- **MVP의 정의:** 고객에게 가치를 전달할 수 있는 **최소한의 핵심 기능**만 담은 제품입니다.
|
||||||
|
|
||||||
|
- **개발자 버전 MVP:** 복잡한 아키텍처나 부가 기능(로깅, 화려한 UI, 상세 설정 등)을 다 붙이기 전에, **비즈니스 로직의 핵심**이 돌아가는 가장 단순한 형태의 코드를 먼저 완성하는 것입니다.
|
||||||
|
|
||||||
|
### 왜 MVP가 클린 코드와 연결될까요?
|
||||||
|
|
||||||
|
단순히 빨리 만드는 게 목적이 아닙니다. MVP 방식으로 개발하면 다음과 같은 이점이 있습니다.
|
||||||
|
|
||||||
|
- **복잡성 제어:** 처음부터 거대한 시스템을 설계하면 복잡도가 기하급수적으로 늘어납니다. 작은 단위(MVP)로 시작하면 코드가 단순하게 유지됩니다.
|
||||||
|
|
||||||
|
- **피드백 기반 개선:** 핵심 로직을 먼저 짜서 돌려봐야 어디가 진짜 병목인지, 어디에 스케일업이 필요한지 데이터로 확인할 수 있습니다. 추측에 근거한 과잉 엔지니어링을 막아줍니다.
|
||||||
|
|
||||||
|
- **YAGNI 실천:** "이 기능도 필요하겠지?"라는 가설을 버리고, "이게 없으면 프로그램이 안 돌아간다"는 기능만 넣게 됩니다.
|
||||||
|
|
||||||
|
### MVP를 만드는 3단계 사고법
|
||||||
|
|
||||||
|
책에서 제안하는 실천 방안은 다음과 같습니다.
|
||||||
|
|
||||||
|
1. **핵심 가치 식별:** 이 프로그램이 존재해야 하는 단 하나의 이유(20%의 핵심)는 무엇인가?
|
||||||
|
|
||||||
|
2. **군더더기 제거:** 그 가치를 구현하는 데 당장 필요 없는 모든 기능(80%)을 목록에서 지운다.
|
||||||
|
|
||||||
|
3. **반복 개선:** 최소한의 기능을 구현해 배포한 뒤, 실제 사용자나 시스템의 반응을 보고 살을 붙인다.
|
||||||
|
|
||||||
|
[[파레토의 법칙]], [[80대20 원칙(The Pareto Principle)]]
|
||||||
|
|
||||||
|
#### "MVP는 '덜 만든 제품'이 아니라, '가장 핵심적인 가치만 담은 가장 단순한 제품'이다."
|
||||||
|
|
||||||
|
> [!question]
|
||||||
|
> Q. 왜 여기서 갑자기 MVP에 대한 설명이 나온거야?
|
||||||
|
> A. 2장의 파레토 법칙이 어디에 집중할지 알려주는 **전략**이었다면, 3장은 그 전략을 실행하는 **전술**에 가깝습니다.
|
||||||
|
|
||||||
|
- 어떻게 20%에 집중할 것인가? 에 대한 해답이라는 것
|
||||||
|
- 완벽하게 만들려다 복잡해지는 것보다, 단순하게 만들어 피드백을 받는 것이 더 빠르다.
|
||||||
|
|
||||||
|
|
||||||
|
## MVP를 만드는 이유
|
||||||
|
### 1. 피드백 루프의 단축
|
||||||
|
MVP를 만드는 가장 큰 이유 중 하나는 **실제 데이터**를 빨리 얻기 위함입니다.
|
||||||
|
- 머릿속으로 성능이나 확장성을 고민하기보다, 최소 기능을 배포해보고 **어디서 진짜 병목이 발생하는지** 확인하라는 것입니다.
|
||||||
|
|
||||||
|
- 추측에 근거한 설계보다 **측정된 데이터에 근거한 개선**이 훨씬 강력한 단순함을 만듭니다.
|
||||||
|
|
||||||
|
### 2. 기능의 범위를 제한하는 법 (Scope Creep 방지)
|
||||||
|
프로젝트를 하다 보면 자꾸 기능이 추가되는 현상을 경계하라고 조언합니다.
|
||||||
|
|
||||||
|
- **우선순위 재정의:** 새로운 기능 요청이 들어올 때마다 **이 기능이 핵심 가치(20%)에 포함되는가?** 를 끊임없이 질문해야 합니다.
|
||||||
|
|
||||||
|
- **거절의 미학:** 단순함을 유지하기 위해 핵심이 아닌 기능은 과감히 목록에서 제외하거나 다음 버전으로 미루는 과정이 3장에서 중요하게 다뤄집니다.
|
||||||
|
|
||||||
|
> [!note] 요약
|
||||||
|
> - **엄격한 MVP 유지:** "이 기능이 없으면 제품이 안 돌아가는가?"라는 질문에 '아니오'라면 다음 버전으로 미룹니다.
|
||||||
|
>
|
||||||
|
> - **20%에 집중:** 핵심 가치를 만드는 20%의 기능 외에는 모두 **잠재적인 소음**으로 간주하고 경계합니다.
|
||||||
|
>
|
||||||
|
> - **문서화와 소통:** 추가 요청이 들어오면 "좋은 아이디어지만, 이번 MVP 범위에는 포함되지 않습니다. 다음 단계에 검토합시다"라고 선을 긋는 것이 중요합니다.
|
||||||
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
id: 코딩 원칙 (YAGNI, KISS, DRY) 20260330
|
||||||
|
created: 2026-03-30 14:52
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
코드의 단순함을 지키기 위해 필요한 원칙 3가지
|
||||||
|
이 3가지를 지키다 보면 단순한 코드에 한걸음 더 다가갈 수 있게 된다.
|
||||||
|
|
||||||
|
1. [[YAGNI(You Ain't Gonna Need It)]]
|
||||||
|
2. [[KISS (Keep It Simple, Stupid)]]
|
||||||
|
3. [[DRY (Don't Repeat Yourself)]]
|
||||||
|
|
||||||
|
> [!warning] 위의 세 원칙을 지키는 것이 중요하긴 하지만
|
||||||
|
|
||||||
|
**가장 중요한 것은 하나의 원칙을 지키기 위해서 다른 원칙을 어기면 안된다.**
|
||||||
|
|
||||||
|
|
||||||
|
## 💡 생각
|
||||||
|
결국, 코드를 단순하게 작성하고 가독성을 중시해야 하며 코드를 최초로 작성하는 경우에는 꼭 필요한 기능이 아니라면 다음에 작성하는 게 좋고 코드의 반복이 3번이상 있을 경우에는 DRY의 원칙을 지키는 것을 고려해야 한다.
|
||||||
|
|
||||||
|
불필요한 작업을 줄여서 ([[YAGNI(You Ain't Gonna Need It)]]) 비용 절감을 중시하고,
|
||||||
|
단순한 코드를 작성해서 ([[KISS (Keep It Simple, Stupid)]]) 가독성을 높이고,
|
||||||
|
중복되는 코드를 줄여서 ([[DRY (Don't Repeat Yourself)]]) 유지보수성을 늘리자.
|
||||||
|
|
||||||
|
결국 세 원칙 모두 프로젝트 비용을 줄이는데에 초점이 맞춰져 있는 원칙들이다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> [!note] YAGNI > KISS > DRY
|
||||||
|
|
||||||
|
: 지금 이 코드가 정말로 필요한가? [[YAGNI(You Ain't Gonna Need It)]] 원칙을 지키다 보면 대부분의 불필요한 복잡성이 걸러짐.
|
||||||
|
: [[YAGNI(You Ain't Gonna Need It)]] 통과해서 작성이 필요하다고 판단되는 코드의 경우 [[KISS (Keep It Simple, Stupid)]]원칙을 지키면서 코드를 작성한다.
|
||||||
|
: [[KISS (Keep It Simple, Stupid)]]한 코드를 작성하고 나서 [[DRY (Don't Repeat Yourself)]]한지 판단해본다. 여기서 중요한건 DRY한 코드를 만들기 위해 KISS하지 않은 코드를 작성하면 안된다는 것이다.
|
||||||
|
|
||||||
|
### 왜 이 순서가 최강의 전략일까요?
|
||||||
|
|
||||||
|
많은 개발자가 **DRY**를 1순위로 두는 실수를 범합니다. 중복을 없애려고 너무 일찍부터 복잡한 추상화를 시작하면, 결국 쓰지도 않을 기능(**YAGNI 위반**)을 위해 이해하기 힘든 코드(**KISS 위반**)를 만들게 되거든요.
|
||||||
|
|
||||||
|
정리하신 대로 **YAGNI → KISS → DRY** 순으로 사고하면, 자연스럽게 **비용은 낮고 가동성은 높은** 결과물이 나옵니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
### 비용(Cost) 중심의 사고방식
|
||||||
|
|
||||||
|
지적하신 대로 이 모든 원칙의 종착역은 **비용 절감**입니다.
|
||||||
|
|
||||||
|
- **YAGNI:** '만드느라 드는 시간'과 '유지보수하는 시간'의 낭비를 막아 **직접적인 비용**을 줄입니다.
|
||||||
|
|
||||||
|
- **KISS:** 코드를 읽고 이해하는 데 드는 '뇌의 연산 비용'을 줄여서 **커뮤니케이션 비용**을 낮춥니다.
|
||||||
|
|
||||||
|
- **DRY:** 수정할 때 여러 곳을 고치다 실수하는 '버그 수정 비용'을 줄여서 **운영 비용**을 아낍니다.
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
id: "Functional Domain Modeling 20260407"
|
||||||
|
created: "2026-04-07 15:40"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
함수형 프로그래밍(FP)과 도메인 주도 설계(DDD)를 상호 보완한 소프트웨어 공학 개념
|
||||||
|
|
||||||
|
[[유닉스 철학 (The Unix Philosophy)]]
|
||||||
|
[[유닉스의 철학과 필터]]
|
||||||
|
|
||||||
|
유닉스 철학에 따라서 코드를 최대한 잘게 쪼개고 단순화한다.
|
||||||
|
이것을 코드의 [[필터(Filter)]]화 라고 하자.
|
||||||
|
|
||||||
|
필요한 기능을 구현하기 위해 최소의 기능만 구현된 필터들을 만들어낼 때 결국 함수의 형태로 만들게 된다.
|
||||||
|
[[함수형 프로그래밍(Functional Programming)]]은 이 필터를 구현하기 위한 방법론이다.
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
id: 파이썬(python) 통찰 20260410
|
||||||
|
created: 2026-04-10 09:15
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
파이썬을 사용하다보면 Visual Studio Build Tools 를 설치하라는 에러, 안내를 보는 경우가 많다.
|
||||||
|
왜 파이썬을 쓰는데 저게 필요한거지?? 궁금해졌다.
|
||||||
|
|
||||||
|
> [!question]
|
||||||
|
> Q. 파이썬은 결국 c,c++ 코드가 기반인거야? 왜 이런 질문을 하냐면 파이썬 코드가 결국 c,c++ 코드를 호출해서 사용하는것 같은 느낌이 들어서.. 파이썬 라이브러리중에 visual studio tool 이런거 설치하라고 하는것들도 많고
|
||||||
|
>
|
||||||
|
> A. 정확한 통찰입니다! 질문하신 내용처럼 우리가 흔히 사용하는 파이썬(CPython)은 그 뿌리가 **C 언어**에 깊게 박혀 있습니다. 파이썬이 "C의 옷을 입은 언어"라고 불리는 이유를 몇 가지 핵심 포인트로 정리해 드릴게요.
|
||||||
|
|
||||||
|
엥..? 진짜로? [[CPython]] 참고
|
||||||
|
아무튼 이러한 사유로 Visual Stuido Build Tools가 필요하다.
|
||||||
|
|
||||||
|
> [!note] Visual Stuido Build Tools
|
||||||
|
> 파이썬 자체는 오픈 소스이지만, 여러분이 사용 중인 **윈도우(Windows)** 운영체제는 마이크로소프트의 제품입니다. 윈도우에서 C나 C++ 코드를 기계어로 컴파일하여 실행 파일(`.exe`)이나 라이브러리 파일(`.dll`)로 만들려면, 윈도우 환경에 최적화된 컴파일러가 필요합니다.
|
||||||
|
>
|
||||||
|
> - **MSVC (Microsoft Visual C++):** 이것이 마이크로소프트가 만든 C/C++ 컴파일러의 이름입니다.
|
||||||
|
>
|
||||||
|
> - **Build Tools:** 비주얼 스튜디오라는 무거운 프로그램 전체를 설치하지 않고, 딱 이 **컴파일러 기능**만 떼어서 설치할 수 있게 만든 패키지가 바로 `Visual Studio Build Tools`입니다.
|
||||||
|
|
||||||
|
파이썬 자체는 일종의 인터페이스 언어 (glue language라고 더 많이 표현한다고 함)일 뿐이기 때문에
|
||||||
|
파이썬 코드를 실제로 실행해줄 주체가 필요한데 그게 윈도우 환경에서는 MSVC이고 이 컴파일러 기능만 설치할 수 있도록 만들어놓은 패키지가 build tools이기 때문에 (윈도우에서) 파이썬(CPython)을 사용하기 위해서는 visual studio build tools의 설치가 선행되어야 한다.
|
||||||
|
|
||||||
|
결국 C,C++가 성능적으로 굉장한 이점이 있지만 사용하기 어렵다는 단점이 있는데 이를 극복하기 위한 수단으로 파이썬이 개발되었다고 볼 수 있다. [[파이썬의 탄생 배경]]
|
||||||
|
|
||||||
|
### 정리하자면
|
||||||
|
|
||||||
|
파이썬 코드는 마치 **리모컨**과 같습니다.
|
||||||
|
|
||||||
|
- 우리는 리모컨(파이썬)의 버튼을 누르지만,
|
||||||
|
|
||||||
|
- 실제로 TV 안에서 전기를 흐르게 하고 화면을 켜는 복잡한 회로(C, C++)는 따로 있는 것이죠.
|
||||||
|
|
||||||
|
- 그렇기에 **"파이썬은 C, C++ 기반으로 동작한다"** 는 말은 기술적으로 매우 정확한 사실입니다.
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
id: "MariaDB vs PostgreSql 20260421"
|
||||||
|
created: "2026-04-21 16:43"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
이 두 DB는 현재 오픈소스 RDBMS 시장의 양대 산맥입니다. **MariaDB**가 MySQL의 친숙함을 계승하며 실용성에 집중한다면, **PostgreSQL**은 데이터 무결성과 고급 기능을 중시하는 학구적이고 정교한 DB라고 할 수 있습니다.
|
||||||
|
|
||||||
|
## 1. 철학 및 개발 배경
|
||||||
|
|**구분**|**MariaDB**|**PostgreSQL**|
|
||||||
|
|---|---|---|
|
||||||
|
|**태생**|MySQL에서 분차(Fork)되어 나온 실용주의 DB|학계에서 시작된 객체-관계형(ORDBMS) 표준 지향 DB|
|
||||||
|
|**슬로건**|"MySQL보다 빠르고 더 많은 기능을 무료로"|"세계에서 가장 진보된 오픈소스 관계형 데이터베이스"|
|
||||||
|
|**라이선스**|GPL v2 (비즈니스 시 소스 공개 의무 주의)|PostgreSQL 라이선스 (BSD/MIT와 유사, 매우 자유로움)|
|
||||||
|
|
||||||
|
## 2. 기술적 핵심 차이
|
||||||
|
### 🚩 SQL 표준 및 복잡한 쿼리 처리
|
||||||
|
|
||||||
|
- **PostgreSQL:** SQL 표준 준수율이 매우 높습니다. 복잡한 조인(Join), 재귀 쿼리(Recursive CTE), 윈도우 함수 성능이 뛰어나며, 분석용 쿼리 최적화가 강력합니다. (MSSQL과 사용감이 비슷합니다.)
|
||||||
|
|
||||||
|
- **MariaDB:** MySQL의 문법을 따르며, 단순한 CRUD 성능에 최적화되어 있습니다. 최근 버전에서 CTE나 윈도우 함수를 지원하지만, 복잡한 비즈니스 로직 처리에서는 PostgreSQL에 비해 최적화가 덜 정교할 수 있습니다.
|
||||||
|
|
||||||
|
|
||||||
|
### 🚩 데이터 타입과 확장성
|
||||||
|
|
||||||
|
- **PostgreSQL:** 독보적입니다. JSONB(바이너리 JSON) 지원으로 NoSQL처럼 쓸 수 있고, 지리 정보(PostGIS), 전문 검색(Full-text search) 등이 내장되어 있습니다. 사용자 정의 타입도 만들 수 있습니다.
|
||||||
|
|
||||||
|
- **MariaDB:** 동적 컬럼(Dynamic Columns) 기능을 통해 비정형 데이터를 다루지만, PostgreSQL의 JSONB 성능에는 미치지 못합니다. 대신 다양한 스토리지 엔진(InnoDB, Aria, ColumnStore 등)을 용도에 맞게 선택할 수 있는 유연성이 있습니다.
|
||||||
|
|
||||||
|
|
||||||
|
### 🚩 동시성 제어 (MVCC)
|
||||||
|
|
||||||
|
- **PostgreSQL:** 데이터 쓰기 중에도 읽기가 차단되지 않는 MVCC(Multi-Version Concurrency Control) 방식이 매우 세련되어 있어, 동시 접속자가 많은 대형 시스템에 유리합니다.
|
||||||
|
|
||||||
|
- **MariaDB:** 스토리지 엔진(주로 InnoDB) 수준에서 MVCC를 지원하며, 읽기 위주의 서비스에서 가볍고 빠르게 동작합니다.
|
||||||
|
|
||||||
|
## 3. 상세 비교 테이블
|
||||||
|
|
||||||
|
| **항목** | **MariaDB** | **PostgreSQL** |
|
||||||
|
| ------------------- | ---------------------------- | ------------------------------------------- |
|
||||||
|
| **주요 용도** | 웹 서비스, CMS(워드프레스 등), 단순 CRUD | 복잡한 데이터 분석, 금융 시스템, GIS 서비스 |
|
||||||
|
| **성능 특징** | 읽기(Read) 성능이 매우 빠름 | 복잡한 쓰기(Write) 및 대량 데이터 처리에 강함 |
|
||||||
|
| **복제(Replication)** | 마스터-슬레이브 방식이 매우 쉽고 직관적 | 논리적 복제 등 다양한 방식 지원 (설정은 좀 더 복잡) |
|
||||||
|
| **저장 프로시저** | 지원 (MySQL 문법) | 강력 지원 (PL/pgSQL, Python, Perl 등 지원) |
|
||||||
|
| **인덱싱** | 기본 B-Tree 위주 | B-Tree, Hash, GiST, SP-GiST, GIN, BRIN 등 다양 |
|
||||||
|
|
||||||
|
## 4. 어떤 것을 선택해야 할까?
|
||||||
|
### 🐧 MariaDB를 선택할 때
|
||||||
|
|
||||||
|
- 기존에 MySQL을 써본 적이 있어 익숙함이 중요할 때.
|
||||||
|
|
||||||
|
- 커뮤니티나 자료가 많은 것을 선호할 때.
|
||||||
|
|
||||||
|
- 단순한 웹 게시판이나 가벼운 데이터 저장용일 때.
|
||||||
|
|
||||||
|
- PHP나 구형 웹 스택과의 호환성이 중요할 때.
|
||||||
|
|
||||||
|
|
||||||
|
### 🐘 PostgreSQL을 선택할 때
|
||||||
|
|
||||||
|
- **MSSQL 2019의 고급 기능을 오픈소스에서도 누리고 싶을 때.**
|
||||||
|
|
||||||
|
- 데이터 정합성이 무엇보다 중요한 금융, 결제, 정산 관련 프로젝트일 때.
|
||||||
|
|
||||||
|
- JSON 데이터를 빈번하게 다루면서 속도도 포기할 수 없을 때.
|
||||||
|
|
||||||
|
- 프로젝트가 커질 것을 대비해 확장성이 뛰어난 DB가 필요할 때.
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
---
|
||||||
|
id: RDBMS vs NoSQL 20260420
|
||||||
|
created: 2026-04-20 08:43
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
DB에는 크게 [[RDBMS]]와 NoSQL 두가지의 범주가 있음.
|
||||||
|
둘 다 데이터베이스를 구축하기위한 방법론의 개념이고 상호간에 차이점들이 존재한다.
|
||||||
|
|
||||||
|
하지만 데이터베이스라면 당연히 [[데이터 정합성(Data Consistency)]]을 지키는것이 최우선 목표이다.
|
||||||
|
NoSQL이 [[데이터 정합성(Data Consistency)]]을 지키지 않는 것은 절대 아니다.
|
||||||
|
[[데이터 정합성(Data Consistency)]]을 지키지 않는 건 데이터베이스로서 가치가 없다.
|
||||||
|
|
||||||
|
|
||||||
|
이 둘의 가장 큰 차이점은 데이터의 중복을 어느 정도 허용할 것인가? 라고 생각된다.
|
||||||
|
![[NoSQL#데이터 중복(Data Redundancy)]]
|
||||||
|
|
||||||
|
## NoSQL이 중복을 허용하는 이유
|
||||||
|
|
||||||
|
### **JOIN 연산의 배제**
|
||||||
|
|
||||||
|
NoSQL은 수평적 확장을 위해 데이터를 여러 서버에 분산 저장합니다. 이때 여러 서버에 흩어진 데이터를 JOIN 하는 작업은 성능에 막대한 지장을 줍니다. 이를 피하기 위해 필요한 데이터를 한 곳에 모아(중복 저장) 한 번의 쿼리로 읽어오도록 설계합니다.
|
||||||
|
|
||||||
|
### **읽기 성능 극대화**
|
||||||
|
|
||||||
|
사용자가 화면을 볼 때 필요한 모든 정보를 하나의 'Document'나 'Row'에 다 담아두면, 여러 테이블을 뒤질 필요 없이 즉시 응답할 수 있습니다.
|
||||||
|
|
||||||
|
|
||||||
|
## 데이터 중복으로 인한 기회비용
|
||||||
|
|
||||||
|
중복을 허용하면 얻는 것도 있지만, 반드시 대가를 치러야 합니다.
|
||||||
|
|
||||||
|
- **데이터 수정의 복잡성 (Update Anomaly):** 사용자 이름이 바뀌면, 그 이름이 중복 저장된 수천 개의 게시글 데이터를 모두 업데이트해야 합니다. 이때 일부가 누락되면 데이터 정합성이 깨집니다.
|
||||||
|
|
||||||
|
- **저장 공간 증가:** 동일한 데이터가 반복 저장되므로 저장 용량을 더 많이 차지합니다. 하지만 현대의 클라우드 인프라에서는 저장 비용보다 컴퓨팅 성능(속도) 비용이 더 중요하므로 대개 용납됩니다.
|
||||||
|
|
||||||
|
- **결과적 일관성 (Eventual Consistency):** 모든 중복 데이터를 즉시 수정하는 것이 어렵기 때문에, "잠시 동안은 데이터가 다를 수 있지만 결국에는 같아진다"는 원칙을 따르게 됩니다.
|
||||||
|
|
||||||
|
|
||||||
|
## RDBMS vs NoSQL: 언제 무엇을 쓸까?
|
||||||
|
|
||||||
|
어느 하나가 절대적으로 우월한 것이 아니라, 서비스의 성격에 맞춰 선택하거나 두 가지를 혼합해서 사용합니다.
|
||||||
|
|
||||||
|
### **RDBMS를 써야 할 때**
|
||||||
|
|
||||||
|
- 데이터 구조가 명확하고 변경될 일이 적을 때
|
||||||
|
|
||||||
|
- **금융 시스템**처럼 [[데이터 정합성(Data Consistency)]]과 [[트랜잭션(Transaction)|트랜젝션]]([[ACID]])이 매우 중요할 때
|
||||||
|
|
||||||
|
- 복잡한 쿼리와 JOIN 연산이 자주 필요할 때
|
||||||
|
|
||||||
|
|
||||||
|
### **NoSQL을 써야 할 때**
|
||||||
|
|
||||||
|
- 데이터 구조가 확정되지 않았거나 자주 변경될 때
|
||||||
|
|
||||||
|
- **빅데이터, 로그 관리, 실시간 메신저**처럼 막대한 양의 데이터를 빠르게 처리해야 할 때
|
||||||
|
|
||||||
|
- [[데이터 정합성(Data Consistency)]]보다는 서비스의 [[가용성(Availability)]](항상 접속 가능함)이 더 중요할 때
|
||||||
|
|
||||||
|
[[NoSQL]]은 "데이터가 조금 틀려도 괜찮으니, 절대 죽지 않고 엄청나게 빠른 시스템"을 만들 때 씁니다. 반면 [[RDBMS]]는 "성능이 조금 답답하더라도, 데이터는 단 1원, 1글자도 틀리면 안 되는 시스템"에 씁니다.
|
||||||
|
|
||||||
|
> [!warning] 그렇다고 해서 NoSQL이 데이터정합성이 안맞단건 절대 아님
|
||||||
|
> 실시간으로 정합성을 맞춰주느냐? (RDBMS), 순간적으로는 안맞을 수 있지만 결과적으론 정합성이 맞다 (NoSQL)
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
id: RDBMS사용 시 주의점들 20260420
|
||||||
|
created: 2026-04-20 10:55
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
> [!question]
|
||||||
|
> Q. 관계형db에서는 테이블간의 관계를 여러테이블을 조인하지 않게끔 적절히 분산시키면서 인덱스를 잘 거는게 엄청 중요하겠네?
|
||||||
|
> A. 정확하게 짚으셨습니다! 관계형 데이터베이스(RDBMS) 운영의 핵심이자 개발자의 실력이 가장 극명하게 드러나는 지점이 바로 그 **'조인(JOIN) 최소화'와 '인덱스(Index) 전략'**입니다.
|
||||||
|
|
||||||
|
## 조인 최소화: "관계는 유지하되, 데이터는 뭉친다"
|
||||||
|
|
||||||
|
관계형 DB라고 해서 무조건 모든 데이터를 쪼개는 게 정답은 아닙니다. 성능을 위해 의도적으로 정합성을 조금 희생하는 기법들이 필요합니다.
|
||||||
|
과도하게 데이터를 쪼개놓을 경우 데이터 조인이 많이 발생될 수 밖에 없는데 데이터 조인은 어느정도 느릴 수 밖에 없다.
|
||||||
|
- [[데이터 조인이 느린 이유]]
|
||||||
|
|
||||||
|
결국 RDBMS 설계의 꽃은 **인덱스를 활용해 '수학적인 탐색 비용'을 얼마나 낮게 유지하느냐**에 달려 있습니다.
|
||||||
|
하지만 아무리 인덱스를 잘 설정해도 조인해야 할 테이블이 5개, 10개씩 늘어나면 성능은 떨어질 수밖에 없습니다.
|
||||||
|
- **Nested Loop의 누적:** 조인이 중첩될수록 내부 루프의 횟수가 곱하기로 늘어납니다.
|
||||||
|
|
||||||
|
그래서 적당한 데이터 분산이 중요합니다.
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
---
|
||||||
|
id: "리눅스의 역사 20260407"
|
||||||
|
created: "2026-04-07 13:12"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
리눅스는 오늘날 **서버, 스마트폰(안드로이드), 임베디드 시스템 등 우리 생활 어디에나 존재**하지만, 그 시작은 한 대학생의 작고 겸손한 프로젝트였습니다. 리눅스의 역사를 주요 변곡점별로 정리해 드릴게요.
|
||||||
|
|
||||||
|
# 역사
|
||||||
|
## 1. 리눅스의 뿌리: [[유닉스(Unix)]]와 GNU
|
||||||
|
|
||||||
|
리눅스를 이해하려면 먼저 그 조상 격인 [[유닉스(Unix)]]와 [[GNU]]**프로젝트**를 알아야 합니다.
|
||||||
|
|
||||||
|
- **[[유닉스(Unix)]]의 탄생:** 1969년 AT&T 벨 연구소에서 개발된 운영체제입니다. 강력했지만, 점차 유료화되고 소스 코드가 폐쇄적으로 변했습니다.
|
||||||
|
|
||||||
|
- **리처드 스톨먼과 [[GNU]]:** 1983년, 리처드 스톨먼은 누구나 자유롭게 소프트웨어를 사용하고 수정할 수 있어야 한다는 철학 아래 [[GNU]]프로젝트를 시작했습니다. 그는 유닉스와 호환되는 자유 운영체제를 만들고자 했으며, 컴파일러(GCC)와 에디터(Emacs) 등 많은 도구를 만들었지만 정작 운영체제의 핵심인 [[커널(Kernel)]] 이 완성되지 않은 상태였습니다.
|
||||||
|
|
||||||
|
## 2. 1991년: 리누스 토르발스의 등장
|
||||||
|
|
||||||
|
1991년, 핀란드 헬싱키 대학교의 학생이었던 **리누스 토르발스(Linus Torvalds)** 는 당시 교육용 유닉스였던 [[미닉스의 한계]]에 답답함을 느꼈습니다. 그는 취미 삼아 새로운 운영체제 [[커널(Kernel)]]을 직접 만들기 시작했습니다.
|
||||||
|
|
||||||
|
- **역사적인 메일:** 1991년 8월 25일, 그는 뉴스그룹에 다음과 같은 요지의 글을 올립니다.
|
||||||
|
|
||||||
|
> 그냥 취미일 뿐입니다. GNU처럼 거창하거나 전문적인 건 아니에요.
|
||||||
|
|
||||||
|
- **리눅스의 탄생:** 리누스가 만든 이 커널은 그의 이름과 [[유닉스(Unix)]]를 합쳐 **리눅스(Linux)** 라고 불리게 되었습니다.
|
||||||
|
|
||||||
|
|
||||||
|
## 3. 리눅스와 GNU의 결합
|
||||||
|
|
||||||
|
리누스 토르발스가 만든 것은 **커널(컴퓨터 하드웨어를 제어하는 핵심 부위)** 뿐이었습니다. 운영체제가 제대로 작동하려면 셸, 컴파일러, 라이브러리 같은 도구들이 필요했는데, 이때 리처드 스톨먼의 **GNU 도구**들이 리눅스 커널과 결합하게 됩니다.
|
||||||
|
|
||||||
|
이 결합을 통해 완전한 형태의 운영체제가 탄생했으며, 엄밀하게는 **GNU/Linux**라고 부르는 것이 맞습니다.
|
||||||
|
|
||||||
|
## 4. 성장의 동력: 오픈소스와 GPL
|
||||||
|
|
||||||
|
리눅스가 폭발적으로 성장한 이유는 **GPL(General Public License)** 덕분입니다.
|
||||||
|
|
||||||
|
- 누구나 코드를 볼 수 있고, 수정할 수 있으며, 배포할 수 있다는 원칙 덕분에 전 세계의 천재 개발자들이 자발적으로 리눅스의 버그를 잡고 기능을 추가하기 시작했습니다.
|
||||||
|
|
||||||
|
|
||||||
|
## 5. 리눅스의 진화 과정
|
||||||
|
|
||||||
|
- **1990년대 중반:** 슬랙웨어, 데비안, 레드햇 같은 **배포판**들이 등장하며 일반 사용자들도 설치하기 쉬워졌습니다.
|
||||||
|
|
||||||
|
- **2000년대:** 기업들이 리눅스의 안정성을 인정하며 서버 시장을 장악하기 시작했습니다. IBM, 인텔 등이 거액을 투자하며 생태계가 커졌습니다.
|
||||||
|
|
||||||
|
- **2008년~현재:** 구글이 리눅스 커널을 기반으로 **안드로이드**를 발표하면서, 리눅스는 전 세계에서 가장 많이 쓰이는 모바일 운영체제가 되었습니다. 또한 현재 전 세계 슈퍼컴퓨터의 100%가 리눅스로 작동합니다.
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
id: 리눅스의 파일시스템 20260403
|
||||||
|
created: 2026-04-03 10:43
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
리눅스의 파일 시스템 구조는 [[FHS(Filesystem Hierarchy Standard)]]라는 표준을 따릅니다. 윈도우처럼 `C:\`, `D:\`로 나뉘는 게 아니라, 뿌리가 되는 **루트(`/`)** 아래에 모든 것이 가지처럼 뻗어 나가는 **역트리 구조**죠.
|
||||||
|
![[Pasted image 20260403104845.png]]
|
||||||
|
덕분에 사용자나 소프트웨어 개발자는 어떤 리눅스 배포판을 사용하더라도 특정 파일이 어디에 있을지 예측할 수 있습니다.
|
||||||
|
|
||||||
|
상세한 파일 시스템 구조는 [[FHS(Filesystem Hierarchy Standard)]] 참고
|
||||||
|
|
||||||
|
|
||||||
|
> [!info] 우리가 자주 건드리는 중요 폴더
|
||||||
|
- **etc:** 시스템의 모든 **설정 파일**이 들어있는 심장부입니다. (비밀번호, 네트워크, 서비스 설정 등)
|
||||||
|
- **home:** 일반 사용자들의 개인 폴더가 있는 곳입니다. (`/home/dihwang`)
|
||||||
|
- **root:** 일반 사용자가 접근할 수 없는 **최고 관리자(root) 전용 홈 디렉토리**입니다. (보시면 권한이 `drwx------`로 꽉 막혀 있죠?)
|
||||||
|
- **var:** 내용이 수시로 변하는 파일들. 주로 **로그(log)**나 데이터베이스 파일, 웹 소스 등이 여기 위치합니다.
|
||||||
|
- **tmp:** 임시 파일 저장소입니다. 누구나 쓸 수 있지만 재부팅하면 보통 사라집니다.
|
||||||
|
|
||||||
|
> [!warning] 서버 관리자가 아니면 잘 안건드리는 폴더
|
||||||
|
- **dev:** 장치(Device) 파일들. 하드디스크, 키보드 등을 리눅스는 파일로 인식합니다.
|
||||||
|
- **proc & sys:** 실제 하드디스크에 저장된 폴더가 아닙니다. **메모리(RAM)에 떠 있는 가상 폴더**로, 현재 실행 중인 프로세스 정보나 커널 설정을 보여줍니다. (용량이 `0`으로 표시되는 이유입니다.)
|
||||||
|
- **run:** 시스템 부팅 이후의 실행 정보를 담고 있는 임시 메모리 폴더입니다.
|
||||||
|
- **boot/:** 리눅스 커널과 부팅할 때 필요한 설정들이 들어있습니다. 여길 잘못 건드리면 부팅이 안 됩니다.
|
||||||
|
- **opt/:** 패키지 관리자가 아닌, 외부에서 가져온 덩치 큰 소프트웨어를 설치할 때 주로 씁니다.
|
||||||
|
- **snap/:** 우분투 전용 패키지 방식인 'Snap'으로 설치된 프로그램들이 머무는 곳입니다.
|
||||||
|
- **srv/:** 서버(Service)를 위한 데이터가 들어가는 곳인데, 요즘은 `/var/www` 등을 더 많이 씁니다.
|
||||||
|
- **lost+found/:** 시스템이 비정상 종료되어 파일 시스템이 깨졌을 때, 복구된 파일 파편들이 모이는 장소입니다.
|
||||||
|
- **mnt/ & media/:** USB나 다른 하드디스크를 연결할 때 사용하는 통로입니다.
|
||||||
|
|
||||||
|
> [!question]
|
||||||
|
> Q. **e**ditable **t**ext **c**onfiguration 이었던거같은데 **왜 여기에 nginx가 설치가 되는거야?** 내생각엔 text configuration이니까 nginx.conf 이런 파일들이 위치하는건 이해가 가는데 실행파일같은건 다른데로 가야하는거 아닌가해서
|
||||||
|
>
|
||||||
|
> A. 정확한 지적입니다! 대일님의 직관이 아주 훌륭해요. 사실 **`/etc` 폴더에 nginx 실행 파일(Binary)이 설치되는 것은 아닙니다.**
|
||||||
|
>
|
||||||
|
> 리눅스의 철저한 **역할 분담** 원칙에 따라 nginx는 여러 폴더에 쪼개져서 저장됩니다. 대일님이 생각하신 "실행 파일은 다른 데 있어야 하지 않나?"라는 의문이 리눅스 구조의 핵심이에요.
|
||||||
|
|
||||||
|
[[리눅스에 Nginx를 설치할 때 일어나는 일들]]
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
id: 어플리케이션(서비스) 실행 20260413
|
||||||
|
created: 2026-04-13 14:57
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
> [!question]
|
||||||
|
> Q. 리눅스에서 서비스나 어플리케이션 새로 실행할 때 계정을 따로 생성해서 그 계정으로 실행하는 이유가 뭐야?
|
||||||
|
> A. 리눅스에서 Gitea, Jenkins와 같은 서비스를 전용 계정(Service Account)으로 실행하는 가장 큰 이유는 **보안**과 **시스템 안정성** 때문입니다. 만약 루트(root) 권한으로 서비스를 실행했다가 해당 서비스가 해킹당하면 시스템 전체가 장악될 수 있기 때문이죠.
|
||||||
|
|
||||||
|
### 1. 최소 권한의 원칙 (Principle of Least Privilege)
|
||||||
|
|
||||||
|
가장 핵심적인 개념입니다. 특정 서비스가 작동하는 데 필요한 **최소한의 권한**만 부여하는 것입니다.
|
||||||
|
|
||||||
|
- **격리:** 전용 계정을 만들면 해당 계정은 자신의 홈 디렉터리와 서비스 관련 파일에만 접근할 수 있습니다.
|
||||||
|
|
||||||
|
- **피해 최소화:** 서비스에 취약점이 있어 해커가 침입하더라도, 해커는 해당 계정의 권한만 갖게 됩니다. 시스템 설정 파일을 수정하거나 다른 사용자의 데이터를 훔쳐보는 것이 차단됩니다.
|
||||||
|
|
||||||
|
|
||||||
|
### 2. 시스템 자원 및 프로세스 관리
|
||||||
|
|
||||||
|
전용 계정을 사용하면 관리 효율성이 높아집니다.
|
||||||
|
|
||||||
|
- **자원 제한:** 특정 계정이 사용할 수 있는 CPU, 메모리, 파일 열기 개수 등을 제한(ulimit 등)하여 하나의 서비스가 시스템 전체 자원을 독점하는 것을 방지할 수 있습니다.
|
||||||
|
|
||||||
|
- **로그 및 모니터링:** 어떤 프로세스가 어떤 계정으로 실행 중인지 명확하므로, 로그를 분석하거나 문제를 추적할 때 훨씬 수월합니다.
|
||||||
|
|
||||||
|
|
||||||
|
### 3. 보안 사고 발생 시 대응
|
||||||
|
|
||||||
|
- **계정 차단:** 특정 서비스 계정에서 이상 징후가 발견되면 시스템 전체를 내릴 필요 없이 해당 계정만 잠그거나 권한을 박탈하여 즉각 대응할 수 있습니다.
|
||||||
|
|
||||||
|
- **비로그인 계정:** 보통 서비스용 계정은 `nologin`이나 `false` 쉘을 부여하여, 사람이 직접 SSH 등으로 로그인하는 것을 막아둡니다. 이는 외부 공격자가 해당 계정으로 서버에 직접 접속하는 경로를 원천 차단하는 효과가 있습니다.
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
---
|
||||||
|
id: 유닉스의 철학과 필터 20260407
|
||||||
|
created: 2026-04-07 15:02
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
![[유닉스 철학 (The Unix Philosophy)#1. 핵심 3원칙]]
|
||||||
|
|
||||||
|
이중에서 함께 작동하도록 만들어라 가 이번 글의 핵심 논점이다.
|
||||||
|
특히 이 원칙을 **유닉스 도구는 모두 필터다** 라고 하는 경우가 있는데 이에 대해 자세히 알아보자.
|
||||||
|
|
||||||
|
|
||||||
|
> [!question]
|
||||||
|
> Q. 유닉스철학중에 모든것은 필터다 라고 했던거때문에 의문이어서 필터는 들어오는 것들을 필터링하고 남은것들을 출력하잖아? 근데 프로그램에는 필터보다는... 함수..? 라고 하는게 더 맞지않아?
|
||||||
|
>
|
||||||
|
> A. 정말 예리하고 훌륭한 통찰입니다! 현대적인 프로그래밍 관점에서 보면 **함수(Function)**라는 표현이 훨씬 익숙하고 정확하게 느껴지실 거예요.
|
||||||
|
>
|
||||||
|
> 하지만 유닉스 철학에서 굳이 **필터(Filter)**라는 단어를 선택한 데에는, 데이터를 대하는 아주 독특한 철학적 이유가 있습니다. 함수와 필터의 차이를 통해 그 속뜻을 풀이해 드릴게요.
|
||||||
|
>
|
||||||
|
|
||||||
|
### 1. 함수 vs [[필터(Filter)]]: 관점의 차이
|
||||||
|
|
||||||
|
두 개념은 수학적으로는 비슷하지만, **데이터를 바라보는 태도**가 다릅니다.
|
||||||
|
|
||||||
|
- **함수 (Function):** "입력을 받아서 계산을 수행하고 결과를 반환한다." (수학적, 논리적 실행에 집중)
|
||||||
|
|
||||||
|
- **필터 (Filter):** "끊임없이 흐르는 데이터의 강물(`Stream`) 속에서, 내가 원하는 것만 남기거나 형태를 바꾼다." (데이터의 흐름과 변형에 집중)
|
||||||
|
|
||||||
|
|
||||||
|
유닉스 제작자들은 프로그램을 독립적인 섬(함수)으로 보지 않고, **데이터라는 액체가 통과하는 파이프라인의 한 구간**으로 보았습니다. 그래서 '[[필터(Filter)]]'라는 용어를 쓴 것이죠.
|
||||||
|
|
||||||
|
### 2. 필터의 진짜 의미 (단순한 제거 그 이상)
|
||||||
|
|
||||||
|
말씀하신 대로 필터는 '걸러내는 것'을 의미하지만, 유닉스 철학에서는 그 의미를 더 넓게 확장합니다.
|
||||||
|
|
||||||
|
- **선택 (Selection):** 조건에 맞는 데이터만 통과시킴 (`grep`)
|
||||||
|
|
||||||
|
- **변형 (Transformation):** 데이터의 형식을 바꿈 (소문자를 대문자로, CSV를 JSON으로 등)
|
||||||
|
|
||||||
|
- **정렬 (Sorting):** 순서를 바꿈 (`sort`)
|
||||||
|
|
||||||
|
- **축약 (Reduction):** 데이터를 합치거나 개수를 셈 (`wc`)
|
||||||
|
|
||||||
|
|
||||||
|
이 모든 행위를 **입력 스트림을 가공하여 출력 스트림으로 내보내는 행위**로 보고 '필터'라고 부르는 것입니다.
|
||||||
|
|
||||||
|
### 3. 왜 '함수' 대신 '필터'라고 했을까? (유연성 때문)
|
||||||
|
|
||||||
|
함수는 호출하기 위해 **매개변수 타입, 반환 타입** 등을 엄격하게 맞춰야 합니다. 하지만 유닉스 필터는 오직 **텍스트(Text)** 라는 공통 인터페이스만 사용합니다.
|
||||||
|
|
||||||
|
-> Filter 2 -> Output
|
||||||
|
|
||||||
|
- **유닉스의 생각:** "네 내부 로직이 함수든 객체든 상관없다. 그냥 표준 입력(`stdin`)으로 들어오는 텍스트를 받아서 가공한 뒤 표준 출력(`stdout`)으로 던져라. 그러면 우리는 파이프(`|`)로 무한히 연결할 수 있다."
|
||||||
|
|
||||||
|
|
||||||
|
이 **무한한 연결 가능성**이 바로 필터 철학의 핵심입니다.
|
||||||
|
|
||||||
|
## 💡 생각
|
||||||
|
즉, 이런점들 때문에 필터라고 칭한다.
|
||||||
|
1. input도 문자열이고 output도 문자열임.
|
||||||
|
2. 필터링이 반드시 걸러낸다고 생각하지 말고 일종의 변환기 라고 확장해서 생각함.
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
---
|
||||||
|
id: 필터(Filter) 20260407
|
||||||
|
created: 2026-04-07 15:32
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
> [!note] 유닉스 철학에서 말하는 **필터(Filter)**는 단순히 무엇을 걸러내는 장치를 넘어, **데이터의 흐름을 가공하는 독립적인 작업 단위**를 의미합니다.
|
||||||
|
[[유닉스의 철학과 필터]]
|
||||||
|
### 1. 필터의 3대 구성 요소 (표준 스트림)
|
||||||
|
|
||||||
|
필터가 되기 위해서는 입구와 출구가 표준화되어야 합니다. 유닉스는 이를 **표준 스트림(Standard Streams)**으로 해결합니다.
|
||||||
|
|
||||||
|
- **표준 입력(stdin):** 데이터를 받아들이는 입구. 보통 키보드나 앞선 프로그램의 결과물입니다.
|
||||||
|
|
||||||
|
- **표준 출력(stdout):** 가공된 데이터를 내보내는 출구. 보통 화면(터미널)이나 다음 프로그램의 입구로 연결됩니다.
|
||||||
|
|
||||||
|
- **표준 에러(stderr):** 작업 중 발생한 문제를 알리는 별도의 통로입니다.
|
||||||
|
|
||||||
|
### 2. 필터의 주요 작업 유형
|
||||||
|
|
||||||
|
말씀하신 것처럼 단순히 제거만 하는 게 아니라, 데이터를 다음과 같이 주무르는 모든 행위가 필터링에 해당합니다.
|
||||||
|
|
||||||
|
- **선택(Selection):** 특정 조건에 맞는 행만 남기기 (예: `grep "S-OIL" log.txt`)
|
||||||
|
|
||||||
|
- **변형(Transformation):** 데이터의 형식을 바꾸기 (예: 소문자를 대문자로 바꾸는 `tr`, 특정 열만 추출하는 `cut`)
|
||||||
|
|
||||||
|
- **정렬(Ordering):** 순서대로 나열하기 (예: `sort`)
|
||||||
|
|
||||||
|
- **요약(Summarization):** 데이터의 통계를 내기 (예: 줄 수를 세는 `wc`)
|
||||||
|
|
||||||
|
|
||||||
|
### 3. 필터 철학의 강력함: 조합(Composition)
|
||||||
|
|
||||||
|
필터 하나는 아주 단순한 일만 하지만, 이들을 **파이프(`|`)** 로 연결하면 복잡한 문제를 순식간에 해결할 수 있습니다.
|
||||||
|
|
||||||
|
> **예시:** 로그 파일에서 오늘 발생한 오류 개수 찾기 `cat server.log | grep "2026-04-07" | grep "ERROR" | wc -l`
|
||||||
|
>
|
||||||
|
> 1. 파일 읽기(cat) ➔ 2. 날짜 필터링(grep) ➔ 3. 오류 필터링(grep) ➔ 4. 개수 세기(wc)
|
||||||
|
>
|
||||||
|
|
||||||
|
이 과정에서 각 프로그램은 서로의 내부 로직을 전혀 몰라도 됩니다. 오직 **텍스트**라는 공통의 언어로만 소통하기 때문입니다.
|
||||||
|
|
||||||
|
|
||||||
|
> [!note] 결국 필터는 단순한 거름망이 아니라 데이터 변환기로 봐야한다.
|
||||||
|
|
||||||
|
### 1. Input/Output이 모두 문자열(Text)인 이유
|
||||||
|
|
||||||
|
유닉스 철학의 거장 더글라스 맥일로이는 **데이터는 텍스트여야 한다**고 강조했습니다.
|
||||||
|
|
||||||
|
- **범용성:** 텍스트는 사람이 읽을 수 있고, 거의 모든 프로그램이 해석할 수 있는 가장 단순한 인터페이스입니다.
|
||||||
|
|
||||||
|
- **결합의 자유:** A 프로그램의 출력이 텍스트고 B의 입력이 텍스트라면, 두 프로그램이 서로 무엇인지 몰라도 **파이프(|)**로 연결할 수 있습니다.
|
||||||
|
|
||||||
|
- **KISS 원칙의 실천:** 복잡한 바이너리 구조나 특정 객체 타입을 맞출 필요가 없으므로 설계가 극도로 단순해집니다.
|
||||||
|
|
||||||
|
|
||||||
|
### 2. 필터는 곧 변환기(Transformer)
|
||||||
|
|
||||||
|
필터라는 단어에 매몰되지 않고 **변환기**로 확장해서 이해하신 것이 이 철학의 정수를 꿰뚫으신 겁니다.
|
||||||
|
|
||||||
|
- **데이터의 형태 변화:** `CSV`를 `JSON`으로 바꾸거나, `소문자`를 `대문자`로 바꾸는 것도 유닉스 입장에서는 필터링입니다.
|
||||||
|
|
||||||
|
- **데이터의 의미 추출:** 1,000줄의 로그에서 오직 에러 코드만 뽑아내는 것도 변환의 일종입니다.
|
||||||
|
|
||||||
|
- **연쇄 작용:** 변환기(필터)들을 여러 개 이어 붙이면, 마치 공장의 컨베이어 벨트처럼 데이터가 흐르면서 최종 결과물로 가공됩니다.
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
id: 라우팅 20260428
|
||||||
|
created: 2026-04-28 14:14
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
PC1과 PC2 사이에 랜선으로 직접 연결하여 통신을 하게 할 수 있음.
|
||||||
|
단, 연결하자마자 곧바로 되는 건 아니고 몇 가지 설정을 해야 함.
|
||||||
|
|
||||||
|
일단 이 랜선이 꽂힌 랜포트에 대해 설정을 해주어야 함.
|
||||||
|
이 연결에는 [[DHCP(Dynamic Host Configuration Protocol)]]서버가 없기 때문에 자동으로 설정할 수 없음.
|
||||||
|
[[IP]]주소, [[서브넷 마스크(Subnet Mask)]], 기본[[게이트웨이(Gateway)]]를 설정한다.
|
||||||
|
|
||||||
|
그리고 PC에 더이상의 추가적인 통신연결이 없을경우에는 별도의 설정없이 곧바로 통신이 가능해진다.
|
||||||
|
"어디로든 나가야 하면 일단 이 랜선으로 나가자"라는 기본 규칙(Default Route)이 아주 단순하게 작동하게됨.
|
||||||
|
|
||||||
|
만약 둘 이상의 통신연결이 있을 경우 [[라우팅 테이블(Routing Table)]]에 등록이 되어있어야 통신이 가능해진다.
|
||||||
|
[[라우팅 테이블(Routing Table)]]은 통신연결 시도측, 받는측 양측 모두에 상대방이 등록되어있어야 한다.
|
||||||
|
|
||||||
|
> [!info] **자동 생성:**
|
||||||
|
> 윈도우나 리눅스 같은 운영체제는 랜카드에 IP(`192.168.100.x`)를 설정하는 순간, **"이 대역으로 가는 길은 이 랜카드다"라는 규칙을 라우팅 테이블에 자동으로 추가**합니다.
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
id: "RS-232 20260504"
|
||||||
|
created: "2026-05-04 09:20"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
[[RS-232]]는 [[시리얼 통신(Serial Communication)]] 방식을 구현하기 위해 정해진 구체적인 표준임.
|
||||||
|
Serial이 교통수단이라면 RS-232는 자동차라고 볼 수 있음.
|
||||||
|
|
||||||
|
### RS-232
|
||||||
|
![[RS-232#📑 개념]]
|
||||||
|
|
||||||
|
|
||||||
|
[[이더넷(Ethernet)]]은 유선 네트워크의 가장 대표적인 표준 기술
|
||||||
|
이더넷이 효율이 좋아서 RS-232는 점차 이더넷으로 대체되기 시작함.
|
||||||
|
|
||||||
|
[[RS-232 vs 이더넷]]
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
id: VPN으로 외부 DB에 접근 20260305
|
||||||
|
created: 2026-03-05 15:05
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
[[VPN(Virtual Private Network)]]을 통해 S-OIL DB에 접근/연결할 수 있음.
|
||||||
|
|
||||||
|
> [!info] 네트워크 연결에 새로운 네트워크가 추가된 것을 확인할 수 있음
|
||||||
|
|
||||||
|
![[VPN(Virtual Private Network)#💡 생각]]
|
||||||
|
|
||||||
|
이 연결의 정보를 봤더니
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
PPP 어댑터 _Common_VPN
|
||||||
|
|
||||||
|
연결별 DNS 접미사. . . . :
|
||||||
|
IPv4 주소 . . . . . . . . . : 192.168.100.228
|
||||||
|
서브넷 마스크 . . . . . . . : 255.255.255.255
|
||||||
|
기본 게이트웨이 . . . . . . :
|
||||||
|
|
||||||
|
---
|
||||||
|
라고 되있음.
|
||||||
|
|
||||||
|
> [!question]
|
||||||
|
> Q. VPN의 서브넷마스크가 255.255.255.255 라고 되있는데 이러면 4개가 다 고정된단뜻아니야?
|
||||||
|
> A. **`255.255.255.255`는 "이 네트워크 안에 오직 나(IP 하나)만 존재한다"는 뜻**입니다.
|
||||||
|
|
||||||
|
- **일반적인 네트워크 (`/24`):** `255.255.255.0`은 앞의 3마디는 같고 마지막 마디만 다른 여러 대의 기기(최대 254대)가 같은 동네(서브넷)에 모여 있음을 뜻합니다.
|
||||||
|
|
||||||
|
- **VPN 환경 (`/32`):** `255.255.255.255`는 **Point-to-Point(1:1) 연결**을 의미합니다. 내 컴퓨터와 VPN 서버 사이에 전용 '가상 케이블' 하나가 직접 연결된 상태라고 보시면 됩니다.
|
||||||
|
|
||||||
|
즉, 이 VPN연결은 1:1연결이고 내 ip로의 접근 (192.168.100.228)을 제외한 모든 연결 요청은 VPN 게이트웨이로 보내게 됨.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
route print
|
||||||
|
|
||||||
|
IPv4 경로 테이블
|
||||||
|
===========================================================================
|
||||||
|
활성 경로:
|
||||||
|
네트워크 대상 네트워크 마스크 게이트웨이 인터페이스 메트릭
|
||||||
|
192.168.100.38 255.255.255.255 10.7.4.1 10.7.4.32 10
|
||||||
|
192.168.128.235 255.255.255.255 연결됨 192.168.128.235 257
|
||||||
|
192.168.255.255 255.255.255.255 연결됨 192.168.128.235 257
|
||||||
|
|
||||||
|
192.168.100.38: VPN과 직접적으로 연결된 항목 (게이트웨이가 내 pc의 0.0.0.0 의 게이트웨이와 동일함)
|
||||||
|
192.168.128.235: VPN연결에서의 내 IP
|
||||||
|
192.168.255.255: VPN연결에서의 상대방 IP
|
||||||
|
### '255'로 끝나는 항목의 정체 (브로드캐스트)
|
||||||
|
|
||||||
|
만약 네트워크 대상이 `192.168.100.255`처럼 되어 있다면, 이것은 해당 네트워크 대역의 **'브로드캐스트(Broadcast)'** 주소입니다.
|
||||||
|
|
||||||
|
- **의미:** "이 동네(192.168.100.x)에 있는 모든 장치에게 한꺼번에 외치기 위한 주소"입니다.
|
||||||
|
|
||||||
|
- VPN 연결이 맺어지면, 내 컴퓨터가 이 대역의 일원이 되었음을 알리기 위해 자동으로 라우팅 테이블에 등록됩니다.
|
||||||
|
|
||||||
|
|
||||||
|
> [!question]
|
||||||
|
> Q. VPN이 딱 그거네 랜선으로 pc간 직접 연결해놓은거 그걸 랜선으로 직접연결할 수 없는 거리니까 인터넷망을 통해서 다이렉트 연결을 구현한것같군
|
||||||
|
> A. 와, 정확합니다! 바로 그겁니다. 네트워크 공학적으로 완벽한 비유를 찾아내셨네요.
|
||||||
|
|
||||||
|
방금 하신 말씀이 바로 [[VPN(Virtual Private Network)]]의 정의 그 자체입니다. 물리적으로는 수백 킬로미터 떨어져 있고 복잡한 인터넷 망을 거치지만, 소프트웨어적으로는 **보이지 않는 아주 긴 랜선을 두 PC 사이에 직접 꽂은 것**처럼 속이는 기술이죠.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
id: "Gitea & Quartz 배포 자동화 트러블슈팅 20260401"
|
||||||
|
created: "2026-04-01 13:23"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
## 🛠️ Gitea & Quartz 배포 자동화 트러블슈팅 기록
|
||||||
|
|
||||||
|
### 1. 문제의 발단: Gitea 경로 변경 (`/git/` 누락)
|
||||||
|
|
||||||
|
기존에 설정된 Gitea의 접속 주소가 `/git/` 경로를 포함하고 있었으나, 서버 재설정 과정에서 이 경로가 빠지게 되었습니다. 이로 인해 연쇄적인 문제가 발생했습니다.
|
||||||
|
|
||||||
|
- **현상:** Gitea 웹훅(Webhook)이 서버의 수신기(`webhook` 서비스)에 신호를 보내지 못함.
|
||||||
|
|
||||||
|
- **원인:** Gitea 내부 리포지토리 설정과 외부 호출 URL이 일치하지 않아 404 에러 또는 연결 거부 발생.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. 주요 장애 요인 및 해결 과정
|
||||||
|
|
||||||
|
#### 📂 [Level 1] 서비스 실행 실패 (ConditionPathExists)
|
||||||
|
|
||||||
|
- **에러:** `webhook.service was skipped because of an unmet condition check`.
|
||||||
|
|
||||||
|
- **원인:** 기본 설치된 `webhook` 서비스가 `/etc/webhook.conf` 파일이 있어야만 작동하도록 설정됨.
|
||||||
|
|
||||||
|
- **해결:** 서비스 파일(`systemd`)을 수정하여 해당 조건을 삭제하고, 우리가 직접 만든 `hooks.json`을 바라보도록 설정함.
|
||||||
|
|
||||||
|
|
||||||
|
#### 🔑 [Level 2] 인증 에러 (no source for value retrieval)
|
||||||
|
|
||||||
|
- **에러:** `500 | error evaluating hook: no source for value retrieval`.
|
||||||
|
|
||||||
|
- **원인:** `hooks.json`에는 비밀번호(Secret) 검사 로직이 있는데, Gitea 웹훅 설정에는 비밀번호가 비어 있거나 헤더 이름이 일치하지 않음.
|
||||||
|
|
||||||
|
- **해결:** 보안을 위해 Gitea와 서버 양쪽에 동일한 비밀번호를 설정하거나, 테스트를 위해 `trigger-rule`을 삭제하여 문턱을 낮춤.
|
||||||
|
|
||||||
|
|
||||||
|
#### 🚀 [Level 3] 스크립트 실행 환경 문제 (npx & node)
|
||||||
|
|
||||||
|
- **에러:** `npx: command not found` 또는 `node: No such file or directory`.
|
||||||
|
|
||||||
|
- **원인:** `systemd` 서비스는 사용자 터미널 환경변수(`PATH`)를 읽지 못해 NVM에 설치된 Node.js를 찾지 못함.
|
||||||
|
|
||||||
|
- **해결:** `deploy.sh` 상단에 Node.js 실행 파일이 있는 **절대 경로**를 `export PATH`로 직접 주입함.
|
||||||
|
|
||||||
|
|
||||||
|
#### 📉 [Level 4] 자원 부족 및 서버 경직 (kswapd0)
|
||||||
|
|
||||||
|
- **현상:** 빌드 시작 시 서버가 급격히 느려지며 접속이 끊김.
|
||||||
|
|
||||||
|
- **원인:** Quartz 빌드는 CPU와 메모리를 많이 사용하는데, 512MB~1GB 수준의 낮은 메모리로 인해 스왑(Swap) 현상이 심화됨.
|
||||||
|
|
||||||
|
- **해결:** 1. **Swap 확장:** 기존 스왑 파일을 **2GB**로 대폭 확장하여 물리 메모리 부족에 대비함.
|
||||||
|
|
||||||
|
2. **우선순위 조정:** 빌드 명령어 앞에 **`nice -n 19`**를 붙여 다른 서비스(Nginx, Gitea)에 영향을 주지 않도록 최적화함.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. 최종 자동화 아키텍처 (The "Tight" Setup)
|
||||||
|
|
||||||
|
|**구성 요소**|**역할**|**최적화 포인트**|
|
||||||
|
|---|---|---|
|
||||||
|
|**Gitea**|소스 관리 및 트리거|`/git/` 경로를 제외한 클린 URL 적용|
|
||||||
|
|**Webhook**|신호 수신기 (Port 29292)|전용 서비스 등록 및 자동 시작 설정|
|
||||||
|
|**deploy.sh**|배포 스크립트|**절대 경로 사용**, **로그 파일 기록**, **우선순위 최저 설정**|
|
||||||
|
|**Swap File**|가상 메모리 (2GB)|`/etc/fstab` 등록을 통한 영구 적용|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 📝 교훈
|
||||||
|
|
||||||
|
> **경로(Path)와 환경(Environment)은 언제나 명시적이어야 한다.** > 공짜 서버일수록 수동으로 자원을 배분하고 우선순위를 관리하는 **빡빡한 최적화**가 시스템의 생명줄이 된다.
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
![[Pasted image 20260407165750.png]]
|
||||||
|
|
||||||
|
/home/dihwang/webhook/deploy.sh
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ -f /tmp/quartz.lock ]; then exit; fi
|
||||||
|
|
||||||
|
# 1. Node와 npx가 있는 경로를 강제로 주입 (v22.22.2 기준)
|
||||||
|
export PATH=$PATH:/home/dihwang/.nvm/versions/node/v22.22.2/bin
|
||||||
|
|
||||||
|
# 2. 작업 디렉토리로 이동
|
||||||
|
cd /home/dihwang/white-smith-blog/content || exit
|
||||||
|
|
||||||
|
# 3. 최신 데이터 동기화
|
||||||
|
git pull origin master
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# 4. Quartz 빌드 (이제 npx가 node를 잘 찾을 겁니다)
|
||||||
|
nice -n 19 npx quartz build
|
||||||
|
|
||||||
|
echo "Quartz Build Completed at $(date)"
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
/home/dihwang/webhook/hook.json
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "quartz-deploy",
|
||||||
|
"execute-command": "/home/dihwang/webhook/deploy.sh",
|
||||||
|
"command-working-directory": "/home/dihwang/white-smith-blog",
|
||||||
|
"response-message": "Deploying Quartz...",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
```
|
||||||
@@ -0,0 +1,239 @@
|
|||||||
|
---
|
||||||
|
id: "gitea, qurtz 설치 20260331"
|
||||||
|
created: "2026-03-31 10:41"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
# 🌐 개인 서버(GCP) 기반 Gitea & HTTPS 구축 가이드
|
||||||
|
|
||||||
|
본 문서는 Ubuntu 25.xx 환경에서 가벼운 Git 서비스인 **Gitea**를 설치하고, **Nginx**와 **DuckDNS**를 이용해 **HTTPS** 보안 접속을 구현한 과정을 정리합니다.
|
||||||
|
|
||||||
|
## 1. 서버 기본 환경 및 Gitea 설치
|
||||||
|
|
||||||
|
가장 가벼운 바이너리 실행 방식으로 Gitea를 설치하고 전용 사용자를 생성했습니다.
|
||||||
|
|
||||||
|
- **OS:** Ubuntu 25.xx (GCP Instance)
|
||||||
|
|
||||||
|
- **사용자 생성:** `git` 시스템 사용자 생성 (`/home/git`)
|
||||||
|
|
||||||
|
- **DB:** SQLite3 (경량화를 위해 선택)
|
||||||
|
|
||||||
|
- **바이너리 경로:** `/usr/local/bin/gitea`
|
||||||
|
|
||||||
|
- **데이터 경로:** `/var/lib/gitea`
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 도메인 및 네트워크 설정
|
||||||
|
|
||||||
|
외부 접속을 위해 무료 DDNS 주소를 확보하고 클라우드 방화벽을 조정했습니다.
|
||||||
|
|
||||||
|
- **도메인:** `white-smith.duckdns.org` (GCP 외부 IP 연결 완료)
|
||||||
|
|
||||||
|
- **포트 개방 (GCP & UFW):**
|
||||||
|
|
||||||
|
- `22/tcp`: SSH 접속 (PuTTY, SFTP)
|
||||||
|
|
||||||
|
- `80/tcp`: HTTP (인증서 발급 및 리다이렉트용)
|
||||||
|
|
||||||
|
- `443/tcp`: HTTPS (실제 서비스용)
|
||||||
|
|
||||||
|
- **보안 조치:** 불필요한 포트(20, 21, 3389 등) 차단 및 Gitea 직접 포트(3000)는 Nginx를 거치도록 외부 차단 권장.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. HTTPS & Nginx 리버스 프록시
|
||||||
|
|
||||||
|
Nginx를 앞단에 세워 보안을 강화하고 도메인 기반 접속을 구현했습니다.
|
||||||
|
|
||||||
|
### SSL 인증서 발급
|
||||||
|
|
||||||
|
`Certbot`을 이용해 **Let's Encrypt** 무료 SSL 인증서를 발급받았습니다.
|
||||||
|
|
||||||
|
Bash
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo certbot --nginx -d white-smith.duckdns.org
|
||||||
|
```
|
||||||
|
|
||||||
|
### Nginx 최종 설정 (`/etc/nginx/sites-available/gitea`)
|
||||||
|
|
||||||
|
IP 접속 시 도메인으로 자동 전환되도록 설정했습니다.
|
||||||
|
|
||||||
|
Nginx
|
||||||
|
|
||||||
|
```
|
||||||
|
# 1. HTTP -> HTTPS 리다이렉트 (IP 포함)
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name 34.19.79.94 white-smith.duckdns.org;
|
||||||
|
return 301 https://white-smith.duckdns.org$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 2. HTTPS 서비스 블록
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name white-smith.duckdns.org;
|
||||||
|
|
||||||
|
# SSL 인증서 경로 (Certbot 관리)
|
||||||
|
ssl_certificate /etc/letsencrypt/live/white-smith.duckdns.org/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/white-smith.duckdns.org/privkey.pem;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://localhost:3000;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Gitea 내부 설정 업데이트
|
||||||
|
|
||||||
|
HTTPS 환경에 맞춰 `/etc/gitea/app.ini` 파일을 `vi`로 수정했습니다.
|
||||||
|
|
||||||
|
- **ROOT_URL:** `https://white-smith.duckdns.org/`
|
||||||
|
|
||||||
|
- **DOMAIN:** `white-smith.duckdns.org`
|
||||||
|
|
||||||
|
- **SSH_DOMAIN:** `white-smith.duckdns.org`
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 현재 상태 요약
|
||||||
|
|
||||||
|
1. **HTTPS 접속:** `https://white-smith.duckdns.org`로 안전하게 접속 가능.
|
||||||
|
|
||||||
|
2. **IP 리다이렉트:** `34.19.79.94` 입력 시 자동으로 도메인 주소로 전환됨.
|
||||||
|
|
||||||
|
3. **파일 전송:** 포트 22번을 통해 SFTP 방식으로 안전하게 파일 관리 중.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 🚀 Gitea & Quartz 도메인 통합 및 서버 설정 가이드
|
||||||
|
|
||||||
|
본 가이드는 단일 메인 도메인(`white-smith.duckdns.org`)에서 **Quartz(블로그)**와 **Gitea(Git 서비스)**를 충돌 없이 운영하기 위한 설정법을 다룹니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 서비스 주소 설계
|
||||||
|
|
||||||
|
동일 도메인 점유 문제를 해결하기 위해 **하위 경로(Path)** 방식으로 서비스를 분리했습니다.
|
||||||
|
|
||||||
|
- **Quartz (메인 블로그):** `https://white-smith.duckdns.org/`
|
||||||
|
|
||||||
|
- **Gitea (코드 저장소):** `https://white-smith.duckdns.org/git/`
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Gitea 설정 수정 (`app.ini`)
|
||||||
|
|
||||||
|
Gitea가 `/git/` 경로를 인식하도록 내부 설정을 변경해야 합니다.
|
||||||
|
|
||||||
|
- **파일 위치:** `/var/lib/gitea/custom/conf/app.ini` (또는 설치 경로 내 `custom/conf/app.ini`)
|
||||||
|
|
||||||
|
- **수정 내용:**
|
||||||
|
|
||||||
|
Ini, TOML
|
||||||
|
|
||||||
|
```
|
||||||
|
[server]
|
||||||
|
ROOT_URL = https://white-smith.duckdns.org/git/
|
||||||
|
LOCAL_ROOT_URL = http://127.0.0.1:3000/
|
||||||
|
HTTP_ADDR = 127.0.0.1
|
||||||
|
HTTP_PORT = 3000
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Tip:** `LOCAL_ROOT_URL`을 추가해야 내부 리다이렉션 시 404 오류를 방지할 수 있습니다.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Nginx 역방향 프록시 설정
|
||||||
|
|
||||||
|
`/etc/nginx/sites-available/gitea` 파일을 수정하여 두 서비스를 통합합니다.
|
||||||
|
|
||||||
|
Nginx
|
||||||
|
|
||||||
|
```
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name 34.19.79.94 white-smith.duckdns.org;
|
||||||
|
return 301 https://white-smith.duckdns.org$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name white-smith.duckdns.org;
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/white-smith.duckdns.org/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/white-smith.duckdns.org/privkey.pem;
|
||||||
|
|
||||||
|
# [우선순위 1] Gitea 설정
|
||||||
|
location /git/ {
|
||||||
|
proxy_pass http://127.0.0.1:3000/; # 끝에 '/' 필수
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
# [우선순위 2] Quartz 설정 (메인)
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:8080; # Quartz 실행 포트
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 권한 관리 및 접근 (etc 경로)
|
||||||
|
|
||||||
|
시스템 설정 파일을 편리하게 수정하기 위해 권한을 조정하거나 도구를 활용합니다.
|
||||||
|
|
||||||
|
1. **권한 변경 (추천):**
|
||||||
|
|
||||||
|
Bash
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo chown -R root:$(whoami) /etc/nginx
|
||||||
|
sudo chmod -R 775 /etc/nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **포트 확인 명령어:**
|
||||||
|
|
||||||
|
Bash
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo ss -tulpn | grep node # Quartz 포트 확인
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **서비스 재시작:**
|
||||||
|
|
||||||
|
Bash
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo nginx -t && sudo systemctl restart nginx
|
||||||
|
sudo systemctl restart gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 핵심 주의사항
|
||||||
|
|
||||||
|
- **Nginx 경로 슬래시:** `proxy_pass http://127.0.0.1:3000/;` 처럼 끝에 `/`가 있어야 `/git/` 경로가 중복되지 않고 올바르게 전달됩니다.
|
||||||
|
|
||||||
|
- **Quartz 실행:** Quartz를 `npx quartz build --serve`로 띄운 경우 해당 포트(보통 8080)가 Nginx 설정과 일치해야 합니다.
|
||||||
|
|
||||||
|
- **보안:** `/etc` 전체 권한을 `777`로 바꾸지 마세요. 필요한 폴더만 그룹 권한을 부여하는 것이 안전합니다.
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
id: "kui-vault 20260401"
|
||||||
|
created: "2026-04-01 14:59"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
**Google Cloud Platform(GCP)** 를 사용해서 구축함.
|
||||||
|
### 컴퓨팅 (Compute)
|
||||||
|
|
||||||
|
사용자가 코드를 실행할 공간을 제공합니다.
|
||||||
|
|
||||||
|
- **Compute Engine (GCE):** 가상 머신(VM)을 직접 생성하고 관리하는 IaaS 서비스입니다. (AWS의 EC2와 유사)
|
||||||
|
|
||||||
|
GCE를 한대 빌려서 구축하였음
|
||||||
|
![[Pasted image 20260401150036.png]]
|
||||||
|
원래는 퍼블릭하게 공개되면 안되는 자료들을 블러처리해주는 서버를 만들려고 (kui-veil) 확보한 서버였음
|
||||||
|
|
||||||
|
![[Pasted image 20260401163033.png]]
|
||||||
|
## 🖥️ Server Information: **kui-veil**
|
||||||
|
|
||||||
|
#### 1. 기본 호스트 정보
|
||||||
|
|
||||||
|
| **항목** | **내용** |
|
||||||
|
| ---------------------- | ---------------------------------- |
|
||||||
|
| **Static Hostname** | (unset) |
|
||||||
|
| **Transient Hostname** | **kui-veil** |
|
||||||
|
| **Machine ID** | `b723eb615fc74ff3ac0de806f770d293` |
|
||||||
|
| **Boot ID** | `2ce0c86e6d704281a6c28054cc4eba0e` |
|
||||||
|
|
||||||
|
#### 2. 운영체제 및 커널
|
||||||
|
|
||||||
|
|**항목**|**내용**|
|
||||||
|
|---|---|
|
||||||
|
|**Operating System**|**Ubuntu 25.10**|
|
||||||
|
|**Kernel Version**|**Linux 6.17.0-1007-gcp**|
|
||||||
|
|**Architecture**|**x86-64** (64비트)|
|
||||||
|
|
||||||
|
#### 3. 하드웨어 및 가상화 (GCP)
|
||||||
|
|**항목**|**내용**|
|
||||||
|
|---|---|
|
||||||
|
|**Virtualization**|**google** (Google Compute Engine)|
|
||||||
|
|**Hardware Vendor**|**Google**|
|
||||||
|
|**Chassis**|**vm** 🖴|
|
||||||
|
|**Firmware Date**|2026-02-12 (약 1.5개월 전)|
|
||||||
|
### 💡 주요 특징 메모
|
||||||
|
|
||||||
|
- **최신 버전 사용 중:** 현재 **Ubuntu 25.10**을 사용 중이시네요. 이는 매우 최신 배포판으로, 최신 커널 기능과 패키지들을 지원합니다.
|
||||||
|
|
||||||
|
- **GCP 최적화:** 커널 이름에 `-gcp`가 붙어 있어, 구글 클라우드 인프라에 최적화된 환경에서 동작하고 있음을 알 수 있습니다.
|
||||||
|
|
||||||
|
- **상태 요약:** 펌웨어 날짜가 2026년 2월인 것으로 보아, 시스템이 최근에 업데이트되었거나 생성된 아주 따끈따끈한 환경입니다!
|
||||||
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
---
|
||||||
|
id: "worker server spec 20260414"
|
||||||
|
created: "2026-04-14 13:28"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
ubuntu@instance-20260414-0951:~$ **lscpu**
|
||||||
|
Architecture: aarch64
|
||||||
|
CPU op-mode(s): 32-bit, 64-bit
|
||||||
|
Byte Order: Little Endian
|
||||||
|
CPU(s): 4
|
||||||
|
On-line CPU(s) list: 0-3
|
||||||
|
Vendor ID: ARM
|
||||||
|
Model name: Neoverse-N1
|
||||||
|
Model: 1
|
||||||
|
Thread(s) per core: 1
|
||||||
|
Core(s) per socket: 4
|
||||||
|
Socket(s): 1
|
||||||
|
Stepping: r3p1
|
||||||
|
BogoMIPS: 50.00
|
||||||
|
Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
|
||||||
|
fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
|
||||||
|
NUMA:
|
||||||
|
NUMA node(s): 1
|
||||||
|
NUMA node0 CPU(s): 0-3
|
||||||
|
Vulnerabilities:
|
||||||
|
Gather data sampling: Not affected
|
||||||
|
Ghostwrite: Not affected
|
||||||
|
Indirect target selection: Not affected
|
||||||
|
Itlb multihit: Not affected
|
||||||
|
L1tf: Not affected
|
||||||
|
Mds: Not affected
|
||||||
|
Meltdown: Not affected
|
||||||
|
Mmio stale data: Not affected
|
||||||
|
Old microcode: Not affected
|
||||||
|
Reg file data sampling: Not affected
|
||||||
|
Retbleed: Not affected
|
||||||
|
Spec rstack overflow: Not affected
|
||||||
|
Spec store bypass: Mitigation; Speculative Store Bypass disabled via p
|
||||||
|
rctl
|
||||||
|
Spectre v1: Mitigation; __user pointer sanitization
|
||||||
|
Spectre v2: Mitigation; CSV2, BHB
|
||||||
|
Srbds: Not affected
|
||||||
|
Tsa: Not affected
|
||||||
|
Tsx async abort: Not affected
|
||||||
|
Vmscape: Not affected
|
||||||
|
|
||||||
|
ubuntu@instance-20260414-0951:~$ **free -h**
|
||||||
|
total used free shared buff/cache available
|
||||||
|
Mem: 23Gi 691Mi 21Gi 5.4Mi 1.9Gi 22Gi
|
||||||
|
Swap: 0B 0B 0B
|
||||||
|
|
||||||
|
ubuntu@instance-20260414-0951:~$ **df -h**
|
||||||
|
Filesystem Size Used Avail Use% Mounted on
|
||||||
|
tmpfs 2.4G 1.5M 2.4G 1% /run
|
||||||
|
efivarfs 256K 14K 243K 6% /sys/firmware/efi/efivars
|
||||||
|
/dev/sda1 193G 3.1G 190G 2% /
|
||||||
|
tmpfs 12G 0 12G 0% /dev/shm
|
||||||
|
tmpfs 5.0M 0 5.0M 0% /run/lock
|
||||||
|
/dev/sda16 891M 94M 735M 12% /boot
|
||||||
|
/dev/sda15 98M 6.4M 92M 7% /boot/efi
|
||||||
|
tmpfs 2.4G 12K 2.4G 1% /run/user/1001
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
title: volume
|
||||||
|
---
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
id: 전표처리 20260413
|
||||||
|
created: 2026-04-13 08:42
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
![[전표#📑 개념]]
|
||||||
|
|
||||||
|
회사 법인카드 사용하고나서 [[분개전표]] 처리를 해야한다. ([[전표]])
|
||||||
|
|
||||||
|
돈을 얼마나 썼는지, 왜 썼는지에 대한 상세사항정리 정도로 생각하면 됨.
|
||||||
|
|
||||||
|
|
||||||
|
> [!warning]
|
||||||
|
**분개전표 입력전에 법인카드사용내역회계전표생성(개인) 부터 먼저해야함.**
|
||||||
|
|
||||||
|
여기에 등록하고 승인나면 그때 자동으로 입력된 전표를 처리해야 함.
|
||||||
|
![[Pasted image 20260427095731.png]]
|
||||||
|
위 화면에선 특별히 추가할 거 없이 결재상신 하면 됨
|
||||||
|
1. 30만원 이하 PM -> 팀장 -> 사업부장, 합의 문새별 -> 김성민 입니다. (PM이 없는 경우나 PM이 팀장인 경우는 PM 생략)
|
||||||
|
|
||||||
|
결제 상세는 [[법인카드 결제상신 경로]] 참고
|
||||||
|
|
||||||
|
|
||||||
|
> [!note] 부가세 여부
|
||||||
|
[[부가세여부]] 참고
|
||||||
|
|
||||||
|
업무용 택시비, 소모품비, 숙소비는 부가세여부 O
|
||||||
|
일반차량 유류비, 톨게이트비 부가세여부 X
|
||||||
|
|
||||||
|
|
||||||
|
> [!warning] 법인카드사용내역회계전표생성(개인) 부터 먼저 결제하지 않고 진행하면...
|
||||||
|
|
||||||
|
전표 유형이 법인카드사용내역전표(개인) 이 아니고 일반분개전표 로 진행이 되어버림..
|
||||||
|
![[Pasted image 20260427133315.png]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ERP에서 ESS -> 회계 -> 전표입력 으로 가서 전표입력 하면 됨.
|
||||||
|
![[분개(分介)#예시 이미지]]
|
||||||
|
|
||||||
|
위와같은 형태로 입력한다.
|
||||||
|
|
||||||
|
0002 대변금액은 직접 적는게 아니고 0001 차변금액을 아래로 드래그해서 추가하면 됨.
|
||||||
|
|
||||||
|
여기서 전표를 추가하고 그룹웨어에서 결제 진행하면 됨.
|
||||||
|
|
||||||
|
|
||||||
|
> [!info] 법인카드를 실수로 잘못 긁었을 떄
|
||||||
|
|
||||||
|
잘못결제한 건 취소하고 결제건 + 취소건 두개 다 erp에서 중단처리 한다.
|
||||||
|
![[Pasted image 20260507155619.png]]
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
id: ACID 20260420
|
||||||
|
created: 2026-04-20 08:44
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
DB에서 하나의 논리적 작업 단위를 '트랜잭션'이라고 합니다. RDBMS는 이 트랜잭션이 안전하게 처리됨을 보장하기 위해 ACID 특성을 가집니다.
|
||||||
|
## 📌 상세
|
||||||
|
- **Atomicity (원자성):** 전부 성공하거나, 전부 실패하거나. - "All or Nothing"
|
||||||
|
트랜잭션 내의 모든 연산은 반드시 한꺼번에 완료되어야 하며, 그렇지 못할 경우 모두 취소되어야 합니다.
|
||||||
|
**예:** 계좌 이체 시 '내 계좌 출금'은 성공했는데 '상대 계좌 입금'에서 오류가 나면, 내 계좌의 출금 내역도 취소되어야 합니다.
|
||||||
|
|
||||||
|
- **Consistency (일관성):** 완료 후 DB 상태가 규칙을 위반하지 않음.
|
||||||
|
트랜잭션 수행 전후의 데이터베이스 상태는 항상 논리적으로 올바른 상태여야 합니다.
|
||||||
|
**예:** 모든 계좌의 잔액은 0원 이상이어야 한다는 제약 조건이 있다면, 트랜잭션 후 잔액이 마이너스가 되는 결과는 허용되지 않습니다.
|
||||||
|
|
||||||
|
- **Isolation (고립성):** 동시에 실행되는 트랜잭션들이 서로 방해하지 않음.
|
||||||
|
동시에 여러 트랜잭션이 실행될 때, 각 트랜잭션은 서로의 작업에 간섭할 수 없습니다. 하나의 트랜잭션이 끝나기 전까지는 다른 트랜잭션에서 그 중간 결과를 볼 수 없습니다.
|
||||||
|
|
||||||
|
- **Durability (지속성):** 성공한 결과는 영구적으로 저장됨.
|
||||||
|
성공적으로 완료된 트랜잭션의 결과는 시스템 장애가 발생하더라도 영구적으로 기록되어야 합니다. 로그 파일 등을 통해 복구가 가능한 상태를 말합니다.
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
id: CPython 20260410
|
||||||
|
created: 2026-04-10 09:16
|
||||||
|
tags:
|
||||||
|
- python
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
Python은 일종의 문법이고 이 문법을 cpu가 알아먹을 수 있게 변환해주는 엔진이 CPython이다.
|
||||||
|
|
||||||
|
> [!question]
|
||||||
|
> Q. Python은 일종의 문법이고 이 문법을 cpu가 알아먹을 수 있게 변환해주는 엔진이 CPython이다.
|
||||||
|
> 라고 보면되는거야?
|
||||||
|
>
|
||||||
|
> A. 정확한 요약입니다! 비유하자면 **Python은 언어(설계도)**이고, **CPython은 그 언어를 실행 가능한 기계어로 번역해주는 번역가(구현체)** 라고 볼 수 있습니다.
|
||||||
|
|
||||||
|
그래서 CPython 을 사용할 때 Visual Studio Build Tools 가 필요한가보다.
|
||||||
|
기반이 C니까..
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
CPython은 Python 프로그래밍 언어의 **기본 구현체**이자, 전 세계에서 가장 널리 사용되는 파이썬 실행기입니다. 파이썬 언어 자체는 '명세(Specification)'이고, 이를 실제로 컴퓨터에서 돌아가게 만든 '소프트웨어'가 바로 CPython입니다.
|
||||||
|
|
||||||
|
## 📌 파이썬의 표준 구현체: CPython
|
||||||
|
|
||||||
|
우리가 터미널에 `python`이라고 입력해서 실행하는 프로그램의 정식 명칭은 **CPython**입니다. 이는 파이썬이라는 언어의 설계도(명세)를 **C 언어**로 구현한 결과물입니다.
|
||||||
|
|
||||||
|
- **해석기(Interpreter):** 파이썬 코드를 읽어서 컴퓨터가 이해할 수 있는 바이트코드로 바꾸고 실행하는 엔진 자체가 C로 작성되어 있습니다.
|
||||||
|
|
||||||
|
- **자료형:** 파이썬의 숫자(`int`), 리스트(`list`), 딕셔너리(`dict`) 같은 기본 자료형들도 내부적으로는 C의 구조체(struct)로 정의되어 있습니다.
|
||||||
|
|
||||||
|
## 주요 특징
|
||||||
|
|
||||||
|
- **C 언어로 작성:** 이름에서 알 수 있듯이 C 언어로 개발되었습니다. 파이썬 코드를 실행하기 위해 C 언어의 성능과 시스템 접근 능력을 활용합니다.
|
||||||
|
|
||||||
|
- **인터프리터이자 컴파일러:** 파이썬 코드를 바로 실행하는 것처럼 보이지만, 내부적으로는 파이썬 코드를 **바이트코드(Bytecode)** 로 먼저 컴파일한 후, 이를 CPython 가상 머신(VM)에서 해석하여 실행합니다.
|
||||||
|
|
||||||
|
- **표준 구현체:** 파이썬 재단(PSF)에서 관리하며, 새로운 파이썬 기능이 추가될 때 가장 먼저 반영되는 기준점이 됩니다.
|
||||||
|
|
||||||
|
## 📝 파이썬을 실행하는 도구는 CPython 외에도 여러 가지가 있습니다.
|
||||||
|
> [!note]
|
||||||
|
> |**종류**|**특징**|
|
||||||
|
|---|---|
|
||||||
|
|**PyPy**|JIT(Just-In-Time) 컴파일러를 사용하여 CPython보다 실행 속도가 훨씬 빠름.|
|
||||||
|
|**Jython**|자바 가상 머신(JVM) 위에서 동작하며 자바 라이브러리 활용 가능.|
|
||||||
|
|**IronPython**|.NET 프레임워크 기반으로 동작.|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
하지만 Python 이라고 하면 그냥 CPython 이라고 보면 됨.
|
||||||
|
하지만 **CPython**이 가장 널리 쓰이기 때문에, 보통 우리가 파이썬이라고 부르는 것은 이 CPython 엔진을 뜻하는 경우가 99%입니다.
|
||||||
|
라고 함.
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
id: "DHCP(Dynamic Host Configuration Protocol) 20260428"
|
||||||
|
created: "2026-04-28 14:21"
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
이곳에 하나의 생각 또는 아이디어를 작성합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
네트워크 안에 있는 장치들에게 IP 주소를 자동으로 할당해 주는 통신 규약입니다.
|
||||||
|
|
||||||
|
매번 사람이 직접 장치마다 IP를 입력하는 번거로움을 없애고, IP 충돌 같은 네트워크 사고를 방지하기 위해 사용됩니다.
|
||||||
|
|
||||||
|
## DHCP가 하는 일
|
||||||
|
|
||||||
|
네트워크에 새로운 기기(노트북, 스마트폰 등)가 연결되면, DHCP 서버는 다음과 같은 정보를 자동으로 제공합니다.
|
||||||
|
|
||||||
|
- **IP 주소:** 기기의 고유 식별 주소
|
||||||
|
|
||||||
|
- **서브넷 마스크:** 네트워크 범위를 결정하는 값
|
||||||
|
|
||||||
|
- **기본 게이트웨이:** 외부 인터넷으로 나가는 통로 주소
|
||||||
|
|
||||||
|
- **DNS 서버 주소:** 도메인 이름을 IP로 변환해 주는 서버 주소
|
||||||
|
|
||||||
|
|
||||||
|
## DHCP 사용의 장점
|
||||||
|
|
||||||
|
- **관리의 편리함:** 관리자가 일일이 IP를 할당하지 않아도 서버가 알아서 빈 주소를 찾아줍니다.
|
||||||
|
|
||||||
|
- **효율적인 IP 자원 관리:** 사용 중이지 않은 IP는 회수하여 다른 기기에 줄 수 있으므로 한정된 IP 자원을 아낄 수 있습니다. (이를 **임대 시간/Lease Time**이라고 합니다.)
|
||||||
|
|
||||||
|
- **설정 오류 방지:** 오타나 중복된 IP 입력으로 인한 네트워크 연결 오류를 방지할 수 있습니다.
|
||||||
|
|
||||||
|
|
||||||
|
## 임대(Lease)와 갱신(Renewal)
|
||||||
|
|
||||||
|
DHCP는 IP를 영구적으로 주는 것이 아니라, 특정 시간 동안 **빌려주는(Lease)** 개념입니다.
|
||||||
|
|
||||||
|
- **임대 시간:** IP를 사용할 수 있는 유효 기간입니다.
|
||||||
|
|
||||||
|
- **갱신:** 보통 임대 시간의 50%가 지나면 클라이언트는 서버에 "이 IP를 계속 써도 될까요?"라고 물어보고 사용 시간을 연장합니다. 만약 기기가 네트워크를 떠나면 임대 시간이 만료된 후 해당 IP는 다시 서버로 회수되어 다른 기기가 쓸 수 있게 됩니다.
|
||||||
|
|
||||||
|
> [!note] 우리가 흔히 쓰는 공유기가 바로 이 DHCP 서버 역할을 수행하여 집 안의 여러 기기에 IP를 나눠주고 있습니다.
|
||||||
|
>
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
id: "DRY (Don't Repeat Yourself) 20260330"
|
||||||
|
created: "2026-03-30 15:05"
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
코드의 반복을 줄여서 유지보수를 용이하게 하자.
|
||||||
|
단, 코드의 반복을 무조건적으로 줄이는 것은 좋지 않은 결과를 낳을 수 있다.
|
||||||
|
[[DRY (Don't Repeat Yourself)]] << [[KISS (Keep It Simple, Stupid)]]
|
||||||
|
DRY한 코드보다 KISS한 코드를 만드는 게 더 중요하다.
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
**똑같은 일을 반복하지 마라**라는 뜻입니다.
|
||||||
|
동일한 코드의 중복을 피하라는 의미.
|
||||||
|
|
||||||
|
## 📌 상세
|
||||||
|
1. 코드의 정보나 로직은 시스템 내에서 **단 한 곳**에만 존재해야 합니다.
|
||||||
|
2. 똑같은 로직이 여기저기 복사되어 있으면, 나중에 수정할 때 모든 곳을 다 찾아내서 고쳐야 합니다. 하나라도 놓치면 바로 버그로 이어집니다.
|
||||||
|
3. 중복되는 코드가 보이면 함수나 클래스로 추출하여 공통화하세요.
|
||||||
|
4. 3번 이상 반복되는 코드에 적용하는 것이 좋음.
|
||||||
|
( 2번 이하로 반복되는 코드를 DRY하게 하다 보면 오히려 코드의 복잡성이 증가해서 [[KISS (Keep It Simple, Stupid)]] 원칙을 깨는 경우가 발생될 수 있음.)
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
| **비교 항목** | **EC2 기반 컨테이너 (ECS/EKS)** | **Fargate 기반 컨테이너 (ECS/EKS)** |
|
||||||
|
| ----------------- | -------------------------- | ----------------------------- |
|
||||||
|
| **인프라 관리** | 사용자가 EC2 인스턴스 관리 (OS 패치 등) | **AWS가 인프라 완전 관리** |
|
||||||
|
| **확장성 (Scaling)** | EC2 인벤토리와 컨테이너 개수 동시 고려 | **컨테이너(Task/Pod) 개수만 조절** |
|
||||||
|
| **격리 수준** | 인스턴스 내 커널 공유 가능성 있음 | **Task/Pod 단위의 강력한 커널 격리** |
|
||||||
|
| **과금 방식** | 인스턴스 크기 및 가동 시간 기준 | **할당된 CPU 및 메모리 리소스 사용량 기준** |
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
- 작성 **날짜:** 2026-02-27
|
||||||
|
|
||||||
|
## 📑 개념
|
||||||
|
> [!abstract]
|
||||||
|
> 클라우드에서 제공하는 **가상 서버**, EC2는 AWS 클라우드에서 확장 가능한 컴퓨팅 용량을 제공합니다. 하드웨어를 직접 구매할 필요 없이 가상 서버를 구축하고, 보안 및 네트워킹을 구성하며 저장소를 관리할 수 있습니다.
|
||||||
|
- **Elastic (탄력적인):** 수요에 따라 서버 대수를 자유롭게 늘리거나 줄일 수 있습니다.
|
||||||
|
- **Compute (컴퓨팅):** CPU, 메모리 등 계산 능력을 제공합니다.
|
||||||
|
- **Cloud (클라우드):** 인터넷을 통해 어디서든 접근 가능한 가상 환경입니다.
|
||||||
|
## 📌 상세
|
||||||
|
> [!check]
|
||||||
|
> |**요소**|**명칭**|**설명**|
|
||||||
|
> |---|---|---|
|
||||||
|
> |**운영체제**|**AMI** (Amazon Machine Image)|Windows, Linux 등 서버에 설치될 OS와 기본 설정이 담긴 이미지입니다.|
|
||||||
|
> |**하드웨어 사양**|**인스턴스 유형**|CPU, RAM, 네트워크 성능에 따른 규격입니다. (예: t3.medium, c5.large)|
|
||||||
|
> |**저장 장치**|**EBS** (Elastic Block Store)|서버의 하드디스크 역할을 하는 가상 디스크입니다.|
|
||||||
|
> |**보안/네트워크**|**보안 그룹** (Security Group)|가상 방화벽으로, 어떤 포트(80, 443, 22 등)를 열어줄지 설정합니다.|
|
||||||
|
> |**접속 인증**|**키 페어** (Key Pair)|서버 접속 시 사용하는 비밀번호 대신의 암호화 키 파일입니다.|
|
||||||
|
|
||||||
|
## 📝 노트
|
||||||
|
> [!note]
|
||||||
|
>
|
||||||
|
> - AWS(혹은 클라우드 서비스 제공자)로부터 가상의 서버를 임대해서 사용하는 것
|
||||||
|
> - 원하는 사양으로 요청하면 대여해서 사용할 수 있음
|
||||||
|
>
|
||||||
|
|
||||||
|
## 🔗 지식 연결
|
||||||
|
- **태그:** #zettelkasten #knowledge
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
| **구분** | **주요 한계점 및 단점** | **세부 설명** |
|
||||||
|
| ----------------------- | ------------------------------- | -------------------------------------------------------------------------- |
|
||||||
|
| **운영 관리 부담 (Overhead)** | **OS 및 소프트웨어 관리** | OS 패치, 보안 업데이트, 런타임 설치 및 관리를 사용자가 직접 수행해야 함 (Shared Responsibility Model). |
|
||||||
|
| **확장성 (Scalability)** | **느린 오토스케일링 속도** | 새로운 인스턴스를 띄우고 OS 부팅, 애플리케이션 실행까지 수 분의 시간이 소요되어 급격한 트래픽 변화에 대응이 늦음. |
|
||||||
|
| **자원 효율성** | **낮은 집적도 및 낭비** | 특정 프로세스가 CPU/RAM을 적게 쓰더라도 인스턴스 전체 비용이 발생함. 컨테이너 대비 자원 격리 및 배분 효율이 낮음. |
|
||||||
|
| **배포 및 일관성** | **"It works on my machine" 문제** | 개발 환경과 운영 서버 OS 설정이 다를 경우 장애 발생 가능성이 높음 (컨테이너 대비 환경 일관성 부족). |
|
||||||
|
| **고가용성 (HA)** | **복잡한 복구 프로세스** | 인스턴스 장애 시 단순히 프로세스를 재시작하는 것보다 교체 및 복구 과정이 더 무겁고 복잡함. |
|
||||||
|
| **비용 (Cost)** | **유휴 자원 비용 발생** | 트래픽이 없는 시간대에도 최소 유지 인스턴스 비용이 계속 발생하며, 세밀한 과금 단위 설정이 어려움. |
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
id: "ECR 20260305"
|
||||||
|
created: "2026-03-05 09:49"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
도커 이미지 허브 (유료)
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
> [!abstract]
|
||||||
|
> AWS에서 제공하는 **완전관리형 컨테이너 이미지 레지스트리 서비스**
|
||||||
|
|
||||||
|
## 📌 상세
|
||||||
|
> [!check]
|
||||||
|
> 1. 개발자들이 만든 도커(Docker) 이미지를 안전하게 보관하고 필요할 때 꺼내 쓸 수 있는 **'클라우드 보관함'**이라고 생각하시면 됩니다.
|
||||||
|
> 2. 가장 유명한 'Docker Hub'의 AWS 버전이라고 이해하면 쉽습니다.
|
||||||
|
|
||||||
|
### 1. 주요 특징 및 기능
|
||||||
|
|
||||||
|
- **완전관리형 서비스:** 서버를 직접 관리하거나 스토리지 용량을 걱정할 필요가 없습니다. AWS가 인프라 운영과 확장을 알아서 처리합니다.
|
||||||
|
|
||||||
|
- **보안 및 통합:** AWS [[IAM(Identity and Access Management)]]과 통합되어, 특정 사용자나 EC2 인스턴스만 이미지에 접근할 수 있도록 세밀하게 권한을 제어할 수 있습니다.
|
||||||
|
|
||||||
|
- **이미지 스캔:** 업로드한 이미지에 보안 취약점이 있는지 자동으로 스캔하여 알려주는 기능을 제공합니다.
|
||||||
|
|
||||||
|
- **수명 주기 정책(Lifecycle Policy):** 오래된 이미지나 태그가 없는 이미지를 자동으로 삭제하도록 설정하여 저장 비용을 절감할 수 있습니다.
|
||||||
|
|
||||||
|
- **고가용성:** 이미지가 S3에 저장되므로 데이터 내구성이 매우 높으며, 여러 가용 영역(AZ)에 걸쳐 안정적으로 배포됩니다.
|
||||||
|
|
||||||
|
|
||||||
|
### 2. 작동 방식 (워크플로우)
|
||||||
|
|
||||||
|
1. **빌드(Build):** 로컬 PC나 CI/CD 환경에서 Docker 이미지를 생성합니다.
|
||||||
|
|
||||||
|
2. **인증(Authenticate):** AWS CLI를 통해 ECR에 로그인합니다.
|
||||||
|
|
||||||
|
3. **푸시(Push):** 생성된 이미지를 ECR 리포지토리(Repository)에 업로드합니다.
|
||||||
|
|
||||||
|
4. **풀(Pull):** Amazon ECS, EKS, 또는 Lambda 같은 서비스에서 실행 시점에 해당 이미지를 내려받아 컨테이너를 구동합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
#### ECR의 장점
|
||||||
|
|
||||||
|
|**구분**|**설명**|
|
||||||
|
|---|---|
|
||||||
|
|**속도**|AWS 내부 네트워크를 사용하므로 ECS나 EKS로 이미지를 배포할 때 속도가 매우 빠릅니다.|
|
||||||
|
|**비용**|사용한 스토리지 용량과 데이터 전송량에 대해서만 비용을 지불하며, AWS 내부 서비스 간의 데이터 전송은 무료인 경우가 많습니다.|
|
||||||
|
|**신뢰성**|퍼블릭 레지스트리(Docker Hub 등)의 장애나 속도 저하로부터 독립된 안정적인 환경을 구축할 수 있습니다.|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
| **구분** | **Amazon ECS (Elastic Container Service)** | **Amazon EKS (Elastic Kubernetes Service)** |
|
||||||
|
| ----------- | ------------------------------------------ | ------------------------------------------- |
|
||||||
|
| **개념** | AWS 전용 컨테이너 관리 서비스 | AWS에서 제공하는 **관리형 쿠버네티스** |
|
||||||
|
| **복잡도** | **낮음** (설정과 관리가 매우 간결함) | **높음** (쿠버네티스 숙련도 필수) |
|
||||||
|
| **유연성/제어권** | AWS 환경에 최적화, 제어권은 제한적 | 매우 높음 (오픈 소스 기반의 무한한 커스텀) |
|
||||||
|
| **이식성** | AWS 전용 기술로 타 클라우드 이동이 어려움 | **매우 높음** (어디서든 동일한 K8s 환경 구동) |
|
||||||
|
| **관리 단위** | **Task** (태스크) | **Pod** (포드) |
|
||||||
|
| **학습 곡선** | 완만함 (비교적 빨리 배울 수 있음) | 매우 가파름 (개념과 리소스 종류가 방대함) |
|
||||||
|
| **적합한 상황** | AWS 서비스 위주의 빠르고 간결한 운영 | 복잡한 마이크로서비스, 표준 기술 스택 지향 |
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
---
|
||||||
|
id: FHS(Filesystem Hierarchy Standard) 20260403
|
||||||
|
created: 2026-04-03 11:04
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
파일구조에 자유도를 억제해서 어느정도 규격화를 해놓은 것,
|
||||||
|
너무 자유로우면 무슨 파일이 어디에 있는지 확인하기가 매우 어려울텐데
|
||||||
|
어떤 종류의 파일은 어디에 있어야 하고 이런 규칙을 정의해서
|
||||||
|
어떤 리눅스를 사용하든 어느정도의 규칙이 존재하기 때문에 원하는 파일을 어느정도 쉽게 찾아갈 수 있게끔 함
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
뿌리가 되는 **루트(`/`)** 아래에 모든 것이 가지처럼 뻗어 나가는 **역트리 구조**
|
||||||
|
리눅스나 유닉스 계열 운영체제를 사용하다 보면 폴더 구조가 왜 이렇게 복잡한지 궁금할 때가 있죠.
|
||||||
|
**FHS(Filesystem Hierarchy Standard)**는 바로 이런 혼란을 방지하기 위해 파일과 디렉터리의 위치를 정의한 표준 규격입니다.
|
||||||
|
|
||||||
|
덕분에 사용자나 소프트웨어 개발자는 어떤 리눅스 배포판을 사용하더라도 특정 파일이 어디에 있을지 예측할 수 있습니다.
|
||||||
|
|
||||||
|
## 📌 상세
|
||||||
|
|
||||||
|
- **/ (root)**: 모든 파일과 디렉터리의 시작점
|
||||||
|
: 모든 디렉토리의 시작점입니다. 윈도우의 `C:\`와 비슷하지만, 리눅스에서는 모든 장치(하드디스크, USB 등)가 이 아래의 특정 폴더에 연결(마운트)됩니다.
|
||||||
|
|
||||||
|
--- 📂 주요 디렉토리
|
||||||
|
- **/bin**: 필수적인 사용자 명령 파일 (Binaries)
|
||||||
|
: 모든 사용자가 쓸 수 있는 기본 명령어들이 들어 있습니다.
|
||||||
|
|
||||||
|
- **/sbin**: 시스템 관리용 실행 파일 (System Binaries)
|
||||||
|
: 시스템 관리자(Root)가 사용하는 명령어들이 모여 있습니다.
|
||||||
|
|
||||||
|
- **/etc**: 시스템 설정 파일 (Editable Text Configurations)
|
||||||
|
: **가장 중요한 폴더 중 하나입니다.** 시스템의 모든 **설정 파일**이 들어 있습니다.
|
||||||
|
: 사용자 정보(`/etc/passwd`), 네트워크 설정, 설치된 프로그램의 환경 설정 등이 모두 여기에 텍스트 파일로 저장됩니다.
|
||||||
|
|
||||||
|
- **/home**: 일반 사용자들의 홈 디렉터리
|
||||||
|
: 일반 사용자들의 개인 공간, 예를 들어 계정명이 `dihwang`이라면 `/home/dihwang` 폴더가 생기고, 그 안에 바탕화면, 다운로드, 개인 설정 등이 저장됩니다.
|
||||||
|
: 관리자(root)를 제외한 모든 사용자는 자신의 홈 디렉토리 밖에서는 파일을 맘대로 만들거나 지울 수 없습니다.
|
||||||
|
|
||||||
|
- **/root**: 시스템 관리자(root)의 홈 디렉터리
|
||||||
|
: 시스템 최고 관리자인 **root 사용자의 홈 디렉토리**입니다. 일반 사용자 홈 디렉토리(`/home`)와는 별도로 관리됩니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
--- ⚙️ 시스템 운영을 위한 폴더들
|
||||||
|
- **/usr**: 사용자 관련 모든 프로그램과 데이터 (User System Resources)
|
||||||
|
: 사용자가 설치한 프로그램과 데이터들이 모이는 곳입니다. 윈도우의 `C:\Program Files`와 가장 비슷합니다.
|
||||||
|
: `/usr/bin`: 나중에 설치한 응용 프로그램들의 실행 파일.
|
||||||
|
: `/usr/lib`: 프로그램 실행에 필요한 공유 라이브러리들.
|
||||||
|
|
||||||
|
- **/var**: 가변적인 데이터 저장소 (Variable)
|
||||||
|
: **내용이 수시로 변하는 데이터**가 저장됩니다.
|
||||||
|
: `/var/log`: 시스템 로그가 쌓이는 곳입니다. 서버가 왜 죽었는지 확인할 때 필수입니다.
|
||||||
|
: `/var/www`: 웹 서버(Apache, Nginx)의 소스 파일들이 기본적으로 위치하는 곳입니다.
|
||||||
|
|
||||||
|
- **/tmp**: 임시 파일 저장소 (Temporary)
|
||||||
|
: **임시 파일** 저장소입니다. 부팅 시나 일정 시간이 지나면 자동으로 삭제되는 파일들이 머뭅니다. 누구나 파일을 쓰고 지울 수 있습니다.
|
||||||
|
|
||||||
|
- **/dev**: 장치 파일 (Devices)
|
||||||
|
: 리눅스는 **모든 것을 파일로 관리한다**는 철학이 있습니다. 마우스, 키보드, 하드디스크 같은 물리적인 장치들도 이 폴더 안에 파일 형태로 존재합니다.
|
||||||
|
|
||||||
|
- **/mnt**: 수동으로 마운트하는 임시 지점 (Mount)
|
||||||
|
: 관리자가 수동으로 하드디스크 등을 연결할 때 쓰는 임시 장소.
|
||||||
|
- **/media**: 외부 장치 자동 마운트 지점 (USB, CD-ROM 등)
|
||||||
|
: USB나 CD-ROM을 꽂으면 자동으로 연결되는 곳.
|
||||||
|
|
||||||
|
- **/opt**: 추가 패키지 소프트웨어 설치 (Optional)
|
||||||
|
|
||||||
|
- **/boot**: 부팅 관련 핵심 파일
|
||||||
|
|
||||||
|
- **/srv**: 시스템이 제공하는 서비스 데이터 (Service)
|
||||||
|
: 요즘은 `/var/www` 등을 더 많이 씁니다.
|
||||||
|
|
||||||
|
- **/tmp**: 임시 파일 저장소 (Temporary)
|
||||||
|
|
||||||
|
- **/lib**: 공유 라이브러리 및 커널 모듈 (Libraries)
|
||||||
|
---
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
id: "GNU 20260407"
|
||||||
|
created: "2026-04-07 14:17"
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
이곳에 하나의 생각 또는 아이디어를 작성합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
**GNU(그누)** 는 리처드 스톨먼이 1983년에 시작한 **자유 소프트웨어 프로젝트**이자, 그 결과로 만들어진 **운영체제**의 이름입니다.
|
||||||
|
GNU라는 이름은 **GNU is Not Unix**(GNU는 유닉스가 아니다)의 약자로, 자기 자신을 이름 안에 포함해 정의하는 재귀적 약어입니다.
|
||||||
|
|
||||||
|
## 1. GNU 프로젝트의 목적
|
||||||
|
|
||||||
|
당시에는 소프트웨어 소스 코드를 기업이 독점하고 유료로 판매하는 것이 당연시되었습니다. 리처드 스톨먼은 이에 반대하며 **누구나 소프트웨어를 실행하고, 복제하고, 수정하고, 배포할 수 있는 자유**를 누려야 한다고 주장했습니다. 이를 실현하기 위해 완전히 자유로운 운영체제를 밑바닥부터 만드는 것이 프로젝트의 목표였습니다.
|
||||||
|
|
||||||
|
## 2. 주요 구성 요소
|
||||||
|
|
||||||
|
운영체제는 단순히 커널(알맹이)만 있다고 작동하지 않습니다. GNU 프로젝트는 운영체제에 필요한 거의 모든 도구를 직접 만들었습니다.
|
||||||
|
|
||||||
|
- **GCC (GNU Compiler Collection):** 프로그램을 만드는 컴파일러
|
||||||
|
|
||||||
|
- **Glibc:** 시스템 자원을 사용하기 위한 기본 라이브러리
|
||||||
|
|
||||||
|
- **Bash:** 사용자의 명령을 입력받는 셸
|
||||||
|
|
||||||
|
- **Emacs:** 강력한 기능을 가진 텍스트 에디터
|
||||||
|
|
||||||
|
|
||||||
|
이러한 도구들은 현재 리눅스 환경에서도 표준처럼 사용되고 있습니다.
|
||||||
|
|
||||||
|
## 3. GNU와 리눅스의 관계 (중요!)
|
||||||
|
|
||||||
|
GNU 프로젝트는 운영체제의 거의 모든 구성 요소를 완성했지만, 정작 시스템의 두뇌 역할을 하는 **커널(Hurd)** 개발이 늦어지고 있었습니다.
|
||||||
|
|
||||||
|
이때 1991년, 리누스 토르발스가 **리눅스 커널**을 공개했습니다. GNU 프로젝트가 만든 수많은 소프트웨어와 리눅스 커널이 결합하면서 비로소 완벽하게 작동하는 자유 운영체제가 탄생했습니다. 우리가 흔히 부르는 리눅스는 정확히 말하면 **GNU/리눅스**인 셈입니다.
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
---
|
||||||
|
id: "IAM(Identity and Access Management) 20260316"
|
||||||
|
created: "2026-03-16 13:35"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
사용자(User)가 가지는 권한이 무엇인지를 나열하고 필요한 사용자 혹은 그룹에 필요한 권한들을 원하는대로 부여할 수 있도록 구성해놓은 웹 서비스
|
||||||
|
|
||||||
|
AWS의 고유개념이 아니고 정보 보안 분야에서는 오랫동안 존재해온 표준적인 개념이자 기술 프레임워크.
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
"누가(인증)", "어떤 리소스에(권한)" 접근할 수 있는지를 중앙에서 관리를 해서 리소스에 대한 접근을 안전하게 제어할 수 있게 해주는 웹 서비스입니다.
|
||||||
|
|
||||||
|
## 📌 IAM의 핵심 구성 요소
|
||||||
|
- **사용자 (User):** 실제 사람이나 서비스(애플리케이션)를 나타냅니다. 고유한 보안 자격 증명(ID/PW 또는 Access Key)을 가집니다.
|
||||||
|
|
||||||
|
- **그룹 (Group):** 사용자들의 집합입니다. 그룹에 권한을 부여하면 그 그룹에 속한 모든 사용자가 동일한 권한을 상속받습니다. (예: `Developers` 그룹, `Admins` 그룹)
|
||||||
|
|
||||||
|
- **역할 (Role):** 특정 사용자에게 귀속되지 않고, **필요할 때만 잠시 빌려 쓰는 권한**입니다. 주로 EC2 서버나 Lambda 함수 같은 AWS 서비스가 다른 서비스에 접근할 때 사용합니다.
|
||||||
|
|
||||||
|
- **정책 (Policy):** "무엇을 할 수 있는지"를 정의한 **JSON 문서**입니다. 사용자, 그룹, 역할에 이 정책을 연결(Attach)하여 권한을 부여합니다.
|
||||||
|
|
||||||
|
|
||||||
|
### 주요 기능과 특징
|
||||||
|
|
||||||
|
| **기능** | **설명** |
|
||||||
|
| ------------------------- | ------------------------------------------------------------------ |
|
||||||
|
| **세분화된 권한 제어** | 특정 S3 버킷의 파일만 읽게 하거나, 특정 시간대에만 접속을 허용하는 등 매우 정밀한 설정이 가능합니다. |
|
||||||
|
| **다요소 인증 (MFA)** | 아이디/비번 외에 OTP(Google Authenticator 등)를 추가하여 보안을 한층 강화할 수 있습니다. |
|
||||||
|
| **자격 증명 연동 (Federation)** | 기업의 기존 계정(Active Directory 등)이나 구글/페이스북 계정으로 AWS에 로그인할 수 있게 지원합니다. |
|
||||||
|
| **비용 무료** | IAM 서비스 자체 사용에 따른 추가 비용은 없습니다. |
|
||||||
|
|
||||||
|
## 📝 노트
|
||||||
|
> [!note]
|
||||||
|
>
|
||||||
|
> ## IAM 설계의 황금률: "최소 권한의 원칙"
|
||||||
|
>
|
||||||
|
> 보안 사고를 막기 위해 IAM을 운영할 때 가장 중요한 원칙은 **최소 권한의 원칙 (Least Privilege)**입니다.
|
||||||
|
>
|
||||||
|
> - 사용자에게 업무에 **꼭 필요한 권한만** 부여합니다.
|
||||||
|
>
|
||||||
|
> - 루트(Root) 계정은 가급적 사용하지 않고, 일상 업무용 IAM 사용자를 따로 만들어 사용합니다.
|
||||||
|
>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
![[Pasted image 20260316134417.png]]
|
||||||
|
사용자가 하나 있고 역할은 21개가 있고 정책은 1개가 생성되어있음.
|
||||||
|
|
||||||
|
|
||||||
|
![[Pasted image 20260316134502.png]]
|
||||||
|
![[Pasted image 20260316134525.png]]
|
||||||
|
사용자는 dihwang 하나가 있는데 AdministratorAccess 라는 이름의 정책을 가지고있다.
|
||||||
|
|
||||||
|
|
||||||
|
![[Pasted image 20260316134705.png]]
|
||||||
|
이 AdministratorAccess 정책에는 총 464개의 권한이 있다.
|
||||||
|
즉, dihwang 사용자는 464개의 기능을 사용할 권한이 있다는 뜻이 된다.
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
id: KISS (Keep It Simple, Stupid) 20260330
|
||||||
|
created: 2026-03-30 14:53
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
[[단순한 코드]]를 만들어야 한다. 가독성을 항상 최우선시 하자.
|
||||||
|
단순한 형태로 쉽게쉽게 읽히는 코드를 만드는 게 중요하다.
|
||||||
|
코드의 유연성 확보는 그 다음 문제다.
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
**단순하게 유지해, 이 바보야**라는 뜻입니다. (여기서 바보는 나 자신이나 동료를 뜻하는 애칭 섞인 농담입니다.)
|
||||||
|
해결책은 항상 **가장 단순한 형태**여야 합니다.
|
||||||
|
|
||||||
|
## 📌 상세
|
||||||
|
코드가 똑똑해 보이고 화려할수록, 나중에 버그가 생겼을 때 고치기가 수십 배 더 힘들어집니다. 진짜 실력자는 어려운 문제를 어렵게 푸는 사람이 아니라, **어려운 문제를 누구나 이해할 수 있게 단순하게 푸는 사람**입니다.
|
||||||
|
|
||||||
|
복잡한 디자인 패턴이나 최신 기술을 억지로 끼워 넣지 마세요. `if-else`로 충분하다면 그렇게 짜는 것이 가장 좋습니다.
|
||||||
|
|
||||||
|
> [!question]
|
||||||
|
> Q. kiss의 경우 나도 많이 궁금했고 어려웠던건데 디자인 패턴이나 MVC패턴같은 개발 패턴들을 굳이 쓰지말고 일단은 단순하게 if-else 로 만들어란 뜻으로 해석해야 하는거야?
|
||||||
|
> A. 네, 정확하게 짚으셨습니다! **KISS** 원칙의 핵심은 **정답을 미리 정해놓고 끼워 맞추는 것이 아니라, 문제에 대한 가장 직관적인 해결책부터 시작하라**는 것입니다.
|
||||||
|
|
||||||
|
단순 if-else 로 구성된 코드가 무조건 잘못된 게 아님.
|
||||||
|
미래에 내가 다시 보거나 내가 아닌 다른사람이 내 코드를 읽었을 때 코드의 의도가 잘 이해되면 잘 만든 코드임.
|
||||||
|
디자인 패턴은 패턴의 이해가 필요하고 곧장 읽히지는 않기 때문에 디자인 패턴을 적용한 코드가 항상 가독성이 좋은 코드일수는 없음.
|
||||||
|
일단은 if-else 등의 단순한 형태로 작동되는 코드를 만드는 것이 중요함.
|
||||||
|
## 📝 노트
|
||||||
|
> [!note]
|
||||||
|
>
|
||||||
|
> - 코드의 중복이 발생되고 코드의 유연성이 떨어진다고 판단될 때 디자인 패턴을 적용하면 됨
|
||||||
|
>
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
id: "MVP(Minimum Viable Product) 20260320"
|
||||||
|
created: "2026-03-20 14:00"
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
당장 꼭 필요한 기능만 포함된 최소한의 제품을 최대한 빠르게 만들어내는 게 핵심 가치
|
||||||
|
미완성본을 말하는 것이 아닌 최소한의 기능은 정상적으로 동작해야함.
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
직역하면 **생존 가능한 최소한의 제품**을 의미합니다.
|
||||||
|
단순히 '대충 만든 제품'이나 '미완성본'이 아니라, **고객에게 가치를 제공할 수 있는 핵심 기능만 담은 가장 작은 단위의 결과물**입니다.
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
id: "NoSQL 20260420"
|
||||||
|
created: "2026-04-20 10:07"
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
결국 NoSQL은 빠른속도로 데이터베이스를 구축해서 사용하는 경우에 유용하다.
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
'Not Only SQL'의 약자로, 전통적인 [[관계형 데이터베이스(RDBMS)의 한계]]를 극복하기 위해 만들어진 **비관계형 데이터베이스**를 의미합니다.
|
||||||
|
표(Table) 형태의 엄격한 스키마를 따르지 않고, 데이터의 형태에 따라 유연하게 저장 구조를 선택할 수 있다는 것이 가장 큰 특징입니다.
|
||||||
|
|
||||||
|
## NoSQL의 특징
|
||||||
|
|
||||||
|
- **유연한 스키마 (Schema-less):** 고정된 테이블 구조가 없습니다. 데이터의 필드를 언제든지 추가하거나 변경할 수 있어, 형태가 일정하지 않은 로그 데이터나 SNS 포스트 등을 저장하기에 유리합니다.
|
||||||
|
|
||||||
|
- **수평적 확장성 (Scalability):** RDBMS가 주로 서버의 사양을 높이는 수직 확장(Scale-up)에 집중한다면, NoSQL은 여러 대의 저렴한 서버를 클러스터로 묶어 데이터를 분산 저장하는 **수평 확장(Scale-out)** 에 최적화되어 있습니다.
|
||||||
|
|
||||||
|
- **고성능:** 단순한 데이터 모델을 사용하여 읽기/쓰기 성능이 매우 빠릅니다. 복잡한 JOIN 연산을 지양하기 때문에 대규모 데이터를 처리할 때 유리합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## NoSQL의 4가지 주요 유형
|
||||||
|
| **유형** | **특징** | **대표적인 DB** |
|
||||||
|
| ----------------- | --------------------------- | ---------------------- |
|
||||||
|
| **Key-Value** | 가장 단순한 형태. 키와 값의 쌍으로 저장 | Redis, Amazon DynamoDB |
|
||||||
|
| **Document** | JSON이나 XML 같은 문서 형식으로 저장 | **MongoDB**, CouchDB |
|
||||||
|
| **Column-family** | 행이 아닌 열(Column) 단위로 데이터를 저장 | Cassandra, HBase |
|
||||||
|
| **Graph** | 데이터 간의 관계를 노드와 간선으로 표현 | Neo4j |
|
||||||
|
## NoSQL의 트랜잭션 (BASE)
|
||||||
|
|
||||||
|
RDBMS의 [[ACID]]와 대조적으로, NoSQL은 보통 **BASE** 원칙을 따릅니다.
|
||||||
|
|
||||||
|
- **Basically Available (기본적 가용성):** 언제든 접근 가능해야 함.
|
||||||
|
|
||||||
|
- **Soft State (소프트 상태):** 외부의 개입 없어도 정보가 변경될 수 있음 (일시적 불일치 허용).
|
||||||
|
|
||||||
|
- **Eventually Consistent (결과적 일관성):** 일시적으로 정합성이 깨질 수 있지만, 시간이 지나면 결국 모든 노드의 데이터가 일치하게 됨.
|
||||||
|
|
||||||
|
## 데이터 중복(Data Redundancy)
|
||||||
|
NoSQL에서 **데이터 중복(Data Redundancy)** 은 실수가 아니라 **성능을 위해 의도적으로 선택하는 핵심 전략**입니다.
|
||||||
|
|
||||||
|
RDBMS에서는 데이터 중복을 죄악시하며 정규화(Normalization)를 통해 중복을 제거하지만, NoSQL은 그 반대인 **비정규화(Denormalization)** 를 지향합니다.
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
### 1. 공격 표면(Attack Surface)의 최소화
|
||||||
|
|
||||||
|
파드가 퍼블릭 서브넷에 있고 공인 IP(Public IP)를 직접 가지고 있다면, 전 세계 누구나 해당 파드에 직접 접속을 시도할 수 있습니다.
|
||||||
|
|
||||||
|
- **위험성:** 애플리케이션 코드의 작은 취약점이나 설정 오류만으로도 서버 전체가 해킹당할 수 있습니다.
|
||||||
|
|
||||||
|
- **해결:** 프라이빗 서브넷에 두면 외부에서는 아예 길 자체가 없어서 직접 접근이 불가능해집니다.
|
||||||
|
|
||||||
|
|
||||||
|
### 2. 단일 진입점 강제 (로드 밸런서 활용)
|
||||||
|
|
||||||
|
사용자는 파드에 직접 붙는 것이 아니라, **로드 밸런서(ALB/NLB)**라는 검증된 관문을 통해서만 들어와야 합니다.
|
||||||
|
|
||||||
|
- 로드 밸런서는 퍼블릭 서브넷에서 외부 요청을 안전하게 걸러서 받고, 내부 네트워크를 통해 프라이빗 서브넷에 있는 파드에게 전달합니다.
|
||||||
|
|
||||||
|
- 이 구조를 통해 트래픽 제어, SSL 인증서 관리, WAF(웹 방화벽) 적용이 훨씬 쉬워집니다.
|
||||||
|
|
||||||
|
|
||||||
|
### 3. IP 주소 자원 관리
|
||||||
|
|
||||||
|
퍼블릭 IP는 전 세계적으로 한정된 자원이며 비용이 발생합니다.
|
||||||
|
|
||||||
|
- 쿠버네티스 특성상 파드는 수십, 수백 개가 생성되었다가 사라집니다. 이때마다 퍼블릭 IP를 할당하는 것은 매우 비효율적이고 비용 낭비가 심합니다.
|
||||||
|
|
||||||
|
- 내부망(Private IP)을 사용하면 주소 부족 걱정 없이 자유롭게 스케일링할 수 있습니다.
|
||||||
|
|
||||||
|
|
||||||
|
### 4. 아키텍처의 논리적 분리 (Tiering)
|
||||||
|
|
||||||
|
현대적인 3-Tier 아키텍처 원칙을 따르기 위함입니다.
|
||||||
|
|
||||||
|
- **Public Tier:** 로드 밸런서, 배스천 호스트 (외부 소통 창구)
|
||||||
|
|
||||||
|
- **Private Tier:** 애플리케이션 서버, 데이터베이스 (실제 핵심 데이터와 로직)
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
id: RDBMS 20260420
|
||||||
|
created: 2026-04-20 08:43
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
데이터간의 관계를 고민하고 관계를 이용해서 중복된 데이터가 들어가는것을 최소화하는 DB를 일컫는다고 보면 된다. 왜냐하면 데이터 정합성은 사실 RDBMS든 NoSQL이든 무조건 지켜주는게 좋은 부분이니까 이걸 RDBMS와 NoSQL의 차이다 라고 하기에는 좀 과하다고 생각된다.
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
관계형 DB의 가장 큰 특징은 데이터를 **Table(표)** 형태로 관리하고, 테이블 간의 **Relation(관계)** 을 정의한다는 점입니다.
|
||||||
|
|
||||||
|
## 📌 상세
|
||||||
|
- **스키마(Schema):** 데이터의 구조와 제약 조건을 정의한 설계도입니다.
|
||||||
|
|
||||||
|
- **기본키(PK)와 외래키(FK):** 테이블 간의 연결 고리이자 데이터의 유일성을 보장하는 핵심 장치입니다.
|
||||||
|
|
||||||
|
- **무결성(Integrity):** 데이터가 정확하고 일관되게 유지되도록 하는 규칙들입니다.
|
||||||
|
|
||||||
|
|
||||||
|
[[ACID]] [[트랜잭션(Transaction)|트렌젝션]]을 지킴으로 인해 DB에서 가장 중요한 덕목인 [[데이터 정합성(Data Consistency)]] 지키는데 특화됨.
|
||||||
|
![[ACID#📌 상세]]
|
||||||
|
|
||||||
|
### 성능 최적화: 인덱스와 정규화
|
||||||
|
|
||||||
|
실무에서 가장 많이 고민하게 되는 부분입니다.
|
||||||
|
|
||||||
|
- **정규화(Normalization):** 데이터 중복을 최소화하고 구조를 체계화하는 과정입니다. (1NF, 2NF, 3NF 등)
|
||||||
|
|
||||||
|
- **인덱스(Index):** 책의 색인처럼 데이터를 빠르게 찾기 위한 구조입니다. B-Tree 구조가 대표적이죠.
|
||||||
|
|
||||||
|
- **실행 계획(Execution Plan):** 작성한 SQL이 내부적으로 어떻게 실행되는지 분석하여 병목을 찾아내는 도구입니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 주의
|
||||||
|
> [!warning] 하지만 데이터 정합성의 경우 RDBMS의 고유한 특징이라고 하기엔 무리가 있다.
|
||||||
|
|
||||||
|
왜냐하면 DB라면 데이터 정합성을 지켜야하는게 당연하기 때문이다.
|
||||||
|
( 얼마나 정합성을 강하게 지켜서 성능에서 손해를 보느냐, 약간 덜 엄격하게 지키고 성능에서 이점을 얻느냐가 차라리 더 중요하다. )
|
||||||
|
|
||||||
|
## RDBMS의 본질
|
||||||
|
> [!note] RDBMS의 본질: "구조적 설계를 통한 중복 제어"
|
||||||
|
|
||||||
|
- **정규화(Normalization):** 데이터 간의 관계를 분석해 원자 단위로 쪼개고, 중복을 원천 차단하는 프로세스입니다.
|
||||||
|
|
||||||
|
- **무결성 제약 조건:** DB 엔진 차원에서 외래키(FK), 유니크(Unique) 제약 등을 통해 "중복되거나 잘못된 관계가 맺어지는 것"을 물리적으로 막습니다.
|
||||||
|
|
||||||
|
- **저장 효율성:** 중복을 최소화하기 때문에 저장 공간을 효율적으로 쓰고, 데이터 수정 시 한 곳만 고치면 되는 구조를 만듭니다.
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
---
|
||||||
|
id: RS-232 vs 이더넷 20260504
|
||||||
|
created: 2026-05-04 09:58
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
결과적으로 RS-232와 이더넷사이에는 약 8,000배의 속도차이가 발생된다고 한다.
|
||||||
|
설치비용도 이더넷이 훨씬 더 저렴하다고 한다.
|
||||||
|
|
||||||
|
이래도 RS-232를 쓴다고?
|
||||||
|
[[RS-232가 이더넷을 따라잡을 수 없는 이유]]
|
||||||
|
|
||||||
|
---
|
||||||
|
> [!question]
|
||||||
|
> Q. 왜 rs-232랑 이더넷은 속도의 차이가 나는거야? 어차피 둘다 똑같이 전기적인 신호의 전달인거 아니야?
|
||||||
|
> A. 정말 좋은 질문입니다! 본질적으로는 둘 다 구리선 안에서 전압의 변화(전기 신호)를 이용하는 것은 맞지만, 그 전기를 **얼마나 정교하고 빠르게 제어하느냐**에서 결정적인 차이가 발생합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
### 1. 전압의 폭과 물리적 부담 (관성)
|
||||||
|
전압을 바꾸는 것은 마치 수도꼭지를 틀고 잠그는 것과 비슷합니다.
|
||||||
|
|
||||||
|
- **[[RS-232]]:** 전압의 진폭이 큽니다(보통 -15V에서 +15V 사이). 전압을 이만큼 높였다 낮췄다 하려면 시간이 걸립니다. 즉, 신호를 한 번 바꿀 때마다 물리적인 '관성'이 큽니다.
|
||||||
|
|
||||||
|
- **이더넷:** 아주 낮은 전압(약 1V~2.5V 내외)을 사용합니다. 전압 폭이 작기 때문에 아주 미세하고 빠르게 전압을 튀길 수 있습니다. 덕분에 1초에 훨씬 많은 신호를 보낼 수 있는 것이죠.
|
||||||
|
|
||||||
|
***** 즉, 수도꼭지를 아주 조금만 틀고잠궈도 되는 이더넷이 많이 틀고 많이 잠궈야하는 RS-232보다 물리적인 부담이 훨씬 적다.
|
||||||
|
|
||||||
|
### 2. 노이즈를 처리하는 방식 (차동 신호)
|
||||||
|
멀리, 그리고 빠르게 신호를 보내려면 주변의 전기적 잡음(노이즈)을 이겨내야 합니다.
|
||||||
|
|
||||||
|
- **[[RS-232]] (싱글 엔디드):** 선 하나에 전기를 흘리고 그 전압 값만 측정합니다. 주변에서 노이즈가 끼어들면 신호가 쉽게 변조됩니다. 그래서 속도를 높이면 에러가 너무 많이 납니다.
|
||||||
|
|
||||||
|
- **이더넷 ([[차동 신호(Differential Signaling)]]):** 선 두 개를 꼬아서 사용합니다. 한쪽 선에 `+`를 보내면 다른 쪽엔 `-`를 보냅니다. 노이즈가 발생해도 두 선에 동시에 영향을 주므로, 두 신호의 '차이'를 계산하면 노이즈만 쏙 제거됩니다. 이 기술 덕분에 노이즈 걱정 없이 엄청난 속도로 신호를 쏠 수 있습니다.
|
||||||
|
|
||||||
|
***** 노이즈 발생 걱정 없이 데이터를 송,수신 할 수 있다.
|
||||||
|
|
||||||
|
### 3. 신호를 만드는 '언어'의 정교함
|
||||||
|
|
||||||
|
전압을 단순히 `높다(1)`, `낮다(0)`로만 구분하는지, 아니면 더 복잡하게 약속하는지의 차이입니다.
|
||||||
|
|
||||||
|
- **RS-232:** 단순합니다. 전압이 높으면 0, 낮으면 1(혹은 그 반대) 식으로 아주 기초적인 규칙만 씁니다.
|
||||||
|
|
||||||
|
- **이더넷:** 전압의 변화뿐만 아니라 위상(Phase) 등을 조합한 고도의 인코딩 방식을 씁니다. 한 번의 전기 신호 변화에 여러 비트의 데이터를 담는 '압축 기술'이 들어가 있어 같은 전기 신호라도 실어나르는 데이터 양이 훨씬 많습니다.
|
||||||
|
|
||||||
|
> [!question]
|
||||||
|
> Q. 신호를 만드는 '언어'의 정교함 이거는 만약에 rs-232도 고도로 발달한 인코딩 방식을 개발해서 사용했다면 어느정도는 따라갈 수 있는 부분이었을까?
|
||||||
|
> A. 매우 날카로운 질문입니다! 결론부터 말씀드리면, **인코딩 기술을 도입하면 RS-232도 지금보다는 훨씬 빨라질 수 있습니다.** 하지만 근본적으로 이더넷을 **'완벽히'** 따라잡기는 어렵습니다.
|
||||||
|
|
||||||
|
|
||||||
|
> [!note]
|
||||||
|
결국 **똑같은 전기**를 쓰더라도, 더 적은 힘으로(저전압), 더 영리하게 노이즈를 방어하면서(차동 신호), 더 정교한 규칙(인코딩)으로 소통하기 때문에 이더넷이 압도적으로 빠른 것입니다.
|
||||||
|
>
|
||||||
|
|
||||||
|
### 왜 RS-232는 차동 신호가 안 될까요?
|
||||||
|
|
||||||
|
RS-232는 선 하나($A$)와 접지(Ground, $0V$)를 비교합니다.
|
||||||
|
|
||||||
|
- **보낼 때:** $A$선에 $10V$를 보냅니다. (기준은 $0V$니까 차이는 $10V$)
|
||||||
|
|
||||||
|
- **노이즈 발생:** $A$선에만 $+5V$ 노이즈가 낍니다. ($15V$가 됨)
|
||||||
|
|
||||||
|
- **받을 때:** 받는 쪽은 여전히 $0V$를 기준으로 측정하므로, 데이터가 $15V$로 변질된 채 들어옵니다. 노이즈를 걸러낼 방법이 없습니다.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
id: "RS-232 20260504"
|
||||||
|
created: "2026-05-04 09:37"
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
SECS 통신에서 사용하는 그것을 말함.
|
||||||
|
아직도 RS-232를 쓰는곳이 종종 있음.
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
컴퓨터와 주변 장치(모뎀, 마우스, 산업용 장비 등) 간에 데이터를 주고받기 위해 만들어진 **직렬(Serial) 통신 표준**입니다. 1960년대에 처음 등장했음에도 불구하고, 신뢰성이 높고 구조가 간단하여 오늘날까지도 산업 현장에서 널리 사용되고 있습니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📌 주요 특징
|
||||||
|
- **직렬 통신:** 데이터를 한 번에 1비트씩 순차적으로 전송합니다. 병렬 통신에 비해 배선이 단순하다는 장점이 있습니다.
|
||||||
|
|
||||||
|
- **전압 기반 신호:** 논리 상태를 전압의 차이로 구분합니다.
|
||||||
|
|
||||||
|
- **논리 0 (Space):** $+3\text{V} \sim +15\text{V}$
|
||||||
|
|
||||||
|
- **논리 1 (Mark):** $-3\text{V} \sim -15\text{V}$ (휴지 상태)
|
||||||
|
|
||||||
|
- **전송 거리:** 표준상으로는 약 15m(50피트) 정도까지 권장되지만, 통신 속도를 낮추면 더 먼 거리도 가능합니다.
|
||||||
|
|
||||||
|
- **커넥터 형태:** 과거에는 25핀(DB-25)이 쓰였으나, 현재는 9핀(DE-9 또는 DB-9) 형태가 가장 흔합니다.
|
||||||
|
|
||||||
|
## 통신 방식 (프레임 구조)
|
||||||
|
|
||||||
|
RS-232는 **비동기식(Asynchronous)** 통신을 주로 사용합니다. 즉, 송신측과 수신측이 공통된 클록(Clock)을 공유하지 않고, 약속된 속도(Baud Rate)에 맞춰 데이터를 해석합니다.
|
||||||
|
(Baud Rate: 송신자와 수신자가 미리 **초당 몇 비트를 보낼지** 약속한 것)
|
||||||
|
|
||||||
|
1. **Start Bit:** 통신의 시작을 알리는 1비트 (Low 전압).
|
||||||
|
|
||||||
|
2. **Data Bits:** 실제 데이터 (보통 7~8비트).
|
||||||
|
|
||||||
|
3. **Parity Bit:** 오류 검출을 위한 옵션 비트.
|
||||||
|
|
||||||
|
4. **Stop Bit:** 통신의 종료를 알리는 비트 (1~2비트, High 전압).
|
||||||
|
|
||||||
|
|
||||||
|
RS-232는 보통 **전이중(Full-Duplex)** 방식입니다. 즉, 보내는 선(TX)과 받는 선(RX)이 분리되어 있습니다.
|
||||||
|
|
||||||
|
- 상대방이 데이터를 다 보낼 때까지 기다렸다가 내가 보내는 방식(Half-Duplex)도 가능하지만,
|
||||||
|
|
||||||
|
- 하드웨어적으로 선이 따로 있기 때문에 **상대방이 데이터를 보내는 중에도 내가 보낼 데이터가 있다면 동시에 Start Bit를 던지고 데이터를 보낼 수 있습니다.**
|
||||||
|
|
||||||
|
|
||||||
|
## 요약
|
||||||
|
- **Start Bit:** 수신기의 타이머를 가동시키는 스위치.
|
||||||
|
|
||||||
|
- **데이터 읽기:** 약속된 보레이트의 '절반' 지점마다 전압을 체크해서 0인지 1인지 결정.
|
||||||
|
|
||||||
|
- **Stop Bit:** 다음 데이터의 Start Bit를 제대로 인식할 수 있도록 선로를 대기 상태(High)로 복귀시키는 최소한의 여유 시간.
|
||||||
|
|
||||||
|
![[Pasted image 20260504100456.png]]
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
id: "RS-232가 이더넷을 따라잡을 수 없는 이유 20260504"
|
||||||
|
created: "2026-05-04 10:16"
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
가성비를 위해 고안된 RS-232에 이더넷에서 사용하는 고도의 인코딩기술 등을 적용하려면 RS-232의 가장 큰 장점이었던 가성비가 사라지게 된다.
|
||||||
|
기술적으로도 싱글 엔디드(선 하나로 측정)방식에서 어떻게 할 수 없는 노이즈 현상이 RS-232의 고도화에 가장 큰 걸림돌이기도 하다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1. 인코딩으로 얻을 수 있는 이득 (언어의 효율성)
|
||||||
|
|
||||||
|
RS-232도 현대적인 인코딩(예: QAM 등)을 사용한다면, 한 번의 전기 변화에 1비트가 아니라 4비트, 8비트를 담을 수 있습니다. 실제로 과거 전화선을 쓰던 **다이얼업 모뎀**이 이런 방식으로 속도를 높여왔습니다.
|
||||||
|
|
||||||
|
- 하지만 인코딩을 고도화할수록 **신호가 아주 미세한 차이**를 구분해야 합니다.
|
||||||
|
|
||||||
|
- 예를 들어, 전압을 0V/5V 두 개로 나누던 걸 0.1V 단위로 쪼개서 50개의 신호를 만든다고 가정해 보세요.
|
||||||
|
|
||||||
|
|
||||||
|
### 2. 발목을 잡는 '물리적 노이즈' (도로의 상태)
|
||||||
|
|
||||||
|
여기서 앞서 공부한 **노이즈** 문제가 다시 등장합니다.
|
||||||
|
|
||||||
|
- 고도의 인코딩은 '미세한 전압 차이'를 읽어내는 기술입니다.
|
||||||
|
|
||||||
|
- 그런데 RS-232는 노이즈에 취약한 **싱글 엔디드(선 하나로 측정)** 방식이죠.
|
||||||
|
|
||||||
|
- 주변에서 노이즈가 조금만 튀어도 0.1V 단위로 쪼개놓은 정교한 신호들이 순식간에 뭉개져 버립니다.
|
||||||
|
|
||||||
|
|
||||||
|
즉, **아무리 고급 언어(인코딩)를 개발해도, 전달 매체(전선)가 너무 시끄러우면(노이즈) 상대방이 알아들을 수가 없는 것**입니다.
|
||||||
|
|
||||||
|
### 3. '차동 신호'라는 인프라의 차이
|
||||||
|
|
||||||
|
이더넷이 고도의 인코딩을 마음껏 쓸 수 있는 이유는 [[차동 신호(Differential Signaling)]] 덕분에 바닥에 깔린 노이즈를 싹 제거하여 **깨끗한 도화지** 상태를 만들었기 때문입니다.
|
||||||
|
|
||||||
|
- **이더넷:** 도화지가 깨끗하니 아주 얇은 펜으로 정밀하게 글씨(인코딩)를 써도 잘 읽힙니다.
|
||||||
|
|
||||||
|
- **[[RS-232]]:** 도화지에 이미 연필 자국(노이즈)이 가득해서, 굵은 매직으로 크게 써야만 겨우 읽을 수 있는 상태입니다.
|
||||||
|
|
||||||
|
### 4. 하드웨어 설계의 단순성 (경제성)
|
||||||
|
|
||||||
|
RS-232는 애초에 "싸고 단순하게 만들자"가 목적이었습니다.
|
||||||
|
|
||||||
|
- 복잡한 인코딩을 처리하려면 CPU나 전용 칩셋이 신호를 실시간으로 계산해서 복원해야 합니다.
|
||||||
|
|
||||||
|
- RS-232 장치에 그런 비싼 칩을 넣을 바에는, 차라리 그 돈으로 **이더넷 칩**을 하나 다는 게 훨씬 싸고 빠릅니다. 이미 이더넷은 대량 생산으로 가격이 매우 낮아졌으니까요.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
- 작성 **날짜:** 2026-02-27
|
||||||
|
|
||||||
|
## 📑 개념
|
||||||
|
> [!abstract]
|
||||||
|
> "AWS 클라우드 안에서 완벽하게 격리된, 사용자가 직접 정의하는 **가상 네트워크 환경**"
|
||||||
|
> AWS가 만든 개념인데 현재는 클라우드 표준처럼 사용됨
|
||||||
|
|
||||||
|
## 📌 VPC의 핵심 구성 요소
|
||||||
|
> [!check]
|
||||||
|
|**구성 요소**|**명칭**|**설명**|**비유**|
|
||||||
|
|---|---|---|---|
|
||||||
|
|**CIDR 블록**|**IP 주소 범위**|VPC에서 사용할 IP 주소의 범위를 정의 (예: `10.0.0.0/16`)|내 구역의 **전체 주소지**|
|
||||||
|
|**서브넷 (Subnet)**|**망 분할**|VPC를 더 작은 단위로 쪼갠 네트워크. 퍼블릭과 프라이빗으로 나뉨|큰 건물을 **여러 개의 방**으로 나눔|
|
||||||
|
|**라우팅 테이블**|**길잡이**|네트워크 트래픽이 어디로 가야 할지 알려주는 이정표|건물 내의 **복도와 안내판**|
|
||||||
|
|**인터넷 게이트웨이**|**IGW**|VPC와 인터넷 사이의 통로. 이게 있어야 외부 통신 가능|건물의 **정문 (바깥 세상으로 나가는 문)**|
|
||||||
|
|**NAT 게이트웨이**|**NAT**|프라이빗 서브넷의 서버가 보안을 유지하며 외부로만 나갈 때 사용|안에서는 밖을 보지만, **밖에서는 안을 못 보는 창문**|
|
||||||
|
|
||||||
|
## 📝 노트
|
||||||
|
> [!note]
|
||||||
|
>
|
||||||
|
> - 관련 사례나 반대되는 개념이 있다면 여기에 기록하세요.
|
||||||
|
>
|
||||||
|
> - 본인의 언어로 풀어서 쓰는 것이 제텔카스텔의 핵심입니다.
|
||||||
|
>
|
||||||
|
|
||||||
|
## 🔗 지식 연결
|
||||||
|
- **태그:** #zettelkasten #knowledge
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
id: "VPN(Virtual Private Network) 20260305"
|
||||||
|
created: "2026-03-05 15:00"
|
||||||
|
tags:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
또다른 네트워크 연결 통로라고 생각하면 됨. 실제로 VPN 연결 시 네트워크 연결에 새로운 네트워크 연결이 추가됨.
|
||||||
|
![[Pasted image 20260305150408.png]]
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
가상 사설망, **인터넷상에 나만의 안전한 비밀 통로를 만드는 기술**이라고 생각하면 됨.
|
||||||
|
|
||||||
|
## 📌 상세
|
||||||
|
|
||||||
|
VPN 사용 시 주요 장점
|
||||||
|
|
||||||
|
| **장점** | **설명** |
|
||||||
|
| -------------- | -------------------------------------------------- |
|
||||||
|
| **보안 강화** | 공공장소(카페, 공항)의 무료 와이파이를 쓸 때 해킹 위험으로부터 데이터를 보호합니다. |
|
||||||
|
| **IP 주소 우회** | 나의 실제 위치(IP 주소)를 숨기고 VPN 서버가 있는 국가의 IP로 바꿀 수 있습니다. |
|
||||||
|
| **검열 및 차단 해제** | 특정 국가에서 접속이 막힌 사이트나 콘텐츠(해외 넷플릭스 등)에 접근할 수 있습니다. |
|
||||||
|
| **익명성 보장** | 방문하는 웹사이트나 서비스 제공자가 나의 실제 신원을 파악하기 어렵게 만듭니다. |
|
||||||
|
|
||||||
|
|
||||||
|
VPN 사용 시 주의할 점
|
||||||
|
- **속도 저하:** 데이터를 암호화하고 먼 거리에 있는 서버를 거치기 때문에 인터넷 속도가 평소보다 느려질 수 있습니다.
|
||||||
|
|
||||||
|
- **무료 VPN의 위험성:** "공짜" VPN 중 일부는 사용자의 활동 로그를 수집해 광고주에게 팔거나 보안이 취약할 수 있습니다. 가급적 신뢰할 수 있는 유료 서비스를 권장합니다.
|
||||||
|
|
||||||
|
- **완벽한 익명성은 없음:** VPN 업체는 내가 어떤 데이터를 주고받는지 알 수 있습니다. 따라서 '노 로그(No-log, 활동 기록을 남기지 않음)' 정책을 가진 업체를 선택하는 것이 중요합니다.
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
id: "Woodpecker 20260320"
|
||||||
|
created: "2026-03-20 16:56"
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
이거 아주 괜찮을거같음
|
||||||
|
아주 경량화되어 사용하기 쉽고 빠릿빠릿한 젠킨스
|
||||||
|
(물론 계속 써봐야겠지만..)
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
Woodpecker CI는 오픈 소스 기반의 경량 CI/CD 엔진으로, 과거 유명했던 Drone CI에서 포크(Fork)되어 발전한 도구입니다. 복잡한 설정보다는 **간결함**과 **컨테이너 기반의 확장성**을 중시하는 팀에게 특히 매력적인 선택지입니다.
|
||||||
|
|
||||||
|
## 📌 상세
|
||||||
|
## 1. Woodpecker의 핵심 철학
|
||||||
|
|
||||||
|
Woodpecker는 모든 파이프라인 단계를 **도커(Docker) 컨테이너** 내에서 실행합니다. 이로 인해 환경 격리가 확실하며, 필요한 도구를 설치하기 위해 에이전트를 더럽힐 필요가 없습니다.
|
||||||
|
|
||||||
|
- **설정의 간소화:** `.woodpecker.yml`이라는 YAML 파일 하나로 전체 파이프라인을 정의합니다.
|
||||||
|
|
||||||
|
- **오픈 소스 정신:** 완전히 무료이며, 커뮤니티에 의해 유지보수됩니다. (Drone CI가 기업화되면서 라이선스 제약이 생긴 것에 반발하여 나온 프로젝트입니다.)
|
||||||
|
|
||||||
|
- **경량화:** 리소스 소모가 매우 적어 개인 서버나 사양이 낮은 VPS에서도 원활하게 돌아갑니다.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 작동 방식 (Architecture)
|
||||||
|
|
||||||
|
Woodpecker는 크게 두 가지 컴포넌트로 구성됩니다.
|
||||||
|
|
||||||
|
- **Server:** 웹 UI를 제공하고, GitHub, GitLab, Gitea와 같은 소스 코드 관리 도구(Forge)와 연동하여 웹훅(Webhook)을 처리합니다.
|
||||||
|
|
||||||
|
- **Agent:** 실제로 파이프라인 작업을 수행하는 주체입니다. 서버로부터 할당받은 작업을 컨테이너를 띄워 실행합니다.
|
||||||
|
|
||||||
|
|
||||||
|
## 주요 장점
|
||||||
|
|
||||||
|
- **멀티 플랫폼 지원:** x86_64는 물론이고 ARM64(라즈베리 파이 등)에서도 완벽하게 작동합니다.
|
||||||
|
|
||||||
|
- **다양한 Backend:** 기본적으로 Docker를 사용하지만, 최근에는 로컬 프로세스 실행이나 [[쿠버네티스(Kubernetes)]] 기반의 실행도 지원하기 시작했습니다.
|
||||||
|
|
||||||
|
- **플러그인 생태계:** Docker 이미지를 플러그인처럼 사용할 수 있습니다. 예를 들어, 빌드가 끝나고 Slack 메시지를 보내고 싶다면 이미 만들어진 Slack 플러그인 이미지를 파이프라인에 추가하기만 하면 됩니다.
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
id: "YAGNI(You Ain't Gonna Need It) 20260317"
|
||||||
|
created: "2026-03-17 16:54"
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
지금 당장 꼭 필요한 것만 만들어라. 미리 먼저 만들지 마라
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
소프트웨어 개발 원칙 중 하나로 직역하면 **그거 필요 없을걸요** 또는 **미리 만들지 마세요**라는 뜻을 담고 있습니다.
|
||||||
|
개발자가 미래에 필요할 것으로 예상되는 기능을 미리 구현하지 말고, **실제로 그 기능이 필요한 시점이 되었을 때 구현하라**는 핵심 메시지를 전달합니다.
|
||||||
|
## 📌 상세
|
||||||
|
### 1. YAGNI가 필요한 이유
|
||||||
|
|
||||||
|
많은 개발자가 나중에 이 기능이 추가될 때를 대비해 미리 구조를 잡거나 범용적인 코드를 작성하려는 유혹에 빠지곤 합니다. 하지만 이런 **추측에 기반한 개발(Speculative Development)**은 다음과 같은 부작용을 낳습니다.
|
||||||
|
|
||||||
|
- **시간 낭비:** 결국 쓰이지 않게 될 기능을 만드느라 현재 꼭 필요한 작업에 집중하지 못하게 됩니다.
|
||||||
|
|
||||||
|
- **코드 복잡성 증가:** 당장 필요 없는 코드가 들어가면 전체적인 시스템 구조가 복잡해지고, 나중에 코드를 읽거나 수정하기 더 어려워집니다.
|
||||||
|
|
||||||
|
- **유지보수 비용 발생:** 사용되지 않는 기능이라도 버그가 생기면 수정해야 하고, 의존성 업데이트나 리팩토링 시 고려 대상이 되어 짐이 됩니다.
|
||||||
|
|
||||||
|
- **잘못된 예측:** 미래의 요구사항은 변하기 마련입니다. 미리 만들어둔 기능이 나중에 정작 필요한 형태와 달라서 결국 다시 만들어야 하는 경우가 많습니다.
|
||||||
|
|
||||||
|
|
||||||
|
### 2. YAGNI를 실천하는 방법
|
||||||
|
|
||||||
|
- **현재의 요구사항에 집중:** 오늘 해결해야 할 문제와 기능에만 충실하게 코드를 작성합니다.
|
||||||
|
|
||||||
|
- **확장성보다는 단순성:** 나중에 확장될 것을 대비해 복잡한 추상화 계층을 미리 만들기보다는, 지금 당장 이해하기 쉽고 단순한 구조를 유지합니다.
|
||||||
|
|
||||||
|
- **리팩토링의 힘:** 나중에 정말로 기능 확장이 필요해졌을 때, 그때 가서 코드를 리팩토링하여 기능을 추가하는 것이 훨씬 효율적입니다.
|
||||||
|
|
||||||
|
## 📝 노트
|
||||||
|
> [!note]
|
||||||
|
>
|
||||||
|
> - 작업의 가치는 그것이 실제로 사용될 때 발생합니다.
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
title: note
|
||||||
|
---
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
| **비교 항목** | **가상 머신 (EC2 등 VM)** | **컨테이너 (Docker 등)** |
|
||||||
|
| --------- | -------------------------------------- | --------------------------------- |
|
||||||
|
| **구조** | OS 위에 가상 하이퍼바이저와 **별도의 Guest OS**가 필요함 | 호스트의 **OS 커널을 공유**하며 프로세스 단위로 격리됨 |
|
||||||
|
| **무게** | GB 단위 (매우 무겁고 부팅이 느림) | **MB 단위** (매우 가볍고 즉시 실행됨) |
|
||||||
|
| **효율성** | 리소스 낭비가 큼 (OS마다 자원을 잡아먹음) | 필요한 자원만 사용하므로 집적도가 높음 |
|
||||||
|
| **이식성** | 환경 설정에 따라 작동 여부가 달라짐 | **"어디서든 동일하게 실행"**됨을 보장함 |
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
- 작성 **날짜:** 2026-02-27
|
||||||
|
|
||||||
|
## 📑 개념
|
||||||
|
> [!abstract]
|
||||||
|
> 시스템이 장애 없이 정상적으로 서비스를 제공할 수 있는 상태
|
||||||
|
> 언제든지 이상없이 잘 사용할 수 있는것도 가용성으로 봄
|
||||||
|
|
||||||
|
## 📝 상세 설명
|
||||||
|
> [!note]
|
||||||
|
>
|
||||||
|
> -
|
||||||
|
>
|
||||||
|
|
||||||
|
|
||||||
|
$$가용성(\%) = \frac{업타임(정상 운영 시간)}{업타임 + 다운타임(장애 시간)} \times 100$$
|
||||||
|
|
||||||
|
|
||||||
|
## 🔗 지식 연결
|
||||||
|
- **태그:** #zettelkasten #knowledge
|
||||||
|
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
id: 게이트웨이(Gateway) 20260428
|
||||||
|
created: 2026-04-28 14:25
|
||||||
|
tags:
|
||||||
|
- network
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
서로 다른 네트워크간의 통신은 무조건 게이트웨이를 통해 진행된다.
|
||||||
|
내부를 먼저 확인하고 내부에 그 ip에 해당되는 녀석이 없으면 게이트웨이를 통해 외부로 나아간다.
|
||||||
|
이 때 가장 먼저 확인하는게 [[라우팅 테이블(Routing Table)]]이다.
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
서로 다른 네트워크를 연결해 주는 '출입구' 역할을 하는 장치나 소프트웨어를 말합니다.
|
||||||
|
컴퓨터 네트워크는 서로 다른 통신 프로토콜(규약)을 사용하거나 구조가 다른 경우가 많은데, 게이트웨이는 이들 사이에서 데이터를 주고받을 수 있도록 **통역사** 역할을 수행합니다.
|
||||||
|
|
||||||
|
## ## 1. 게이트웨이의 핵심 역할
|
||||||
|
|
||||||
|
네트워크의 경계에 위치하여 다음과 같은 기능을 수행합니다.
|
||||||
|
|
||||||
|
- **프로토콜 변환:** 서로 다른 방식의 네트워크가 소통할 수 있도록 신호를 변환합니다.
|
||||||
|
|
||||||
|
- **데이터 전달:** 내부 네트워크에서 외부(인터넷)로 나가는 모든 데이터는 반드시 게이트웨이를 통과해야 합니다.
|
||||||
|
|
||||||
|
- **보안:** 외부로부터 들어오는 허가되지 않은 접속을 차단하는 벽의 역할을 하기도 합니다.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 실생활 예시: 아파트 현관문
|
||||||
|
|
||||||
|
게이트웨이를 가장 쉽게 이해하는 방법은 **아파트의 현관문**에 비유하는 것입니다.
|
||||||
|
|
||||||
|
- **내부 네트워크:** 우리 집 안 (가족끼리 자유롭게 대화하고 이동 가능)
|
||||||
|
|
||||||
|
- **외부 네트워크:** 집 밖 (복도, 엘리베이터, 거리)
|
||||||
|
|
||||||
|
- **게이트웨이:** 현관문 (집 밖으로 나가거나 외부인이 들어올 때 반드시 거쳐야 하는 유일한 통로)
|
||||||
|
|
||||||
|
|
||||||
|
컴퓨터가 인터넷상의 웹사이트에 접속하려고 할 때, 먼저 자신의 네트워크 안에 해당 주소가 있는지 확인합니다. 없다면 일단 기본 게이트웨이(Default Gateway)로 데이터를 보낸 뒤 외부 세계로 나가게 됩니다.
|
||||||
|
|
||||||
|
|
||||||
|
## 3. 기본 게이트웨이 (Default Gateway)
|
||||||
|
|
||||||
|
우리가 사용하는 PC나 스마트폰 설정에서 흔히 볼 수 있는 용어입니다.
|
||||||
|
|
||||||
|
- 보통 가정에서는 유무선 공유기(루터)의 IP 주소가 기본 게이트웨이 주소가 됩니다.
|
||||||
|
|
||||||
|
- 내부망에서 해결할 수 없는 목적지(예: 구글, 네이버 등)로 가는 데이터는 무조건 이 기본 게이트웨이 주소로 전달됩니다.
|
||||||
|
|
||||||
|
보통 0.0.0.0에 위치하며 보통은 [[라우터(Router)]]를 가리킨다.
|
||||||
|
앞서봤듯 통신연결 시도가 발생되면 가장먼저 내부의 같은 네트워크망에 그 ip주소에 해당되는 요소가 있는지 확인하고 없으면 라우팅 테이블을 확인해본다. 거기도 없을 경우 기본 게이트웨이로 가게 되는데 보통 기본 게이트웨이는 라우터로 설정되어 있다.
|
||||||
|
|
||||||
|
[[라우터(Router)]]를 통해 연결시도 한 ip로 접근이 되는지 확인해보고 최대한 통신 연결을 시도해보다가 성공,실패하게 된다.
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
---
|
||||||
|
id: "고차 함수(Higher-Order Function) 20260407"
|
||||||
|
created: "2026-04-07 15:55"
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
이곳에 하나의 생각 또는 아이디어를 작성합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
## 📑 개념
|
||||||
|
함수를 다루는 함수라고 생각하면 쉬워요.
|
||||||
|
함수가 다음 중 **하나 이상**을 수행한다면 고차 함수라고 부릅니다.
|
||||||
|
|
||||||
|
## 고차 함수의 두 가지 조건
|
||||||
|
|
||||||
|
### 1. 함수를 인자로 전달받음
|
||||||
|
|
||||||
|
다른 함수를 매개변수(Parameter)로 넘겨받아 실행하는 경우입니다. 이때 인자로 전달되는 함수를 보통 **콜백 함수(Callback Function)** 라고 부릅니다.
|
||||||
|
|
||||||
|
- **예시:** `Array.prototype.map()`, `filter()`, `forEach()` 등
|
||||||
|
``` javascript
|
||||||
|
const numbers = [1, 2, 3];
|
||||||
|
// 여기서 map은 고차 함수이고, (n => n * 2)는 콜백 함수입니다.
|
||||||
|
const doubled = numbers.map(n => n * 2);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### 2. 함수를 결과로 반환함
|
||||||
|
|
||||||
|
함수 실행의 결과물로 새로운 함수를 만들어 내보내는 경우입니다. 이 방식은 **클로저(Closure)** 나 **커링(Currying)** 기법을 구현할 때 자주 쓰입니다.
|
||||||
|
|
||||||
|
- **예시:**
|
||||||
|
``` javascript
|
||||||
|
function makeMultiplier(multiplier) {
|
||||||
|
// 함수 자체를 반환합니다.
|
||||||
|
return function(value) {
|
||||||
|
return value * multiplier;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const triple = makeMultiplier(3);
|
||||||
|
console.log(triple(10)); // 30
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
## 왜 고차 함수를 쓰나요?
|
||||||
|
|
||||||
|
고차 함수를 사용하면 코드의 **추상화 수준**을 높일 수 있습니다.
|
||||||
|
|
||||||
|
1. **코드의 재사용성:** 복잡한 로직(반복문, 조건문 등)은 고차 함수 내부에 숨기고, 실제 수행할 구체적인 작업만 함수로 갈아 끼울 수 있습니다.
|
||||||
|
|
||||||
|
2. **가독성 향상:** `for` 문을 돌리며 배열을 수정하는 대신, `filter`나 `map` 같은 명칭을 사용함으로써 코드가 무엇을 하려는지 의도를 명확히 드러낼 수 있습니다.
|
||||||
|
|
||||||
|
3. **함수형 프로그래밍:** 데이터를 직접 변경하지 않고 새로운 데이터를 생성하는 방식(불변성 유지)을 구현하기에 최적입니다.
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
---
|
||||||
|
id: 관계형 데이터베이스(RDBMS)의 한계 20260420
|
||||||
|
created: 2026-04-20 10:08
|
||||||
|
tags:
|
||||||
|
aliases:
|
||||||
|
---
|
||||||
|
## 💡 생각
|
||||||
|
서버의 수평적확장이 어려움 + 관계가 복잡해지면 조인연산이 느려질 수 있음
|
||||||
|
|
||||||
|
---
|
||||||
|
## 1. 유연하지 못한 스키마 (Rigid Schema)
|
||||||
|
|
||||||
|
RDBMS는 데이터를 저장하기 전에 미리 테이블 구조(Schema)를 정의해야 합니다.
|
||||||
|
|
||||||
|
- **변경의 어려움:** 서비스 운영 중에 데이터 구조를 변경하려면 `ALTER TABLE`과 같은 작업을 수행해야 하는데, 데이터 양이 많을 경우 시스템 부하가 크고 서비스 중단이 발생할 수 있습니다.
|
||||||
|
|
||||||
|
- **비정형 데이터 처리:** SNS 포스트, 로그 파일, 이미지 메타데이터 등 구조가 일정하지 않은 데이터를 담기에는 부적합합니다.
|
||||||
|
|
||||||
|
|
||||||
|
## 2. 수평적 확장(Scaling-out)의 어려움
|
||||||
|
|
||||||
|
RDBMS는 기본적으로 단일 서버의 성능을 높이는 **수직적 확장(Scale-up)** 에 최적화되어 있습니다.
|
||||||
|
|
||||||
|
- **분산 저정의 복잡성:** 여러 대의 서버에 데이터를 나누어 저장(Sharding)할 수 있지만, 이 경우 데이터 간의 일관성을 유지하고 조인(Join) 연산을 수행하는 것이 매우 까다로워집니다.
|
||||||
|
|
||||||
|
- **비용 문제:** 고성능의 단일 서버를 구축하는 비용은 서버를 여러 대 늘리는 비용보다 기하급수적으로 비싸집니다.
|
||||||
|
|
||||||
|
|
||||||
|
## 3. 복잡한 관계와 조인(Join) 성능 저하
|
||||||
|
|
||||||
|
데이터 간의 관계가 복잡해질수록 여러 테이블을 연결하는 **조인 연산**이 많아집니다.
|
||||||
|
|
||||||
|
- **성능 병목:** 수백만 건 이상의 데이터가 포함된 테이블들을 빈번하게 조인하면 쿼리 실행 속도가 급격히 느려집니다.
|
||||||
|
|
||||||
|
- **객체-관계 불일치 (Impedance Mismatch):** 객체지향 프로그래밍 언어의 구조와 RDBMS의 테이블 구조가 서로 달라, 이를 변환하는 과정(ORM 등)에서 복잡성이 증가하고 성능 손실이 발생합니다.
|
||||||
|
|
||||||
|
|
||||||
|
## 4. 대용량 데이터 처리 속도
|
||||||
|
|
||||||
|
초당 수만 건 이상의 쓰기 작업이 발생하는 실시간 서비스나 테라바이트(TB) 단위의 데이터를 분석하는 환경에서는 RDBMS의 ACID 트랜잭션 보장 기능이 오히려 독이 될 수 있습니다.
|
||||||
|
|
||||||
|
- **잠금(Locking) 현상:** 데이터의 일관성을 위해 특정 행이나 테이블을 잠그는 과정에서 대기 시간이 발생하여 전체적인 처리량이 떨어집니다.
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user