<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>구르미의 개발 이야기</title>
    <link>https://gurumee92.tistory.com/</link>
    <description>구르미의 개발 블로그입니다.
개발, Devops 관련 포스팅을 주로 다루고 있습니다.</description>
    <language>ko</language>
    <pubDate>Wed, 15 Apr 2026 06:19:13 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Gurumee</managingEditor>
    <image>
      <title>구르미의 개발 이야기</title>
      <url>https://tistory1.daumcdn.net/tistory/2871444/attach/96ac41f5dbc24067a4ca1bcd00bda3df</url>
      <link>https://gurumee92.tistory.com</link>
    </image>
    <item>
      <title>vcpkg cmake gtest를 이용하여 C++ 단위 테스트 환경 구축하기</title>
      <link>https://gurumee92.tistory.com/330</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ChatGPT Image 2025년 8월 19일 오후 03_03_05.png&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btHrhi/btsPWtE5lAg/aht2c53WGrJNGlulw0BiQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btHrhi/btsPWtE5lAg/aht2c53WGrJNGlulw0BiQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btHrhi/btsPWtE5lAg/aht2c53WGrJNGlulw0BiQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtHrhi%2FbtsPWtE5lAg%2Faht2c53WGrJNGlulw0BiQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1536&quot; height=&quot;1024&quot; data-filename=&quot;ChatGPT Image 2025년 8월 19일 오후 03_03_05.png&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;vcpkg 설치하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;vcpkg&lt;/code&gt;란 마이크로소프트에서 만든 C/C++을 위한 패키지 매니저이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 &lt;a href=&quot;https://learn.microsoft.com/ko-kr/vcpkg/get_started/get-started?pivots=shell-bash&quot;&gt;문서&lt;/a&gt; 참조하여 설치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필수 조건&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;c++&lt;/li&gt;
&lt;li&gt;cmake&lt;/li&gt;
&lt;li&gt;ninja-build&lt;/li&gt;
&lt;li&gt;git&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 명령어 이용하여 설치한다.&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;git clone https://github.com/microsoft/vcpkg.git
cd vcpkg &amp;amp;&amp;amp; ./bootstrap-vcpkg.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경 변수를 등록한다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot;&gt;&lt;code&gt;echo &quot;VCPKG_ROOT=$PWD&quot; &amp;gt;&amp;gt; ~/.bashrc
echo &quot;export PATH=\$PATH:$VCPKG_ROOT&quot; &amp;gt;&amp;gt; ~/.bashrc

source ~/.bashrc&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 명령어를 이용하여 설치를 확인한다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# vcpkg version
vcpkg version 
# 다음이 출력됨    
vcpkg package management program version 2025-07-21-d4b65a2b83ae6c3526acd1c6f3b51aff2a884533

See LICENSE.txt for license information.&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;vcpkg, cmake를 이용하여, 프로젝트 만들기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/vcpkg/get_started/get-started?pivots=shell-bash&quot;&gt;MS 공식 문서&lt;/a&gt;에서 관련해서 자세한 내용이 적혀 있다. 먼저 프로젝트 디렉토리를 생성한다.&lt;/p&gt;
&lt;pre class=&quot;dos&quot;&gt;&lt;code&gt;mkdir hello_vcpkg &amp;amp;&amp;amp; cd hello_vcpkg&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 &lt;code&gt;vcpkg new&lt;/code&gt; 명령어를 이용하여, 메니페스트 파일 &lt;code&gt;vcpkg.json&lt;/code&gt;을 생성한다.&lt;/p&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;vcpkg new --application&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 다음 명령어로 &lt;code&gt;fmt&lt;/code&gt; 라이브러리를 추가한다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# vcpkg add port &amp;lt;라이브러리 이름&amp;gt;
vcpkg add port fmt&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 &lt;code&gt;vcpkg.json&lt;/code&gt;에 다음 내용이 추가된다.&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;dependencies&quot;: [
    &quot;fmt&quot;
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;CMakeLists.txt&lt;/code&gt; 파일을 다음과 같이 생성한다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;cmake_minimum_required(VERSION 3.10)                 # 프로젝트를 빌드하는 데 필요한 CMake의 최소 버전이 3.10임을 지정
project(hello_vcpkg)                                 # 프로젝트 이름
find_package(fmt CONFIG REQUIRED)                    # fmt 라이브러리가 있는지 확인
add_executable(hello_vcpkg src/main.cpp)             # 소스 파일 src/main.cpp 로부터 hello_vcpkg 실행 파일을 만들게 한다.
target_link_libraries(hello_vcpkg PRIVATE fmt::fmt)  # 실행 파일 hello_vcpkg에 fmt 라이브러리를 링킹합니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 &lt;code&gt;src&lt;/code&gt; 디렉토리를 만들고 &lt;code&gt;main.cpp&lt;/code&gt; 를 생성한 후 다음과 같이 작성한다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;#include &amp;lt;fmt/core.h&amp;gt;
#include &quot;hello.h&quot;

int main() {
    fmt::print(&quot;Hello Vcpkg!\n&quot;);
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 루트 디렉토리에 &lt;code&gt;CMakePresets.json&lt;/code&gt;을 다음과 같이 작성한다.&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;version&quot;: 2,
  &quot;configurePresets&quot;: [
    {
      &quot;name&quot;: &quot;vcpkg&quot;,
      &quot;generator&quot;: &quot;Ninja&quot;,
      &quot;binaryDir&quot;: &quot;${sourceDir}/build&quot;,
      &quot;cacheVariables&quot;: {
        &quot;CMAKE_TOOLCHAIN_FILE&quot;: &quot;$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake&quot;
      }
    }
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 다음 명령어를 입력하여 빌드를 구성한다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;cmake --preset=vcpkg&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 다음 명령어로 프로젝트를 빌드할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;cmake --build build&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션 실행은 다음 명령어를 실행하면 된다.&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;./build/hello_vcpkg

# 다음이 출력됨
Hello Vcpkg!&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단위테스트 할 수 있도록 리팩토링하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트를 더 쉽게 하기 위해서 리팩토링을 먼저 진행한다. (보통은 테스트를 작성한 후 리팩토링을 하는 것이 일반적이다.) &lt;code&gt;src&lt;/code&gt; 디렉토리 밑에 &lt;code&gt;utils&lt;/code&gt; 디렉토리를 만든다. 그 후, &lt;code&gt;hello.h&lt;/code&gt;를 다음과 같이 작성한다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#pragma once
#include &amp;lt;string&amp;gt;

std::string getHelloMessage();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 함수 본문을 작성하기 위해서 &lt;code&gt;hello.cpp&lt;/code&gt;를 작성한다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#include &quot;hello.h&quot;

std::string getHelloMessage() {
    return &quot;Hello Vcpkg!\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 &lt;code&gt;utils&lt;/code&gt; 디렉토리에 대해서 &lt;code&gt;cmake&lt;/code&gt; 빌드에 들어갈 수 있도록 &lt;code&gt;CMakeLists.txt&lt;/code&gt;를 &lt;code&gt;utils&lt;/code&gt; 디렉토리 밑에 하나 생성한다.&lt;/p&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;# utils 라이브러리 생성
# 여기에는 &quot;&amp;lt;라이브러리 이름&amp;gt; &amp;lt;등록할 cpp 파일 1&amp;gt; &amp;lt;등록할 cpp 파일 2&amp;gt; ...&quot; 이렇게 작성한다. 
add_library(utils hello.cpp)              

# utils 디렉토리 하위에 작성된 헤더들을 찾을 수 있게 하는 설정입니다.
target_include_directories(utils PUBLIC  
    ${CMAKE_CURRENT_SOURCE_DIR}
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 루트 &lt;code&gt;CMakeLists.txt&lt;/code&gt;를 다음과 같이 수정한다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;cmake_minimum_required(VERSION 3.10)
project(hello_vcpkg)

set(CMAKE_CXX_STANDARD 17)

# utils 라이브러리 등록
add_subdirectory(src/utils)

find_package(fmt CONFIG REQUIRED)
add_executable(hello_vcpkg src/main.cpp)

# fmt와 함께 utils 라이브러리 등록
target_link_libraries(hello_vcpkg 
    PRIVATE
        fmt::fmt utils
)
target_include_directories(hello_vcpkg 
    PUBLIC
        &quot;${PROJECT_BINARY_DIR}&quot;
        &quot;${PROJECT_SOURCE_DIR}/utils&quot;
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;src/main.cpp&lt;/code&gt;를 다음과 같이 수정한다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;#include &amp;lt;fmt/core.h&amp;gt;
#include &quot;hello.h&quot;

int main() {
    auto message = getHelloMessage();
    fmt::print(message);
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 빌드하여, 정사 결과가 반환되는지 확인합니다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;# 라이브러리 추가 후 빌드 재구성
cmake --preset=vcpkg       

# 빌드
cmake --build build

# 실행 파일 실행
./build/hello_vcpkg&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Google Test 라이브러리를 이용하여 단위 테스트 환경 구축하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;gtest(Google Test)&lt;/code&gt; 라이브러리를 이용하여 단위 테스트 환경을 구축할 것이다. 다음 명령어를 입력한다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;vcpkg add port gtest&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 &lt;code&gt;vcpkg.json&lt;/code&gt;에 다음 내용이 추가된다.&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;dependencies&quot;: [
    &quot;fmt&quot;,
    &quot;gtest&quot; // &amp;lt;- 추가
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 &lt;code&gt;tests&lt;/code&gt; 디렉토리를 만들고 &lt;code&gt;main_test.cpp&lt;/code&gt;를 다음과 같이 작성한다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;#include &amp;lt;gtest/gtest.h&amp;gt;
#include &quot;hello.h&quot;

TEST(MainTest, ReturnsHelloVcpkg) {                 // TEST 매크로는 테스트를 실행하는 함수를 의미한다. 첫 번째 인수는 TestSuitName, 두 번쨰 인수는 TestName이다. 간단하게 말하면, MainTest는 실행할 테스트 클래스, ReturnsHelloVcpkg는 테스트 메소드 이름이다.
    auto message = getHelloMessage();
    EXPECT_EQ(message, &quot;Hello Vcpkg!\n&quot;);
}


int main(int argc, char **argv) {                   // gtest 실행 메인 함수이다. 테스트 실행 시, 엔드리포인트가 된다.
    ::testing::InitGoogleTest(&amp;amp;argc, argv);
    return RUN_ALL_TESTS();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 &lt;code&gt;CMakeLists.txt&lt;/code&gt;에 다음 내용을 추가한다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;cmake_minimum_required(VERSION 3.10)
project(hello_vcpkg)
set(CMAKE_CXX_STANDARD 17)

add_subdirectory(src/utils)

find_package(fmt CONFIG REQUIRED)
add_executable(hello_vcpkg src/main.cpp)
target_link_libraries(hello_vcpkg 
    PRIVATE
        fmt::fmt utils
)
target_include_directories(hello_vcpkg 
    PUBLIC
        &quot;${PROJECT_BINARY_DIR}&quot;
        &quot;${PROJECT_SOURCE_DIR}/utils&quot;
)

# 추가된 내용
enable_testing()
find_package(GTest CONFIG REQUIRED)
add_executable(hello_vcpkg_tests tests/main_test.cpp)
target_link_libraries(hello_vcpkg_tests 
    PRIVATE 
        GTest::gtest GTest::gtest_main fmt::fmt pthread utils
)
target_include_directories(hello_vcpkg_tests
    PUBLIC
        &quot;${PROJECT_BINARY_DIR}&quot;
        &quot;${PROJECT_SOURCE_DIR}/utils&quot;
)

add_test(NAME hello_vcpkg_tests COMMAND hello_vcpkg_tests)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후, 다음 명령어를 입력한다.&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;# 라이브러리 추가 후 빌드 재구성
cmake --preset=vcpkg       

# 빌드
cmake --build build&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 다음 명령어를 입력하면 테스트 파일을 실행할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;cd build &amp;amp;&amp;amp; ctest &amp;amp;&amp;amp; cd ../
# 다음이 출력됨
Test project /home/gurumee/Workspaces/studies/00_project/cli-cpp/01/hello_vcpkg/build
    Start 1: hello_vcpkg_tests
1/1 Test #1: hello_vcpkg_tests ................   Passed    0.00 sec

100% tests passed, 0 tests failed out of 1

Total Test time (real) =   0.01 sec&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/c++</category>
      <category>cmake</category>
      <category>cpp</category>
      <category>gtest</category>
      <category>Unit Test</category>
      <category>vcpkg</category>
      <category>단위 테스트</category>
      <author>Gurumee</author>
      <guid isPermaLink="true">https://gurumee92.tistory.com/330</guid>
      <comments>https://gurumee92.tistory.com/330#entry330comment</comments>
      <pubDate>Tue, 19 Aug 2025 14:55:15 +0900</pubDate>
    </item>
    <item>
      <title>C#&amp;nbsp;시작하기</title>
      <link>https://gurumee92.tistory.com/329</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  이 문서는 The Rust Programming Language를 보고, C# 기준으로 재구성하였습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;C# 설치하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;C#&lt;/code&gt; 을 설치하기 위해서 &lt;code&gt;dotnet&lt;/code&gt; CLI 도구를 설치합니다. &lt;code&gt;dotnet&lt;/code&gt; 도구는 빌드 도구이자, 패키지 매니저이며 &lt;code&gt;C#&lt;/code&gt; 개발을 위한 필수적인 도구입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리눅스 환경에 설치하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문서에서는 &lt;code&gt;kali-linux&lt;/code&gt; 배포판 기준으로 진행합니다. 다음 명령어를 입력하여 설치합니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo apt-get update &amp;amp;&amp;amp; \
  sudo apt-get install -y dotnet-sdk-9.0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ 이 단계에서 설치가 진행되지 않을 수 있습니다.&lt;br /&gt;현재 운영체제가 기본적으로 dotnet-sdk-9.0 패키지 레포지토리를 인식하지 못할 수 도 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744725651312&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ wget https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
$ sudo dpkg -i packages-microsoft-prod.deb
$ rm packages-microsoft-prod.deb&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치가 완료된 후, &lt;code&gt;dotnet --version&lt;/code&gt; 명령어를 입력하면 현재 버전을 확인할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ dotnet --version
9.0.203&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;업데이트 및 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 명령어들로 &lt;code&gt;donet&lt;/code&gt; 도구를 업데이트 및 삭제할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업데이트:&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo apt-get update
$ sudo apt-get upgraade&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삭제:&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo apt-get remove --purge dotnet-sdk-9.0&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Hello World!&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  적절한 코드 에디터 혹은 IDE를 설치하세요!&lt;br /&gt;&lt;br /&gt;이 절을 진행하기 이전에, 러스트 개발하기 좋은 코드 에디터 혹은 IDE를 설치해주세요. 대표적인 코드 에디터로는&amp;nbsp;VSCode,&amp;nbsp;Cursor AI&amp;nbsp;,&amp;nbsp;Wind Surf&amp;nbsp;가 있고, IDE로는&amp;nbsp;Visual Studio,&amp;nbsp;Rider&amp;nbsp;가 있습니다. 이 문서에서는 코드 에디터&amp;nbsp;Cursor AI&amp;nbsp;기준으로 합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Hello World!&lt;/code&gt;란 프로그래밍 언어를 배울 때, 관례적으로 만드는, 단순히 &lt;code&gt;Hello World!&lt;/code&gt;라는 문자열을 출력하는 프로그램입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로젝트 생성하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;code&gt;dotnet new&lt;/code&gt; 명령어를 이용하여 프로젝트를 생성하세요!&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# 프로젝트 모음 디렉토리 생성
$ mkdir ~/projects

# 프로젝트 모음 디렉토리로 이동
$ cd ~/projects

# 콘솔 기반 Hello World! 프로젝트 생성
$ dotnet new console --use-program-main -o HelloWorld
The template &quot;Console App&quot; was created successfully.

Processing post-creation actions...
Restoring /home/gurumee/Workspaces/studies/TheCSharapProgrammingLanguage/HelloWorld/HelloWorld.csproj:
Restore succeeded.

# Hello World! 프로젝트 이동
$ cd HelloWorld&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 생성된 프로젝트가 어떻게 구성되었는지 확인해보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;# 디렉토리 구성 확인
$ tree              
.
├── HelloWorld.csproj
├── obj
│   ├── HelloWorld.csproj.nuget.dgspec.json
│   ├── HelloWorld.csproj.nuget.g.props
│   ├── HelloWorld.csproj.nuget.g.targets
│   ├── project.assets.json
│   └── project.nuget.cache
└── Program.cs

2 directories, 7 files&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 파일 몇 가지만 짚고 넘어가겠습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;HelloWorld.csproj&lt;/code&gt; : 프로젝트 설정 파일입니다. 현재 &lt;code&gt;C#&lt;/code&gt; 버전 정보 등의 프로젝트 설정들이 들어있습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Program.cs&lt;/code&gt; : 메인 함수가 존재하고 있는 &lt;code&gt;C#&lt;/code&gt; 파일입니다. &lt;code&gt;.cs&lt;/code&gt; 확장자는 &lt;code&gt;C#&lt;/code&gt; 으로 작성된 코드 파일을 의미합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 생성된 &lt;code&gt;Program.cs&lt;/code&gt; 코드를 확인해봅시다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;namespace HelloWorld;

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(&quot;Hello, World!&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Hello World! 프로그램 뜯어보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Program.cs&lt;/code&gt; 코드를 분석해봅시다. 먼저 살펴볼 부분은 다음과 같습니다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;namespace HelloWorld;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 &lt;code&gt;C#&lt;/code&gt; 에서 네임스페이스를 지정한 부분입니다. &lt;code&gt;C#&lt;/code&gt; 에서 네임스페이스는 고유한 공간을 의미하며, 대규모 프로젝트에서 클래스 및 메서드 이름의 범위를 제어하는 단위입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음은 클래스입니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;// ...
class Program
{
    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;C#&lt;/code&gt; 의 모든 것은 클래스로 이루어져 있습니다. 클래스는 개체의 속성을 나타내는 필드들과 행동을 정의하는 메소드들을 가질 수 있습니다. 여기서는 &lt;code&gt;Main&lt;/code&gt; 메소드를 정의하기 위해서 꼭 필요한 구문이다 정도로 이해하고 넘어가도 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;Main&lt;/code&gt; 메소드입니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;// ... 
    static void Main(string[] args)
    {
        Console.WriteLine(&quot;Hello, World!&quot;);
    }
 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 부분 몇 가지만 짚고 넘어가겠습니다. 먼저, &lt;code&gt;Main&lt;/code&gt; 메소드는 프로그램의 시작 지점입니다. 아주 특별한 메소드로써, 프로젝트 내에서 단 하나의 클래스에서만 유일하게 존재할 수 있습니다. 메소드는 일종의 작은 코드 조각으로써, 구문들로 구성되어 있다고 합니다. &lt;code&gt;Main&lt;/code&gt; 메소드는 Hello, World! 문자열을 출력합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Console.WriteLine&lt;/code&gt; 은 콘솔 객체의 메소드로 주어진 문자열을 출력하는 메소드입니다. 메소드 이름 뒤에는 &lt;code&gt;()&lt;/code&gt; 를 꼭 써야 합니다. 이 안에는 인자를 전달합니다. 이 메소드의 인자로 &lt;code&gt;&quot;Hello, World!&quot;&lt;/code&gt; 문자열이 전달되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Main&lt;/code&gt; 메소드의 인자 &lt;code&gt;string[] args&lt;/code&gt; 는 특별한 인자입니다. 프로그램 실행 인자로써 외부에서 데이터를 전달 받을 때 사용합니다. 지금은 그냥 이런 것이 있다 정도로만 이해해주시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 구문 뒤에는 반드시 &lt;code&gt;;&lt;/code&gt; 이 붙습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;C# 프로젝트 실행하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 프로젝트를 실행해보도록 하겠습니다. 터미널에 &lt;code&gt;dotnet run&lt;/code&gt; 이란 명령어를 입력하면 프로젝트를 실행할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;# 프로젝트 실행
$ dotnet run          
Hello, World!&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;C# 프로젝트 빌드하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 마지막으로 프로젝트를 빌드하고 실행해보겠습니다. 터미널에 &lt;code&gt;dotnet build&lt;/code&gt; 명령어를 입력하면 프로젝트를 빌드할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ dotnet build
Restore complete (0.3s)
  HelloWorld succeeded (0.1s) &amp;rarr; bin/Debug/net9.0/HelloWorld.dll

Build succeeded in 0.6s&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 빌드하면, &lt;code&gt;bin/Debug/net9.0&lt;/code&gt; 폴더에 &lt;code&gt;HelloWorld&lt;/code&gt; 란 실행 파일이 생성됩니다. 이제 실행 파일을 생성해봅시다.&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;$ ./bin/Debug/net9.0/HelloWorld
Hello, World!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 &lt;code&gt;dotnet run&lt;/code&gt; 이란 명령어는 빌드 후 실행 파일을 실행하는 것을 축약한 명령어입니다.&lt;/p&gt;</description>
      <category>프로그래밍 언어/c#</category>
      <category>c#</category>
      <category>C# 기초</category>
      <category>c# 시작하기</category>
      <category>CSharp</category>
      <category>dotnet</category>
      <category>dotnet build</category>
      <category>dotnet new</category>
      <category>dotnet run</category>
      <category>프로그래밍 기초</category>
      <author>Gurumee</author>
      <guid isPermaLink="true">https://gurumee92.tistory.com/329</guid>
      <comments>https://gurumee92.tistory.com/329#entry329comment</comments>
      <pubDate>Tue, 15 Apr 2025 22:59:35 +0900</pubDate>
    </item>
    <item>
      <title>러스트 시작하기</title>
      <link>https://gurumee92.tistory.com/328</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  이 문서는 The Rust Programming Language를 보고 재구성하였습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;러스트 설치하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;러스트를 설치하기 위해서 &lt;code&gt;rustup&lt;/code&gt; CLI 도구를 설치합니다. &lt;code&gt;rustup&lt;/code&gt; 도구는 러스트 컴파일러인 &lt;code&gt;rustc&lt;/code&gt; , 파일을 깔끔하게 코드 스타일을 관리할 수 있는 포매터 &lt;code&gt;rustfmt&lt;/code&gt;, 그리고 라이브러리 의존성을 관리할 수 있는 &lt;code&gt;cargo&lt;/code&gt; 등의 도구들이 모두 들어있기 때문에 간편하게 러스트 개발 환경을 구성할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리눅스 및 맥 환경에 설치하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 명령어를 입력하여 설치합니다.&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;$ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치가 완료되면 다음 문구가 나타납니다.&lt;/p&gt;
&lt;pre class=&quot;mizar&quot;&gt;&lt;code&gt;Rust is installed now. Great!&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ 이 단계에서 C 컴파일러 설치가 필요할 수 있습니다!&lt;br /&gt;러스트&amp;nbsp;링커의&amp;nbsp;경우,&amp;nbsp;기본으로&amp;nbsp;설치됩니다.&amp;nbsp;그러나,&amp;nbsp;컴파일&amp;nbsp;시&amp;nbsp;실행할&amp;nbsp;수&amp;nbsp;없다는&amp;nbsp;에러가&amp;nbsp;나타날&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;이&amp;nbsp;경우에,&amp;nbsp;각&amp;nbsp;운영&amp;nbsp;환경에&amp;nbsp;맞는&amp;nbsp;C&amp;nbsp;컴파일러가&amp;nbsp;필요합니다.&lt;br /&gt;&lt;br /&gt;리눅스:&lt;br /&gt;일반적으로&amp;nbsp;`gcc`&amp;nbsp;나&amp;nbsp;`Clang`&amp;nbsp;이&amp;nbsp;설치되어&amp;nbsp;있습니다.&amp;nbsp;만약&amp;nbsp;설치되지&amp;nbsp;않은&amp;nbsp;경우&amp;nbsp;우분투의&amp;nbsp;`build-essential`&amp;nbsp;같은&amp;nbsp;기본&amp;nbsp;패키지를&amp;nbsp;재설치하면&amp;nbsp;컴파일러를&amp;nbsp;설치할&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;맥:&lt;br /&gt;다음 명령어로 설치할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744460688084&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ xcode-select --install&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;업데이트 및 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 명령어들로 &lt;code&gt;rustup&lt;/code&gt; 을 업데이트 및 삭제할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업데이트:&lt;/p&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;$ rustup update&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삭제:&lt;/p&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;$ rustup self uninstall&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Hello World!&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  적절한 코드 에디터 혹은 IDE를 설치하세요!&lt;br /&gt;이&amp;nbsp;절을&amp;nbsp;진행하기&amp;nbsp;이전에,&amp;nbsp;러스트&amp;nbsp;개발하기&amp;nbsp;좋은&amp;nbsp;코드&amp;nbsp;에디터&amp;nbsp;혹은&amp;nbsp;IDE를&amp;nbsp;설치해주세요.&amp;nbsp;대표적인&amp;nbsp;코드&amp;nbsp;에디터로는&amp;nbsp;`VSCode`,&amp;nbsp;`Cursor&amp;nbsp;AI`&amp;nbsp;,&amp;nbsp;`Wind&amp;nbsp;Surf`&amp;nbsp;가&amp;nbsp;있고,&amp;nbsp;IDE로는&amp;nbsp;`RustRover`&amp;nbsp;가&amp;nbsp;있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Hello World!&lt;/code&gt;란 프로그래밍 언어를 배울 때, 관례적으로 만드는, 단순히 &lt;code&gt;Hello World!&lt;/code&gt;라는 문자열을 출력하는 프로그램입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로젝트 디렉토리 생성하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 다음 명령어를 이용하여 프로젝트를 생성하세요!&lt;/p&gt;
&lt;pre class=&quot;shell&quot;&gt;&lt;code&gt;# 프로젝트 모음 디렉토리 생성
$ mkdir ~/projects

# 프로젝트 모음 디렉토리로 이동
$ cd ~/projects

# Hello World! 프로젝트 생성
$ mkdir hello_world

# Hello World! 프로젝트 이동
$ cd hello_world&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;러스트 프로그램 작성하고 실행하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;main.rs&lt;/code&gt; 를 다음과 같이 작성합니다.&lt;/p&gt;
&lt;pre class=&quot;rust&quot;&gt;&lt;code&gt;fn main() {
    println!(&quot;Hello, World!&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후, 터미널에 다음을 입력하여, &amp;ldquo;컴파일&amp;rdquo;합니다.&lt;/p&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;$ rustc main.rs&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 프로젝트 디렉토리 내에 &lt;code&gt;main&lt;/code&gt; 이라는 실행 파일이 생성됩니다.&lt;/p&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;$ ls
main    main.rs&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 우리가 생성한 프로그램을 실행할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;autohotkey&quot;&gt;&lt;code&gt;$ ./main
Hello, World!&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;러스트 프로그램 뜯어보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 살펴볼 부분은 다음과 같습니다.&lt;/p&gt;
&lt;pre class=&quot;rust&quot;&gt;&lt;code&gt;fn main() {
    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 러스트에서 &lt;code&gt;main&lt;/code&gt; 함수를 정의한 것입니다. 일반적으로 &lt;code&gt;main&lt;/code&gt; 함수는 특별한 함수로써 실행 프로그램에서 가장 먼저 실행되는 부분입니다. 여기서는 프로그램 실행 매개 변수를 아무것도 받지 않았지만, 매개 변수를 받고 싶다면 &lt;code&gt;()&lt;/code&gt; 이 부분에 매개 변수를 작성해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;러스트에서 함수 본문은 항상 &lt;code&gt;{}&lt;/code&gt; 로 감싸주어야 합니다. 이제 &lt;code&gt;main&lt;/code&gt; 함수 내 코드를 살펴봅시다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;    println!(&quot;Hello, World!&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드가 실제 로직인 &lt;code&gt;Hello, World!&lt;/code&gt; 를 출력하는 코드입니다. 대표적으로 세가지만 살펴봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;code&gt;println!&lt;/code&gt; 은 매크로입니다. 여기서는 호출 부에 &lt;code&gt;!&lt;/code&gt; 가 붙은 건 매크로라고 알아둡시다. 이 매크로는 &lt;code&gt;()&lt;/code&gt; 안의 문자열을 출력합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째는, &lt;code&gt;&quot;Hello, World!&quot;&lt;/code&gt; 는 문자열 리터럴입니다. 리터럴이란 일반적으로 고정된 값을 의미합니다. 숫자나 문자(&lt;code&gt;&amp;rsquo;&amp;rsquo;&lt;/code&gt;), 문자열(&lt;code&gt;&amp;rdquo;&amp;rdquo;&lt;/code&gt;)이 대표적인 리터럴입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 러스트는 모든 표현식 뒤에 &lt;code&gt;;&lt;/code&gt; 붙여야 합니다. 러스트 코드의 거의 모든 라인이 이 문자로 끝난다는 것을 알아두세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Hello Cargo!&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 cargo 를 이용하여 러스트 애플리케이션을 만들어보겠습니다. cargo 란 러스트의 빌드 도구이자 패키지 매니저입니다. 간단한 프로그램이라면, &amp;ldquo;Hello World!&amp;rdquo; 프로젝트처럼 간단하게 러스트 코드를 작성하고 rustc 로 컴파일 후 실행해도 좋습니다. 하지만 애플리케이션이 복잡해질수록 cargo 를 이용하는 것을 권장드립니다. 이 도구는 코드 빌드나, 코드 작성에 필요한 외부 라이브러리를 다운로드할 때나, 라이브러리를 제작할 때 겪는 귀찮은 일들을 상당수 줄여주는 편리한 도구입니다&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;카고로 프로젝트 생성하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 프로젝트 모음ㅁ 디렉토리로 이동합니다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;# 프로젝트 모음 디렉토리로 이동
$ cd ~/projects
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 모음 디렉토리에서 현재 생성된 프로젝트 목록을 확인해보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;# 프로젝트 목록 확인
$ ls 
hello_world
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 cargo 로 프로젝트를 생성해봅시다. 다음 명령어를 입력해주세요.&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# cargo로 프로젝트 생성
# cargo new &amp;lt;프로젝트 이름&amp;gt;
$ cargo new hello_cargo    
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 프로젝트 목록을 확인해봅시다.&lt;/p&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;# 프로젝트 목록 확인
$ ls 
hello_cargo  hello_world
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hello_cargo 프로젝트가 생성된 것을 확인할 수 있습니다. 이제 디렉토리로 이동한 후 어떻게 디렉토리가 구성되었는지 확인해보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;shell&quot;&gt;&lt;code&gt;# hello_cargo 프로젝트 이동
$ cd hello_cargo

# 디렉토리 구성 확인
$ tree              
.
├── hello_cargo
│   ├── Cargo.toml
│   └── src
│       └── main.rs
└── hello_world
    └── main.rs

4 directories, 3 files
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 생성된 src/main.rs 코드를 확인해봅시다.&lt;/p&gt;
&lt;pre class=&quot;rust&quot;&gt;&lt;code&gt;fn main() {
    println!(&quot;Hello, world!&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hello World! 프로젝트와 거의 동일한 코드가 생성된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;카고로 애플리케이션 실행하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 애플리케이션을 실행해보도록 하겠습니다. 터미널에 cargo run 이란 명령어를 실행해봅시다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# 프로젝트 실행
$ cargo run     
   Compiling hello_cargo v0.1.0 (/home/gurumee/Workspaces/studies/the-rust-programming-language/hello_cargo)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.42s
     Running `target/debug/hello_cargo`
Hello, world!
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 src/main.rs 에서 다음처럼 수정해보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;rust&quot;&gt;&lt;code&gt;fn main() {
    println!(&quot;Hello, Cargo!&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 다시 cargo run 명령어로 애플리케이션을 실행해봅시다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# 프로젝트 실행
$ cargo run
   Compiling hello_cargo v0.1.0 (/home/gurumee/Workspaces/studies/the-rust-programming-language/hello_cargo)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.18s
     Running `target/debug/hello_cargo`
Hello, Cargo!
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;카고로 애플리케이션 빌드하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 마지막으로 애플리케이션을 빌드하고 실행해보겠습니다. 터미널에 cargo build 명령어를 실행해봅시다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ cargo build
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 빌드하면, 개발 환경으로 빌드가 실행됩니다. 빌드 후, target/debug 폴더에 hello_cargo 란 실행 파일이 생성됩니다. 이제 실행 파일을 생성해봅시다.&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;$ ./target/debug/hello_cargo
Hello, Cargo!
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 cargo run 이란 명령어는 빌드 후 실행 파일을 실행하는 것을 축약한 명령어입니다. 실제 프로덕션 환경에 배포할 애플리케이션을 빌드하려면 터미널에 다음과 같이 명령어를 입력하면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ cargo build --release
   Compiling hello_cargo v0.1.0 (/home/gurumee/Workspaces/studies/the-rust-programming-language/hello_cargo)
    Finished `release` profile [optimized] target(s) in 0.15s
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 마찬가지로 target/release 폴더에 실행 파일이 생성됩니다.&lt;/p&gt;</description>
      <category>프로그래밍 언어/rust</category>
      <category>Cargo</category>
      <category>cargo build</category>
      <category>cargo new</category>
      <category>cargo run</category>
      <category>rust baisc</category>
      <category>rust hello world</category>
      <category>rust 설치</category>
      <category>the rust programming language</category>
      <author>Gurumee</author>
      <guid isPermaLink="true">https://gurumee92.tistory.com/328</guid>
      <comments>https://gurumee92.tistory.com/328#entry328comment</comments>
      <pubDate>Sat, 12 Apr 2025 21:23:15 +0900</pubDate>
    </item>
    <item>
      <title>[R] Mac 환경에서 R과 R Studio 설치하기</title>
      <link>https://gurumee92.tistory.com/327</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-15 오후 9.57.41.png&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsjfm3/btsagrIk6nE/Hh9PARlOxZKTGYr2Ysi6K1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsjfm3/btsagrIk6nE/Hh9PARlOxZKTGYr2Ysi6K1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsjfm3/btsagrIk6nE/Hh9PARlOxZKTGYr2Ysi6K1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbsjfm3%2FbtsagrIk6nE%2FHh9PARlOxZKTGYr2Ysi6K1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;506&quot; height=&quot;349&quot; data-filename=&quot;스크린샷 2023-04-15 오후 9.57.41.png&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문서는 Mac 환경에서 R과 R Studio를 설치하는 내용을 정리한 문서입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저의 환경은 아래와 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Mac OS Ventura 13.1 (intel)&lt;/li&gt;
&lt;li&gt;HomeBrew 4.0.13&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문서는 Mac의 패키지 매니저인 &lt;code&gt;HomeBrew&lt;/code&gt;를 통해서 설치를 진행합니다. 만약, &lt;code&gt;HomeBrew&lt;/code&gt;를 설치하지 않았다면 다음 문서를 참고해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1681563266988&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;주니어 엔지니어의 개발 환경 구축하기 (1) 기본 소프트웨어&quot; data-og-description=&quot;개요 이 문서는 필자의 맥북에 개발 환경, 특히 개발 시 필요한 소프트웨어 혹은 기본 소프트웨어를 대체하여 유틸리티를 높이는 소프트웨어들을 설치하는 방법에 대해 다룬다. 이 문서에서 다&quot; data-og-host=&quot;gurumee92.tistory.com&quot; data-og-source-url=&quot;https://gurumee92.tistory.com/298&quot; data-og-url=&quot;https://gurumee92.tistory.com/298&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/csBgu0/hyShMu3fYT/vPc2xiExThntM5iaRFTTdk/img.png?width=800&amp;amp;height=290&amp;amp;face=0_0_800_290,https://scrap.kakaocdn.net/dn/ds9nKs/hyShJd2P6R/ppEuB2HXONbb0mxaOYwHN1/img.png?width=800&amp;amp;height=290&amp;amp;face=0_0_800_290,https://scrap.kakaocdn.net/dn/bdmTM0/hySi48HRYq/Xn3lD6ileMVy73D7ksLJc0/img.png?width=2062&amp;amp;height=748&amp;amp;face=0_0_2062_748&quot;&gt;&lt;a href=&quot;https://gurumee92.tistory.com/298&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://gurumee92.tistory.com/298&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/csBgu0/hyShMu3fYT/vPc2xiExThntM5iaRFTTdk/img.png?width=800&amp;amp;height=290&amp;amp;face=0_0_800_290,https://scrap.kakaocdn.net/dn/ds9nKs/hyShJd2P6R/ppEuB2HXONbb0mxaOYwHN1/img.png?width=800&amp;amp;height=290&amp;amp;face=0_0_800_290,https://scrap.kakaocdn.net/dn/bdmTM0/hySi48HRYq/Xn3lD6ileMVy73D7ksLJc0/img.png?width=2062&amp;amp;height=748&amp;amp;face=0_0_2062_748');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;주니어 엔지니어의 개발 환경 구축하기 (1) 기본 소프트웨어&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요 이 문서는 필자의 맥북에 개발 환경, 특히 개발 시 필요한 소프트웨어 혹은 기본 소프트웨어를 대체하여 유틸리티를 높이는 소프트웨어들을 설치하는 방법에 대해 다룬다. 이 문서에서 다&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;gurumee92.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설치 R&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;R&lt;/code&gt;프로그래밍 언어를 설치합니다. 터미널에 다음 명령어를 입력해주세요.&lt;/p&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;$ brew install --cask r
==&amp;gt; Downloading https://cloud.r-project.org/bin/macosx/base/R-4.2.3.pkg
######################################################################## 100.0%
==&amp;gt; Installing Cask r
==&amp;gt; Running installer for r; your password may be necessary.
Package installers may write to any location; options such as `--appdir` are ignored.
Password:
installer: Package name is R 4.2.3 for macOS
installer: Installing at base path /
installer: The install was successful.
   r was successfully installed!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치가 정상적으로 완료되었다면, 터미널에 다음을 입력해봅니다.&lt;/p&gt;
&lt;pre class=&quot;prolog&quot;&gt;&lt;code&gt;$ R  # R 입력 후 엔터를 입력합니다. 아래부터는 입력 후 출력되는 문구입니다.

R version 4.2.3 (2023-03-15) -- &quot;Shortstop Beagle&quot;
Copyright (C) 2023 The R Foundation for Statistical Computing
Platform: x86_64-apple-darwin17.0 (64-bit)

R은 자유 소프트웨어이며, 어떠한 형태의 보증없이 배포됩니다.
또한, 일정한 조건하에서 이것을 재배포 할 수 있습니다.
배포와 관련된 상세한 내용은 'license()' 또는 'licence()'을 통하여 확인할 수 있습니다.

R은 많은 기여자들이 참여하는 공동프로젝트입니다.
'contributors()'라고 입력하시면 이에 대한 더 많은 정보를 확인하실 수 있습니다.
그리고, R 또는 R 패키지들을 출판물에 인용하는 방법에 대해서는 'citation()'을 통해 확인하시길 부탁드립니다.

'demo()'를 입력하신다면 몇가지 데모를 보실 수 있으며, 'help()'를 입력하시면 온라인 도움말을 이용하실 수 있습니다.
또한, 'help.start()'의 입력을 통하여 HTML 브라우저에 의한 도움말을 사용하실수 있습니다
R의 종료를 원하시면 'q()'을 입력해주세요.

[이전에 저장한 작업공간을 복구하였습니다]

&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 1 + 1 을 입력해봅시다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;&amp;gt; 1 + 1   # 1 + 1 입력 후 엔터를 입력합니다.
[1] 2     # 결과가 나옵니다. 2
&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;R&lt;/code&gt;을 종료합니다. &quot;q()&quot;를 입력합니다.&lt;/p&gt;
&lt;pre class=&quot;perl&quot;&gt;&lt;code&gt;&amp;gt; q()                             # q() 입력 후 엔터를 칩니다.
Save workspace image? [y/n/c]: y  # y를 입력합니다.
$&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설치 R Studio&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;R&lt;/code&gt; 프로그래밍 언어의 전용 IDE인 &lt;code&gt;R Studio&lt;/code&gt;를 설치합니다. 터미널에 다음을 입력합니다.&lt;/p&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;$ brew install --cask rstudio 
==&amp;gt; Caveats
rstudio depends on R. The R Project provides official binaries:

  brew install --cask r

Alternatively, the Homebrew-compiled version of R omits the GUI app:

  brew install r

==&amp;gt; Downloading https://download1.rstudio.org/electron/macos/RStudio-2023.03.0-386.dmg
######################################################################## 100.0%
==&amp;gt; Installing Cask rstudio
==&amp;gt; Moving App 'RStudio.app' to '/Applications/RStudio.app'
   rstudio was successfully installed!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치가 완료되었다면, &lt;code&gt;R Studio&lt;/code&gt;를 실행시켜봅시다. (Finder로 R Studio를 검색하면 됩니다.) 프로그램이 실행되고 다음 화면이 보인다면 성공입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-15 오후 9.50.11.png&quot; data-origin-width=&quot;1720&quot; data-origin-height=&quot;1436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/elPlbY/btsaje2JdFU/ZMWrhIsNmatncK9i7xXkL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/elPlbY/btsaje2JdFU/ZMWrhIsNmatncK9i7xXkL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/elPlbY/btsaje2JdFU/ZMWrhIsNmatncK9i7xXkL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FelPlbY%2Fbtsaje2JdFU%2FZMWrhIsNmatncK9i7xXkL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1720&quot; height=&quot;1436&quot; data-filename=&quot;스크린샷 2023-04-15 오후 9.50.11.png&quot; data-origin-width=&quot;1720&quot; data-origin-height=&quot;1436&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>레거시/AI</category>
      <category>data analysis</category>
      <category>Data Engineer</category>
      <category>Data Engineering</category>
      <category>Install R for mac</category>
      <category>Install R Studio for mac</category>
      <category>r</category>
      <category>r studio</category>
      <category>데이터 분석</category>
      <author>Gurumee</author>
      <guid isPermaLink="true">https://gurumee92.tistory.com/327</guid>
      <comments>https://gurumee92.tistory.com/327#entry327comment</comments>
      <pubDate>Sat, 15 Apr 2023 21:41:54 +0900</pubDate>
    </item>
    <item>
      <title>Jaeger 설치하기</title>
      <link>https://gurumee92.tistory.com/326</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;분산추적.png&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;872&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmZVDU/btrZV8cMrfa/PpKkrV2yPDBFytLV70KXWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmZVDU/btrZV8cMrfa/PpKkrV2yPDBFytLV70KXWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmZVDU/btrZV8cMrfa/PpKkrV2yPDBFytLV70KXWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmZVDU%2FbtrZV8cMrfa%2FPpKkrV2yPDBFytLV70KXWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1222&quot; height=&quot;872&quot; data-filename=&quot;분산추적.png&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;872&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문서는 분산 추적 시스템 중 하나인 &lt;code&gt;jaeger&lt;/code&gt;를 설치하는 것을 다루고 있습니다. 특히, 하나의 바이너리 파일의 실행으로 간단하게 분산 추적 시스템을 구축할 수 있는 &lt;code&gt;all-in-one&lt;/code&gt; 모드로 실행하는 것을 목표로 합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;준비 사항&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문서는 &lt;code&gt;Docker&lt;/code&gt; 환경에서 &lt;code&gt;Jaeger&lt;/code&gt;를 설치합니다. 따라서, &lt;code&gt;Docker&lt;/code&gt;가 필요합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker v20.10.12 이상&lt;/li&gt;
&lt;li&gt;docker-compose v1.29.2 이상&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Jaeger 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 명령어로, &lt;code&gt;Jaeger&lt;/code&gt;를 설치할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ docker run -d --name jaeger \
  -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
  -e COLLECTOR_OTLP_ENABLED=true \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 4317:4317 \
  -p 4318:4318 \
  -p 14250:14250 \
  -p 14268:14268 \
  -p 14269:14269 \
  -p 9411:9411 \
  jaegertracing/all-in-one:1.42&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 &lt;code&gt;docker-compose&lt;/code&gt;를 이용하여 구성한다면, 다음과 같이 구성할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a&gt;src/ch02/docker-compose.yml&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;haml&quot;&gt;&lt;code&gt;version: &quot;3.9&quot;
services:
  jaeger: 
    image: &quot;jaegertracing/all-in-one:1.42&quot;
    environment:
      - COLLECTOR_ZIPKIN_HOST_PORT=:9411
      - COLLECTOR_OTLP_ENABLED=true
    ports:
      - &quot;6831:6831/udp&quot;
      - &quot;6832:6832/udp&quot;
      - &quot;5778:5778&quot;
      - &quot;16686:16686&quot;
      - &quot;4317:4317&quot;
      - &quot;4318:4318&quot;
      - &quot;14250:14250&quot;
      - &quot;14268:14268&quot;
      - &quot;14269:14269&quot;
      - &quot;9411:9411&quot;
    networks:
      - getting-started-distributed-tracing

networks:
  getting-started-distributed-tracing:
    driver: bridge&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;docker-compose&lt;/code&gt;를 이용한다면 다음 명령어로 실행이 가능합니다.&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;$ docker compose up
[+] Running 1/1
 ⠿ Container ch02-jaeger-1  Recreated                                                                                              0.1s
Attaching to ch02-jaeger-1
ch02-jaeger-1  | 2023/02/19 12:11:01 maxprocs: Leaving GOMAXPROCS=6: CPU quota undefined
ch02-jaeger-1  | {&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:1676808661.6135793,&quot;caller&quot;:&quot;flags/service.go:119&quot;,&quot;msg&quot;:&quot;Mounting metrics handler on admin server&quot;,&quot;route&quot;:&quot;/metrics&quot;}
# ...
ch02-jaeger-1  | {&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:1676808662.6579118,&quot;caller&quot;:&quot;channelz/funcs.go:340&quot;,&quot;msg&quot;:&quot;[core][Channel #10] Channel Connectivity change to IDLE&quot;,&quot;system&quot;:&quot;grpc&quot;,&quot;grpc_log&quot;:true}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정상적으로 실행이 되면, 브라우저에서 다음 URL을 접속해봅니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://localhost:16686&quot;&gt;http://localhost:16686&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 화면이 보이면 성공입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3580&quot; data-origin-height=&quot;1994&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bivuYU/btrZR1LUNM5/cbkowTdXyukv4BfFzDTgbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bivuYU/btrZR1LUNM5/cbkowTdXyukv4BfFzDTgbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bivuYU/btrZR1LUNM5/cbkowTdXyukv4BfFzDTgbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbivuYU%2FbtrZR1LUNM5%2FcbkowTdXyukv4BfFzDTgbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3580&quot; height=&quot;1994&quot; data-origin-width=&quot;3580&quot; data-origin-height=&quot;1994&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;각 포트의 의미&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 포트의 의미는 다음과 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 170px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;port&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;protocol&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;component&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;function&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;6831&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;UDP&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;agent&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;대부분의 SDK에서 Jaeger로 트레이싱 정보를 전달하는 포트입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;6832&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;UDP&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;agent&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;Node.js SDK에서 Jaeger로 트레이싱 정보를 전달하는 포트입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;5778&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;HTTP&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;agent&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;샘플링 등의 설정을 확인할 수 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;16686&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;HTTP&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;query&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;프론트엔드 서비스를 확인할 수 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;4317&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;HTTP&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;collector&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;COLLECTOR_OTLB_ENABLED가 활성화되어 있다면, gRPC 기반의 OTLP(오픈 텔레메트리 프로토콜)을 수신합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;4318&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;HTTP&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;collector&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;COLLECTOR_OTLB_ENABLED가 활성화되어 있다면, http 기반의 OTLP(오픈 텔레메트리 프로토콜)을 수신합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;14268&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;HTTP&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;collector&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;클라이언트로부터 직접 트레이스 정보를 수신합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;14250&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;HTTP&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;collector&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;model.proto 를 수신합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;9411&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;HTTP&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;collector&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;Zipkin호환 엔드포인트입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 컴포넌트가 있지만, 이 문서에서는 따로 설명하지 않습니다. (기회가 있다면, 추후 이어지는 장에서 설명하도록 하겠습니다.)&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참고&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jaegertracing.io/docs/1.42/getting-started/&quot;&gt;Jaeger 공식 문서 - Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>24년 11월 이전/Distributed Tracing</category>
      <category>distributed tracing</category>
      <category>install jaeger</category>
      <category>jaeger</category>
      <category>jaeger 설치하기</category>
      <category>Observability</category>
      <category>관찰 가능성</category>
      <category>분산 추적</category>
      <author>Gurumee</author>
      <guid isPermaLink="true">https://gurumee92.tistory.com/326</guid>
      <comments>https://gurumee92.tistory.com/326#entry326comment</comments>
      <pubDate>Sun, 19 Feb 2023 20:49:36 +0900</pubDate>
    </item>
    <item>
      <title>ArgoCD 맛보기</title>
      <link>https://gurumee92.tistory.com/325</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;302&quot; data-origin-height=&quot;167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EgHFx/btrLwJyIubN/2aTXuF1PQsykdBmj15oH0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EgHFx/btrLwJyIubN/2aTXuF1PQsykdBmj15oH0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EgHFx/btrLwJyIubN/2aTXuF1PQsykdBmj15oH0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEgHFx%2FbtrLwJyIubN%2F2aTXuF1PQsykdBmj15oH0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;302&quot; height=&quot;167&quot; data-origin-width=&quot;302&quot; data-origin-height=&quot;167&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문서에서는 &lt;code&gt;Gitops&lt;/code&gt; 구현체 중 하나인 &lt;code&gt;ArgoCD&lt;/code&gt;에 대해서 간단히 알아보도록 하곘습니다. 또한 &lt;code&gt;minikube&lt;/code&gt; 쿠버네티스 클러스터 환경에서 &lt;code&gt;ArgoCD&lt;/code&gt; 배포 후, &lt;code&gt;argocd&lt;/code&gt; CLI를 통해 간단히 애플리케이션을 배포하는 내용을 실습해보도록 하겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Gitops와 ArgoCD&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Gitops&lt;/code&gt;란 애플리케이션의 배포와 운영에 관련된 모든 요소를 코드화하여 깃(Git)에서 관리(Ops)하는 방법론 중 하나입니다. CI/CD 중 지속적인 배포(Continuous Deployment)에 초첨을 두고 있으며, 기본 개념은 코드를 이용하여 인프라를 프로비저닝 하고 관리하는 IaC(Infrastructure as Code)에서 나온 것으로 깃옵스는 이를 인프라에서 전체 애플리케이션 범위로 확장하였다고 보시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Gitops&lt;/code&gt;의 장점은 다음과 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인프라를 포함한 애플리케이션 배포와 운영에 관련된 모든 것을 코드로 관리할 수 있습니다.&lt;/li&gt;
&lt;li&gt;Git을 단일 진실 공급원으로 지정하고 오직 이 곳에서만 관리하도록 합니다. 모든 운영 활동의 시작은 깃이므로 사람 혹은 시스템 간의 혼선을 최소화 할 수 있습니다.&lt;/li&gt;
&lt;li&gt;Git 에서 누릴 수 있었던 깃의 기능을 운영 단계에서도 활용할 수 있습니다.(History, Commit, Merge Request/ Review, Revert 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;ArgoCD&lt;/code&gt;는 &lt;code&gt;Gitops&lt;/code&gt;의 대표적인 구현체이며, &lt;code&gt;Jenkins&lt;/code&gt; 같은 push 방식이 아닌 pull 방식을 채택한 &lt;code&gt;Gitops&lt;/code&gt; 도구입니다. 다음은 &lt;code&gt;ArgoCD&lt;/code&gt;의 아키텍처를 나타낸 그림입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;779&quot; data-origin-height=&quot;743&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzuWDn/btrLzkdRN2P/9cu85AZ7jj0u69v9bkntKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzuWDn/btrLzkdRN2P/9cu85AZ7jj0u69v9bkntKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzuWDn/btrLzkdRN2P/9cu85AZ7jj0u69v9bkntKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzuWDn%2FbtrLzkdRN2P%2F9cu85AZ7jj0u69v9bkntKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;779&quot; height=&quot;743&quot; data-origin-width=&quot;779&quot; data-origin-height=&quot;743&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 쿠버네티스 클러스터 내 리소스들로 구성되며, 코드에 반영되면 설치된 &lt;code&gt;ArgoCD&lt;/code&gt;가 쿠버네티스 클러스터에 설치된 리소스와 형상을 비교한 뒤, 차이가 있으면 이를 최신 코드 기준으로 동일하게 맞춰줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 이제 간단하게 알아보았으니 &lt;code&gt;ArgoCD&lt;/code&gt;를 통해서 애플리케이션을 배포해보는 간단한 실습을 진행해보겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;요구사항&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실습을 진행하기 위해서는 아래 소프트웨어들이 구성되어 있어야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;docker v20.10.17&lt;/li&gt;
&lt;li&gt;minikube v1.24.0&lt;/li&gt;
&lt;li&gt;kubectl v1.24.2&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;쿠버네티스 클러스터에 ArgoCD 배포하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 절에서 언급했듯이 &lt;code&gt;ArgoCD&lt;/code&gt;는 쿠버네티스 리소스로 구성되어 있습니다. 따라서 메니페스트를 구성해야 하는데, 여기서는 간단하게 CLI 명령어로 구성해보도록 하곘습니다. 아래 명령어들을 입력합니다.&lt;/p&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;# argocd 네임스페이스 생성
$ kubectl create namespace argocd

# 쿠버네티스 클러스터에 argocd 설치
$ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 명령어를 실행하면 &quot;argocd&quot; 네임스페이스 아래 다음 리소스들이 구성됩니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ kubectl get all -n argocd
NAME                                                    READY   STATUS    RESTARTS   AGE
pod/argocd-application-controller-0                     1/1     Running   0          115m
pod/argocd-applicationset-controller-78b8b554f9-pg6tv   1/1     Running   0          115m
pod/argocd-dex-server-6bbc85c688-fxqwf                  1/1     Running   0          115m
pod/argocd-notifications-controller-75847756c5-v9qc7    1/1     Running   0          115m
pod/argocd-redis-f4cdbff57-879q5                        1/1     Running   0          115m
pod/argocd-repo-server-d5c7f7ffb-fddm7                  1/1     Running   0          115m
pod/argocd-server-76497676b-m9gq4                       1/1     Running   0          115m

NAME                                              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
service/argocd-applicationset-controller          ClusterIP   10.111.172.181   &amp;lt;none&amp;gt;        7000/TCP,8080/TCP            115m
service/argocd-dex-server                         ClusterIP   10.100.226.17    &amp;lt;none&amp;gt;        5556/TCP,5557/TCP,5558/TCP   115m
service/argocd-metrics                            ClusterIP   10.109.114.206   &amp;lt;none&amp;gt;        8082/TCP                     115m
service/argocd-notifications-controller-metrics   ClusterIP   10.104.167.93    &amp;lt;none&amp;gt;        9001/TCP                     115m
service/argocd-redis                              ClusterIP   10.102.69.51     &amp;lt;none&amp;gt;        6379/TCP                     115m
service/argocd-repo-server                        ClusterIP   10.104.11.4      &amp;lt;none&amp;gt;        8081/TCP,8084/TCP            115m
service/argocd-server                             ClusterIP   10.109.178.58    &amp;lt;none&amp;gt;        80/TCP,443/TCP               115m
service/argocd-server-metrics                     ClusterIP   10.110.59.129    &amp;lt;none&amp;gt;        8083/TCP                     115m

NAME                                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/argocd-applicationset-controller   1/1     1            1           115m
deployment.apps/argocd-dex-server                  1/1     1            1           115m
deployment.apps/argocd-notifications-controller    1/1     1            1           115m
deployment.apps/argocd-redis                       1/1     1            1           115m
deployment.apps/argocd-repo-server                 1/1     1            1           115m
deployment.apps/argocd-server                      1/1     1            1           115m

NAME                                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/argocd-applicationset-controller-78b8b554f9   1         1         1       115m
replicaset.apps/argocd-dex-server-6bbc85c688                  1         1         1       115m
replicaset.apps/argocd-notifications-controller-75847756c5    1         1         1       115m
replicaset.apps/argocd-redis-f4cdbff57                        1         1         1       115m
replicaset.apps/argocd-repo-server-d5c7f7ffb                  1         1         1       115m
replicaset.apps/argocd-server-76497676b                       1         1         1       115m

NAME                                             READY   AGE
statefulset.apps/argocd-application-controller   1/1     115m&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구성된 &lt;code&gt;ArgoCD&lt;/code&gt;는 웹 UI(이하 &quot;ArgoCD UI&quot;)를 제공합니다. 이를 브라우저로 접근하기 위해서는 다음의 4가지 방식이 있습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서비스 타입을 LoadBalancer로 변경&lt;/li&gt;
&lt;li&gt;서비스 타입을 NodePort로 변경&lt;/li&gt;
&lt;li&gt;Ingress 생성 및 서비스 연결&lt;/li&gt;
&lt;li&gt;Port Forward로 서비스 연결&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 가장 간단한 &lt;code&gt;Port Forward&lt;/code&gt; 방식을 이용해보도록 하곘습니다. 터미널에 다음을 입력하세요.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ kubectl port-forward svc/argocd-server -n argocd 8080:443&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;a href=&quot;http://localhost:8080&quot;&gt;http://localhost:8080&lt;/a&gt;으로 접속하면 &lt;code&gt;ArgoCD UI&lt;/code&gt;를 접속할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1913&quot; data-origin-height=&quot;931&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clJ4eB/btrLxYI7d14/eRkmwG3pscKIuM44NkQWh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clJ4eB/btrLxYI7d14/eRkmwG3pscKIuM44NkQWh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clJ4eB/btrLxYI7d14/eRkmwG3pscKIuM44NkQWh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclJ4eB%2FbtrLxYI7d14%2FeRkmwG3pscKIuM44NkQWh0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1913&quot; height=&quot;931&quot; data-origin-width=&quot;1913&quot; data-origin-height=&quot;931&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 로그인을 해야 하는데, 이 방식으로 설치하게 되면 기본적으로 &quot;admin&quot; 계정과 함께 임의의 비밀번호가 생성됩니다. 비밀번호는 다음 명령어로 확인할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# 비밀번호를 확인화기 위한 명령어
$ kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath=&quot;{.data.password}&quot; | base64 -d; echo
# 생성된 비밀번호
7FHwxAybf9aXICII&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 생성된 비밀번호와 함께 &quot;admin&quot; 계정으로 로그인하면 다음 화면을 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1917&quot; data-origin-height=&quot;936&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dGkdWq/btrLvKEBXnc/1TTRYcPk48uRjzBzFKACk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dGkdWq/btrLvKEBXnc/1TTRYcPk48uRjzBzFKACk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dGkdWq/btrLvKEBXnc/1TTRYcPk48uRjzBzFKACk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdGkdWq%2FbtrLvKEBXnc%2F1TTRYcPk48uRjzBzFKACk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1917&quot; height=&quot;936&quot; data-origin-width=&quot;1917&quot; data-origin-height=&quot;936&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;애플리케이션 배포하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;ArgoCD&lt;/code&gt;에 애플리케이션을 배포하기 위해서는 몇 가지 설정이 추가적으로 더 필요합니다. 손 쉽게 구성하기 위해서 &lt;code&gt;argocd CLI&lt;/code&gt;를 설치한다. mac 환경이라면, 다음 명령어로 손귑게 설치할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;$ brew install argocd&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;code&gt;argocd CLI&lt;/code&gt;로 배포한 &lt;code&gt;ArgoCD&lt;/code&gt;에 로그인을 진행해야 합니다. 터미널에 다음을 입력합니다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;# argocd login &amp;lt;ArgoCD URL&amp;gt;
$ argocd login localhost:8080
WARNING: server certificate had error: x509: &amp;ldquo;Argo CD&amp;rdquo; certificate is not trusted. Proceed insecurely (y/n)? y  # &amp;lt;- y 입력
Username: admin # &amp;lt;- admin 입력
Password:       # &amp;lt;- 위에서 확인한 비밀번호 입력
'admin:login' logged in successfully
Context 'localhost:8080' updated&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인이 다 되었으면 &lt;code&gt;application&lt;/code&gt;을 배포해도록 하겠습니다. 터미널에 다음 명령어를 입력합니다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;$ argocd app create guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --dest-server https://kubernetes.default.svc --dest-namespace default&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 명령어는 &lt;code&gt;argocd(여기서는 argocd를 만들고 관리하는 단체를 의미한다.)&lt;/code&gt;에서 제공하는 예제 샘플을 우리가 구성한 &lt;code&gt;ArgoCD&lt;/code&gt;로 배포하고 관리할 수 있는 객체를 생성합니다. 이 객체, 혹은 배포 단위를 &lt;code&gt;argocd&lt;/code&gt;에서는 &quot;application&quot;이라고 합니다. &lt;code&gt;ArgoCD UI&lt;/code&gt;로 돌아가보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 그림과 같이 애플리케이션이 구성되었음을 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1925&quot; data-origin-height=&quot;957&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBffiW/btrLx0z9blY/KqPlqbr24A3buCykRb0pY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBffiW/btrLx0z9blY/KqPlqbr24A3buCykRb0pY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBffiW/btrLx0z9blY/KqPlqbr24A3buCykRb0pY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBffiW%2FbtrLx0z9blY%2FKqPlqbr24A3buCykRb0pY0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1925&quot; height=&quot;957&quot; data-origin-width=&quot;1925&quot; data-origin-height=&quot;957&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 노란 색깔이 보이는데, 아직 쿠버네티스 클러스터에 배포되지 않았음을 의미합니다. 여기서 &quot;Sync&quot;를 누르면 배포를 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1912&quot; data-origin-height=&quot;964&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqzxTs/btrLwAIwhQd/MOt5Fp6yUT2PjcOUum1bw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqzxTs/btrLwAIwhQd/MOt5Fp6yUT2PjcOUum1bw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqzxTs/btrLwAIwhQd/MOt5Fp6yUT2PjcOUum1bw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqzxTs%2FbtrLwAIwhQd%2FMOt5Fp6yUT2PjcOUum1bw1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1912&quot; height=&quot;964&quot; data-origin-width=&quot;1912&quot; data-origin-height=&quot;964&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 오른쪽에서 다음 UI가 발생하는데 &quot;Synchronize&quot;를 누릅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1917&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjvgDV/btrLu8Z2BZO/9zL5u7GSM2G1ii3qqWDSQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjvgDV/btrLu8Z2BZO/9zL5u7GSM2G1ii3qqWDSQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjvgDV/btrLu8Z2BZO/9zL5u7GSM2G1ii3qqWDSQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjvgDV%2FbtrLu8Z2BZO%2F9zL5u7GSM2G1ii3qqWDSQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1917&quot; height=&quot;960&quot; data-origin-width=&quot;1917&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 얼마 있다가 색깔이 노란색에서 초록색으로 바뀌게 됩니다. 예제 샘플이 배포가 되었음을 의미합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1915&quot; data-origin-height=&quot;958&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k2kNK/btrLyZHPr5Y/Ot4pCJKDnPsyhzxkUHFct0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k2kNK/btrLyZHPr5Y/Ot4pCJKDnPsyhzxkUHFct0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k2kNK/btrLyZHPr5Y/Ot4pCJKDnPsyhzxkUHFct0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk2kNK%2FbtrLyZHPr5Y%2FOt4pCJKDnPsyhzxkUHFct0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1915&quot; height=&quot;958&quot; data-origin-width=&quot;1915&quot; data-origin-height=&quot;958&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션을 UI를 클릭해보면 어떤 리소스들이 구성되는지 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1917&quot; data-origin-height=&quot;963&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6UDFb/btrLzDjXtdL/XVksAMO5PAKL14YHUfphmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6UDFb/btrLzDjXtdL/XVksAMO5PAKL14YHUfphmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6UDFb/btrLzDjXtdL/XVksAMO5PAKL14YHUfphmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6UDFb%2FbtrLzDjXtdL%2FXVksAMO5PAKL14YHUfphmk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1917&quot; height=&quot;963&quot; data-origin-width=&quot;1917&quot; data-origin-height=&quot;963&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 UI에서 다음 리소스들이 생성되었음을 확인할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;service x1 (endpoint, endpointslice는 서비스 생성 시 자동 구성됨)&lt;/li&gt;
&lt;li&gt;deployment x1&lt;/li&gt;
&lt;li&gt;replicaset x1&lt;/li&gt;
&lt;li&gt;pod x1&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 쿠버네티스에서 구성된 리소스들과 비교해보죠. 다음 명령어를 입력합니다.&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;$ kubectl get all | grep &quot;guestbook&quot;
pod/guestbook-ui-85985d774c-dk6gz   1/1     Running   0          7m16s
service/guestbook-ui   ClusterIP   10.104.51.32   &amp;lt;none&amp;gt;        80/TCP    7m16s
deployment.apps/guestbook-ui   1/1     1            1           7m16s
replicaset.apps/guestbook-ui-85985d774c   1         1         1       7m16s&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정확하게 일치됨을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문서에서는 예제 샘플, 즉 저희가 코드 관리를 할 수 없기 때문에 코드 내용이 변경될 때 싱크를 맞춰서 배포됨을 확인할 수 없습니다. 하지만, 만약 자신의 레포를 설정했다면, 레포에 코드 변경이 발생할 시 최대 3분을 기다렸다가 &lt;code&gt;ArgoCD&lt;/code&gt;가 쿠버네티스 클러스터에 싱크를 맞춰서 애플리케이션을 배포하는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://argo-cd.readthedocs.io/en/stable/getting_started/&quot;&gt;ArgoCD 공식 문서 - &quot;Getting Started&quot;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>24년 11월 이전/ArgoCD</category>
      <category>argocd</category>
      <category>CICD</category>
      <category>DevOps</category>
      <category>Getting Started</category>
      <category>GitOps</category>
      <category>SRE</category>
      <category>tutorial</category>
      <category>깃옵스</category>
      <category>데브옵스</category>
      <category>운영</category>
      <author>Gurumee</author>
      <guid isPermaLink="true">https://gurumee92.tistory.com/325</guid>
      <comments>https://gurumee92.tistory.com/325#entry325comment</comments>
      <pubDate>Wed, 7 Sep 2022 19:30:57 +0900</pubDate>
    </item>
    <item>
      <title>그라파나 9 새로운 기능 (1) Query Builder</title>
      <link>https://gurumee92.tistory.com/324</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;logo.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XUwO2/btrLgZ9ASnO/bKEJLZoNu8SQTxsNouwiAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XUwO2/btrLgZ9ASnO/bKEJLZoNu8SQTxsNouwiAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XUwO2/btrLgZ9ASnO/bKEJLZoNu8SQTxsNouwiAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXUwO2%2FbtrLgZ9ASnO%2FbKEJLZoNu8SQTxsNouwiAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;600&quot; data-filename=&quot;logo.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 &lt;code&gt;Grafana 9&lt;/code&gt; 버전이 출시되었습니다. 사용자들의 편의성을 위한 많은 기능들이 업데이트 및 생성되었습니다. 이 문서에서는 새로운 기능 중 하나인 &lt;b&gt;Query Builder&lt;/b&gt;에 대해서 간단하게 알아보겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그라파나 9 이전에 쿼리하는 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어서 다음 쿼리를 &lt;code&gt;Grafana&lt;/code&gt;를 통해서 조회한다고 해봅시다.&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;sum(rate(go_gc_duration_seconds{job=&quot;node-exporter&quot;}[$__rate_interval]))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Grafana 9&lt;/code&gt; 이전 버전에서는 &quot;Explore&quot;를 탭에서 쿼리를 하는 UI는 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2860&quot; data-origin-height=&quot;1388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1yUKA/btrLe1nfbiR/VHcS8bW0Ch2EnNPJGIkwx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1yUKA/btrLe1nfbiR/VHcS8bW0Ch2EnNPJGIkwx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1yUKA/btrLe1nfbiR/VHcS8bW0Ch2EnNPJGIkwx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1yUKA%2FbtrLe1nfbiR%2FVHcS8bW0Ch2EnNPJGIkwx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2860&quot; height=&quot;1388&quot; data-origin-width=&quot;2860&quot; data-origin-height=&quot;1388&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 &lt;code&gt;Grafana 8&lt;/code&gt;에서는 사용자가 하나 하나 쿼리를 모두 입력해야하는 불편함이 있었습니다.(물론 자동 완성 기능으로 어느 정도 커버가 가능합니다.)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그라파나 9 에서 쿼리하는 방법 (1) Query Builder&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Grafana 9&lt;/code&gt; 버전부터는 &lt;code&gt;Query Builder&lt;/code&gt;를 통해서 보다 쉽고 정확하게 그라파나를 통해서 데이터를 쿼리할 수 있습니다. (아직 &quot;베타&quot; 기능인게 함정.) 지금부터 &lt;code&gt;Grafana 9&lt;/code&gt;에서 제공하는 &lt;code&gt;Query Builder&lt;/code&gt;를 통해서 데이터를 조회하는 방법에 대해서 차근 차근 살펴보도록 하죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &quot;Explore&quot; 탭으로 이동합니다. 그 후 아래 그림처럼 &quot;Metric&quot; 아래 드랍다운 UI에서 원하는 메트릭을 지정합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2868&quot; data-origin-height=&quot;1400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzZuOU/btrLhQc1QuO/3oZXp5cyaxEy71yDrgu88k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzZuOU/btrLhQc1QuO/3oZXp5cyaxEy71yDrgu88k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzZuOU/btrLhQc1QuO/3oZXp5cyaxEy71yDrgu88k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzZuOU%2FbtrLhQc1QuO%2F3oZXp5cyaxEy71yDrgu88k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2868&quot; height=&quot;1400&quot; data-origin-width=&quot;2868&quot; data-origin-height=&quot;1400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 필터링이 필요하다면 &quot;Labels&quot;에서 원하는 레이블과 값을 지정하면 됩니다. 이 문서에서는 1개만 지정하지만, 여러 개를 지정해줄 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2856&quot; data-origin-height=&quot;1392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pP174/btrLgbwoDDK/lkGbG52bUaK3Jx2kcPjP3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pP174/btrLgbwoDDK/lkGbG52bUaK3Jx2kcPjP3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pP174/btrLgbwoDDK/lkGbG52bUaK3Jx2kcPjP3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpP174%2FbtrLgbwoDDK%2FlkGbG52bUaK3Jx2kcPjP3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2856&quot; height=&quot;1392&quot; data-origin-width=&quot;2856&quot; data-origin-height=&quot;1392&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 집계 및 연산을 원한다면 &quot;+ Operations&quot;를 클릭합니다. 첫 연산 식으로는 &quot;Range functions&quot;의 &quot;Rate&quot;를 선택했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2864&quot; data-origin-height=&quot;1396&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GEXWe/btrLgTuPTzg/Sq2BA85kwgeZV7vl155NfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GEXWe/btrLgTuPTzg/Sq2BA85kwgeZV7vl155NfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GEXWe/btrLgTuPTzg/Sq2BA85kwgeZV7vl155NfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGEXWe%2FbtrLgTuPTzg%2FSq2BA85kwgeZV7vl155NfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2864&quot; height=&quot;1396&quot; data-origin-width=&quot;2864&quot; data-origin-height=&quot;1396&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 여러 연산 식을 조합할 수 있습니다. 두번째 연산 식으로는 &quot;Aggregate&quot;의 &quot;Sum&quot;을 선택해보도록 하죠.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2856&quot; data-origin-height=&quot;1392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpu727/btrLgaK2FB9/VO8H7uzB0WPKM8GjGCqmw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpu727/btrLgaK2FB9/VO8H7uzB0WPKM8GjGCqmw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpu727/btrLgaK2FB9/VO8H7uzB0WPKM8GjGCqmw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbpu727%2FbtrLgaK2FB9%2FVO8H7uzB0WPKM8GjGCqmw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2856&quot; height=&quot;1392&quot; data-origin-width=&quot;2856&quot; data-origin-height=&quot;1392&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;짜잔! 놀라운 점은 조합 방법을 순서대로 하지 않더라도 동일하게 동작하는 쿼리를 구성할 수 있다는 것입니다. 이렇게 조회하고 싶은 쿼리를 손쉽고 정확하게 만들어낼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2866&quot; data-origin-height=&quot;1386&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXUs4C/btrLggdhEzZ/A2IJBWfgILf13rExMXiXKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXUs4C/btrLggdhEzZ/A2IJBWfgILf13rExMXiXKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXUs4C/btrLggdhEzZ/A2IJBWfgILf13rExMXiXKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXUs4C%2FbtrLggdhEzZ%2FA2IJBWfgILf13rExMXiXKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2866&quot; height=&quot;1386&quot; data-origin-width=&quot;2866&quot; data-origin-height=&quot;1386&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리의 결과는 이전 UI와 마찬가지로 아래 그림처럼 나타납니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2858&quot; data-origin-height=&quot;1390&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lgKYq/btrLguoEgzs/NVuo5W7iGfs3UiKuws17Xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lgKYq/btrLguoEgzs/NVuo5W7iGfs3UiKuws17Xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lgKYq/btrLguoEgzs/NVuo5W7iGfs3UiKuws17Xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlgKYq%2FbtrLguoEgzs%2FNVuo5W7iGfs3UiKuws17Xk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2858&quot; height=&quot;1390&quot; data-origin-width=&quot;2858&quot; data-origin-height=&quot;1390&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그라파나 9 에서 쿼리하는 방법 (2) 기존 방식 그대로&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 직접 쿼리를 작성하는게 편하시다면 왼쪽 상단에 &quot;Code&quot;를 클릭하여 기존 방식처럼 쿼리할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2862&quot; data-origin-height=&quot;1402&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wIkf4/btrLgO8gDT0/D4HErtiQPRyGtvkv1uPrQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wIkf4/btrLgO8gDT0/D4HErtiQPRyGtvkv1uPrQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wIkf4/btrLgO8gDT0/D4HErtiQPRyGtvkv1uPrQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwIkf4%2FbtrLgO8gDT0%2FD4HErtiQPRyGtvkv1uPrQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2862&quot; height=&quot;1402&quot; data-origin-width=&quot;2862&quot; data-origin-height=&quot;1402&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 &lt;code&gt;Grafana 9&lt;/code&gt; 이전 방식에서 쿼리를 작성했던 것처럼 직접 작성할 수 있는 UI를 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2842&quot; data-origin-height=&quot;1388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mmzsZ/btrLgrew0Yc/fuHtE2QXq570awZPPi3Qn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mmzsZ/btrLgrew0Yc/fuHtE2QXq570awZPPi3Qn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mmzsZ/btrLgrew0Yc/fuHtE2QXq570awZPPi3Qn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmmzsZ%2FbtrLgrew0Yc%2FfuHtE2QXq570awZPPi3Qn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2842&quot; height=&quot;1388&quot; data-origin-width=&quot;2842&quot; data-origin-height=&quot;1388&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://grafana.com/docs/grafana/latest/explore/query-management/#query-management-in-explore&quot;&gt;그라파나 공식 문서 - &quot;Que (1)ry management in Explore&quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://grafana.com/blog/2022/06/14/grafana-9.0-release-oss-and-cloud-features/&quot;&gt;그라파나 공식 블로그 문서 - (1)&quot;Grafana 9.0: Prometheus and Grafana Loki visual query builders, new navigation, improved workflows, heatmap panels, and more!&quot;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>24년 11월 이전/Dashboard</category>
      <category>DevOps</category>
      <category>Grafana</category>
      <category>grafana 9</category>
      <category>monitoring</category>
      <category>SRE</category>
      <category>그라파나</category>
      <category>그라파나 9</category>
      <category>데브옵스</category>
      <category>모니터링</category>
      <category>운영</category>
      <author>Gurumee</author>
      <guid isPermaLink="true">https://gurumee92.tistory.com/324</guid>
      <comments>https://gurumee92.tistory.com/324#entry324comment</comments>
      <pubDate>Fri, 2 Sep 2022 18:20:09 +0900</pubDate>
    </item>
    <item>
      <title>쿠버네티스에서 metrics-server 구성하기</title>
      <link>https://gurumee92.tistory.com/323</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;kubernetes.png&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctvPPc/btrKBFJ0Fnr/gGr2mPFi5sDKjxlXWlS6e1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctvPPc/btrKBFJ0Fnr/gGr2mPFi5sDKjxlXWlS6e1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctvPPc/btrKBFJ0Fnr/gGr2mPFi5sDKjxlXWlS6e1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctvPPc%2FbtrKBFJ0Fnr%2FgGr2mPFi5sDKjxlXWlS6e1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1004&quot; height=&quot;368&quot; data-filename=&quot;kubernetes.png&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;368&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스 클러스터를 운영하다보면 파드, 노드들의 리소스들을 확인해야 할 때가 정말 빈번하게 일어납니다. 이럴 때, 유용한 명령어로 &lt;code&gt;kubectl top&lt;/code&gt; 명령어가 있습니다. 한, 번 명령어를 입력해볼까요?&lt;/p&gt;
&lt;pre class=&quot;subunit&quot;&gt;&lt;code&gt;$ kubectl top po
error: Metrics API not available&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 로그를 확인할 수 있듯이 아쉽게도 기본적으로 제공되는 것은 아닙니다. 쿠버네티스 클러스터에 &lt;code&gt;metrics-server&lt;/code&gt;라는 컴포넌트를 추가적으로 설치해주어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문서에서는 쿠버네티스 클러스터 &lt;code&gt;minikube&lt;/code&gt; 환경에서 &lt;code&gt;metrics-server&lt;/code&gt;를 구성하는 것에 대하여 다룹니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;metrics-server 구성하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 다음 명령어를 이용하여 &lt;code&gt;metrics-server&lt;/code&gt;를 설치할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;$ kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
serviceaccount/metrics-server created
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrole.rbac.authorization.k8s.io/system:metrics-server created
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created
service/metrics-server created
deployment.apps/metrics-server created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치가 됐으니 한 번 &lt;code&gt;kubectl top&lt;/code&gt; 명령어를 사용해볼까요?&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ kubectl top po
Error from server (ServiceUnavailable): the server is currently unable to handle the request (get pods.metrics.k8s.io)

$ kubectl top no
Error from server (ServiceUnavailable): the server is currently unable to handle the request (get nodes.metrics.k8s.io)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런.. 아직도 정상적으로 실행이 안됩니다. 왜 그런 것일까요? 한 번 로그를 살펴봅시다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ kubectl logs -n kube-system metrics-server-64cf6869bd-l9lmp
...
I0825 12:20:36.015508       1 server.go:187] &quot;Failed probe&quot; probe=&quot;metric-storage-ready&quot; err=&quot;no metrics to serve&quot;
I0825 12:20:38.629536       1 server.go:187] &quot;Failed probe&quot; probe=&quot;metric-storage-ready&quot; err=&quot;no metrics to serve&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;metrics-server&lt;/code&gt;는 기본적으로 &lt;code&gt;kube-api-server&lt;/code&gt;와 https 통신을 통하여 노드/파드의 리소스들을 얻습니다. 하지만 &lt;code&gt;minikube&lt;/code&gt;로 구성된 쿠버네티스 클러스터는 &lt;code&gt;kube-api-server&lt;/code&gt;가 https 통신을 지원하지 않는 것으로 추정됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &lt;code&gt;metrics-server&lt;/code&gt; 역시 https 통신을 하지 않도록 구성을 해주면 됩니다. 다음 명령어를 통해서, &lt;code&gt;metrics-server&lt;/code&gt;에 전달하는 args를 수정합니다.&lt;/p&gt;
&lt;pre class=&quot;axapta&quot;&gt;&lt;code&gt;$ kubectl edit deployments.apps -n kube-system metrics-server &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 그림처럼 다음 옵션들을 추가해줍니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;--kubelet-insecure-tls&lt;/li&gt;
&lt;li&gt;--kubelet-preferred-address-types=InternalIP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;01.png&quot; data-origin-width=&quot;2532&quot; data-origin-height=&quot;302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yD3Si/btrKCWkotLw/1O820J6kRKAixi4bk0Ab4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yD3Si/btrKCWkotLw/1O820J6kRKAixi4bk0Ab4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yD3Si/btrKCWkotLw/1O820J6kRKAixi4bk0Ab4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyD3Si%2FbtrKCWkotLw%2F1O820J6kRKAixi4bk0Ab4k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2532&quot; height=&quot;302&quot; data-filename=&quot;01.png&quot; data-origin-width=&quot;2532&quot; data-origin-height=&quot;302&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;kubectl top 명령어 사용해보기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;metrics-server&lt;/code&gt;가 쿠버네티스 클러스터에 정상적으로 설치가 되었다면 &lt;code&gt;kubectl top&lt;/code&gt; 명령어가 활성화가 됩니다. 파드 단위의 리소스들을 모니터링하고 싶다면 &lt;code&gt;kubectl top po&lt;/code&gt;를 이용하면 됩니다. 다만 네임스페이스 단위로 리소스들을 확인할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ kubectl top po -n kube-system
NAME                               CPU(cores)   MEMORY(bytes)
coredns-78fcd69978-s5l6w           3m           11Mi
etcd-minikube                      30m          29Mi
kube-apiserver-minikube            126m         292Mi
kube-controller-manager-minikube   41m          43Mi
kube-proxy-2bzll                   2m           10Mi
kube-scheduler-minikube            5m           14Mi
metrics-server-7f6fdd8fc5-wzq5v    5m           13Mi
storage-provisioner                3m           8Mi&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, &lt;code&gt;kubectl top no&lt;/code&gt; 명령어를 사용하여 노드 단위의 리소스들을 확인할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ kubectl top no
NAME       CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
minikube   275m         6%     610Mi           3%&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/kubernetes-sigs/metrics-server&quot;&gt;metrics-server Github Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sarc.io/index.php/forum/tips/6747-minikube-metrics-server&quot;&gt;삵 블로그 - minikube에 metrics-server 설치&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>24년 11월 이전/쿠버네티스</category>
      <category>DevOps</category>
      <category>k8s</category>
      <category>kubectl top no</category>
      <category>kubectl top po</category>
      <category>Kubernetes</category>
      <category>metrics-server</category>
      <category>모니터링</category>
      <category>운영</category>
      <category>쿠버네티스</category>
      <author>Gurumee</author>
      <guid isPermaLink="true">https://gurumee92.tistory.com/323</guid>
      <comments>https://gurumee92.tistory.com/323#entry323comment</comments>
      <pubDate>Thu, 25 Aug 2022 22:07:02 +0900</pubDate>
    </item>
    <item>
      <title>[kubernetes] docker desktop에서 구성된 kubernetes 클러스터에서 metrics-server가 정상적으로 동작하지 않을 때</title>
      <link>https://gurumee92.tistory.com/322</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-08-21 오후 8.27.44.png&quot; data-origin-width=&quot;857&quot; data-origin-height=&quot;299&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yvgoR/btrJ9tEumIN/WZ9lknNCvGkSt8EDrpbdX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yvgoR/btrJ9tEumIN/WZ9lknNCvGkSt8EDrpbdX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yvgoR/btrJ9tEumIN/WZ9lknNCvGkSt8EDrpbdX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyvgoR%2FbtrJ9tEumIN%2FWZ9lknNCvGkSt8EDrpbdX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;857&quot; height=&quot;299&quot; data-filename=&quot;스크린샷 2022-08-21 오후 8.27.44.png&quot; data-origin-width=&quot;857&quot; data-origin-height=&quot;299&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 개인적으로 진행하는 작업이 있어서, &lt;code&gt;docker desktop&lt;/code&gt;에서 활성화한 &lt;code&gt;kubernetes&lt;/code&gt;에서 pod/node 등의 메트릭 지표를 얻기 위해서 &lt;code&gt;metrics-server&lt;/code&gt;를 설치했습니다. 이 때 만났던 문제들에 대해서 트러블슈팅하는 방법을 기록합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;docker v20.10.17&lt;/li&gt;
&lt;li&gt;맥북 정보:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;cpu: 2.3 GHz 쿼드 코어 Intel Core i7&lt;/li&gt;
&lt;li&gt;mem: 32GB 3733 MHz LPDDR4X&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;metrics-server&lt;/code&gt; 설치 명령어:&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;$ kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 이후 &lt;code&gt;kubectl top&lt;/code&gt; 명령어 실행 결과:&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ kubectl top no
Error from server (ServiceUnavailable): the server is currently unable to handle the request (get nodes.metrics.k8s.io)

$ kubectl top po
Error from server (ServiceUnavailable): the server is currently unable to handle the request (get pods.metrics.k8s.io)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 #1 Error from server (ServiceUnavailable): the server is currently unable to handle the request&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 문제는 &lt;code&gt;metrics-server&lt;/code&gt; 파드의 로그를 보면 왜 에러가 나는지 알 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ kubectl logs -n kube-system metrics-server-678f4bf65b-lg5n6
...
I0821 11:32:44.142448       1 server.go:187] &quot;Failed probe&quot; probe=&quot;metric-storage-ready&quot; err=&quot;no metrics to serve&quot;
E0821 11:32:51.407435       1 scraper.go:140] &quot;Failed to scrape node&quot; err=&quot;Get \&quot;https://192.168.65.4:10250/metrics/resource\&quot;: x509: cannot validate certificate for 192.168.65.4 because it doesn't contain any IP SANs&quot; node=&quot;docker-desktop&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 로그에 따르면 &lt;code&gt;metrics-server&lt;/code&gt;와 &lt;code&gt;kube-api-server&lt;/code&gt;와 https 통신이 원활하게 이루어지지 않고 있음을 확인할 수 있습니다. 이 문제를 해결하는 가장 쉬운 방법은 &lt;code&gt;metrics-server&lt;/code&gt;를 실행할 때 &lt;code&gt;--kubelet-insecure-tls&lt;/code&gt; 플래그를 추가하는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에 다음을 입력하여 &lt;code&gt;metrics-server&lt;/code&gt; 디플로이먼트를 수정합니다.&lt;/p&gt;
&lt;pre class=&quot;axapta&quot;&gt;&lt;code&gt;$ kubectl edit deployments.apps -n kube-system metrics-server&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 아래 그림처럼 해당 플래그를 추가해줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-08-21 오후 8.35.10.png&quot; data-origin-width=&quot;1063&quot; data-origin-height=&quot;287&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YrRxM/btrKb7mOECI/v6Ul5TyTEjd7jZQapQYcrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YrRxM/btrKb7mOECI/v6Ul5TyTEjd7jZQapQYcrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YrRxM/btrKb7mOECI/v6Ul5TyTEjd7jZQapQYcrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYrRxM%2FbtrKb7mOECI%2Fv6Ul5TyTEjd7jZQapQYcrK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1063&quot; height=&quot;287&quot; data-filename=&quot;스크린샷 2022-08-21 오후 8.35.10.png&quot; data-origin-width=&quot;1063&quot; data-origin-height=&quot;287&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;kubectl top&lt;/code&gt; 명령어를 입력해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;kubectl top&lt;/code&gt; 명령어 실행 결과:&lt;/p&gt;
&lt;pre class=&quot;subunit&quot;&gt;&lt;code&gt;$ kubectl top no
NAME             CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
docker-desktop   242m         6%     1567Mi          26%

$ kubectl top po -n kube-system
error: Metrics not available for pod kube-system/coredns-6d4b75cb6d-5db2z, age: 49m3.256834s&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드 단위는 정상 수행되지만 파드 단위에서 새로운 에러가 발생됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 #2 error: Metrics not available for pod&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 에러는 &lt;a href=&quot;https://github.com/kubernetes-sigs/metrics-server/issues/1061&quot;&gt;다음 이슈&lt;/a&gt;에서 해결 방법을 찾을 수 있었습니다. 이 문제의 근본적인 원인은 기본적으로 mac OS &lt;code&gt;docker desktop&lt;/code&gt;이 설치되면 &lt;code&gt;cri-dockerd v2.1.0&lt;/code&gt;이 도커 엔진으로 사용하는데 이 버전에서 버그가 있기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 그 버그가 해결된 &lt;code&gt;v2.3.0&lt;/code&gt;으로 변경해줍니다. 아래 명령어를 잘 따라하면 됩니다. 먼저 로컬 &lt;code&gt;Docker VM&lt;/code&gt;에 로그인합니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ docker run -it --privileged --pid=host ubuntu nsenter -t 1 -m -u -n -i sh
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
d19f32bd9e41: Pull complete
Digest: sha256:34fea4f31bf187bc915536831fd0afc9d214755bf700b5cdb1336c82516d154e
Status: Downloaded newer image for ubuntu:latest
# ---- 여기서부터 docker vm 컨테이너에 접속됩니다.
# ---- (위치) # 으로 표시됩니다.
/ #&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 다음 명령어들을 이용해서 &lt;code&gt;cri-dockerd v2.3.0&lt;/code&gt;를 설치합니다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;# ---- tmp로 이동
/ # cd /tmp/

# ---- cri-dockerd v2.3.0 다운로드
/tmp # wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.2.3/cri-dockerd-0.2.3.arm64.tgz

# ---- cri-dockerd v2.3.0 압축 해제
/tmp # tar zxvf cri-dockerd-0.2.3.arm64.tgz
cri-dockerd/
cri-dockerd/cri-dockerd&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치된 &lt;code&gt;cri-dockerd(v2.1.0)&lt;/code&gt; 바이너리 파일의 위치를 찾습니다.&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;/tmp # cd /
/ # find . -name &quot;cri-dockerd&quot;
./var/lib/kube-binary-cache-debian/cri-dockerd
./var/lib/docker/overlay2/057ad611e25d8e23d4d8f5b1dfe105f4bcb0dc2b784ef6f251cd11d91daa06c8/diff/binaries/cri-dockerd
./var/lib/docker/overlay2/a2b982b647747b7e3f29db8cfb5668279e47402b24ed0cbe8ddec256b3a112cc/diff/binaries/cri-dockerd
./var/lib/mount-services-cache/entries/services.tar/cfaf2b3b5d8c80d1fd63ca0acaa230bb7f027982b7783d8a9029e7c5fc0023be/containers/services/docker/rootfs/usr/bin/cri-dockerd
./var/lib/mount-services-cache/entries/services.tar/cfaf2b3b5d8c80d1fd63ca0acaa230bb7f027982b7783d8a9029e7c5fc0023be/containers/services/docker/tmp/upper/usr/bin/cri-dockerd
./var/lib/cri-dockerd
./tmp/cri-dockerd
./tmp/cri-dockerd/cri-dockerd
./containers/services/docker/rootfs/usr/bin/cri-dockerd             # --- 이부분
./containers/services/docker/tmp/upper/usr/bin/cri-dockerd          # --- 이부분&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 위치가 찾고 있는&amp;nbsp; cri-dockerd(v2.1.0)&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;바이너리 파일이&lt;/span&gt;&amp;nbsp;맞는지 확인합니다.&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;/ # ./containers/services/docker/tmp/upper/usr/bin/cri-dockerd --version
cri-dockerd 0.2.1 (HEAD)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;cri-dockerd(v2.3.0)&lt;/code&gt;으로 대체합니다.&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;/ # cp /tmp/cri-dockerd/cri-dockerd /containers/services/docker/rootfs/usr/bin
/ # cp /tmp/cri-dockerd/cri-dockerd /var/lib/kube-binary-cache-debian/cri-dockerd
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 &lt;code&gt;docker desktop&lt;/code&gt;을 재시작합니다. 그 후 &lt;code&gt;kubectl top&lt;/code&gt; 명령어를 입력합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;kubectl top&lt;/code&gt; 명령어 실행 결과:&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;$ kubectl top no
NAME             CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
docker-desktop   341m         8%     1480Mi          25%

$ kubectl top po -n kube-system
NAME                                     CPU(cores)   MEMORY(bytes)
coredns-6d4b75cb6d-5db2z                 4m           11Mi
coredns-6d4b75cb6d-nwbqv                 4m           45Mi
etcd-docker-desktop                      36m          73Mi
kube-apiserver-docker-desktop            65m          390Mi
kube-controller-manager-docker-desktop   38m          115Mi
kube-proxy-x4fsh                         1m           50Mi
kube-scheduler-docker-desktop            7m           52Mi
kube-state-metrics-5b8455d88b-j57kx      1m           40Mi
metrics-server-658867cdb7-wzq2c          8m           54Mi
storage-provisioner                      3m           9Mi
vpnkit-controller                        0m           24Mi&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두 정상 수행되는 것을 확인할 수 있습니다.&lt;/p&gt;</description>
      <category>레거시/트러블슈팅</category>
      <category>docker</category>
      <category>Error from server (ServiceUnavailable)</category>
      <category>error: Metrics not available for pod</category>
      <category>k8s</category>
      <category>kubectl top</category>
      <category>Kubernetes</category>
      <category>metrics-server</category>
      <category>monitoring</category>
      <category>troubleshooting</category>
      <category>트러블슈팅</category>
      <author>Gurumee</author>
      <guid isPermaLink="true">https://gurumee92.tistory.com/322</guid>
      <comments>https://gurumee92.tistory.com/322#entry322comment</comments>
      <pubDate>Sun, 21 Aug 2022 20:44:39 +0900</pubDate>
    </item>
    <item>
      <title>[Golang] fatal error: concurrent map writes</title>
      <link>https://gurumee92.tistory.com/321</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;트러블슈팅 로고.png&quot; data-origin-width=&quot;851&quot; data-origin-height=&quot;289&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s73nV/btryq60QwWn/LVUWbkfq3SqEsYfFEGAGTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s73nV/btryq60QwWn/LVUWbkfq3SqEsYfFEGAGTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s73nV/btryq60QwWn/LVUWbkfq3SqEsYfFEGAGTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs73nV%2Fbtryq60QwWn%2FLVUWbkfq3SqEsYfFEGAGTk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;851&quot; height=&quot;289&quot; data-filename=&quot;트러블슈팅 로고.png&quot; data-origin-width=&quot;851&quot; data-origin-height=&quot;289&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 상황&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;golang&lt;/code&gt; 개발 중, &lt;code&gt;map&lt;/code&gt; 객체에 어떤 값을 저장하여, 이를 이용하는 서비스를 만든다고 해보자. 처음에는 쉽게 다음과 같이 &lt;code&gt;WriteMap&lt;/code&gt; 함수를 이용해서 코드를 간단하게 작성할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func WriteMap(m map[int]int, num int) {
    for i := 0; i &amp;lt; num; i++ {
        m[i] = i
    }
}

func main() {
    fmt.Println(&quot;map writes start!&quot;)
    m := map[int]int{}
    WriteMap(m, 100)
    fmt.Println(&quot;map writes end!&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, 고루틴을 이용하여 &lt;code&gt;WriteMap&lt;/code&gt; 함수의 성능 향상을 계획했다고 가정해보자. 그럼 코드는 이렇게 바꿀 수 있을 것이다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func WriteMap(m map[int]int, num int) {
    for i := 0; i &amp;lt; num; i++ {
        go func() {
            m[i] = i
        }()
    }
}

func main() {
    fmt.Println(&quot;map writes start!&quot;)
    m := map[int]int{}
    WriteMap(m, 100)
    fmt.Println(&quot;map writes end!&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 프로그램을 실행시키면, 다음 에러를 일으키는 것을 확인할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ go run main.go 
map writes start!
fatal error: concurrent map writes

goroutine 12 [running]:
runtime.throw(0x10ca420, 0x15)
        /Users/gurumee/.gvm/gos/go1.16/src/runtime/panic.go:1117 +0x72 fp=0xc00004d760 sp=0xc00004d730 pc=0x10327f2
runtime.mapassign_fast64(0x10b1ce0, 0xc00007a180, 0x1e, 0x0)
        /Users/gurumee/.gvm/gos/go1.16/src/runtime/map_fast64.go:101 +0x33e fp=0xc00004d7a0 sp=0xc00004d760 pc=0x1010c3e
main.WriteMap.func1(0xc0000160c8, 0xc00007a180)
        /Users/gurumee/Workspace/troubleshooting/go-concurrent-map-writes/main.go:8 +0x45 fp=0xc00004d7d0 sp=0xc00004d7a0 pc=0x10a3365
runtime.goexit()
        /Users/gurumee/.gvm/gos/go1.16/src/runtime/asm_amd64.s:1371 +0x1 fp=0xc00004d7d8 sp=0xc00004d7d0 pc=0x1064361
created by main.WriteMap
        /Users/gurumee/Workspace/troubleshooting/go-concurrent-map-writes/main.go:7 +0x65

goroutine 1 [runnable]:
fmt.Fprintln(0x10e83a0, 0xc00000e018, 0xc000076f58, 0x1, 0x1, 0x12, 0x0, 0x0)
        /Users/gurumee/.gvm/gos/go1.16/src/fmt/print.go:262 +0xed
fmt.Println(...)
        /Users/gurumee/.gvm/gos/go1.16/src/fmt/print.go:274
main.main()
        /Users/gurumee/Workspace/troubleshooting/go-concurrent-map-writes/main.go:17 +0xe5

goroutine 9 [runnable]:
main.WriteMap.func1(0xc0000160c8, 0xc00007a180)
        /Users/gurumee/Workspace/troubleshooting/go-concurrent-map-writes/main.go:7
created by main.WriteMap
        /Users/gurumee/Workspace/troubleshooting/go-concurrent-map-writes/main.go:7 +0x65

goroutine 11 [runnable]:
main.WriteMap.func1(0xc0000160c8, 0xc00007a180)
        /Users/gurumee/Workspace/troubleshooting/go-concurrent-map-writes/main.go:7
created by main.WriteMap
        /Users/gurumee/Workspace/troubleshooting/go-concurrent-map-writes/main.go:7 +0x65
...&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 원인&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 &lt;a href=&quot;https://go.dev/doc/faq#atomic_maps&quot;&gt;문서&lt;/a&gt;를 보면, 그 실마리를 찾을 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Why are map operations not defined to be atomic?&lt;br /&gt;&lt;br /&gt;After long discussion it was decided that the typical use of maps did not require safe access from multiple goroutines, and in those cases where it did, the map was probably part of some larger data structure or computation that was already synchronized. Therefore requiring that all map operations grab a mutex would slow down most programs and add safety to few. This was not an easy decision, however, since it means uncontrolled map access can crash the program.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문서에 따르면, &lt;code&gt;golang&lt;/code&gt; 개발진은 &lt;code&gt;map&lt;/code&gt; 객체를 동시에 접근하는 상황을 일반적인 상황으로 보지 않았고, 따라서 표준 라이브러리에서 제공하는 &lt;code&gt;map&lt;/code&gt;은 &quot;atomic&quot;한 연산을 지원하지 않는다. 쉽게 말해 동시성을 처리하는 연산을 지원하지 않는다는 뜻이다. 즉 위 &lt;code&gt;WriteMap&lt;/code&gt;의 경우 &lt;code&gt;num&lt;/code&gt;개 만큼 생성되는 고루틴들에서 &lt;code&gt;map&lt;/code&gt; 객체를 동시에 접근하나, 이를 처리하지 않기 때문에 생기는 문제였다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 해결&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 해결 방법은 크게 2가지이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WaitGroup, Mutex Lock/Unlock을 이용한 동시성 제어&lt;/li&gt;
&lt;li&gt;Channel을 이용한 동시성 제어&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 가장 쉬운 &lt;code&gt;WaitGroup&lt;/code&gt;과 &lt;code&gt;Mutex&lt;/code&gt;를 이용한 방법을 살펴보자. &lt;code&gt;Mutex&lt;/code&gt;는 여러 스레드가 동시에 접근하는 객체에 한 스레드만 수행할 수 있도록 잠금을 해버린다. 한 스레드의 수행이 끝나야 다른 스레드의 수행이 실행될 수 있다. 다음과 같이 &lt;code&gt;WriteMap&lt;/code&gt;을 수정하면 된다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;package main

import (
    &quot;fmt&quot;
    &quot;sync&quot;
)

func WriteMap(m map[int]int, num int) {
    mutex := &amp;amp;sync.Mutex{}
    wg := &amp;amp;sync.WaitGroup{}

    for i := 0; i &amp;lt; num; i++ {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            mutex.Lock()
            m[i] = i
            mutex.Unlock()
        }(i)
    }

    wg.Wait()
}

// ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;WaitGroup&lt;/code&gt;은 고루틴 개수만큼 카운터를 저장한다. 이 카운터가 0가 될 때까지 &lt;code&gt;WriteMap&lt;/code&gt; 함수는 종료되지 않고 대기하게 된다. &lt;code&gt;defer wg.Done()&lt;/code&gt; 구문 덕분에 고루틴이 종료되는 순간 풀에서 &lt;code&gt;WaitGroup&lt;/code&gt;의 카운터를 줄이게 된다. 쉽게 말해서 동시에 접근하는 동안, 모든 고루틴이 실행을 마칠 때까지 기다리기 위해서 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Mutex&lt;/code&gt;가 실제로 여러 고루틴이 동시에 접근할 때 순차적으로 접근할 수 있도록 잠금을 해주는 장치라고 보면 된다. 이 때, &lt;code&gt;Lock&lt;/code&gt;과 &lt;code&gt;Unlock&lt;/code&gt;이 쌍을 이루어야 한다는 점에 주의하자. 순서가 잘못되거나, 쌍이 맞지 않으면 여러 고루틴이 영원히 종료되지 않는 데드락 상황이 벌어지기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 방식은 &lt;code&gt;Channel&lt;/code&gt;을 이용한 방식이다. 실제로 &lt;code&gt;golang&lt;/code&gt;에서 수 많은 고루틴을 제어할 때 권장하는 방법이며 주로 &lt;code&gt;select&lt;/code&gt;랑 같이 사용된다. 다음과 같이 코드를 변경하면 채널을 이용해서 여러 고루틴들을 제어할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;package main

// ...

func WriteMapChan(m map[int]int, num int) {
    c := make(chan int)

    for i := 0; i &amp;lt; num; i++ {
        go func(i int) {
            c &amp;lt;- i
        }(i)
    }

    for i := 0; i &amp;lt; num; i++ {
        v := &amp;lt;-c
        m[v] = v
    }
}

// ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;channel&lt;/code&gt;은 보통 &lt;code&gt;make(chan [type])&lt;/code&gt; 형태로 만들어진다. 이들은 타입만 맞는다면 여러 고루틴이 값을 전송할 수 있는 일종의 통로가 된다. 즉, 첫 번째 for문에서, 다음과 같은 형태로 채널에 값을 전달하는 코드이다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;for i := 0; i &amp;lt; num; i++ {
    go func(i int) {
        c &amp;lt;- i        // 채널에 값을 전달
    }(i)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;&amp;lt;-c&lt;/code&gt;는 채널에서 값을 빼온다는 구문이다. 즉 &lt;code&gt;num&lt;/code&gt;개만큼 채널에 데이터를 전달했으니 그만큼 데이터를 빼와야 하는 것이다. 즉 두 번째 for문은 채널에서 값을 빼와 맵에 값을 넣는 방식이다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;for i := 0; i &amp;lt; num; i++ {
    v := &amp;lt;-c        // 채널에서 값을 빼옴
    m[v] = v        // 빼온 값을 맵객체에 넣음.
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 가지 중 하나를 적용했다면, &quot;fatal error: concurrent map writes&quot; 문제는 제거됨을 확인할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;$ go run main.go
map writes start!
map writes end!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 다 장단점이 있다. &lt;code&gt;WaitGroup/Mutex&lt;/code&gt; 방법은 코드 구조가 변경되지 않기 때문에 굉장히 직관적이다. 하지만 성능이 떨어진다. &lt;code&gt;Channel&lt;/code&gt; 방식은 성능은 빠르나, 코드 구조를 살짝 바꿔줘야 하는 번거로움이 있다. 개인적으로는 &lt;code&gt;Channel&lt;/code&gt; 방식이 숙달만 되면 확실히 더 편한 감이 있다.&lt;/p&gt;</description>
      <category>레거시/트러블슈팅</category>
      <category>Channel</category>
      <category>Concurrency</category>
      <category>fatal error: concurrent map writes</category>
      <category>Golang</category>
      <category>mutex</category>
      <category>troubleshooting</category>
      <category>WaitGroup</category>
      <category>고</category>
      <category>동시성</category>
      <category>트러블슈팅</category>
      <author>Gurumee</author>
      <guid isPermaLink="true">https://gurumee92.tistory.com/321</guid>
      <comments>https://gurumee92.tistory.com/321#entry321comment</comments>
      <pubDate>Mon, 4 Apr 2022 19:19:12 +0900</pubDate>
    </item>
  </channel>
</rss>