<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>bitneer.dev</title>
	<atom:link href="https://www.bitneer.dev/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.bitneer.dev</link>
	<description>AI 시대에 취미로 하는 코딩</description>
	<lastBuildDate>Tue, 06 Jan 2026 20:59:26 +0000</lastBuildDate>
	<language>ko-KR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.3</generator>

<image>
	<url>https://www.bitneer.dev/wp/wp-content/uploads/2023/11/cropped-bitneer_Logo_for_Google_200-32x32.png</url>
	<title>bitneer.dev</title>
	<link>https://www.bitneer.dev</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>데비안에 Eclipse Temurin JDK 설치하기</title>
		<link>https://www.bitneer.dev/blog/%eb%8d%b0%eb%b9%84%ec%95%88%ec%97%90-eclipse-temurin-jdk-%ec%84%a4%ec%b9%98%ed%95%98%ea%b8%b0/</link>
		
		<dc:creator><![CDATA[Choi Kyung-sik]]></dc:creator>
		<pubDate>Tue, 30 Dec 2025 20:41:04 +0000</pubDate>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jdk]]></category>
		<guid isPermaLink="false">https://www.bitneer.dev/?p=10094</guid>

					<description><![CDATA[<p>Atlassian이 Cloud 중심 전략으로 전환하기 위해 2021년 Confluence, Jira, Bitbucket에 대한 개인용 영구 라이선스(Server) 판매를 중단했고, 기업용인 Data Center 제품도 2029년까지 단계적으로 종료할 예정이다. 이에 따라 개인적으로 사용 중이던 Jira와 Bitbucket은 Gitea로 대체하였다. Confluence는 노션(Notion), 아웃라인(Outline), 옵시디언(Obsidian) 등을 검토해 보았으나 딱히 마음에 드는 대안이 없었다. 다행히 Confluence는 폴백(Fallback) 영구 라이선스라 업그레이드는 불가능하지만 계속 사용할 수 있어 아직 유지하고 있다. Java에 ...</p>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/%eb%8d%b0%eb%b9%84%ec%95%88%ec%97%90-eclipse-temurin-jdk-%ec%84%a4%ec%b9%98%ed%95%98%ea%b8%b0/">데비안에 Eclipse Temurin JDK 설치하기</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>
  Atlassian이 Cloud 중심 전략으로 전환하기 위해 2021년 Confluence, Jira,
  Bitbucket에 대한 개인용 영구 라이선스(Server) 판매를 중단했고, 기업용인 Data
  Center 제품도 2029년까지 단계적으로 종료할 예정이다. 이에 따라 개인적으로 사용
  중이던 Jira와 Bitbucket은
  <a rel="noopener noreferrer" target="_blank" href="https://about.gitea.com/">Gitea</a
  >로 대체하였다. Confluence는
  <a rel="noopener noreferrer" target="_blank" href="https://www.notion.com/ko">노션(Notion)</a
  >,
  <a rel="noopener noreferrer" target="_blank" href="https://www.getoutline.com/">아웃라인(Outline)</a
  >,
  <a rel="noopener noreferrer" target="_blank" href="https://obsidian.md/">옵시디언(Obsidian)</a
  >
  등을 검토해 보았으나 딱히 마음에 드는 대안이 없었다. 다행히 Confluence는
  폴백(Fallback) 영구 라이선스라 업그레이드는 불가능하지만 계속 사용할 수 있어
  아직 유지하고 있다.
</p>
<p>
  Java에 대한 흥미를 잃어 대체 솔루션으로 교체하게 되면 JDK를 삭제할
  예정이었으나, 한동안은 더 필요할 듯하다. 또한 검색을 통해 이전에 작성한
  <a rel="noopener noreferrer" target="_blank" href="https://www.bitneer.dev/blog/%eb%8d%b0%eb%b9%84%ec%95%88%ec%97%90-adoptopenjdk-%ec%84%a4%ec%b9%98%ed%95%98%ea%b8%b0/">데비안에 AdoptOpenJDK 설치하기</a
  >
  글로 유입되는 경우가 있어, 최신 정보를 공유하고자 기록을 남긴다.
</p>
<h5>AdoptOpenJDK의 브랜드 변경과 이관</h5>
<p>
  AdoptOpenJDK는 2021년 Eclipse 재단으로 이관되면서
  <strong>Eclipse Adoptium</strong> 프로젝트로 재탄생하였다. 이는 Oracle의
  상표권 문제를 해결하고, 공식 호환성 테스트(TCK)를 통과하여 엔터프라이즈
  환경에서 더 신뢰할 수 있는 바이너리를 제공하기 위함이다.
</p>
<ul>
  <li>
    <strong>상표권 분쟁 회피:</strong> &#8216;OpenJDK&#8217;라는 단어는 Oracle의 등록
    상표이다. 커뮤니티 프로젝트였던 &#8216;AdoptOpenJDK&#8217;의 규모가 커지자, 법적으로
    안전하고 영구적인 이름을 갖기 위해 Eclipse 재단으로 이관하며 이름을 변경해야
    했다.
  </li>
  <li>
    <strong>Java 공식 인증 (TCK 라이선스 획득)</strong>: 과거 AdoptOpenJDK는
    Oracle과의 라이선스 문제로 &#8216;자바 호환성 테스트(TCK)&#8217;를 공식적으로 수행할 수
    없었다. 하지만 Eclipse 재단 산하로 들어가면서 Oracle과 협약을 맺고 TCK
    인증을 통과한 &#8216;공식 호환 Java&#8217;를 배포할 수 있게 되었다.
  </li>
</ul>
<p>
  2021년 AdoptOpenJDK 프로젝트가 Eclipse 재단으로 합류하며 Eclipse Adoptium으로
  이름이 바뀌었고, <strong>Eclipse Temurin</strong>이라는 바이너리가 처음
  배포되었다. 이후 2023년 7월, 기존에 사용하던
  <kbd>adoptopenjdk.jfrog.io</kbd> 저장소는 완전히 사용 중단(Deprecated)되었다.
</p>
<p>
  Eclipse Adoptium(어댑티움)은 프로젝트 이름이고 Eclipse Temurin(테무린)은 해당
  프로젝트에서 생산하는 JDK 제품 이름이다. <strong>Temurin</strong>은
  <strong>Runtime</strong>의 아나그램(철자 순서 바꾸기)이다. (R-u-n-t-i-m-e
  &harr; T-e-m-u-r-i-n)
</p>
<h5>AdoptOpenJDK 저장소 정리하기</h5>
<p>
  Eclipse Temurin으로 이관되던 2023년 무렵, <kbd>apt update</kbd> 실행 시 다음과
  같은 경고 메시지가 발생했었다. 현재는 저장소 자체가 삭제되었을 것으로 보인다.
</p>
<pre class="language-none">
<code># apt update
...
W: https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/dists/buster/InRelease 파일을 받는데 실패했습니다  503  Service Temporarily Unavailable [IP: 34.74.126.177 443]
W: Some index files failed to download. They have been ignored, or old ones used instead.</code>
</pre>
<p>
  아직 저장소를 정리하지 않았다면 <kbd>/etc/apt/sources.list</kbd>나
  <kbd>/etc/apt/sources.list.d</kbd>에서 AdoptOpenJDK 저장소 설정을 삭제하자.
</p>
<p>
  AdoptOpenJDK GPG 키는 <kbd>apt-key add</kbd> 명령으로
  <kbd>/etc/apt/trusted.gpg</kbd> 파일에 저장되어 있을 것이다. 다음 명령어로 키
  정보를 확인한다.
</p>
<pre class="language-none" data-line="4">
<code># apt-key list
...
pub   rsa4096 2019-06-25 [SC] [expires: 2023-06-24]
      5951 8666 C652 3968 B1F8  6530 8AC3 B291 7488 5C03
uid           [ unknown] AdoptOpenJDK &lt;adoptopenjdk@jfrog.com&gt;
sub   rsa4096 2019-06-25 [E] [expires: 2023-06-24]
...</code>
</pre>
<p>
  4번째 줄의 전체 핑거프린트(Fingerprint)에서 마지막 8자리를 Key ID로 사용한다.
  위 예시에서는 <kbd>74885C03</kbd>이 Key ID이다. 다음 명령어로 AdoptOpenJDK
  키를 삭제한다.
</p>
<pre class="language-none">
<code># apt-key del 74885C03</code>
</pre>
<h5>데비안의 최신 apt 보안 표준</h5>
<p>외부 저장소의 GPG 키를 저장하는 곳은 크게 다음 세 가지가 있다.</p>
<ol>
  <li><kbd>/etc/apt/trusted.gpg</kbd> 파일</li>
  <li><kbd>/etc/apt/trusted.gpg.d/</kbd> 디렉터리 내부</li>
  <li><kbd>/etc/apt/keyrings/</kbd> 디렉터리 내부</li>
</ol>
<p>
  첫 번째와 두 번째 방식은 보안상 좋지 않아 권장되지 않거나 사용이 중단될
  예정이다. <kbd>trusted.gpg</kbd> 파일과 <kbd>trusted.gpg.d</kbd> 디렉터리 안의
  키는 시스템의 <strong>모든</strong> 저장소에서 해당 키를 무조건 신뢰하기
  때문이다.
</p>
<ul>
  <li>
    <kbd>apt-key add</kbd> 명령어로 <kbd>trusted.gpg</kbd> 파일에 추가하던
    방법은 사용이 금지된다.
    <strong
      >Debian 13 &quot;Trixie&quot;부터 apt-key는 제거되어 더 이상 사용할 수
      없다.</strong
    >
  </li>
  <li>
    <kbd>/etc/apt/trusted.gpg.d/</kbd> 디렉터리에 넣는 것 또한 권장되지 않는다.
    <kbd>rm</kbd> 명령어로 GPG 키를 편하게 삭제할 수 있다는 장점은 있으나,
    여전히 전역 신뢰(Global Trust) 문제로 인해 보안에 좋지 않다.
  </li>
</ul>
<p>
  따라서 별도의 디렉터리인 <kbd>/etc/apt/keyrings</kbd>에 GPG 키를 저장하고,
  <kbd>sources.list</kbd>에서
  <strong>&quot;이 저장소는 오직 이 키로만 인증한다(signed-by)&quot;</strong
  >라고 명시하는 세 번째 방식을 권장하고 있다.
</p>
<p>
  이 권장 방식을 따르고 있는 대표적인 예로 GitHub CLI가 있다. (공식 문서 참조:
  <a rel="noopener noreferrer" target="_blank" href="https://github.com/cli/cli/blob/trunk/docs/install_linux.md#debian">GitHub CLI Install</a
  >) GitHub CLI는
  <kbd>/etc/apt/keyrings/githubcli-archive-keyring.gpg</kbd> 경로에 GPG 키를
  생성하며, <kbd>/etc/apt/sources.list.d/github-cli.list</kbd> 파일의 내용은
  다음과 같다.
</p>
<pre class="language-none">
<code>deb [arch=amd64 signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main</code>
</pre>
<p>
  <kbd>signed-by</kbd> 옵션에 GPG 키 경로를 명시적으로 설정한 것을 볼 수 있다.
</p>
<h5>Eclipse Temurin 설치</h5>
<p>
  Eclipse Temurin 설치 페이지(<a rel="noopener noreferrer" target="_blank" href="https://adoptium.net/installation/linux/">https://adoptium.net/installation/linux/</a
  >)에서는 앞서 언급한 두 번째 방식(<kbd>/etc/apt/trusted.gpg.d/</kbd>)을
  안내하고 있다. 데비안의 최신 권장 방식을 아직 따르고 있지 않은데, 언젠가는
  문서가 업데이트될 것으로 보인다. 공식 문서대로 설치해도 사용에는 지장이
  없으나, 이 글에서는 <strong>데비안의 권장 방식(signed-by)</strong>으로
  설치하는 방법을 설명한다.
</p>
<h6>1. 필수 패키지 설치</h6>
<p>
  다음 명령어로 Eclipse Temurin 설치 과정에 필요한
  <kbd>wget, apt-transport-https, gpg</kbd> 패키지를 설치한다. <kbd>gpg</kbd>는
  데비안 설치 시 <kbd>gnupg</kbd>에 포함되어 이미 설치되어 있을 수 있다.
</p>
<pre class="language-none">
<code># apt update
# apt install wget apt-transport-https gpg</code>
</pre>
<h6>2. Eclipse Adoptium GPG 키 설치</h6>
<p>
  패키지의 무결성 검사에 사용하는 Eclipse Adoptium GPG 키를 설치한다.
  <kbd>/etc/apt/keyrings</kbd> 디렉터리에 설치하는 점에 주목하자.
</p>
<pre class="language-none">
<code># wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor | tee /etc/apt/keyrings/adoptium.gpg > /dev/null</code>
</pre>
<h6>3. Eclipse Adoptium DEB 저장소 설정</h6>
<p>
  Eclipse Adoptium DEB 저장소 설정을 추가한다. <kbd>signed-by</kbd> 옵션에
  Eclipse Adoptium GPG 키 경로를 지정하여, 해당 저장소가 오직 이 키만 사용하도록
  강제한다.
</p>
<pre class="language-none">
<code># echo "deb [signed-by=/etc/apt/keyrings/adoptium.gpg] https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" | tee /etc/apt/sources.list.d/adoptium.list</code>
</pre>
위 명령어로 생성된 <kbd>/etc/apt/sources.list.d/adoptium.list</kbd> 파일의
내용은 다음과 같다.
<pre class="language-none">
<code>deb [signed-by=/etc/apt/keyrings/adoptium.gpg] https://packages.adoptium.net/artifactory/deb bookworm main</code>
</pre>
<h6>4. temurin-&lt;version&gt;-jdk 설치</h6>
다음은 개인적으로 사용하는 구버전 Confluence 환경에 맞춰
<kbd>temurin-8-jdk</kbd> 패키지를 설치하는 예시이다. 본인이 필요한 버전의
패키지를 설치하면 된다.
<pre class="language-none">
<code># apt update
# apt install temurin-8-jdk</code>
</pre>
<h5>관련 글</h5>
<ul>
  <li>
    <a rel="noopener noreferrer" target="_blank" href="https://www.bitneer.dev/blog/%eb%8d%b0%eb%b9%84%ec%95%88%ec%97%90-adoptopenjdk-%ec%84%a4%ec%b9%98%ed%95%98%ea%b8%b0/">데비안에 AdoptOpenJDK 설치하기</a
    >
  </li>
</ul>
<h5>참고 자료</h5>
<ul>
  <li>
    <a rel="noopener noreferrer" target="_blank" href="https://adoptium.net/blog/2023/07/adoptopenjdk-jfrog-io-has-been-deprecated/">AdoptOpenJDK.jfrog.io has been deprecated! | Adoptium</a
    >
  </li>
  <li>
    <a rel="noopener noreferrer" target="_blank" href="https://adoptium.net/installation/linux/">https://adoptium.net/installation/linux/</a
    >
  </li>
  <li>
    <a rel="noopener noreferrer" target="_blank" href="https://wiki.debian.org/SecureApt">SecureApt &#8211; Debian Wiki</a
    >
  </li>
  <li>
    <a rel="noopener noreferrer" target="_blank" href="https://unix.stackexchange.com/questions/420961/how-to-identify-gpg-key-ids-so-they-may-be-deleted">debian &#8211; How to identify gpg key IDs so they may be deleted &#8211; Unix &amp;
      Linux Stack Exchange</a
    >
  </li>
</ul>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/%eb%8d%b0%eb%b9%84%ec%95%88%ec%97%90-eclipse-temurin-jdk-%ec%84%a4%ec%b9%98%ed%95%98%ea%b8%b0/">데비안에 Eclipse Temurin JDK 설치하기</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>윈도우 터미널 설치와 설정</title>
		<link>https://www.bitneer.dev/blog/%ec%9c%88%eb%8f%84%ec%9a%b0-%ed%84%b0%eb%af%b8%eb%84%90-%ec%84%a4%ec%b9%98%ec%99%80-%ec%84%a4%ec%a0%95/</link>
		
		<dc:creator><![CDATA[Choi Kyung-sik]]></dc:creator>
		<pubDate>Sun, 28 Dec 2025 01:37:58 +0000</pubDate>
				<category><![CDATA[네트워크와 시스템 관리]]></category>
		<category><![CDATA[ssh]]></category>
		<category><![CDATA[terminal]]></category>
		<guid isPermaLink="false">https://www.bitneer.dev/?p=10050</guid>

					<description><![CDATA[<p>이전에 Windows 터미널의 설정 및 ssh 사용하기라는 글을 작성한 적이 있다. 최근 설정 화면이 대폭 개선되고 인터페이스에 변화가 생겼으므로, 변경 사항 위주로 내용을 다시 정리한다. 설치 공식 웹사이트: Windows Terminal &#8211; Microsoft Apps에서 설치 파일을 다운로드한다. Microsoft Store: 윈도우 운영체제에 내장된 Microsoft Store 프로그램을 실행한 후 &#8216;Windows Terminal&#8217;을 검색하여 설치할 수도 있다. 설정 열기 윈도우 터미널에서 Ctrl + , 키를 ...</p>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/%ec%9c%88%eb%8f%84%ec%9a%b0-%ed%84%b0%eb%af%b8%eb%84%90-%ec%84%a4%ec%b9%98%ec%99%80-%ec%84%a4%ec%a0%95/">윈도우 터미널 설치와 설정</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>
  이전에
  <a rel="noopener noreferrer" target="_blank" href="https://www.bitneer.dev/blog/windows-%ed%84%b0%eb%af%b8%eb%84%90%ec%9d%98-%ec%84%a4%ec%a0%95-%eb%b0%8f-ssh-%ec%82%ac%ec%9a%a9%ed%95%98%ea%b8%b0/">Windows 터미널의 설정 및 ssh 사용하기</a
  >라는 글을 작성한 적이 있다. 최근 설정 화면이 대폭 개선되고 인터페이스에
  변화가 생겼으므로, 변경 사항 위주로 내용을 다시 정리한다.
</p>
<h5>설치</h5>
<ul>
  <li>
    <strong>공식 웹사이트:</strong>
    <a rel="noopener noreferrer" target="_blank" href="https://aka.ms/terminal" style="text-decoration: none">Windows Terminal &#8211; Microsoft Apps</a
    >에서 설치 파일을 다운로드한다.
  </li>
  <li>
    <strong>Microsoft Store:</strong> 윈도우 운영체제에 내장된 Microsoft Store
    프로그램을 실행한 후 &#8216;Windows Terminal&#8217;을 검색하여 설치할 수도 있다.
  </li>
</ul>
<h5>설정 열기</h5>
<p>
  윈도우 터미널에서 <strong><kbd>Ctrl + ,</kbd></strong> 키를 누르면 설정 화면이
  나타난다. 이전 버전에서는 <kbd>settings.json</kbd> 파일이 직접 열렸으나,
  현재는 GUI 기반의 설정 페이지가 기본으로 열린다. 단축키 대신 상단 탭의
  드롭다운 아이콘을 클릭한 후 <strong>[설정]</strong> 메뉴를 선택해도 동일하다.
</p>
<p>
  <img decoding="async"
    src="https://cdn.jsdelivr.net/gh/bitneer/wp-media-001/2025-12-28/001.png"
    alt="윈도우 터미널의 드롭다운 메뉴에서 설정 열기"
  />
</p>
<h5>프로필 추가하기</h5>
<p>
  좌측 메뉴 하단의 <strong>[새 프로필 추가]</strong>를 클릭하여 프로필을 추가할
  수 있다.
</p>
<p>
  <img decoding="async"
    src="https://cdn.jsdelivr.net/gh/bitneer/wp-media-001/2025-12-28/002.png"
    alt="윈도우 터미널의 새 프로필 추가 화면"
  />
</p>
<p>
  <strong>이름</strong>과 <strong>명령줄</strong>, 이 두 가지 항목이 접속을 위한
  최소한의 필수 설정이다. 설정을 마친 후에는 우측 하단의
  <strong>저장</strong> 버튼을 반드시 클릭해야 적용된다.
</p>
<h5>프로필 연결 예제 (카페24 SSH)</h5>
<p>
  몇 년 전 워드프레스 서버를 이전하면서 도메인을 <kbd>bitneer.info</kbd>에서
  <kbd>bitneer.dev</kbd>로 변경하고, 집 서버에서
  <a rel="noopener noreferrer" target="_blank" href="https://aws.amazon.com/ko/lightsail/">AWS Lightsail</a
  >을 거쳐 최종적으로 카페24의
  <a rel="noopener noreferrer" target="_blank" href="https://hosting.cafe24.com/?controller=new_product_page&amp;page=managed-wordpress">뉴매니지드 워드프레스</a
  >
  호스팅으로 옮겼다. 여기서는 카페24 서버에 접속하는 프로필 설정 예시를
  소개한다.
</p>
<h6>1. 사전 준비</h6>
<ul>
  <li>윈도우에 <strong>OpenSSH 클라이언트</strong>가 설치되어 있어야 한다.</li>
  <li>
    <kbd>ssh-copy-id</kbd> 명령어를 사용하기 위해 리눅스용 OpenSSH 클라이언트가
    필요하다. 이 글에서는 WSL(Windows Subsystem for Linux)의 Debian 환경에
    <kbd>openssh-client</kbd> 패키지를 설치하여 진행한다.
  </li>
  <li>
    WSL을 사용하지 않는다면,
    <a rel="noopener noreferrer" target="_blank" href="https://www.bitneer.dev/blog/windows-%ed%84%b0%eb%af%b8%eb%84%90%ec%9d%98-%ec%84%a4%ec%a0%95-%eb%b0%8f-ssh-%ec%82%ac%ec%9a%a9%ed%95%98%ea%b8%b0/">이전 글</a
    >의 &#8216;암호를 입력하지 않고 SSH 사용하기&#8217; 부분을 참고하여 수동으로 키를
    등록해야 한다.
  </li>
</ul>
<h6>2. SSH 키 생성</h6>
<p>
  SSH 키를 만든 적이 없다면 PowerShell에서 다음 명령어를 입력하여
  개인키(<kbd>id_rsa</kbd>)와 공개키(<kbd>id_rsa.pub</kbd>)를 생성한다. 설정
  과정 중 나타나는 질문에는 모두 <kbd>Enter</kbd> 키를 눌러 기본값으로 넘긴다.
  특히 <strong>비밀번호(passphrase)는 입력하지 않아야</strong> 자동 로그인이
  가능하다.
</p>
<pre class="language-none">
<code>> ssh-keygen -t rsa
> ls ~/.ssh</code>
</pre>
<h6>3. 카페24 설정 및 키 복사</h6>
<ul>
  <li>
    카페24 관리자 페이지의 [서비스 사용현황]에서 <strong>아이디</strong>와
    <strong>서버 IP</strong>를 확인한다.
  </li>
  <li>
    [보안관리] &gt; [FTP/Shell 접속설정]에서
    <strong>&#8216;SSH Key 로그인 사용&#8217; 대신 &#8216;비밀번호 로그인 사용&#8217;을 선택</strong
    >한다. 카페24에서 제공하는 자체 SSH Key는 30일마다 갱신해야 하는 번거로움이
    있으므로, 직접 생성한 키를 사용하는 것이 관리 측면에서 효율적이다. 다만,
    보안을 위해 비밀번호는 크롬 브라우저에서 제안하는 것과 같이 추측하기 어려운
    강력한 조합을 사용한다.
  </li>
  <li>
    WSL 리눅스 환경에 <kbd>~/.ssh</kbd> 디렉터리가 없다면 생성하고, 윈도우에서
    만든 키 파일들을 해당 디렉터리로 복사한다.
  </li>
  <li>
    다음 명령어를 실행하여 공개키를 카페24 서버의 적절한 권한을 가지는
    <kbd>authorized_keys</kbd>로 복사한다.
    <pre class="language-none">
<code>$ ssh-copy-id 아이디@서버IP주소</code>
</pre>
  </li>
</ul>
<h6>4. 터미널 프로필 등록</h6>
<p>윈도우 터미널 설정을 열고 다음과 같이 새 프로필을 추가한다.</p>
<ul>
  <li><strong>이름:</strong> <kbd>카페24</kbd></li>
  <li><strong>명령줄:</strong> <kbd>ssh 아이디@서버IP주소</kbd></li>
</ul>
<h5>기타 세부 설정</h5>
<p>윈도우 터미널에 개인적으로 사용하는 추가 설정들이다.</p>
<ul>
  <li>
    프로필의 <strong>기본값</strong> 설정
    <ul>
      <li>
        <strong>추가 설정</strong>의 <strong>모양</strong>에서
        <strong>텍스트</strong>의 <strong>글꼴 크기</strong>를
        <strong><kbd>11</kbd></strong
        >로 조정하고, <strong>커서</strong>의 <strong>커서 모양</strong>은
        <strong><kbd>빈티지</kbd></strong
        >를 선택했다.
      </li>
      <li>
        <strong>추가 설정</strong>의 <strong>고급</strong>에서
        <strong>벨 알림 스타일</strong>의 <strong>들을 수 있음</strong>을 체크
        해제하고 <strong>플래시 창</strong>을 체크했다. Bash에서 Tab 키를 이용한
        자동완성을 자주 사용하는데, 그때마다 발생하는 비프음이 거슬리기
        때문이다.
      </li>
    </ul>
  </li>
  <li>
    사용하지 않는 프로필은
    <strong>드롭다운에서 프로필 숨기기</strong>를
    <strong>켬</strong>
    으로 하여 목록을 깔끔하게 유지한다.
  </li>
  <li>
    카페24 프로필의
    <strong>아이콘</strong>에서 적당한 아이콘이 없어 AWS의 ec2 이미지를 구하여
    설정하였다.
  </li>
  <li>
    Debian 프로필의 <strong>추가 설정</strong>의 <strong>모양</strong>에서
    <strong>텍스트</strong>의 <strong>글꼴</strong>에
    <strong><kbd>BitstromWera Nerd Font</kbd></strong
    >를 선택하였다. Debian 프로필의 경우 <strong>Starship</strong>을 설치하여
    Git 브랜치나 개발 환경 정보를 확인한다. 이를 제대로 표시하기 위해
    <a rel="noopener noreferrer" target="_blank" href="https://www.nerdfonts.com/">Nerd Fonts</a
    >에서 &#8216;BitstromWera Nerd Font&#8217;를 다운로드하고 설치하였다.
  </li>
  <li>
    Git Bash 프로필의 <strong>추가설정</strong>의
    <strong>터미널 에뮬레이션</strong>에서
    <strong>제목 변경 표시 안 함</strong>을 <strong>켬</strong>으로 하였다. 폴더
    이동 시 경로가 제목 표시줄에 길게 노출하는 데 끝이 잘려 나가 확인이 어렵다.
  </li>
</ul>
<h5>프로필 순서 변경하기</h5>
<p>
  최신 버전(1.16 이상)의 윈도우 터미널은 설정 화면 왼쪽 메뉴에서 드래그 앤
  드롭으로 순서를 바꿀 수 있는 기능을 지원한다. 하지만 윈도우 터미널을 관리자
  권한으로 실행한다거나 UAC(사용자 계정 컨트롤)를 꺼두는 등 시스템 환경에
  따라 이 기능이 제대로 작동하지 않는 경우가 있는 것 같다. 이럴 때는 직접
  <kbd>settings.json</kbd>
  파일을 수정하는 것이 가장 확실하다.
</p>
<p>
  설정 화면 좌측 하단의
  <strong>[JSON 파일 열기]</strong>
  를 클릭하여 파일을 연 후,
  <kbd>&quot;profiles&quot;: { &quot;list&quot;: [ ... ] }</kbd>
  내부에 나열된 프로필 블록들의 순서를 수동으로 재배치하고 저장하면 된다. 각
  블록 사이의 쉼표(
  <kbd>,</kbd>
  ) 처리에 주의하자.
</p>
<h5>관련 글</h5>
<p>
  이전에 쓴
  <a rel="noopener noreferrer" target="_blank" href="https://www.bitneer.dev/blog/windows-%ed%84%b0%eb%af%b8%eb%84%90%ec%9d%98-%ec%84%a4%ec%a0%95-%eb%b0%8f-ssh-%ec%82%ac%ec%9a%a9%ed%95%98%ea%b8%b0/">Windows 터미널의 설정 및 ssh 사용하기</a
  >
  에서 다음 내용을 참고할 수 있다.
</p>
<ul>
  <li>커서의 깜박임을 없애는 방법</li>
  <li>SSH 서버 자동 접속 상세 가이드</li>
</ul><p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/%ec%9c%88%eb%8f%84%ec%9a%b0-%ed%84%b0%eb%af%b8%eb%84%90-%ec%84%a4%ec%b9%98%ec%99%80-%ec%84%a4%ec%a0%95/">윈도우 터미널 설치와 설정</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>VS Code에 WSL의 C/C++ 개발 환경 설정하기</title>
		<link>https://www.bitneer.dev/blog/vs-code%ec%97%90-wsl%ec%9d%98-c-cpp-%ea%b0%9c%eb%b0%9c-%ed%99%98%ea%b2%bd-%ec%84%a4%ec%a0%95%ed%95%98%ea%b8%b0/</link>
		
		<dc:creator><![CDATA[Choi Kyung-sik]]></dc:creator>
		<pubDate>Mon, 22 Dec 2025 12:23:04 +0000</pubDate>
				<category><![CDATA[C/CPP]]></category>
		<category><![CDATA[cpp]]></category>
		<category><![CDATA[vscode]]></category>
		<category><![CDATA[wsl]]></category>
		<guid isPermaLink="false">https://www.bitneer.dev/?p=9948</guid>

					<description><![CDATA[<p>C/C++ 개발을 위한 확장 설치하기 C/C++ Extension Pack 확장을 설치한다. 이 확장은 데비안(Debian)의 메타 패키지와 유사하게 여러 확장을 모아 놓은 것으로, 설치 시 다음과 같은 C++ 개발 필수 확장들이 함께 설치된다. C/C++ C/C++ Themes CMake Tools 코드 분석 도구로는 Microsoft C/C++ 확장보다 clangd 확장이 더 빠르고 지능적이라는 평가를 받는다. clangd 확장을 설치할 때, 아래 그림과 같이 제작사인 LLVM을 신뢰할 것인지 ...</p>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/vs-code%ec%97%90-wsl%ec%9d%98-c-cpp-%ea%b0%9c%eb%b0%9c-%ed%99%98%ea%b2%bd-%ec%84%a4%ec%a0%95%ed%95%98%ea%b8%b0/">VS Code에 WSL의 C/C++ 개발 환경 설정하기</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h5>C/C++ 개발을 위한 확장 설치하기</h5>
<p>
  <strong>C/C++ Extension Pack</strong> 확장을 설치한다. 이 확장은
  데비안(Debian)의 메타 패키지와 유사하게 여러 확장을 모아 놓은 것으로, 설치 시
  다음과 같은 C++ 개발 필수 확장들이 함께 설치된다.
</p>
<ul>
  <li>C/C++</li>
  <li>C/C++ Themes</li>
  <li>CMake Tools</li>
</ul>
<p>
  코드 분석 도구로는 Microsoft C/C++ 확장보다 <strong>clangd</strong> 확장이 더
  빠르고 지능적이라는 평가를 받는다.
</p>
<p>
  clangd 확장을 설치할 때, 아래 그림과 같이 제작사인 LLVM을 신뢰할 것인지 묻는
  창이 나타나면 <strong>Trust Publisher &amp; Install</strong> 버튼을 클릭하여
  설치를 진행한다.
</p>
<img decoding="async"
  src="https://cdn.jsdelivr.net/gh/bitneer/wp-media-001/2025-12-21/001.png"
  alt="clangd 확장 설치시 경고 창"
/>
<p>clangd 확장 설치를 완료하면 우측 하단에 두 개의 알림 창이 나타난다.</p>
<img decoding="async"
  src="https://cdn.jsdelivr.net/gh/bitneer/wp-media-001/2025-12-21/002.png"
  alt="clangd 확장 설치시 알림 창"
/>
<ol>
  <li>
    clangd language server가 없다는 알림 창에서는
    <strong>Install</strong> 버튼을 클릭하여 설치한다.
  </li>
  <li>
    Microsoft C/C++ 확장과 clangd 확장이 충돌한다는 알림 창에서는
    <strong>Disable IntelliSense</strong> 버튼을 클릭한 후, 이어지는
    <strong>Reload</strong> 버튼을 클릭하여 VS Code 설정을 다시 불러온다.<br />
  </li>
</ol>
<p>
  이렇게 하면 Microsoft C/C++ 확장의 인텔리센스(코드 분석/자동 완성) 기능만
  비활성화되고, 디버깅 기능(GDB/LLDB 연동)은 그대로 유지되어 두 확장의 장점을
  모두 활용할 수 있다.
</p>
<h5>프로젝트 폴더에 CMakeLists.txt 파일 생성하기</h5>
<p>
  <kbd>tasks.json</kbd>이나 <kbd>launch.json</kbd> 파일을 수동으로 만들기보다
  <strong>CMake</strong>를 사용하여 빌드 시스템을 정의하는 것이 효율적이다. 최근
  대부분의 C++ 프로젝트는 CMake를 표준으로 사용한다. CMake는 빌드 파일을 직접
  생성하는 것이 아니라 <kbd>make</kbd>나 <kbd>Ninja</kbd>용 빌드 파일을 생성해
  주는 도구이다. 최신 개발 환경에서는 <kbd>cmake -G Ninja</kbd> 명령을 통해
  속도가 빠른 <strong>Ninja</strong>를 사용하는 것이 추세다.
</p>
<p>
  VS Code의 <strong>CMake Tools</strong> 확장을 활용하면 빌드, 테스트, 디버깅
  설정을 자동화할 수 있다. 이 확장은 CMake 프로젝트를 인식하면 하단 상태
  표시줄에 <em>빌드, 디버그, 실행</em> 버튼을 제공한다.
</p>
<p>
  CMake 프로젝트임을 인식시키기 위해 프로젝트 루트 폴더에
  <strong><kbd>CMakeLists.txt</kbd></strong> 파일을 생성한다. 이전 글(<a rel="noopener noreferrer" target="_blank" href="https://www.bitneer.dev/blog/wsl에-c-cpp-개발을-위한-패키지-설치하기/">WSL에 C/C++ 개발을 위한 패키지 설치하기</a
  >)에서 생성한 <kbd>wsl_cpp</kbd> 디렉터리를 그대로 사용한다.
</p>
<p>
  파일을 생성하면 곧바로 <strong>Kit</strong>을 선택하라는 창이 나타난다. 동시에
  하단 상태 표시줄에는 빌드 설정, 디버그, 실행 아이콘이 생성된다. 만약 Kit 선택
  창을 닫았다면 상태 표시줄의 <strong>Build</strong> 설정 아이콘을 클릭하여 다시
  열 수 있다.
</p>
<img decoding="async"
  src="https://cdn.jsdelivr.net/gh/bitneer/wp-media-001/2025-12-21/003.png"
  alt="kit 선택 화면 첫번째로 Clang 안나옴"
/>
<p><br /></p>
<img decoding="async"
  src="https://cdn.jsdelivr.net/gh/bitneer/wp-media-001/2025-12-21/004.png"
  alt="상태 표시줄의 CMake Tools 아이콘"
/>
<p>
  Kit 선택 창에서 사용할 컴파일러를 선택한다. 보통 Clang이나 GCC를 선택한다. 위
  그림에 <kbd>mingw32</kbd> 항목이 보이는 이유는 리눅스 환경에서 윈도우용 실행
  파일(.exe)을 만드는 크로스 컴파일 테스트를 위해 <kbd>mingw-w64</kbd> 패키지를
  설치했기 때문이다. 일반적인 리눅스 환경의 GCC를 사용하려면
  <kbd>/usr/bin/gcc</kbd>, <kbd>/usr/bin/g++</kbd> 경로가 표시된 항목을
  선택한다. 만약 Clang이 목록에 없다면 맨 위의 <strong>Scan for kits</strong>를
  실행하여 컴파일러를 새로 검색한다.
</p>
<img decoding="async"
  src="https://cdn.jsdelivr.net/gh/bitneer/wp-media-001/2025-12-21/005.png"
  alt="kit 선택 화면 두번째로 Clang 나옴"
/>
<p>
  검색 후 위 그림과 같이 Clang 컴파일러 항목이 나타나면, WSL Linux 시스템 경로인
  <kbd>/usr/bin/clang</kbd>, <kbd>/usr/bin/clang++</kbd>이 포함된 항목을
  선택한다.
</p>
<p>
  컴파일러 선택을 마치면 프로젝트 폴더에 <kbd>build</kbd> 디렉터리가 자동으로
  생성된다. 이전에 테스트로 생성했던 <kbd>a.out</kbd>이나 <kbd>hello</kbd> 실행
  파일은 삭제해도 무방하다. 앞으로 빌드 결과물은 모두 <kbd>build</kbd> 디렉터리
  안에 생성되기 때문이다. 왼쪽 액티비티 바(Activity Bar)에
  <strong>CMake</strong> 아이콘이 추가된 것도 확인할 수 있다.
</p>
<img decoding="async"
  src="https://cdn.jsdelivr.net/gh/bitneer/wp-media-001/2025-12-21/006.png"
  alt="CMake Tools의 build 디렉터리 생성"
/>
<h5>CMakeLists.txt 파일에 설정 내용 추가하기</h5>
<p>
  <kbd>CMakeLists.txt</kbd> 파일에 아무 내용도 입력하지 않으면, 아래 그림과 같이
  <strong>OUTPUT</strong> 패널의 <strong>CMake/Build</strong> 메시지에 경고가
  표시된다.
</p>
<img decoding="async"
  src="https://cdn.jsdelivr.net/gh/bitneer/wp-media-001/2025-12-21/007.png"
  alt="CMakeLists.txt에 내용이 없어 OUTPUT에 경고 메시지 출력"
/>
<p><kbd>CMakeLists.txt</kbd> 파일에 다음 내용을 추가한다.</p>
<pre class="language-none line-numbers" data-label="CMakeLists.txt">
<code>cmake_minimum_required(VERSION 3.10)
project(WSLCPP LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_executable(hello hello.cpp)</code>
</pre>
<ul>
  <li>라인 1: 최소 CMake 요구 버전 설정.</li>
  <li>라인 2: 프로젝트 이름 및 사용 언어 설정.</li>
  <li>라인 3, 4: C++17 표준 사용을 강제하는 설정.</li>
  <li>
    라인 5: clangd를 위한 컴파일 데이터베이스(<kbd>compile_commands.json</kbd>)
    생성 설정.
  </li>
  <li>
    라인 6: <kbd>hello.cpp</kbd> 소스 파일을 사용하여 <kbd>hello</kbd>라는
    이름의 실행 파일을 생성하는 설정.
  </li>
</ul>
<p>
  파일을 저장하면 <strong>OUTPUT</strong> 패널에서 설정을 자동으로 반영한다.
  만약 자동 반영이 되지 않는다면 <strong>Ctrl + Shift + P</strong>를 누른 후
  <strong>CMake: Configure</strong>를 실행한다.
</p>
<pre class="language-none" data-line="2">
<code>[main] Configuring project: wsl_cpp 
[proc] Executing command: /usr/bin/cmake -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/clang -DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/clang++ --no-warn-unused-cli -S /home/bitneer/study/CPP/wsl_cpp -B /home/bitneer/study/CPP/wsl_cpp/build -G Ninja
[cmake] Not searching for unused variables given on the command line.
[cmake] -- Configuring done
[cmake] -- Generating done
[cmake] -- Build files have been written to: /home/bitneer/study/CPP/wsl_cpp/build</code>
</pre>
<p>
  로그의 두 번째 라인에서 설정한 컴파일러와 빌드 시스템을 확인한다. 위
  예시에서는 <strong>Clang</strong>과 <strong>Ninja</strong>를 사용하고 있다.
  CMake Tools 확장은 시스템에 Ninja가 설치되어 있으면 기존의 <kbd>make</kbd>보다
  속도가 빠른 Ninja를 우선적으로 선택한다.
</p>
<p>빌드 도구를 <kbd>make</kbd>로 변경하고 싶다면 다음 과정을 따른다.</p>
<ol>
  <li>
    <strong>Ctrl + ,</strong> 키로 설정을 연 후
    <strong>Cmake: Generator</strong> 항목에 <kbd>Unix Makefiles</kbd>를
    입력한다.
  </li>
  <li>프로젝트 루트의 <kbd>build</kbd> 폴더를 삭제한다.</li>
  <li>
    <strong>Ctrl + Shift + P</strong>를 누른 후
    <strong>CMake: Configure</strong>를 실행하여 설정을 재구성한다.
  </li>
</ol>
<h5>CMake Tools 확장의 빌드와 실행</h5>
<p>
  상태 표시줄의 <strong>빌드(Build)</strong> 아이콘을 클릭하여 컴파일한 후,
  <strong>실행(Run)</strong> 아이콘을 클릭한다. 아래 그림과 같이 터미널 탭에서
  실행 결과를 확인할 수 있다.
</p>
<img decoding="async"
  src="https://cdn.jsdelivr.net/gh/bitneer/wp-media-001/2025-12-21/008.png"
  alt="CMake Tools를 사용한 빌드와 실행"
/>
<p>CMake Tools의 주요 단축키는 다음과 같다.</p>
<ul>
  <li>빌드: <strong>F7</strong></li>
  <li>디버그 없이 실행: <strong>Ctrl + Shift + F5</strong></li>
</ul>
<h5>여러 개의 main 함수 관리하기</h5>
<p>
  학습 중에는 여러 소스 파일에 각각 <kbd>main</kbd> 함수를 두고 관리하고 싶을
  때가 있다. <kbd>add_executable</kbd>을 매번 수동으로 추가하는 것은
  번거로우므로, 다음과 같은 자동화 방법을 추천한다.
</p>
<p>
  1. <kbd>CMakeLists.txt</kbd>에서 기존
  <kbd>add_executable(hello hello.cpp)</kbd> 줄을 삭제하고 아래 내용을 추가한다.
  하위 폴더를 재귀적으로 검색하여 <kbd>main_</kbd>으로 시작하는 모든 파일을
  각각의 실행 파일로 등록한다.
</p>
<pre class="language-none" data-label="CMakeLists.txt">
<code># 폴더 아래의 main_*.cpp 파일을 모두 재귀적으로 찾기
file(GLOB_RECURSE MAIN_FILES "main_*.cpp")
foreach(main_file ${MAIN_FILES})
    get_filename_component(target_name ${main_file} NAME_WE)
    add_executable(${target_name} ${main_file})
endforeach()</code>
</pre>
<p>
  2. 기존 <kbd>hello.cpp</kbd> 파일명을 <kbd>main_hello.cpp</kbd>로 변경한다.
</p>
<p>
  3. <strong>Ctrl + Shift + P</strong> 키를 누른 후
  <strong>CMake: Configure</strong>를 실행한다.
</p>
<p>
  4. 테스트를 위해 다음 내용을 가진 <kbd>main_goobye.cpp</kbd> 파일을 생성한다.
</p>

<pre class="language-cpp" data-label="main_goobye.cpp">
<code>#include &ltiostream&gt;

int main() {
    std::cout << "Goodbye, WSL!" << std::endl;
    return 0;
}</code>
</pre>
<p>
  5. 설정이 확실히 반영되도록 <strong>Ctrl + Shift + P</strong> 키를 누른 후
  <strong>CMake: Delete Cache and Reconfigure</strong>를 실행한다.
</p>
<p>
  6. 액티비티 바의 <strong>CMake</strong> 아이콘 클릭 후,
  <strong>Launch</strong> 항목의 편집 아이콘을 클릭하여 실행할 타겟을 선택한다.
</p>
<img decoding="async"
  src="https://cdn.jsdelivr.net/gh/bitneer/wp-media-001/2025-12-21/009.png"
  alt="여러개의 main 함수가 있을 때 타겟 선택"
/>
<p>
  7. 타겟을 선택한 후 상태 표시줄의 실행 아이콘을 누르면 해당 파일이 실행된다.
</p>
<p>과정이 복잡해 보인다면 단축키를 설정하여 단순화할 수 있다.</p>
<p>
  예: <strong>CMake: Delete Cache and Reconfigure</strong> 단축키
  <strong>Ctrl + Shift + F7</strong> &rarr;
  <strong>CMake: Set Launch/Debug Target</strong> 단축키
  <strong>Ctrl + Shift + F6</strong> &rarr;
  <strong>CMake: Run Without Debugging</strong> 단축키
  <strong>Ctrl + Shift + F5</strong>
</p>
<h5>코드 포맷 설정</h5>
<p>
  소스 코드에서 마우스 오른쪽 버튼을 클릭하여 <strong>Format Document</strong>를
  선택하거나 포맷 단축키를 누른다.
</p>
<img decoding="async"
  src="https://cdn.jsdelivr.net/gh/bitneer/wp-media-001/2025-12-21/010.png"
  alt="포멧터 선택시 포맷할 수 없음을 나타내는 창"
/>
<p>
  Microsoft C/C++ 확장의 인텔리센스를 비활성화했기 때문에 위와 같은 안내 창이
  뜬다. <strong>Configure</strong> 버튼을 클릭한 후 포맷터로
  <strong>clangd</strong>를 선택한다.
</p>
<img decoding="async"
  src="https://cdn.jsdelivr.net/gh/bitneer/wp-media-001/2025-12-21/011.png"
  alt="clangd를 포멧터로 선택하는 화면"
/>
<h5>.clang-format 포맷 설정</h5>
<p>
  C++ 코드 스타일은 <kbd>.clang-format</kbd> 파일로 관리하는 것이 표준이다.
  프로젝트 루트에 파일을 생성하고 다음 내용을 입력한다. 구글 스타일(Google
  Style) 기반의 예시 설정이다.
</p>

<pre class="language-yaml" data-label=".clang-format">
<code>BasedOnStyle: Google
IndentWidth: 2	# 들여쓰기 설정
ColumnLimit: 100  # 한 줄의 최대 길이 (보통 80~100자)
InsertTrailingNewline: true  # 파일 끝에 빈 줄 추가 활성화 - Clang 16 버전에서 처음 도입. 이전 버전 적용 안됨
AllowShortFunctionsOnASingleLine: Empty  # 중괄호 및 공백 설정
BreakBeforeBraces: Attach  # 구글 스타일: 함수 옆에 중괄호 붙이기</code>
</pre>
<h5>.clangd 설정</h5>
<p>
  소스 파일을 열면 하단에 <strong>clangd</strong> 확장 아이콘이 표시된다. CMake
  프로젝트의 표준인 <kbd>build</kbd> 디렉터리를 사용하면 clangd가
  <kbd>compile_commands.json</kbd>을 자동으로 찾아 코드 분석, 정의 이동,
  리팩토링 등을 수행한다.
</p>
<img decoding="async"
  src="https://cdn.jsdelivr.net/gh/bitneer/wp-media-001/2025-12-21/012.png"
  alt="상태 표시줄의 clangd 아이콘"
/>
<p>
  <kbd>.clangd</kbd> 파일은 clangd의 동작을 세밀하게 제어한다. 프로젝트 루트에
  파일을 생성하고 다음 설정을 추가해 보자.
</p>
<pre class="language-yaml" data-label=".clangd">
<code>CompileFlags:
  CompilationDatabase: build  # CMake 빌드 데이터베이스 위치 지정. build가 기본값이나 나중의 변경을 위해 명시.

Index:
  Background: Build  # 백그라운드 인덱싱 활성화. 코드 정의 이동 및 심볼 검색 속도 향상.

InlayHints:   # 코드 내 인라인 힌트 설정
  Enabled: Yes
  ParameterNames: Yes
  DeducedTypes: Yes
  Designators: Yes

Diagnostics: # 코드 진단 및 교정
  ClangTidy:
    Add: [modernize-*, readability-*, bugprone-*] 
    Remove: [modernize-use-trailing-return-type]
    CheckOptions:
      readability-identifier-naming.VariableCase: camelCase</code>
</pre>
<p>
  설정을 변경했다면 <strong>Ctrl + Shift + P</strong> 키를 누른 후
  <strong>clangd: Restart language server</strong>를 실행하여 적용한다.
</p>
<h5>관련 글</h5>
<ul>
  <li>
    <a rel="noopener noreferrer" target="_blank" href="https://www.bitneer.dev/blog/wsl에-c-cpp-개발을-위한-패키지-설치하기/">WSL에 C/C++ 개발을 위한 패키지 설치하기</a
    >
  </li>
</ul>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/vs-code%ec%97%90-wsl%ec%9d%98-c-cpp-%ea%b0%9c%eb%b0%9c-%ed%99%98%ea%b2%bd-%ec%84%a4%ec%a0%95%ed%95%98%ea%b8%b0/">VS Code에 WSL의 C/C++ 개발 환경 설정하기</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>WSL에 C/C++ 개발을 위한 패키지 설치하기</title>
		<link>https://www.bitneer.dev/blog/wsl%ec%97%90-c-cpp-%ea%b0%9c%eb%b0%9c%ec%9d%84-%ec%9c%84%ed%95%9c-%ed%8c%a8%ed%82%a4%ec%a7%80-%ec%84%a4%ec%b9%98%ed%95%98%ea%b8%b0/</link>
		
		<dc:creator><![CDATA[Choi Kyung-sik]]></dc:creator>
		<pubDate>Mon, 22 Dec 2025 12:22:45 +0000</pubDate>
				<category><![CDATA[C/CPP]]></category>
		<category><![CDATA[cpp]]></category>
		<category><![CDATA[wsl]]></category>
		<guid isPermaLink="false">https://www.bitneer.dev/?p=9941</guid>

					<description><![CDATA[<p>gcc/g++ 컴파일러 사용을 위한 개발 환경 데비안(Debian) 계열 리눅스에서 C/C++ 개발을 하고자 할 때 build-essential 패키지를 설치한다. 이 패키지는 여러 필수 패키지를 의존성으로 묶어 한 번에 설치할 수 있게 돕는 메타 패키지이다. 메타 패키지는 실제 실행 파일은 포함하지 않고 의존성 정보만 가지고 있어 &#34;빈 패키지(empty package)&#34;라고도 부른다. 다음 명령어로 의존성을 확인할 수 있다. apt는 apt-get과 apt-cache 기능을 통합한 것이므로 apt ...</p>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/wsl%ec%97%90-c-cpp-%ea%b0%9c%eb%b0%9c%ec%9d%84-%ec%9c%84%ed%95%9c-%ed%8c%a8%ed%82%a4%ec%a7%80-%ec%84%a4%ec%b9%98%ed%95%98%ea%b8%b0/">WSL에 C/C++ 개발을 위한 패키지 설치하기</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h5>gcc/g++ 컴파일러 사용을 위한 개발 환경</h5>
<p>
  데비안(Debian) 계열 리눅스에서 C/C++ 개발을 하고자 할 때
  <kbd>build-essential</kbd> 패키지를 설치한다. 이 패키지는 여러 필수 패키지를
  의존성으로 묶어 한 번에 설치할 수 있게 돕는 메타 패키지이다. 메타 패키지는
  실제 실행 파일은 포함하지 않고 의존성 정보만 가지고 있어 &quot;빈 패키지(empty
  package)&quot;라고도 부른다. 다음 명령어로 의존성을 확인할 수 있다.
  <kbd>apt</kbd>는 <kbd>apt-get</kbd>과 <kbd>apt-cache</kbd> 기능을 통합한
  것이므로 <kbd>apt depends</kbd> 대신 <kbd>apt-cache depends</kbd>를 사용할
  수도 있다.
</p>
<pre class="language-none">
<code>$ apt depends build-essential
build-essential
 |의존: libc6-dev
  의존: &lt;libc-dev&gt;
    libc6-dev
  의존: gcc (&gt;= 4:10.2)
  의존: g++ (&gt;= 4:10.2)
  의존: make
    make-guile
  의존: dpkg-dev (&gt;= 1.17.11)</code>
</pre>
<p>
  <strong><kbd>gcc</kbd></strong
  >와 <strong><kbd>g++</kbd></strong
  >은 각각 C와 C++ 컴파일러이며, <strong><kbd>make</kbd></strong
  >는 빌드 자동화 도구이다. <kbd>build-essential</kbd> 패키지는 이러한 핵심
  도구들에 의존하므로, 이를 설치하면 관련 도구들이 일괄 설치된다. 물론 필요에
  따라 이들을 개별적으로 설치하는 것도 가능하다.
</p>
<p>
  추가로 <strong><kbd>gdb</kbd></strong
  >와 <strong><kbd>cmake</kbd></strong> 패키지를 함께 설치하는 것이 좋다.
  <kbd>gdb</kbd>는 디버거이며, <kbd>cmake</kbd>는 현대적인 C/C++ 프로젝트 관리를
  위한 표준 빌드 시스템 생성기이다. 특히 VS Code의 &#8216;CMake Tools&#8217; 확장을 제대로
  활용하기 위해서는 <kbd>cmake</kbd> 설치가 필수적이다.
</p>
<p>
  패키지 설치 전에는 다음과 같이 패키지 목록 업데이트와 시스템 업그레이드를 먼저
  수행한다.
</p>
<pre class="language-none">
<code>$ sudo apt update && sudo apt upgrade</code>
</pre>
<p>
  참고로 논리 AND(<kbd>&amp;&amp;</kbd>)는 앞선 명령이 성공했을 때만 뒷 명령을
  실행하라는 의미이다. 이와 반대로 논리 OR(<kbd>||</kbd>)은 앞선 명령이 실패했을
  때만 뒷 명령을 실행한다. (예: 명령이 실패할 경우 에러 메시지를 출력할 때 주로
  사용한다.)
</p>
<p>C/C++ 개발에 필요한 패키지들을 다음과 같이 설치한다.</p>
<pre class="language-none">
<code>$ sudo apt install build-essential gdb cmake</code>
</pre>
<p>
  이미 설치된 패키지가 있다면 자동으로 제외하고 중복 설치하지 않는다. 다만, 새
  패키지를 설치하는 과정에서 의존성 해결을 위해 기존 패키지가 업그레이드될 수는
  있다.
</p>
<p>
  <kbd>dpkg -l</kbd> 명령은 시스템에 설치된 모든 패키지 목록을 보여준다. 다음과
  같이 파이프(<kbd>|</kbd>)와 <kbd>grep</kbd>을 연결하여 특정 패키지의 설치
  여부를 확인할 수 있다.
</p>
<pre class="language-none">
<code>$ dpkg -l | grep cmake
ii  cmake                              3.25.1-1                       amd64        cross-platform, open-source make system
ii  cmake-data                         3.25.1-1                       all          CMake data files (modules, templates and documentation)</code>
</pre>
<p>
  또는 다음과 같이 버전 정보를 출력하여 설치 여부를 확인하거나, 실행 파일의
  위치를 알려주는 <kbd>which</kbd> 명령어를 사용할 수 있다.
</p>
<pre class="language-none">
<code>$ gcc --version
$ g++ --version
$ make --version
$ cmake --version
$ which g++</code>
</pre>
<h5>Clang 컴파일러 사용을 위한 개발 환경</h5>
<p>
  GCC 대신 애플(Apple)이 주도하여 개발한 Clang 컴파일러를 사용할 수도 있다.
  Clang은 에러 메시지가 매우 명확하고 친절하며, Apache 2.0 라이선스를 채택해
  기업 친화적이고 유연하다. 반면 GCC는 대부분의 리눅스 배포판 커널과 기본
  시스템을 빌드하는 검증된 컴파일러이며, 런타임 성능 최적화가 매우 정교하다.
  또한 GCC는 GPL 라이선스를 따르므로 소스 코드 공개 의무와 전염성이 강하다는
  특징이 있다.
</p>
<p>
  일반적으로 학습용이나 개발 단계에서는 친절한 에러 메시지 덕분에 오타나 문법
  실수를 빠르게 교정할 수 있는 Clang을 사용하고, 실제 배포용 빌드에는 GCC를
  사용하는 하이브리드 전략을 취하기도 한다. C++ 표준은 계속 발전하고 있지만,
  GCC와 Clang 모두 최신 표준을 빠르게 도입하고 있으므로 어떤 것을 선택해도 최신
  문법 활용에는 지장이 없다.
</p>
<p>
  Clang으로 개발 환경을 구축할 때는 가급적 Clang 기반의 전체 도구
  세트(Toolchain)를 갖추는 것이 좋다. 주요 패키지 목록은 다음과 같다.
</p>
<ul>
  <li><strong>clang</strong>: 컴파일러</li>
  <li><strong>lldb</strong>: 디버거</li>
  <li><strong>valgrind</strong>: 메모리 분석 도구</li>
  <li><strong>clang-format</strong>: 코드 스타일 정리 도구</li>
  <li><strong>clang-tidy</strong>: 정적 분석 도구</li>
</ul>
<p>위 패키지들을 다음 명령으로 한 번에 설치한다.</p>
<pre class="language-none">
<code>$ sudo apt install clang lldb valgrind clang-format clang-tidy</code>
</pre>
<h5>Ninja 빌드 시스템 설치</h5>
<p>
  현대적인 C++ 개발 환경에서 Ninja는 이미 <kbd>make</kbd>를 대체하는 표준으로
  자리 잡았다. 대규모 오픈 소스 프로젝트를 분석할 때 &#8216;컴파일
  데이터베이스(<kbd>compile_commands.json</kbd>)&#8217; 파일을 생성해야 VS Code의
  &#8216;C/C++&#8217; 확장이나 &#8216;clangd&#8217; 확장에서 코드 바로가기, 자동 완성 기능을 정확히
  제공할 수 있다.
</p>
<p>
  이 파일을 생성하기 위해 기존의 <kbd>make</kbd>와 <kbd>bear</kbd>를 조합하는
  방법과 <kbd>Ninja</kbd> 빌드 시스템을 사용하는 두 가지 방법이 있다. 리눅스
  커널이나 고전적인 C 라이브러리 등 오래된 프로젝트를 분석한다면
  <kbd>make</kbd> + <kbd>bear</kbd> 조합이 적합하며, 현대적인 프로젝트라면
  <kbd>Ninja</kbd>를 사용하는 것이 효율적이다.
</p>
<p>
  다음과 같이 <kbd>bear</kbd>와 <kbd>ninja-build</kbd> 패키지를 설치하고, 가급적
  <kbd>make</kbd> 대신 <kbd>Ninja</kbd>를 주력으로 사용하도록 한다.
</p>
<pre class="language-none">
<code>$ sudo apt install bear ninja-build</code>
</pre>
<h5>예제 작성과 컴파일 테스트</h5>
<p>
  VS Code의 C/C++ 관련 확장을 설치하기 전, 간단한 예제를 작성하여
  명령줄(CLI)에서 설치한 컴파일러가 잘 작동하는지 확인해 본다. 윈도우 터미널을
  통해 WSL에 접속한 후 프로젝트 디렉터리를 생성하고 이동한다.
</p>
<pre class="language-none">
<code>$ mkdir wsl_cpp
$ cd wsl_cpp</code>
</pre>
<p>
  <kbd>vi</kbd>나 VS Code를 사용하여 다음 내용을 입력하고
  <kbd>hello.cpp</kbd>라는 이름으로 저장한다. 해당 디렉터리에서
  <kbd>code .</kbd> 명령을 실행하면 현재 폴더를 작업 영역으로 하여 VS Code가
  열린다.
</p>
<pre class="language-cpp" data-label="hello.cpp">
<code>#include &ltiostream&gt;

int main() {
    std::cout << "Hello, WSL!" << std::endl;
    return 0;
}</code>
</pre>
터미널에서 <strong><kbd>g++</kbd></strong
>을 사용하여 컴파일하고 실행해 본다.
<pre class="language-none">
<code>$ g++ hello.cpp
$ ./a.out
Hello, WSL!</code>
</pre>
<p>
  별도의 옵션 없이 컴파일하면 실행 파일 이름은 기본적으로 <kbd>a.out</kbd>으로
  생성된다. 실행 시 <kbd>./</kbd>와 같이 현재 디렉터리를 명시해야 하는데, 이는
  유닉스 계열 시스템이 보안상의 이유로 현재 디렉터리를 실행
  경로(<kbd>PATH</kbd>)에 포함하지 않기 때문이다. 반면 윈도우의 명령
  프롬프트(CMD)는 현재 디렉터리를 실행 경로에 포함한다는 차이가 있다. 현재 실행
  경로는 <kbd>echo $PATH</kbd> 명령어로 확인할 수 있다.
</p>
<p>
  다음과 같이 <kbd>-o</kbd> 옵션을 사용하면 생성될 실행 파일의 이름을 직접
  지정할 수 있다.
</p>
<pre class="language-none">
<code>$ g++ -o hello hello.cpp
$ ./hello
Hello, WSL!</code>
</pre>
<p>
  Clang의 경우 C 컴파일러는 <strong><kbd>clang</kbd></strong
  >, C++ 컴파일러는 <strong><kbd>clang++</kbd></strong> 명령어를 사용한다.
  다음과 같이 여러 옵션을 붙여 컴파일해 본다. (이 옵션들은 <kbd>g++</kbd>에서도
  동일하게 사용할 수 있다.)
</p>
<pre class="language-none">
<code>$ clang++ -Wall -std=c++17 -g -o hello hello.cpp
$ ./hello
Hello, WSL!</code>
</pre>
<ul>
  <li><strong>-Wall</strong>: 모든 경고(Warning) 메시지를 출력한다.</li>
  <li><strong>-std=c++17</strong>: 사용할 C++ 표준 버전을 명시한다.</li>
  <li>
    <strong>-g</strong>: 디버깅 정보를 포함하여 <kbd>gdb</kbd>나
    <kbd>lldb</kbd>에서 사용할 수 있게 한다. (최종 제품 배포 시에는 이 옵션을
    제외한다.)
  </li>
</ul>
<p>
  이외에도 최적화 단계를 지정하는 옵션 등이 있으며, 이러한 설정값들은 주로
  <kbd>Makefile</kbd>이나 <kbd>Ninja</kbd> 빌드 파일에서 정의하여 사용한다.
</p>
<p>
  과거에는 유닉스나 리눅스 환경에서 <kbd>vi</kbd>, <kbd>Emacs</kbd> 같은
  에디터만으로 작업해야 했고, 파이썬이 보급되기 전에는 복잡한 빌드 과정을
  관리하기 위해 쉘 스크립트를 직접 작성해야 했다.
</p>
<p>
  이제는 VS Code 덕분에 훨씬 편리한 환경에서 개발이 가능해졌다. VS Code에서
  C/C++ 개발 관련 확장을 설치하고, 보다 효율적으로 개발 환경을 구축하는 방법으로
  넘어가 보자.
</p>
<h5>관련 글</h5>
<ul>
  <li>
    <a rel="noopener noreferrer" target="_blank" href="https://www.bitneer.dev/blog/vs-code에-wsl의-c-cpp-개발-환경-설정하기/">VS Code에 WSL의 C/C++ 개발 환경 설정하기</a
    >
  </li>
</ul>
<h5>참고 자료</h5>
<ul>
  <li>
    <a rel="noopener noreferrer" target="_blank" href="https://gcc.gnu.org/">https://gcc.gnu.org/</a
    >
  </li>
  <li>
    <a rel="noopener noreferrer" target="_blank" href="https://clang.llvm.org/">https://clang.llvm.org/</a
    >
  </li>
  <li>
    <a rel="noopener noreferrer" target="_blank" href="https://cmake.org/cmake/help/latest/">CMake Reference Documentation</a
    >
  </li>
  <li>
    <a rel="noopener noreferrer" target="_blank" href="https://ninja-build.org/">https://ninja-build.org/</a
    >
  </li>
  <li>
    <a rel="noopener noreferrer" target="_blank" href="https://github.com/rizsotto/Bear">https://github.com/rizsotto/Bear</a
    >
  </li>
</ul>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/wsl%ec%97%90-c-cpp-%ea%b0%9c%eb%b0%9c%ec%9d%84-%ec%9c%84%ed%95%9c-%ed%8c%a8%ed%82%a4%ec%a7%80-%ec%84%a4%ec%b9%98%ed%95%98%ea%b8%b0/">WSL에 C/C++ 개발을 위한 패키지 설치하기</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>트랜잭션의 격리 수준</title>
		<link>https://www.bitneer.dev/blog/%ed%8a%b8%eb%9e%9c%ec%9e%ad%ec%85%98%ec%9d%98-%ea%b2%a9%eb%a6%ac-%ec%88%98%ec%a4%80/</link>
		
		<dc:creator><![CDATA[Choi Kyung-sik]]></dc:creator>
		<pubDate>Sun, 28 Jun 2020 03:17:03 +0000</pubDate>
				<category><![CDATA[데이터베이스 시스템]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[mariadb]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[postgresql]]></category>
		<category><![CDATA[transaction]]></category>
		<guid isPermaLink="false">https://www.bitneer.dev/?p=664</guid>

					<description><![CDATA[<p>트랜잭션의 격리 수준을 이해하기 위한 배경 지식으로 트랜잭션, 고립성, 이상현상을 먼저 살펴본다. 트랜잭션의 개요 데이터베이스의 여러 연산을 묶어 놓은 것을 사용자의 관점에서는 하나의 단위로 여겨질 수 있다. 예를 들어, 다른 계좌로 돈을 이체하는 것은 사용자의 관점에서 하나의 작업이지만, 데이터베이스 시스템 내에서는 여러 연산을 결합한 것이다. 이처럼, 하나의 논리적인 작업 단위를 위한 연산들의 모음을 트랜잭션(transaction)이라 한다. 데이터의 무결성(integrity)을 보장하려면, 데이터베이스 시스템은 ...</p>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/%ed%8a%b8%eb%9e%9c%ec%9e%ad%ec%85%98%ec%9d%98-%ea%b2%a9%eb%a6%ac-%ec%88%98%ec%a4%80/">트랜잭션의 격리 수준</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>
  트랜잭션의 격리 수준을 이해하기 위한 배경 지식으로 트랜잭션, 고립성,
  이상현상을 먼저 살펴본다.
</p>
<h5>트랜잭션의 개요</h5>
<p>
  데이터베이스의 여러 연산을 묶어 놓은 것을 사용자의 관점에서는 하나의 단위로
  여겨질 수 있다. 예를 들어, 다른 계좌로 돈을 이체하는 것은 사용자의 관점에서
  하나의 작업이지만, 데이터베이스 시스템 내에서는 여러 연산을 결합한 것이다.
  이처럼, 하나의 논리적인 작업 단위를 위한 연산들의 모음을
  <em>트랜잭션(transaction)</em>이라 한다.
</p>
<p>
  데이터의 무결성(integrity)을 보장하려면, 데이터베이스 시스템은 트랜잭션의
  다음과 같은 특성을 관리해야 한다.
</p>
<ul>
  <li>
    <strong>원자성(atomicity):</strong> 트랜잭션의 모든 연산을 데이터베이스에
    반영하든지, 아니면 전혀 반영하지 않아야 한다.
  </li>
  <li>
    <strong>일관성(consistency):</strong> 고립 상태에 있는 트랜잭션의 실행은
    데이터베이스의 일관성을 유지해야 한다. 고립 상태란 동시에 실행하는 다른
    트랜잭션이 없다는 것을 의미한다.
  </li>
  <li>
    <strong>고립성(isolation):</strong> 여러 개의 트랜잭션을 동시에
    실행하더라도, 각 트랜잭션은 동시에 실행하고 있는 다른 트랜잭션을 인식하지
    못해야 한다.
  </li>
  <li>
    <strong>지속성(durability):</strong> 트랜잭션이 성공적으로 끝나면, 그
    트랜잭션이 데이터베이스 시스템에 수정한 내용은 시스템 장애가 발생하더라도
    영속적이어야 한다.
  </li>
</ul>
<p>위의 특성 중에 격리 수준과 관련한 고립성에 대해 좀 더 알아보자.</p>
<h5>고립성</h5>
<p>
  여러 개의 트랜잭션을 동시에 실행하면 성능이 좋아진다. 그러나 여러 트랜잭션의
  연산이 원하지 않는 방향으로 겹쳐 <em>불일치 상태(inconsistent state)</em>가
  발생할 수 있다. 동시에 실행하는 트랜잭션의 문제를 해결하는 방법은 트랜잭션을
  순차적으로 실행하는 것이다. 트랜잭션의 <em>고립성(isolation)</em>은 여러 개의
  트랜잭션을 동시에 실행하여도, 이 트랜잭션들을 순차적으로 실행한 것과 같은
  상태가 되도록 하는 특성이다.
</p>

<h5>이상현상</h5>
<p>
  <em>이상현상(Phenomena)</em>은 동시 실행하는 여러 트랜잭션이 상호 작용하면서
  나타날 수 있는 문제를 의미한다. 읽기 이상현상으로 dirty read, non-repeatable
  read, phantom read 세 가지가 있다. 쓰기 이상현상으로 lost update가 있다.
  이상현상을 예제로 보이기 위해 간단한 student 테이블을 사용할 것이다.
</p>
<table>
  <colgroup>
    <col />
    <col />
    <col />
  </colgroup>
  <tbody>
    <tr>
      <th>id</th>
      <th>name</th>
      <th>age</th>
    </tr>
    <tr>
      <td>1</td>
      <td>홍길동</td>
      <td>20</td>
    </tr>
    <tr>
      <td>2</td>
      <td>임꺽정</td>
      <td>25</td>
    </tr>
  </tbody>
</table>
<h6>Dirty Read</h6>
<p>
  dirty read는 한 트랜잭션이 진행 중에, 다른 트랜잭션이
  <strong><em>갱신</em></strong
  >은 하였으나 아직 commit하지 않은 데이터를 읽을 때 발생한다.
</p>
<table>
  <colgroup>
    <col />
    <col />
  </colgroup>
  <tbody>
    <tr>
      <th>T1</th>
      <th>T2</th>
    </tr>
    <tr>
      <td>SELECT age FROM students WHERE id = 1;</td>
      <td></td>
    </tr>
    <tr>
      <td></td>
      <td>UPDATE students SET age = 21 where id = 1;</td>
    </tr>
    <tr>
      <td>SELECT age FROM students WHERE id = 1; /* 21을 읽는다 */</td>
      <td></td>
    </tr>
    <tr>
      <td></td>
      <td>ROLLBACK;</td>
    </tr>
  </tbody>
</table>
<p>
  T2 트랜잭션에서 갱신은 하였으나 아직 커밋하지 않은 나이인 21을 T1 트랜잭션이
  읽는다. T2에서 롤백하면 결국 T1은 이상한 값을 읽어 들인 셈이다.
</p>
<h6>Non-repeatable Read</h6>
<p>
  non-repeatable read는 한 트랜잭션이 읽었던 데이터를 다시 읽을 때 데이터가
  변경되는 것으로, 다시 읽기 전에 다른 트랜잭션이 데이터를
  <strong><em>갱신</em></strong
  >하고 <strong><em>commit</em></strong
  >하기 때문에 발생한다. dirty read와 비슷해 보이지만 다른 트랜잭션에서 commit을
  한다는 차이점이 있다.
</p>
<table>
  <colgroup>
    <col />
    <col />
  </colgroup>
  <tbody>
    <tr>
      <th>T1</th>
      <th>T2</th>
    </tr>
    <tr>
      <td>SELECT age FROM students WHERE id = 1; /* 20을 읽는다 */</td>
      <td></td>
    </tr>
    <tr>
      <td></td>
      <td>UPDATE students SET age = 21 where id = 1; COMMIT;</td>
    </tr>
    <tr>
      <td>SELECT age FROM students WHERE id = 1; /* 21을 읽는다 */ COMMIT;</td>
      <td></td>
    </tr>
  </tbody>
</table>
<p>
  T1 트랜잭션 내에서 age가 20과 21 두 개의 값을 갖는다. 의도하지 않은 결과가
  발생할 수 있을 것이다.
</p>
<h6>Phantom Read</h6>
<p>
  phantom read는 우리말로 &#8216;유령 읽기&#8217; 정도로 바꿀 수 있겠다. 유령 읽기는 한
  트랜잭션이 진행 중에, 다른 트랜잭션이 <strong><em>추가</em></strong
  >하거나 <strong><em>삭제</em></strong
  >한 <strong><em>행(row)</em></strong
  >의 데이터를 읽어 발생한다.
</p>
<table>
  <colgroup>
    <col />
    <col />
  </colgroup>
  <tbody>
    <tr>
      <th>T1</th>
      <th>T2</th>
    </tr>
    <tr>
      <td>SELECT * FROM students WHERE age BETWEEN 10 AND 30;</td>
      <td></td>
    </tr>
    <tr>
      <td></td>
      <td>
        INSERT INTO students(id, name, age) VALUES(3, &#8216;장길산&#8217;, 28); COMMIT;
      </td>
    </tr>
    <tr>
      <td>SELECT * FROM students WHERE age BETWEEN 10 AND 30; COMMIT;</td>
      <td></td>
    </tr>
  </tbody>
</table>
<p>T1 트랜잭션에서 의도하지 않은 &#8216;장길산&#8217; 이름을 가진 3번째 행이 나온다.</p>
<h6>Lost Update(Dirty Write)</h6>
<p>
  Lost Update는 &#8216;갱신 손실&#8217;로 대역할 수 있겠다. 갱신 손실은 한 트랜잭션이
  데이터를 갱신한 후 다른 트랜잭션이 그 갱신한 값을 덮어쓸 때 발생한다. 다음의
  예는 한 고객이 잔고가 1000원 계좌에서 500원을 인출하고 있는데 동업자가 400원을
  동시에 출금하는 예이다.
</p>
<table>
  <colgroup>
    <col />
    <col />
    <col />
    <col />
  </colgroup>
  <tbody>
    <tr>
      <th colspan="2">Transaction 1</th>
      <th colspan="2">Transaction 2</th>
    </tr>
    <tr>
      <td>read(balance) balance = balance &#8211; 500</td>
      <td colspan="1">1000 500</td>
      <td></td>
      <td colspan="1"></td>
    </tr>
    <tr>
      <td></td>
      <td colspan="1"></td>
      <td>read(balance) balance = balance &#8211; 400</td>
      <td colspan="1">1000 400</td>
    </tr>
    <tr>
      <td>write(balance)</td>
      <td colspan="1">500</td>
      <td></td>
      <td colspan="1"></td>
    </tr>
    <tr>
      <td colspan="1"></td>
      <td colspan="1"></td>
      <td colspan="1">write(balance)</td>
      <td colspan="1">600</td>
    </tr>
  </tbody>
</table>
<p>
  잔고에 100원이 남아야 정상이지만 갱신 손실로 600원이 남았다. 위의 예에서 SQL
  문을 사용하지 않고 수식으로 표현하였다. MariaDB, PostgreSQL에서 확인한 바로는
  한 트랜잭션이 갱신을 한 상태에서 다른 트랜잭션이 동일 데이터에 갱신을 시도하면
  대기를 하여야 한다. 즉, 데이터를 갱신한 트랜잭션이 commit이나 rollback을 하기
  전에는 다른 트랜잭션은 동일 데이터를 갱신할 수 없다. 대부분의 DBMS 제품들은
  모든 격리 수준에서 갱신 시 테이블이나 행(row)에 락(lock)을 걸어 lost update가
  발생하지 않도록 하고 있다.
</p>
<h5>격리 수준(Isolation Level)</h5>
<p>
  동시에 실행하는 트랜잭션들을 순차적인 실행 상태로 만드는 것은 성능에 좋지
  않다. 성능과 일관성을 고려하여 트랜잭션에 격리 수준을 지정할 수 있다. SQL
  표준은 네 종류의 트랜잭션 격리 수준을 정의하고 있다. 다음 항목에서 아래로
  내려갈수록 일관성은 좋아지지만, 성능은 떨어진다.
</p>
<ul>
  <li>
    <strong>read uncommited:</strong> 다른 트랜잭션에서 commit하지 않은 데이터를
    읽을 수 있다. 데이터의 정확도가 중요하지 않으면서 트랜잭션의 수행 시간이 긴
    경우에 지정하여 사용할 수 있다.
  </li>
  <li>
    <strong>read commited:</strong> 다른 트랜잭션에서 commit한 데이터만을
    읽는다.
  </li>
  <li>
    <strong>repeatable read:</strong> read commited와 동일하게 다른 트랜잭션에서
    commit한 데이터만을 읽는다. 추가로 트랜잭션 진행 중에 읽었던 데이터를 다시
    읽을 때, 그 중간에 다른 트랜잭션이 그 데이터를 갱신할 수 없다.
  </li>
  <li>
    <strong>serializable:</strong> 동시 진행하는 트랜잭션들이 순차적으로 실행한
    것과 같은 결과가 나와야 한다. <em>직렬성(serializability)</em>에 더하여 연쇄
    복귀(rollback)도 없어야 한다.
  </li>
</ul>
<p>
  SQL 표준은 <strong>serializable</strong>이 디폴트이다. 이 수준은 트랜잭션 간에
  상호 작용이 전혀 없어야 하는 데 현실과는 맞지 않는다. 일반적인 데이터베이스
  시스템은 <strong>read commited</strong>나 <strong>repeatable read</strong>를
  디폴트로 사용한다. 또한, DBMS 제품마다 표준을 구현하는 방법은 다를 수 있다.
</p>
<p>아래의 표는 각 격리 수준에서 발생할 수 있는 이상현상을 나타낸 것이다.</p>
<table>
  <colgroup>
    <col />
    <col />
    <col />
    <col />
  </colgroup>
  <tbody>
    <tr>
      <th></th>
      <th>Dirty Read</th>
      <th>Non-repeatable Read</th>
      <th>Phantom Read</th>
    </tr>
    <tr>
      <th>Read Uncommitted</th>
      <td style="background-color: #ffebe6">발생할 수 있음</td>
      <td style="background-color: #ffebe6">발생할 수 있음</td>
      <td style="background-color: #ffebe6">발생할 수 있음</td>
    </tr>
    <tr>
      <th>Read Committed</th>
      <td style="background-color: #deebff">발생하지 않음</td>
      <td style="background-color: #ffebe6">발생할 수 있음</td>
      <td style="background-color: #ffebe6">발생할 수 있음</td>
    </tr>
    <tr>
      <th>Repeatable Read</th>
      <td style="background-color: #deebff">발생하지 않음</td>
      <td style="background-color: #deebff">발생하지 않음</td>
      <td style="background-color: #ffebe6">발생할 수 있음</td>
    </tr>
    <tr>
      <th>Serializable</th>
      <td style="background-color: #deebff">발생하지 않음</td>
      <td style="background-color: #deebff">발생하지 않음</td>
      <td style="background-color: #deebff">발생하지 않음</td>
    </tr>
  </tbody>
</table>
<p>
  MySQL의 InnoDB엔진은 repeatable read 격리 수준에서 phantom read가 발생하지
  않는다.
</p>
<p>
  PostgreSQL도 마찬가지로 repeatable read 격리 수준에서 phantom read가 발생하지
  않는다. 또한 트랜잭션을 read uncommitted로 설정은 할 수 있지만, dirty read는
  발생하지 않는다.
</p>
<h5>참고 자료</h5>
<ul>
  <li>
    <a href="https://www.amazon.com/gp/product/0070310866?pf_rd_r=QVPWASZQQQVJ3P915ZHY&amp;pf_rd_p=6fc81c8c-2a38-41c6-a68a-f78c79e7253f" target="_blank" rel="noopener noreferrer">Database System Concepts, 3rd</a
    >
    &#8211; Chapter 13 Transactions
  </li>
  <li>
    <a href="https://en.wikipedia.org/wiki/Isolation_(database_systems)" target="_blank" rel="noopener noreferrer">Isolation (database systems) &#8211; Wikipedia</a
    >
  </li>
  <li>
    <a href="https://postgresql.kr/docs/11/transaction-iso.html" target="_blank" rel="noopener noreferrer">PostgreSQL 11.1 문서 &#8211; 13.2. 트랜잭션 격리</a
    >
  </li>
  <li>
    <a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html" target="_blank" rel="noopener noreferrer">MySQL :: MySQL 8.0 Reference Manual :: 15.7.2.1 Transaction Isolation
      Levels</a
    >
  </li>
  <li>
    <a href="https://mariadb.com/kb/en/mariadb-transactions-and-isolation-levels-for-sql-server-users/#isolation-levels-and-locks" target="_blank" rel="noopener noreferrer">MariaDB Transactions and Isolation Levels for SQL Server Users &#8211; MariaDB
      Knowledge Base</a
    >
  </li>
</ul>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/%ed%8a%b8%eb%9e%9c%ec%9e%ad%ec%85%98%ec%9d%98-%ea%b2%a9%eb%a6%ac-%ec%88%98%ec%a4%80/">트랜잭션의 격리 수준</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>데비안 9(Stretch)에서 10(Buster)으로 업그레이드 시 주의 사항</title>
		<link>https://www.bitneer.dev/blog/%eb%8d%b0%eb%b9%84%ec%95%88-9stretch%ec%97%90%ec%84%9c-10buster%ec%9c%bc%eb%a1%9c-%ec%97%85%ea%b7%b8%eb%a0%88%ec%9d%b4%eb%93%9c-%ec%8b%9c-%ec%a3%bc%ec%9d%98-%ec%82%ac%ed%95%ad/</link>
		
		<dc:creator><![CDATA[Choi Kyung-sik]]></dc:creator>
		<pubDate>Wed, 17 Jun 2020 04:38:57 +0000</pubDate>
				<category><![CDATA[네트워크와 시스템 관리]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[network]]></category>
		<category><![CDATA[postgresql]]></category>
		<category><![CDATA[upgrade]]></category>
		<guid isPermaLink="false">https://www.bitneer.dev/?p=649</guid>

					<description><![CDATA[<p>데비안 9에서 데비안 10으로 업그레이드 하면서 내가 부딪쳤던 문제들을 정리해 본다. eth0 네트워크 인터페이스 이름의 미지원 네트워크 인터페이스 이름으로 eth0 등을 사용하고 있다면 데비안 10으로 업그레이드하기 전에 새로운 방식의 이름으로 변경해 주어야 한다. 이에 대한 이해를 위해 네트워크 인터페이스에 이름을 부여하는 방법의 변화 과정을 보자. 원래의 간단한 체계(Original Simple Scheme)는 리눅스 커널이 단순히 eth0, eth1 등으로 이름을 붙인다. 이 체계의 ...</p>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/%eb%8d%b0%eb%b9%84%ec%95%88-9stretch%ec%97%90%ec%84%9c-10buster%ec%9c%bc%eb%a1%9c-%ec%97%85%ea%b7%b8%eb%a0%88%ec%9d%b4%eb%93%9c-%ec%8b%9c-%ec%a3%bc%ec%9d%98-%ec%82%ac%ed%95%ad/">데비안 9(Stretch)에서 10(Buster)으로 업그레이드 시 주의 사항</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>
  데비안 9에서 데비안 10으로 업그레이드 하면서 내가 부딪쳤던 문제들을 정리해
  본다.
</p>
<h5>eth0 네트워크 인터페이스 이름의 미지원</h5>
<p>
  네트워크 인터페이스 이름으로 <kbd><strong>eth0</strong></kbd> 등을 사용하고
  있다면 데비안 10으로 업그레이드하기 전에 새로운 방식의 이름으로 변경해 주어야
  한다. 이에 대한 이해를 위해 네트워크 인터페이스에 이름을 부여하는 방법의 변화
  과정을 보자. <em>원래의 간단한 체계(Original Simple Scheme)</em>는 리눅스
  커널이 단순히 eth0, eth1 등으로 이름을 붙인다. 이 체계의 문제는 부팅 후에
  eth0과 eth1의 이름이 서로 바뀔 수 있다는 점이다. 이 문제를 해결하기 위한 여러
  방법이 생겨났는데 그중의 하나가
  <em>영속적인 이름 체계(Persistent Names Scheme)</em>이다. 이 체계는 Mac 주소를
  사용하여 고정된 eth0 등의 이름을 부여한다. 이 체계도 완전하지 않고 특히
  가상머신(virtualization)에서 문제가 있다. 그래서 나온 것이 펌웨어/BIOS에서
  제공하는 정보를 사용하는
  <em>예측가능한 이름 체계(Predictable Name Scheme)</em>이다.
</p>
<p>
  데비안 5(Lenny) 즈음부터 영속적인 이름 체계를 사용해 왔다. 데비안
  9(Stretch)에서 예측가능한 이름 체계가 들어 왔다. 데비안 9를 새로 설치하면
  예측가능한 이름 체계를 사용한다. &#8216;<strong>ip a</strong>&#8216; 명령어를 실행하면
  기존의 eth0 대신 하드웨어에 따라 달라지는 <kbd>eno1, enp0s1, wlp1s0</kbd> 등의
  이름을 볼 수 있을 것이다. 새로 설치하는 것이 아니라 업그레이드로 데비안 9까지
  왔다면 여전히 영속적인 이름 체계를 사용할 것이다.
  <kbd>/etc/udev/rules.d/70-persistent-net.rules</kbd> 파일의 존재로 확인할 수
  있다.
</p>
<p>
  데비안 10(Buster)에서 <em>실제 제작자(upstream)</em>가 영속적인 이름 체계를
  공식적으로 지원하지 않는다.
  <a href="https://wiki.debian.org/NetworkInterfaceNames" target="_blank" rel="noopener noreferrer">NetworkInterfaceNames &#8211; Debian Wiki</a
  >
  페이지에서는 영속적인 이름 체계를 데비안 10까지는 사용할 수 있고 데비안
  11(Bullseye) 무렵에 완전히 없어질 것이라 나온다.
  <a href="https://www.debian.org/releases/buster/releasenotes" target="_blank" rel="noopener noreferrer">데비안 10 &#8212; 릴리스 노트</a
  >
  5장에서는 영속적인 이름 체계가 가능할지도 모르지만, 위험할 수 있어 새로운
  이름으로 변경할 것을 권고하고 있다. 어쨌든 영속적인 이름 체계는 피하는 것이
  나을 것이고 이에 대한 몇 가지 방법이 있다.
</p>
<h6>1. 원래의 간단한 체계 사용하기</h6>
<p>
  네트워크 인터페이스를 하나만 가지고 있고 예측가능한 이름 체계를 싫어한다면
  원래의 간단한 체계를 사용할 수 있는 다양한 방법이 있다. 그러나 이것이 지속
  가능할지는 알 수 없다. 다음에서 커널의 옵션을 설정하는 방법을 설명한다.
</p>
<p>
  1.1. <kbd>/etc/default/grub</kbd> 파일의
  <strong><kbd>GRUB_CMDLINE_LINUX_DEFAULT</kbd></strong
  >의 값으로 <strong><kbd>"net.ifnames=0"</kbd></strong
  >을 추가한다.
</p>
<pre class="language-none">
<code>GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet net.ifnames=0&quot;</code>
</pre>
<p>1.2. update-grub 명령어를 실행한다.</p>
<pre class="language-none">
<code># update-grub</code>
</pre>
<p>
  데비안 9를 새로 설치했다면 위까지 작업한 후 시스템을 재시작하면 eth0을 사용할
  수 있을 것이다. 그러나 영속적인 이름 체계를 사용하여
  <kbd>/etc/udev/rules.d/70-persistent-net.rules</kbd> 파일을 가지고 있다면
  추가적인 작업이 필요하다.
</p>
<p>
  1.3.
  <kbd>/etc/udev/rules.d/70-persistent-net.rules</kbd> 파일을 삭제하거나 이름을
  바꾼다.
</p>
<pre class="language-none line-numbers" data-line="2">
<code># cd /etc/udev/rules.d
# mv 70-persistent-net.rules 70-persistent-net.rules.old</code>
</pre>
<p>1.4. 다음의 명령어로 initrd를 재생성한다.</p>
<pre class="language-none line-numbers" data-line="1">
<code># update-initramfs -u
...</code>
</pre>
<p>1.5. 시스템을 재시작한다.</p>
<pre class="language-none">
<code># systemctl reboot</code>
</pre>

<h6>2. ssh로 접속하여 예측가능한 이름 체계로 변경하기</h6>
<p>
  ssh로 접속하여 원격 시스템의 네트워크 인터페이스 이름을 바꾸는 것은 신중하게
  해야 한다. 오타 하나 때문에 ssh로 접속할 수 없는 불상사가 발생한다. 내가
  사용하는 시스템이 모니터와 키보드 없이 구석에 자리하고 있는데 작업에서 실수가
  발생한다면 상당히 귀찮을 것이다. 시스템이 모니터와 키보드를 가지고 있어 콘솔로
  직접 접근할 수 있다면 작업은 좀 더 편할 것이다. 다음의 설명 중 @reboot cronjob
  등은 콘솔을 가지고 있다면 생략할 수 있으므로 참작하여 보자.
</p>
<p>
  2.1. 먼저 자신이 현재 사용하고 있는 네트워크 인터페이스 이름을 확인한다.
  여기에는 다양한 방법들이 있다.
</p>
<pre class="language-none">
<code># ip a
# cat /etc/udev/rules.d/70-persistent-net.rules
# echo /sys/class/net/[ew]*</code>
</pre>
<p>
  2.2. 영속적인 이름 체계에서 특별한 경우가 아니라면 eth0을 사용하고 있을
  것이다. 다음의 명령어로 eth0을 사용하고 있는 설정 파일들을 찾는다.
</p>
<pre class="language-none">
<code># grep -r eth0 /etc
...</code>
</pre>
<p>
  위의 결과로 나온 대부분은 주석으로 처리한 것이고 실제 변경이 필요한 파일은
  <strong><kbd>/etc/network/interfaces</kbd></strong
  >일 것이다.
</p>
<p>
  2.3. 다음의 명령어로 예측가능한 이름 체계에서 사용할 네트워크 인터페이스
  이름을 찾는다.
</p>
<pre class="language-none" data-line="1,4">
<code># udevadm test-builtin net_id /sys/class/net/eth0 2&gt; /dev/null
ID_NET_NAME_MAC=enxf46d04d4b9f6
ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
ID_NET_NAME_PATH=enp3s0</code>
</pre>
<p>
  라인 4에서 나온 <kbd>enp3s0</kbd>이 내가 앞으로 사용해야 할 이름이다. 여러분이
  가지고 있는 하드웨어에 따라 이름은 달라질 것이다. VirtualBox 가상머신의
  데비안은 enp0s3 이름이 나온다.
</p>
<p>2.4. 다음으로 진행하기 전에 무언가 잘못되었을 때를 위한 대비책을 세우자!</p>
<p>2.4.1. 다음의 스크립트는 아래에서 작업할 내용을 복구하는 스크립트이다.</p>
<pre
  class="language-none line-numbers"
  data-line="3,7,8,10,11"
  data-label="/root/revoke_net.sh"
>
<code>#!/bin/bash

sleep 5m

ip a &gt;&gt; /root/network_interfaces.txt
mv -f /etc/network/interfaces /etc/network/interfaces.fail
cp -a -f /etc/network/interfaces.bak /etc/network/interfaces
cp -a -f /etc/udev/rules.d/70-persistent-net.rules.old /etc/udev/rules.d/70-persistent-net.rules
#cp -a -f /root/99-default.link /etc/systemd/network/99-default.link
update-initramfs -u
systemctl reboot</code>
</pre>
<p>
  이 스크립트를 부팅 시 실행할 수 있게 Crontab에 등록할 것이다. 라인 3은 5분을
  대기하기 위한 것이다. 시스템을 재시작하고 ssh로 접속을 할 수 있는지 확인한다.
  접속에 성공하면 이 스크립트를 실행하는 프로세스를 찾아 죽여야 한다. ssh 접속에
  실패한다면 5분 후 라인 5부터 복구 작업을 시작한다. 라인 5는 &#8216;ip -a&#8217; 명령어로
  네트워크 인터페이스의 이름을 확인하기 위한 것이다. 라인 6은 네트워크 이름
  <kbd>enp3s0</kbd>으로 변경했던 /etc/network/interfaces 파일의 이름을 변경하여
  보관해 둔다. 라인 7에서 기존의 eth0 이름을 가진 /etc/network/interfaces로
  복구한다. 라인 8은 /etc/udev/rules.d/70-persistent-net.rules 파일을 복구한다.
  라인 9는 가상머신에 설치한 데비안을 위한 것이다. 가상머신의 데비안을
  사용한다면 라인 8을 주석 처리하고 라인 9의 주석을 제거한다. 라인 10에서
  initrd를 재생성한다. 라인 11에서 시스템을 재시작한다. 시스템을 재시작하면
  기존의 eth0으로 다시 접속할 수 있을 것이다. 접속하자마자 위의 실행 프로세스를
  찾아 죽여야 한다.
</p>
<p>2.4.2. 다음의 명령으로 위에서 작성한 스크립트에 실행 모드를 추가한다.</p>
<pre class="language-none">
<code># chmod +x /root/revoke_net.sh</code>
</pre>
<p>
  2.4.3. <strong>crontab -e</strong> 명령어를 사용하여 다음의 내용을 추가한 후
  저장한다.
</p>
<pre class="language-none line-numbers" data-line="1,3">
<code># crontab -e
...
@reboot /root/revoke_net.sh</code>
</pre>
<p>
  <strong>crontab -l</strong> 명령어를 실행하여 제대로 등록하였는지 확인해 볼 수
  있다.
</p>
<p>2.5. /etc/network/interfaces 파일을 복구에 사용할 수 있도록 백업해 둔다.</p>
<pre class="language-none">
<code># cp -a /etc/network/interfaces /etc/network/interfaces.bak</code>
</pre>
<p>
  /etc/network/interfaces 파일에서 eth0을 2.3.에서 나온 <kbd>enp3s0</kbd>으로
  변경한다.
</p>
<pre class="language-none line-numbers" data-line="2,3">
<code>...
auto enp3s0
iface enp3s0 inet static
...</code>
</pre>
<p>
  2.6. <kbd>/etc/udev/rules.d/70-persistent-net.rules</kbd> 파일의 이름을
  바꾼다. 가상머신의 데비안이라면 /etc/systemd/network/99-default.link 파일을
  /root 디렉토리로 옮겨준다.
</p>
<pre class="language-none line-numbers" data-line="2">
<code># cd /etc/udev/rules.d
# mv 70-persistent-net.rules 70-persistent-net.rules.old</code>
</pre>
<p>2.7. 다음의 명령어로 initrd를 재생성한다.</p>
<pre class="language-none line-numbers" data-line="1">
<code># update-initramfs -u
...</code>
</pre>
<p>2.8. 시스템을 재시작한다.</p>
<pre class="language-none">
<code># systemctl reboot</code>
</pre>
<p>
  2.9. ssh로 접속해 본다. 접속에 성공한다면 다음과 같이 revoke_net.sh 스크립트를
  실행하는 프로세스를 찾아 죽인다.
</p>
<pre class="language-none line-numbers" data-line="1,3,5">
<code># ps -ef | grep revoke
root       723   717  0 14:58 ?        00:00:00 /bin/sh -c /root/revoke_net.sh
root       724   723  0 14:58 ?        00:00:00 /bin/bash /root/revoke_net.sh
root      1849  1779  0 14:58 pts/0    00:00:00 grep revoke
# kill -9 724
# ps -ef | grep revoke
root      1917  1779  0 14:59 pts/0    00:00:00 grep revoke</code>
</pre>
<p>
  2.10. &#8216;<strong>ip a</strong>&#8216; 명령어로 네트워크 인터페이스의 이름이
  <kbd>enp3s0</kbd>으로 나오는지 확인해 본다.
</p>
<p>
  2.11. 성공적으로 작업을 마쳤으면 정리에 들어간다.
  <strong>crontab -e</strong> 명령어를 사용하여 2.4.3.에서 추가한 &#8216;<kbd
    >@reboot /root/revoke_net.sh</kbd
  >&#8216;를 삭제한 후 저장한다. <strong>crontab -l</strong> 명령어로 확인해 본다.
  <kbd>/etc/network/interfaces.bak</kbd> 파일을 삭제한다.
  <kbd>/etc/udev/rules.d/70-persistent-net.rules.old</kbd> 파일은 따로
  보관하거나 삭제한다.
</p>
<h5>기존의 PostgreSQL 데이터베이스는 reindex 필요</h5>
<p>
  데비안 10은 <kbd>glibc</kbd> 로케일 데이터를 업그레이드하기 때문에
  PostgreSQL의 기존 데이터베이스에 대한 인덱스를 다시 만들어야 한다. 가능하다면
  PostgreSQL의 데이터베이스를 사용하는 응용 프로그램을 업그레이드가 끝날 때까지
  잠시 중단하는 것이 좋을 것이다. 업그레이드를 완료한 즉시 다음의 명령어를
  실행한다.
</p>
<pre class="language-none line-numbers" data-line="1">
<code># sudo -u postgres reindexdb --all
...</code>
</pre>

<h5>관련 글</h5>
<ul>
  <li>
    <a href="https://www.bitneer.dev/wp/%eb%8d%b0%eb%b9%84%ec%95%88%ec%9d%84-%ec%83%88-%eb%b2%84%ec%a0%84%ec%9c%bc%eb%a1%9c-%ec%97%85%ea%b7%b8%eb%a0%88%ec%9d%b4%eb%93%9c%ed%95%98%ea%b8%b0/" target="_blank" rel="noopener noreferrer">데비안을 새 버전으로 업그레이드하기</a
    >
  </li>
</ul>
<h5>참고 자료</h5>
<ul>
  <li>
    <a href="https://wiki.debian.org/NetworkInterfaceNames" target="_blank" rel="noopener noreferrer">NetworkInterfaceNames &#8211; Debian Wiki</a
    >
  </li>
  <li>
    <a href="https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/" target="_blank" rel="noopener noreferrer">Predictable Network Interface Names</a
    >
  </li>
  <li>
    <a href="https://www.freedesktop.org/software/systemd/man/systemd.net-naming-scheme.html" target="_blank" rel="noopener noreferrer">systemd.net-naming-scheme — Network device naming schemes</a
    >
  </li>
  <li>
    <a href="https://www.debian.org/releases/buster/releasenotes" target="_blank" rel="noopener noreferrer">데비안 10 &#8212; 릴리스 노트</a
    >
  </li>
</ul><p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/%eb%8d%b0%eb%b9%84%ec%95%88-9stretch%ec%97%90%ec%84%9c-10buster%ec%9c%bc%eb%a1%9c-%ec%97%85%ea%b7%b8%eb%a0%88%ec%9d%b4%eb%93%9c-%ec%8b%9c-%ec%a3%bc%ec%9d%98-%ec%82%ac%ed%95%ad/">데비안 9(Stretch)에서 10(Buster)으로 업그레이드 시 주의 사항</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>데비안을 새 버전으로 업그레이드하기</title>
		<link>https://www.bitneer.dev/blog/%eb%8d%b0%eb%b9%84%ec%95%88%ec%9d%84-%ec%83%88-%eb%b2%84%ec%a0%84%ec%9c%bc%eb%a1%9c-%ec%97%85%ea%b7%b8%eb%a0%88%ec%9d%b4%eb%93%9c%ed%95%98%ea%b8%b0/</link>
		
		<dc:creator><![CDATA[Choi Kyung-sik]]></dc:creator>
		<pubDate>Wed, 17 Jun 2020 01:14:36 +0000</pubDate>
				<category><![CDATA[네트워크와 시스템 관리]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[upgrade]]></category>
		<guid isPermaLink="false">https://www.bitneer.dev/?p=285</guid>

					<description><![CDATA[<p>데비안은 정교한 패키지 관리 시스템을 가지고 있어 한 번 설치하면 재설치 없이 계속해서 새 버전으로 업그레이드할 수 있다. 이 글을 쓰는 데 사용하고 있는 시스템은 2011년 즈음에 버전 5.0(Lenny)을 설치한 이래로 버전 10(Buster)까지 왔다. 데비안은 게으른 사람에게 더할 나위 없는 리눅스 배포판이다. 현재 사용하는 버전 안에서의 업그레이드는 apt update &#38;&#38; apt upgrade 명령어로 한껏 여유를 부릴 수 있다. 새 버전으로 ...</p>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/%eb%8d%b0%eb%b9%84%ec%95%88%ec%9d%84-%ec%83%88-%eb%b2%84%ec%a0%84%ec%9c%bc%eb%a1%9c-%ec%97%85%ea%b7%b8%eb%a0%88%ec%9d%b4%eb%93%9c%ed%95%98%ea%b8%b0/">데비안을 새 버전으로 업그레이드하기</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>
  데비안은 정교한 패키지 관리 시스템을 가지고 있어 한 번 설치하면 재설치 없이
  계속해서 새 버전으로 업그레이드할 수 있다. 이 글을 쓰는 데 사용하고 있는
  시스템은 2011년 즈음에 버전 5.0(Lenny)을 설치한 이래로 버전 10(Buster)까지
  왔다. 데비안은 게으른 사람에게 더할 나위 없는 리눅스 배포판이다. 현재 사용하는
  버전 안에서의 업그레이드는
  <strong>apt update &amp;&amp; apt upgrade</strong> 명령어로 한껏 여유를 부릴
  수 있다.
</p>
<p>
  <em>새 버전</em>으로 업그레이드하려면 조금은 부지런해야 한다. 제일 먼저
  업그레이드할 버전의 <em>릴리스 노트(Release Notes)</em>를 읽어 봐야 한다.
  릴리스 노트의 페이지 주소는
  <kbd
    >https://www.debian.org/releases/<strong>&lt;코드네임&gt;</strong>/releasenotes</kbd
  >다. 코드네임이 buster라면
  <a href="https://www.debian.org/releases/buster/releasenotes" target="_blank" rel="noopener noreferrer">https://www.debian.org/releases/buster/releasenotes</a
  >
  주소로 접속할 수 있다. 데비안 릴리스의 버전 넘버와 코드네임은
  <a href="https://wiki.debian.org/DebianReleases" target="_blank" rel="noopener noreferrer">DebianReleases &#8211; Debian Wiki</a
  >에서 볼 수 있다. 코드네임은 개발 단계에서 사용하고 이후에 버전 넘버를 붙인다.
  4.0(Etch) 이후로 버전 넘버는 1씩 규칙적으로 증가했지만, 그전에는 그렇지
  않았다.
</p>
<p>
  릴리스 노트의 PDF 문서는 50쪽 정도의 분량을 가진다. 아쉽게도 한글 번역 문서는
  없다. 그러나 새 버전으로 업그레이드하는 것이 처음이라면 한 번 읽어 볼 것을
  추천한다. 전체적인 내용을 통해 자신만의 업그레이드 절차를 만들어 보기를
  바란다. 다음번에 업그레이드할 때는 <strong>2장</strong>에서 새 버전의 전체적인
  내용을 대강 훑고, <strong>5장</strong>에서 자신이 설치한 패키지에 따라 영향을
  받을만한 것이 있는지 정도만 본다. 나머지 장의 내용은 거의 변하지 않기
  때문이다.
</p>
<p>
  이 글은 나의 관점에서 데비안을 새 버전으로 업그레이드할 때 릴리스 노트에
  기반하여 필요한 사전 지식과 절차를 정리한 것이다.
</p>
<h5>단계적 업그레이드</h5>
<p>
  버전 간의 업그레이드는 단계적으로 해야 한다. 예를 들면, 버전 8(Jessie)에서
  버전 10(Buster)으로 업그레이드하려면 먼저 버전 9(Stretch)로 업그레이드한 후
  다시 Buster로 업그레이드한다. 데비안 개발자가 직전 버전에서 새 버전으로
  업그레이드하는 것만을 테스트하기 때문에 단계적으로 업그레이드할 것을 제안하는
  것으로 보인다.
</p>
<h5>버전 업그레이드 시 추천하는 패키지 관리 도구</h5>
<p>
  릴리스 노트 <strong>4장</strong>에서 새 버전으로 업그레이드할 때 추천하는
  패키지 관리 도구는 가끔 달라질 때가 있다. <strong>aptitude</strong>를 추천한
  적도 있지만, 대부분은 <strong>apt-get</strong> 사용을 권장해 왔다. 데비안
  10(Buster)에서 처음으로 <strong>apt</strong>를 추천한다. apt는 apt-get과
  apt-cache의 기능을 합치고, 출력할 때 색깔을 사용하여 눈을 즐겁게 해준다.
  그러나 색깔이 들어간 코드로 인해 파싱 등을 위한 스크립트에서 사용하기에
  부적절하다. 다음은 업그레이드와 관련하여 apt-get을 apt로 대체할 수 있는 명령어
  목록이다.
</p>
<ul>
  <li>apt-get update → apt update</li>
  <li>apt-get upgrade → apt upgrade</li>
  <li>apt-get dist-upgrade → apt full-upgrade</li>
</ul>
<h5>/etc 설정 충돌</h5>
<p>
  /etc 디렉토리는 데비안 개발자(패키지 메인테이너)와 사용자가 충돌하는 영역이다.
  패키지에 중요한 설정의 변화가 있을 수 있다. 예를 들면 Apache 2.2에서 2.4로
  변경되었을 때 설정에 많은 차이가 있었다. 업그레이드 시 마지막 단계인 패키지의
  설정에서 이러한 충돌을 마주칠 것이다. 패키지 개발자의 설정으로 대체할 것인지
  사용자의 설정을 유지할 것인지 선택을 묻는다. 대부분 패키지 개발자의 설정으로
  대체하는 것이 좋다. 그러고 나서 나중에 내가 원하는 설정으로 변경해 준다. 내가
  했던 설정은 <kbd>.dpkg-old, .ucf-old</kbd> 등의 확장자를 가진 파일로 남아 있을
  것이다.
</p>
<p>
  업그레이드를 진행 중일 때는 정신이 없어서 어떤 패키지에서 무엇을 선택했는지
  잊어버릴 때가 있다. 그리고 간간이 보이는 경고 메시지도 신경 쓰인다. 화면이
  빠르게 지나가기 때문에 메시지를 잡아내기도 힘들다. 따라서
  <strong>script</strong> 프로그램으로 진행 상황을 기록하는 것이 좋다.
</p>
<p>script의 사용 방법을 간단히 알아보자.</p>
<pre class="language-none line-numbers" data-line="1,2,7,9">
<code># script --timing=test.time test.script
Script started, file is test.script
# free
              total        used        free      shared  buff/cache   available
Mem:       16345836     8126580     1408848     1259412     6810408     6622112
Swap:       2579452        1352     2578100
# exit
exit
Script done, file is test.script
#</code>
</pre>
<p>
  라인 1에서 script 명령어를 실행한다. <kbd>--timing=test.time</kbd> 옵션은
  <strong>scriptreplay</strong>에서 사용하기 위해 시간을 저장하는 것이다. 라인
  2에서 스크립트가 시작되었음을 알려 준다. 라인 3에서 free 명령어를 사용하여
  메모리의 정보를 본다. script의 기록을 위한 예제로 아무 명령어나 실행해 보자.
  라인 7에서 <strong>exit</strong> 명령어를 사용하여 script의 실행을 끝낸다.
  우리가 했던 행동은 <kbd>test.scirpt</kbd> 파일에 저장하고 있다.
</p>
<pre class="language-none" data-line="1">
<code># scriptreplay test.time test.script
# free
              total        used        free      shared  buff/cache   available
Mem:       16345836     8126580     1408848     1259412     6810408     6622112
Swap:       2579452        1352     2578100
# exit
exit

#</code>
</pre>
<p>
  script에서 <kbd>--timing</kbd> 옵션을 사용하였다면 라인 1과 같이 scriptreplay
  명령어로 우리가 했던 행동을 볼 수 있다. 데비안의 업그레이드 과정은 내용이
  많아서 scriptreplay로 한가하게 다시 보기를 하지는 않을 것이다. 스크립트
  파일(test.script)을 편집기로 보면서 검토하는 것이 빠르다.
</p>
<p>
  데비안 10에서 추천하는 &#8216;<strong>apt full-upgrade</strong>&#8216; 명령어는 색깔이
  들어가 있는 코드 때문에 script 프로그램하고는 맞지 않는다. 대신에
  <kbd><strong>/var/log/apt/term.log</strong></kbd> 파일에서 우리가 했던
  행동들을 볼 수 있다.
</p>
<h5>screen 사용</h5>
<p>
  ssh로 접속하여 업그레이드한다면 <strong>screen</strong>을 사용해야 한다.
  네트워크 관련 패키지를 업그레이드할 때 ssh 세션이 끊어질 수 있기 때문이다.
  또는 ssh 클라이언트를 사용하는 윈도우 운영체제의 컴퓨터가 업그레이드하면서
  컴퓨터를 다시 시작해 버릴 수도 있다. ssh 세션이 끊기면 ssh 서버 프로세스에서
  포크한 bash 쉘도 종료하고 업그레이드 작업이 중단될 것이다.
</p>
<p>
  screen 사용법에 대해 간단히 알아보자. screen을 설치하지 않았다면 다음의
  명령어로 screen 패키지를 설치한다.
</p>
<pre class="language-none">
<code># apt install screen</code>
</pre>
<p>
  다음과 같이 screen 명령어를 실행한다. 실행 후 <kbd>&lt;Space&gt;</kbd>나
  <kbd>&lt;Return&gt;</kbd> 키를 눌러 작업을 시작한다.
</p>
<pre class="language-none">
<code># screen</code>
</pre>
<p>
  현재 상태를 유지하면서 screen 세션에서 빠져나오려면
  <kbd>&lt;Ctrl + a&gt;</kbd> 키를 누른 후 이어서 <kbd>&lt;d&gt;</kbd> 키를
  누른다. (detach)
</p>
<p>
  다시 이전에 작업하던 screen 세션으로 들어가려면 다음의 명령어를 실행한다.
  (reattach) 업그레이드 도중 ssh 세션이 끊어져 다시 접속했을 때에도 다음의
  명령어를 실행하여 작업을 계속할 수 있다.
</p>
<pre class="language-none" data-line="1">
<code># screen -Dr</code>
</pre>
<p>
  screen 세션을 종료하려면 screen의 쉘에서 exit 명령어를 실행한다. 또는
  <kbd>&lt;Ctrl + a&gt;</kbd> 키에 이어서 <kbd>&lt;k&gt;</kbd> 키를 누른 후
  종료를 확인하는 메시지가 나오면 <kbd>y</kbd>를 입력한다.
</p>
<pre class="language-none">
<code># exit</code>
</pre>

<h5>sources.list와 서드파티 저장소</h5>
<p>
  새 버전으로 업그레이드하려면 <kbd>/etc/apt/sources.list</kbd> 파일을 변경해야
  한다. 다음은 데비안 9(Stretch)의 sources.list 파일의 예이다.
</p>
<pre class="language-none" data-label="/etc/apt/sources.list">
<code># stretch
deb http://deb.debian.org/debian/ stretch main contrib non-free
deb-src http://deb.debian.org/debian/ stretch main contrib non-free

# stretch - security updates
deb http://security.debian.org/debian-security stretch/updates main contrib non-free
deb-src http://security.debian.org/debian-security stretch/updates main contrib non-free

# stretch-updates
deb http://deb.debian.org/debian/ stretch-updates main contrib non-free
deb-src http://deb.debian.org/debian/ stretch-updates main contrib non-free</code>
</pre>
<p>
  <kbd>stretch</kbd> 코드네임을 업그레이드하려는 <kbd>buster</kbd>로 모두
  변경하면 된다.
</p>
<p>
  데비안에 없는 패키지를 제공하는 비공식 APT 저장소를 서드파티
  저장소(third-party repository)라고 부른다. 나의 경우
  <a href="https://adoptopenjdk.net/installation.html#linux-pkg" target="_blank" rel="noopener noreferrer">AdoptOpenJDK</a
  >,
  <a href="https://docs.microsoft.com/en-us/dotnet/core/install/linux-debian" target="_blank" rel="noopener noreferrer">.NET Core SDK</a
  >,
  <a href="https://github.com/nodesource/distributions/blob/master/README.md#debinstall" target="_blank" rel="noopener noreferrer">Node.js</a
  >,
  <a href="https://www.virtualbox.org/wiki/Linux_Downloads" target="_blank" rel="noopener noreferrer">VirtualBox</a
  >
  네 개가 있다. 일반적으로 서드파티 저장소의 GPG 키는
  <kbd>/etc/apt/trusted.gpg</kbd> 파일이나
  <kbd>/etc/apt/trusted.gpg.d</kbd> 디렉토리에 추가하고 저장소의 설정은
  <kbd>/etc/apt/sources.list</kbd> 파일이나
  <kbd>/etc/apt/sources.list.d</kbd> 디렉토리에 추가한다. 나는 일관성을 위해
  저장소의 설정은 <kbd>/etc/apt/sources.list.d</kbd> 디렉토리에 다음의 파일로
  관리한다. 파일 이름은 .list 확장자를 가져야 한다.
</p>
<ul>
  <li>adoptopenjdk.list</li>
  <li>microsoft-prod.list</li>
  <li>nodesource.list</li>
  <li>virtualbox.list</li>
</ul>
<p>
  새 버전으로 업그레이드하려면 위의 파일들도 수정해 주어야 한다. 몇 가지 예를
  보자. 다음은 데비안 9(Stretch)의 <kbd>nodesource.list</kbd> 파일의 내용이다.
</p>
<pre
  class="language-none"
  data-line="1"
  data-label="/etc/apt/sources.list.d/nodesource.list"
>
<code>deb https://deb.nodesource.com/node_10.x stretch main
deb-src https://deb.nodesource.com/node_10.x stretch main</code>
</pre>
<p>
  위의 <kbd>stretch</kbd> 코드네임을 업그레이드하려는 <kbd>buster</kbd>로
  변경해야 한다.
  <a href="https://deb.nodesource.com/node_10.x/dists/buster/" target="_blank" rel="noopener noreferrer">https://deb.nodesource.com/node_10.x/dists/buster/</a
  >
  주소로 접속하여 <em>buster 저장소</em>의 존재를 확인할 수 있다. 저장소 설정의
  URL에서 <kbd><strong>dists</strong></kbd
  >는 관례로 생략하기 때문에 실제 주소에는 추가해야 한다.
</p>
<p>
  마이크로소프트의 .NET Core 저장소는 특이하게 URL에 데비안의 버전 넘버가 있다.
  다음은
  <kbd>microsoft-prod.list</kbd> 파일의 내용이다.
</p>
<pre
  class="language-none"
  data-line="1"
  data-label="/etc/apt/sources.list.d/microsoft-prod.list"
>
<code>deb [arch=amd64] https://packages.microsoft.com/debian/9/prod stretch main</code>
</pre>
<p>
  코드네임을 <kbd>buster</kbd>로 변경하는 것에 더하여
  <strong><kbd>9</kbd></strong
  >를 <strong><kbd>10</kbd></strong
  >으로 수정해야 한다.
  <a href="https://packages.microsoft.com/debian/10/prod/dists/buster/" target="_blank" rel="noopener noreferrer">https://packages.microsoft.com/debian/10/prod/dists/buster/</a
  >
  주소로 접속하여 저장소를 확인할 수 있다.
</p>
<h5>업그레이드 절차</h5>
<p>
  새 버전으로 업그레이드하는 것은 보통 2년 정도의 주기를 가진다. 긴 기간 동안
  업그레이드 작업 절차는 잊히기 쉽고 한 번만 하고 끝나는 것이 아니므로 정리해 둘
  필요가 있다.
</p>
<ol>
  <li>
    <kbd>https://www.debian.org/releases/&lt;코드네임&gt;/releasenotes</kbd>에서
    릴리스 노트를 확인한다. <strong>2장</strong>에서 새 버전의 전체적인 내용을
    대강 훑고, <strong>5장</strong>에서 문제가 발생할 만한 것이 있는지 본다.
    <strong>4장</strong>에서 추천하는 패키지 관리 도구 정도를 확인한다.
  </li>
  <li>
    데이터와 설정 정보들을 백업한다. 나의 경우 데이터베이스를 포함하여 서버
    전체를 백업하는 스크립트를 사용한다.
  </li>
  <li>
    <kbd>/etc/apt/sources.list</kbd> 파일에서 현재 코드네임을 업그레이드할
    코드네임으로 변경한다.
  </li>
  <li>
    <kbd>/etc/apt/sources.list.d</kbd> 디렉토리에서 서드파티 저장소에 대한 설정
    파일을 변경한다.
  </li>
  <li>
    screen을 실행한다.
    <pre class="language-none">
<code># screen</code>
</pre>
  </li>
  <li>
    script를 실행한다.
    <pre class="language-none">
<code># script --timing=upgrade.time upgrade.script</code>
</pre>
  </li>
  <li>
    패키지 리스트를 업데이트한다.
    <pre class="language-none">
<code># apt update</code>
</pre>
  </li>
  <li>
    최소한의 시스템 업그레이드를 실행한다.
    <pre class="language-none">
<code># apt-get upgrade</code>
</pre>
  </li>
  <li>
    시스템 업그레이드를 실행한다.
    <pre class="language-none">
<code># apt full-upgrade</code>
</pre>
  </li>
  <li>
    업그레이드 진행 중에 발생했던 <kbd>/etc</kbd> 디렉토리의 설정 충돌을
    해결한다. 데비안 개발자의 설정에 자신이 원하는 설정을 추가한다.
    <kbd><strong>/var/log/apt/term.log</strong></kbd
    >나 <strong><kbd>upgrade.script</kbd></strong> 파일을 참고할 수 있다.
  </li>
  <li>
    script를 종료하고 screen 세션을 종료한다.
    <pre class="language-none">
<code># exit
...
# exit</code>
</pre>
  </li>
  <li>
    새로운 커널을 반영하기 위해 시스템을 재시작한다.

    <pre class="language-none">
<code># systemctl reboot</code>
</pre>
  </li>
  <li>
    삭제한 패키지의 설정 파일이 남아 있는 것을 찾아 제거한다.
    <pre class="language-none">
<code># aptitude search '~c'
# aptitude purge '~c'</code>
</pre>
  </li>
  <li>
    aptitude를 실행하고
    <strong>Obsolete and Locally Created Packages</strong> 카테고리에서 쓸모가
    없어진 패키지를 선택적으로 삭제한다.
  </li>
</ol>
<h5>참고 자료</h5>
<ul>
  <li>
    <a href="https://wiki.debian.org/DebianReleases" target="_blank" rel="noopener noreferrer">DebianReleases - Debian Wiki</a
    >
  </li>
  <li>
    <a href="https://www.debian.org/releases/buster/releasenotes" target="_blank" rel="noopener noreferrer">데비안 10 -- 릴리스 노트</a
    >
  </li>
  <li>
    <a href="https://wiki.debian.org/SourcesList" target="_blank" rel="noopener noreferrer">SourcesList - Debian Wiki</a
    >
  </li>
  <li>
    <a href="https://wiki.debian.org/DebianRepository/UseThirdParty" target="_blank" rel="noopener noreferrer">DebianRepository/UseThirdParty - Debian Wiki</a
    >
  </li>
  <li>
    <a href="https://www.debian.org/doc/manuals/debian-faq/index.en.html" target="_blank" rel="noopener noreferrer">The Debian GNU/Linux FAQ</a
    >
  </li>
  <li>
    <a href="https://www.debian.org/doc/manuals/debian-reference/" target="_blank" rel="noopener noreferrer">Debian Reference</a
    >
  </li>
</ul>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/%eb%8d%b0%eb%b9%84%ec%95%88%ec%9d%84-%ec%83%88-%eb%b2%84%ec%a0%84%ec%9c%bc%eb%a1%9c-%ec%97%85%ea%b7%b8%eb%a0%88%ec%9d%b4%eb%93%9c%ed%95%98%ea%b8%b0/">데비안을 새 버전으로 업그레이드하기</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>데비안의 MariaDB 설치와 설정</title>
		<link>https://www.bitneer.dev/blog/%eb%8d%b0%eb%b9%84%ec%95%88%ec%9d%98-mariadb-%ec%84%a4%ec%b9%98%ec%99%80-%ec%84%a4%ec%a0%95/</link>
		
		<dc:creator><![CDATA[Choi Kyung-sik]]></dc:creator>
		<pubDate>Wed, 10 Jun 2020 23:21:35 +0000</pubDate>
				<category><![CDATA[데이터베이스 시스템]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[mariadb]]></category>
		<guid isPermaLink="false">https://www.bitneer.dev/?p=627</guid>

					<description><![CDATA[<p>데비안 9(Stretch)부터 MariaDB는 디폴트 MySQL 변종이다. 즉, MariaDB가 기존의 MySQL을 완전히 대체한다. 데비안 8(Jessie)의 MySQL 버전은 5.5이다. 내가 사용하는 Confluence 등이 MySQL 5.5를 지원하지 않았기 때문에 MySQL Community의 MySQL 5.6을 설치해야 했다. 최근에 Confluence, Jira, Bitbucket의 MySQL 데이터베이스를 PostgreSQL로 이전하였다. 워드프레스의 데이터베이스만이 MySQL에 남았다. 워드프레스는 현재 공식적으로 MySQL과 MariaDB만을 지원한다. 정교한 데비안 패키지 관리의 이점을 얻기 위해 MariaDB로 돌아갈 것이다. ...</p>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/%eb%8d%b0%eb%b9%84%ec%95%88%ec%9d%98-mariadb-%ec%84%a4%ec%b9%98%ec%99%80-%ec%84%a4%ec%a0%95/">데비안의 MariaDB 설치와 설정</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>
  데비안 9(Stretch)부터 MariaDB는 <em>디폴트 MySQL</em> 변종이다. 즉, MariaDB가
  기존의 MySQL을 완전히 대체한다. 데비안 8(Jessie)의 MySQL 버전은 5.5이다. 내가
  사용하는 Confluence 등이 MySQL 5.5를 지원하지 않았기 때문에
  <a href="https://www.mysql.com/products/community/" target="_blank" rel="noopener noreferrer">MySQL Community</a
  >의 MySQL 5.6을 설치해야 했다. 최근에 Confluence, Jira, Bitbucket의 MySQL
  데이터베이스를 PostgreSQL로 이전하였다. 워드프레스의 데이터베이스만이 MySQL에
  남았다. 워드프레스는 현재 공식적으로 MySQL과 MariaDB만을 지원한다. 정교한
  데비안 패키지 관리의 이점을 얻기 위해 MariaDB로 돌아갈 것이다. MariaDB 설치 후
  처음에 마주칠 수 있는 unix_socket 인증과 튜닝 등의 설정을 정리해 본다.
</p>
<h5>MariaDB 설치</h5>
<p>
  MySQL Community의 MySQL 패키지를 설치했다면 완전히 삭제하는 것이 필요하다.
  패키지의 의존성 문제로 삭제에 애를 먹을 수 있는데
  <strong>apt-get remove &#8211;purge &#8216;mysql-.*&#8217;</strong> 명령어를 사용하여 mysql
  관련 패키지를 모두 제거하는 편법을 사용해야 한다.
  <em>패키지를 삭제하기 전에</em> mysqldump로 데이터베이스를 백업하고 /etc/mysql
  디렉토리 안의 my.cnf 등 설정 파일을 백업하는 것이 좋을 것이다.
</p>
<p>
  데비안 9(Stretch) 또는 10(Buster)에서
  <strong>apt install mariadb-server</strong> 명령어로 MariaDB를 설치할 수 있다.
  데비안 9는 MariaDB 10.1을 데비안 10은 MariaDB 10.3을 설치할 것이다.
</p>
<pre class="language-none line-numbers" data-line="2">
<code># apt update
# apt install mariadb-server</code>
</pre>
<p>
  데비안 패키지와 관련한 문서는
  <kbd>/usr/share/doc/&lt;패키지 이름&gt;</kbd> 디렉토리에 위치한다. 패키지 설치
  후 가장 먼저 찾아볼 문서이다. 참고로 README는 <em>실제 제작자(upstream)</em>의
  문서이고, README.Debian은 <em>데비안 개발자</em>(패키지 메인테이너)가 제공하는
  문서이다. MariaDB 서버와 관련하여 볼 만한 문서는
  <kbd>/usr/share/doc/mariadb-server-10.1</kbd> 또는
  <kbd>/usr/share/doc/mariadb-server-10.3</kbd> 디렉토리 안의
  <strong>README.Debian.gz</strong> 파일이다. gzip으로 압축이 되어 있으므로
  zmore나 zcat 명령어로 보거나 윈도우 운영체제에서는 7-Zip 등으로 압축을 풀어
  편집 프로그램을 사용하여 본다.
</p>
<pre class="language-none line-numbers" data-line="1">
<code># zmore /usr/share/doc/mariadb-server-10.3/README.Debian.gz
...
# zcat /usr/share/doc/mariadb-server-10.3/README.Debian.gz &gt; ~/mariadb-server.README.Debian</code>
</pre>

<h5>systemd</h5>
<p>
  MariaDB는 버전 10.1.8부터 systemd unit 파일을 제공한다. 데비안 패키지에서
  <kbd>/lib/systemd/system/mariadb.service</kbd> 파일이 이에 해당한다.
  mariadb.service는 편리를 위해 <kbd>mysql.service, mysqld.service</kbd> 별칭을
  가진다. systemctl 사용시 .service 접미사는 생략할 수 있다. 따라서 다음과 같이
  systemctl 명령어를 사용하여 MariaDB 서비스의 시작, 종료 등을 할 수 있다.
</p>
<pre class="language-none">
<code># systemctl status mariadb
# systemctl status mysql.service
# systemclt status mysqld
# systemctl stop mysqld.service
# systemctl start mysql
# systemctl restart mariadb.service</code>
</pre>

<h5>mysql_secure_installation을 실행할 필요가 없음</h5>
<p>
  데비안의 MariaDB 패키지는 보안을 적용한 상태이기 때문에 패키지 설치 후
  mysql_secure_installation 명령어를 실행할 필요는 없다. 어떤 보안 설정들을
  적용하였는지 살펴보자.
</p>
<pre class="language-none" data-line="1,8,13,15,17,19,21">
<code># mysql_secure_installation
...
In order to log into MariaDB to secure it, we&#039;ll need the current
password for the root user.  If you&#039;ve just installed MariaDB, and
you haven&#039;t set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none):
...
Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.

Set root password? [Y/n] n
...
Remove anonymous users? [Y/n] y
...
Disallow root login remotely? [Y/n] y
...
Remove test database and access to it? [Y/n] y
...
Reload privilege tables now? [Y/n] y
...</code>
</pre>
<p>
  위의 내용은 mysql_secure_installation 실행 과정의 일부분을 발췌한 것이다. 라인
  8에서 현재 root 계정의 암호를 묻고 있다. 처음 설치 시에는 MariaDB에 대한 root
  계정의 암호가 없으므로 <kbd>&lt;Enter&gt;</kbd> 키를 누른다. 라인 13에서
  root의 암호를 설정할 것인지를 묻는다. unix_socket을 사용하여 root 계정을
  인증하기 때문에 <kbd>n</kbd>을 입력한다. 이후 나머지 설정에서는 모두
  <kbd>y</kbd>를 입력한다. 라인 15는 anonymous 사용자를 삭제한다. 라인 17은
  root의 원격 로그인을 허용하지 않는다. 라인 19는 test 데이터베이스를 삭제한다.
  라인 21은 보안 강화를 위해 변경한 내용을 바로 적용한다.
</p>
<p>
  데비안에서 MariaDB 패키지를 설치하면 <em>이미</em> 위와 같이 설정한 상태이다.
  데비안에서 라인 13처럼 MariaDB의 root 계정에 대한 암호를 설정하지 않는 데
  다음에서 이에 대해 알아볼 것이다.
</p>
<h5>Unix Socket 인증</h5>
<p>
  데비안은 MariaDB에서 <em>unix_socket 인증 플러그인</em>을 기본적으로 사용한다.
  unix_socket 인증 플러그인이 나오기 전에 MySQL이나 MariaDB는 데이터베이스를
  보호하기 위해 자체적인 인증을 사용하였다. 그래서 시스템에 모든 권한이 있는
  root 계정이라도 MySQL 내에 암호를 별도로 가져야 했다. mysql 클라이언트 사용 시
  root 계정임에도 불필요해 보이는 <strong>-u</strong>,
  <strong>-p</strong> 옵션을 사용해야만 했다. 데이터베이스의 백업 스크립트에서
  암호를 노출해야 하는 문제도 있었다.
</p>
<p>
  unix_socket 인증 플러그인은 시스템의 인증과 MariaDB의 인증을 함께 묶어 준다.
  로컬 시스템으로 접속하여 mysql 클라이언트 실행 시 -u, -p 옵션을 사용하지 않을
  수 있게 한다. 예제를 통해 좀 더 알아보자. 규모가 큰 조직에서 미숙한 신입 DB
  관리자가 들어왔다고 가정해 보자. 시스템 전체의 권한을 주지 않으면서
  데이터베이스의 관리 권한만 주고 싶다면 다음과 같이 한다.
</p>
<pre class="language-none" data-line="1-3,7">
<code># groupadd dbadmin
# useradd dbadmin -g dbadmin -m
# passwd dbadmin
새  암호:
새  암호 재입력:
passwd: 암호를 성공적으로 업데이트했습니다
# mysql -e &quot;GRANT ALL ON *.* TO &#039;dbadmin&#039;@&#039;localhost&#039; IDENTIFIED VIA unix_socket WITH GRANT OPTION&quot;</code>
</pre>
<p>
  라인 1에서 3까지 시스템에 <kbd>dbadmin</kbd> 계정을 만들고 암호를 설정한다.
  라인 7에서 unix_socket 인증을 사용하는 <kbd>dbadmin</kbd> 계정에
  데이터베이스의 모든 권한을 주는 SQL 문을 실행한다. 다른 ssh 세션에서
  <kbd>dbadmin</kbd>으로 로그인하여 <kbd>mysql</kbd> 클라이언트를 실행해 보자.
</p>
<pre class="language-none" data-line="1">
<code>$ mysql
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 59
Server version: 10.3.22-MariaDB-0+deb10u1 Debian 10

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type &#039;help;&#039; or &#039;\h&#039; for help. Type &#039;\c&#039; to clear the current input statement.

MariaDB [(none)]&gt;</code>
</pre>
<p>
  라인 1에서 보듯이 -u, -p 옵션을 사용하지 않았다. 로컬 시스템의 dbadmin 계정과
  암호로 로그인하면 unix_socket 인증에 의해 mysql 클라이언트를 사용할 수 있는
  것이다.
</p>
<p>
  신입 DB 관리자가 자신의 컴퓨터에서
  <a href="https://dbeaver.io/" target="_blank" rel="noopener noreferrer">DBeaver</a
  >,
  <a href="https://www.jetbrains.com/ko-kr/datagrip/features/" target="_blank" rel="noopener noreferrer">DataGrip</a
  >
  같은 그래픽 도구로 MariaDB 서버에 접속하여 데이터베이스를 관리하고 싶다고
  해보자. 그리고 집에서도 접속하고 싶어 한다. 이럴 때는 unix_socket이 아니라
  password 인증을 사용해야 한다. 다음과 같이 작업한다.
</p>
<pre class="language-none" data-line="1,6,9,12,16-18,22">
<code>MariaDB [(none)]&gt; USE mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [mysql]&gt; GRANT ALL ON *.* TO &#039;dbadmin&#039;@&#039;192.168.10.%&#039; IDENTIFIED BY &#039;원하는 암호 입력&#039; WITH GRANT OPTION;
Query OK, 0 rows affected (0.000 sec)

MariaDB [mysql]&gt; GRANT ALL ON *.* TO &#039;dbadmin&#039;@&#039;%&#039; IDENTIFIED BY &#039;원하는 암호 입력&#039; WITH GRANT OPTION;
Query OK, 0 rows affected (0.000 sec)

MariaDB [mysql]&gt; SELECT user, host, password, plugin FROM user WHERE user=&#039;dbadmin&#039;;
+---------+--------------+-------------------------------------------+-------------+
| user    | host         | password                                  | plugin      |
+---------+--------------+-------------------------------------------+-------------+
| dbadmin | localhost    |                                           | unix_socket |
| dbadmin | 192.168.10.% | *CB04FE5BBC0DAAE405DB6DD0745827BCF1CF624D |             |
| dbadmin | %            | *CB04FE5BBC0DAAE405DB6DD0745827BCF1CF624D |             |
+---------+--------------+-------------------------------------------+-------------+
3 rows in set (0.000 sec)

MariaDB [mysql]&gt; DROP USER &#039;dbadmin&#039;@&#039;%&#039;;
Query OK, 0 rows affected (0.000 sec)

MariaDB [mysql]&gt;</code>
</pre>
<p>
  라인 1에서 라인 12의 SELECT 문을 사용하기 쉽게 mysql 데이터베이스로 이동한다.
  라인 6에서 암호 인증을 사용하는 dbadmin 계정에 데이터베이스의 모든 권한을
  주었다. <strong>&#8216;dbadmin&#8217;@&#8217;192.168.10.%&#8217;</strong>는 dbadmin이
  <kbd>192.168.10</kbd>의 네트워크에 있는 컴퓨터에서 접속할 수 있음을 의미한다.
  % 문자는 &#8216;모든&#8217;을 의미한다. 라인 9에서 <strong>&#8216;dbadmin&#8217;@&#8217;%&#8217;</strong>는
  네트워크 제한을 두지 않는다. dbadmin 계정은 어떤 IP에서든 접속할 수 있다.
  당연히 보안에 좋지 않다. 라인 12에서 <strong>SELECT</strong> 문을 사용하여
  dbadmin 사용자의 인증 방법과 접속할 수 있는 네트워크 대역을 확인한다. 라인
  22에서 <strong>DROP USER</strong> 문을 사용하여 &#8216;dbadmin&#8217;@&#8217;%&#8217; 사용자를
  삭제한다.
</p>
<p>
  원격으로 접속하기 위해서는 추가적인 설정이 필요하다. 이에 대해서는 아래의
  &#8216;원격 접속을 허용하기&#8217;에서 다룬다.
</p>
<h5>워드프레스의 데이터베이스 만들기</h5>
<p>
  응용 프로그램을 위한 데이터베이스 생성은 기존의 방식과 동일하게 암호 인증을
  사용한다. 워드프레스를 위한 데이터베이스와 사용자는 다음과 같이 만들 수 있다.
</p>
<pre class="language-none line-numbers" data-line="1,4">
<code>MariaDB [mysql]&gt; CREATE DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Query OK, 1 row affected (0.00 sec)

MariaDB [mysql]&gt; GRANT ALL ON wordpress.* TO &#039;wordpress&#039;@&#039;localhost&#039; IDENTIFIED BY &#039;원하는 암호 입력&#039; WITH GRANT OPTION;
Query OK, 0 rows affected (0.00 sec)

MariaDB [mysql]&gt;</code>
</pre>

<h5>MariaDB 설정 파일의 위치</h5>
<p>/etc/mysql/mariadb.cnf 파일을 보면 MariaDB 설정 파일은 다음과 같다.</p>
<ol>
  <li>/etc/mysql/mariadb.cnf</li>
  <li>/etc/mysql/conf.d/*.cnf</li>
  <li>/etc/mysql/mariadb.conf.d/*.cnf</li>
  <li>~/.my.cnf</li>
</ol>
<p>
  위의 순서로 설정 파일을 읽기 때문에 같은 옵션이 여러 번 나타난다면 가장
  마지막에 있는 설정을 적용할 것이다. MariaDB 서버와 관련한 설정은
  <kbd>/etc/mysql/mariadb.conf.d</kbd> 디렉토리 안의
  <kbd><strong>50-server.cnf</strong></kbd> 파일에서 한다.
</p>
<h5>원격 접속을 허용하기</h5>
<p>
  데비안의 MariaDB는 보안을 위해 <kbd>3306</kbd> 포트를 루프백(loop-back) 주소인
  <kbd>127.0.0.1</kbd>로 바인딩한다. 다음의 명령어로 확인할 수 있다.
</p>
<pre class="language-none line-numbers" data-line="2">
<code># netstat -tlnp | grep mysql
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      12435/mysqld</code>
</pre>
<p>
  따라서 시스템 외부에서 접근할 수 없다. 시스템 외부에서 접근할 수 있도록 하려면
  <kbd><strong>50-server.cnf</strong></kbd> 파일에서 bind-address를 다음과 같이
  변경한다.
</p>
<pre class="language-none line-numbers" data-line="1">
<code>bind-address            = 0.0.0.0</code>
</pre>
<p>변경한 설정을 반영하기 위해 MariaDB 서버를 다시 시작한다.</p>
<pre class="language-none">
<code># systemctl restart mariadb</code>
</pre>
<p>
  공유기(방화벽 역할)의 외부에서 오는 접근을 허용하려면 3306 포트에 대한 포트
  포워딩을 해야 한다. 보안에 좋지 않기 때문에 데이터베이스 서버의 포트를 여는
  경우는 거의 없을 것이다.
</p>
<h5>언어 설정</h5>
<p>
  데비안의 MariaDB에서 디폴트 <em>문자 집합(character set)</em>은
  <strong>utf8mb4</strong>이다. 디폴트 <em>데이터 정렬(collation)</em>은
  <strong>utf8mb4_general_ci</strong>이다. 데이터 정렬을
  <strong>utf8mb4_unicode_ci</strong>로 바꾸고 싶다면
  <kbd><strong>50-server.cnf</strong></kbd> 파일을 다음과 같이 편집한다.
</p>
<pre class="language-none" data-line="1,2">
<code>collation-server      = utf8mb4_unicode_ci
skip-character-set-client-handshake</code>
</pre>
<p>
  라인 1의 collation-server의 값을 utf8mb4_general_ci에서
  <strong>utf8mb4_unicode_ci</strong>로 변경한다. 라인 2의
  <strong>skip-character-set-client-handshake</strong>를 추가한다.
</p>
<p>
  MariaDB 서버를 다시 시작하고 MySQL 클라이언트를 다시 실행한 후 다음의 SQL
  문으로 변경을 확인한다.
</p>
<pre class="language-none" data-line="1">
<code>MariaDB [(none)]&gt; SHOW VARIABLES LIKE &#039;coll%&#039;;
+----------------------+--------------------+
| Variable_name        | Value              |
+----------------------+--------------------+
| collation_connection | utf8mb4_unicode_ci |
| collation_database   | utf8mb4_unicode_ci |
| collation_server     | utf8mb4_unicode_ci |
+----------------------+--------------------+
3 rows in set (0.001 sec)

MariaDB [(none)]&gt;</code>
</pre>
<p>
  MariaDB 서버의 데이터 정렬 설정은 MySQL 클라이언트 외에 다른
  <em>응용 프로그램</em>의 데이터 정렬을 강제하지는 않는다. 예를 들면
  <a href="https://www.adminer.org/" target="_blank" rel="noopener noreferrer">Adminer</a
  >는 collation_connection을 utf8mb4_general_ci로 나타낸다. 워드프레스의 일부
  플러그인은 utf8mb4_general_ci를 가지는 테이블을 만든다.
</p>
<h5>튜닝</h5>
<p>
  데이터베이스의 데이터는 &#8216;하드디스크 &gt; 메모리 &gt; CPU의 레지스터&#8217; 순으로
  옮겨간다. 오른쪽으로 갈수록 속도가 빠른 대신 저장 비용은 비싸진다.
  데이터베이스 읽기의 최적화는 디스크 입출력(I/O)을 최소화하고 메모리를 최대한
  사용하는 것이다. 단순하지만 중요한 개념이다. 데이터베이스 쓰기의 최적화는
  메모리의 휘발성으로 인해 간단하지 않다. 커밋(commit)한 데이터를 메모리에서
  디스크로 쓰기 전에 시스템 장애가 발생한다면 데이터를 잃을 것이다. 은행이나
  증권의 돈과 관련한 데이터라면 커밋 즉시 메모리에서 디스크로 써야 한다.
  안정성은 증가하지만, 성능은 준다. 게시판의 글에 대한 데이터라면 메모리를 좀 더
  활용하고 디스크에 쓰는 것을 늦출 수 있을 것이다. 데이터베이스 쓰기의 최적화는
  데이터의 종류에 따라 안정성과 성능 사이에서 고민해야 할 문제이다.
</p>
<p>
  MariaDB의 디폴트 스토리지 엔진(default_storage_engine)은 InnoDB이다. InnoDB와
  관련한 디폴트 설정값은 데스크톱 시스템에 맞게 되어 있다. 데이터베이스 전용의
  서버를 사용한다면 최적의 성능을 위해 설정값을 변경하여야 할 것이다. 전용의
  서버가 아니더라도 약간의 설정값 변경으로 성능 향상을 꾀할 수 있다. 나는
  <a href="https://mariadb.com/kb/en/configuring-mariadb-for-optimal-performance/" target="_blank" rel="noopener noreferrer">Configuring MariaDB for Optimal Performance</a
  >와
  <a href="https://mariadb.com/resources/blog/10-database-tuning-tips-for-peak-workloads/" target="_blank" rel="noopener noreferrer">10 Database Tuning Tips for Peak Workloads</a
  >
  페이지를 참고하여 3가지 정도의 설정만 추가하였다.
</p>
<pre
  class="language-none"
  data-line="1,2"
  data-label="/etc/mysql/mariadb.conf.d/50-server.cnf"
>
<code>innodb_buffer_pool_size=4096M
innodb_log_file_size=1024M
innodb_log_buffer_size=64M</code>
</pre>

<p>
  위의 설정은 모두 <kbd><strong>50-server.cnf</strong></kbd> 파일에 추가한다.
  라인 1의<strong> innodb_buffer_pool_size</strong>는 성능 최적화에 가장 중요한
  설정이다. 하나만 설정해야 한다면 이것을 해야 한다. 참고한 페이지에서는
  innodb_buffer_pool_size를 데이터베이스 전용의 서버일 때 메모리의
  <kbd>80%</kbd> 정도를 권장한다. Buffer Pool은 주로 데이터의 읽기와 관련한
  것으로 디스크보다는 메모리를 사용하기 위해 가능한 한 크게 설정하는 것을
  추천하고 있다. 데이터베이스 전용의 서버가 아니더라도 자신의 시스템 환경에 맞춰
  크게 설정하는 것이 좋겠다.
</p>

<p>
  InnoDB는 데이터를 디스크에 쓰기 전에 속도와 안정성을 목적으로 Redo Log를
  사용한다. Redo Log는 시스템 장애 발생 시 복구를 위해 변경 기록들을 저장한다.
  INSERT 문과 같은 데이터 변경이 발생한다면 그 데이터는 &#8216;Buffer Pool(메모리)
  &gt; Log Buffer(메모리) &gt; Redo Log(ib_logfile0, ib_logfile1 파일) &gt;
  테이블(디스크)&#8217;의 순으로 이동한다. Redo Log의 파일 크기인
  <strong>innodb_log_file_size</strong>는 innodb_buffer_pool_size의
  <kbd>1/4</kbd>에서 <kbd>1/2</kbd>까지를 권장한다. Log Buffer의 크기인
  <strong>innodb_log_buffer_size</strong>는 참고한 페이지에서 <kbd>64M</kbd>을
  추천하고 있다.
</p>
<p><strong>innodb_log_file_size</strong>의 변경은 다음의 절차로 한다.</p>
<ol>
  <li>MariaDB 서버를 종료한다.</li>
  <li>
    위 라인 2처럼 <kbd><strong>50-server.cnf</strong></kbd> 파일에
    <kbd>innodb_log_file_size</kbd> 설정을 추가한다.
  </li>
  <li>
    <kbd>/var/lib/mysql</kbd> 디렉토리에서 <kbd>ib_logfile0, ib_logfile1</kbd>을
    삭제하거나 다른 디렉토리로 옮긴다.
    (<strong>innodb_log_files_in_group</strong>의 디폴트 값이 <kbd>2</kbd>이기
    때문에 Redo Log 파일이 2개가 있다.)
  </li>
  <li>
    MariaDB 서버를 시작한다. 새로 설정한 크기의
    <kbd>ib_logfile0, ib_logfile1</kbd> 파일을 볼 수 있을 것이다.
  </li>
</ol>
<p>
  참고한 페이지에는 데이터 안정성과 관련한
  <strong>innodb_flush_log_at_trx_commit</strong>과
  <strong>sync_binlog</strong>, 동시 접속자 수에 대한
  <strong>max_connections</strong> 등을 다루고 있다. 나는 위 3개의 설정을
  제외하고 모두 디폴트 값을 사용할 것이어서 크게 관심을 가지지 않았지만,
  여러분에게 필요한 내용이 있을지 모르겠다.
</p>
<h5>참고 자료</h5>
<ul>
  <li>
    <a href="https://mariadb.com/kb/en/moving-from-mysql-to-mariadb-in-debian-9/" target="_blank" rel="noopener noreferrer">Moving from MySQL to MariaDB in Debian 9</a
    >
  </li>
  <li>
    <a href="https://serverfault.com/questions/111358/how-do-i-completely-remove-mysql-server-on-debian" target="_blank" rel="noopener noreferrer">How do I completely remove mysql-server on Debian?</a
    >
  </li>
  <li>
    <a href="https://mariadb.com/kb/en/systemd/" target="_blank" rel="noopener noreferrer">systemd</a
    >
  </li>
  <li>
    <a href="https://mariadb.com/kb/en/mysql_secure_installation/" target="_blank" rel="noopener noreferrer">mysql_secure_installation</a
    >
  </li>
  <li>
    <a href="https://mariadb.com/kb/en/authentication-plugin-unix-socket/" target="_blank" rel="noopener noreferrer">Authentication Plugin &#8211; Unix Socket</a
    >
  </li>
  <li>
    <a href="https://mariadb.com/kb/en/configuring-mariadb-for-optimal-performance/" target="_blank" rel="noopener noreferrer">Configuring MariaDB for Optimal Performance</a
    >
  </li>
  <li>
    <a href="https://mariadb.com/resources/blog/10-database-tuning-tips-for-peak-workloads/" target="_blank" rel="noopener noreferrer">10 Database Tuning Tips for Peak Workloads</a
    >
  </li>
  <li>
    <a href="https://mariadb.com/kb/en/innodb-system-variables/" target="_blank" rel="noopener noreferrer">InnoDB System Variables</a
    >
  </li>
  <li>
    <a href="https://mariadb.com/kb/en/server-system-variables/" target="_blank" rel="noopener noreferrer">Server System Variables</a
    >
  </li>
</ul>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/%eb%8d%b0%eb%b9%84%ec%95%88%ec%9d%98-mariadb-%ec%84%a4%ec%b9%98%ec%99%80-%ec%84%a4%ec%a0%95/">데비안의 MariaDB 설치와 설정</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Windows 터미널의 설정 및 ssh 사용하기</title>
		<link>https://www.bitneer.dev/blog/windows-%ed%84%b0%eb%af%b8%eb%84%90%ec%9d%98-%ec%84%a4%ec%a0%95-%eb%b0%8f-ssh-%ec%82%ac%ec%9a%a9%ed%95%98%ea%b8%b0/</link>
		
		<dc:creator><![CDATA[Choi Kyung-sik]]></dc:creator>
		<pubDate>Fri, 05 Jun 2020 22:58:24 +0000</pubDate>
				<category><![CDATA[네트워크와 시스템 관리]]></category>
		<category><![CDATA[ssh]]></category>
		<category><![CDATA[terminal]]></category>
		<guid isPermaLink="false">https://www.bitneer.dev/?p=598</guid>

					<description><![CDATA[<p>Windows 10은 OpenSSH를 포함하고 있으나 명령 프롬프트(cmd.exe)의 기능 부족으로 사용이 꺼려졌다. Windows 터미널이 나오면서 Xshell, SecureCTR, PuTTY 등을 대체할 수준까지 올라왔다. Windows 터미널을 처음 설치하고 막막할 수 있는 설정 방법과 ssh 클라이언트의 효율적인 사용을 정리해 본다. Windows 터미널은 Microsoft 스토어에서 검색해서 설치한다. Windows Terminal 구매에서 무료 버튼을 클릭하면 Windows 터미널이 있는 스토어로 들어갈 것이다. 프로필에 기본적인 설정하기 Windows 터미널 화면상에서 ...</p>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/windows-%ed%84%b0%eb%af%b8%eb%84%90%ec%9d%98-%ec%84%a4%ec%a0%95-%eb%b0%8f-ssh-%ec%82%ac%ec%9a%a9%ed%95%98%ea%b8%b0/">Windows 터미널의 설정 및 ssh 사용하기</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>
  Windows 10은 OpenSSH를 포함하고 있으나 명령 프롬프트(cmd.exe)의 기능 부족으로
  사용이 꺼려졌다. Windows 터미널이 나오면서 Xshell, SecureCTR, PuTTY 등을
  대체할 수준까지 올라왔다.
</p>
<p>
  Windows 터미널을 처음 설치하고 막막할 수 있는 설정 방법과 ssh 클라이언트의
  효율적인 사용을 정리해 본다. Windows 터미널은 Microsoft 스토어에서 검색해서
  설치한다.
</p>
<a href="https://www.microsoft.com/ko-kr/p/windows-terminal/9n0dx20hk701?rtc=1&amp;activetab=pivot:overviewtab" target="_blank" rel="noopener noreferrer">Windows Terminal 구매</a
>에서 <strong>무료</strong> 버튼을 클릭하면 Windows 터미널이 있는 스토어로
들어갈 것이다.

<h5>프로필에 기본적인 설정하기</h5>
Windows 터미널 화면상에서 <strong>&lt;Ctrl + ,&gt;</strong> 키를 누르면
<strong>settings.json</strong> 설정 파일이 열린다.
<pre class="language-none line-numbers" data-line="2,4,7,8,10,15,22,29">
<code>...
    &quot;profiles&quot;:
    {
        &quot;defaults&quot;:
        {
            // Put settings here that you want to apply to all profiles.
            &quot;fontSize&quot;: 10,
            &quot;cursorShape&quot;: &quot;vintage&quot;
        },
        &quot;list&quot;:
        [
            {
                // Make changes here to the powershell.exe profile.
                &quot;guid&quot;: &quot;{61c54bbd-c2c6-5271-96e7-009a87ff44bf}&quot;,
                &quot;name&quot;: &quot;Windows PowerShell&quot;,
                &quot;commandline&quot;: &quot;powershell.exe&quot;,
                &quot;hidden&quot;: false
            },
            {
                // Make changes here to the cmd.exe profile.
                &quot;guid&quot;: &quot;{0caa0dad-35be-5f56-a8ff-afceeeaa6101}&quot;,
                &quot;name&quot;: &quot;명령 프롬프트&quot;,
                &quot;commandline&quot;: &quot;cmd.exe&quot;,
                &quot;hidden&quot;: false
            },
            {
                &quot;guid&quot;: &quot;{b453ae62-4e3d-5e58-b989-0a998ec441b8}&quot;,
                &quot;hidden&quot;: false,
                &quot;name&quot;: &quot;Azure Cloud Shell&quot;,
                &quot;source&quot;: &quot;Windows.Terminal.Azure&quot;
            }
        ]
    },
...</code>
</pre>

<p>
  위의 내용은 settings.json 파일에서 일부분을 발췌한 것이다. 라인 1과 34의
  <kbd>...</kbd>은 내용을 생략하였음을 나타낸다. 우리가 중점적으로 보아야 할
  부분은 라인 2부터 시작하는 <strong>&#8220;profiles&#8221;</strong>이다. Windows 터미널은
  설정 단위로 <em>프로필</em>이라는 용어를 사용한다.
</p>
<p>
  처음 설치 시 Windows Powershell, 명령 프롬프트, Azure Cloude Shell 3개의
  프로필이 있다. 라인 10의 <strong>&#8220;list&#8221;</strong> <em>절(section)</em>에서 각
  프로필을 포함하고 있는 것을 볼 수 있다. 라인 4의
  <strong>&#8220;defaults&#8221;</strong> 절에서 모든 프로필에 적용할
  <em>속성(property)</em>을 설정할 수 있다. 속성 설정은
  <strong>&#8220;속성&#8221;: &#8220;문자열 값&#8221;</strong> 형식으로 한다. 숫자 값이나 불린 값(true,
  false)은 <strong>&#8220;속성&#8221;: 값</strong> 형태로 값에 인용 부호(&#8220;)를 사용하지
  않는다.
</p>
<p>
  라인 7, 8은 내가 추가한 설정이다. 폰트가 너무 큰 것 같아
  <strong>&#8220;fontSize&#8221;</strong> 속성을 <kbd>10</kbd>으로 설정하였다. 라인 8은
  커서의 모양을 굵은 밑줄로 한 것이다. 커서 모양 속성인
  <strong>&#8220;cursorShape&#8221;</strong>는
  <kbd>"bar", "vintage", "underscore", "filledBox", "emptyBox"</kbd> 값을 설정할
  수 있다. 편집한 내용을 저장하면 설정이 바로 적용되는 것을 볼 수 있을 것이다.
</p>
<p>
  나는 커서가 깜박이는 것을 좋아하지 않는다. 나와 취향이 비슷한 분을 위해 설명을
  추가한다. 커서 깜박임 설정은 <em>윈도우 운영체제</em>에서 해야 한다. 다음의
  절차로 커서 깜박임을 없앨 수 있다.
</p>
<ol>
  <li>
    <strong>시작 &gt; 설정</strong>의 <strong>설정 검색</strong>에
    &#8216;<kbd>제어판</kbd>&#8216;을 입력하고 검색한 후 <strong>제어판</strong>을 클릭한다.
  </li>
  <li>
    <strong>제어판 검색</strong>에 &#8216;<kbd>키보드</kbd>&#8216;를 입력하고 검색한다.
  </li>
  <li><strong>키보드 상태 확인</strong>을 클릭한다.</li>
  <li>
    <strong>속도</strong> 탭에서 <strong>커서 깜박임 속도</strong>를
    <strong>없음</strong>으로 설정한다.
  </li>
  <li><strong>확인</strong> 버튼을 클릭하여 설정을 마친다.</li>
</ol>
<h5>Git Bash 프로필 추가하기</h5>
<p>
  기본으로 제공하는 3개의 프로필에 더하여 새로운 프로필을 추가해 보자. Git Bash
  프로필을 추가하는 방법을 먼저 살펴본다. Git Bash는
  <a href="https://git-scm.com/downloads" target="_blank" rel="noopener noreferrer">Git &#8211; Downloads</a
  >에서 Windows 용 설치 파일을 다운로드하여 설치할 수 있다. git을 사용하지
  않는다면 GUID 생성 방법과 속성 설명 만을 보고 다음으로 넘어간다.
</p>
<p>
  각 프로필은 고유의 GUID 값을 가져야 한다. Windows 터미널은 실행할 때 디폴트로
  파워쉘을 실행한다. <em>파워쉘</em>에서 &#8216;<strong
    ><kbd>[guid]::NewGuid()</kbd></strong
  >&#8216; 명령어를 실행하여 GUID를 만들 수 있다.
</p>
<pre class="language-none" data-line="1,5">
<code>PS C:\Users\bitneer&gt; [guid]::NewGuid()

Guid
----
d32532fa-83a2-4b38-91ad-fb5990d24199


PS C:\Users\bitneer&gt;</code>
</pre>

<p>
  라인 5의 값을 복사해서 <strong>&#8220;guid&#8221;</strong> 속성의 값으로 사용하면 된다.
  Windows 터미널에서 클립보드로 복사하는 단축키는
  <strong
    >&lt;Ctrl + C&gt;, &lt;Ctrl + Shift + C&gt;, &lt;Ctrl + Insert&gt;</strong
  >
  3가지가 있다. &lt;Ctrl + C&gt; 키는 Unix/Linux 시스템에서 포그라운드
  프로세스를 종료하는 데 사용한다. 따라서 &lt;Ctrl + Shift + C&gt;나 &lt;Ctrl +
  Insert&gt; 키로 복사하는 습관을 들이는 것이 좋겠다.
</p>
<p>settings.json 파일에 Git Bash 프로필 설정을 다음과 같이 추가한다.</p>
<pre class="language-none line-numbers" data-line="4,6-10,11">
<code>...
        &quot;name&quot;: &quot;Azure Cloud Shell&quot;,
        &quot;source&quot;: &quot;Windows.Terminal.Azure&quot;
    },
    {
        &quot;guid&quot;: &quot;{d32532fa-83a2-4b38-91ad-fb5990d24199}&quot;,
        &quot;name&quot;: &quot;Git Bash&quot;,
        &quot;commandline&quot;: &quot;C:/Program Files/Git/bin/bash.exe --login&quot;,
        &quot;icon&quot;: &quot;file:///C:/Program Files/Git/mingw64/share/git/git-for-windows.ico&quot;,
        &quot;hidden&quot;: false
    }
...</code>
</pre>

<p>
  기본적으로 제공하는 프로필 중 마지막 프로필인 Azure Cloude Shell 뒤에 Git Bash
  프로필을 추가하였다. 라인 4에서 쉼표(,)를 추가하는 것에 주의한다. 프로필
  항목이 이어지면 쉼표를 붙이고 라인 11처럼 제일 끝 항목은 쉼표를 붙이지 않는다.
  속성도 마찬가지로 라인 10의 마지막 &#8220;hidden&#8221; 속성에는 쉼표를 붙이지 않았다.
</p>
<p>
  라인 6의 <strong>&#8220;guid&#8221;</strong> 속성은 위에서 만든 GUID 값으로 설정하였다.
  라인 7의 <strong>&#8220;name&#8221;</strong> 속성에는 원하는 이름을 사용한다. 이 이름이
  <em>드롭다운 메뉴</em>에 나타난다. 라인 10의 <strong>&#8220;hidden&#8221;</strong> 속성은
  드롭다운 메뉴에 프로필을 숨길지를 설정한다. 디폴트 값이 false이므로 이 속성을
  삭제할 수 있다. 그러나 설정 내용은 유지하면서 드롭다운 메뉴에서 숨기고 싶을 때
  편집의 용이성을 위해 넣어주는 것이 좋을 것이다. 라인 9의
  <strong>&#8220;icon&#8221;</strong> 속성에 Git Bash의 아이콘 이미지의 파일 경로를 설정하여
  드롭다운 메뉴와 <em>탭</em>에 아이콘을 보이게 한다.
</p>
<p>
  라인 8의 <strong>&#8220;commandline&#8221;</strong> 속성에 Git Bash의 실행 파일 경로를
  값으로 설정하였다. &#8216;<strong>&#8211;login</strong>&#8216; 옵션을 주어 로그인 시 적용하는
  환경 변수들을 불러온다. 추가로 환경 변수를 설정하고 싶다면 자신의 홈 폴더에
  .profile 파일을 만들고 로그인 시에 적용할 내용을 넣어 줄 수 있다. 예를 들면
  다음과 같이 할 수 있다.
</p>
<pre class="language-none" data-label="C:\Users\bitneer\.profile">
<code>export LS_COLORS=&quot;di=00;36:fi=00;37&quot;
cd &quot;D:\MySpace&quot;</code>
</pre>

<p>
  라인 1은 ls 명령어 사용 시 디렉토리의 색깔이 어두운 파란색으로 나오는 것을 좀
  더 밝은색으로 한 것이다. 라인 2는 주로 작업하는 디렉토리로 이동하기 위한
  것이다. 여러분에게 맞게 설정 내용을 추가할 수 있다. 참고로 Windows 용 Git에는
  MinGW를 포함하고 있다. 따라서 vim, grep, ssh 같은 유닉스 명령어들을 사용할 수
  있다. Git Bash 쉘에서 &#8216;<kbd>echo $PATH</kbd>&#8216; 명령어를 실행하고 나온 경로를
  통해 어떤 명령어들을 사용할 수 있는지 확인해 볼 수 있을 것이다.
</p>

<h5>OpenSSH 클라이언트 확인하기</h5>
<p>
  Git Bash는 ssh를 포함하고 있으므로 Git Bash 쉘에서 ssh를 바로 사용할 수 있다.
  파워 쉘이나 명령 프롬프트에서 모든 경로를 타이핑하지 않고 편하게 사용하려면
  64-bit 시스템일 때
  <kbd>C:\Program Files\Git\usr\bin</kbd> 폴더를 PATH 환경 변수에 추가해야 할
  것이다.
</p>
<p>
  Git Bash를 설치하지 않는다면 Windows 10의 OpenSSH를 사용할 수 있다. OpenSSH
  클라이언트를 추가하였는지 다음과 같이 확인한다.
</p>
<ol>
  <li>
    윈도우에서 <strong>시작 &gt; 설정 &gt; 앱</strong>의
    <strong>선택적 기능</strong>을 클릭한다.
  </li>
  <li><strong>OpenSSH 클라이언트</strong>가 목록에 있는지 확인한다.</li>
  <li>
    목록에 없으면 &#8216;<strong>+</strong>&#8216; 기능 추가 아이콘을 클릭하여
    <strong>OpenSSH 클라이언트</strong>를 추가한다.
  </li>
</ol>
<p>
  OpenSSH 클라이언트 기능을 추가하면
  <kbd>C:\Windows\System32\OpenSSH</kbd> 폴더를 자동으로 PATH 환경 변수에
  추가하여 준다.
</p>
<p>
  원격에 있는 시스템(예: <kbd>192.168.10.10</kbd>)의 <kbd>root</kbd> 계정으로
  접속하기 위해 다음의 ssh 명령어를 실행할 수 있다.
</p>
<pre class="language-none line-numbers" data-line="1">
<code>PS C:\Users\bitneer&gt; ssh root@192.168.10.10
...</code>
</pre>

<p>
  첫 접속이라면 접속을 계속할지를 물을 것이다. &#8216;<kbd>yes</kbd>&#8216;를 입력하고
  &lt;Enter&gt; 키를 누르면 $HOME/.ssh/known_hosts 파일에
  호스트(192.168.10.10)를 추가해 줄 것이다. 호스트 추가 후 다시 위의 명령어를
  실행하면 &#8216;암호&#8217;를 물을 것이고 root 계정의 암호를 입력하여 접속한다.
</p>
<p>
  위의 예제에서 위험하게 root 계정을 사용하였다. 나의 경우 공유기(방화벽 역할)
  안에 시스템이 있고 ssh 서버를 포트 포워딩으로 열어 두지 않았기 때문에 보안에는
  문제가 없다. 참고로 ssh 서버에서 root로 로그인을 허용하려면 데비안 시스템의
  경우 <kbd>/etc/ssh/sshd_config</kbd> 파일에 &#8216;<kbd>PermitRootLogin yes</kbd>&#8216;를
  추가하고 ssh 서버를 다시 시작해야 한다. 앞으로의 예제에서도
  <kbd>192.168.10.10</kbd> 시스템의 <kbd>root</kbd> 계정으로 예를 들 것이다.
  여러분에게 맞게 참작해서 보기 바란다.
</p>
<h5>SSH 사용을 위한 프로필 추가하기</h5>
<p>
  settings.json 파일에 192.168.10.10 시스템의 root 계정으로 로그인하는 프로필을
  다음과 같이 추가한다.
</p>

<pre class="language-none line-numbers" data-line="2,4-8,10,15,16">
<code>...
    },
    {
        &quot;guid&quot;: &quot;{12fec865-77d4-4c96-89ef-e1781e805c13}&quot;,
        &quot;name&quot;: &quot;192.168.10.10 - root&quot;,
        //&quot;commandline&quot;: &quot;C:/Program Files/Git/usr/bin/ssh root@192.168.10.10&quot;,
        &quot;suppressApplicationTitle&quot;: true,
        &quot;commandline&quot;: &quot;ssh root@192.168.10.10&quot;,
        // Linux Icon
        &quot;icon&quot;: &quot;ms-appx:///ProfileIcons/{9acb9455-ca41-5af7-950f-6bca1bc9722f}.scale-100.png&quot;,
        // Poswershell Icon
        //&quot;icon&quot;: &quot;ms-appx:///ProfileIcons/{61c54bbd-c2c6-5271-96e7-009a87ff44bf}.png&quot;,
        // CMD Icon
        //&quot;icon&quot;: &quot;ms-appx:///ProfileIcons/{0caa0dad-35be-5f56-a8ff-afceeeaa6101}.png&quot;,
        &quot;hidden&quot;: false
    }
...</code>
</pre>

<p>
  라인 2의 Git Bash 프로필 항목의 끝에 쉼표(,)를 추가한다. 라인 16처럼 프로필의
  마지막 항목이면 쉼표를 쓰지 않는다. 라인 4의
  <strong>&#8220;guid&#8221;</strong> 속성에 파워쉘에서 &#8216;<strong
    ><kbd>[guid]::NewGuid()</kbd></strong
  >&#8216; 명령어를 실행하여 나온 GUID 값을 복사하여 붙여준다. 라인 5의
  <strong>&#8220;name&#8221;</strong> 속성에는 원하는 이름을 넣어 준다.
</p>
<p>
  라인 8의 <strong>&#8220;commandline&#8221;</strong> 속성에는 ssh 명령어를 입력한다.
  주석으로 처리한 라인 6에서 보듯이 Git Bash의 ssh를 사용할 수 있다. Windows의
  OpenSSH 클라이언트의 경우 라인 7의
  <strong>&#8220;suppressApplicationTitle&#8221;</strong> 속성을 <kbd>true</kbd>로 설정해야
  <em>탭</em>에 &#8220;name&#8221; 속성으로 설정한 이름 &#8216;<kbd>192.168.10.10 - root</kbd>&#8216;가
  나온다. &#8220;suppressApplicationTitle&#8221;: true를 설정하지 않으면 &#8220;commandline&#8221;에서
  지정한 ssh 프로그램의 이름인 &#8216;<kbd>OpenSSH SSH client</kbd>&#8216;를 탭에 표시할
  것이다.
</p>
<p>
  라인 10의 <strong>&#8220;icon&#8221;</strong> 속성에 Windows 터미널에서 기본적으로
  제공하는 Linux 아이콘으로 설정하였다. Git Bash 프로필에 했던 것처럼 파일
  경로를 지정하여 여러분이 원하는 아이콘으로 설정할 수 있다. 마지막으로 라인
  15에서 <strong>&#8220;hidden&#8221;</strong> 속성을 false로 하여 드롭다운 메뉴에 이
  프로필이 나오게 한다. &#8220;hidden&#8221;은 마지막 속성이기 때문에 문장의 끝에 쉼표를
  사용하지 않는 것에 주의한다.
</p>
<h5>암호를 입력하지 않고 SSH 사용하기</h5>
<p>
  ssh 사용 시 매번 암호를 입력하는 것은 귀찮은 과정이다. 암호 없이 ssh를
  사용하기 위해 다음과 같이 작업한다.
</p>
<p>
  1. Windows 터미널을 실행한 후 다음과 같이
  <strong>ssh-keygen</strong> 명령어를 실행하여
  <strong>개인키(id_rsa)</strong>와 <strong>공개키(id_rsa.pub)</strong>를
  만든다. 이미 키가 있다면 이 단계는 넘어간다.
</p>
<pre class="language-none line-numbers" data-line="1">
<code>PS C:\Users\bitneer&gt; ssh-keygen -t rsa
...</code>
</pre>

<p>
  무엇을 할지 물으면 모두 &lt;Enter&gt; 키를 눌러 넘어간다. 특히, 암호는
  입력하지 않아야 한다. 위 명령어는 <strong>$HOME/.ssh</strong> 폴더에 id_rsa,
  id_rsa.pub 파일을 생성한다. 주의할 것은 ssh-keygen에
  <strong>-f</strong> 옵션으로 id_rsa와 다른 이름으로 키를 생성하였다면 아래의
  작업 후 ssh 명령어 실행 시 <strong>-i</strong> 옵션에 개인키 이름을 지정해야
  암호를 묻지 않을 것이다. ssh 클라이언트는 디폴트로 id_rsa 이름만을 인식하기
  때문이다.
</p>
<p>
  2. 다음으로 접속하고자 하는 시스템(예: <kbd>192.168.10.10</kbd>) 계정의 ~/.ssh
  디렉토리 안에 <strong>공개키(id_rsa.pub)</strong>를
  <strong>authorized_keys</strong> 파일 이름으로 만들어야 한다. linux의
  OpenSSH는 이를 쉽게 하려고 <strong>ssh-copy-id</strong> 명령어를 제공한다.
  그러나 윈도우의 ssh 클라이언트에는 ssh-copy-id 프로그램이 없다. 이 파일을
  데비안에서 한 번 조사해 보았다.
</p>
<pre class="language-none" data-line="1,3,5,6">
<code># which ssh-copy-id
/usr/bin/ssh-copy-id
# dpkg -S /usr/bin/ssh-copy-id
openssh-client: /usr/bin/ssh-copy-id
# file /usr/bin/ssh-copy-id
/usr/bin/ssh-copy-id: POSIX shell script, ASCII text executable</code>
</pre>

<p>
  라인 1에서 <strong>which</strong> 명령어로 ssh-copy-id의 경로를 확인한다. 라인
  3에서 <strong>dpkg</strong>의 <strong>-S</strong> 옵션으로 ssh-copy-id 파일을
  포함하고 있는 패키지를 확인한다. 라인 5에서 <strong>file</strong> 명령어로
  ssh-copy-id 파일의 종류를 확인한다. 라인 6에서 보듯이 본쉘 스크립트임을 알 수
  있다. 윈도우의 OpenSSH는 배치파일이나 파워쉘 스크립트로 ssh-copy-id를 포팅하지
  않은 것으로 보인다.
</p>
<p>
  2.1. Git Bash를 설치했다면 Git Bash 쉘에서 다음과 같이 ssh-copy-id 명령어를
  실행한다.
</p>

<pre class="language-none line-numbers" data-line="1">
<code>$ ssh-copy-id -i $HOME/.ssh/id_rsa.pub root@192.168.10.10
...</code>
</pre>

<p>
  &#8216;$HOME&#8217; 대신 물결표 문자(~)로 대치하여 &#8216;~/.ssh/id_rsa_pub&#8217;처럼 간단하게 할 수
  있다. 실행 중에 암호를 물으면 192.168.10.10 시스템의 root 계정에 대한 암호를
  입력한다.
</p>
<p>
  2.2. Git Bash를 설치하지 않았다면 접속하고자 하는 시스템의 계정에 .ssh
  디렉토리가 있는지에 따라 다음과 같이 한다.
</p>
<p>
  2.2.1. 접속하고자 하는 계정에 ~/.ssh 디렉토리가 없는 경우 다음의 명령어를
  실행하여 .ssh 디렉토리를 만든 후 공개 키를 authorized_keys 파일에 추가한다.
</p>
<pre class="language-none line-numbers" data-line="1">
<code>PS C:\Users\bitneer&gt; cat $HOME/.ssh/id_rsa.pub | ssh root@192.168.10.10 &quot;umask 077; mkdir ~/.ssh; cat &gt;&gt; ~/.ssh/authorized_keys&quot;
...</code>
</pre>

<p>
  실행 중에 암호를 물으면 192.168.10.10 시스템의 root 계정에 대한 암호를
  입력한다.
</p>
<p>
  2.2.2. 접속하고자 하는 계정에 ~/.ssh 디렉토리가 있는 경우 다음의 명령어를
  실행하여 공개 키를 authorized_keys 파일에 추가한다.
</p>
<pre class="language-none line-numbers" data-line="1">
<code>PS C:\Users\bitneer&gt; cat $HOME/.ssh/id_rsa.pub | ssh root@192.168.10.10 &quot;umask 077; cat &gt;&gt; ~/.ssh/authorized_keys&quot;
...</code>
</pre>

<p>
  3. 암호 없이 ssh를 사용하는 것은 스크립트 파일 작성에 유용하다. 암호를 노출
  시키지 않고 백업 스크립트 등을 작성할 수 있기 때문이다. 예를 들면 다음의
  명령어 등을 시스템에 직접 접속하지 않고 실행할 수 있다.
</p>
<pre class="language-none">
<code>PS C:\Users\bitneer&gt; ssh root@192.168.10.10 &quot;systemctl stop mariadb&quot;
PS C:\Users\bitneer&gt; ssh root@192.168.10.10 &quot;shutdown -h now&quot;</code>
</pre>

<h5>단축키 사용</h5>
<p>다음은 Windows 터미널에서 유용하게 사용할 수 있는 단축키이다.</p>
<ul>
  <li>
    <strong>&lt;Ctrl + Shift + D&gt;</strong> : 현재 창의 프로필을 새 창으로
    연다.
  </li>
  <li><strong>&lt;Ctrl + Tab&gt;</strong> : 탭 간에 전환한다.</li>
  <li>
    <strong>&lt;Alt + Enter&gt;</strong> 또는 <strong>&lt;F11&gt;</strong> :
    전체 화면으로 실행한다. 한 번 더 단축키를 누르면 원래 화면으로 돌아온다.
  </li>
  <li>
    <strong>&lt;Ctrl + Shift + C&gt;</strong>와
    <strong>&lt;Ctrl + Shift + V&gt;</strong>로 복사와 붙여넣기를 하는 습관을
    들인다.
  </li>
</ul>
<p>
  자신이 추가한 프로필을 여는 단축키를 설정하고 싶다면 settings.json 파일에
  다음과 같이 한다.
</p>
<pre class="language-none" data-line="2,8">
<code>...
    &quot;keybindings&quot;:
    [
        // Copy and paste are bound to Ctrl+Shift+C and Ctrl+Shift+V in your defaults.json.
        ...

        // 192.168.10.10 - root
        { &quot;command&quot;: { &quot;action&quot;: &quot;newTab&quot;, &quot;profile&quot;: &quot;{12fec865-77d4-4c96-89ef-e1781e805c13}&quot; }, &quot;keys&quot;: &quot;ctrl+shift+n&quot; }
    ]
}</code>
</pre>

<p>
  맨 마지막에 있는 <strong>&#8220;keybindings&#8221;</strong>에서 라인 8과 같이 단축키
  설정을 추가할 수 있다. <strong>&#8220;profile&#8221;</strong> 속성의 값으로 GUID나
  프로필의 이름(<kbd>"192.168.10.10 - root"</kbd>)을 설정할 수 있다.
  <strong>&#8220;keys&#8221;</strong> 속성에 원하는 단축키를 설정한다.
</p>
<p>
  위 내용은 나의 관점에서 다루었다. 원하는 기능을 추가하고 싶거나 좀 더 개성
  있게 꾸미고 싶다면 참고 자료의 페이지를 보기 바란다.
</p>
<h5>참고 자료</h5>
<ul>
  <li>
    <a href="https://github.com/microsoft/terminal" target="_blank" rel="noopener noreferrer">GitHub &#8211; microsoft/terminal: The new Windows Terminal and the original
      Windows console host, all in the same place!</a
    >
  </li>
  <li>
    <a href="https://docs.microsoft.com/ko-kr/windows/terminal/customize-settings/global-settings" target="_blank" rel="noopener noreferrer">Windows 터미널의 글로벌 설정</a
    >
    /
    <a href="https://docs.microsoft.com/en-us/windows/terminal/customize-settings/global-settings" target="_blank" rel="noopener noreferrer">Global settings in Windows Terminal</a
    >
  </li>
  <li>
    <a href="https://docs.microsoft.com/ko-kr/windows/terminal/customize-settings/profile-settings" target="_blank" rel="noopener noreferrer">Windows 터미널의 프로필 설정</a
    >
    /
    <a href="https://docs.microsoft.com/en-us/windows/terminal/customize-settings/profile-settings" target="_blank" rel="noopener noreferrer">Profile settings in Windows Terminal</a
    >
  </li>
  <li>
    <a href="https://docs.microsoft.com/ko-kr/windows/terminal/customize-settings/key-bindings" target="_blank" rel="noopener noreferrer">Windows 터미널의 사용자 지정 키 바인딩</a
    >
    /
    <a href="https://docs.microsoft.com/en-us/windows/terminal/customize-settings/key-bindings" target="_blank" rel="noopener noreferrer">Custom key bindings in Windows Terminal</a
    >
  </li>
  <li>
    <a href="https://serverfault.com/questions/224810/is-there-an-equivalent-to-ssh-copy-id-for-windows" target="_blank" rel="noopener noreferrer">Is there an equivalent to ssh-copy-id for Windows?</a
    >
  </li>
  <li>
    <a href="https://stackoverflow.com/questions/56839307/adding-git-bash-to-the-new-windows-terminal" target="_blank" rel="noopener noreferrer">Adding Git-Bash to the new Windows Terminal</a
    >
  </li>
  <li>
    <a href="https://www.json.org/json-ko.html" target="_blank" rel="noopener noreferrer">JSON 개요</a
    >
  </li>
</ul>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/windows-%ed%84%b0%eb%af%b8%eb%84%90%ec%9d%98-%ec%84%a4%ec%a0%95-%eb%b0%8f-ssh-%ec%82%ac%ec%9a%a9%ed%95%98%ea%b8%b0/">Windows 터미널의 설정 및 ssh 사용하기</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Confluence 서버의 MySQL을 PostgreSQL로 마이그레이션 하기</title>
		<link>https://www.bitneer.dev/blog/confluence-%ec%84%9c%eb%b2%84%ec%9d%98-mysql%ec%9d%84-posgresql%eb%a1%9c-%eb%a7%88%ec%9d%b4%ea%b7%b8%eb%a0%88%ec%9d%b4%ec%85%98-%ed%95%98%ea%b8%b0/</link>
		
		<dc:creator><![CDATA[Choi Kyung-sik]]></dc:creator>
		<pubDate>Fri, 29 May 2020 22:50:49 +0000</pubDate>
				<category><![CDATA[네트워크와 시스템 관리]]></category>
		<category><![CDATA[데이터베이스 시스템]]></category>
		<category><![CDATA[confluence]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[postgresql]]></category>
		<guid isPermaLink="false">https://www.bitneer.dev/?p=494</guid>

					<description><![CDATA[<p>데비안 시스템의 Confluence 서버에서 MySQL을 PostgreSQL로 마이그레이션 한 과정을 보여주려고 한다. 내가 사용하는 데비안 9(stretch)의 PostgreSQL 버전은 9.6이다. Confluence는 버전 6.13.8을 설치하고 있다. 먼저 이 버전의 Confluence에서 지원하는 데이터베이스를 볼 필요가 있다. Supported Platforms &#8211; Confluence 6.13을 보면 PostgreSQL 9.4, 9.5, 9.6을 지원하므로 마이그레이션을 진행할 수 있다. 작업을 진행하기 전에 MySQL의 데이터베이스와 Confluence 홈 디렉토리를 백업한다. 뒤에서 서술할 내용에서 Confluence의 ...</p>
<p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/confluence-%ec%84%9c%eb%b2%84%ec%9d%98-mysql%ec%9d%84-posgresql%eb%a1%9c-%eb%a7%88%ec%9d%b4%ea%b7%b8%eb%a0%88%ec%9d%b4%ec%85%98-%ed%95%98%ea%b8%b0/">Confluence 서버의 MySQL을 PostgreSQL로 마이그레이션 하기</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>
  데비안 시스템의 Confluence 서버에서 MySQL을 PostgreSQL로 마이그레이션 한
  과정을 보여주려고 한다. 내가 사용하는 데비안 9(stretch)의 PostgreSQL 버전은
  9.6이다. Confluence는 버전 6.13.8을 설치하고 있다. 먼저 이 버전의
  Confluence에서 지원하는 데이터베이스를 볼 필요가 있다.
  <a href="https://confluence.atlassian.com/conf613/supported-platforms-964961686.html" target="_blank" rel="noopener noreferrer">Supported Platforms &#8211; Confluence 6.13</a
  >을 보면 PostgreSQL 9.4, 9.5, 9.6을 지원하므로 마이그레이션을 진행할 수 있다.
  작업을 진행하기 전에 MySQL의 데이터베이스와 Confluence 홈 디렉토리를 백업한다.
  뒤에서 서술할 내용에서 Confluence의 설치 위치는
  <kbd>/opt/share/confluence</kbd>, 홈 디렉토리는
  <kbd>/var/local/lib/confluence</kbd>이다. 여러분이 이와 다르다면 참작해서 보기
  바란다.
</p>
<h5>단계 1. Confluence에 설치한 Atlassian Marketplace 앱의 정보를 확인하기</h5>
<p>
  단계 4에서 보겠지만 기존 버전과 같은 Confluence를 새로 설치하고 앞으로 그것을
  사용해야 한다. 이전의 Confluence에 있던 앱들은 다시 설치해야 한다. 단계 2에서
  생성하는 XML 포맷의 백업 파일에는 앱의 환경 설정 정보들을 가지고 있다. 이 안의
  동일한 버전으로 앱을 설치해야 문제가 발생하지 않을 것이다. 같은 버전으로 쉽게
  설치하기 위해 앱을 미리 <em>업데이트</em>해 주는 것이 좋을 것이다. 업데이트 후
  앱 이름, 버전, 제작자, 활성화 여부를 기록해 둔다. 나의 경우는 다음과 같다.
</p>
<ul>
  <li>
    Atlassian Troubleshooting and Support Tools / 1.25.0 / Atlassian / enabled
  </li>
  <li>
    Atlassian Universal Plugin Manager Plugin / 3.0.6 / Atlassian / enabled
  </li>
  <li>Confluence Cloud Migration Assistant / 2.6.0 / Atlassian / enabled</li>
  <li>Confluence Mobile Plugin / 2.2.4 / Atlassian / enabled</li>
  <li>Refined for Confluence / 6.1.15 / Refined / enabled</li>
  <li>RefinedMobile for Confluence / 3.3.2 / RefinedWiki / enabled</li>
  <li>Gliffy Diagrams for Confluence / 8.6.5 / Gliffy, Inc. / enabled</li>
  <li>LaTex Math / 3.9.13 / Bolo Software / enabled</li>
</ul>
<h5>단계 2. XML 포맷으로 데이터를 백업하기</h5>
<p>
  이 단계를 진행할 때
  <kbd
    >http://<strong>192.168.1.10:8090</strong>/confluence/admin/backup.action</kbd
  >
  주소처럼 Confluence 서버에 직접 연결한다. IP 주소는 Confluence를 설치한
  시스템의 주소로 여러분에게 맞는 것을 입력한다. Proxy 등과 같이 Confluence
  전단의 Apache로 접속하여 작업하면 에러가 날 가능성이 크다. IP 주소로 직접
  접속할 때 Confluence의 base URL을 변경하라는 메시지가 나오면 무시하고 진행해도
  괜찮다. 다음과 같이 작업한다.
</p>
<ol>
  <li>
    Confluence 설정으로 들어가서
    <strong>ADMINISTRATION &gt; Backup &amp; Restore</strong>를 클릭한다.
  </li>
  <li>
    Export this site에서 디폴트 선택인
    <strong>Include attachments</strong> 체크를 그대로 둔 채
    <strong>Export</strong> 버튼을 클릭한다. 백업할 데이터가 크다면 시간이 오래
    걸린다. 인내심을 가지고 기다린다.
  </li>
  <li>
    작업이 완료되면 새로운 창에서 다음과 같이 백업 성공 메시지와 백업 파일의
    저장 위치가 나온다. 그리고 24시간 안에 이 파일이 지워질 것을 알려준다. 나는
    Proxy Error가 한 번 발생해서
    <strong>xmlexport-20200524-215026-2.zip</strong>처럼 끝에
    <strong>-2</strong>가 붙었다. 이후에 이 파일을 복원에 사용할 것이다.
    <pre class="language-none">
<code>The backup was successfully created at /var/local/lib/confluence/temp/xmlexport-20200524-215026-2.zip. This file will be deleted in 24 hours.</code>
</pre>
  </li>
</ol>
<p>
  attachments가 너무 크다면 <strong>Include attachments</strong>를 체크하지 않는
  것이 좋을 수도 있다. 이 경우 단계 5의 다음 단계에서 이전 Confluence의
  attachments를 새 Confluence로 복사해야 할 것이다. 다음의 명령어 실행으로
  attachments의 크기를 알아볼 수 있다.
</p>
<pre class="language-none line-numbers" data-line="1">
<code># du -h /var/local/lib/confluence/attachments
...
4.6G	/var/local/lib/confluence/attachments</code>
</pre>
<p>
  du의 <strong>-h</strong> 옵션은 크기를 읽기 쉽게 K, M, G로 표시해 준다. 나의
  경우 4.6 기가바이트가 나왔는데 attachments 디렉토리를 포함하여 XML 포맷으로
  백업할 수 있었다.
</p>
<h5>단계 3. PostgreSQL의 데이터베이스 만들기</h5>
<p>
  Confluence에서 사용할 PostgreSQL의 데이터베이스를 생성한다. 다음은 psql
  클라이언트를 사용한 진행 과정이다.
</p>
<pre class="language-none" data-line="6,8,10,14">
<code># psql -h localhost -U postgres -d postgres
psql (9.6.17)
SSL 연결정보 (프로토콜: TLSv1.2, 암호화기법: ECDHE-RSA-AES256-GCM-SHA384, 비트: 256, 압축: off)
도움말을 보려면 &quot;help&quot;를 입력하십시오.

postgres=# CREATE ROLE confluence WITH LOGIN PASSWORD &#039;원하는 암호 입력&#039;;
CREATE ROLE
postgres=# CREATE DATABASE confluence WITH ENCODING=&#039;UTF8&#039; OWNER=confluence;
CREATE DATABASE
postgres=# \l
                                  데이터베이스 목록
    이름    |   소유주   | 인코딩 |   Collate   |    Ctype    |      액세스 권한
------------+------------+--------+-------------+-------------+-----------------------
 confluence | confluence | UTF8   | ko_KR.UTF-8 | ko_KR.UTF-8 |
 jira       | jira       | UTF8   | C           | C           |
 postgres   | postgres   | UTF8   | ko_KR.UTF-8 | ko_KR.UTF-8 |
 template0  | postgres   | UTF8   | ko_KR.UTF-8 | ko_KR.UTF-8 | =c/postgres          +
            |            |        |             |             | postgres=CTc/postgres
 template1  | postgres   | UTF8   | ko_KR.UTF-8 | ko_KR.UTF-8 | =c/postgres          +
            |            |        |             |             | postgres=CTc/postgres
(5개 행)</code>
</pre>
<p>
  라인 6에서 <strong>CREATE ROLE</strong>로 <kbd>confluence</kbd> 사용자를
  만든다. 라인 8에서 <strong>CREATE DATABASE</strong>로
  <kbd>confluence</kbd> 데이터베이스를 생성한다. Confluence의 데이터베이스는
  인코딩과 Collation은 utf8로 설정해야 한다. 라인 10에서
  <strong>\l</strong> 명령어로 새로 생성한 confluence 데이터베이스를 확인한다.
  PostgreSQL에 기본적인 사용은
  <a href="https://www.bitneer.dev/wp/postgresql%ec%9d%98-%eb%8d%b0%ec%9d%b4%ed%84%b0%eb%b2%a0%ec%9d%b4%ec%8a%a4%ec%99%80-%ec%82%ac%ec%9a%a9%ec%9e%90-%ec%83%9d%ec%84%b1-%eb%b0%b1%ec%97%85-%eb%b0%8f-%eb%b3%b5%ea%b5%ac/" target="_blank" rel="noopener noreferrer">PostgreSQL의 데이터베이스와 사용자 생성, 백업 및 복구</a
  >를 참고할 수 있다.
</p>
<h5>
  단계 4. 현재 사용하는 Confluence와 같은 버전의 Confluence를 새로 설치하기
</h5>
<p>
  새로 설치하는 Confluence는 <em>현재 사용하는 Confluence와 같은 버전</em>이어야
  한다. 그러나 설치 위치와 홈 디렉토리는 달라져야 한다. 다음과 같이 작업한다.
</p>
<p>1. 현재 사용하는 Confluence를 종료한다.</p>
<p>
  2. 마이그레이션에 실패할 시 빠르게 원래대로 복구하기 위해 기존 Confluence의
  설치 파일과 홈 디렉토리의 이름을 변경해 둔다.
</p>
<pre class="language-none">
<code># mv /opt/share/confluence /opt/share/confluence-old
# mv /var/local/lib/confluence /var/local/lib/confluence-old</code>
</pre>
<p>3. 새 Confluence를 위한 홈 디렉토리를 생성한다.</p>
<pre class="language-none line-numbers" data-line="4">
<code># mkdir /var/local/lib/confluence
# cd /var/local/lib
# chown confluence:confluence confluence
# chmod g-s confluence</code>
</pre>
<p>
  라인 4는 스티키 비트(sticky bit)를 사용하지 않으므로 제거한 것이다. 데비안에서
  /var/local 디렉토리의 그룹에 스티키 비트가 있어 /var/local/lib/confluence
  디렉토리에 스티키 비트가 붙는다. 여러분이 다른 Confluence 홈 디렉토리를
  사용한다면 무시하고 넘어간다.
</p>
<p>
  4. 기존 Confluece와 같은 버전의 TAR.GZ 압축 파일을 /opt/share에 복사한 후
  다음의 절차로 /opt/share/confluece에 위치하도록 압축을 푼다.
</p>
<pre class="language-none line-numbers" data-line="4-7">
<code># cd /opt/share
# tar zxvf atlassian-confluence-6.13.8.tar.gz
# mv atlassian-confluence-6.13.8 confluence
# chown -R root:root confluence
# chown -R confluence:confluence confluence/logs
# chown -R confluence:confluence confluence/temp
# chown -R confluence:confluence confluence/work</code>
</pre>
<p>
  라인 4에서 7까지 파일의 소유주와 그룹을 설정하는 이유는 보안 때문이다.
  Confluence 데몬이 쓰기 권한을 가져야만 하는 logs, temp, work 디렉토리 이외에는
  파일을 저장할 수 없도록 한다. 데몬(서비스)의 보안에 관해서는
  <a href="https://www.bitneer.dev/wp/confluence-jira-bitbucket%ec%9d%98-systemd-unit-%ec%84%a4%ec%a0%95/" target="_blank" rel="noopener noreferrer">Confluence, Jira, Bitbucket의 systemd unit 설정</a
  >에서 볼 수 있다.
</p>
<p>
  5. /opt/share/confluence/confluence/WEB-INF/classes/confluence-init.properties
  파일에서 다음과 같이 Confluence Home Directory를 지정한다.
</p>
<pre class="language-none">
<code>confluence.home=/var/local/lib/confluence</code>
</pre>
<p>
  6. (선택적) Confluence에 접속할 때 웹 브라우저에 따라 언어를 설정하지 않도록
  /opt/share/confluence/bin/setenv.sh 파일에 다음의 내용을 추가한다.
  Confluence에서 언어를 영어로 선택하여 항상 영문 메뉴가 나오도록 하기 위한
  것이다.
</p>
<pre class="language-none">
<code>CATALINA_OPTS="-Dconfluence.browser.language.enabled=false ${CATALINA_OPTS}"</code>
</pre>

<h5>
  단계 5. Confluence Setup Wizard를 진행하여 PostgreSQL로 마이그레이션 하기
</h5>
<p>
  1. 새로 설치한 Confluence 서버를 시작한 후 웹 브라우저로
  <kbd>http://192.168.1.10:8090/</kbd>에 접속하여 Confluence setup wizard를
  진행한다. IP 주소는 여러분에게 맞는 것으로 변경한다.
</p>
<p>
  2.
  <strong>Get apps</strong>에서 <strong>Production Installation</strong>을
  선택하고 <strong>Next</strong> 버튼을 클릭한다.
  <strong>Apps extend what Confluence can do. &#8230;</strong>에서
  <strong>Confluece Questions, Confluece Team Calendars</strong>를 디폴트인
  선택하지 않은 상태를 그대로 둔 채 <strong>Next</strong> 버튼을 클릭한다.
</p>
<p>
  3.
  <strong>License key</strong>에서 Confluence의 라이센스를 입력하고
  <strong>Next</strong> 버튼을 클릭한다. (<a href="https://my.atlassian.com/" target="_blank" rel="noopener noreferrer">https://my.atlassian.com/</a
  >에 접속하여 라이센스 키를 복사할 수 있다.)
</p>
<p>
  4.
  <strong>Set up your database</strong>에서 디폴트 선택인
  <strong>My own database</strong> 선택을 그대로 둔 채
  <strong>Next</strong> 버튼을 클릭한다. 다음의 설정을 한 후
  <strong>Test connection</strong> 버튼을 클릭한다. 데이터베이스 연결에 성공한
  메시지가 나오면 <strong>Next</strong> 버튼을 클릭한다.
</p>
<ul>
  <li>Database type: 디폴트 선택인 PostgreSQL을 그대로 둔다.</li>
  <li>Setup type: 디폴트 선택인 Simple을 그대로 둔다.</li>
  <li>
    Hostname: PostgreSQL이 설치된 시스템의 로컬 IP 주소를 입력한다. (예:
    192.168.1.10)
  </li>
  <li>Post: <kbd>5432</kbd>를 입력한다.</li>
  <li>
    Database name: 위에서 생성한 데이터베이스의 이름인 <kbd>confluecne</kbd>를
    입력한다.
  </li>
  <li>
    Username: 위에서 생성한 데이터베이스의 사용자 이름인 <kbd>confluence</kbd>를
    입력한다.
  </li>
  <li>Password: 위에서 생성한 데이터베이스의 &#8216;암호&#8217;를 입력한다.</li>
</ul>
<p>
  5. <strong>Load Content</strong>에서
  <strong>Restore From Backup</strong> 버튼을 클릭한다.
</p>
<p>
  6. <strong>Restore Data</strong> 화면에서
  <strong>Import form the home directory</strong>로 작업한다. 복원할
  xmlexport-20200524-215026-2.zip 파일의 크기가 25MB보다 크기 때문이다.
</p>
<p>
  6.1. 새로 설치한 Confluence 홈 디렉토리의 restore 디렉토리로 단계 2에서 생성한
  xmlexport-20200524-215026-2.zip 파일을 복사하기 위해 다음의 명령어를 실행한다.
</p>
<pre class="language-none">
<code># cp -a /var/local/lib/confluence-old/temp/xmlexport-20200524-215026-2.zip /var/local/lib/confluence/restore/</code>
</pre>
<p>
  cp의 <strong>-a</strong> 옵션은 파일의 속성인 소유자, 생성 날짜 등을 유지한 채
  복사하기 위한 것이다.
</p>
<p>
  6.2. 복사를 완료하였으면
  <strong>Import from the home directory</strong>의
  <strong>Import</strong> 버튼을 클릭한다. 에러 메시지와 함께
  xmlexport-20200524-215026-2.zip 파일이 보이면 선택하고 다시 한번
  <strong>Import</strong> 버튼을 클릭한다.
</p>
<p>
  6.3.
  <strong>Restore</strong> 과정이 진행된다. Restore 과정이 끝난 후
  <strong>Next</strong> 버튼을 클릭한다.
</p>
<p>
  7.
  <strong>Setup Successful</strong> 화면에서 <strong>Start</strong> 버튼을
  클릭한다.
</p>
<h5>단계 6. Atlassian Marketplace 앱을 다시 설치하기</h5>
<p>
  단계 1에서 메모해 두었던 앱들을 같은 버전으로 다시 설치한다. Confluence
  설정으로 들어가서
  <strong>ATLASSIAN MARKETPLACE &gt; Find new apps</strong>에서 앱을 검색할 수
  있다. Atlassian이 제공하는 앱은 이미 설치되어 있으므로 간단하게 Update만 한다.
</p>
<h5>단계 7. 새로 설치한 Confluence를 위한 설정을 한다.</h5>
<p>
  도메인의 URL 주소로 접속하기 위해 /opt/share/confluence/conf/server.xml 파일을
  수정한다. 나의 경우 Apache의 Proxy를 사용하기 때문에 다음과 같이 한다.
</p>
<p>
  &lt;Context&gt; 지시자의 <strong>path</strong>를 <kbd>/confluence</kbd>로
  설정한다.
</p>
<pre class="language-none">
<code>&lt;Context path="/confluence" docBase="../confluence" debug="0" reloadable="false" useHttpOnly="true"&gt</code>
</pre>
<p>
  디폴트 &lt;Connector&gt; 지시자는 주석 처리한다. HTTS 상의 Proxying인
  &lt;Connector&gt; 지시자의 주석을 제거하고 <strong>proxyName</strong>을
  <kbd>www.bitneer.dev</kbd>로 변경한다.
</p>
<pre class="language-markup line-numbers" data-line="5">
<code>&lt;Connector port=&quot;8090&quot; connectionTimeout=&quot;20000&quot; redirectPort=&quot;8443&quot;
           maxThreads=&quot;48&quot; minSpareThreads=&quot;10&quot;
           enableLookups=&quot;false&quot; acceptCount=&quot;10&quot; debug=&quot;0&quot; URIEncoding=&quot;UTF-8&quot;
           protocol=&quot;org.apache.coyote.http11.Http11NioProtocol&quot;
           scheme=&quot;https&quot; secure=&quot;true&quot; proxyName=&quot;www.bitneer.dev&quot; proxyPort=&quot;443&quot;/&gt;
</code></pre>
<p>
  Confluence를 다시 시작하고 웹 브라우저로 Confluence에 접속한다. Confluence
  설정에 들어가서 <strong>CONFIGURATION &gt; General Configuration</strong>의
  <strong>Server Base URL</strong>을 도메인 주소에 맞게 설정한다.
</p>
<h5>단계 8. 문제 점검 및 기존 파일 삭제하기</h5>
<p>
  다음의 명령어를 실행한 후 다른 ssh 연결 세션에서 Confluence를 시작, 종료하면서
  발생하는 로그를 검사한다.
</p>

<pre class="language-none">
<code># tail -100f /var/local/lib/confluence/logs/atlassian-confluence.log</code>
</pre>
<p>
  위의 atlassian-confluence.log에 Error 로그가 보인다면 Confluence 설정의
  <strong>ADMINISTRATION &gt; Troubleshooting and support tools</strong>의
  <strong>Log analyzer</strong>에서 문제를 해결할 수 있는지 확인한다. 해당 Error
  로그를 클릭하면 해결책을 제시하는 페이지에 접속할 수 있다.
</p>
<p>
  Confluence 설정의
  <strong>ADMINISTRATION &gt; Troubleshooting and support tools</strong>의
  <strong>Instance heath</strong>에 문제가 있는지 확인한다.
  atlassian-confluence.log에 Error 로그가 나오더라도
  <strong>Instance heath</strong>에서 모든 항목이 초록색으로 표시되어 있고
  <strong>Log analyzer</strong>에 해당 Error 로그가 나오지 않는다면 Confluence
  사용에 크게 문제를 일으키지는 않는 것으로 보인다.
</p>
<p>
  MySQL에서 PostgreSQL로 마이그레이션에 성공하였다면 기존의 Confluence 관련
  파일을 삭제한다.
</p>
<pre class="language-none">
<code># cd /opt/share/
# rm -rf confluence-old
# rm atlassian-confluence-6.13.8.tar.gz
# cd /var/local/lib/
# rm -rf confluence-old</code>
</pre>

<h5>관련 글</h5>
<ul>
  <li>
    <a href="https://www.bitneer.dev/wp/confluence-jira-bitbucket%ec%9d%98-systemd-unit-%ec%84%a4%ec%a0%95/" target="_blank" rel="noopener noreferrer">Confluence, Jira, Bitbucket의 systemd unit 설정</a
    >
  </li>
</ul>
<h5>참고 자료</h5>
<ul>
  <li>
    <a href="https://confluence.atlassian.com/conf613/supported-platforms-964961686.html" target="_blank" rel="noopener noreferrer">Supported Platforms &#8211; Confluence 6.13</a
    >
  </li>
  <li>
    <a href="https://confluence.atlassian.com/conf613/migrating-to-another-database-964961318.html" target="_blank" rel="noopener noreferrer">Migrating to Another Database &#8211; Confluence 6.13</a
    >
  </li>
  <li>
    <a href="https://confluence.atlassian.com/conf613/database-setup-for-postgresql-964961302.html" target="_blank" rel="noopener noreferrer">Database Setup for PostgreSQL &#8211; Confluence 6.13</a
    >
  </li>
</ul><p>The post <a rel="nofollow" href="https://www.bitneer.dev/blog/confluence-%ec%84%9c%eb%b2%84%ec%9d%98-mysql%ec%9d%84-posgresql%eb%a1%9c-%eb%a7%88%ec%9d%b4%ea%b7%b8%eb%a0%88%ec%9d%b4%ec%85%98-%ed%95%98%ea%b8%b0/">Confluence 서버의 MySQL을 PostgreSQL로 마이그레이션 하기</a> appeared first on <a rel="nofollow" href="https://www.bitneer.dev">bitneer.dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
