<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Minho.log</title>
        <link>https://velog.io/</link>
        <description>개발 공부를 하며 직접 부딪히고 공부한 것을 기록합니다.</description>
        <lastBuildDate>Tue, 31 Mar 2026 04:17:40 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Minho.log</title>
            <url>https://velog.velcdn.com/images/minho-03/profile/693d8254-5694-4ef0-8a52-e1755e48e102/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Minho.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/minho-03" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Pixel Processing: 화소 접근 및 밝기/명암비 조절]]></title>
            <link>https://velog.io/@minho-03/Pixel-Processing-%ED%99%94%EC%86%8C-%EC%A0%91%EA%B7%BC-%EB%B0%8F-%EB%B0%9D%EA%B8%B0%EB%AA%85%EC%95%94%EB%B9%84-%EC%A1%B0%EC%A0%88</link>
            <guid>https://velog.io/@minho-03/Pixel-Processing-%ED%99%94%EC%86%8C-%EC%A0%91%EA%B7%BC-%EB%B0%8F-%EB%B0%9D%EA%B8%B0%EB%AA%85%EC%95%94%EB%B9%84-%EC%A1%B0%EC%A0%88</guid>
            <pubDate>Tue, 31 Mar 2026 04:17:40 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>영상 내 개별 화소(Pixel) 데이터 접근법 및 산술 연산을 통한 밝기 제어</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>OpenCV 영상은 결국 uint8 형식을 갖는 행렬이다. 이 행렬의 각 원소(화소) 값을 수정하면 영상의 밝기를 밝게 하거나 어둡게 만들 수 있다.</p>
<ol>
<li>화소 접근 (Pixel Access)
배열 인덱싱: img[y, x] 형태로 특정 위치의 픽셀 값에 접근한다.
BGR 구조: 컬러 영상의 경우 img[y, x]는 [B, G, R] 세 개의 값을 가진 리스트 형태다.</li>
<li>밝기 조절 (Brightness)
영상의 모든 화소에 일정 값을 더하면 밝아지고, 빼면 어두워진다.
Overflow 주의: uint8 자료형은 $0$ ~ $255$ 사이만 표현한다. $250 + 10$이 $260$이 아닌 $4$(나머지값)가 되지 않도록 포화 연산(Saturation) 처리가 필수다.</li>
<li>명암비(Contrast) 조절
영상의 밝은 부분과 어두운 부분의 차이를 크게 만드는 것이다.
보통 픽셀 값에 특정 상수를 곱하여 조절한다.</li>
</ol>
<h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>영상의 밝기를 전체적으로 높이고, 포화 연산을 적용하는 실습.</p>
<ol>
<li>밝기 조절 및 산술 연산 (brightness_test.py)
Python<pre><code>import cv2
import numpy as np
</code></pre></li>
</ol>
<h1 id="영상-불러오기-grayscale로-테스트">영상 불러오기 (Grayscale로 테스트)</h1>
<p>src = cv2.imread(&#39;lenna.jpg&#39;, cv2.IMREAD_GRAYSCALE)</p>
<p>if src is None:
    print(&quot;이미지를 찾을 수 없습니다.&quot;)
    exit()</p>
<h1 id="1-단순-더하기-numpy-연산---overflow-위험-있음">1. 단순 더하기 (Numpy 연산 - Overflow 위험 있음)</h1>
<h1 id="255를-넘어가면-다시-0부터-시작해서-이상한-무늬가-생김">255를 넘어가면 다시 0부터 시작해서 이상한 무늬가 생김</h1>
<p>dst_bad = src + 100</p>
<h1 id="2-opencv-포화-연산-함수-사용-권장">2. OpenCV 포화 연산 함수 사용 (권장)</h1>
<h1 id="255를-넘으면-255로-고정해줌">255를 넘으면 255로 고정해줌</h1>
<p>dst_good = cv2.add(src, 100)</p>
<h1 id="3-명암비-조절-픽셀-값에-20-곱하기">3. 명암비 조절 (픽셀 값에 2.0 곱하기)</h1>
<p>dst_contrast = cv2.multiply(src, 2.0)</p>
<p>cv2.imshow(&#39;Original&#39;, src)
cv2.imshow(&#39;Bad Brightness (Numpy)&#39;, dst_bad)
cv2.imshow(&#39;Good Brightness (OpenCV)&#39;, dst_good)
cv2.imshow(&#39;Contrast High&#39;, dst_contrast)</p>
<p>cv2.waitKey(0)
cv2.destroyAllWindows()</p>
<p>```</p>
<h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<p>Numpy 연산 vs OpenCV 함수: src + 100처럼 넘파이 배열 연산을 직접 쓰면 $255$를 초과할 때 값이 튀어버리는(Modulo 연산) 현상이 발생한다. 영상 처리를 할 때는 반드시 cv2.add()나 np.clip()을 사용해 값을 가둬줘야 한다는 점을 배웠다.
데이터 타입: 연산 과정에서 일시적으로 $255$를 넘거나 음수가 될 수 있으므로, 복잡한 연산 시에는 float32로 변환했다가 다시 uint8로 바꾸는 과정이 필요할 수 있음을 알게 되었다.</p>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<p>영상의 밝기는 화소 값의 덧셈/뺄셈, 명암비는 곱셈으로 조절한다.
값의 범위가 $0$ ~ $255$를 벗어나지 않도록 <strong>포화 연산(Saturation)</strong>을 적용해야 한다.
OpenCV의 cv2.add(), cv2.subtract() 함수는 내부적으로 포화 연산을 처리해준다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Drawing & Events: 영상 위 도형 그리기와마우스 이벤트]]></title>
            <link>https://velog.io/@minho-03/Drawing-Events-%EC%98%81%EC%83%81-%EC%9C%84-%EB%8F%84%ED%98%95-%EA%B7%B8%EB%A6%AC%EA%B8%B0%EC%99%80%EB%A7%88%EC%9A%B0%EC%8A%A4-%EC%9D%B4%EB%B2%A4%ED%8A%B8</link>
            <guid>https://velog.io/@minho-03/Drawing-Events-%EC%98%81%EC%83%81-%EC%9C%84-%EB%8F%84%ED%98%95-%EA%B7%B8%EB%A6%AC%EA%B8%B0%EC%99%80%EB%A7%88%EC%9A%B0%EC%8A%A4-%EC%9D%B4%EB%B2%A4%ED%8A%B8</guid>
            <pubDate>Mon, 30 Mar 2026 07:54:16 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>OpenCV를 활용한 데이터 시각화(도형, 텍스트) 및 마우스 인터랙션 구현</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>이미지 행렬 데이터 위에 직접 선을 긋거나 글자를 써서 분석 결과를 표현할 수 있다. 또한, 마우스 클릭이나 드래그 같은 이벤트를 감지하여 특정 영역(ROI)을 지정하는 등의 인터랙티브한 코드를 짤 수 있다.</p>
<ol>
<li>주요 그리기 함수</li>
</ol>
<p>cv2.line(): 직선 그리기.</p>
<p>cv2.rectangle(): 사각형 그리기 (검출된 객체 표시용으로 가장 많이 씀).</p>
<p>cv2.circle(): 원 그리기.</p>
<p>cv2.putText(): 영상 위에 문자열 출력. (한글은 기본적으로 지원되지 않음)</p>
<ol start="2">
<li>마우스 이벤트 처리</li>
</ol>
<p>cv2.setMouseCallback(): 특정 윈도우 창에서 발생하는 마우스 동작을 감지할 콜백(Callback) 함수를 등록한다.</p>
<p>마우스 왼쪽 버튼 클릭(LBUTTONDOWN), 떼기(LBUTTONUP), 움직임(MOUSEMOVE) 등을 구분하여 처리할 수 있다.</p>
<h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>빈 캔버스에 마우스 드래그로 사각형을 그리는 실습.</p>
<ol>
<li>도형 그리기 및 이벤트 처리 (mouse_draw.py)</li>
</ol>
<p>Python</p>
<pre><code>import cv2
import numpy as np

# 전역 변수 설정
is_drawing = False
start_x, start_y = -1, -1

def draw_rect(event, x, y, flags, param):
    global is_drawing, start_x, start_y, img

    if event == cv2.EVENT_LBUTTONDOWN: # 마우스 클릭 시작
        is_drawing = True
        start_x, start_y = x, y

    elif event == cv2.EVENT_MOUSEMOVE: # 마우스 이동
        if is_drawing:
            # 실시간으로 그려지는 효과를 위해 원본 복사본 사용 추천 (여기선 생략)
            pass

    elif event == cv2.EVENT_LBUTTONUP: # 마우스 클릭 종료
        is_drawing = False
        # 사각형 그리기 (이미지, 시작점, 끝점, 색상(BGR), 두께)
        cv2.rectangle(img, (start_x, start_y), (x, y), (0, 255, 0), 2)
        cv2.imshow(&#39;Canvas&#39;, img)

# 검은색 배경 이미지 생성
img = np.zeros((512, 512, 3), np.uint8)
cv2.namedWindow(&#39;Canvas&#39;)

# 마우스 콜백 함수 등록
cv2.setMouseCallback(&#39;Canvas&#39;, draw_rect)

while True:
    cv2.imshow(&#39;Canvas&#39;, img)
    if cv2.waitKey(1) &amp; 0xFF == ord(&#39;q&#39;):
        break

cv2.destroyAllWindows()</code></pre><h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<p>BGR 색상 순서: 여전히 (Red, Green, Blue) 순서가 아니라 (Blue, Green, Red) 순서라는 점. 초록색 사각형을 그릴 때 (0, 255, 0)을 사용하는 것에 익숙해져야 한다.</p>
<p>좌표계 체계: 영상의 왼쪽 상단이 $(0, 0)$이며, 마우스 이벤트로 들어오는 x, y 값도 이 좌표계를 따른다는 점을 명확히 이해했다.</p>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<p>Drawing 함수는 원본 이미지(numpy 배열)를 직접 수정한다.</p>
<p>콜백 함수를 이용하면 사용자의 마우스/키보드 입력을 실시간으로 반영할 수 있다.</p>
<p>영상 처리 결과를 사용자에게 직관적으로 보여주기 위해 시각화 능력은 필수다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[OpenCV 영상 읽기/쓰기 및 동영상 스트리밍]]></title>
            <link>https://velog.io/@minho-03/OpenCV-%EC%98%81%EC%83%81-%EC%9D%BD%EA%B8%B0%EC%93%B0%EA%B8%B0-%EB%B0%8F-%EB%8F%99%EC%98%81%EC%83%81-%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D</link>
            <guid>https://velog.io/@minho-03/OpenCV-%EC%98%81%EC%83%81-%EC%9D%BD%EA%B8%B0%EC%93%B0%EA%B8%B0-%EB%B0%8F-%EB%8F%99%EC%98%81%EC%83%81-%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D</guid>
            <pubDate>Mon, 30 Mar 2026 07:40:21 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>OpenCV를 이용한 정지 영상 및 동영상 데이터의 입출력 프로세스 이해</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>영상 처리는 결국 데이터를 읽어와서(Input), 가공하고, 다시 보여주거나 저장하는(Output) 과정의 반복이다. 특히 동영상은 아주 빠른 속도로 정지 영상을 연속해서 보여주는 것이 핵심이다.</p>
<ol>
<li>정지 영상 (Image)</li>
</ol>
<p>cv2.imread(filename, flags): 파일을 읽어 행렬(numpy.ndarray)로 반환한다.</p>
<p>cv2.imshow(title, image): 특정 윈도우 창에 영상을 출력한다.</p>
<p>cv2.imwrite(filename, image): 가공된 행렬 데이터를 파일로 저장한다.</p>
<ol start="2">
<li>동영상 및 카메라 (Video/Webcam)</li>
</ol>
<p>cv2.VideoCapture(): 카메라 장치나 동영상 파일을 연다. (보통 웹캠은 0번 사용)</p>
<p>프레임(Frame): 동영상을 구성하는 한 장 한 장의 정지 영상.</p>
<p>cap.read(): 카메라로부터 한 프레임씩 읽어온다</p>
<h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>웹캠 영상을 실시간으로 읽어와서 화면에 출력하고 종료하는 실습.</p>
<ol>
<li>웹캠 스트리밍 코드 (webcam_test.py)</li>
</ol>
<p>Python</p>
<pre><code>import cv2

# 0번 카메라 장치 열기
cap = cv2.VideoCapture(0)

if not cap.isOpened():
    print(&quot;카메라를 열 수 없습니다.&quot;)
    exit()

# 카메라 속성 출력 (가로, 세로 크기)
print(&#39;Width:&#39;, cap.get(cv2.CAP_PROP_FRAME_WIDTH))
print(&#39;Height:&#39;, cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

while True:
    # 한 프레임씩 읽기 (ret: 성공여부, frame: 이미지 데이터)
    ret, frame = cap.read()

    if not ret:
        break

    # 영상을 화면에 표시
    cv2.imshow(&#39;Webcam View&#39;, frame)

    # 1ms 대기, &#39;q&#39; 키를 누르면 루프 탈출
    if cv2.waitKey(1) &amp; 0xFF == ord(&#39;q&#39;):
        break

# 자원 해제
cap.release()
cv2.destroyAllWindows()</code></pre><h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<p>cap.isOpened() 체크: 카메라가 다른 프로그램에서 사용 중이거나 연결이 불량하면 에러 없이 빈 화면만 나올 수 있다. 반드시 초기 오픈 여부를 확인하는 습관이 중요하다.</p>
<p>waitKey(1)의 중요성: 동영상 출력 시 waitKey 값이 너무 크면 슬로우 모션이 되고, 너무 작으면 CPU 점유율이 치솟는다. 보통 실시간 처리를 위해 1 또는 10 정도를 사용한다는 점을 배웠다.</p>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<p>영상 입출력의 기본 함수는 imread, imshow, imwrite이다.</p>
<p>동영상은 VideoCapture 객체를 통해 While 루프 안에서 프레임 단위로 처리한다.</p>
<p>작업이 끝나면 반드시 <strong>release()</strong>를 호출하여 카메라 자원을 반납해야 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ROS 워크스페이스 생성과 빌드 시스템(catkin_make)]]></title>
            <link>https://velog.io/@minho-03/ROS-%EC%9B%8C%ED%81%AC%EC%8A%A4%ED%8E%98%EC%9D%B4%EC%8A%A4-%EC%83%9D%EC%84%B1%EA%B3%BC-%EB%B9%8C%EB%93%9C-%EC%8B%9C%EC%8A%A4%ED%85%9Ccatkinmake</link>
            <guid>https://velog.io/@minho-03/ROS-%EC%9B%8C%ED%81%AC%EC%8A%A4%ED%8E%98%EC%9D%B4%EC%8A%A4-%EC%83%9D%EC%84%B1%EA%B3%BC-%EB%B9%8C%EB%93%9C-%EC%8B%9C%EC%8A%A4%ED%85%9Ccatkinmake</guid>
            <pubDate>Wed, 04 Mar 2026 01:18:20 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>ROS Noetic의 작업 공간(catkin_ws) 설정 및 빌드 프로세스 이해</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>ROS에서 소스코드를 작성하고 실행하려면, 단순히 폴더를 만드는 게 아니라 ROS 빌드 시스템이 인식할 수 있는 워크스페이스(Workspace) 형식을 갖춰야 한다. Noetic에서는 주로 catkin 빌드 시스템을 사용한다.</p>
<ol>
<li>워크스페이스 구조
기본적으로 다음과 같은 3가지 주요 폴더로 구성된다.</li>
</ol>
<ul>
<li>src/: 우리가 만든 패키지(소스코드)가 들어가는 곳. (가장 중요!)</li>
<li>build/: 빌드 과정에서 생성되는 중간 파일들이 저장되는 곳.</li>
<li>devel/: 빌드가 완료된 실행 파일과 환경 설정 파일(setup.bash)이 있는 곳.</li>
</ul>
<ol start="2">
<li>워크스페이스 생성 과정</li>
</ol>
<pre><code># 1. 폴더 생성 (반드시 src 폴더까지 한 번에!)
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/

# 2. 초기 빌드 실행 (작업 공간 초기화)
catkin_make</code></pre><ol start="3">
<li>환경 등록 (Overlay 설정)
우리가 만든 패키지를 ROS가 인식하게 하려면, 워크스페이스의 setup.bash를 불러와야 한다.</li>
</ol>
<pre><code>source ~/catkin_ws/devel/setup.bash</code></pre><p>매번 입력하기 번거로우므로 ~/.bashrc에 추가해두는 것이 국룰이다.</p>
<h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>새로운 패키지를 하나 만들어서 빌드하는 과정을 실습</p>
<ol>
<li>패키지 생성 (의존성 포함)</li>
</ol>
<pre><code>cd ~/catkin_ws/src
# catkin_create_pkg [패키지명] [의존성1] [의존성2]
catkin_create_pkg my_first_pkg std_msgs rospy roscpp</code></pre><ul>
<li>std_msgs: 기본 데이터 타입 (문자열, 숫자 등)</li>
<li>rospy: 파이썬용 ROS 라이브러리</li>
<li>roscpp: C++용 ROS 라이브러리</li>
</ul>
<ol start="2">
<li>빌드 실행</li>
</ol>
<pre><code>cd ~/catkin_ws
catkin_make</code></pre><p>성공하면 build와 devel 폴더가 업데이트된다.</p>
<h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<ul>
<li>catkin_make 위치: 반드시 catkin_ws의 루트(최상위) 폴더에서 실행해야 한다. src 안에서 실행하면 에러가 난다.</li>
<li>패키지 인식 문제: 패키지를 분명히 만들었는데 rospack find로 안 찾아진다면? source ~/catkin_ws/devel/setup.bash를 실행했는지 꼭 확인해야 한다. (이거 10년 차들도 가끔 까먹는다.)</li>
</ul>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<ul>
<li><strong>catkin_ws</strong>는 ROS 개발의 베이스캠프다.</li>
<li>소스코드는 반드시 src 폴더 안에 패키지 형태로 넣어야 한다.</li>
<li>빌드는 catkin_make 명령어로 수행하며, 빌드 후에는 <strong>devel/setup.bash</strong>를 로드해야 한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[ROS의 핵심 개념(Master, Node, Package)]]></title>
            <link>https://velog.io/@minho-03/ROS%EC%9D%98-%ED%95%B5%EC%8B%AC-%EA%B0%9C%EB%85%90Master-Node-Package</link>
            <guid>https://velog.io/@minho-03/ROS%EC%9D%98-%ED%95%B5%EC%8B%AC-%EA%B0%9C%EB%85%90Master-Node-Package</guid>
            <pubDate>Wed, 04 Mar 2026 00:58:59 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>ROS Noetic의 기본 통신 구조와 구성 요소 이해</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>ROS는 거대한 하나의 프로그램이 아니라, 여러 개의 작은 프로그램들이 서로 데이터를 주고받으며 작동하는 분산 처리 시스템이다. 이를 이해하기 위한 3가지 핵심 키워드는 다음과 같다.</p>
<ol>
<li>노드 (Node)</li>
</ol>
<ul>
<li>정의: 최소 단위의 실행 프로그램.</li>
<li>역할: 로봇의 센서 하나, 모터 하나, 혹은 특정 알고리즘 하나가 각각의 노드가 된다.</li>
<li>장점: 하나가 죽어도 다른 노드에 영향을 주지 않아 시스템이 안정적이다.</li>
</ul>
<ol start="2">
<li>마스터 (Master / roscore)</li>
</ol>
<ul>
<li>정의: 노드들 사이의 통신을 돕는 중개자.</li>
<li>역할: 각 노드가 어디에 있는지 정보를 가지고 있으며, 노드들이 서로를 찾을 수 있게 연결해준다.</li>
<li>실행: 터미널에서 roscore 명령어를 입력하면 마스터가 실행된다. (이게 꺼지면 통신 불가!)</li>
</ul>
<ol start="3">
<li>패키지 (Package)</li>
</ol>
<ul>
<li>정의: ROS 소프트웨어를 구성하는 기본 단위.</li>
<li>역할: 관련된 노드, 설정 파일, 데이터 등을 하나로 묶어놓은 폴더 개념이다.</li>
<li>특징: 남이 만든 기능을 가져다 쓸 때도 &#39;패키지&#39; 단위로 내려받아 사용한다.</li>
</ul>
<h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>현재 실행 중인 노드와 마스터의 상태를 확인하는 필수 명령어들이다.</p>
<ol>
<li>마스터 실행</li>
</ol>
<pre><code>roscore</code></pre><ol start="2">
<li>실행 중인 노드 목록 확인</li>
</ol>
<pre><code>rosnode list</code></pre><p>/rosout: 로그 기록을 담당하는 기본 노드로, 항상 떠 있어야 정상이다.</p>
<ol start="3">
<li>특정 노드의 정보 확인</li>
</ol>
<pre><code>rosnode info /turtlesim</code></pre><p>어떤 데이터를 보내고 받는지 상세 정보를 보여준다.</p>
<ol start="4">
<li>노드 간의 관계 시각화 (치트키)</li>
</ol>
<pre><code>rqt_graph</code></pre><p>어떤 노드가 어떤 통로(Topic)로 연결되어 있는지 그림으로 보여준다. 초보 때는 무조건 이걸 켜놓고 공부하는 게 좋다.</p>
<h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<ul>
<li>마스터의 역할: 마스터가 데이터를 직접 전달하는 줄 알았는데, 사실 마스터는 <strong>&quot;연락처&quot;</strong>만   알려줄 뿐이다. 실제 데이터는 노드끼리 직접(Peer-to-Peer) 주고받는다는 점이 놀라웠다.</li>
<li>패키지 vs 폴더: 그냥 폴더를 만든다고 패키지가 되는 게 아니라, 안에 package.xml과<br>CMakeLists.txt가 있어야 ROS가 패키지로 인식한다는 점을 잊지 말자.</li>
</ul>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<ul>
<li><strong>마스터(roscore)</strong>는 통신의 전화국 역할을 한다.</li>
<li>노드는 각 기능을 수행하는 개별 프로그램이다.</li>
<li>패키지는 코드를 담는 가방이며, ROS 관리의 기본 단위다.</li>
<li><strong>rqt_graph</strong>를 통해 시스템 전체 구조를 한눈에 파악할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Ubuntu 20.04에 ROS Noetic 설치]]></title>
            <link>https://velog.io/@minho-03/Ubuntu-20.04%EC%97%90-ROS-Noetic-%EC%84%A4%EC%B9%98</link>
            <guid>https://velog.io/@minho-03/Ubuntu-20.04%EC%97%90-ROS-Noetic-%EC%84%A4%EC%B9%98</guid>
            <pubDate>Wed, 04 Mar 2026 00:53:15 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>ROS Noetic Ninjemys 설치 및 환경 설정</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>ROS Noetic은 Ubuntu 20.04(Focal Fossa) OS를 공식 지원하는 마지막 ROS 1 버전이다. 설치 과정은 크게 리포지토리 설정, 키 등록, 패키지 설치, 환경 변수 설정으로 나뉜다.</p>
<ol>
<li><p>소프트웨어 저장소 설정
Ubuntu의 restricted, universe, multiverse 저장소가 허용되어 있어야 한다.</p>
</li>
<li><p>sources.list 설정 및 Keys 등록
패키지를 다운로드할 서버 주소를 등록하고, 보안을 위한 인증키를 추가한다.</p>
<pre><code>sudo sh -c &#39;echo &quot;deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main&quot; &gt; /etc/apt/sources.list.d/ros-latest.list&#39;
sudo apt install curl # curl이 없을 경우
curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -</code></pre></li>
<li><p>ROS Noetic 설치
가장 권장되는 방식은 시각화 도구(RViz, Gazebo 등)가 모두 포함된 Desktop-Full 버전이다.</p>
<pre><code>sudo apt update
sudo apt install ros-noetic-desktop-full</code></pre></li>
<li><p>환경 설정 (bashrc)
새 터미널을 열 때마다 ROS 명령어를 인식할 수 있도록 setup.bash 파일을 불러와야 한다.</p>
</li>
</ol>
<pre><code>echo &quot;source /opt/ros/noetic/setup.bash&quot; &gt;&gt; ~/.bashrc
source ~/.bashrc</code></pre><h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>설치가 잘 되었는지 확인하려면 ROS Master를 실행해본다.</p>
<p>터미널 1:</p>
<pre><code>roscore</code></pre><p>rosout 노드가 실행되며 &quot;started core service&quot; 메시지가 뜨면 성공이다.</p>
<p>터미널 2 (설치 확인용 거북이 실행):</p>
<pre><code>rosrun turtlesim turtlesim_node</code></pre><p>파란 배경의 거북이 창이 뜨면 그래픽 라이브러리까지 완벽하게 설치된 것이다.</p>
<h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<ul>
<li>Python 버전: Noetic은 이전 버전(Melodic)과 달리 Python 3가 기본이다. 따라서 python-rosdep이 아니라 python3-rosdep 처럼 패키지 명에 3이 들어가는 경우가 많으니 주의해야 한다.</li>
<li>source 명령: 환경 설정을 .bashrc에 추가한 뒤, 현재 열려있는 터미널에 적용하려면 반드시 source ~/.bashrc를 직접 한 번 실행해줘야 한다.</li>
</ul>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<ul>
<li>ROS Noetic은 Ubuntu 20.04 전용이다.</li>
<li>설치 후에는 반드시 <strong>.bashrc</strong>에 환경 변수를 등록해야 ros 명령어를 어디서든 쓸 수 있다.</li>
<li>설치 확인은 roscore와 turtlesim으로 간단하게 할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[ROS development]]></title>
            <link>https://velog.io/@minho-03/ROS-development</link>
            <guid>https://velog.io/@minho-03/ROS-development</guid>
            <pubDate>Tue, 03 Mar 2026 04:19:51 GMT</pubDate>
            <description><![CDATA[<h1 id="ros-development">ROS development</h1>
<ul>
<li>Ubuntu 20.04</li>
<li>ROS noetic</li>
</ul>
<h1 id="ros-install">ROS install</h1>
<ol>
<li>source list<pre><code class="language-bash">sudo sh -c &#39;echo &quot;deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main&quot; &gt; /etc/apt/sources.list.d/ros-latest.list&#39;</code></pre>
</li>
<li>Set up your keys<pre><code class="language-bash">sudo apt install curl
curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -</code></pre>
</li>
<li>Installation<pre><code class="language-bash">sudo apt update</code></pre>
<pre><code class="language-bash">sudo apt install ros-noetic-desktop-full</code></pre>
</li>
<li>Environment setup<pre><code class="language-bash">source /opt/ros/noetic/setup.bash</code></pre>
<pre><code class="language-bash">echo &quot;source /opt/ros/noetic/setup.bash&quot; &gt;&gt; ~/.bashrc
source ~/.bashrc</code></pre>
</li>
<li>Create a ROS Workspace<pre><code class="language-bash">mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/
catkin_make</code></pre>
<pre><code class="language-bash">source devel/setup.bash</code></pre>
<pre><code class="language-bash">echo $ROS_PACKAGE_PATH</code></pre>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Flask 프로젝트 구조]]></title>
            <link>https://velog.io/@minho-03/Flask-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@minho-03/Flask-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Sat, 14 Feb 2026 12:53:23 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>Flask 프로젝트 구조 (templates / static 분리)</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>Flask는 파일 하나로도 서버를 만들 수 있지만, 실제로는 기능이 늘어나면서 파일을 분리하는 구조가 필요하다.
프로젝트 구조를 잘 잡아두면 라우팅, 템플릿, 정적 파일(CSS/JS/이미지), 설정을 관리하기가 훨씬 편해진다.</p>
<p>Flask에서 기본적으로 자주 쓰는 폴더는 다음과 같다.</p>
<ul>
<li>templates/ : HTML 템플릿 파일 위치</li>
<li>static/ : CSS, JS, 이미지 같은 정적 파일 위치</li>
</ul>
<p>Flask는 기본 설정으로 templates와 static 폴더를 자동으로 인식한다.
그래서 별도 설정 없이도 파일을 넣기만 하면 사용할 수 있다.</p>
<pre><code>기본 구조 예시 (가장 단순)
myflask/
 ├── app.py
 ├── templates/
 │    └── index.html
 └── static/
      ├── css/
      │    └── style.css
      └── js/
           └── main.js</code></pre><p>이 구조는 템플릿과 정적 파일을 분리해서 관리하는 가장 기본 형태다.</p>
<p>템플릿 연결
Flask에서 HTML을 반환할 때는 render_template()를 사용한다.</p>
<pre><code>from flask import render_template

@app.route(&quot;/&quot;)
def home():
    return render_template(&quot;index.html&quot;)</code></pre><p>정적 파일 연결
정적 파일은 HTML에서 url_for(&quot;static&quot;, filename=&quot;...&quot;) 형태로 연결한다.
CSS 연결 예시</p>
<pre><code>&lt;link rel=&quot;stylesheet&quot; href=&quot;{{ url_for(&#39;static&#39;, filename=&#39;css/style.css&#39;) }}&quot;&gt;</code></pre><p>JS 연결 예시</p>
<pre><code>&lt;script src=&quot;{{ url_for(&#39;static&#39;, filename=&#39;js/main.js&#39;) }}&quot;&gt;&lt;/script&gt;</code></pre><p>이미지 연결 예시</p>
<pre><code>&lt;img src=&quot;{{ url_for(&#39;static&#39;, filename=&#39;img/logo.png&#39;) }}&quot;&gt;</code></pre><p>파일이 많아졌을 때 구조 확장
프로젝트가 커지면 보통 다음처럼 분리한다.</p>
<pre><code>myflask/
 ├── app/
 │    ├── __init__.py
 │    ├── routes.py
 │    ├── templates/
 │    └── static/
 ├── run.py
 └── requirements.txt</code></pre><p>app/ 안에 실제 Flask 코드들을 모아두고 run.py에서 실행하는 형태로 많이 사용한다</p>
<h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>폴더 구조</p>
<pre><code>myflask/
 ├── app.py
 ├── templates/
 │    └── index.html
 └── static/
      └── css/
           └── style.css</code></pre><p>app.py</p>
<pre><code>from flask import Flask, render_template

app = Flask(__name__)

@app.route(&quot;/&quot;)
def home():
    return render_template(&quot;index.html&quot;)

if __name__ == &quot;__main__&quot;:
    app.run(debug=True)</code></pre><p>templates/index.html</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot; /&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;{{ url_for(&#39;static&#39;, filename=&#39;css/style.css&#39;) }}&quot;&gt;
  &lt;title&gt;Flask 구조&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;Flask Templates + Static&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>static/css/style.css</p>
<pre><code>h1 {
  font-size: 40px;
}</code></pre><h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<ul>
<li>정적 파일 경로를 직접 /static/... 로 써도 되지만, url_for()로 연결하는 방식이 더 안전하다는 점이 낯설었다.</li>
</ul>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<ul>
<li>Flask는 templates 폴더에서 HTML을 관리한다.</li>
<li>static 폴더에서 CSS/JS/이미지 같은 정적 파일을 관리한다.</li>
<li>정적 파일은 url_for(&#39;static&#39;, filename=&#39;...&#39;)로 연결하는 것이 기본이다.</li>
<li>프로젝트가 커지면 app 폴더로 구조를 확장해서 관리하는 방식이 좋다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Flask 요청(Request)과 응답(Response)]]></title>
            <link>https://velog.io/@minho-03/Flask-%EC%9A%94%EC%B2%ADRequest%EA%B3%BC-%EC%9D%91%EB%8B%B5Response</link>
            <guid>https://velog.io/@minho-03/Flask-%EC%9A%94%EC%B2%ADRequest%EA%B3%BC-%EC%9D%91%EB%8B%B5Response</guid>
            <pubDate>Sat, 14 Feb 2026 12:42:17 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>Flask 요청(Request)과 응답(Response) 기본</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>Flask에서 웹 서버는 기본적으로 요청(Request)을 받고 응답(Response)을 반환하는 구조로 동작한다.
사용자가 브라우저에서 URL에 접속하거나, 클라이언트가 API 호출을 하면 서버에 요청이 들어오고 Flask가 이를 처리한 뒤 응답을 돌려준다.</p>
<p>요청에서 자주 다루는 요소는 다음과 같다.</p>
<ul>
<li>요청 방식(Method): GET, POST 등</li>
<li>URL 파라미터(Query String)</li>
<li>경로 변수(Path Variable)</li>
<li>요청 본문(Body): JSON, Form 데이터</li>
<li>요청 헤더(Header)
응답은 다음과 같은 형태로 반환할 수 있다.</li>
<li>문자열(텍스트)</li>
<li>HTML 템플릿</li>
<li>JSON 데이터</li>
<li>상태 코드(Status Code)</li>
</ul>
<p>요청 방식(Method)
라우팅에 methods를 지정해서 어떤 요청을 받을지 설정한다.</p>
<pre><code>@app.route(&quot;/test&quot;, methods=[&quot;GET&quot;, &quot;POST&quot;])
def test():
    return &quot;ok&quot;</code></pre><p>GET은 조회에, POST는 데이터 전송/생성에 주로 사용한다.</p>
<p>Query String 받기 (URL 파라미터)
URL 뒤에 ?key=value 형태로 붙는 값이다.</p>
<pre><code>from flask import request

@app.route(&quot;/search&quot;, methods=[&quot;GET&quot;])
def search():
    q = request.args.get(&quot;q&quot;)
    return f&quot;query={q}&quot;</code></pre><p>예시 URL</p>
<pre><code>/search?q=flask</code></pre><p>Path Variable 받기 (경로 변수)
URL 경로 자체에 변수를 포함한다.</p>
<pre><code>@app.route(&quot;/users/&lt;name&gt;&quot;, methods=[&quot;GET&quot;])
def users(name):
    return f&quot;user={name}&quot;</code></pre><p>예시 URL</p>
<pre><code>/users/minho</code></pre><p>Body 데이터 받기 (POST)
Form 데이터와 JSON 데이터는 받는 방식이 다르다.
Form 데이터 받기 (HTML form)</p>
<pre><code>from flask import request

@app.route(&quot;/login&quot;, methods=[&quot;POST&quot;])
def login():
    username = request.form.get(&quot;username&quot;)
    return f&quot;username={username}&quot;</code></pre><p>JSON 데이터 받기 (API)</p>
<pre><code>from flask import request, jsonify

@app.route(&quot;/echo&quot;, methods=[&quot;POST&quot;])
def echo():
    data = request.json
    return jsonify(data)</code></pre><p>Header 확인하기
요청 헤더는 인증 토큰이나 Content-Type 확인에 자주 사용한다.</p>
<pre><code>from flask import request

@app.route(&quot;/headers&quot;, methods=[&quot;GET&quot;])
def headers():
    ua = request.headers.get(&quot;User-Agent&quot;)
    return f&quot;User-Agent={ua}&quot;</code></pre><p>응답: 상태 코드와 함께 반환하기
Flask에서는 응답 데이터와 상태 코드를 함께 반환할 수 있다.</p>
<pre><code>from flask import jsonify

@app.route(&quot;/notfound&quot;, methods=[&quot;GET&quot;])
def notfound():
    return jsonify({&quot;message&quot;: &quot;not found&quot;}), 404</code></pre><h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>요청과 응답을 한 번에 연습할 수 있는 예제</p>
<pre><code>from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route(&quot;/api/users/&lt;name&gt;&quot;, methods=[&quot;GET&quot;])
def get_user(name):
    age = request.args.get(&quot;age&quot;, type=int)
    return jsonify({&quot;name&quot;: name, &quot;age&quot;: age})

@app.route(&quot;/api/users&quot;, methods=[&quot;POST&quot;])
def create_user():
    data = request.json
    if not data or &quot;name&quot; not in data:
        return jsonify({&quot;message&quot;: &quot;name is required&quot;}), 400
    return jsonify({&quot;message&quot;: &quot;created&quot;, &quot;user&quot;: data}), 201

if __name__ == &quot;__main__&quot;:
    app.run(debug=True)</code></pre><p>GET 테스트</p>
<pre><code>curl &quot;http://127.0.0.1:5000/api/users/minho?age=24&quot;</code></pre><p>POST 테스트</p>
<pre><code>curl -X POST &quot;http://127.0.0.1:5000/api/users&quot; \
  -H &quot;Content-Type: application/json&quot; \
  -d &#39;{&quot;name&quot;:&quot;minho&quot;,&quot;age&quot;:24}&#39;</code></pre><h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<ul>
<li>Query String은 request.args, Form 데이터는 request.form, JSON 데이터는 request.json으로 받는다는 점이 처음에 헷갈렸다.</li>
<li>응답에 상태 코드를 붙이는 방식이 낯설었는데 return 데이터, 상태코드 형태로 쓸 수 있다는 점을 정리했다.</li>
</ul>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<ul>
<li>Flask는 요청을 받아 응답을 반환하는 구조로 동작한다.</li>
<li>Query String은 request.args, Form은 request.form, JSON은 request.json을 사용한다.</li>
<li>응답은 문자열/HTML/JSON으로 만들 수 있고 상태 코드도 함께 반환할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Flask API 만들기]]></title>
            <link>https://velog.io/@minho-03/Flask-API-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@minho-03/Flask-API-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Sat, 14 Feb 2026 12:35:25 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>Flask로 API 만들기 (JSON 응답)</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>API는 클라이언트(브라우저, 앱 등)가 서버에 요청을 보내면 서버가 데이터를 응답하는 방식이다.
웹 페이지(HTML)를 반환하는 것과 달리, API는 보통 JSON 형태의 데이터를 반환한다.</p>
<p>Flask에서 API를 만들 때는 다음 흐름을 이해하면 된다.</p>
<ol>
<li>URL(라우팅)을 만든다</li>
<li>요청 방식(GET/POST 등)을 지정한다</li>
<li>필요한 데이터를 처리한다</li>
<li>JSON 형태로 응답한다
Flask에서는 JSON 응답을 쉽게 만들기 위해 jsonify()를 사용한다.
또한 POST 요청에서 JSON 데이터를 받으려면 request.json을 사용한다.</li>
</ol>
<h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>GET 방식으로 JSON 응답하기</p>
<pre><code>from flask import Flask, jsonify

app = Flask(__name__)

@app.route(&quot;/ping&quot;, methods=[&quot;GET&quot;])
def ping():
    return jsonify({&quot;result&quot;: &quot;pong&quot;})

if __name__ == &quot;__main__&quot;:
    app.run(debug=True)</code></pre><p>브라우저에서 접속</p>
<pre><code>http://127.0.0.1:5000/ping</code></pre><p>응답 예시</p>
<pre><code>{&quot;result&quot;:&quot;pong&quot;}</code></pre><p>POST 방식으로 JSON 받기 + JSON 응답하기</p>
<pre><code>from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route(&quot;/echo&quot;, methods=[&quot;POST&quot;])
def echo():
    data = request.json
    return jsonify({
        &quot;you_sent&quot;: data,
        &quot;message&quot;: &quot;ok&quot;
    })

if __name__ == &quot;__main__&quot;:
    app.run(debug=True)</code></pre><p>터미널에서 테스트 (curl)</p>
<pre><code>curl -X POST http://127.0.0.1:5000/echo \
  -H &quot;Content-Type: application/json&quot; \
  -d &#39;{&quot;name&quot;:&quot;minho&quot;,&quot;age&quot;:24}&#39;</code></pre><p>응답 예시</p>
<pre><code>{
  &quot;message&quot;: &quot;ok&quot;,
  &quot;you_sent&quot;: {
    &quot;age&quot;: 24,
    &quot;name&quot;: &quot;minho&quot;
  }
}</code></pre><h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<ul>
<li>HTML을 반환할 때는 render_template()를 썼는데, API는 jsonify()를 써야 한다는 점이 처음에는 헷갈렸다.</li>
<li>POST 요청에서 데이터를 받을 때 request.form과 request.json의 차이가 헷갈렸는데, JSON 요청이면 request.json을 사용해야 한다는 걸 정리했다.</li>
</ul>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<ul>
<li>API는 보통 JSON 데이터를 응답한다.</li>
<li>Flask에서는 jsonify()로 JSON 응답을 만든다.</li>
<li>POST 요청에서 JSON 데이터를 받으려면 request.json을 사용한다.</li>
<li>curl로 API 테스트가 가능하다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Flask 템플릿 사용하기]]></title>
            <link>https://velog.io/@minho-03/Flask-%ED%85%9C%ED%94%8C%EB%A6%BF-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@minho-03/Flask-%ED%85%9C%ED%94%8C%EB%A6%BF-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 13 Feb 2026 08:44:31 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>Flask 템플릿 사용하기</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>지금까지는 Flask에서 문자열만 반환했다.
하지만 실제 웹 개발에서는 HTML 파일을 화면에 보여줘야 한다.
Flask에서는 템플릿 엔진으로 Jinja2를 사용한다.
HTML 파일을 templates 폴더에 저장하고,render_template() 함수를 통해 화면에 출력한다.</p>
<p>Flask 템플릿 사용 흐름은 다음과 같다.</p>
<ol>
<li>프로젝트 폴더 안에 templates 디렉토리 생성</li>
<li>HTML 파일 작성</li>
<li>render_template()로 HTML 반환
Flask는 기본적으로 templates 폴더를 자동으로 인식한다.</li>
</ol>
<p>기본 템플릿 구조
폴더 구조 예시</p>
<pre><code>project/
 ├── app.py
 └── templates/
      └── index.html</code></pre><p>index.html 예시</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;Home&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;Hello Flask&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>Flask 코드</p>
<pre><code>from flask import Flask, render_template

app = Flask(__name__)

@app.route(&quot;/&quot;)
def home():
    return render_template(&quot;index.html&quot;)

if __name__ == &quot;__main__&quot;:
    app.run(debug=True)</code></pre><p>이제 브라우저에 HTML 페이지가 출력된다.</p>
<p>템플릿에 변수 전달하기
Flask에서는 HTML에 값을 전달할 수 있다.</p>
<pre><code>@app.route(&quot;/user/&lt;name&gt;&quot;)
def user(name):
    return render_template(&quot;user.html&quot;, username=name)</code></pre><p>user.html</p>
<pre><code>&lt;h1&gt;Hello {{ username }}&lt;/h1&gt;</code></pre><p>{{ 변수명 }} 형태로 HTML 안에서 사용할 수 있다.</p>
<p>조건문과 반복문
Jinja2에서는 조건문과 반복문도 사용할 수 있다.
조건문</p>
<pre><code>{% if username %}
    &lt;h1&gt;Hello {{ username }}&lt;/h1&gt;
{% endif %}</code></pre><p>반복문</p>
<pre><code>&lt;ul&gt;
{% for item in items %}
    &lt;li&gt;{{ item }}&lt;/li&gt;
{% endfor %}
&lt;/ul&gt;</code></pre><h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>app.py</p>
<pre><code>from flask import Flask, render_template

app = Flask(__name__)

@app.route(&quot;/&quot;)
def home():
    return render_template(&quot;index.html&quot;, name=&quot;Minho&quot;)

if __name__ == &quot;__main__&quot;:
    app.run(debug=True)</code></pre><p>templates/index.html</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;body&gt;
    &lt;h1&gt;Hello {{ name }}&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<ul>
<li>왜 반드시 templates 폴더여야 하는지 처음에는 이해되지 않았다.</li>
<li>{{ }}와 {% %}의 차이도 헷갈렸다.</li>
</ul>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<ul>
<li>Flask에서는 render_template()로 HTML을 반환한다.</li>
<li>HTML 파일은 templates 폴더에 위치해야 한다.</li>
<li>{{ }}는 변수 출력, {% %}는 제어문이다.</li>
<li>이제 단순 문자열이 아닌 실제 웹 페이지를 만들 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Flask 라우팅 개념]]></title>
            <link>https://velog.io/@minho-03/Flask-%EB%9D%BC%EC%9A%B0%ED%8C%85-%EA%B0%9C%EB%85%90</link>
            <guid>https://velog.io/@minho-03/Flask-%EB%9D%BC%EC%9A%B0%ED%8C%85-%EA%B0%9C%EB%85%90</guid>
            <pubDate>Fri, 13 Feb 2026 08:38:14 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>Flask 라우팅 개념</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>라우팅(Routing)은 사용자가 특정 URL로 접속했을 때 어떤 함수가 실행될지 연결해주는 기능이다.
Flask에서는 @app.route() 데코레이터를 사용해 URL과 함수를 연결한다.</p>
<p>예를 들어,</p>
<ul>
<li>/ 로 접속하면 home 함수 실행</li>
<li>/about 로 접속하면 about 함수 실행
이처럼 URL 경로와 파이썬 함수가 매핑된다.</li>
</ul>
<p>기본 구조는 다음과 같다.</p>
<ul>
<li>@app.route(&quot;경로&quot;)</li>
<li>바로 아래에 실행할 함수 정의</li>
<li>함수에서 문자열이나 HTML 반환</li>
</ul>
<p>라우팅은 Flask의 가장 핵심적인 개념이다.
웹 서버는 결국 URL 요청을 받아 적절한 응답을 반환하는 구조이기 때문이다.</p>
<p>여러 개의 라우트 만들기
Flask에서는 여러 개의 URL을 쉽게 만들 수 있다.</p>
<pre><code>@app.route(&quot;/&quot;)
def home():
    return &quot;Home Page&quot;

@app.route(&quot;/about&quot;)
def about():
    return &quot;About Page&quot;</code></pre><p>각 URL마다 다른 함수가 실행된다.</p>
<p>동적 라우팅
URL에 값을 포함할 수도 있다.</p>
<pre><code>@app.route(&quot;/user/&lt;name&gt;&quot;)
def user(name):
    return f&quot;Hello {name}&quot;</code></pre><p>브라우저에서</p>
<pre><code>/user/minho</code></pre><p>로 접속하면</p>
<pre><code>Hello minho</code></pre><p>가 출력된다.
이처럼 URL에 포함된 값을 함수의 매개변수로 받을 수 있다.</p>
<p>타입 지정 라우팅
Flask는 URL 변수의 타입도 지정할 수 있다.</p>
<pre><code>@app.route(&quot;/post/&lt;int:id&gt;&quot;)
def post(id):
    return f&quot;Post number {id}&quot;</code></pre><p>여기서 <a href="int:id">int:id</a>는 id를 정수로 받겠다는 의미이다.</p>
<h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>여러 라우트 테스트 코드</p>
<pre><code>from flask import Flask

app = Flask(__name__)

@app.route(&quot;/&quot;)
def home():
    return &quot;Home&quot;

@app.route(&quot;/hello/&lt;name&gt;&quot;)
def hello(name):
    return f&quot;Hello {name}&quot;

@app.route(&quot;/number/&lt;int:num&gt;&quot;)
def number(num):
    return f&quot;Number is {num}&quot;

if __name__ == &quot;__main__&quot;:
    app.run(debug=True)</code></pre><h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<p>URL과 함수가 어떻게 연결되는지 처음에는 구조가 잘 이해되지 않았다.</p>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<ul>
<li>라우팅은 URL과 함수를 연결하는 기능이다.</li>
<li>@app.route()로 경로를 지정한다.</li>
<li>URL에 변수를 포함할 수 있다.</li>
<li>Flask의 핵심 구조는 요청과 응답의 연결이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Flask 기본 서버 실행]]></title>
            <link>https://velog.io/@minho-03/Flask-%EA%B8%B0%EB%B3%B8-%EC%84%9C%EB%B2%84-%EC%8B%A4%ED%96%89</link>
            <guid>https://velog.io/@minho-03/Flask-%EA%B8%B0%EB%B3%B8-%EC%84%9C%EB%B2%84-%EC%8B%A4%ED%96%89</guid>
            <pubDate>Fri, 13 Feb 2026 08:30:52 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>Flask 기본 서버 실행</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>Flask를 사용하려면 먼저 Flask 패키지를 설치해야 한다.
Flask는 Python 기반 프레임워크이기 때문에 pip를 통해 설치할 수 있다.</p>
<p>설치 과정은 다음과 같다.</p>
<ol>
<li>가상환경 생성 (선택이지만 권장)</li>
<li>Flask 설치</li>
<li>기본 서버 코드 작성</li>
<li>서버 실행</li>
</ol>
<p>Flask 서버는 기본적으로 127.0.0.1:5000 포트에서 실행된다.
개발 단계에서는 debug 모드를 사용하면 코드 수정 시 자동으로 서버가 재시작된다.</p>
<p>Flask의 기본 실행 구조는 다음과 같다.</p>
<ul>
<li>Flask 객체 생성</li>
<li>URL 라우팅 설정</li>
<li>함수에서 응답 반환</li>
<li>app.run()으로 서버 실행</li>
</ul>
<h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>Flask 설치</p>
<pre><code>pip install flask</code></pre><p>기본 서버 코드 (app.py)</p>
<pre><code>from flask import Flask

app = Flask(__name__)

@app.route(&quot;/&quot;)
def home():
    return &quot;Hello Flask&quot;

if __name__ == &quot;__main__&quot;:
    app.run(debug=True)</code></pre><p>서버 실행</p>
<pre><code>python app.py</code></pre><p>브라우저 접속</p>
<pre><code>http://127.0.0.1:5000</code></pre><h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<ul>
<li>app = Flask(name) 부분이 처음에는 이해되지 않았다.</li>
<li>debug=True 옵션이 정확히 무엇을 하는지도 헷갈렸다.</li>
<li>실행해보면서 서버가 자동으로 재시작되는 것을 보고 기능을 이해하게 되었다.</li>
</ul>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<ul>
<li>Flask는 pip로 설치할 수 있다.</li>
<li>기본 구조는 Flask 객체 생성 후 라우팅을 설정하는 방식이다.</li>
<li>app.run()으로 서버를 실행한다.</li>
<li>debug 모드는 개발 단계에서 유용하다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Flask란 무엇인가]]></title>
            <link>https://velog.io/@minho-03/Flask%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</link>
            <guid>https://velog.io/@minho-03/Flask%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</guid>
            <pubDate>Fri, 13 Feb 2026 06:53:20 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>Flask란 무엇인가</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>Flask는 Python 기반의 마이크로 웹 프레임워크이다.
웹 서버를 간단하게 구축할 수 있도록 도와주는 도구라고 이해하면 된다.</p>
<p>Flask는 “마이크로 프레임워크”라고 불리지만, 기능이 부족하다는 의미는 아니다.
기본 기능만 제공하고, 필요한 기능은 개발자가 직접 추가하는 구조라는 뜻이다.</p>
<p>Flask의 특징은 다음과 같다.</p>
<ul>
<li>구조가 단순하다</li>
<li>학습 난이도가 비교적 낮다</li>
<li>Python 문법을 그대로 활용할 수 있다</li>
<li>확장성이 좋다</li>
</ul>
<p>Flask를 사용하면 웹 페이지를 만들거나, API 서버를 구축하거나, 간단한 백엔드 서버를 구현할 수 있다.
지금까지 배운 Python 문법과 Linux 환경을 실제 서버 형태로 연결해볼 수 있는 단계가 바로 Flask라고 생각한다.</p>
<h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>가장 기본적인 Flask 서버 코드이다.</p>
<pre><code>from flask import Flask

app = Flask(__name__)

@app.route(&quot;/&quot;)
def home():
    return &quot;Hello, Flask!&quot;

if __name__ == &quot;__main__&quot;:
    app.run(debug=True)</code></pre><p>위 코드를 실행한 후 브라우저에서 아래 주소로 접속하면 문자열이 출력된다.</p>
<pre><code>http://127.0.0.1:5000</code></pre><h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<ul>
<li>프레임워크와 라이브러리의 차이가 처음에는 헷갈렸다.</li>
<li>마이크로 프레임워크라는 표현이 기능이 적다는 의미처럼 느껴졌지만, 실제로는 구조가 단순하다는 의미라는 점을 이해했다.</li>
</ul>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<ul>
<li>Flask는 Python 기반 웹 프레임워크이다.</li>
<li>구조가 단순하고 확장성이 좋다.</li>
<li>웹 서버를 빠르게 구현할 수 있다.</li>
<li>Python과 Linux 학습을 실제 서버 개발로 연결하는 단계이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Linux(Ubuntu) 기초 학습을 마치며...]]></title>
            <link>https://velog.io/@minho-03/LinuxUbuntu-%EA%B8%B0%EC%B4%88-%ED%95%99%EC%8A%B5%EC%9D%84-%EB%A7%88%EC%B9%98%EB%A9%B0</link>
            <guid>https://velog.io/@minho-03/LinuxUbuntu-%EA%B8%B0%EC%B4%88-%ED%95%99%EC%8A%B5%EC%9D%84-%EB%A7%88%EC%B9%98%EB%A9%B0</guid>
            <pubDate>Fri, 13 Feb 2026 06:42:55 GMT</pubDate>
            <description><![CDATA[<p>&lt;Linux(Ubuntu) 기초 학습을 마치며&gt;
Linux는 서버 환경에서 많이 사용되는 운영체제라 개발을 계속하려면 반드시 익숙해져야 한다고 생각해서 기초 학습을 시작했다.
처음에는 명령어가 많고 터미널 환경이 익숙하지 않아 어렵게 느껴졌지만, 하나씩 정리하면서 구조가 보이기 시작했다.
파일 관리, 권한, 사용자, 프로세스, 네트워크, 서비스까지 단계적으로 정리하면서 Linux가 단순한 명령어 모음이 아니라 운영체제의 동작 원리를 이해하는 과정이라는 걸 느꼈다.
특히 systemctl, 로그 확인, 권한 개념을 배우면서 서버가 어떻게 돌아가는지 조금은 감이 잡히기 시작했다.</p>
<p>&lt;느낀 점&gt;
Linux는 GUI보다 터미널 중심으로 사용하다 보니
처음에는 불편하게 느껴졌지만, 명령어에 익숙해질수록 오히려 더 빠르고 명확하다는 생각이 들었다.
명령어를 외우는 것보다 “이 상황에서 어떤 개념을 써야 하는지”를 이해하는 게 더 중요하다고 느꼈다.
아직 실습 경험은 많지 않지만, 기초 개념을 정리해둔 것이 앞으로 서버나 클라우드 공부에 큰 도움이 될 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Linux 압축 명령어]]></title>
            <link>https://velog.io/@minho-03/Linux-%EC%95%95%EC%B6%95-%EB%AA%85%EB%A0%B9%EC%96%B4</link>
            <guid>https://velog.io/@minho-03/Linux-%EC%95%95%EC%B6%95-%EB%AA%85%EB%A0%B9%EC%96%B4</guid>
            <pubDate>Tue, 10 Feb 2026 08:51:20 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>Linux 압축 명령어</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>Linux에서는 여러 파일이나 디렉토리를 하나로 묶거나(아카이브), 용량을 줄이기 위해 압축하는 명령어를 사용한다. 서버 파일 백업, 로그 전달, 프로젝트 배포 시 매우 자주 사용된다.</p>
<p>Linux에서 압축은 보통 두 단계로 이루어진다.</p>
<ul>
<li>파일을 하나로 묶기(archive)</li>
<li>묶인 파일을 압축하기(compress)
이 역할을 가장 많이 담당하는 명령어가 tar이다.</li>
</ul>
<p>tar (Tape Archive)
여러 파일과 디렉토리를 하나의 파일로 묶는 명령어다.
압축 옵션을 함께 사용하면 압축까지 동시에 수행할 수 있다.
기본 형식:</p>
<pre><code>tar 옵션 파일명 대상</code></pre><p>자주 사용하는 옵션:
c : 생성(create)
x : 해제(extract)
v : 과정 출력(verbose)
f : 파일 지정(file)
z : gzip 압축
j : bzip2 압축</p>
<p>tar로 압축하기 (gzip)
디렉토리를 .tar.gz 형식으로 압축</p>
<pre><code>tar -cvzf test.tar.gz test/</code></pre><p>c : 생성
v : 진행 과정 출력
z : gzip 압축
f : 파일명 지정</p>
<p>tar 압축 해제
압축 파일 해제</p>
<pre><code>tar -xvzf test.tar.gz</code></pre><p>gzip / gunzip
단일 파일을 압축하거나 해제할 때 사용한다.
파일 압축:</p>
<pre><code>gzip file.txt</code></pre><p>파일 해제:</p>
<pre><code>gunzip file.txt.gz</code></pre><p>디렉토리는 gzip으로 직접 압축 불가
보통 tar와 함께 사용</p>
<p>zip / unzip
Windows와 호환성이 좋은 압축 방식이다.
압축:</p>
<pre><code>zip test.zip file.txt</code></pre><p>디렉토리 압축:</p>
<pre><code>zip -r test.zip test/</code></pre><p>해제:</p>
<pre><code>unzip test.zip</code></pre><h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>디렉토리 생성 후 압축 / 해제</p>
<pre><code> mkdir sample
 touch sample/a.txt sample/b.txt
 tar -cvzf sample.tar.gz sample/
 tar -xvzf sample.tar.gz
</code></pre><p>zip 방식 사용</p>
<pre><code>zip -r sample.zip sample/
 unzip sample.zip</code></pre><h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<ul>
<li>tar는 압축 명령어라고만 알고 있었는데,</li>
<li>실제로는 파일을 묶는 역할이 핵심이라는 점이 헷갈렸다.</li>
<li>옵션 순서와 의미를 처음에는 외우기 어려웠다.</li>
</ul>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<ul>
<li>Linux에서는 tar를 가장 많이 사용한다.</li>
<li>tar는 파일을 묶고 옵션으로 압축을 수행한다.</li>
<li>gzip은 단일 파일 압축에 사용된다.</li>
<li>zip은 다른 운영체제와 파일 공유 시 유용하다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Linux 환경 변수]]></title>
            <link>https://velog.io/@minho-03/Linux-%ED%99%98%EA%B2%BD-%EB%B3%80%EC%88%98</link>
            <guid>https://velog.io/@minho-03/Linux-%ED%99%98%EA%B2%BD-%EB%B3%80%EC%88%98</guid>
            <pubDate>Tue, 10 Feb 2026 08:42:01 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>Linux 환경 변수</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>Linux에서 환경 변수(Environment Variale) 는 시스템이나 프로그램이 동작할 때 참고하는 설정 값이다.
경로, 언어, 사용자 정보 등 실행 환경에 필요한 정보들을 담고 있다.</p>
<p>환경 변수의 특징은 다음과 같다.</p>
<ul>
<li>문자열 형태의 키=값 구조</li>
<li>쉘(Shell)에서 관리됨</li>
<li>프로그램 실행 시 자동으로 참조됨</li>
<li>사용자별 / 시스템 전체 적용 가능
대표적인 환경 변수에는 PATH, HOME, USER 등이 있다.</li>
</ul>
<p>PATH 환경 변수
PATH는 명령어 실행 파일을 찾는 경로 목록이다.
터미널에서 ls 같은 명령어를 입력했을 때 시스템은 PATH에 등록된 디렉토리를 순서대로 탐색한다.</p>
<pre><code>echo $PATH</code></pre><p>여러 경로가 :로 구분되어 있음
PATH에 없는 경로의 명령어는 전체 경로로 실행해야 함</p>
<p>환경 변수 확인
현재 설정된 환경 변수를 확인하는 방법은 다음과 같다.</p>
<pre><code>env</code></pre><pre><code>printenv</code></pre><p>특정 변수만 확인:</p>
<pre><code>echo $HOME</code></pre><p>환경 변수 설정 (임시)
현재 터미널 세션에서만 적용되는 환경 변수 설정이다.</p>
<pre><code>export TEST_VAR=hello</code></pre><p>확인:</p>
<pre><code>echo $TEST_VAR</code></pre><p>터미널을 닫으면 설정은 사라짐</p>
<p>환경 변수 설정 (영구)
로그인할 때마다 적용되도록 설정하려면 쉘 설정 파일에 추가해야 한다.</p>
<p>주로 사용하는 파일:</p>
<ul>
<li>~/.bashrc : 사용자 쉘 설정</li>
<li>~/.profile : 로그인 시 적용</li>
<li>/etc/environment : 시스템 전체 적용
예시 (~/.bashrc):<pre><code>export JAVA_HOME=/usr/lib/jvm/java-17-openjdk</code></pre>변경 사항 즉시 적용:<pre><code>source ~/.bashrc</code></pre></li>
</ul>
<p>환경 변수 사용 예
프로그램 실행 시 환경 변수를 활용할 수 있다.</p>
<pre><code>MY_VAR=test ./run.sh</code></pre><p>또는 스크립트 내부에서:</p>
<pre><code>echo $MY_VAR</code></pre><h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>환경 변수 확인 및 설정 흐름</p>
<pre><code>echo $PATH
export MY_TEST=linux
echo $MY_TEST</code></pre><p>영구 설정 후 적용</p>
<pre><code>nano ~/.bashrc
source ~/.bashrc</code></pre><h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<ul>
<li>임시 설정과 영구 설정의 차이가 헷갈렸다.</li>
<li>export로 설정한 값은 현재 세션에만 적용되고,</li>
<li>~/.bashrc에 추가해야 로그인 후에도 유지된다는 점을 정리했다.</li>
<li>PATH가 단일 경로가 아니라 여러 경로의 집합이라는 점도 처음엔 헷갈렸다.</li>
</ul>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<ul>
<li>환경 변수는 프로그램 실행 환경을 정의하는 값이다.</li>
<li>PATH는 명령어 탐색 경로를 관리한다.</li>
<li>export는 임시 설정이다.</li>
<li>영구 설정은 ~/.bashrc 등을 사용한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Linux 로그 파일과 위치]]></title>
            <link>https://velog.io/@minho-03/Linux-%EB%A1%9C%EA%B7%B8-%ED%8C%8C%EC%9D%BC%EA%B3%BC-%EC%9C%84%EC%B9%98</link>
            <guid>https://velog.io/@minho-03/Linux-%EB%A1%9C%EA%B7%B8-%ED%8C%8C%EC%9D%BC%EA%B3%BC-%EC%9C%84%EC%B9%98</guid>
            <pubDate>Tue, 10 Feb 2026 08:36:42 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>Linux 로그 파일과 위치</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>Linux에서 로그(Log) 는 시스템과 서비스에서 발생한 동작 기록과 오류 정보를 의미한다.
서버 운영이나 문제 해결 시 로그 확인은 가장 기본적이면서도 중요한 작업이다. 
Linux 로그 파일은 보통 /var/log 디렉토리 아래에 저장된다.
각 로그 파일은 시스템, 서비스, 보안 등 목적에 따라 나뉘어 관리된다.</p>
<p>로그를 통해 다음과 같은 정보를 확인할 수 있다.</p>
<ul>
<li>시스템 부팅 및 종료 기록</li>
<li>서비스 실행 및 오류 기록</li>
<li>사용자 로그인 기록</li>
<li>보안 관련 이벤트</li>
</ul>
<p>/var/log 디렉토리
Linux 로그 파일의 중심 디렉토리다.</p>
<pre><code>ls /var/log</code></pre><p>이 안에 다양한 로그 파일과 디렉토리가 존재한다.</p>
<p>주요 로그 파일</p>
<ul>
<li><p>/var/log/syslog
시스템 전반적인 로그
서비스 실행, 시스템 이벤트 기록</p>
</li>
<li><p>/var/log/auth.log
로그인, sudo 사용 기록
보안 관련 로그</p>
</li>
<li><p>/var/log/kern.log
커널 관련 메시지
하드웨어, 드라이버 관련 로그</p>
</li>
<li><p>/var/log/dmesg
부팅 시 커널 메시지
하드웨어 인식 정보</p>
</li>
<li><p>/var/log/apache2/
웹 서버(Apache) 로그
접근 로그, 에러 로그</p>
</li>
</ul>
<p>journalctl
Ubuntu(systemd) 환경에서는 로그를 journal 이라는 형태로 관리한다.
이를 확인하는 명령어가 journalctl이다.</p>
<pre><code>journalctl</code></pre><p>최근 로그만 확인:</p>
<pre><code>journalctl -n 20</code></pre><p>특정 서비스 로그 확인:</p>
<pre><code>journalctl -u ssh</code></pre><p>부팅 로그 확인:</p>
<pre><code>journalctl -b</code></pre><p>로그 확인 시 주의점
로그 파일은 지속적으로 커지기 때문에 파일이 매우 클 수 있다.
그래서 보통 less, tail 같은 명령어와 함께 사용한다.</p>
<pre><code>less /var/log/syslog</code></pre><pre><code>tail -f /var/log/syslog</code></pre><h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>최근 시스템 로그 확인</p>
<pre><code>journalctl -n 10</code></pre><p>로그 파일 위치 확인</p>
<pre><code>ls /var/log</code></pre><p>실시간 로그 확인</p>
<pre><code>tail -f /var/log/syslog</code></pre><h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<p>로그 파일이 하나만 있는 줄 알았지만, 실제로는 목적별로 여러 로그 파일이 나뉘어 있다는 점이 헷갈렸다. 또한 journalctl과 /var/log 파일의 관계가 처음에는 이해하기 어려웠다.</p>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<ul>
<li>로그는 시스템과 서비스 동작 기록이다.</li>
<li>대부분의 로그는 /var/log 아래에 저장된다.</li>
<li>journalctl로 systemd 로그를 확인할 수 있다.</li>
<li>문제 발생 시 로그 확인이 가장 중요하다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Linux systemctl 기본 사용법]]></title>
            <link>https://velog.io/@minho-03/Linux-systemctl-%EA%B8%B0%EB%B3%B8-%EC%82%AC%EC%9A%A9%EB%B2%95</link>
            <guid>https://velog.io/@minho-03/Linux-systemctl-%EA%B8%B0%EB%B3%B8-%EC%82%AC%EC%9A%A9%EB%B2%95</guid>
            <pubDate>Tue, 10 Feb 2026 08:31:12 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>systemctl 기본 사용법</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>systemctl은 systemd 기반 Linux에서 서비스(데몬)를 관리하는 핵심 명령어다.
서비스의 상태 확인, 시작/중지, 재시작, 부팅 시 자동 실행 설정 등을 수행한다.</p>
<p>Ubuntu를 포함한 현대 Linux에서는 서비스 관리를 systemctl로 통합해서 처리한다.</p>
<p>주요 사용 목적은 다음과 같다.</p>
<ul>
<li>서비스 상태 확인</li>
<li>서비스 시작/중지/재시작</li>
<li>부팅 시 자동 실행 설정</li>
<li>실행 실패 원인 확인</li>
</ul>
<p>서비스 상태 확인
특정 서비스의 현재 상태를 확인한다.</p>
<pre><code>systemctl status 서비스명</code></pre><p>예시:</p>
<pre><code>systemctl status ssh</code></pre><ul>
<li>실행 중(active)</li>
<li>중지(inactive)</li>
<li>실패(failed) 상태 확인 가능</li>
<li>최근 로그 일부도 함께 표시됨</li>
</ul>
<p>서비스 시작 / 중지
서비스를 직접 제어한다.</p>
<pre><code>sudo systemctl start 서비스명</code></pre><pre><code>sudo systemctl stop 서비스명</code></pre><p>예시:</p>
<pre><code>sudo systemctl start nginx
sudo systemctl stop nginx</code></pre><p>서비스 재시작 / 재로딩
설정 변경 후 서비스 반영 시 사용한다.</p>
<pre><code>sudo systemctl restart 서비스명</code></pre><pre><code>sudo systemctl reload 서비스명</code></pre><p>restart : 완전히 재시작
reload : 설정만 다시 로드 (지원하는 서비스만 가능)</p>
<p>부팅 시 자동 실행 설정
시스템 부팅 시 서비스 자동 실행 여부를 설정한다.</p>
<pre><code>sudo systemctl enable 서비스명</code></pre><pre><code>sudo systemctl disable 서비스명</code></pre><p>예시:</p>
<pre><code>sudo systemctl enable ssh
sudo systemctl disable ssh</code></pre><p>서비스 목록 확인
현재 실행 중인 서비스 목록 확인</p>
<pre><code>systemctl list-units --type=service</code></pre><p>설치된 모든 서비스 확인</p>
<pre><code>systemctl list-unit-files --type=service</code></pre><h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>SSH 서비스 상태 확인 후 자동 실행 설정</p>
<pre><code>systemctl status ssh
sudo systemctl enable ssh</code></pre><p>웹 서버 재시작</p>
<pre><code>sudo systemctl restart apache2</code></pre><h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<ul>
<li>start와 enable의 차이가 헷갈렸다.</li>
<li>start는 지금 당장 실행,</li>
<li>enable은 부팅 시 자동 실행 설정이라는 점을 정리했다.</li>
<li>restart와 reload의 차이도 처음에는 혼동되었다.</li>
</ul>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<ul>
<li>systemctl은 서비스를 관리하는 핵심 명령어이다.</li>
<li>서비스 상태 확인, 시작, 중지, 재시작이 가능하다.</li>
<li>enable은 부팅 시 자동 실행 설정이다.</li>
<li>Ubuntu 서비스 관리는 systemctl 중심으로 이루어진다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Linux 서비스 개념]]></title>
            <link>https://velog.io/@minho-03/Linux-%EC%84%9C%EB%B9%84%EC%8A%A4-%EA%B0%9C%EB%85%90</link>
            <guid>https://velog.io/@minho-03/Linux-%EC%84%9C%EB%B9%84%EC%8A%A4-%EA%B0%9C%EB%85%90</guid>
            <pubDate>Tue, 10 Feb 2026 08:20:41 GMT</pubDate>
            <description><![CDATA[<h2 id="공부-주제">&lt;공부 주제&gt;</h2>
<p>Linux 서비스 개념</p>
<h2 id="공부한-내용-정리">&lt;공부한 내용 정리&gt;</h2>
<p>Linux에서 서비스(Service) 는 시스템이 부팅된 이후 백그라운드에서 계속 실행되는 프로그램을 의미한다.
웹 서버, 데이터베이스 서버처럼 항상 실행되어 있어야 하는 프로그램들이 서비스 형태로 동작한다.</p>
<p>서비스는 사용자가 직접 실행하지 않아도 시스템이 자동으로 시작하거나 관리할 수 있도록 설계되어 있다.</p>
<p>Linux 서비스의 핵심 특징은 다음과 같다.</p>
<ul>
<li>백그라운드에서 실행됨</li>
<li>시스템 부팅 시 자동 실행 가능</li>
<li>사용자의 로그인 여부와 무관하게 동작</li>
<li>서버 환경에서 필수적인 개념</li>
</ul>
<p>데몬(Daemon)
Linux 서비스는 보통 데몬(Daemon) 형태로 실행된다.
데몬은 백그라운드에서 동작하는 프로세스로, 이름 끝에 d가 붙는 경우가 많다.</p>
<p>예:
sshd : SSH 서비스
httpd : 웹 서버
cron : 작업 스케줄러</p>
<ul>
<li>서비스 = 데몬이라고 이해해도 무방하다.</li>
</ul>
<p>서비스가 필요한 이유
서비스는 다음과 같은 상황에서 필요하다.</p>
<ul>
<li>웹 서버가 항상 요청을 받을 수 있도록 하기 위해</li>
<li>네트워크 연결을 지속적으로 유지하기 위해</li>
<li>시스템 작업을 자동으로 처리하기 위해</li>
</ul>
<p>즉, “항상 켜져 있어야 하는 프로그램” 이 서비스다.</p>
<p>systemd
현대 Linux 시스템(Ubuntu 포함)에서는 systemd 가 서비스 관리를 담당한다.</p>
<p>systemd는
서비스 시작 / 중지, 부팅 시 자동 실행 설정, 서비스 상태 확인 등을 관리하는 시스템이다.</p>
<h2 id="예제--실습-코드">&lt;예제 / 실습 코드&gt;</h2>
<p>현재 실행 중인 서비스 목록 확인</p>
<pre><code>systemctl list-units --type=service</code></pre><p>특정 서비스 상태 확인</p>
<pre><code>systemctl status ssh</code></pre><h2 id="헷갈렸던-점">&lt;헷갈렸던 점&gt;</h2>
<ul>
<li>서비스와 일반 프로그램의 차이가 처음에는 헷갈렸다.</li>
<li>하지만 서비스는 항상 실행되며, 사용자의 직접 실행 없이 시스템에서 관리된다는 점을 정리했다.</li>
<li>서비스와 데몬이라는 용어가 혼용되어 사용된다는 점도 헷갈렸다.</li>
</ul>
<h2 id="오늘의-정리">&lt;오늘의 정리&gt;</h2>
<ul>
<li>서비스는 백그라운드에서 실행되는 프로그램이다.</li>
<li>데몬 형태로 동작하는 경우가 많다.</li>
<li>서버 환경에서는 서비스 개념이 매우 중요하다.</li>
<li>systemd가 서비스를 관리한다.</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>