<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>gojol_devops.log</title>
        <link>https://velog.io/</link>
        <description>고졸개발자취업도전</description>
        <lastBuildDate>Thu, 16 Jan 2025 08:58:03 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>gojol_devops.log</title>
            <url>https://velog.velcdn.com/images/gojol_devops/profile/482ffee9-a798-4ab7-8dab-a756c45fcee3/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. gojol_devops.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/gojol_devops" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Istio]]></title>
            <link>https://velog.io/@gojol_devops/Istio</link>
            <guid>https://velog.io/@gojol_devops/Istio</guid>
            <pubDate>Thu, 16 Jan 2025 08:58:03 GMT</pubDate>
            <description><![CDATA[<h1 id="istio-란">Istio 란?</h1>
<p>기존 분산 애플리케이션에 투명하게 레이어링되는 오픈 소스 서비스 메시입니다. Istio의 강력한 기능은 서비스를 보안, 연결 및 모니터링하는 균일하고 효율적인 방법을 제공합니다. Istio는 서비스 코드를 거의 변경하지 않고도 부하 분산, 서비스 간 인증 및 모니터링을 위한 경로입니다. 다음을 제공합니다.</p>
<ul>
<li>상호 TLS 암호화, 강력한 ID 기반 인증 및 권한 부여를 통해 클러스터에서 안전한 서비스 간 통신을 제공합니다.</li>
<li>HTTP, gRPC, WebSocket 및 TCP 트래픽에 대한 자동 로드 밸런싱</li>
<li>풍부한 라우팅 규칙, 재시도, 장애 조치 및 오류 주입을 통한 트래픽 동작의 세부적인 제어</li>
<li>액세스 제어, 속도 제한 및 할당량을 지원하는 플러그형 정책 계층 및 구성 API</li>
<li>클러스터 유입 및 유출을 포함하여 클러스터 내의 모든 트래픽에 대한 자동 메트릭, 로그 및 추적</li>
</ul>
<hr>
<h1 id="sidecar-or-ambient-">Sidecar or ambient ?</h1>
<p>Istio 서비스 메시는 논리적으로 데이터 플레인과 제어 플레인으로 분할합니다.</p>
<p>그만큼데이터 플레인마이크로서비스 간의 모든 네트워크 통신을 중재하고 제어하는 프록시 세트입니다. 또한 모든 메시 트래픽에 대한 원격 측정을 수집하고 보고합니다.</p>
<h2 id="sidecar-mode">Sidecar mode</h2>
<p>Istio는 2017년 첫 번째 릴리스부터 사이드카 패턴을 기반으로 구축되었습니다. Sidecar 모드는 잘 이해되고 철저히 검증 되었지만 리소스 비용과 운영 오버헤드가 발생합니다.</p>
<ul>
<li>배포하는 각 애플리케이션에는 사이드카로 주입된 Envoy 프록시가 있습니다.</li>
<li>모든 프록시는 Layer 4와 Layer 7을 모두 처리할 수 있습니다.</li>
</ul>
<h2 id="ambient-mode">Ambient mode</h2>
<p>2022년에 출시된 Ambient 모드는 Sidecar 모드 사용자가 보고한 단점을 해결하기 위해 구축되었습니다. Istio 1.22 기준으로 단일 클러스터 사용 사례에 대해 프로덕션 준비가 완료되었습니다.</p>
<ul>
<li>모든 트래픽은 Layer 4 전용 노드 프록시를 통해 프록시됩니다.</li>
<li>애플리케이션은 Layer 7 기능을 얻기 위해 Envoy 프록시를 통한 라우팅을 선택할 수 있습니다.</li>
</ul>
<hr>
<h1 id="virtual-service">Virtual Service</h1>
<p>Istio의 서비스 메쉬에서 트래픽을 관리하고 라우팅 규칙을 정희하는 중요한 개체입니다. 이를 사용하여 요청을 처리하는 방식, 즉 특정 서비스로의 트래픽 흐름을 제어할 수 있습니다. VirtualService 는 일반적으로 DestinationRule과 함께 사용되어, 요청을 서비스의 여러 버전 중 하나로 라우팅 할 수 있게 합니다.</p>
<h2 id="virtualservice-의-주요기능">VirtualService 의 주요기능</h2>
<ol>
<li><p>트래픽 라우팅 :</p>
<ul>
<li>VirtualService는 HTTP, TCP, gRPC 등 다양한 프로토콜을 기반으로 트래픽을 정의할 수 있습니다.</li>
<li>요청을 특정 서비스로 라우팅하거나, 서비스 내 여러 버전으로 분배할 수 있습니다.</li>
</ul>
</li>
<li><p>동적 라우팅 규칙 설정 : </p>
<ul>
<li>트래픽을 특정 조건에 따라 동적으로 라우팅할 수 있습니다. 예를 들어, 요청의 헤더,, 쿼리 파라미터, URI 경로 등에 따라 트래픽을 분배할 수 있습니다.</li>
</ul>
</li>
<li><p>트래픽 분할 :</p>
<ul>
<li>A/B 테스트, Canary 배포, 트래픽의 점진적 배포를 위해 트래픽을 여러 서비스 버전 간에 나누어 보낼 수 있습니다.</li>
<li>예를 들어, 전체 트래픽의 90%는 안정적인 버전으로 보내고, 나머지 10%는 새로 배포된 버전으로 보내는 방식입니다.</li>
</ul>
</li>
<li><p>리트라이 및 타임아웃 설정:</p>
<ul>
<li>요청이 실패할 경우 자동으로 재시도하는 기능을 설정하거나, 타임아웃을 지정할 수 있습니다.</li>
</ul>
</li>
<li><p>헤더 리다이렉션 및 리라이트:</p>
<ul>
<li>요청 헤더를 변경하거나 리다이렉션할 수 있습니다. 예를 들어, HTTP 요청의 User-Agent 헤더를 기반으로 라우팅을 변경하거나, URI를 리라이트하여 새로운 경로로 리디렉션할 수 있습니다.</li>
</ul>
</li>
<li><p>Fault Injection (장애 주입):</p>
<ul>
<li>서비스의 내구성을 테스트하기 위해 의도적으로 지연, 오류 등을 주입하여 장애 상황을 시뮬레이션할 수 있습니다.</li>
</ul>
<hr>
</li>
</ol>
<h3 id="virtualservice-예시">VirtualService 예시</h3>
<pre><code class="language-yaml">apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: example-virtualservice
spec:
  hosts:
  - example.com
  http:
  - match:
    - uri:
        prefix: &quot;/v1&quot;
    route:
    - destination:
        host: example-service
        subset: v1
  - match:
    - uri:
        prefix: &quot;/v2&quot;
    route:
    - destination:
        host: example-service
        subset: v2
</code></pre>
<h3 id="예시-설명">예시 설명</h3>
<p>이 예시에서는 <code>/v1</code> 경로로 들어오는 요청은 <code>example-service</code>의 <code>v1</code> 버전으로 라우팅되고, <code>/v2</code> 경로로 들어오는 요청은 <code>v2</code> 버전으로 라우팅됩니다.</p>
<hr>
<h3 id="virtualservice의-중요한-구성-요소">VirtualService의 중요한 구성 요소</h3>
<ul>
<li><p><strong>hosts</strong>:</p>
<ul>
<li>트래픽을 처리할 서비스의 도메인 이름을 지정합니다. 예를 들어, <code>example.com</code>과 같은 값을 지정할 수 있습니다.</li>
</ul>
</li>
<li><p><strong>http / tcp / tls</strong>:</p>
<ul>
<li>트래픽의 종류를 정의합니다. <ul>
<li><code>http</code>: HTTP 요청을</li>
<li><code>tcp</code>: TCP 트래픽을</li>
<li><code>tls</code>: TLS 암호화된 트래픽을 처리합니다.</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>match</strong>:</p>
<ul>
<li>라우팅 조건을 정의합니다. 예를 들어, 특정 URI 경로, 헤더 값, 메소드 등 다양한 조건을 사용할 수 있습니다.</li>
</ul>
</li>
<li><p><strong>route</strong>:</p>
<ul>
<li>트래픽을 라우팅할 대상과 그에 대한 설정을 정의합니다. 여기서 <code>destination</code>은 라우팅할 서비스와 서비스의 버전을 지정할 수 있습니다.</li>
</ul>
</li>
<li><p><strong>faultInjection</strong>:</p>
<ul>
<li>요청에 오류를 주입하는 설정을 할 수 있습니다. 예를 들어, 트래픽에 지연을 주거나 오류 상태를 반환하도록 설정할 수 있습니다.</li>
</ul>
</li>
</ul>
<hr>
<h3 id="virtualservice-활용-예시">VirtualService 활용 예시</h3>
<ol>
<li><p><strong>Canary 배포</strong>:</p>
<ul>
<li>새로운 버전의 애플리케이션을 배포할 때, 전체 트래픽 중 일부만 새로운 버전으로 보내어 점진적으로 배포할 수 있습니다.</li>
</ul>
</li>
<li><p><strong>A/B 테스트</strong>:</p>
<ul>
<li>두 개 이상의 버전을 동시에 운용하면서 트래픽을 분할하여 성능이나 기능을 테스트할 수 있습니다.</li>
</ul>
</li>
<li><p><strong>트래픽 리다이렉션</strong>:</p>
<ul>
<li>특정 URI나 요청 헤더 값에 따라 트래픽을 다른 서비스나 엔드포인트로 리디렉션할 수 있습니다.</li>
</ul>
</li>
</ol>
<hr>
<h3 id="결론">결론</h3>
<p>Istio VirtualService는 다양한 라우팅 기능을 제공하여 서비스 간 트래픽을 세밀하게 제어하고, 서비스 메쉬 환경에서의 트래픽 관리 및 최적화를 가능하게 합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[gRPC 란,]]></title>
            <link>https://velog.io/@gojol_devops/gRPC-%EB%9E%80</link>
            <guid>https://velog.io/@gojol_devops/gRPC-%EB%9E%80</guid>
            <pubDate>Tue, 17 Dec 2024 08:30:42 GMT</pubDate>
            <description><![CDATA[<h1 id="grpc">gRPC</h1>
<blockquote>
<p>Google에서 개발한 언어에 상관없이 사용할 수 있는 고성능 RPC 프레임워크입니다.
특히 마이크로서비스 아키텍쳐에서 많이 사용됩니다.</p>
</blockquote>
<hr>
<h1 id="rpc-remote-procedure-call-">RPC (Remote Procedure Call) ?</h1>
<ul>
<li>네트워크로 연결된 서버 상의 프로시저(함수, 메서드 등)를 원격으로 호출할 수 있는 기능입니다. </li>
<li>통신이나 call 방식에 신경쓰지 않고 원격지의 자원을 내 것처럼 사용할 수 있습니다. </li>
<li>IDL 기반으로 다양한 언어를 가진 환경에서도 쉽게 확장이 가능하며, 인터페이스 협업에도 용이하다는 장점이 있습니다.</li>
</ul>
<h2 id="stub">Stub</h2>
<p>RPC의 핵심 개념은 <strong>Stub</strong> (스텁)이라는 것입니다.
서버와 클라이언트는 서로 다른 주소 공간을 사용하므로, 함수 호출에 사용된 매개 변수를 꼭 변환해줘야 합니다.
이 변환을 담당하는게 스텁입니다.</p>
<h3 id="기본적인-rpc-통신과정">기본적인 RPC 통신과정</h3>
<p><img src="https://velog.velcdn.com/images/gojol_devops/post/e5672589-4efc-42a3-ba72-b1bdea6b1769/image.png" alt="">
RPC 구조 (출처 :<a href="https://middlewares.files.wordpress.com/2008/04/17.jpg">https://middlewares.files.wordpress.com/2008/04/17.jpg</a>)</p>
<ol>
<li><p>IDL을 사용하여 호출 규약 정의합니다.</p>
<ul>
<li>함수명, 인자, 반환값에 대한 데이터형이 정의된 IDL파일을 rpcgen으로 컴파일하면 stub code가 자동으로 생성됩니다.</li>
</ul>
</li>
<li><p>Stub Code에 명시된 함수는 원시코드의 형태로, 상세 기능은 server에서 구현됩니다.</p>
<ul>
<li>만들어진 stub 코드는 클라이언트/서버에 함께 빌드 합니다.</li>
</ul>
</li>
<li><p>client에서 stub 에 정의된 함수를 사용할 때,</p>
</li>
<li><p>client stub 은 RPC runtime을 통해 함수를 호출하고,</p>
</li>
<li><p>server는 수신된 procedure 호출에 대한 처리 후 결과 값을 반환합니다.</p>
</li>
<li><p>최종적으로 Cilent는 Server의 결과 값을 반환받고, 함수를 Local에 있는 것 처럼 사용할 수 있습니다.</p>
</li>
</ol>
<hr>
<p>RPC는 상당히 획기적인 방법론이었으며, 분산 환경의 등장에 따라 함께 발전해 온 오래된 기술입니다. 
따라서 구현체도 CORBA, RMI 등 여러가지가 있었는데요. 
이들 모두 로컬에서 제공하는 빠른 속도, 가용성 등을 분산 프로그래밍에서도 제공하고 있다고 홍보를 했지만, 정작 구현의 어려움/지원 기능의 한계 등으로 제대로 활용되지 못했습니다. 그렇게 RPC 프로젝트도 점차 뒷길로 가게되며 데이터 통신을 우리에게 익숙한 Web을 활용해보려는 시도로 이어졌고, <strong>이 자리를 REST가 차지하게됩니다.</strong></p>
<hr>
<h1 id="rest">REST</h1>
<blockquote>
<p>REST는 HTTP/1.1 기반으로 URI를 통해 모든 자원(Resource)을 명시하고 HTTP Method를 통해 처리하는 아키텍쳐 입니다. </p>
</blockquote>
<ul>
<li>자원 그 자체를 표현하기에 직관적이고, HTTP를 그대로 계승하였기에 별도 작업 없이도 쉽게 사용할 수 있다는 장점으로 현대에 매우 보편화되어있었습니다. 
하지만 REST에도 한계는 존재했습니다. 
REST는 일종의 스타일이지 표준이 아니기 때문에 parameter와 응답 값이 명시적이지 않습니다. 
또한 HTTP 메소드의 형태가 제한적이기 때문에 세부 기능 구현에는 제약이 있습니다.</li>
</ul>
<p>덧붙여, 웹 데이터 전달 format으로 xml, json을 많이 사용하는데요.</p>
<ul>
<li>XML은 html과 같이 tag 기반이지만 미리 정의된 태그가 없어(no pre-defined tags) 높은 확장성을 인정 받아 이기종간 데이터 전송의 표준이었으나, 다소 복잡하고 비효율적인 데이터 구조탓에 속도가 느리다는 단점이 있었습니다. 이런 효율 문제를 JSON이 간결한 Key-Value 구조 기반으로 해결하는 듯 하였으나, 제공되는 자료형의 한계로 파싱 후 추가 형변환이 필요한 경우가 많아졌습니다. 또한 두 타입 모두 string 기반이라 사람이 읽기 편하다는 장점은 있으나, 바꿔 말하면 데이터 전송 및 처리를 위해선 별도의 Serialization이 필요하다는 것을 의미합니다.</li>
</ul>
<hr>
<h1 id="grpc-특징">gRPC 특징</h1>
<ul>
<li><p>HTTP/2 기반으로 동작합니다. HTTP/2의 멀티플렉싱 기능을 통해 하나의 커넥션에서 동시에 여러 요청과 응답을 처리할 수 있습니다.</p>
</li>
<li><p>Protocol Buffer(Protobuf)를 데이터 직렬화 포맷으로 사용합니다.
Protobuf는 데이터 구조를 컴팩트하게 직렬화하며, JSON보다 더 빠르고 효율적인 직렬화와 역직렬화를 제공합니다.</p>
</li>
<li><p>다양한 언어 지원</p>
</li>
<li><p>클라이언트와 서버 간의 양방향 스트리밍을 지원합니다. 따라서 실시간 데이터 전송에 유용합니다</p>
</li>
</ul>
<h2 id="http2의-특징">HTTP/2의 특징</h2>
<ul>
<li><p>Binary Protocol 을 사용해서 데이터 전송합니다.</p>
<ul>
<li>데이터의 직렬화와 파싱이 효율적입니다.</li>
</ul>
</li>
<li><p>Multiplexing : 하나의 TCP 연결에서 여러 요청과 응답을 동시에 처리할 수 있습니다.</p>
<ul>
<li>네트워크 효율성을 향상시키고 요청 및 응답간의 지연속도를 줄입니다.</li>
</ul>
</li>
<li><p>HPACK : 헤더 압축 알고리즘을 사용해서 요청과 응답 헤더를 압축합니다. 헤더의 중복을 줄이고 전송 데이터의 크기를 줄여 네트워크 대역폭을 절약합니다.</p>
</li>
<li><p>Server Push : 서버가 클라이언트의 요청을 예상하고 필요한 리소스를 클라이언트에게 미리 전송할 수 있습니다.</p>
</li>
</ul>
<hr>
<h2 id="grpc-구성요소">gRPC 구성요소</h2>
<h3 id="stub-1">Stub</h3>
<p>gRPC의 클라이언트와 서버간의 인터페이스를 정의하고 구현하는 역할을 합니다.</p>
<ul>
<li><p>client Stub : 클라이언트에서 원격 프로시저를 호출하는데 사용되는 객체입니다. 해당 Stub으로 서버의 매서드를 로컬 메서드처럼 호출할 수 있습니다.</p>
</li>
<li><p>server Stub : 서버 측에서 클라이언트의 요청을 처리하는데 사용되는 객체입니다. 해당 stub으로 클라이언트의 요청을 수신하고, 적절한 로직을 수행하여 응답을 클라이언트에게 반환합니다.</p>
</li>
</ul>
<h3 id="protocl-buffer-protobuf">Protocl Buffer (Protobuf)</h3>
<p>데이터 구조를 정의하고, 이 구조에 따라 데이터를 직렬화하고 역직렬화합니다.
Protobuf는 다양한 프로그래밍 언어와 플랫폼에서 사용될 수 있는 데이터를 정의하는 방법을 제공합니다.</p>
<p>Protobuf는 <strong>protoc</strong>를 이용해서 .proto 파일을 기반으로 다양한 프로그래밍 언어에 맞는 소스 코드를 자동으로 생성합니다.</p>
<ul>
<li>직렬화 : 바이트 스트림으로 변환</li>
<li>역직렬화 : 바이트 스트림을 원래 구조로 복원</li>
<li>.proto 파일 : 데이터 구조와 메시지 형식을 정의</li>
</ul>
<pre><code># proto file
syntax = &quot;proto3&quot;;

// 메시지 정의
message Person {
  int32 id = 1;
  string name = 2;
  string email = 3;
}

// RPC 서비스 정의
service ExampleService {
  rpc GetPerson (PersonRequest) returns (Person);
}

// 요청 메시지 정의
message PersonRequest {
  int32 id = 1;
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Kubernetes] - 쿠버네티스(k8s)]]></title>
            <link>https://velog.io/@gojol_devops/Kubernetes-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4k8s</link>
            <guid>https://velog.io/@gojol_devops/Kubernetes-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4k8s</guid>
            <pubDate>Mon, 16 Dec 2024 08:55:18 GMT</pubDate>
            <description><![CDATA[<h1 id="컨테이너-오케스트레이션">컨테이너 오케스트레이션</h1>
<blockquote>
<p>컨테이너 오케스트레이션은 <strong>중앙관리자</strong>로 복잡한 컨테이너 환경을 효과적으로 관리하기 위한 도구입니다.</p>
</blockquote>
<p>컨테이너 오케스트레이션은 아래와 같은 기능을 제공해줍니다.</p>
<ul>
<li>상태관리</li>
<li>배포관리</li>
<li>배포 버전 관리</li>
<li>서비스 등록 및 조회</li>
</ul>
<hr>
<h1 id="쿠버네티스">쿠버네티스</h1>
<blockquote>
<p>컨테이너화된 애플리케이션을 자동으로 배포, 스케일링 및 관리해주는 오픈소스 시스템</p>
</blockquote>
<p>컨테이너 오케스트레이션 중 하나가 쿠버네티스입니다.</p>
<hr>
<h2 id="pod-란">Pod 란</h2>
<blockquote>
<p>쿠버네티스에서 생성하고 관리할 수 있는 배포 가능한 가장 작은 컴퓨팅 단위입니다.
그리고 하나 이상의 컨테이너 그룹을 뜻합니다.</p>
</blockquote>
<h3 id="파드-컨테이너-개념정리">파드-컨테이너 개념정리</h3>
<ul>
<li>컨테이너는 애플리케이션을 뜻합니다. 이는 완전한 어플리케이션의 일부 기능일 수도 있고, 완전한 어플리케이션 그 자체일 수 있습니다.</li>
<li>만약 컨테이너가 완전한 어플리케이션의 일부 기능이라면?<ul>
<li>여러 개의 컨테이너들이 모여 하나의 완전한 어플리케이션을 구성할 것입니다.</li>
<li>이때 여러 개의 컨테이너가 모여 하나의 파드가 됩니다. (그럼 이 파드가 완전한 어플리케이션이 됩니다.)</li>
</ul>
</li>
<li>만약 컨테이너 1개가 완전한 어플리케이션 기능을 갖추고 있다면?<ul>
<li>하나의 컨테이너로도 하나의 파드를 구성할 수 있습니다.</li>
</ul>
</li>
<li>즉, 파드에 정의된 여러 개의 컨테이너는 하나의 완전한 애플리케이션으로서 동작합니다</li>
</ul>
<hr>
<h2 id="node-란">node 란</h2>
<blockquote>
<p>클러스터 내 가상 서버
즉, 컴퓨팅 엔진 단위라고 이해하면 됩니다.</p>
</blockquote>
<p>클러스터 다음으로 큰 단위이며, 마스터 노드와 워커 노드로 분리되어 있습니다.</p>
<p>마스터 노드가 죽으면 클러스터를 관리할 노드가 없기에, 일반적으로는 3개 정도의 마스터 노드를 띄어 관리하는 것으로 알려져 있습니다</p>
<hr>
<h2 id="cluster-란">Cluster 란</h2>
<blockquote>
<p>쿠버네티스 내 가장 큰 단위로, 가상 서버들이 속한 클라우드를 뜻합니다.</p>
</blockquote>
<p>쿠버네티스에서 서버는 노드 라는 단위로 불리므로,
클러스터란 마스터 노드와 워커노드를 합친 것 이라 해석할 수 있습니다.</p>
<hr>
<h2 id="쿠버네티스-클러스터-구성">쿠버네티스 클러스터 구성</h2>
<h3 id="master-node--워커-노드들의-상태를-관리하고-제어">Master node : 워커 노드들의 상태를 관리하고 제어</h3>
<ul>
<li>etcd : key-value 타입의 저장소. worker node, 쿠버네티스의 상태정보를 가지고 있습니다.</li>
<li>kube - apiserver : 사용자와 클러스터 간의 통신 인터페이스, scheduler에게 요청</li>
<li>kube - scheduler : 새로 생성된 Pod의 배치를 결정.</li>
<li>kube - controller - manager : 클러스터 상태를 유지하도록 관리(복제본, 노드 상태 등).</li>
</ul>
<h3 id="worker-node--실제-애플리케이션이-실행되는-곳">Worker node : 실제 애플리케이션이 실행되는 곳</h3>
<ul>
<li>kubelet : 마스터와 통신하여 Pod의 생애 주기를 관리</li>
<li>Container Runtime : 컨테이너(Docker, containerd)를 실행.</li>
<li>Kube Proxy : 네트워크 트래픽을 관리하고, 서비스 간 통신을 지원.</li>
</ul>
<hr>
<h2 id="cni-란">CNI 란?</h2>
<blockquote>
<p>CNI(Container Network Interface)는 컨테이너 네트워크를 관리하기 위한 표준 인터페이스를 정의한 사양입니다.</p>
</blockquote>
<h3 id="cni-역할">CNI 역할</h3>
<ul>
<li>컨테이너 네트워크 설정 : 컨테이너 생성 시 네트워크 인터페이스를 추가하고 IP 주소 및 라우팅 설정</li>
<li>컨테이너 네트워크 삭제 : 컨테이너 종료 시 네트워크 설정 제거</li>
<li>네트워크 플러그인 관리 : 다양한 네트워크 플러그인과의 호환성 제공</li>
</ul>
<h3 id="쿠버네티스에서-cni">쿠버네티스에서 CNI</h3>
<ul>
<li>쿠버네티스는 CNI를 통해 Pod 간 통신을 설정합니다.</li>
<li>Pod는 기본적으로 오버레이 네트워크를 사용하여 클러스터 내 다른 노드와 통신합니다.</li>
<li>CNI 플러그인을 설치해야 Pod 간의 통신과 네트워킹이 제대로 작동합니다.</li>
</ul>
<h3 id="cni의-주요-구성-요소">CNI의 주요 구성 요소</h3>
<p>CNI 플러그인 :</p>
<p>네트워크를 실제로 구성하는 도구.</p>
<ul>
<li>Calico: 네트워크 정책과 보안을 중점으로 둔 플러그인.</li>
<li>Flannel: 간단하고 빠른 네트워크 플러그인.</li>
<li>Weave Net: 자동화된 클러스터 네트워크 생성.</li>
</ul>
<p>CNI 사양:</p>
<ul>
<li>플러그인은 반드시 CNI 사양을 준수해야 하며, 네트워크 인터페이스 추가/삭제를 위한 명령을 구현.</li>
</ul>
<p>CNI 실행 바이너리:</p>
<ul>
<li>컨테이너 런타임(Docker, containerd)에서 CNI 플러그인을 호출하여 네트워크 설정.</li>
</ul>
<hr>
<h2 id="쿠버네티스에서-컨테이너-동작-flow">쿠버네티스에서 컨테이너 동작 Flow</h2>
<h3 id="1-사용자-요청---api-server">1. 사용자 요청 -&gt; API Server</h3>
<ol>
<li><p>사용자가 kubectl 명령어 또는 API 요청을 통해 쿠버네티스 클러스터에 작업 요청</p>
<ul>
<li>요청 내용은 YAML/JSON 형식으로 정의</li>
</ul>
</li>
<li><p>API Server가 요청을 받아들이고, 요청을 etcd(분산 저장소)에 저장.</p>
<ul>
<li>API Server는 쿠버네티스의 중앙 컨트롤 인터페이스 역할.</li>
</ul>
</li>
</ol>
<h3 id="2-스케줄링-단계">2. 스케줄링 단계</h3>
<ol>
<li><p>Scheduler가 클러스터의 모든 워커 노드를 확인하여 적합한 노드를 선택.</p>
<ul>
<li>리소스상태, 태그, 우선 순위 등 기준으로 노드 결정.</li>
</ul>
</li>
<li><p>선택된 노드에 Pod가 배치됨.</p>
</li>
</ol>
<h3 id="3-컨테이너-생성-및-실행">3. 컨테이너 생성 및 실행</h3>
<ol>
<li><p>워커 노드의 kubelet이 API Server로 부터 작업 명령을 받음.</p>
<ul>
<li>kubelet은 각 워커 노드에서 실행되는 에이전트로, Pod 관리</li>
</ul>
</li>
<li><p>kubelet이 다음 작업 수행 : </p>
<ul>
<li>Pod 사양 확인 : 생성할 컨테이너 이미지, 리소스 요청, 볼륨 마운트 정보 확인.</li>
<li>Container Runtime 호출 : Docker 또는 containerd와 같은 런타임을 호출하여 컨테이너 실행</li>
</ul>
</li>
<li><p>컨테이너 생성 및 네트워크 설정 : </p>
<ul>
<li>CNI 플러그인이 호출되어 네트워크 인터페이스를 설정.</li>
<li>컨테이너가 지정된 IP를 할당받고, 네트워크 경로 설정.</li>
</ul>
</li>
</ol>
<h3 id="4-pod의-상태-확인-및-유지">4. Pod의 상태 확인 및 유지</h3>
<ol>
<li>컨테이너가 실행되면, Kubelet은 Pod의 상태를 지속적으로 모니터링.</li>
</ol>
<ul>
<li><p>Probe(헬스체크)로 상태 확인:</p>
<p>  Liveness Probe: 컨테이너가 살아 있는지 확인.
  Readiness Probe: 컨테이너가 요청을 처리할 준비가 되었는지 확인.</p>
</li>
<li><p>만약 컨테이너가 종료되거나 실패하면:</p>
<p>  Restart Policy에 따라 재시작.
  문제가 지속될 경우, Scheduler가 다른 노드에 Pod를 재배치.</p>
<h3 id="5-서비스네트워크-연결">5. 서비스(네트워크) 연결</h3>
</li>
</ul>
<ol>
<li><p>Service 생성 및 연결 :</p>
<ul>
<li>Pod가 외부 트래픽을 처리할 수 있도록 Service 객체를 생성.</li>
<li>ClusterIP, NodePort, LoadBalancer 등 다양한 타입 사용 가능.</li>
</ul>
</li>
<li><p>DNS 서비스:</p>
<ul>
<li>쿠버네티스 내에서 CoreDNS를 사용해 Pod 이름으로 통신 가능.</li>
</ul>
</li>
</ol>
<ol start="3">
<li>Ingress 설정(선택 사항):<ul>
<li>외부 트래픽을 특정 Service로 라우팅하기 위해 Ingress 리소스를 설정.</li>
</ul>
</li>
</ol>
<h3 id="6-로깅-및-모니터링">6. 로깅 및 모니터링</h3>
<ol>
<li><p>실행 중인 컨테이너의 로그 및 메트릭 수집:</p>
<ul>
<li>kubectl logs로 Pod 로그 확인.</li>
</ul>
</li>
<li><p>모니터링 툴을 통해 상태를 실시간으로 확인:</p>
<ul>
<li>Prometheus + Grafana.</li>
<li>쿠버네티스 이벤트 추적.</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kubernetes] - Longhorn]]></title>
            <link>https://velog.io/@gojol_devops/Longhorn</link>
            <guid>https://velog.io/@gojol_devops/Longhorn</guid>
            <pubDate>Fri, 13 Dec 2024 06:11:46 GMT</pubDate>
            <description><![CDATA[<h1 id="longhorn-이란">Longhorn 이란,,</h1>
<p>kubernetes 클러스터를 위해 Rancher labs에서 개발한 가볍고 안정적이며 강력한 분산 블록 스토리지 시스템 입니다.</p>
<p>longhorn은 컨테이너와 마이크로 서비스를 사용하여 분산 블록 스토리지를 구현하며, 각 block device volume에 대한 전용 longhorn Engine를 만들고 다수의 노드에 저장된 여러 복제본에 걸쳐 volume을 복제하여 동기화 합니다. 
Longhorn Engine(storage controller)와 복제본은 쿠버네티스를 사용하여 자체적으로 오케스트레이션 됩니다.</p>
<hr>
<blockquote>
<p>Longhorn을 사용하면 다음과 같은 작업을 수행할 수 있습니다:</p>
</blockquote>
<p>Kubernetes 클러스터에서 분산 상태 저장 애플리케이션을 위한 영구 스토리지로 Longhorn 볼륨을 사용할 수 있습니다.
블록 스토리지를 Longhorn 볼륨으로 분할하여 클라우드 제공업체와 상관없이 Kubernetes 볼륨을 사용할 수 있습니다.
블록 스토리지를 여러 노드와 데이터 센터에 걸쳐 복제하여 가용성을 높일 수 있습니다.
NFS나 AWS S3 같은 외부 스토리지에 백업 데이터를 저장할 수 있습니다.
크로스 클러스터 재해 복구 볼륨을 생성하여 주요 Kubernetes 클러스터의 데이터를 두 번째 Kubernetes 클러스터의 백업에서 신속히 복구할 수 있습니다.
볼륨의 주기적인 스냅샷을 예약하고 NFS 또는 S3 호환 보조 스토리지에 주기적인 백업을 예약할 수 있습니다.
백업에서 볼륨을 복구할 수 있습니다.
영구 볼륨을 중단하지 않고 Longhorn을 업그레이드할 수 있습니다.
Longhorn은 독립형 UI를 제공하며, Helm, kubectl 또는 Rancher 앱 카탈로그를 통해 설치할 수 있습니다.</p>
<hr>
<h1 id="longhorn-architecture">Longhorn Architecture</h1>
<p>Longhorn은 Kubernetes에서 실행되는 분산 블록 스토리지 시스템으로, 애플리케이션에 높은 가용성과 안정성을 제공하기 위해 설계되었습니다. 각 요소는 컨테이너 기반으로 동작하며 Kubernetes와 깊은 통합을 이루고 있습니다.</p>
<h3 id="longhorn-enginestorage-controller">Longhorn Engine(Storage Controller)</h3>
<p>Longhorn Engine은 <strong><em>data plane</em></strong>에 해당 하는 Storage Controller이며 항상 Longhorn 볼륨을 사용하는 Pod와 동일한 노드에서 실행 됩니다. </p>
<p>다중 노드에 저장된 여러 복제복(replica)에서 볼륨을 동시에 복제하며, Engine과 복제본들(replicas)은 쿠버네티스에 의해 오케스트레이션 됩니다.</p>
<blockquote>
<p>특징</p>
</blockquote>
<ul>
<li>각 Longhorn 볼륨에 대해 실행되는 컨트롤러입니다.</li>
<li>실제 데이터 읽기/쓰기 요청을 처리합니다.</li>
<li>데이터의 복제본 간 동기화를 담당합니다.</li>
<li>장애 발생 시 복제본 재구성 및 복구 작업을 수행합니다.</li>
</ul>
<p>아래의 아키텍처를 보면,</p>
<ul>
<li>각 Pod와 Longhorn 볼륨들이 3개의 인스턴스와 함께 있으며,</li>
<li>각 볼륨은 Longhorn Engine이라는 Storage Controller가 Linux 프로세스로 실행 됩니다.</li>
<li>각 Longhorn 볼륨에는 두 개의 복제본(replica)이 있으며 각 복제본(replica) 또한 Linux 프로세스 입니다.</li>
<li>아키텍처의 화살표는 볼륨 → Engine → 복제본 → 인스턴스(노드) 및 디스크 간의 read/write 데이터 흐름 입니다.</li>
<li>각 볼륨들은 개별적인 Longhorn Engine이 생성 되기 때문에 하나의 Engine(또는 storage controller)에 장애가 발생하더라도 다른 볼륨의 기능에는 영향을 미치지 않습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/gojol_devops/post/ce1c48d1-ff22-4d95-9183-3b3f4c514434/image.svg" alt=""></p>
<hr>
<h3 id="longhorn-manager">Longhorn Manager</h3>
<p>Longhorn Manager는 <strong><em>control plane</em></strong>의 역할을 하며, Longhorn API를 사용하여 volume 생성 요청에 따른 Engine을 생성 하고 volume을 관리 등의 작업을 수행 합니다.</p>
<blockquote>
<p>특징</p>
</blockquote>
<ul>
<li>Longhorn의 핵심 컨트롤러 역할을 합니다.</li>
<li>각 Kubernetes 노드에서 실행되며, 볼륨의 상태를 모니터링하고 필요한 작업(예: 복제본 생성/삭제, 백업 관리)을 수행합니다.</li>
<li>사용자와의 인터페이스 역할을 하며, Longhorn UI 및 CLI를 통해 요청을 처리합니다.</li>
</ul>
<p>아래의 아키텍처를 보면,</p>
<ul>
<li><em>DaemonSet</em>으로 각 nodes에 Longhorn Manager Pod 있으며,</li>
<li>Kubernetes 클러스터에서 볼륨 생성 및 관리를 담당하고, UI와 쿠버네티스 볼륨 plugin에서 API 호출을 처리 합니다.</li>
<li>Longhorn Manager에 볼륨 생성을 요청하면 볼륨이 연결된 인스턴스(노드)에 Longhorn Engine을 생성하고 복제본(replica)이 배치될 각 노드에 복제본(replica)을 생성하게 됩니다.</li>
<li>스토리지의 최대 가용성을 보장하려면 복제본(replica)은 전용 호스트에 배치하는 것을 권장합니다.
<img src="https://velog.velcdn.com/images/gojol_devops/post/16106440-8e73-4237-ad16-1528ef543869/image.webp" alt=""></li>
</ul>
<hr>
<h2 id="replicas의-읽기쓰기-작동-방식">Replicas의 읽기/쓰기 작동 방식</h2>
<p>Longhorn의 복제본(replica)으로 부터 데이터를 읽기/쓰기에 대한 작동 방식을 알아 보겠습니다.</p>
<p>데이터를 복제본에서 읽을 때 라이브 데이터(Live Data)가 있으면 해당 데이터를 사용하고, 만약 데이터가 없을 경우 최신 snapshot에서 데이터를 가져오게 됩니다.</p>
<p>최신 snapshot에도 데이터가 없다면 다음으로 오래된 snapshot으로 부터 읽는 식으로 데이터를 가져오게 됩니다.</p>
<blockquote>
<p>특징</p>
</blockquote>
<ul>
<li>데이터를 저장하는 실제 스토리지 유닛입니다.</li>
<li>각 볼륨의 복제본은 Kubernetes 노드의 디스크에 저장됩니다.</li>
<li>여러 노드에 분산되어 데이터 복제 및 고가용성을 제공합니다.</li>
</ul>
<h3 id="읽기-인덱스가-가장-최근-데이터를-보유하고-있는-스냅샷을-추적하는-방법">읽기 인덱스가 가장 최근 데이터를 보유하고 있는 스냅샷을 추적하는 방법</h3>
<p><img src="https://velog.velcdn.com/images/gojol_devops/post/70a3bc46-0038-4872-974d-b84db4d95d7b/image.png" alt=""></p>
<table>
<thead>
<tr>
<th>인덱스</th>
<th>읽기 데이터 출처</th>
</tr>
</thead>
<tbody><tr>
<td>0</td>
<td>최신 스냅샷</td>
</tr>
<tr>
<td>1</td>
<td>라이브 데이터</td>
</tr>
<tr>
<td>2</td>
<td>가장 오래된 스냅샷</td>
</tr>
<tr>
<td>3</td>
<td>가장 오래된 스냅샷</td>
</tr>
<tr>
<td>4</td>
<td>가장 오래된 스냅샷</td>
</tr>
<tr>
<td>5</td>
<td>라이브 데이터</td>
</tr>
<tr>
<td>6</td>
<td>라이브 데이터</td>
</tr>
<tr>
<td>7</td>
<td>라이브 데이터</td>
</tr>
</tbody></table>
<hr>
<p>참고 : 
<a href="https://longhorn.io/">https://longhorn.io/</a>
<a href="https://awx.notion.site/Introduction-to-Longhorn-974fcd62047541429bbe3d5aed1c32e2">https://awx.notion.site/Introduction-to-Longhorn-974fcd62047541429bbe3d5aed1c32e2</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kubernetes] - RKE2 설치]]></title>
            <link>https://velog.io/@gojol_devops/RKE2-%EC%84%A4%EC%B9%98</link>
            <guid>https://velog.io/@gojol_devops/RKE2-%EC%84%A4%EC%B9%98</guid>
            <pubDate>Thu, 05 Dec 2024 06:55:51 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>REK2 설치 과정은 루트 사용자나 sudo를 사용해야합니다.</p>
</blockquote>
<h1 id="server-노드">Server 노드</h1>
<p>RKE2는 systemd 기반 시스템에 서비스로 설치하는 편리한 방법인 설치 스크립트를 제공합니다.
이 스크립트는 <a href="https://get.rke2.io">https://get.rke2.io</a> 에서 제공됩니다.</p>
<ol>
<li><pre><code>curl -sfL https://get.rke2.io | sh -
</code></pre></li>
</ol>
<hr>
<ol start="2">
<li><pre><code>systemctl enable rke2-server.service
</code></pre></li>
</ol>
<hr>
<ol start="3">
<li><pre><code>systemctl start rke2-server.service
</code></pre></li>
</ol>
<hr>
<p>RKE2 서비스 실행 이후 서비스가 올라가기 까지 잠깐의 시간이 소요됩니다.</p>
<pre><code>systemctl status rke2-server.service</code></pre><p>status 명령어를 사용해 active 상태인지 확인합니다
<img src="https://velog.velcdn.com/images/gojol_devops/post/3181a4d3-b68e-48c2-b68d-d180f7291047/image.png" alt=""></p>
<h1 id="worker-노드">Worker 노드</h1>
<ol>
<li><pre><code>curl -sfL https://get.rke2.io | INSTALL_RKE2_TYPE=&quot;agent&quot; sh -
</code></pre></li>
</ol>
<hr>
<ol start="2">
<li><pre><code>systemctl enable rke2-agent.service</code></pre></li>
</ol>
<hr>
<ol start="3">
<li><pre><code>mkdir -p /etc/rancher/rke2/
vim /etc/rancher/rke2/config.yaml
</code></pre></li>
</ol>
<p>yaml 내용
server: https://<server-ip>:9345
token: <server node token></p>
<pre><code>
&gt; token 값은 master 노드에서 찾아 볼 수 있습니다.
</code></pre><p>cat /var/lib/rancher/rke2/server/node-token</p>
<pre><code>
4. ```
systemctl start rke2-agnet.service

이후 status 명령어로 active 상태인지 확인합니다

![](https://velog.velcdn.com/images/gojol_devops/post/d0f453b4-30cf-44c5-aa87-0aa0f2bc3f1f/image.png)


# Kubectl

Master 노드에서 kubectl 명령어를 통해 Master 노드와 Worker 노드가 쿠버네티스 클러스터에 올라갔는지 확인 하면됩니다.
ROLES에 &lt;none&gt; 으로 표기된곳이 Worker 노드 입니다


![](https://velog.velcdn.com/images/gojol_devops/post/aa291949-a0cd-453d-8550-60c93a1aa9b7/image.png)



---
## 트러블 슈팅

저는 Vmfusion에 리눅스을 올려 테스트를 진행하였습니다.

그래서 첫번째 vm을 생성하고 복제를 하여 두개의 vm으로 테스트 진행을 하였는데요.

worker 노드에서 master에 403에러가 발생하는것을 확인하였습니다.

문제점으로는 vm을 복제 후 hostname을 변경하지 않아

같은 hostname이였기에 연결이 되지않았습니다.

이러한 문제점으로 같은 hostname이 있을경우 연결이 되지 않는다는 점을 알게되었습니다.
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Kubernetes] -  kubectl 명령어 정리]]></title>
            <link>https://velog.io/@gojol_devops/Kubernetes-kubectl-%EB%AA%85%EB%A0%B9%EC%96%B4-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@gojol_devops/Kubernetes-kubectl-%EB%AA%85%EB%A0%B9%EC%96%B4-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Tue, 03 Dec 2024 07:07:47 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/gojol_devops/post/6c0704cd-6f52-4277-adeb-520d0ab5316e/image.jpg" alt=""></p>
<h1 id="1클러스터-상태-확인-명령어">1.클러스터 상태 확인 명령어</h1>
<h3 id="노드-상태-확인">노드 상태 확인</h3>
<pre><code>#클러스터 내 노드의 상태 및 역할 확인.
kubectl get nodes

출력 예시 :
NAME           STATUS   ROLES           AGE   VERSION
node-1         Ready    control-plane   10d   v1.27.0
node-2         Ready    worker          8d    v1.27.0
</code></pre><h3 id="클러스터-정보-확인">클러스터 정보 확인</h3>
<pre><code>#클러스터의 API 서버 및 DNS 정보 확인
kubectl cluster-info</code></pre><hr>
<h1 id="2-네임스페이스-관리">2. 네임스페이스 관리</h1>
<h3 id="네임스페이스-목록확인">네임스페이스 목록확인</h3>
<pre><code>kubectl get namespaces</code></pre><h3 id="특정-네임스페이스에서-작업">특정 네임스페이스에서 작업</h3>
<pre><code>kubectl get pods -n &lt;namespace&gt;</code></pre><hr>
<h1 id="3-리소스-조회">3. 리소스 조회</h1>
<h3 id="pod-조회">Pod 조회</h3>
<pre><code>kubectl get pods
kubectl get pods -o wide     #추가 정보 포함
kubectl get pods -A         #모든 네임스페이스의 Pod 조회</code></pre><h3 id="deployment-조회">Deployment 조회</h3>
<pre><code>kubectl get deployments</code></pre><h3 id="service-조회">Service 조회</h3>
<pre><code>kubectl get services</code></pre><h3 id="configmap-또는-secret-조회">ConfigMap 또는 Secret 조회</h3>
<pre><code>kubectl get configmaps

kubectl get secrets</code></pre><h3 id="리소스의-상세-정보-조회">리소스의 상세 정보 조회</h3>
<pre><code>kubectl describe &lt;resource-type&gt; &lt;resource-name&gt;</code></pre><hr>
<h1 id="4-리소스-생성">4. 리소스 생성</h1>
<h3 id="리소스-적용">리소스 적용</h3>
<pre><code>kubectl apply -f &lt;file.yaml&gt;</code></pre><h3 id="간단한-리소스-생성">간단한 리소스 생성</h3>
<pre><code>kubectl run &lt;pod-name&gt; --image&lt;image-name&gt;

#예 : kubectl run nginx-pod --image=nginx</code></pre><hr>
<h1 id="5-리소스-수정">5. 리소스 수정</h1>
<h3 id="리소스-직접-수정">리소스 직접 수정</h3>
<pre><code>kubectl edit &lt;resource-type&gt; &lt;resource-name&gt;</code></pre><h3 id="리소스-재배포">리소스 재배포</h3>
<pre><code>kubectl rollout restart deployment &lt;deployment-name&gt;</code></pre><hr>
<h1 id="6-리소스-삭제">6. 리소스 삭제</h1>
<h3 id="리소스-삭제">리소스 삭제</h3>
<pre><code>kubectl delete &lt;resource-type&gt; &lt;resource-name&gt;</code></pre><h3 id="yaml-파일로-리소스-삭제">YAML 파일로 리소스 삭제</h3>
<pre><code>kubectl delete -f &lt;file.yaml&gt;</code></pre><h3 id="모든-리소스-삭제">모든 리소스 삭제</h3>
<pre><code>#현재 네임스페이스의 모든 리소스 삭제

kubectl delete all --all
</code></pre><h1 id="7-로그-및-디버깅">7. 로그 및 디버깅</h1>
<h3 id="pod-로그-확인">Pod 로그 확인</h3>
<pre><code>kubectl logs &lt;pod-name&gt;
kubectl logs &lt;pod-name&gt; -c &lt;container-name&gt; #특정 컨테이너 로그</code></pre><h3 id="pod-상태-확인">Pod 상태 확인</h3>
<pre><code>kubectl describe pod &lt;pod-name&gt;</code></pre><h3 id="pod에-접속">Pod에 접속</h3>
<pre><code>kubectl exec -it &lt;pod-name&gt; -- /bin/bash</code></pre><hr>
<h1 id="8-리소스-이벤트-확인">8. 리소스 이벤트 확인</h1>
<h3 id="리소스의-최근-이벤트">리소스의 최근 이벤트</h3>
<pre><code>kubectl get events</code></pre><h3 id="pod-또는-다른-리소스의-상세-이벤트">Pod 또는 다른 리소스의 상세 이벤트</h3>
<pre><code>kubectl describe pod &lt;pod-name&gt;</code></pre><hr>
<h1 id="9-yaml-템플릿-생성">9. YAML 템플릿 생성</h1>
<h3 id="리소스-yaml-템플릿-생성">리소스 YAML 템플릿 생성</h3>
<pre><code>kubectl create deployment &lt;deployment-name&gt; --image=&lt;image-name&gt; --dry-run=client -o yaml</code></pre><hr>
<h1 id="10-버전-및-설정-확인">10. 버전 및 설정 확인</h1>
<h3 id="클러스터와-클라이언트-버전-확인">클러스터와 클라이언트 버전 확인</h3>
<pre><code>kubectl version --short</code></pre><h3 id="현재-컨텍스트-확인">현재 컨텍스트 확인</h3>
<pre><code>kubectl config current-context</code></pre><h3 id="컨텍스트-목록-확인">컨텍스트 목록 확인</h3>
<pre><code>kubectl config get-contexts</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Kubernetes RKE1 vs RKE2]]></title>
            <link>https://velog.io/@gojol_devops/Kubernetes-RKE1-vs-RKE2</link>
            <guid>https://velog.io/@gojol_devops/Kubernetes-RKE1-vs-RKE2</guid>
            <pubDate>Mon, 02 Dec 2024 07:23:32 GMT</pubDate>
            <description><![CDATA[<p>MSA 아키텍쳐 설계 하면서 엔진에 대해 고민해보았습니다.</p>
<p>크게 RKE1과 RKE2 중 고민하게 되었습니다.</p>
<p>RKE1(Rancher Kubernetes Engine)와 RKE2는 Rancher에서 제공하는 Kubernetes 클러스터 관리 솔루션으로, 각각 다른 목적과 기술 스택을 가지고 있습니다. 다음은 두 엔진의 주요 차이점과, 특징, 그리고 어떤 사항에서 적합한지 설명하겠습니다.</p>
<blockquote>
<p>Rancher 는 컨테이너 관리 플랫폼으로 다양한 Kubernetes 클러스터를 효율적으로 배포, 관리, 모니터링을할 수 있는 도구 입니다.</p>
</blockquote>
<h1 id="rke1">RKE1</h1>
<ul>
<li>RKE1 이란,
  기존 Rancher 사용자를 위한 Kubernetes 클러스터 설치 및 관리 도구 입니다. 기존 Docker 컨테이너 런타임을 기반으로 클러스터를 구성합니다.</li>
</ul>
<ul>
<li>특징 <ol>
<li>Docker 기반 : RKE1은 노드에서 Kubernetes를 실행하기 위해 Docker를 필수로 사용합니다.</li>
<li>유연한 설치 : YAML 파일을 사용하여 손쉽게 클러스터 설정가능</li>
<li>경량화 : 비교적 간단하고 가벼운 설치 과정</li>
<li>지원 : 안정성과 성숙도가 높아 많은 기업에서 사용 중</li>
</ol>
</li>
</ul>
<ul>
<li>한계<ol>
<li>Docker 의존성이 높아 향후 Kubernetes의 방향성과 다소 상충될 수 있습니다</li>
<li><strong>CNCF</strong> (컨테이너 기술을 발전시키고 기술 산업의 진화를 지원하기 위해 설립된 프로젝트) 가 더이상 Docker를 기본 컨테이너 런타임으로 추천하지 않습니다.</li>
</ol>
</li>
</ul>
<h1 id="rke2">RKE2</h1>
<ul>
<li>RKE2 이란, 
  Kubernetes의 최신 요구사항과 보안 표준을 충족하기 위해 설계된 RKE의 차세대 버전입니다. RKE1과 달리 K3s의 기술 스택을 기반으로 구축되었습니다.</li>
</ul>
<ul>
<li><p>특징</p>
<ol>
<li>컨테이너 런타임 변경: RKE2는 Docker 대신 Containerd를 기본 컨테이너 런타임으로 사용합니다.</li>
<li>보안 강화: FIPS(Federal Information Processing Standards)를 준수하는 구성 옵션 제공합니다</li>
<li>이식성: RKE2는 클라우드 네이티브 환경에 최적화되어 더 나은 성능을 제공합니다.</li>
<li>Kubernetes 방향성과 일치: 최신 Kubernetes 트렌드와 아키텍처 설계에 맞춰 개발.</li>
</ol>
</li>
<li><p>한계</p>
<ol>
<li>RKE1보다 상대적으로 복잡한 설정 과정.</li>
<li>기존 시스템을 RKE2로 마이그레이션할 때 추가 학습 곡선이 필요.</li>
</ol>
</li>
</ul>
<hr>
<h2 id="어떤-엔진을-선택해야-할까">어떤 엔진을 선택해야 할까?</h2>
<p><strong>RKE1이 적합한 경우</strong></p>
<ol>
<li>기존 인프라가 Docker 기반으로 운영되고 있다면.</li>
<li>빠르게 Kubernetes 클러스터를 설치하고 운영하려는 경우.</li>
<li>온프레미스 환경에서 가볍고 간단한 클러스터를 원하는 경우.</li>
</ol>
<p><strong>RKE2가 적합한 경우</strong></p>
<ol>
<li>보안이 중요한 환경(예: 금융, 공공)에서 운영해야 하는 경우.</li>
<li>최신 Kubernetes 트렌드와 기능을 활용하고자 하는 경우.</li>
<li>컨테이너 런타임 표준(Containerd)으로의 전환을 고려하고 있다면.</li>
<li>클라우드 네이티브 환경에서 확장 가능한 클러스터를 운영하려는 경우.</li>
</ol>
<hr>
<p>저희 프로젝트는 장기 프로젝트로 지속적인 업데이트를 진행 할 것입니다.</p>
<p>따라서 장기적인 관점에서 Kubernetes 생태계가 Containerd와 최신 보안 표준으로 전환 되고 있으므로 RKE2가 더 유리하다고 생각합니다.</p>
<hr>
<h1 id="rke2의-mastercontrol-plane-와-slave-worker">RKE2의 Master(Control Plane) 와 Slave (Worker)</h1>
<h2 id="1-master의-역할">1. Master의 역할</h2>
<ul>
<li><p>클러스터 상태 관리 및 스케줄링을 담당.</p>
</li>
<li><p>주요 구성 요소 :</p>
<ul>
<li>Scheduler : 새 워크로드를 적합한 워커 노드에 배치</li>
<li>API Server : 클러스터에 대한 모든 요청을 처리.</li>
<li>Controller Manager : 클러스터 상태를 원하는 상태로 유지</li>
<li>etcd : 클러스터의 상태 데이터 저장</li>
</ul>
</li>
</ul>
<h2 id="2-slave-worker의-역할">2. Slave (Worker)의 역할</h2>
<ul>
<li><p>Control Plane 에서 지정한 워크로드를 실행하는 역할.</p>
</li>
<li><p>주요 구성 요소 : </p>
<ul>
<li>kubelet : Pod의 생명 주기를 관리.</li>
<li>kube - proxy : 클러스터 네트워크 통신 관리.</li>
<li>containerd : Pod 내 컨테이너 실행.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring + SSE]]></title>
            <link>https://velog.io/@gojol_devops/Spring-SSE</link>
            <guid>https://velog.io/@gojol_devops/Spring-SSE</guid>
            <pubDate>Fri, 29 Nov 2024 08:52:45 GMT</pubDate>
            <description><![CDATA[<p>주식관련 메신저 프로젝트를 진행하면서, 실시간 알림기능을 맡게 되었습니다.</p>
<p>현제 구상한 알림 기능으로는 내가 즐겨찾기한 주식이 변동할때 알림기능과</p>
<p>톡방에서 상대방이 메세지를 보냈을때 실시간으로 알림이 오는 기능입니다.</p>
<p>그래서 저는 실시간 알림 기능에 대해서 찾아봤습니다.</p>
<p>우선, HTTP 프로토콜에서는 client에서 요청이 있어야 server에서 응답을 보낼 수 있습니다.
client에 요청없이 server에서는 응답을 보내는 것은 불가능합니다.</p>
<p>실시간 통신에 대해 찾아보면서</p>
<p>웹 소켓에 대해서 알게 되었습니다.</p>
<h1 id="웹-소켓web-socket">웹 소켓(Web Socket)</h1>
<p>웹 소켓이란 두 프로그램 간의 메시지 교환을 위한 통신 방법입니다.</p>
<h3 id="웹-소켓의-특징">웹 소켓의 특징</h3>
<ul>
<li><p>양방향 통신(Full-Duplex)</p>
</li>
<li><p>실시간 네트워킹</p>
</li>
<li><p>http 프로토콜이 아닌 ws 프로토콜 사용</p>
</li>
</ul>
<p>웹 소켓의 특징으로 실시간 채팅알림, 또는 실시간으로 변화하는 주식장에서 사용자가 선택한 매수/매도 타이밍에 알림에 대해 적합하다고 생각하였습니다.</p>
<p>하지만, 이러한 장점이 있는 웹 소켓을 선택하지 않은 이유로는 
저는 실시간 채팅을 맡은게 아닌 알림 기능만 맡았기 때문에 굳이 2개의 웹 소켓을 열 필요가 없다고 생각했습니다.</p>
<p>또한 웹 소켓은 한번 연결되면 별도의 에러나, 지시가 없는한 지속적으로 연결을 유지하므로 서버의 부하가 증가할 수 있기 때문입니다.</p>
<h1 id="sseserver-sent-events">SSE(Server Sent Events)</h1>
<p>SSE는 단방향 통신이며 클리이언트의 별도 추가요청 없이 서버에서 업데이트를 스트리밍할 수 있다는 특징을 가집니다.</p>
<h3 id="sse-특징">SSE 특징</h3>
<ul>
<li><p>서버에서 실시간으로 이벤트 전송</p>
</li>
<li><p>polling 기법보다 적은 통신 횟수</p>
</li>
<li><p>새로운 프로토콜을 익힐 필요가 없음</p>
</li>
<li><p>서버 측에서의 단방향 통신</p>
</li>
</ul>
<h2 id="sse-통신-과정">SSE 통신 과정</h2>
<h4 id="1-sse-구독-신청">1. SSE 구독 신청</h4>
<p>클라이언트가 서버와의 연결을 요청하는 것을 구독이라는 행위로 나타낼 수 있다. 서버의 변화를 구독하여 실시간으로 관찰하고 싶다는 의미이다.</p>
<pre><code class="language-java">
    @GetMapping(path = &quot;/emitter&quot;, produces = MediaType.TEXT_EVENT_STREAM_VALUE)
   public SseEmitter subscribe() {

    }</code></pre>
<p>컨트롤러에는 produces로 Content-Type을 <strong>MediaType.TEXT_EVENTSTREAM_VALUE</strong> 으로 지정하였다. 
이렇게 지정하면 서버에서 응답 패킷의 헤더의 Content-Type이 text/event-stream으로 되고 텍스트 데이터를 연속해서 보낼 수 있다.</p>
<h4 id="2-sse-연결-수립">2. SSE 연결 수립</h4>
<ul>
<li>SSeEmitter 객체 생성
  가장 먼저 클라이언트의 요청에 따라 서버에서는 통신 객체인 SSeEitter를 생성한다. 생성할때 만료 시간을 입력할 수 있다. 만료시간이 너무 길면 연결 관리를 해줘야하고 짧으면 재연결 요청이 잦게 일어나므로 적절하게 설정 해야한다.</li>
</ul>
<pre><code class="language-java">            SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
</code></pre>
<ul>
<li>더미 데이터 전송
  서버와의 연결을 맺을때 더미 데이터를 넘겨줘야 한다. 그렇지 않고 데이터를 하나도 전송하지 않으면 재연결 요청시 503 Service Unavaliable 에러가 발생한다. 따라서 이를 방지하기 위해 Dummy 데이터를 보낸다.</li>
</ul>
<pre><code class="language-java">   //주기적으로 이벤트를 보내는 예시 (필요하지 않다면 삭제 가능)
    @Scheduled(fixedRate = 1000)
    public void sendEvents() {
       for (SseEmitter emitter : emitters) {
            try {
                emitter.send(&quot;Hello, World!&quot;);
           } catch (IOException e) {
               emitter.complete();
                emitters.remove(emitter);
           }
       }
    }</code></pre>
<ul>
<li>Emitter 객체 관리
  Emitter를 저장하기 위해 Spring Data JPA를 사용해서 물리적으로 저장해도 된다. 하지만 HashMap을 사용한 케이스가 많아 HashMap을 사용했다. HashMap을 사용하면 데이터 저장 위치를 해시함수를 통해 바로 알 수 있어 검색이 빠르다. 일반 HashMap은 Thread-safe 하지 않으므로 ConcurrentHashMap을 사용한다. 멀티 쓰레드 환경에서 데이터를 관리하기 위해 동기화 과정이 필요하다. 이를 위해 쓰레드가 접근하는 Map에 Lock을 걸어야하는데 ConcurrentHashMap 에서는 Bucket 단위로 관리가 되어 오버헤드를 줄일 수 있다는 장점이 있다.</li>
</ul>
<pre><code class="language-java">    private final List&lt;SseEmitter&gt; emitters = new CopyOnWriteArrayList&lt;&gt;();</code></pre>
<h4 id="3-클라이언트에게-메세지-보내기">3. 클라이언트에게 메세지 보내기</h4>
<p>마지막으로 연결되어있는 클라이언트에게 메세지를 전달하는 컨트롤러를 만들었다.
sendData에 전달할 message를 인자로 주어 메세지를 전달한다. </p>
<pre><code class="language-java">    // POST 요청을 통해 데이터를 수신하고, 이를 SSE로 클라이언트에 전달
    @PostMapping(&quot;/send&quot;)
    public void sendData(@RequestBody String message) {
        // 받은 데이터를 모든 연결된 클라이언트에 전송
        sseService.sendMessageToClients(message);
    }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[mac] Intellij - node.js Project setting]]></title>
            <link>https://velog.io/@gojol_devops/mac-Intellij-node.js-Project-setting</link>
            <guid>https://velog.io/@gojol_devops/mac-Intellij-node.js-Project-setting</guid>
            <pubDate>Mon, 04 Nov 2024 09:52:53 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h1 id="plug---in-설치">Plug - in 설치</h1>
</blockquote>
<h2 id="mac-환경에서-설정되었습니다">mac 환경에서 설정되었습니다.</h2>
<p>인텔리제이 에서는 Node.js 개발을 위한 플러그인을 설치해야합니다.</p>
<img src="https://velog.velcdn.com/images/gojol_devops/post/b0aaacce-6624-49dc-a882-d02b8d057eb4/image.png" width="50%" height="n%">


<blockquote>
<h1 id="nodejs-설치">node.js 설치</h1>
</blockquote>
<p><a href="https://nodejs.org/en">node.js</a> 공식 사이트에 접속하여 설치하는 방법이 있습니다.</p>
<p>저는 <a href="https://brew.sh/">homebrew</a> 를 통해서 node를 설치하였습니다.</p>
<pre><code>brew install node</code></pre><p>이후 node가 잘 설치 되었는지 확인하기 위해</p>
<pre><code>node -v
npm -v</code></pre><p>버전이 나온다면 맞게 설치된것입니다.</p>
<blockquote>
<h1 id="프로젝트-생성">프로젝트 생성</h1>
</blockquote>
<p>node.js 까지 설치를 끝냈다면, 프로젝트를 생성해야겠죠,<img src="" alt=""></p>
<h3 id="새-프로젝트-생성">새 프로젝트 생성</h3>
<p><img src="https://velog.velcdn.com/images/gojol_devops/post/c4b5fa9d-3db8-429e-9d71-34848014865a/image.png
" width="50%" height="n%"></p>
<h3 id="왼쪽에-express를-선택하고-프로젝트명-위치를-설정해줍니다">왼쪽에 express를 선택하고 프로젝트명, 위치를 설정해줍니다.</h3>
<h3 id="이때-엔진표시-view-engine-는-ejs를-선택합니다">이때, 엔진표시 (view Engine) 는 EJS를 선택합니다</h3>
<p>EJS : HTML 내에 JavaScript를 내장하여 동적 웹 페이지를 쉽게 만들 수 있게 해줍니다.
<img src="https://velog.velcdn.com/images/gojol_devops/post/6393a9d8-7d89-4e3e-b75f-60819e73e206/image.png
" width="50%" height="n%"></p>
<blockquote>
<h1 id="프로젝트-실행">프로젝트 실행</h1>
</blockquote>
<p>인텔리제이에서는 control + R 를 선택하면 실행이 됩니다.
또한, 상단에서 초록색 실행 버튼을 클릭하여도 실행이 됩니다. <img src="https://velog.velcdn.com/images/gojol_devops/post/30fc4b0b-1949-4ef8-aaf7-5537d1d6e373/image.png" alt=""></p>
<p>이렇게 실행된 프로젝트는 </p>
<p>브라우저에서 <a href="http://localhost:3000/">http://localhost:3000/</a> 에서 확인할수 있습니다.</p>
<p>기본페이지는  views &gt; index.ejs 입니다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[컨테이너 인프라 환경이란,,?]]></title>
            <link>https://velog.io/@gojol_devops/%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EC%9D%B8%ED%94%84%EB%9D%BC-%ED%99%98%EA%B2%BD%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@gojol_devops/%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EC%9D%B8%ED%94%84%EB%9D%BC-%ED%99%98%EA%B2%BD%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Fri, 01 Nov 2024 04:57:16 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h2 id="컨테이너-인프라-환경이란-">컨테이너 인프라 환경이란 ?</h2>
</blockquote>
<p>컨테이너 인프라 환경은 컨테이너를 중심으로 구성된 인프라 환경입니다. 여기서 컨테이너(container)는 하나의 운영 체제 커널에서 다른 프로세스에 영향을 받지 않고 독립적으로 실행되는 프로세스 상태를 의미합니다. 
이렇게 구현된 컨테이너는 가상화 상태에서 동작하는 프로세스보다 가볍고 빠르게 동작합니다.</p>
<hr>
<h2 id="1-모놀리식-아키텍쳐">1. 모놀리식 아키텍쳐</h2>
<p>모놀리식 아키텍처(monolithic architecture) 는 하나의 큰 목적이 있는 서비스 또는 애플리케이션에 여러 기능이 통합돼 있는 구조를 의미합니다.
모놀리식 아키텍처에서는 소프트웨어가 하나의 결합된 코드로 구성되기 때문에 초기 단계에서 설계하기 용이하며 개발이 좀 더 단순하고 코드 관리가 간편합니다.</p>
<p>그러나 서비스를 운영하는 과정에서 수정이 많을 경우, 어떤 서비스에서 이뤄진 수정이 연관된 다른 서비스에 영향을 미칠 가능성이 커집니다. 또한 서비스가 점점 성장해 기능이 추가될수록 처음에는 단순했던 서비스 간의 관계가 매우 복잡해질 수 있습니다.
<img src="https://velog.velcdn.com/images/gojol_devops/post/eee776fa-7aa3-4e6f-8626-7d584aa3397a/image.png" alt=""></p>
<h2 id="2마이크로서비스-아키텍처">2.마이크로서비스 아키텍처</h2>
<p>마이크로서비스 아키텍처(MSA, Microservices Architecture)는 시스템 전체가 하나의 목적을 지향하는 바는 모놀리식 아키텍처와 동일합니다. 하지만 개별 기능을 하는 작은 서비스를 각각 개발해 연결하는 데서 그 차이를 보입니다. 보안, 인증 등과 관련된 기능이 독립된 서비스를 구성하고 있으며 다른 서비스들도 독립적으로 동작할 수 있는 완결된 구조입니다.</p>
<p>이런 구조는 개발된 서비스를 재사용하기 쉽고, 향후 서비스가 변경됐을 때 다른 서비스에 영향을 미칠 가능성이 줄어들며 사용량의 변화에 따라 특정 서비스만 확장할 수 있습니다. 따라서 사용자의 요구 사항에 따라 가용성을 즉각적으로 확보해야 하는 IaaS 환경에 적합합니다. 하지만 마이크로서비스 아키텍처는 모놀리식 아키텍처보다 복잡도가 높으며 각 서비스가 서로 유기적으로 통신하는 구조로 설계되기 때문에 네트워크를 통한 호출 횟수가 증가해 성능에 영향을 줄 수 있습니다.
<img src="https://velog.velcdn.com/images/gojol_devops/post/74b28245-70db-4dde-91de-669e4f8a320f/image.png" width="50%" height="100%"></p>
<p>하나의 애플리케이션 안에 포함돼 있던 뉴스, 블로그, 웹툰 서비스가 각 서비스와 관련된 기능과 데이터베이스를 독립적으로 가지는 구조로 표현됐습니다. 각 서비스는 API 게이트웨이와 REST(REpresentational State Transfer) API를 이용한 통신 방식으로 사용자(외부)의 요청을 전달합니다. 서비스 개수는 고정된 것이 아니기 때문에 어떤 서비스가 등록돼 있는지 파악하기 위해 서비스 디스커버리를 사용합니다. 또한 수많은 서비스의 내부 통신을 이벤트로 일원화하고 이를 효과적으로 관리하기 위해 별도로 이벤트 버스를 서비스로 구성합니다.</p>
<p>이런 구조 덕분에 각 서비스는 필요한 기능이 특화된 데이터베이스를 선택해 개별 서비스에 할당할 수 있습니다. 고객의 요구 사항에 따라 분석 서비스를 새로 추가해야 할 때도 기존에 있는 이벤트 버스에 바로 연결하면 되므로 매우 유연하게 대응할 수 있습니다. 각 서비스는 독립적으로 동작할 수 있는 완결된 구조라서 이미 개발된 기능이 다른 서비스에 필요하다면 바로 재사용할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring Cloud을 활용한 마이크로서비스 아키텍처(MSA)]]></title>
            <link>https://velog.io/@gojol_devops/Spring-Cloud%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98MSA</link>
            <guid>https://velog.io/@gojol_devops/Spring-Cloud%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98MSA</guid>
            <pubDate>Fri, 04 Oct 2024 02:50:05 GMT</pubDate>
            <description><![CDATA[<h3 id="스프링-클라우드spring-cloud는-스프링-프레임워크-기반의-클라우드-네이티브-애플리케이션을-개발하기-위한-프로젝트입니다">스프링 클라우드(Spring cloud)는 스프링 프레임워크 기반의 클라우드 네이티브 애플리케이션을 개발하기 위한 프로젝트입니다.</h3>
<p>스프링클라우드는 분산 시스템에서 필요한 다양한 기능들을 추상화하여 제공하고 있으며, 마이크로서비스 아키텍처를 구현할때 유용하게 사용됩니다.</p>
<blockquote>
<p>스프링 클라우드는 다음과 같은 기능을 제공합니다.</p>
</blockquote>
<ol>
<li><p>서비스 디스커버리(Service Discovery): 서비스 디스커버리는 마이크로서비스 환경에서 서비스를 검색하고 호출하기 위한 기능입니다. 스프링 클라우드는 Netflix OSS의 Eureka, Apache ZooKeeper, Consul 등 다양한 서비스 디스커버리 툴과 통합되어 있습니다.</p>
</li>
<li><p>API 게이트웨이(API Gateway): API 게이트웨이는 여러 개의 마이크로서비스에서 제공하는 API를 단일 진입점으로 노출시켜 주는 역할을 합니다. 스프링 클라우드는 Netflix OSS의 Zuul, Spring Cloud Gateway 등 다양한 API 게이트웨이를 제공합니다.</p>
</li>
<li><p>분산 설정(Distributed Configuration): 분산 설정은 마이크로서비스에서 필요한 설정 정보를 중앙에서 관리하고, 변경사항을 런타임 중에 적용할 수 있는 기능입니다. 스프링 클라우드는 분산 환경에서의 설정 관리를 위한 Spring Cloud Config를 제공합니다.</p>
</li>
<li><p>분산 추적(Distributed Tracing): 분산 추적은 분산 시스템에서의 트랜잭션 추적을 위한 기능입니다. 스프링 클라우드는 분산 추적을 위한 Spring Cloud Sleuth와 Zipkin을 제공합니다.</p>
</li>
<li><p>로드 밸런싱(Load Balancing): 로드 밸런싱은 여러 개의 인스턴스에서 제공되는 서비스를 균등하게 분산시켜 주는 기능입니다. 스프링 클라우드는 Ribbon을 사용한 로드 밸런싱을 제공합니다.</p>
</li>
<li><p>회로 차단기(Circuit Breaker): 회로 차단기는 마이크로서비스에서 일시적으로 문제가 발생하여 서비스가 다운될 때, 다운된 서비스에 대한 요청을 차단하고 다른 대체 서비스를 호출하는 기능입니다. 스프링 클라우드는 Netflix OSS의 Hystrix를 사용한 회로 차단기를 제공합니다.</p>
</li>
</ol>
<hr>
<h3 id="spring-cloud-config는-중앙-집중식으로-애플리케이션의-설정-정보를-관리할-수-있도록-해주는-프레임워크입니다">Spring Cloud Config는 중앙 집중식으로 애플리케이션의 설정 정보를 관리할 수 있도록 해주는 프레임워크입니다.</h3>
<p>이를 통해, 애플리케이션의 설정 정보를 손쉽게 수정하고 배포할 수 있습니다.</p>
<p>Config 서버는 Git, Subversion, Vault  등 다양한 백엔드를 지원하며, 애플리케이션의 환경마다 다른 설정 정보를 저장하고 관리할 수 있습니다.</p>
<h3 id="spring-cloud-gateway는-api-게이트웨이-역할을-합니다">Spring Cloud Gateway는 API 게이트웨이 역할을 합니다.</h3>
<p>API 게이트웨이는 클라이언트의 요청을 받아서 애플리케이션을 전달하고, 애플리케이션의 응답을 클라이언트에게 반환합니다.
Gateway를 사용하면, 여러 개의 서비스를 하나의 앤드포인트로 노출하거나, 요청의 라우팅, 필터링, 트래픽 제어등을 수행할 수 있습니다.
Gateway는 이를 위해 다양한 라우팅 방식을 제공합니다.</p>
<h3 id="spring-discovery는-서비스-디스커버리-역할을-합니다">Spring Discovery는 서비스 디스커버리 역할을 합니다.</h3>
<p>서비스 디스커버리란, 분산 시스템에서 서비스 인스턴스의 위치와 상태를 검색하고 사용할 수 있는 기능을 의미합니다.
이를 위해 Discovery 클라이언트는 Eureka, Consul, Zookeeper 등 다양한 백엔드를 지원하며, 서비스 인스턴스의 상태를 추적하고, 이를 Config 서버에 등록하여 동적으로 구성 정보를 업데이트할 수 있습니다.</p>
<hr>
<h2 id="이들-프레임워크를-함께-사용하면">이들 프레임워크를 함께 사용하면,</h2>
<p>Config 서버에서 구성 정보를 가져와서 Gateway를 구성하고, Discovery를 사용하여 서비스 인스턴스를 검색하여 Gateway에 등록할 수 있습니다. 
이를 통해, 여러 개의 서비스 인스턴스를 투명하게 제공하고, 높은 가용성과 확장성을 보장할 수 있습니다. 
예를 들어, Config 서버에서 포트 정보를 가져와서 Gateway의 라우팅 규칙을 동적으로 업데이트하거나, 
Discovery를 사용하여 서비스 인스턴스의 상태를 추적하여 Gateway의 로드밸런싱 규칙을 동적으로 업데이트할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[java - 제어문]]></title>
            <link>https://velog.io/@gojol_devops/java-%EC%A0%9C%EC%96%B4%EB%AC%B8</link>
            <guid>https://velog.io/@gojol_devops/java-%EC%A0%9C%EC%96%B4%EB%AC%B8</guid>
            <pubDate>Thu, 29 Aug 2024 15:16:12 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h2 id="if문">if문</h2>
</blockquote>
<ul>
<li><p>if 문은 boolean형의 결과를 가지는 조건식이 있어야하며 그 조건식의 결과로 수행하는 문장을 결정하게 되는 분기문이다.</p>
</li>
<li><p>if문에서 continue 를 사용하게 된다면 현재 진행되는 반복 회차를 포기하고 다음 회차로 이동한다.</p>
</li>
</ul>
<pre><code class="language-java">
        int y,m,d;
        boolean flag;
        System.out.println(&quot;년도를 입력하세요 &quot;);
        y = sc.nextInt();

        if(y%4==0&amp;y%100!=0||y%400==0) {
            System.out.println(y+&quot;년은 윤년입니다.&quot;);
            flag = true;
        }
        else {
            System.out.println(y+&quot;년은 평년입니다.&quot;);
            flag = false;
        }
        System.out.println(&quot;월을 입력하세요.&quot;);
        m = sc.nextInt();

        if(m&lt;1 || m&gt;12) {
            System.out.println(&quot;잘못된 월을 입력하셨습니다.&quot;);
            return;
        }
</code></pre>
<blockquote>
<h2 id="switch-case-문">switch case 문</h2>
</blockquote>
<ul>
<li>switch case 문은 if문의 조건값과 다르게 long형을 제외한 정수형(byte, short, lnt) 또는 char형인 것이 다르다.</li>
<li><strong>case 뒤에 오는 조건 값이 중복되지 않도록 해야 한다. 그렇지 않으면 case를 구분하는 값이 복제되어 중복되었다는 오류가 발생한다.</strong></li>
</ul>
<pre><code class="language-java">
        Scanner sc = new Scanner(System.in);

        int num=0;

        System.out.println(&quot;숫자 1~3을 입력하세요.&quot;);
        num = sc.nextInt();
        System.out.println(num+&quot; 을 입력하셨습니다.&quot;);

        switch (num) {
            case 1 :
                    System.out.println(&quot;one&quot;);
                    break;

            case 2 : 
                    System.out.println(&quot;two&quot;);
                    break;

            case 3 :
                    System.out.println(&quot;three&quot;);
                    break;
            default : 
                    System.out.println(&quot;other number&quot;);

        }  // switch case 문에서 해당 case에서 프로그램을 종료하려면 case 마지막에 break;를 사용해서 해당 switch case 문을 종료시킴;
</code></pre>
<blockquote>
<h2 id="for-문">for 문</h2>
</blockquote>
<ul>
<li>for문은 특정한 명령들을 정해진 규칙에 따라 반복처리 할 때 사용하는 제어문이다. </li>
</ul>
<pre><code class="language-java">for(초기식 ; 조건식 ; 증감식){

 수행문1;    

 수행문2;

}</code></pre>
<table>
<thead>
<tr>
<th>초기식</th>
<th>** 조건식 **</th>
<th>증감식</th>
</tr>
</thead>
<tbody><tr>
<td>가장 먼저 수행하는 부분이며 두 번 다시 수행하지 않는다.(다중 for문에서는 예외)</td>
<td>초기식 다음으로 수행하는 부분이며 loop가 돌 때마다 한번씩 비교하여 반복을 수행해야 할지 반복을 벗어나야 할지를 결정한다.</td>
<td>증감식은 loop를 수행할 때마다 조건식에서 비교하기 전에 항상 수행하며 조건식에 사용되는 변수의 값을 증가 시키거나 감소 시켜 loop를 원활하게 수행하거나 무한 루프를 피하는데 바탕이 되는 부분이다.</td>
</tr>
</tbody></table>
<pre><code class="language-java">
Scanner sc = new Scanner(System.in);
        System.out.println(&quot;5개의 정수를 입력하세요.&quot;);    
        int num,sum = 0,count = 0;
        for(int i = 1; i&lt;=5;i++) {

                num = sc.nextInt();
                if(num&lt;=100&amp;&amp;num&gt;=1) {

                sum+=num;
                System.out.println(&quot;점수는 ? &quot;+num);
                count++;
                continue;
                }

        }
        System.out.println(&quot;입력한 점수 갯수 : &quot;+count);
        System.out.println(&quot;총 합계 : &quot;+sum);
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java - 연산자]]></title>
            <link>https://velog.io/@gojol_devops/Java-%EC%97%B0%EC%82%B0%EC%9E%90</link>
            <guid>https://velog.io/@gojol_devops/Java-%EC%97%B0%EC%82%B0%EC%9E%90</guid>
            <pubDate>Thu, 29 Aug 2024 15:00:27 GMT</pubDate>
            <description><![CDATA[<h1 id="1-증감-연산자">1. 증감 연산자</h1>
<ul>
<li><p>전치일 경우 1순위, 후치일 경우는 끝 순위
단, 단항일 경우 상관없음</p>
</li>
<li><p>증감 연산자 이거나 대입 연산자는 초기값이 들어가 있어야함</p>
</li>
</ul>
<pre><code class="language-java">
        int m=5, n=5;
        int a=10, b=10;


        m++;
        ++n;


        System.out.println(&quot;m = &quot;+m);//6
        System.out.println(&quot;n = &quot;+n);//6

        a += m++; // a= a+m; m=m+1;
        System.out.println(&quot;a = &quot;+a);        //a = a(10)+m(6)
        System.out.println(&quot;m = &quot;+m);        

        b += ++n; //n=n+1; b=b+n;
        System.out.println(&quot;b = &quot;+b);        //n(6)+1 + b(10)
        System.out.println(&quot;n = &quot;+n);
        // a와 b, m과 n은 서로 같은 값으로 변수 선언해주었지만 대입 연산자의 위치로 값이 변함

        m=5;
        System.out.println(m++);
        n=5;
        System.out.println(++n);
        System.out.println(&quot;m = &quot;+m+&quot; n = &quot;+n);</code></pre>
<h1 id="2-삼항-연산자">2. 삼항 연산자</h1>
<blockquote>
<p>조건(삼항) 연산자</p>
</blockquote>
<ul>
<li>조건식 ? 참 : 거짓</li>
</ul>
<blockquote>
<p>두수를 입력후 더 큰 숫자를 출력하시오 </p>
</blockquote>
<pre><code class="language-java">Scanner sc = new Scanner(System.in);

        int num,num1,num2;
        int max;
        System.out.println(&quot;3개의 숫자 입력&quot;);
        num = sc.nextInt();        //3
        num1 = sc.nextInt();    //5
        num2 = sc.nextInt();    //9

        max = (num&gt;num1&amp;&amp;num&gt;num2) ? num : (num1&gt;num2&amp;&amp;num1&gt;num) ? num1 : num2; 
            = (3 &gt; 5 이고, 3 &gt; 5)이 참이면, max = 3 아니면, (5 &gt; 9 이고, 5 &gt; 3) 이 참이면, max = 5 아니면 max = 9 


        System.out.println(max);  //9

</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Github 연동 방법]]></title>
            <link>https://velog.io/@gojol_devops/Github-%EC%97%B0%EB%8F%99-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@gojol_devops/Github-%EC%97%B0%EB%8F%99-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Thu, 29 Aug 2024 14:49:45 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h2 id="처음-한번만-이메일과-유저명-확인">처음 한번만 이메일과 유저명 확인</h2>
</blockquote>
<hr>
<pre><code> git config --global user.name &quot;사용자명&quot;
 git config --global user.email &quot;사용자이메일&quot;</code></pre><h2 id="해당-폴더를-git과-연결하기">해당 폴더를 git과 연결하기</h2>
<hr>
<pre><code>git init : 해당폴더를 깃하고 연결하기 위해서 초기화

git branch -M main : 기본이 마스터 인경우 메인 브랜치 생성

git remote add origin “깃 주소” 

git remote set-url origin “깃 주소”

git 의 README 때문에 바로 push하면 오류가 난다 (해당 폴더와 깃 폴더에 자료가다르기 때문)

먼저 pull로 가져온후 push해야한다.

git pull origin main

ls 로 목록확인하기(윈도우는 dir,리눅스는 ls)

로컬영역에 변경된 코드 저장하기

git add . (파일 추가)

git commit -m &quot;메세지&quot;

로컬영역에서 원격으로 보내기

git push origin main

(git push origin +main : 강제로 push하기)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[CORS]]></title>
            <link>https://velog.io/@gojol_devops/CORS</link>
            <guid>https://velog.io/@gojol_devops/CORS</guid>
            <pubDate>Wed, 21 Aug 2024 15:29:35 GMT</pubDate>
            <description><![CDATA[<h1 id="cors">CORS</h1>
<p>CORS (Cross-Origin Resource Sharing)는 웹 어플리케이션에서 다른 도메인의 리소스에 접근할 때 발생하는 보안 이슈를 해결하기 위한 표준 방법이다.</p>
<p>CORS는 쉽게 말해 다른 출처를 가진 리소스를 공유하기 위한 정책이다. 우리가 겪는 CORS 이슈는 이 정책을 위반했기 때문에 발생하는 것이며, 겪는 입장에서는 귀찮지만 사실 CORS는 우리가 여기저기서 가져오는 리소스가 안전하다는 최소한의 보장을 해주는 방어막인 셈이다.</p>
<h2 id="cors-에러가-발생하는-경우를-알아보자">CORS 에러가 발생하는 경우를 알아보자.</h2>
<ol>
<li><p>출처가 다른 도메인 또는 포트로 리소스를 요청할 때
CORS 정책에 따라, 출처가 다른 도메인이나 포트에서 리소스를 요청하는 경우에는 브라우저에서 CORS 에러가 발생한다. 이 경우에는 서버 측에서 Access-Control-Allow-Origin 헤더를 설정하여 요청을 허용해야 한다.</p>
</li>
<li><p>HTTPS에서 HTTP로 리소스를 요청할 때
보안상의 이유로 HTTPS에서 HTTP로 리소스를 요청하는 경우에도 CORS 에러가 발생할 수 있다. 이 경우에는 HTTPS로 통신하는 서버에서 HTTP로 요청을 전달하는 것이 아니라, HTTPS로 전달해야 한다.</p>
</li>
<li><p>인증 정보를 포함한 요청을 보낼 때
CORS 정책에 따라, 인증 정보를 포함한 요청을 보낼 때에는 서버에서 Access-Control-Allow-Credentials 헤더를 설정해야 한다. 이 헤더가 설정되어 있지 않으면 브라우저는 인증 정보가 포함된 요청을 거부한다.</p>
</li>
<li><p>허용되지 않은 메서드를 사용할 때
CORS 정책에 따라, 허용되지 않은 메서드를 사용하는 요청을 보내는 경우에는 CORS 에러가 발생한다. 이 경우에는 서버에서 Access-Control-Allow-Methods 헤더를 설정하여 요청을 허용해야 한다.</p>
</li>
<li><p>허용되지 않은 헤더를 사용할 때
CORS 정책에 따라, 허용되지 않은 헤더를 사용하는 요청을 보내는 경우에도 CORS 에러가 발생한다. 이 경우에는 서버에서 Access-Control-Allow-Headers 헤더를 설정하여 요청을 허용해야 한다.</p>
</li>
<li><p>프리플라이트 요청에 대한 응답이 없는 경우
브라우저는 CORS 정책을 준수하기 위해, 프리플라이트 요청을 보내고 서버에서 이에 대한 응답을 받아야 한다. 이 때, 서버에서 응답이 없는 경우에는 CORS 에러가 발생한다. 이 경우에는 서버에서 프리플라이트 요청에 대한 응답을 보내도록 설정해야 한다.</p>
</li>
<li><p>브라우저가 CORS를 지원하지 않는 경우
일부 오래된 브라우저에서는 CORS를 지원하지 않는 경우가 있다. 이 경우에는 서버 측에서 다른 방법을 사용하여 요청을 처리해야 한다.</p>
</li>
<li><p>CDN 등에서 제공하는 리소스를 요청할 때
일부 CDN 등에서 제공하는 리소스를 요청할 때에도 CORS 에러가 발생할 수 있다. 이 경우에는 CDN 서비스 제공 업체에서 CORS 설정을 제공하고 있으므로 해당 설정을 확인해야 한다.</p>
</li>
<li><p>브라우저 설정 문제
일부 브라우저에서는 CORS 에러가 발생하는 경우가 있는데, 이는 브라우저 설정에서 발생하는 문제일 수 있다. 이 경우에는 브라우저 설정을 확인하거나, 다른 브라우저를 사용하여 문제를 해결할 수 있다.</p>
</li>
</ol>
<hr>
<blockquote>
<p>본인은 프론트에서 ncp ocr을 사용하기 위한 api 호출을 하는 도중에 CORS 에러가 났다. </p>
</blockquote>
<p>개발중인 시기였기 때문에, ncp / Api Gateway / My Products 에서 URL 경로를 다음과 같이 설정해 주었다.</p>
<pre><code>POST /{domainId}/{signature}/{path}</code></pre><p>이후 프론트 에서 </p>
<pre><code class="language-js">vite.config.js
export default defineConfig({
  plugins: [react()],
  server: {
    port: 8080,
    proxy: {
      &#39;/ocr&#39;: {
        target: &#39;프록시 설정에서 요청이 리다이렉트 될 대상 의 url&#39;,
        changeOrigin: true,
        rewrite: (path) =&gt; path.replace(/^\/ocr/, &#39;&#39;),
      },
      // 추가적으로 다른 프록시 설정이 필요한 경우 여기에 추가
    },
  }
});
</code></pre>
<p>다음과 같이 설정해 주었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[REST, REST API 란,]]></title>
            <link>https://velog.io/@gojol_devops/REST-API-%EB%9E%80</link>
            <guid>https://velog.io/@gojol_devops/REST-API-%EB%9E%80</guid>
            <pubDate>Wed, 21 Aug 2024 15:07:15 GMT</pubDate>
            <description><![CDATA[<h1 id="rest-">REST ,</h1>
<p><strong>REST</strong> (Representational State Transfer) 의 약자 자원을 이름으로 구분하여 해당 자원의 상태를 주고 받는 모든 것을 의미한다.</p>
<p>API 개발자는 여러 아키텍처를 사용하여 API를 설계할 수 있습니다. REST 아키텍처 스타일을 따르는 API를 REST API라고 합니다. REST 아키텍처를 구현하는 웹 서비스를 RESTful 웹 서비스라고 합니다. RESTful API라는 용어는 일반적으로 RESTful 웹 API를 나타냅니다. 하지만 REST API와 RESTful API라는 용어는 같은 의미로 사용할 수 있습니다.</p>
<hr>
<blockquote>
<p>REST-API 는 세가지 요소로 구성된다.</p>
</blockquote>
<ul>
<li>리소스 : 리소스(자원) 은 HTTP URL로 표현한다.</li>
<li>행위 : 리소스에 대한 행위는 HTTP 메서드로 표현한다. 일반적으로 리소스를 생성하고 값을 조회, 수정, 삭제 하는 행위 등을 표현 할 수 있다.</li>
<li>표현 : 리소스에 대한 행위 내용은 HTTP 메시지 내용으로 표현한다. HTTP 메시지의 포맷은 JSON을 사용한다.</li>
</ul>
<h2 id="세-가지-요소를-사용하여-rest-api를-설계할-때는-다음-기본-규칙을-준수한다">세 가지 요소를 사용하여 REST-API를 설계할 때는 다음 기본 규칙을 준수한다.</h2>
<ul>
<li>리소스 이름은 가능하면 동사보다 명사를 사용한다.</li>
<li>리소스는 계층적 구조를 가질 수 있다. 계층 관계를 가지므로 복수 형태로 사용한다.</li>
<li>리소스에 대한 행위는 GET, POST, PUT, DELETE 를 기본으로 한다. 때에 따라서는 PATCH 를 사용한다. </li>
</ul>
<hr>
<blockquote>
<p><em>REST-API는 리소스에 대한 행위를 HTTP 메서드를 기준으로 설계한다. 그래서 리소스를 동사로 설계하면, 행위가 중복되므로 의미가 모호해 질 수 있다. 보통 네 개나 다섯 개의 HTTP 메서드를 이용하면 리소스에 대한 행위를 정의한다.</em></p>
</blockquote>
<hr>
<p>설계자 의도에 따라 GET, POST, PUT, DELETE 등 네 개의 HTTP 메서드 외에 PATCH 메서드를 추가해서 사용한다. </p>
<ul>
<li><p>GET   </p>
<ul>
<li>리소스 정보를 조회하는 데 사용한다. 리소스가 복수형이면 리스트 객체를 응답하고 단수형이면 단수 객체를 응답한다.</li>
</ul>
</li>
<li><p>POST</p>
<ul>
<li>클라이언트가 HTTP 메시지 바디에 전송한 데이터를 정의된 리소스에 생성한다.</li>
</ul>
</li>
<li><p>PUT </p>
<ul>
<li>정의된 리소스 객체를 HTTP 메시지 바디에 전송한 데이터로 전체 수정한다.</li>
</ul>
</li>
<li><p>DELETE</p>
<ul>
<li>정의된 리소스를 삭제한다.</li>
</ul>
</li>
<li><p>PATCH</p>
<ul>
<li>정의된 리소스의 일부 데이터를 수정한다.</li>
</ul>
</li>
</ul>
<hr>
<p><img src="
https://velog.velcdn.com/images/gojol_devops/post/267e5e46-306e-4c9d-a7dd-49eea49c5f5a/image.png
          " height="100%" width="800px" > </p>
<hr>
<blockquote>
<p>REST-API 의 특징</p>
</blockquote>
<ul>
<li>Server-Client(서버-클라이언트 구조)</li>
<li>Stateless(무상태)</li>
<li>Cacheable(캐시 처리 가능)</li>
<li>Layered System(계층화)</li>
<li>Uniform Interface(인터페이스 일관성)</li>
</ul>
<blockquote>
<p>REST-API 의 의 장점 </p>
</blockquote>
<ul>
<li><p>HTTP 프로토콜의 인프라를 그대로 사용하므로 REST API 사용을 위한 별도의 인프라를 구출할 필요가 없다.</p>
</li>
<li><p>HTTP 프로토콜의 표준을 최대한 활용하여 여러 추가적인 장점을 함께 가져갈 수 있게 해준다.</p>
</li>
<li><p>HTTP 표준 프로토콜에 따르는 모든 플랫폼에서 사용이 가능하다.</p>
</li>
<li><p>Hypermedia API의 기본을 충실히 지키면서 범용성을 보장한다.</p>
</li>
<li><p>REST API 메시지가 의도하는 바를 명확하게 나타내므로 의도하는 바를 쉽게 파악할 수 있다.</p>
</li>
<li><p>여러가지 서비스 디자인에서 생길 수 있는 문제를 최소화한다.</p>
</li>
<li><p>서버와 클라이언트의 역할을 명확하게 분리한다.</p>
</li>
</ul>
<blockquote>
<p>REST-API 의 의 단점</p>
</blockquote>
<ul>
<li><p>표준이 존재하지 않는다.</p>
</li>
<li><p>사용할 수 있는 메소드가 4가지 밖에 없다.HTTP Method 형태가 제한적이다.</p>
</li>
<li><p>브라우저를 통해 테스트할 일이 많은 서비스라면 쉽게 고칠 수 있는 URL보다 Header 값이 왠지 더 어렵게 느껴진다.</p>
</li>
<li><p>구형 브라우저가 아직 제대로 지원해주지 못하는 부분이 존재한다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[python 기초 - 문자열 자료형]]></title>
            <link>https://velog.io/@gojol_devops/python-%EA%B8%B0%EC%B4%88-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%9E%90%EB%A3%8C%ED%98%95</link>
            <guid>https://velog.io/@gojol_devops/python-%EA%B8%B0%EC%B4%88-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%9E%90%EB%A3%8C%ED%98%95</guid>
            <pubDate>Tue, 13 Aug 2024 15:26:28 GMT</pubDate>
            <description><![CDATA[<h1 id="문자열-자료형">문자열 자료형</h1>
<hr>
<blockquote>
<h1 id="문자열">문자열</h1>
<p>문자열 이란 문자, 단어 등으로 구성된 문자들의 집합을 의미한다. 예를 들어 다음과 같은 것들이 문자열이다.</p>
</blockquote>
<pre><code class="language-py">&quot;Hello World!!!&quot;
&quot;a&quot;
&quot;12345&quot;</code></pre>
<p>위 문자열 예문을 보면 큰 따옴표(&quot;&quot;)로 둘러싸여 있다. 따옴표로 둘러싸여 있다면 모두 문자열이라고 보면 된다.</p>
<hr>
<blockquote>
<h2 id="문자열을-만드는-방법-4가지">문자열을 만드는 방법 4가지</h2>
</blockquote>
<ul>
<li><p>큰 따옴표(&quot; &quot;) 사용하기</p>
<pre><code class="language-py">&quot;Hello world!!!&quot;</code></pre>
</li>
<li><p>작은 따옴표(&#39; &#39;) 사용하기</p>
<pre><code class="language-py">&#39;Hello world!!&#39;</code></pre>
</li>
<li><p>큰 따옴표(&quot; &quot;) 3개를 연속으로 사용하기</p>
<pre><code class="language-py">&quot;&quot;&quot;Hello world&quot;&quot;&quot;</code></pre>
</li>
<li><p>작은 따옴표(&#39; &#39;) 3개를 연속으로 사용하기</p>
<pre><code class="language-py">&gt;&gt;&gt;a * b
21</code></pre>
</li>
</ul>
<h4 id="-문자열-안에-작은-따옴표나-큰-따옴표를-포함시키고-싶을때">** 문자열 안에 작은 따옴표나 큰 따옴표를 포함시키고 싶을때**</h4>
<ul>
<li>문자열에 작은 따옴표(&#39;) 포함시키기</li>
</ul>
<pre><code class="language-py">&gt;&gt;&gt;text = &quot;I&#39;m studying Python.&quot;

//text를 프롬포트에서 실행시켜보면,

&gt;&gt;&gt;text
&quot;I&#39;m studying Python.&quot;

//변수에 저장된 문자열이 그대로 출력된다.
//만약

&quot;I&#39;m&#39; studying Python.&quot;

이런식으로 &#39;&#39;로 문자열을 둘러싼 후 실행하려면 구문 오류(SyntaxError)가 발생할 것이다.</code></pre>
<ul>
<li>문자열에 큰 따옴표(&#39;) 포함시키기</li>
</ul>
<pre><code class="language-py">&gt;&gt;&gt;text = &#39;&quot;Python is easier than Java &quot;he said&quot;&#39;

//text를 프롬포트에서 실행시켜보면,

&gt;&gt;&gt;text
&#39;Python is easier than Java &quot;he said&quot;&#39;

//이렇게 작은 따옴표(&#39;) 안에 큰 따옴표(&quot;)는 문자열을 만드는 기호로 인식되지 않는다.</code></pre>
<ul>
<li>문자열에 큰 따옴표(&#39;) 포함시키기</li>
</ul>
<pre><code class="language-py">&gt;&gt;&gt;text = &#39;&quot;Python is easier than Java &quot;he said&quot;&#39;

//text를 프롬포트에서 실행시켜보면,

&gt;&gt;&gt;text
&#39;Python is easier than Java &quot;he said&quot;&#39;

//이렇게 작은 따옴표(&#39;) 안에 큰 따옴표(&quot;)는 문자열을 만드는 기호로 인식되지 않는다.</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[python 기초 - 사칙연산]]></title>
            <link>https://velog.io/@gojol_devops/python-%EA%B8%B0%EC%B4%88-1</link>
            <guid>https://velog.io/@gojol_devops/python-%EA%B8%B0%EC%B4%88-1</guid>
            <pubDate>Sun, 28 Jul 2024 16:31:09 GMT</pubDate>
            <description><![CDATA[<h1 id="파이썬-프로그래밍의-기초-사칙연산">파이썬 프로그래밍의 기초, 사칙연산</h1>
<hr>
<blockquote>
<h1 id="사칙연산">사칙연산</h1>
<p>프로그래밍을 한 번도 해본 적이 없는 독자라도 사칙연산 (+, -, *, / )은 알고 있을 것이다. 파이썬 역시 계산기와 마찬가지로 아래의 연산자를 이용해 사칙연산을 수행한다.</p>
</blockquote>
<hr>
<h3 id="--기본값">- 기본값</h3>
<pre><code class="language-py">&gt;&gt;&gt;a = 3
&gt;&gt;&gt;b = 7</code></pre>
<ul>
<li>더하기<pre><code class="language-py">&gt;&gt;&gt;a + b
10</code></pre>
</li>
<li>빼기
```py<blockquote>
<blockquote>
<blockquote>
<p>a - b</p>
</blockquote>
</blockquote>
</blockquote>
</li>
<li>4
```</li>
<li>곱셈<pre><code class="language-py">&gt;&gt;&gt;a * b
21</code></pre>
</li>
<li>나눗셈
```py<blockquote>
<blockquote>
<blockquote>
<p>a / b</p>
</blockquote>
</blockquote>
</blockquote>
</li>
</ul>
<p>0.42857142857142855</p>
<pre><code>***
&gt;x의 제곱을 나타내는 연산자


** **연산자는 x****y처럼 사용되었을 때 x의 y제곱 값을 리턴한다. 
```py
&gt;&gt;&gt; a ** b
2187</code></pre><hr>
<blockquote>
<p>나눗셈 후 나머지를 반환하는 % 연산자</p>
</blockquote>
<p>%는 나눗셈의 나머지값을 반환하는 연산자이다. a = 3 , b = 7 일때 , 7을 3으로 나누면 나머지는 1이 될 것이고 3을 7로 나누면 나머지는 3이 될 것이다.</p>
<pre><code class="language-py">&gt;&gt;&gt;b % a
1
&gt;&gt;&gt;a % b
7</code></pre>
<hr>
<blockquote>
<p>나눗셈 후 소수점 아랫자리를 버리는 // 연산자</p>
</blockquote>
<p>/ 연산자를 사용하여 b 나누기 a 를 하면 예상대로 2.3333333333333335 이 될것이다.</p>
<pre><code class="language-py">&gt;&gt;&gt;b / a
2.3333333333333335</code></pre>
<p>// 연산자를 사용하면 소수점 아랫자리는 버려서 2만 출력되는 것을 확인할 수 있다.</p>
<pre><code class="language-py">&gt;&gt;&gt;b // a
2</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[python 기초]]></title>
            <link>https://velog.io/@gojol_devops/python-%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@gojol_devops/python-%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Sun, 28 Jul 2024 16:27:08 GMT</pubDate>
            <description><![CDATA[<h1 id="파이썬-프로그래밍의-기초-자료형">파이썬 프로그래밍의 기초, 자료형</h1>
<hr>
<blockquote>
<h1 id="숫자형">숫자형</h1>
<p>숫자형이란, 숫자 형태로 이루어진 자료형으로, 우리가 이미 잘 알고 있는 것들이다.
우리가 흔히 사용하는 것들을 생각해 보자, 123과 같은 정수, 12.34와 같은 실수, 드물게 사용하긴 하지만 8진수나 16진수 같은것도 있다.</p>
</blockquote>
<hr>
<h3 id="1-정수형">1. 정수형</h3>
<p>정수형이란, 말 그대로 정수를 뜻하는 자료형을 말한다. 다음 예는 양의 정수와 음의 정수, 숫자 0을 변수 a에 대입하는 예이다.</p>
<pre><code class="language-python">&gt;&gt;&gt;a = 123
&gt;&gt;&gt;a = -178
&gt;&gt;&gt;a = 0</code></pre>
<hr>
<h3 id="2-실수형">2. 실수형</h3>
<p>파이썬에서 실수형은 소수점이 포함된 숫자를 말한다. 다음 예는 실수를 변수 a에 대입하는 예이다.</p>
<pre><code class="language-python">&gt;&gt;&gt;a = 1.2
&gt;&gt;&gt;a = -3.45</code></pre>
<p>위의 방식은 우리가 일반적으로 볼 수 있는 실수형의 소수점 표현 방식이다.</p>
<pre><code class="language-python">&gt;&gt;&gt;a = 4.24E10
&gt;&gt;&gt;a = 4.24e-10</code></pre>
<p>위의 방식은 &#39;컴퓨터식 지수 표현 방식&#39; 으로 파이썬에서는 4.24e10 또는 4.24E10처럼 표현한다.</p>
<hr>
<h3 id="3-8진수와-16진수">3. 8진수와 16진수</h3>
<p>8진수를 만들기 위해서는 숫자가 0o 또는 0O(숫자 0 + 알파벳 소문자 o 또는 대문자 O)로 시작하면 된다.</p>
<pre><code class="language-python">&gt;&gt;&gt;a = 0o177</code></pre>
<p>16진수를 만들기 위해서는 0x로 시작하면 된다.</p>
<pre><code class="language-python">&gt;&gt;&gt;a = 0x8ff
&gt;&gt;&gt;b = 0xABC</code></pre>
<hr>
<h3 id="4-복소수">4. 복소수</h3>
<p>일반적으로 복소수를 배울 때 j 대신 i를 사용했을 것이다. 파이썬은 i 대신 j를 사용한다. 소문자, 대문자 상관없다.</p>
<pre><code class="language-python">&gt;&gt;&gt;a = 1+2j
&gt;&gt;&gt;b = 3-4J</code></pre>
<p>복소수 활용 예</p>
<ul>
<li>복소수.real  은 복소수의 실수 부분을 리턴한다,
```python<blockquote>
<blockquote>
<blockquote>
<p>a = 1+2j
a.real</p>
</blockquote>
</blockquote>
</blockquote>
</li>
</ul>
<p>1.0</p>
<pre><code>- 복소수.imag는 복소수의 허수 부분을 리턴한다.
```python
&gt;&gt;&gt;a = 1+2j
&gt;&gt;&gt;a = a.imag
2.0</code></pre><ul>
<li>복소수.conjugate()는 복소수의 켤레복소수를 리턴한다.<pre><code class="language-python">&gt;&gt;&gt;a = 1+2j;
&gt;&gt;&gt;a.conjugate()
(1-2j)</code></pre>
</li>
<li>abs(복소수) 는 복소수의 절댓값을 리턴한다.
```python<blockquote>
<blockquote>
<blockquote>
<p>a = 1+2j
abs(a)</p>
</blockquote>
</blockquote>
</blockquote>
</li>
</ul>
<p>2.2360679774997898</p>
<pre><code></code></pre>]]></description>
        </item>
    </channel>
</rss>