<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>{n_u}.log</title>
        <link>https://velog.io/</link>
        <description>🧑🏻‍💻 Hello World!</description>
        <lastBuildDate>Tue, 09 Jan 2024 14:09:39 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>{n_u}.log</title>
            <url>https://velog.velcdn.com/images/iseon_u/profile/84708b02-44b3-458b-8db3-b6330e44baa4/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. {n_u}.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/iseon_u" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Oracle RAC 환경 2VIP 세팅 값 공유]]></title>
            <link>https://velog.io/@iseon_u/Oracle-RAC-%ED%99%98%EA%B2%BD-2VIP-%EC%84%B8%ED%8C%85-%EA%B0%92-%EA%B3%B5%EC%9C%A0</link>
            <guid>https://velog.io/@iseon_u/Oracle-RAC-%ED%99%98%EA%B2%BD-2VIP-%EC%84%B8%ED%8C%85-%EA%B0%92-%EA%B3%B5%EC%9C%A0</guid>
            <pubDate>Tue, 09 Jan 2024 14:09:39 GMT</pubDate>
            <description><![CDATA[<h2 id="oracle-rac-환경-2vip-jdbc-url">Oracle RAC 환경 2VIP JDBC URL</h2>
<blockquote>
<p>2023년 10월 24일 테스트 후 접속 성공 확인</p>
</blockquote>
<pre><code>jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(FAILOVER=ON)(LOAD_BALANCE=ON)(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.0.1)(PORT=3382))
(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.0.2)(PORT=3382)))(CONNECT_DATA=(SERVICE_NAME=SERVICE_NAME입력)))</code></pre><ul>
<li>구글링해도 저마다 세팅 순서가 다르기에 저도 소신껏 접속 성공한 jdbc URL 공유합니다.<h2 id="대표-오류-메시지">대표 오류 메시지</h2>
<pre><code>SQLRecoverableException : IO 오류 : SO Exception was generated 
</code></pre></li>
</ul>
<p>java.sql.SQLRecoverableException: IO Error: SO Exception was generated 
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로세스의 이해]]></title>
            <link>https://velog.io/@iseon_u/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%9D%98-%EC%9D%B4%ED%95%B4</link>
            <guid>https://velog.io/@iseon_u/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%9D%98-%EC%9D%B4%ED%95%B4</guid>
            <pubDate>Sun, 23 Jul 2023 08:51:51 GMT</pubDate>
            <description><![CDATA[<h1 id="프로세스의-이해">프로세스의 이해</h1>
<hr>
<h2 id="process">Process</h2>
<ul>
<li>실행 중인 프로그램</li>
<li>운영체제 작업의 단위</li>
<li>운영체제가 해야할 가장 기본적인 것<ul>
<li>프로세스 관리</li>
</ul>
</li>
</ul>
<h2 id="프로세스의-메모리-레이아웃-세션">프로세스의 메모리 레이아웃 세션</h2>
<ul>
<li>텍스트 세션<ul>
<li>명령어 코드</li>
</ul>
</li>
<li>데이터 세션<ul>
<li>전역 변수</li>
</ul>
</li>
<li>힙 영역 세션<ul>
<li>메모리 관련</li>
<li>new 키워드</li>
</ul>
</li>
<li>스택 영역 세션<ul>
<li>함수<ul>
<li>함수 파라미터</li>
<li>반환 주소</li>
<li>지역 변수</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="프로세스의-생명주기">프로세스의 생명주기</h2>
<ul>
<li>New<ul>
<li>프로세스가 생성된 상태</li>
</ul>
</li>
<li>Running<ul>
<li>CPU를 점유하여 프로세스의 명령어를 CPU에 로드 하여 실행하는 상태</li>
</ul>
</li>
<li>Waiting<ul>
<li>프로세스가 이벤트를 기다리는 상태</li>
<li>I/O 대기</li>
</ul>
</li>
<li>Ready<ul>
<li>점유 큐에 올라가 CPU 점유를 대기하는 상태</li>
</ul>
</li>
<li>Terminated<ul>
<li>모든 작업을 끝낸 상태</li>
</ul>
</li>
</ul>
<h2 id="pcb-process-control-block">PCB Process Control Block</h2>
<p>TCB Task Control Block</p>
<ul>
<li>프로세스 관리 구조체</li>
<li>각 프로세스가 가져야 할 정보를 PCB에 저장</li>
<li>PCB를 통해 운영체제는 프로세스 관리</li>
<li>PCB 정보<ul>
<li>프로세스 상태 (New, Running, Waiting, Ready, Terminated)</li>
<li>프로그램 카운터<ul>
<li>IR을 통해 메모리에서 명령어를 가져올 때 주소</li>
</ul>
</li>
<li>CPU registers<ul>
<li>IR Instruction Register, DR Data Register</li>
</ul>
</li>
<li>CPU-scheduling 정보</li>
<li>Memory-management 정보</li>
<li>계정 정보</li>
<li>I/O 상태 정보</li>
</ul>
</li>
</ul>
<h2 id="프로세스">프로세스</h2>
<ul>
<li>싱글 쓰레드의 실행</li>
<li>OS의 주요 기능<ul>
<li>멀티 태스킹, 멀티 프로세싱</li>
</ul>
</li>
<li>멀티 쓰레딩<ul>
<li>프로세스 여러 개보단 쓰레드 여러 개가 장점이 많다</li>
</ul>
</li>
</ul>
<h2 id="컨텍스트-스위치">컨텍스트 스위치</h2>
<ul>
<li>컨텍스트<ul>
<li>프로세스가 사용되고 있는 상태</li>
<li>PCB 정보</li>
</ul>
</li>
<li>CPU 코어를 다른 프로세스에 넘겨주는 것<ul>
<li>현재 프로세스의 상태를 저장</li>
<li>새로운 프로세스의 상태를 보관</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[운영체제의 개념과 구조]]></title>
            <link>https://velog.io/@iseon_u/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@iseon_u/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Sun, 23 Jul 2023 08:47:46 GMT</pubDate>
            <description><![CDATA[<h1 id="운영체제의-개념과-구조">운영체제의 개념과 구조</h1>
<hr>
<h2 id="kernel-커널">Kernel 커널</h2>
<ul>
<li>OS의 핵심</li>
</ul>
<h2 id="전통적인-컴퓨터-시스템-구조">전통적인 컴퓨터 시스템 구조</h2>
<ul>
<li>단일 또는 여러 개의 CPU</li>
<li>bus로 연결되어 있는 여러 개의 디바이스 컨트롤러</li>
</ul>
<h2 id="bootstrap-프로그램">Bootstrap 프로그램</h2>
<ul>
<li>컴퓨터 실행 시 가장 먼저 실행되는 프로그램</li>
<li>OS를 로드 해주는 역할</li>
</ul>
<h2 id="interrupts">Interrupts</h2>
<ul>
<li>CPU와 I/O 디바이스끼리 통신하는 방식</li>
</ul>
<h2 id="폰-노이만-아키텍쳐">폰 노이만 아키텍쳐</h2>
<ul>
<li>명령어 집합 (Instruction set)</li>
<li>메모리에 로딩</li>
<li>메모리에 있는 명령어를 CPU가 하나씩 fetch &amp; execute</li>
<li>IR Instruction Register<ul>
<li>IR을 통해 명령어를 가져온다</li>
</ul>
</li>
</ul>
<h2 id="storage-system">Storage System</h2>
<ul>
<li>여러 가지 계층 구조로 구성<ul>
<li>용량</li>
<li>접근 속도</li>
</ul>
</li>
</ul>
<ol>
<li>registers<ul>
<li>CPU안 회로로 구성</li>
</ul>
</li>
<li>cache<ol>
<li>regiser와 RAM 사이 캐싱</li>
</ol>
</li>
<li>main memory<ul>
<li>RAM</li>
</ul>
</li>
<li>solid-state disk<ul>
<li>SSD</li>
<li>memory 기반 저장장치</li>
</ul>
</li>
<li>hard disk<ul>
<li>HDD</li>
<li>마그네틱 기반 저장장치</li>
</ul>
</li>
<li>optical disk<ul>
<li>광학 디스크</li>
</ul>
</li>
<li>magentic tapes<ul>
<li>금융권 백업 용</li>
</ul>
</li>
</ol>
<h2 id="symmetric-multiprocessing-smp">Symmetric multiprocessing (SMP)</h2>
<ul>
<li>멀티 CPU</li>
<li>여러 개의 CPU가 각각의 registers와 cache를 가지고 memory에 붙는다</li>
</ul>
<h2 id="multi-core-design">Multi-core design</h2>
<ul>
<li>같은 프로세스 칩 안에  여러 개의 코어</li>
</ul>
<h2 id="multiprogramming">Multiprogramming</h2>
<ul>
<li>기존은 메모리에 하나의 프로그램만 실행</li>
<li>여러 개의 프로그램을 동시에 메모리에 올려두고 동시에 실행</li>
<li>CPU 사용 효율을 높인다</li>
</ul>
<h2 id="multitasking--multiprocessing">Multitasking = Multiprocessing</h2>
<ul>
<li>하나의 CPU가 실행 속도가 빠를 때</li>
<li>여러 개의 작업을 빠르게 전환하면 사용자는 동시에 사용 가능</li>
<li>concurrency, parallelism</li>
<li>CPU scheduling<ul>
<li>RAM에 여러가지 프로그램이 존재할 때 프로그램 실행 순서를 지정</li>
<li>목표 CPU 효율을 가장 좋게 만드는 선택 방법</li>
</ul>
</li>
</ul>
<h2 id="operation-mode">Operation Mode</h2>
<ul>
<li>User mode</li>
<li>Kernel mode</li>
<li>커널 모드만 직접적으로 H/W 접근을 허용하여 잘못된 사용 방지</li>
</ul>
<h2 id="virtualization">Virtualization</h2>
<ul>
<li>가상화 기술</li>
<li>process 처럼 여러 개의 OS를 가동</li>
<li>VMM Virtual Machine Manager<ul>
<li>VMware, XEN, WSL</li>
<li>OS scheduling</li>
</ul>
</li>
</ul>
<table>
<thead>
<tr>
<th>기존</th>
<th>가상화</th>
<th>가상화</th>
</tr>
</thead>
<tbody><tr>
<td>processes</td>
<td>processes</td>
<td>processes</td>
</tr>
<tr>
<td>kernel</td>
<td>kernel</td>
<td>kernel</td>
</tr>
<tr>
<td></td>
<td>VM1 (LINUX)</td>
<td>VM2 (MAC OS)</td>
</tr>
<tr>
<td></td>
<td>virtual machine manager</td>
<td>virtual machine manager</td>
</tr>
<tr>
<td>hardware</td>
<td>hardware</td>
<td>hardware</td>
</tr>
</tbody></table>
<h2 id="컴퓨팅-환경">컴퓨팅 환경</h2>
<ul>
<li>기본 컴퓨팅</li>
<li>모바일 컴퓨팅</li>
<li>클라이언트 - 서버 컴퓨팅</li>
<li>Peer-to-Peer P2P 컴퓨팅</li>
<li>Cloud 컴퓨팅</li>
<li>Real-Time Embedded Systems</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[운영체제란?]]></title>
            <link>https://velog.io/@iseon_u/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EB%9E%80</link>
            <guid>https://velog.io/@iseon_u/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EB%9E%80</guid>
            <pubDate>Sun, 23 Jul 2023 08:44:48 GMT</pubDate>
            <description><![CDATA[<h1 id="운영체제란">운영체제란?</h1>
<hr>
<h2 id="컴퓨터의-정보-처리-방식">컴퓨터의 정보 처리 방식</h2>
<ul>
<li>정보의 최소 단위<ul>
<li>bit binary digit</li>
</ul>
</li>
<li>정보의 처리<ul>
<li>정보의 상태 변환</li>
<li>0 → 1, 1 → 0</li>
</ul>
</li>
<li>부울 대수 Boolean Algebra<ul>
<li>NOT, AND, OR</li>
<li>트랜지스터</li>
</ul>
</li>
<li>논리 게이트<ul>
<li>NOT, AND, OR, XOR, NAND, NOR</li>
</ul>
</li>
<li>논리 회로<ul>
<li>IC, LSI, VLSI, ULSI, SoC</li>
</ul>
</li>
<li>정보의 저장과 전송<ul>
<li>플립-플롭, 데이터 버스, RF 무선</li>
</ul>
</li>
</ul>
<h2 id="사칙연산">사칙연산</h2>
<ul>
<li>덧셈<ul>
<li>반가산기, 전가산기</li>
</ul>
</li>
<li>뺄셈<ul>
<li>2의 보수 표현법</li>
</ul>
</li>
<li>곱셈 나눗셈<ul>
<li>덧셈과 뺄셈의 반복</li>
</ul>
</li>
</ul>
<h2 id="범용성-universality">범용성 Universality</h2>
<ul>
<li>NOT, AND, OR 게이트만으로 모든 계산 가능</li>
<li>NAND 게이트만으로 모든 계산 가능</li>
</ul>
<h2 id="계산-가능성-computability">계산 가능성 Computability</h2>
<ul>
<li>Turing-computable<ul>
<li>튜링 머신으로 계산 가능한 것</li>
</ul>
</li>
<li>정지 문제 Halting Problem<ul>
<li>튜링 머신으로 풀 수 없는 문제</li>
</ul>
</li>
</ul>
<h2 id="튜링-머신과-현재-컴퓨터-구조">튜링 머신과 현재 컴퓨터 구조</h2>
<table>
<thead>
<tr>
<th>튜링머신</th>
<th>응용프로그램</th>
</tr>
</thead>
<tbody><tr>
<td>유니버셜 튜링 머신</td>
<td>운영체제</td>
</tr>
<tr>
<td>헤드</td>
<td>CPU</td>
</tr>
<tr>
<td>테이프</td>
<td>메모리</td>
</tr>
</tbody></table>
<h2 id="프로그램">프로그램</h2>
<ul>
<li>명령어들의 집합</li>
<li>코드 → 컴파일 → 어셈블리어 → 기계어 (0, 1)</li>
</ul>
<h2 id="운영체제">운영체제</h2>
<ul>
<li>컴퓨터에서 항상 실행되는 프로그램</li>
<li>어플리케이션 프로그램 대신 시스템 서비스 (H/W)에 접근</li>
<li>프로세스 관리</li>
<li>컴퓨터 시스템을 운영하는 소프트웨어 (H/W ↔ OS ↔ APP ↔ USER)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[STS 단축키 정리]]></title>
            <link>https://velog.io/@iseon_u/STS-%EB%8B%A8%EC%B6%95%ED%82%A4-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@iseon_u/STS-%EB%8B%A8%EC%B6%95%ED%82%A4-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Thu, 22 Jun 2023 11:50:26 GMT</pubDate>
            <description><![CDATA[<h1 id="sts-단축키-정리-windows">STS 단축키 정리 (Windows)</h1>
<hr>
<h2 id="소스-코드-편집">소스 코드 편집</h2>
<h3 id="ctrl--space"><code>Ctrl + Space</code></h3>
<ul>
<li>코드 자동 완성</li>
</ul>
<h3 id="ctrl--shift--space"><code>Ctrl + Shift + Space</code></h3>
<ul>
<li>메서드 파라미터 힌트</li>
</ul>
<h3 id="ctrl--1"><code>Ctrl + 1</code></h3>
<ul>
<li>빠른 수정 기능</li>
</ul>
<h3 id="ctrl--shift--f"><code>Ctrl + Shift + F</code></h3>
<ul>
<li>코드 포맷팅</li>
</ul>
<h3 id="alt--shift--r"><code>Alt + Shift + R</code></h3>
<ul>
<li>리팩토링 이름 변경</li>
</ul>
<h3 id="alt--상하-방향키"><code>Alt + 상하 방향키</code></h3>
<ul>
<li>코드 줄 이동</li>
</ul>
<h3 id="ctrl--alt--상하-방향키"><code>Ctrl + Alt + 상하 방향키</code></h3>
<ul>
<li>줄 복사</li>
</ul>
<h3 id="alt--shift--s"><code>Alt + Shift + S</code></h3>
<ul>
<li>코드 생성</li>
</ul>
<h2 id="디버깅">디버깅</h2>
<h3 id="f5"><code>F5</code></h3>
<ul>
<li>단계별로 디버깅</li>
</ul>
<h3 id="f6"><code>F6</code></h3>
<ul>
<li>다음 줄로 이동</li>
</ul>
<h3 id="f7"><code>F7</code></h3>
<ul>
<li>호출된 메서드로 이동</li>
</ul>
<h3 id="f8"><code>F8</code></h3>
<ul>
<li>다음 중단점으로 이동</li>
</ul>
<h3 id="f9"><code>F9</code></h3>
<ul>
<li>중단점 활성화 토글</li>
</ul>
<h3 id="ctrl--f11"><code>Ctrl + F11</code></h3>
<ul>
<li>프로젝트 실행</li>
</ul>
<h2 id="기타">기타</h2>
<h3 id="ctrl--shift--l"><code>Ctrl + Shift + L</code></h3>
<ul>
<li>현재 화면에 대한 모든 단축키 표시</li>
</ul>
<h3 id="ctrl--shift--r"><code>Ctrl + Shift + R</code></h3>
<ul>
<li>빠른 리소스 열기</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git vs. SVN]]></title>
            <link>https://velog.io/@iseon_u/Git-vs.-SVN</link>
            <guid>https://velog.io/@iseon_u/Git-vs.-SVN</guid>
            <pubDate>Wed, 21 Jun 2023 13:04:15 GMT</pubDate>
            <description><![CDATA[<h1 id="git-vs-svn">Git vs. SVN</h1>
<hr>
<h2 id="svn-subversion">SVN Subversion</h2>
<ul>
<li>Client/Server 타입 형상 관리 툴</li>
<li>보통 대부분의 기능을 완성해놓고 소스를 중앙 저장소에 commit</li>
<li>commit 자체가 중앙 저장소에 해당 기능을 공개한다는 의미</li>
<li>자신만의 version history를 가질 수 없다.<ul>
<li>local history는 일시적</li>
</ul>
</li>
<li>commit한 내용이 다른 개발자에게 바로 영향</li>
<li>서버와의 통신 없이는 작업을 수행할 수 없다</li>
<li>브랜치를 생성할 때 전체 소스 코드의 복사본을 생성</li>
<li>병합 작업 시 중앙 서버의 도움이 필요</li>
</ul>
<h2 id="git">Git</h2>
<ul>
<li>분산 저장소 타입 형상 관리 툴</li>
<li>자신만의 version history를 가질 수 있다</li>
<li>필요에 따라 push로 작업 내용 공유</li>
<li>로컬이기 때문에 SVN에 비해 빠르다</li>
<li>네트워크 연결이 필요한 경우에만 서버와 통신</li>
<li>로컬 저장소에서 브랜치를 생성</li>
<li>병합 작업 시 로컬에서 처리</li>
</ul>
<h2 id="svn-용어">SVN 용어</h2>
<ul>
<li>repository<ul>
<li>프로젝트의 모든 파일 및 디렉토리의 이력을 저장</li>
</ul>
</li>
<li>checkout<ul>
<li>저장소에서 프로젝트의 최신 버전을 로컬로 가져오는 작업</li>
</ul>
</li>
<li>commit<ul>
<li>로컬 작업 디렉토리에서 변경된 파일들을 중앙 저장소에 반영하는 작업</li>
<li>다른 개발자들이 즉시 변경 사항 확인 가능</li>
</ul>
</li>
<li>update<ul>
<li>저장소에서 최신 변경 사항을 가져와 로컬 작업 디렉토리를 업데이트하는 작업</li>
</ul>
</li>
<li>trunk<ul>
<li>메인 개발 소스</li>
</ul>
</li>
<li>branch<ul>
<li>trunk에서 분기된 개발 소스</li>
<li>독립적인 작업 영역</li>
</ul>
</li>
<li>tag<ul>
<li>특정 시점의 프로젝트 버전을 식별하기 위한 이름표</li>
<li>관례적으로 개발을 하지 않고 특정 시점 식별</li>
</ul>
</li>
<li>revision<ul>
<li>수정된 버전</li>
</ul>
</li>
</ul>
<h2 id="svn-명령어">SVN 명령어</h2>
<pre><code class="language-bash">#저장소 생성
svnadmin create /path/to/repository

#저장소에서 체크아웃
svn checkout URL

#변경된 파일 스테이징
svn add file1 file2

#변경 내용 커밋
svn commit -m &quot;Commit message&quot;

#변경 내용 업데이트
svn update

#로컬 변경 사항 확인
svn status

#리비전 로그 확인
svn log

#브랜치 생성
svn copy source_URL destination_URL

#브랜치 머지
svn merge source_URL[@source_revision] destination_URL

#태그 생성
svn copy source_URL destination_URL

#충돌 해결
svn resolve --accept=working file1</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[자주 사용하는 리눅스 명령어]]></title>
            <link>https://velog.io/@iseon_u/%EC%9E%90%EC%A3%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EB%A6%AC%EB%88%85%EC%8A%A4-%EB%AA%85%EB%A0%B9%EC%96%B4</link>
            <guid>https://velog.io/@iseon_u/%EC%9E%90%EC%A3%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EB%A6%AC%EB%88%85%EC%8A%A4-%EB%AA%85%EB%A0%B9%EC%96%B4</guid>
            <pubDate>Tue, 06 Jun 2023 12:02:26 GMT</pubDate>
            <description><![CDATA[<h1 id="자주-사용하는-리눅스-명령어">자주 사용하는 리눅스 명령어</h1>
<hr>
<h2 id="파일-및-디렉토리">파일 및 디렉토리</h2>
<ul>
<li><code>ls</code><ul>
<li>현재 디렉토리의 파일 및 디렉토리를 간단히 나열</li>
</ul>
</li>
<li><code>ll</code><ul>
<li><code>ls -l</code> 의 축약된 표현</li>
<li>파일 및 디렉토리의 상세 정보 나열</li>
</ul>
</li>
<li><code>ls -al</code><ul>
<li><code>-a</code> 숨김 파일 나열</li>
<li><code>-l</code> 상세한 정보 나열</li>
</ul>
</li>
<li><code>cd</code><ul>
<li>디렉토리 변경</li>
</ul>
</li>
<li><code>pwd</code><ul>
<li>현재 디렉토리 경로 표시</li>
</ul>
</li>
<li><code>mkdir</code><ul>
<li>새로운 디렉토리 생성</li>
</ul>
</li>
<li><code>rm</code><ul>
<li><code>-r</code> 재귀적으로 디렉토리와 하위 디렉토리 삭제</li>
<li><code>-f</code> 삭제 확인 메시지 없이 강제 삭제</li>
</ul>
</li>
<li><code>cp</code><ul>
<li>파일 또는 디렉토리 복사</li>
</ul>
</li>
<li><code>mv</code><ul>
<li>파일 또는 디렉토리 이동</li>
</ul>
</li>
<li><code>tree [파일명.txt]</code><ul>
<li>파일 내부 경로 트리 구조로 출력</li>
</ul>
</li>
</ul>
<h2 id="파일-내용-관련">파일 내용 관련</h2>
<ul>
<li><code>cat</code><ul>
<li>단순 파일 내용 출력</li>
</ul>
</li>
<li><code>vi</code> <code>vim</code><ul>
<li>텍스트 편집기로 파일 수정</li>
</ul>
</li>
<li><code>chmod</code><ul>
<li>파일 또는 디렉토리의 권한을 변경</li>
</ul>
</li>
<li><code>grep</code><ul>
<li>파일 내 특정 패턴 검색</li>
</ul>
</li>
</ul>
<h2 id="프로세스-관리">프로세스 관리</h2>
<ul>
<li><code>ps</code><ul>
<li>현재 실행 중인 프로세스 목록 표시</li>
</ul>
</li>
<li><code>pgrep</code><ul>
<li>실행 중인 특정 프로세스 출력</li>
</ul>
</li>
<li><code>kill</code><ul>
<li>프로세스 종료</li>
</ul>
</li>
<li><code>top</code><ul>
<li>시스템 프로세스 상태 모니터링</li>
</ul>
</li>
<li><code>nohup</code><ul>
<li>백그라운드에서 독립적으로 프로세스 실행</li>
<li>터미널 세션이 종료되어도 프로세스 실행</li>
</ul>
</li>
</ul>
<h2 id="네트워크-관리">네트워크 관리</h2>
<ul>
<li><code>ifconfig</code><ul>
<li>네트워크 설정 확인 또는 변경</li>
</ul>
</li>
<li><code>ping</code><ul>
<li>호스트나 IP 주소로 네트워크 연결 확인</li>
</ul>
</li>
<li><code>ssh</code><ul>
<li>원격 호스트에 안전한 연결 설정</li>
</ul>
</li>
<li><code>wget</code><ul>
<li>인터넷에서 파일 다운로드</li>
</ul>
</li>
</ul>
<h2 id="기타">기타</h2>
<ul>
<li><code>echo</code><ul>
<li>텍스트 출력</li>
</ul>
</li>
<li><code>date</code><ul>
<li>현재 날짜와 시간 출력</li>
</ul>
</li>
<li><code>sleep</code><ul>
<li>지정된 시간 동안 프로세스 실행 지연</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Apache Tika와 MultipartFile]]></title>
            <link>https://velog.io/@iseon_u/Apache-Tika%EC%99%80-MultipartFile</link>
            <guid>https://velog.io/@iseon_u/Apache-Tika%EC%99%80-MultipartFile</guid>
            <pubDate>Sat, 27 May 2023 07:29:31 GMT</pubDate>
            <description><![CDATA[<h1 id="apache-tika와-multipartfile">Apache Tika와 MultipartFile</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/iseon_u/post/e6d3ba73-d009-47a9-b3b2-3a0c9a9637a9/image.png" alt=""></p>
<h2 id="apache-tika">Apache Tika</h2>
<ul>
<li>다양한 파일 형식의 컨텐츠를 추출하고 분석하는 기능을 제공</li>
<li>그중 MIME Type 체크 기능을 업로드 파일의 유형을 확인하기 위해 Spring에서 사용해 보았다.</li>
</ul>
<h3 id="mime-type-list">MIME Type List</h3>
<p><a href="https://www.freeformatter.com/mime-types-list.html">Complete MIME Types List - FreeFormatter.com</a></p>
<h3 id="gradle-dependency">Gradle Dependency</h3>
<pre><code class="language-groovy">implementation &#39;org.apache.tika:tika-core:2.5.0&#39;</code></pre>
<h3 id="apache-tika-mime-type-체크-예시-코드">Apache Tika MIME Type 체크 예시 코드</h3>
<pre><code class="language-java">public class MimeTypeExample {
    public static void main(String[] args) {
        Tika tika = new Tika();

        // 파일 경로
        File file = new File(&quot;path/to/file&quot;);

        try {
            // MIME 타입 체크
            String mimeType = tika.detect(file);
            System.out.println(&quot;MIME 타입: &quot; + mimeType);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<ul>
<li>예를 들어 확장자가 <code>png</code>인 이미지를 검사하면 <code>image/png</code> 같이 MIME Type을 확인할 수 있다.</li>
</ul>
<blockquote>
<p>그런데 <code>MultipartFile</code>의 <code>getContentType()</code> 메서드를 사용하면 MIME Type을 확인할 수 있다
게다가 Spring에서 기본으로 제공하기 때문에 따로 종속성을 추가하지 않고 사용이 가능하다</p>
</blockquote>
<h2 id="multipartfile-인터페이스">MultipartFile 인터페이스</h2>
<ul>
<li>Spring에서 제공하는 파일 업로드를 처리하기 위한 인터페이스</li>
</ul>
<h3 id="multipartfile-mime-type-체크-예시-코드">MultipartFile MIME Type 체크 예시 코드</h3>
<pre><code class="language-java">@Controller
public class FileUploadController {

    @PostMapping(&quot;/upload&quot;)
    public String handleFileUpload(@RequestParam(&quot;file&quot;) MultipartFile file) {
        if (!file.isEmpty()) {
            String contentType = file.getContentType();
            System.out.println(&quot;MIME 타입: &quot; + contentType);
            return &quot;redirect:/success&quot;;
        } else {
            return &quot;redirect:/error&quot;;
        }
    }
}</code></pre>
<ul>
<li>Apache Tika와 마찬가지로 <code>image/png</code> 같은 형식의 MIME Type을 반환한다.</li>
</ul>
<blockquote>
<p>그럼 이 둘의 차이는 뭘까?</p>
</blockquote>
<h2 id="확장자-유무에-따른-차이">확장자 유무에 따른 차이</h2>
<ol>
<li>확장자를 명시했을 때</li>
</ol>
<p><img src="https://velog.velcdn.com/images/iseon_u/post/a10cb512-105f-48bd-8f36-2b94f5f79445/image.png" alt=""></p>
<ol start="2">
<li><p>확장자가 파일 이름에 없을 때</p>
<p> <img src="https://velog.velcdn.com/images/iseon_u/post/40a907ae-361b-43fc-8de6-a9366abff81b/image.png" alt=""></p>
</li>
</ol>
<ul>
<li>확장자를 명시했을 땐 둘 다 정확한 MIME Type을 반환한다.</li>
<li>하지만 확장자가 없을 땐 Tika의 <code>detect()</code> 메서드만 정확한 MIME Type을 반환한다.</li>
</ul>
<blockquote>
<p>정확한 MIME Type 확인이 요구될 때엔 Tika를 사용하는 것이 좋아 보인다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Google Java Style Guide 코딩 컨벤션]]></title>
            <link>https://velog.io/@iseon_u/Google-Java-Style-Guide-%EC%BD%94%EB%94%A9-%EC%BB%A8%EB%B2%A4%EC%85%98</link>
            <guid>https://velog.io/@iseon_u/Google-Java-Style-Guide-%EC%BD%94%EB%94%A9-%EC%BB%A8%EB%B2%A4%EC%85%98</guid>
            <pubDate>Tue, 16 May 2023 14:59:46 GMT</pubDate>
            <description><![CDATA[<h1 id="google-java-style-guide-코딩-컨벤션">Google Java Style Guide 코딩 컨벤션</h1>
<hr>
<p><a href="https://google.github.io/styleguide/javaguide.html">Google Java Style Guide</a></p>
<ul>
<li>Google Java Style Guide 코딩 컨벤션</li>
<li>Google에서 개발자들이 일관된 코드 스타일을 따르도록 지침을 제공하는 문서</li>
<li>팀 프로젝트 진행시 코딩 컨벤션을 적용하면 포맷팅을 제외한 실제 변경사항만 확인 가능 👍</li>
</ul>
<h2 id="plug-in을-통한-google-java-style-guide-포맷팅-적용">Plug-in을 통한 Google Java Style Guide 포맷팅 적용</h2>
<h3 id="intellij">IntelliJ</h3>
<p><a href="https://plugins.jetbrains.com/plugin/8527-google-java-format">google-java-format - IntelliJ IDEs Plugin | Marketplace</a></p>
<h3 id="visual-studio-code">Visual Studio Code</h3>
<p><a href="https://marketplace.visualstudio.com/items?itemName=ilkka.google-java-format">google-java-format - Visual Studio Code</a></p>
<h3 id="intellij-설정">IntelliJ 설정</h3>
<blockquote>
<p>환경 설정 | 기타 설정 | google-java-format Settings</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/iseon_u/post/5f0931f4-d3c6-4e53-ad89-0a0bfb47aeb5/image.png" alt=""></p>
<ul>
<li>Enable google-java-format 활성화</li>
<li>Code style<ul>
<li>AOSP style (4-space indentation)</li>
</ul>
</li>
</ul>
<blockquote>
<p>도움말 | 사용자 지정 VM 옵션 편집…</p>
</blockquote>
<pre><code>--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</code></pre><ul>
<li>상단 코드 라인 추가</li>
<li>IDE 재시작</li>
<li><code>Ctrl</code> + <code>Alt</code> + <code>L</code> 로 코드 포매팅</li>
</ul>
<h2 id="github-actions를-이용한-저장소-레벨-포맷팅-적용">Github Actions를 이용한 저장소 레벨 포맷팅 적용</h2>
<p><a href="https://github.com/axel-op/googlejavaformat-action">https://github.com/axel-op/googlejavaformat-action</a></p>
<p><img src="https://velog.velcdn.com/images/iseon_u/post/6ed2667f-fd14-445a-ab2f-e65a08ace7c4/image.png" alt=""></p>
<pre><code class="language-yaml">name: google-java-format

on: [ push, pull_request ]
jobs:
  formatting:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - uses: axel-op/googlejavaformat-action@v3
        with:
          args: &quot;--replace --aosp&quot;
          commit-message: &quot;format: Google Java Format&quot;
                    # MacOS를 사용한다면 아래 코드 추가
                    github-token: ${{ secrets.GH_TOKEN }}</code></pre>
<h3 id="macos를-사용하는-경우">MacOS를 사용하는 경우</h3>
<ul>
<li>아래에 해당 코드 추가</li>
</ul>
<pre><code class="language-yaml">github-token: ${{ secrets.GH_TOKEN }}</code></pre>
<blockquote>
<p>Settings | Secrets and variables | Actions</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/iseon_u/post/ec3ddc8f-aacc-449a-b0d1-1ecd25e109c3/image.png" alt=""></p>
<ul>
<li>New repository secret<ul>
<li>Name - GH_TOKEN</li>
<li>Secret - GitHub에서 발급 받은 토큰을 입력한다</li>
</ul>
</li>
</ul>
<h3 id="github-actions-권한-수정">GitHub Actions 권한 수정</h3>
<p><a href="https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs">Assigning permissions to jobs - GitHub Docs</a></p>
<blockquote>
<p>Settings | Actions | General</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/iseon_u/post/b31b9f01-0a40-4ba5-86c2-eab718ed8244/image.png" alt=""></p>
<ul>
<li>Read and write permissions로 전환 후 저장</li>
</ul>
<h3 id="특정-브랜치-제외-하기">특정 브랜치 제외 하기</h3>
<pre><code class="language-yaml">on:
    push:
        branches-ignore:
            - &quot;main&quot;</code></pre>
<ul>
<li><code>main</code> 브랜치 제외</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[CodeMetrics Plug-in]]></title>
            <link>https://velog.io/@iseon_u/CodeMetrics-Plug-in</link>
            <guid>https://velog.io/@iseon_u/CodeMetrics-Plug-in</guid>
            <pubDate>Tue, 16 May 2023 11:42:18 GMT</pubDate>
            <description><![CDATA[<h1 id="codemetrics-plug-in">CodeMetrics Plug-in</h1>
<hr>
<ul>
<li>코드 복잡도 확인 플러그인</li>
<li>대략적인 코드 품질 확인 추정 가능</li>
</ul>
<h3 id="intellij">IntelliJ</h3>
<p><a href="https://plugins.jetbrains.com/plugin/12159-codemetrics">CodeMetrics - IntelliJ IDEs Plugin | Marketplace</a></p>
<h3 id="visual-studio-code">Visual Studio Code</h3>
<p><a href="https://marketplace.visualstudio.com/items?itemName=kisstkondoros.vscode-codemetrics">CodeMetrics - Visual Studio Code</a></p>
<p><img src="https://velog.velcdn.com/images/iseon_u/post/50d5ea18-9121-4fdf-8e69-21f42215038f/image.png" alt=""></p>
<h2 id="복잡도-레벨">복잡도 레벨</h2>
<ol>
<li>Extreme ☠️<ul>
<li>25 &lt; 복잡도</li>
</ul>
</li>
<li>High 🚨<ul>
<li>10 &lt; 복잡도 ≤ 25</li>
</ul>
</li>
<li>Normal ⚠️<ul>
<li>5 &lt; 복잡도 ≤ 10</li>
</ul>
</li>
<li>Low ✅<ul>
<li>0 &lt; 복잡도 ≤ 5</li>
</ul>
</li>
</ol>
<h2 id="복잡도-점수-낮추는-방법">복잡도 점수 낮추는 방법</h2>
<p><a href="https://youtu.be/8NtKoANOezI">CodeMetrics 플러그인 소개: 복잡도 점수로 자극 받기</a></p>
<ul>
<li>if 절 단순화<ul>
<li>바이너리 비교 연산자 점수가 크다</li>
</ul>
</li>
<li>return, throw 개수 감소<ul>
<li>따로 빼서 리팩토링</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[var - Java]]></title>
            <link>https://velog.io/@iseon_u/var-Java</link>
            <guid>https://velog.io/@iseon_u/var-Java</guid>
            <pubDate>Thu, 11 May 2023 10:58:21 GMT</pubDate>
            <description><![CDATA[<h1 id="var">var</h1>
<hr>
<ul>
<li>지역 변수 타입 추론</li>
<li>Java 10부터 도입</li>
<li>컴파일러가 타입을 추론</li>
<li>컴파일 타임에 추론하기 때문에 성능 영향 없음 ❌</li>
</ul>
<pre><code class="language-java">String str = &quot;Hello world&quot;;
var str = &quot;Hello world&quot;;</code></pre>
<ul>
<li>명시적 선언을 타입 선언 없이 선언 가능</li>
</ul>
<h2 id="제약-사항">제약 사항</h2>
<ul>
<li>지역 변수에서만 사용</li>
<li>초기화 필요</li>
<li>null 로 초기화 불가</li>
<li>배열에 사용 불가</li>
<li>Lambda에 사용 불가</li>
</ul>
<h2 id="var-활용">var 활용</h2>
<pre><code class="language-java">Function&lt;String, Integer&gt; foo = (@NotNull var txt) -&gt; {
        return txt.length();
};</code></pre>
<ul>
<li>키워드 앞에만 사용할 수 있는 어노테이션 사용 가능</li>
</ul>
<pre><code class="language-java">for (var n : arr) {
    System.out.println(&quot;n&quot; + n);
}</code></pre>
<ul>
<li>반복문에서 사용 가능</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Mockito 기반의 Controller 단위 테스트]]></title>
            <link>https://velog.io/@iseon_u/Mockito-%EA%B8%B0%EB%B0%98%EC%9D%98-Controller-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@iseon_u/Mockito-%EA%B8%B0%EB%B0%98%EC%9D%98-Controller-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Wed, 10 May 2023 19:37:14 GMT</pubDate>
            <description><![CDATA[<h1 id="mockito-기반의-controller-단위-테스트">Mockito 기반의 Controller 단위 테스트</h1>
<hr>
<h2 id="mockito-어노테이션-종류">Mockito 어노테이션 종류</h2>
<h3 id="mock">@Mock</h3>
<ul>
<li>가짜 객체를 만들어주는 어노테이션</li>
<li>테스트할 레이어에 필요한 객체를 사용</li>
</ul>
<h3 id="spy">@Spy</h3>
<ul>
<li>특정 객체의 실제 메소드를 호출</li>
</ul>
<h3 id="injectmocks">@InjectMocks</h3>
<ul>
<li>Mock 객체가 주입되어야 하는 대상 객체 생성 및 주입</li>
</ul>
<h2 id="mockito-메서드">Mockito 메서드</h2>
<h3 id="doreturn">doReturn()</h3>
<ul>
<li>가짜 객체가 특정한 값을 반환하는 경우</li>
</ul>
<h3 id="donothing">doNothing()</h3>
<ul>
<li>가짜 객체가 아무 것도 반환하지 않는 경우</li>
<li>void인 경우</li>
</ul>
<h3 id="dothrow">doThrow()</h3>
<ul>
<li>가짜 객체가 예외를 발생하는 경우</li>
</ul>
<h2 id="단위-테스트-작성">단위 테스트 작성</h2>
<h3 id="의존성-주입-및-http-호출을-위한-mockmvc">의존성 주입 및 HTTP 호출을 위한 MockMVC</h3>
<pre><code class="language-java">@ExtendWith(MockitoExtension.class)
class StoreControllerTest {

    @InjectMocks
    private StoreController storeController;

    @Mock
    private StoreService storeService;

    private MockMvc mockMvc;

    @BeforeEach
    public void init() {
        mockMvc = MockMvcBuilders.standaloneSetup(storeController).build();
    }
}</code></pre>
<ul>
<li><code>@InjectMocks</code><ul>
<li>테스트 대상</li>
<li>가짜 객체 주입</li>
<li>Controller</li>
</ul>
</li>
<li><code>@Mock</code><ul>
<li>가짜 객체 생성</li>
<li>Service</li>
</ul>
</li>
<li>MockMvc<ul>
<li>컨트롤러 테스트를 위한 HTTP 호출 필요</li>
</ul>
</li>
</ul>
<h3 id="매장-등록-성공-테스트">매장 등록 성공 테스트</h3>
<pre><code class="language-java">@DisplayName(&quot;매장 등록 성공&quot;)
    @Test
    void 매장등록() throws Exception {
        //given
        final var request = 매장등록요청_생성();
        doNothing().when(storeService)
                .createStore(any(StoreRequestDto.class));

        //when
        ResultActions resultActions = mockMvc.perform(
                MockMvcRequestBuilders.post(&quot;/stores&quot;)
                        .contentType(&quot;application/json&quot;)
                        .content(new Gson().toJson(request))
        );

        //then
        resultActions.andExpect(status().isCreated());
    }</code></pre>
<ul>
<li><code>any()</code><ul>
<li>조건을 충족하는 요소가 있는지 여부 테스트</li>
<li>지정한 클래스 타입이면 어떤 객체도 처리할 수 있도록 지정</li>
</ul>
</li>
<li>Gson<ul>
<li>객체에서 문자열로 변환</li>
</ul>
</li>
</ul>
<h2 id="spring-boot에서-webmvctest-사용">Spring Boot에서 @WebMvcTest 사용</h2>
<h3 id="webmvctest">@WebMvcTest</h3>
<ul>
<li>MockMvc 객체 자동 생성</li>
<li>ControllerAdvice, Filter, Interceptor 등을 빈으로 등록</li>
<li><code>@Mock</code>, <code>@Spy</code> 대신 <code>@MockBean</code>, <code>@SpyBean</code> 사용</li>
</ul>
<pre><code class="language-java">@WebMvcTest(StoreController.class)
class StoreControllerTest {

    @MockBean
    private StoreService storeService;

    @Autowired
    private MockMvc mockMvc;

}</code></pre>
<ul>
<li>컨텍스트 캐싱 대신 새로운 컨텍스트 생성이 필요하기 때문에 비교적 느리다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[MockMvc, Rest Assured 차이]]></title>
            <link>https://velog.io/@iseon_u/MockMvc-Rest-Assured-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@iseon_u/MockMvc-Rest-Assured-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Wed, 10 May 2023 15:54:20 GMT</pubDate>
            <description><![CDATA[<h1 id="mockmvc-rest-assured-차이">MockMvc, Rest Assured 차이</h1>
<hr>
<h2 id="mockmvc">MockMvc</h2>
<ul>
<li>주로 컨트롤러 단위 테스트에 사용</li>
<li>빠른 테스트<ul>
<li><code>@WebMvcTest</code>를 사용</li>
</ul>
</li>
<li>가짜 객체를 만들어서 요청 처리</li>
</ul>
<h2 id="rest-assured">Rest Assured</h2>
<ul>
<li>주로 End-to-End Test 전 구간 테스트에 사용</li>
<li>비용 높은 느린 테스트<ul>
<li>항상 <code>@SpringBootTest</code>를 사용</li>
</ul>
</li>
<li>실제 요청으로 처리</li>
</ul>
<table>
<thead>
<tr>
<th></th>
<th>MockMvc</th>
<th>Rest Assured</th>
</tr>
</thead>
<tbody><tr>
<td>사용 범위</td>
<td>컨트롤러 단위 테스트</td>
<td>전 구간 테스트</td>
</tr>
<tr>
<td>사용 객체</td>
<td>가짜 객체 요청</td>
<td>실제 요청</td>
</tr>
<tr>
<td>속도</td>
<td>상대적으로 빠름</td>
<td>오래 걸림</td>
</tr>
<tr>
<td>가독성</td>
<td>낮음</td>
<td>BDD 스타일, 높음</td>
</tr>
</tbody></table>
<h2 id="dependency">Dependency</h2>
<h3 id="mockmvc-1">MockMvc</h3>
<ul>
<li>Spring Framework Test 클래스 중 하나<ul>
<li>Spring test 의존성이 추가되어 있는 경우 사용 가능</li>
</ul>
</li>
</ul>
<h3 id="rest-assured-1">Rest Assured</h3>
<pre><code class="language-groovy">dependencies {
    testImplementation &#39;io.rest-assured:rest-assured:4.4.0&#39;
}</code></pre>
<h3 id="ℹ️-intellj를-통한-gradle-종속성-추가-방법">ℹ️ IntellJ를 통한 Gradle 종속성 추가 방법</h3>
<p><img src="https://velog.velcdn.com/images/iseon_u/post/071bec72-7797-4d97-a099-98b1e9f90577/image.png" alt="">
<img src="https://velog.velcdn.com/images/iseon_u/post/8bf238fe-d46b-4624-a085-c6b29a3b2c5e/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SpringBoot 테스트를 위한 DB 격리]]></title>
            <link>https://velog.io/@iseon_u/Spring-%ED%85%8C%EC%8A%A4%ED%8A%B8%EB%A5%BC-%EC%9C%84%ED%95%9C-DB-%EA%B2%A9%EB%A6%AC</link>
            <guid>https://velog.io/@iseon_u/Spring-%ED%85%8C%EC%8A%A4%ED%8A%B8%EB%A5%BC-%EC%9C%84%ED%95%9C-DB-%EA%B2%A9%EB%A6%AC</guid>
            <pubDate>Wed, 10 May 2023 14:22:40 GMT</pubDate>
            <description><![CDATA[<h1 id="springboot-테스트를-위한-db-격리">SpringBoot 테스트를 위한 DB 격리</h1>
<hr>
<h2 id="db-격리를-생각하게-된-계기">DB 격리를 생각하게 된 계기</h2>
<ul>
<li>단위 테스트만 작성할 땐 <code>@Transactional</code> 어노테이션으로 DB 롤백이 가능 ✅</li>
<li><code>@SpringBootTest</code>에서 <code>RANDOM_PORT</code>나 <code>DEFINED_PORT</code> 를 사용하는 테스트에서는 적용 불가 ❌</li>
</ul>
<h2 id="springboottest-random_port-defined_port-에서-transacation-롤백이-안되는-이유">@SpringBootTest RANDOM_PORT, DEFINED_PORT 에서 @Transacation 롤백이 안되는 이유</h2>
<ul>
<li><code>RANDOM_PORT</code>, <code>DEFINED_PORT</code>를 사용하면 별도의 쓰레드에서 스프링 컨테이너가 실행 된다.</li>
<li>때문에 테스트와 별개의 쓰레드에서 스프링 컨테이너가 실행 되므로 하나의 트랜잭션으로 묶일 수가 없다.</li>
</ul>
<h2 id="해결-방법">해결 방법</h2>
<ol>
<li>테스트를 위한 DB 환경 구축</li>
<li>테스트 격리를 위한 모든 테이블 데이터 초기화<ol>
<li><code>@AfterEach</code> 를 사용해 DB 삭제 메서드 작성</li>
<li><code>@Sql</code>어노테이션을 통한 DB 초기화</li>
<li>Spring Batch를 사용하여 DB 초기화</li>
</ol>
</li>
</ol>
<h3 id="테스트를-위한-db-환경-구축">테스트를 위한 DB 환경 구축</h3>
<blockquote>
<p>test/resources/application.properties</p>
</blockquote>
<pre><code>spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/one_delivery_test?useSSL=false&amp;useUnicode=true&amp;serverTimezone=Asia/Seoul
spring.datasource.username=root</code></pre><ul>
<li>application.properties를 따로 작성</li>
<li>테스트용 DB 생성</li>
</ul>
<h3 id="sql-어노테이션을-통한-db-초기화">@Sql 어노테이션을 통한 DB 초기화</h3>
<blockquote>
<p>/resources/sql/truncate.sql</p>
</blockquote>
<pre><code class="language-sql">SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE TABLE cart
TRUNCATE TABLE menu
TRUNCATE TABLE store
...
SET FOREIGN_KEY_CHECKS = 1;</code></pre>
<pre><code class="language-java">@Sql(scripts = {&quot;/sql/truncate.sql&quot;}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)</code></pre>
<ul>
<li><code>@Sql</code> 어노테이션을 통해 테스트 사용에 따라 이전 또는 이후에 DB 초기화 실행</li>
</ul>
<h3 id="db-초기화-sql">DB 초기화 SQL</h3>
<ol>
<li>모든 테이블에 대한 TRUNCATE TABLE 명령어 리스트 추출</li>
</ol>
<pre><code class="language-sql">SELECT CONCAT(&#39;TRUNCATE TABLE &#39;, TABLE_NAME, &#39;;&#39;) AS list FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = &#39;one_delivery_test&#39;</code></pre>
<ol>
<li>제약 조건 무효화</li>
</ol>
<pre><code class="language-sql">SET FOREIGN_KEY_CHECKS = 0;</code></pre>
<ol>
<li>모든 테이블에 대한 TRUNCATE TABLE 명령어 실행</li>
<li>제약 조건 재설정</li>
</ol>
<pre><code class="language-sql">SET FOREIGN_KEY_CHECKS = 1;</code></pre>
<h3 id="spring-batch를-사용하여-db-초기화">Spring Batch를 사용하여 DB 초기화</h3>
<blockquote>
<p>test/resources/application.properties</p>
</blockquote>
<pre><code>spring.batch.jdbc.initialize-schema=always</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[AWS EC2 프리티어에서 Jenkins 배포시 중단 해결]]></title>
            <link>https://velog.io/@iseon_u/AWS-EC2-%ED%94%84%EB%A6%AC%ED%8B%B0%EC%96%B4%EC%97%90%EC%84%9C-Jenkins-%EB%B0%B0%ED%8F%AC%EC%8B%9C-%EC%A4%91%EB%8B%A8-%ED%95%B4%EA%B2%B0</link>
            <guid>https://velog.io/@iseon_u/AWS-EC2-%ED%94%84%EB%A6%AC%ED%8B%B0%EC%96%B4%EC%97%90%EC%84%9C-Jenkins-%EB%B0%B0%ED%8F%AC%EC%8B%9C-%EC%A4%91%EB%8B%A8-%ED%95%B4%EA%B2%B0</guid>
            <pubDate>Mon, 08 May 2023 14:33:55 GMT</pubDate>
            <description><![CDATA[<h1 id="aws-ec2-프리티어에서-jenkins-배포시-중단-해결">AWS EC2 프리티어에서 Jenkins 배포시 중단 해결</h1>
<hr>
<p><a href="https://repost.aws/ko/knowledge-center/ec2-memory-swap-file">스왑 파일을 사용하여 Amazon EC2 인스턴스의 스왑 공간으로 메모리 할당</a></p>
<h2 id="🌳-환경">🌳 환경</h2>
<ul>
<li>AWS EC2</li>
<li>Jenkins</li>
</ul>
<h2 id="🔥-문제">🔥 문제</h2>
<ul>
<li>AWS EC2 프리티어인 t2.micro에서 Jenkins 배포 시작시 서버 중단</li>
</ul>
<h2 id="🧯-해결">🧯 해결</h2>
<ul>
<li>t2.micro 유형이 Jenkins 배포를 가동하기엔 RAM 용량이 부족하여 발생하는 문제</li>
<li>사양이 높은 유형으로 업그레이드</li>
<li>swap 기능 활용</li>
</ul>
<h2 id="프리티어-유형에서-swap-공간을-활용하여-가동">프리티어 유형에서 swap 공간을 활용하여 가동</h2>
<pre><code class="language-bash">sudo dd if=/dev/zero of=/swapfile bs=128M count=16
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
sudo swapon -s</code></pre>
<ul>
<li>해당 명령어에서 스왑 파일 크기는 2GB</li>
<li>해당 명령어들을 순차적으로 적용시키면 해결 완료</li>
</ul>
<p><img src="https://velog.velcdn.com/images/iseon_u/post/552d405a-5ae5-4dbc-84cd-b7bab3c2d7f0/image.png" alt=""></p>
<ul>
<li>swap 공간 할당 후 배포를 시도해보니 정상적으로 작동된다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[@Transactional]]></title>
            <link>https://velog.io/@iseon_u/Transcational</link>
            <guid>https://velog.io/@iseon_u/Transcational</guid>
            <pubDate>Mon, 08 May 2023 14:09:17 GMT</pubDate>
            <description><![CDATA[<h2 id="transactionmanager">TransactionManager</h2>
<ul>
<li>기존엔 DAO 의 각 메서드는 개별 Connection 을 사용<ul>
<li>1 Connection 에 1 Tx</li>
<li>오류가 발생하여 롤백 처리해도 다른 Connection 은 롤백이 안된다.</li>
</ul>
</li>
<li>→ 같은 Tx 내에서 같은 Connection 을 사용할 수 있게 관리</li>
</ul>
<h3 id="transactionmanager-로-transaction-적용">TransactionManager 로 Transaction 적용</h3>
<pre><code class="language-java">public void insertWithTx() throws Exception {
        // TxManager 생성
        PlatformTransactionManager tm = new DataSourceTransactionManager(ds);
        TransactionStatus status = tm.getTransaction(new DefaultTransactionDefinition());
        // Tx 시작

        try {
                dao.insert(1,100); // 원래는 개별 Connection
                dao.insert(1,200); // TxManager 가 같은 Connection 으로 묶어준다.
                tm.commit(status); // Tx 끝 - 성공 (커밋)
        } catch(Exception ex) {
                tm.rollback(status); // Tx 끝 - 실패 (롤백)
        }
}</code></pre>
<ul>
<li>핵심 기능<ul>
<li><code>dao.insert(1,100);</code></li>
</ul>
</li>
<li>부가 기능<ul>
<li>Tx 관련 코드</li>
<li>불변하는 코드</li>
<li>코드 중복 발생</li>
<li>AOP 필요</li>
</ul>
</li>
</ul>
<h2 id="transactional">@Transactional</h2>
<ul>
<li>AOP 를 이용한 핵심 기능과 부가 기능의 분리</li>
</ul>
<pre><code class="language-java">@Transactional
public void insertWithTx() throws Exception {
        dao.insert(1,100);
        dao.insert(1,200);
}</code></pre>
<ul>
<li>부가 기능 코드를 @Transactional 어노테이션으로 대체<ul>
<li>핵심 로직에만 집중하면 된다.</li>
</ul>
</li>
<li>클래스나 인터페이스에도 @Transactional 어노테이션 가능</li>
<li>RuntimeException 과 Error 만 rollback 처리<ul>
<li><strong>Checked Exception에 대해서는 롤백시키지 않도록 설계</strong> 🚨</li>
<li>스프링 프레임워크가 EJB 관습을 따르기 때문</li>
</ul>
</li>
<li><code>@Transactional(rollbackFor = Exception.class)</code>  ✅<ul>
<li>Exception 과 그 자손들 처리</li>
</ul>
</li>
</ul>
<h3 id="transactional-의-속성">@Transactional 의 속성</h3>
<table>
<thead>
<tr>
<th>속성</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>propagation</td>
<td>Tx 의 경계 (boundary) 를 설정하는 방법을 지정</td>
</tr>
<tr>
<td>isolation</td>
<td>Tx 의 isolation level 을 지정 DEFAULT, READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE</td>
</tr>
<tr>
<td>readOnly</td>
<td>Tx 이 데이터를 읽기만 하는 경우 true 로 지정하면 성능이 향상</td>
</tr>
<tr>
<td>rollbackFor</td>
<td>지정된 예외가 발생하면 Tx 을 rollback</td>
</tr>
<tr>
<td>RuntimeException 과 Error 는 자동 rollback</td>
<td></td>
</tr>
<tr>
<td>noRollbackFor</td>
<td>지정된 예외가 발생해도 Tx 을 rollback 하지 않는다.</td>
</tr>
<tr>
<td>timeout</td>
<td>지정된 시간 (초) 내에 Tx 이 종료되지 않으면 Tx 을 강제 종료</td>
</tr>
</tbody></table>
<h3 id="propagation-속성-값">propagation 속성 값</h3>
<table>
<thead>
<tr>
<th>값</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>REQUIRED</td>
<td>Tx 이 진행 중이면 참여하고 없으면 새로운 Tx 시작 (디폴트)</td>
</tr>
<tr>
<td>REQUIRES_NEW</td>
<td>Tx 이 진행 중이건 아니건 새로 Tx 시작</td>
</tr>
<tr>
<td>NESTED</td>
<td>Tx 이 진행 중이면, Tx 의 내부 Tx 로 실행</td>
</tr>
<tr>
<td>MANDATORY</td>
<td>반드시 진행 중인 Tx 내에서만 실행 가능 아니면 예외 발생</td>
</tr>
<tr>
<td>SUPPORTS</td>
<td>Tx 이 진행 중이건 아니건 상관 없이 실행</td>
</tr>
<tr>
<td>NOT_SUPPORTED</td>
<td>Tx 없이 처리 Tx 이 진행 중이면 잠시 중단 (suspend)</td>
</tr>
<tr>
<td>NEVER</td>
<td>Tx 없이 처리 Tx 이 진행 중 이면 예외 발생</td>
</tr>
</tbody></table>
<h3 id="required">REQUIRED</h3>
<pre><code class="language-java">@Transactional(propagation = Propagation.REQUIRED)
public void insertA1WithTx() throws Exception {
        a1Dao.insert(1,100);
        insertB1WithTx();
        a1Dao.insert(1,200);
}</code></pre>
<pre><code class="language-java">@Transactional(propagation = Propagation.REQUIRED)
public void insertB1WithTx() throws Exception {
        b1Dao.insert(1,100);
        b1Dao.insert(1,200);
}</code></pre>
<ul>
<li>Tx 이 <strong>진행 중이면 참여</strong>하고 없으면 새로운 Tx 시작 (디폴트)</li>
<li>중간에 에러가 발생하면 <strong>다같이 rollback</strong></li>
</ul>
<img src="https://velog.velcdn.com/images/iseon_u/post/36956272-48fa-48ea-9563-a6c251415fc9/image.png" width="200">


<h3 id="requires_new">REQUIRES_NEW</h3>
<pre><code class="language-java">@Transactional(propagation = Propagation.REQUIRED)
public void insertA1WithTx() throws Exception {
        a1Dao.insert(1,100);
        insertB1WithTx();
        a1Dao.insert(1,200);
}</code></pre>
<pre><code class="language-java">@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertB1WithTx() throws Exception {
        b1Dao.insert(1,100);
        b1Dao.insert(1,200);
}</code></pre>
<ul>
<li>Tx 이 진행 중이건 아니건 <strong>새로 Tx 시작</strong></li>
<li>예제에서는 서로 다른 2개의 Tx</li>
<li>만약 A2 에서 에러 발생시 A1 rollback<ul>
<li>B1, B2 는 다른 Tx 이기 때문에 영향이 없다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>프록시 방식 (디폴트) 의 AOP 는 내부 호출인 경우 Advice 가 적용 되지 않기 때문에 따로 Tx 가 적용되지 않는다.</p>
</blockquote>
<blockquote>
<p>두 메서드를 별도의 클래스로 분리 하거나 AOP 를 프록시 방식이 아닌 다른 방식으로 처리해야 예제처럼 Tx 적용</p>
</blockquote>
<img src="https://velog.velcdn.com/images/iseon_u/post/aebafffb-f664-41e7-9382-2f3da3f580b6/image.png" width="200">
]]></description>
        </item>
        <item>
            <title><![CDATA[Java - record class]]></title>
            <link>https://velog.io/@iseon_u/Java-record-class</link>
            <guid>https://velog.io/@iseon_u/Java-record-class</guid>
            <pubDate>Mon, 08 May 2023 13:43:53 GMT</pubDate>
            <description><![CDATA[<h1 id="record-class">record class</h1>
<hr>
<ul>
<li>데이터 전용 클래스</li>
<li>순수하게 데이터를 보유하기 위한 클래스</li>
<li>불필요한 코드를 줄이고 간결한 코드 작성을 가능하게 해준다</li>
<li>DTO 클래스를 생성할 때 주로 사용</li>
<li>Java 14부터 도입, Java 16에서 정식 스펙으로 포함</li>
<li>코틀린의 데이터 클래스와 유사</li>
</ul>
<h2 id="주요-기능">주요 기능</h2>
<ul>
<li>생성자, 데이터 필드, 필드명을 딴 getter 메서드 자동 생성</li>
<li>불변성 보장</li>
<li><code>equals()</code>, <code>hashCode()</code>, <code>toString()</code> 메서드 자동 생성</li>
</ul>
<h2 id="유의-사항">유의 사항</h2>
<ul>
<li>final, public 으로 선언</li>
<li>각 필드는 private final 필드로 정의</li>
<li>JPA entity 로 사용 불가</li>
</ul>
<h2 id="기존의-불변-데이터-객체">기존의 불변 데이터 객체</h2>
<pre><code class="language-java">public class Person {
    private final String name;
    private final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}</code></pre>
<h2 id="record-클래스를-이용한-불변-객체">record 클래스를 이용한 불변 객체</h2>
<pre><code class="language-java">public record Person(String name, int age) {
}</code></pre>
<ul>
<li>코드가 훨씬 간결해진다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS Summit Seoul 2023 후기]]></title>
            <link>https://velog.io/@iseon_u/AWS-Summit-Seoul-2023-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@iseon_u/AWS-Summit-Seoul-2023-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Wed, 03 May 2023 13:47:39 GMT</pubDate>
            <description><![CDATA[<h1 id="aws-summit-seoul-2023-후기">AWS Summit Seoul 2023 후기</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/iseon_u/post/0188eb87-7b7d-42e9-be42-611939fc6a9d/image.jpg" alt=""></p>
<ul>
<li>수많은 기업들이 사용하는 AWS</li>
</ul>
<p><img src="https://velog.velcdn.com/images/iseon_u/post/9b4051cf-2e90-49d3-8b30-b7c3278cd639/image.jpg" alt=""></p>
<p><img src="https://velog.velcdn.com/images/iseon_u/post/8473826f-9abc-4dc3-898e-99c240cb1175/image.jpg" alt=""></p>
<ul>
<li>강의는 언제나 앞자리가 좋다</li>
</ul>
<h2 id="처음-가보는-aws-summit-그리고-컨퍼런스">처음 가보는 AWS Summit 그리고 컨퍼런스</h2>
<p>3년 만에 AWS Summit 행사가 열렸다.</p>
<p>발표하시는 분들도 코로나 이후 이렇게 많은 사람들 앞에서 발표하는 게 오랜만이라고 하시니</p>
<p>나 또한 이런 행사를 접할 기회가 없었다.</p>
<p>그러기에 처음 경험해 보는 AWS Summit 그리고 컨퍼런스의 경험이었고 생각보다 매우 흥미로웠다.</p>
<p>첫 번째로는 개발자뿐만 아니라 모든 사람들의 이목을 끌만한 세션들로 가득했고</p>
<p>때문에 나는 동시간대에 진행되는 7가지 세션 중 어떤 세션을 골라야 할지 굉장히 고민이 되었다.</p>
<h2 id="천만-사용자를-위한-카카오의-aws-native-글로벌-채팅-서비스">천만 사용자를 위한 카카오의 AWS Native 글로벌 채팅 서비스</h2>
<p>내가 선택한 세션 1의 제목이다.</p>
<p>제목만 봐도 궁금증과 흥미를 유발하는 제목이다.</p>
<p>초반에는 AWS 담당자분께서 목차를 설명해주셨고 이후 실제 카카오에서는 어떻게 AWS를 적용시켰는지</p>
<p>개발자 분이 나오셔서 발표하셨다.</p>
<p>솔직한 소감은 약간의 실망감이 있었다.</p>
<p>‘천만 사용자를 위한 카카오’</p>
<p>제목만 보면 누구나 다 ‘카카오톡 서비스에 대한 설명인가?’라고 생각하기 마련이다.</p>
<p>하지만 발표자 분께서 하신 첫마디는 “카카오톡 아닙니다. 오해하지 마세요”였다 ㅎㅎ</p>
<p>발표의 내용은 카카오톡을 제외한 채팅 서비스의 내용이었고</p>
<p>전반적인 채팅 서비스를 카카오의 요구사항마다 해당하는 맞춤 AWS를 사용해서 개발에 성공했다는 이야기를 해주셨다.</p>
<p>또한 서버리스와 Cloud Native를 강조하셨다.</p>
<p>이 것들을 고집한 이유 중 하나는 대규모 서비스의 경우 소프트웨어 개발 기간보다 운영기간이 길기 때문이라고 말씀하셨다.</p>
<h2 id="삼성전자-쿠팡의-대규모-트래픽-처리를-위한-클라우드-네이티브-데이터베이스-활용">삼성전자 쿠팡의 대규모 트래픽 처리를 위한 클라우드 네이티브 데이터베이스 활용</h2>
<p>내가 들은 두 번째 세션의 제목이다.</p>
<p>첫 번째로는 삼성의 ‘채팅 +’ 서비스의 개발 과정을 발표하셨다.</p>
<p>전반적인 설명 방식은 이러한 요구사항이 있고 목표 수치가 있는데</p>
<p>이런 상황에서 어떤 AWS 서비스를 사용했고 또한 그 서비스를 어떤 식으로 사용했는지까지 설명해 주셨다.</p>
<p>발표를 너무 완벽하게 하셔서 개인적으로 가장 만족한 세션이었다.</p>
<p>두 번째로는 쿠팡의 DBA 담당자분께서 나오셔서 발표하셨다.</p>
<p>쿠팡의 DDL 과정을 과거 버전과 현재 버전을 비교하시면서 어떻게 시간과 비용을 줄였는지 설명해 주시고</p>
<p>마지막에는 직접 영상으로 DDL 시스템이 어떤 식으로 작동되는지 보여주셨다.</p>
<p>과거에는 신박한 DDL 요청들이 많았었는데 이러한 시스템 도입 이후 그런 것들이 줄어들었다고 농담도 하셨다.</p>
<p>개인적으로는 기업에서 DDL 하나 작성하고 적용시키기 위해 이러한 시스템을 만들었다는 게 대단하다고 생각했다.</p>
<h2 id="총평">총평</h2>
<p>‘AWS 최고’</p>
<p>위 세션들을 제외한 나머지 세션들은 마치 AWS 제품 소개처럼 느껴졌다.</p>
<p>그래서인지 Day 2의 기술 세션들이 기대가 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Dockerfile 빌드]]></title>
            <link>https://velog.io/@iseon_u/Dockerfile-%EB%B9%8C%EB%93%9C</link>
            <guid>https://velog.io/@iseon_u/Dockerfile-%EB%B9%8C%EB%93%9C</guid>
            <pubDate>Tue, 02 May 2023 08:52:38 GMT</pubDate>
            <description><![CDATA[<h1 id="dockerfile-빌드">Dockerfile 빌드</h1>
<hr>
<h2 id="이미지-생성">이미지 생성</h2>
<h3 id="dockerfile-빌드-1">Dockerfile 빌드</h3>
<pre><code class="language-bash">$ docker build -t mybuild:0.0 ./</code></pre>
<ul>
<li>옵션 <code>-t</code><ul>
<li>생성될 이미지의 이름을 설정</li>
<li>가급적 사용</li>
</ul>
</li>
<li>build 명령어 끝에 Dockerfile 이 저장된 경로 입력<ul>
<li><code>./</code> (현재 디렉터리)</li>
</ul>
</li>
</ul>
<h3 id="생성된-이미지로-컨테이너-실행">생성된 이미지로 컨테이너 실행</h3>
<pre><code class="language-bash">$ docker run -d -P --name myserver mybuild:0.0</code></pre>
<ul>
<li>옵션 <code>-P</code><ul>
<li>이미지에 설정된 EXPOSE의 모든 포트를 호스트에 연결하도록 설정</li>
</ul>
</li>
</ul>
<h2 id="빌드-컨텍스트">빌드 컨텍스트</h2>
<ul>
<li>이미지 빌드 실행 시 빌드 컨텍스트를 읽어온다</li>
<li>Dockerfile이 위치한 디렉터리</li>
<li>Dockerfile이 위치한 곳에는 이미지 빌드에 필요한 파일만 위치</li>
</ul>
<h3 id="dockerignore">.dockerignore</h3>
<ul>
<li>빌드 시 파일에 명시된 이름의 파일은 컨텍스트에서 제외</li>
<li>컨텍스트 최상위 경로, build 명령어에서 맨 마지막에 오는 경로, Dockerfile이 위치한 경로에 위치</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Dockerfile]]></title>
            <link>https://velog.io/@iseon_u/Dockerfile</link>
            <guid>https://velog.io/@iseon_u/Dockerfile</guid>
            <pubDate>Mon, 01 May 2023 16:15:21 GMT</pubDate>
            <description><![CDATA[<h1 id="dockerfile">Dockerfile</h1>
<hr>
<h2 id="이미지를-생성하는-방법">이미지를 생성하는 방법</h2>
<ol>
<li>아무것도 존재하지 않는 이미지(우분투, CentOS)로 컨테이너를 생성</li>
<li>애플리케이션을 위한 환경을 설치하고 소스코드 등을 복사해 잘 동작하는 것을 확인</li>
<li>컨테이너를 이미지로 커밋(commit)</li>
</ol>
<h2 id="dockerfile-1">Dockerfile</h2>
<ul>
<li>위와 같은 일련의 과정을 손쉽게 기록하고 수행할 수 있는 빌드 명령어를 제공</li>
<li>컨테이너에 설치해야 하는 패키지, 소스코드, 명령어, 셸 스크립트 등을 하나의 파일에 기록</li>
<li>빌드 명령어는 Dockerfile을 읽어 이미지 생성</li>
<li>Dockerfile을 작성하여 빌드 및 배포 자동화 가능</li>
</ul>
<h2 id="dockerfile-작성">Dockerfile 작성</h2>
<ul>
<li>컨테이너에서 수행해야 할 작업을 명시</li>
<li>예시 Dockerfile</li>
</ul>
<pre><code class="language-bash">$ vi Dockerfile

FROM ubuntu:14.04
MAINTAINER alicek106
LABEL &quot;purpose&quot;=&quot;practice&quot;
RUN apt-get update
RUN apt-get install apache2 -y
ADD test.html /var/www/html
WORKDIR /var/www/html
RUN [&quot;/bin/bash&quot;, &quot;-c&quot;, &quot;echo hello &gt;&gt; test2.html&quot;] 
EXPOSE 80
CMD apachectl -DFOREGROUND</code></pre>
<ul>
<li>Dockfile 수행 목록<ul>
<li>이미지에 아파치 웹 서버 설치</li>
<li>로컬에 있는 test.html 파일을 웹 서버로 접근할 수 있는 컨테이너의 디렉터리인 /var/www/html에 복사</li>
</ul>
</li>
</ul>
<h2 id="dockerfile-명령어">Dockerfile 명령어</h2>
<ul>
<li><p><code>FROM</code></p>
<ul>
<li>생성할 이미지의 베이스가 될 이미지를 의미</li>
<li>반드시 한 번 이상 입력</li>
</ul>
</li>
<li><p><code>MAINTAINER</code></p>
<ul>
<li><p>이미지를 생성한 개발자의 정보</p>
</li>
<li><p>Dockerfile을 작성한 사람과 연락할 수 있는 이메일 입력</p>
</li>
<li><p>도커 1.13.0 이후 LABEL로 교체해 표현</p>
<blockquote>
<p>LABEL maintainer &quot;alicekl06 <a href="mailto:&#97;&#x6c;&#x69;&#99;&#x65;&#107;&#x6c;&#x30;&#x36;&#x40;&#110;&#97;&#x76;&#101;&#114;&#46;&#x63;&#111;&#x6d;">&#97;&#x6c;&#x69;&#99;&#x65;&#107;&#x6c;&#x30;&#x36;&#x40;&#110;&#97;&#x76;&#101;&#114;&#46;&#x63;&#111;&#x6d;</a>&quot;</p>
</blockquote>
</li>
</ul>
</li>
<li><p><code>LABEL</code></p>
<ul>
<li>이미지에 메타데이터 추가</li>
<li>메타데이터는 키:값의 형태로 저장</li>
</ul>
</li>
<li><p><code>RUN</code></p>
<ul>
<li>이미지를 만들기 위해 컨테이너 내부에서 명령어 실행</li>
<li>이미지 빌드시 별도의 입력을 받아야 하는 RUN이 있다면 오류로 간주하고 빌드 종료</li>
</ul>
</li>
<li><p><code>ADD</code></p>
<ul>
<li>파일을 이미지에 추가</li>
<li>추가하는 파일은 Dockerfile이 위치한 디렉터리인 컨텍스트에서 가져온다</li>
<li>JSON 배열 형태로 사용 가능<ul>
<li>[”추가할 파일 이름”, “컨테이너에 추가될 위치”]</li>
<li>추가할 파일명 여러개 지정 가능</li>
<li>배열 마지막 원소가 컨테이너에 추가될 위치</li>
</ul>
</li>
</ul>
</li>
<li><p><code>WORKDIR</code></p>
<ul>
<li>명령어를 실행할 디렉터리</li>
<li>배시 셸에서 cd 명령어를 입력하는 것과 동일</li>
</ul>
</li>
<li><p><code>EXPOSE</code></p>
<ul>
<li>Dockerfile의 빌드로 생성된 이미지에서 노출할 포트를 설정</li>
<li>반드시 이 포트가 호스트의 포트와 바인딩되는 것은 아니다</li>
</ul>
</li>
<li><p><code>CMD</code></p>
<ul>
<li>컨테이너가 시작될 때마다 실행할 명령어를 설정</li>
<li>Dockerfile에서 한 번만 사용 가능</li>
<li>JSON 배열 형태로 입력 가능<ul>
<li>[”실행 가능한 파일”, “명령줄 인자 1”, “명령줄 인자 2”]</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>