<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>일 하는 나에 관한 이야기</title>
        <link>https://velog.io/</link>
        <description>Software Quality Engineer</description>
        <lastBuildDate>Sun, 01 Jun 2025 13:37:09 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>일 하는 나에 관한 이야기</title>
            <url>https://velog.velcdn.com/images/w_yoon/profile/4d9f71b4-308c-47bc-bdbc-0b7753eda27b/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 일 하는 나에 관한 이야기. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/w_yoon" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[1-1. 쿠버네티스 무게감 있게 설치하기 > 구간별 상태 확인 [미션 1]]]></title>
            <link>https://velog.io/@w_yoon/1-1.-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4-%EB%AC%B4%EA%B2%8C%EA%B0%90-%EC%9E%88%EA%B2%8C-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0-%EA%B5%AC%EA%B0%84%EB%B3%84-%EC%83%81%ED%83%9C-%ED%99%95%EC%9D%B8-%EB%AF%B8%EC%85%98-1</link>
            <guid>https://velog.io/@w_yoon/1-1.-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4-%EB%AC%B4%EA%B2%8C%EA%B0%90-%EC%9E%88%EA%B2%8C-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0-%EA%B5%AC%EA%B0%84%EB%B3%84-%EC%83%81%ED%83%9C-%ED%99%95%EC%9D%B8-%EB%AF%B8%EC%85%98-1</guid>
            <pubDate>Sun, 01 Jun 2025 13:37:09 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>MAC OS에서 UTM을 통해 Rocky Linux OS 위에 VM을 만들고 내부 IP를 할당하여 원격 접속을 진행한다. </p>
</blockquote>
<h3 id="rocky-linux-버전-확인">Rocky Linux 버전 확인</h3>
<pre><code>[root@k8s-master ~]# cat /etc/*-release</code></pre><p><img src="https://velog.velcdn.com/images/w_yoon/post/2e314376-e99c-4879-9a23-7eeaff858a5b/image.png" alt=""></p>
<h3 id="hostname-확인">Hostname 확인</h3>
<pre><code>[root@k8s-master ~]# hostname</code></pre><p><img src="https://velog.velcdn.com/images/w_yoon/post/5005d6ba-cc44-4b79-bbef-a749fcfe13bf/image.png" alt=""></p>
<h3 id="network-확인">Network 확인</h3>
<pre><code>[root@k8s-master ~]# ip addr</code></pre><p><img src="https://velog.velcdn.com/images/w_yoon/post/2e1c8076-1695-4287-bcfa-efe6185b28ea/image.png" alt=""></p>
<h3 id="자원cpu-memory-확인">자원(cpu, memory) 확인</h3>
<pre><code>[root@k8s-master ~]# lscpu
[root@k8s-master ~]# free -h</code></pre><p><img src="https://velog.velcdn.com/images/w_yoon/post/d28954a9-4757-41dc-bd67-0054dcfd1e9e/image.png" alt="">
<img src="https://velog.velcdn.com/images/w_yoon/post/ee84ceb2-b9b1-49d4-8dd6-b753144f7c21/image.png" alt=""></p>
<h3 id="rocky-linux-기본-설정">Rocky linux 기본 설정</h3>
<pre><code>[root@k8s-master ~]# timedatectl</code></pre><p><img src="https://velog.velcdn.com/images/w_yoon/post/4221c4ed-8414-4565-94f6-c0ac8249a1ef/image.png" alt=""></p>
<h3 id="kubeadm-설치-전-사전작업">Kubeadm 설치 전 사전작업</h3>
<ol>
<li>방화벽 해제 확인 <pre><code>[root@k8s-master ~]# ﻿systemctl status firewalld</code></pre><img src="https://velog.velcdn.com/images/w_yoon/post/a1c8d1ca-a46a-4105-8bcc-2f1b90a7f20e/image.png" alt=""></li>
</ol>
<ol start="2">
<li>스왑 비활성화 확인(Swap에 할당된 자원이 없으며 주석 처리 확인) <pre><code>[root@k8s-master ~]# free
[root@k8s-master ~]# cat /etc/fstab | grep swap</code></pre><img src="https://velog.velcdn.com/images/w_yoon/post/eac4ee7b-623b-49e8-9a2f-95ec5e0fbbcc/image.png" alt=""></li>
</ol>
<h3 id="컨테이너-런타임-설치">컨테이너 런타임 설치</h3>
<h4 id="컨테이너-런타임-설치-전-사전작업---istables-세팅">컨테이너 런타임 설치 전 사전작업 - istables 세팅</h4>
<pre><code># 설정 세팅 확인
[root@k8s-master ~]# ﻿cat /etc/modules-load.d/k8s.conf
[root@k8s-master ~]# ﻿cat /etc/sysctl.d/k8s.conf
# 모듈 적제 확인
[root@k8s-master ~]# lsmod | grep overlay
[root@k8s-master ~]# ﻿lsmod | grep br_netfilter</code></pre><p><img src="https://velog.velcdn.com/images/w_yoon/post/1863fbbb-ff99-4d2f-902f-b855ae79481b/image.png" alt=""></p>
<h3 id="컨테이너-런타임-설치-1">컨테이너 런타임 설치</h3>
<ol>
<li>컨테이너 런타임 설치(containerd 설치) </li>
</ol>
<ul>
<li><p>[Kubernetes Docs] : <a href="https://kubernetes.io/ko/docs/setup/production-environment/container-runtimes/#containerd">https://kubernetes.io/ko/docs/setup/production-environment/container-runtimes/#containerd</a></p>
</li>
<li><p>[Containerd Release] : <a href="https://github.com/containerd/containerd/blob/main/RELEASES.md#kubernetes-support">https://github.com/containerd/containerd/blob/main/RELEASES.md#kubernetes-support</a></p>
</li>
</ul>
<ol start="2">
<li>containerd 패키지 설치(option2)</li>
</ol>
<ul>
<li>[Containerd Docs] : <a href="https://github.com/containerd/containerd/blob/main/docs/getting-started.md#option-2-from-apt-get-or-dnf">https://github.com/containerd/containerd/blob/main/docs/getting-started.md#option-2-from-apt-get-or-dnf</a></li>
</ul>
<ol start="3">
<li>docker engine (containerd.io)만 설치</li>
</ol>
<ul>
<li><p>docker repo 설정 확인 </p>
<pre><code>[root@k8s-master ~]# yum repolist enabled</code></pre><p><img src="https://velog.velcdn.com/images/w_yoon/post/f5c341da-6716-44a8-96f5-7d6ea5cc9166/image.png" alt=""></p>
</li>
<li><p>containerd 설치 확인 </p>
<pre><code>[root@k8s-master ~]# systemctl status containerd</code></pre><p><img src="https://velog.velcdn.com/images/w_yoon/post/db05fd57-363c-4e21-b588-b85432d1b18b/image.png" alt=""></p>
</li>
<li><p>[Docker Docs] : <a href="https://docs.docker.com/engine/install/centos/#install-using-the-repository">https://docs.docker.com/engine/install/centos/#install-using-the-repository</a></p>
</li>
<li><p>설치 가능한 버전의 containerd.io 리스트 확인 </p>
<pre><code>[root@k8s-master ~]# yum list containerd.io --showduplicates | sort -r</code></pre><p><img src="https://velog.velcdn.com/images/w_yoon/post/9f057fa2-8fc5-473e-94ad-da154c965c12/image.png" alt=""></p>
</li>
</ul>
<h3 id="컨테이너-런타임-cri-활성화">컨테이너 런타임 CRI 활성화</h3>
<blockquote>
<p>Kublet의 Cgroup의 default가 cgroupfs 입니다. 하지만 레드헷 계열 리눅스(Rocky linux)의 경우 systemd를 메인으로 프로세스를 실행시키는 시스템이기 때문에, 쿠버네티스 설치 시 default로 systemd가 세팅됩니다. 따라서 컨테이너 런타임의 cgroup 드라이버와 동일해야 하기때문에 containerd도 systemd로 변경하여 쓰는 게 Core 사용에 부담이 없다.</p>
</blockquote>
<ol>
<li>CRI 활성화 설정 확인</li>
</ol>
<pre><code>[root@k8s-master ~]# cat /etc/containerd/config.toml</code></pre><p><img src="https://velog.velcdn.com/images/w_yoon/post/d59ed983-f108-4826-811c-646b57b83b6a/image.png" alt=""></p>
<blockquote>
<p>SystemdCgroup을 true로 설정해주어야 한다. false일 경우 cgroupfs를 쓴다. </p>
</blockquote>
<ol start="2">
<li>Kublet cgroup 확인<pre><code>[root@k8s-master ~]# cat /etc/containerd/config.toml</code></pre><img src="https://velog.velcdn.com/images/w_yoon/post/62bcfd59-a3f3-429d-9609-96689ac2c908/image.png" alt=""></li>
</ol>
<pre><code>[root@k8s-master ~]# cat /var/lib/kubelet/config.yaml</code></pre><p><img src="https://velog.velcdn.com/images/w_yoon/post/b84dc0a9-df4e-4bad-97b8-81fbee6caf44/image.png" alt=""></p>
<ul>
<li>[Kubernetes Docs] : <a href="https://kubernetes.io/ko/docs/setup/production-environment/container-runtimes/#containerd">https://kubernetes.io/ko/docs/setup/production-environment/container-runtimes/#containerd</a></li>
</ul>
<h3 id="kubeadm-설치">Kubeadm 설치</h3>
<ol>
<li>repo 설정 확인 <pre><code>[root@k8s-master ~]# yum repolist enabled
</code></pre></li>
</ol>
<pre><code>
![](https://velog.velcdn.com/images/w_yoon/post/25064d3e-686b-4092-8fcc-ac66166642c6/image.png)

2. SELinux 설정 확인 </code></pre><p>[root@k8s-master ~]# cat /etc/selinux/config
[root@k8s-master ~]# sestatus</p>
<pre><code>![](https://velog.velcdn.com/images/w_yoon/post/7501dc6e-452e-4307-9167-4217e9469b4a/image.png)![](https://velog.velcdn.com/images/w_yoon/post/ecd01aa9-d57d-4ef9-baf8-6db6756d4a39/image.png)

3. kubelet, kubeadm, kubectl 패키지 설치 </code></pre><p>#버전 보기
[root@k8s-master ~]# kubeadm version
[root@k8s-master ~]# kubectl version</p>
<p>#상태 보기
[root@k8s-master ~]# systemctl status kubelet</p>
<p>#설정 파일 위치
[root@k8s-master ~]# cat /var/lib/kubelet/config.yaml</p>
<p>#로그 조회
 journalctl -u kubelet | tail -10</p>
<pre><code>![](https://velog.velcdn.com/images/w_yoon/post/f2b77ac5-1e21-4c6f-8a20-66bd5be3f42c/image.png)

### 클러스터 초기화(Pod network 세팅) </code></pre><p>kubeadm init --pod-network-cidr=20.96.0.0/16 --apiserver-advertise-address 192.168.56.30</p>
<pre><code>#### 클러스터 상태 확인 </code></pre><h1 id="master-node-상태확인">master node 상태확인</h1>
<p>[root@k8s-master ~]# kubectl get node</p>
<h1 id="pod-network-cidr-설정-확인">pod network cidr 설정 확인</h1>
<p>[root@k8s-master ~]# kubectl cluster-info dump | grep -m 1 cluster-cidr</p>
<h1 id="apiserver-advertise-address-적용-확인">apiserver advertise address 적용 확인</h1>
<p>[root@k8s-master ~]# kubectl cluster-info</p>
<h1 id="kubernetes-component-pod-확인">kubernetes component pod 확인</h1>
<p>[root@k8s-master ~]# kubectl get pods -n kube-system</p>
<pre><code>![](https://velog.velcdn.com/images/w_yoon/post/d19065f5-fbaa-40bb-a6d4-b7a07fcd9da0/image.png)
- [Kubernetes Docs] : https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#initializing-your-control-plane-node

&gt; 1. 마스터 노드 1개만 있고, 정상적으로 클러스터 구성이 완료 상태인 걸 알 수 있어요. 만약 Pod 네트워크가 없는 상태라면 노드의 상태는 NotReady 상태일 거예요. &#39;control-plane&#39;은 마스터 노드 역할을 의미해요. 그리고 노드가 클러스터에 포함된 시간은 161분이네요. v1.27.2는 쿠버네티스의 버전입니다. 
2. &#39;cluster-cidr&#39;은 Pod 네트워크에 할당된 IP 주소의 범위예요. 이 CIDR 블록은 각 pod에게 IP를 분배하는 풀(pool)이고 20.96.0.0/16은 약 6만 개 이상의 Pod IP를 할당할 수 있는 대역이에요. CNI 플러그인이 이 범위를 기반으로 네트워크를 구성하고 Pod에 IP를 자동으로 부여합니다. 
3. &#39;kubenetes control plane is running at https://192.168.56.30:6443&#39; 이 주소는 클러스터의 API 주소예요. 모든 kubectl 명령어는 이 API 서버에 REST API를 날려서 작동해요. 즉 쿠버네티스의 두뇌가 여기서 작동 중이라는 뜻!
3. &#39;CoreDNS is running at https://.../services/kube-dns:dns/proxy&#39; CoreDNS는 쿠버네티스 내부의 DNS 역할을 해요. 
5. 추가로... 6443 포트를 쓰는 이유는 쿠버네티스 API 서버의 기본 HTTPS 포트(보안 통신), Pod IP는 클러스터를 초기화할 때 설정한 &#39;cluster-cidr&#39;에 따라 CNI 플러그인이 Pod 생성 시 자동으로 설정, CoreDNS가 있어야 Pod 간에 서비스 이름 기반 통신이 가능해요! 

#### kubectl 사용 설정</code></pre><p>[root@k8s-master ~]# cat ~/.kube/config</p>
<pre><code>![](https://velog.velcdn.com/images/w_yoon/post/a41a1983-572a-44d7-afaf-608e3426d130/image.png)

#### CNI 플러그인 설치(calico) </code></pre><h1 id="calico-pod-상태-확인">Calico Pod 상태 확인</h1>
<p>[root@k8s-master ~]# kubectl get -n calico-system pod
[root@k8s-master ~]# kubectl get -n calico-apiserver pod</p>
<h1 id="calico에-pod-network-cidr-적용-확인">Calico에 pod network cidr 적용 확인</h1>
<p>[root@k8s-master ~]# kubectl get installations.operator.tigera.io default -o yaml  | grep cidr</p>
<pre><code>![](https://velog.velcdn.com/images/w_yoon/post/04502d1a-31bc-4b23-8401-5a56b2ee3563/image.png)

#### Master에 pod를 생성할 수 있도록 설정
- 원래 pod는 master node에 만들지 않고 보통 worker node에 만들기 때문에 실습을 위해 master nodedp traint 해제를 확인합니다. 
![](https://velog.velcdn.com/images/w_yoon/post/a98492a5-7edf-4a83-9bec-50039b004ef4/image.png)

### 대시보드 설치 확인 </code></pre><p>kubectl get pod -n kubernetes-dashboard</p>
<p>```
<img src="https://velog.velcdn.com/images/w_yoon/post/8f9761c5-0271-4f8b-9986-2e24a553a8d0/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/60ff95ca-41c5-4703-bf1c-70d9613e9618/image.png" alt=""></p>
<blockquote>
<p>Mac에서 대시보드에 접속하기 위해서 대시보드용 관리자 계정을 만들고 Bearer token(Kubernetes 클러스터에서 대시보드에 로그인할 수 있는 사용자 권한을 가진 인증 토큰)을 발급받아 로그인 했다. 
토큰 확인: kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk &#39;{print $1}&#39;)
<a href="https://192.168.56.30:30000/#/login">https://192.168.56.30:30000/#/login</a></p>
</blockquote>
<ul>
<li>chrome 접속 시 거부 화면에서 아무데나 클릭하고 thisisunsafe로 인증하면 우회된다. </li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[4 - Dockerfile 최적화와 캐싱 메커니즘 ]]></title>
            <link>https://velog.io/@w_yoon/4-Dockerfile</link>
            <guid>https://velog.io/@w_yoon/4-Dockerfile</guid>
            <pubDate>Tue, 06 Feb 2024 10:02:28 GMT</pubDate>
            <description><![CDATA[<h1 id="dockerfile">Dockerfile</h1>
<p>Dockerfile은 애플리케이션을 패키징하기 위한 간단한 스크립트입니다. 스크립트는 익스트럭션으로 구성되어 있고, 대문자로 작성돼 있으나 소문자를 사용해도 무관합니다. </p>
<h2 id="instruction">instruction</h2>
<ol>
<li><strong>FROM</strong>: 모든 이미지는 다른 이미지로부터 출발한다. 빌드할 이미지의 시작점을 지정한다. </li>
<li><strong>ENV</strong>: 환경 변수 값을 지정한다. 값을 지정하기 위해 [key]=[value] 형식을 따른다. </li>
<li><strong>WORKDIR</strong>: 컨테이너의 이미지 파일 시스템에 디렉터리를 만들고, 해당 디렉터리를 작업 디렉터리로 지정한다. 컨테이너 또는 호스트에 이미 존재할 필요가 없고 새로 만든다. </li>
<li><strong>COPY</strong>: 로컬 파일 시스템의 파일 혹은 디렉터리를 컨테이너 이미지로 복사한다. [원본 경로] [복사 경로] 형식으로 지정한다. </li>
<li><strong>ENTRYPOINT</strong>: 이미지로 컨테이너를 띄울 때 항상 실행되어야 하는 커맨드를 지정한다. Docker image를 마치 하나의 실행 파일처럼 사용할 때 유용합니다. 컨테이너가 뜰 때 ENTRYPOINT로 지정한 커맨드가 실행되고, 이 커맨드로 실행한 프로세스가 죽을 때 컨테이너도 따라서 종료되기 때문입니다. </li>
<li><strong>CMD</strong>: 도커가 이미지로부터 컨테이너를 실행했을 때 실행할 디폴트 명령을 지정한다. 또는 ENTRYPOINT 명령문으로 지정된 커맨드에 디폴트로 넘길 파라미터를 지정할 때 사용합니다. </li>
<li><strong>RUN</strong>: CMD와는 실행 시점이 다릅니다. CMD는 컨테이너 실행 시, RUN은 이미지를 빌드하는 과정에서 필요한 커맨드를 실행하기 위해서 사용됩니다. 쉘(shell)을 통해 거의 못하는 작업이 없듯, RUN 명령어로 할 수 있는 일도 무궁무진하지만 보통 이미지 안의 소프트웨어를 설치하기 위해서 많이 사용됩니다. </li>
</ol>
<h2 id="docker-이미지-레이어-캐싱--최적화">Docker 이미지 레이어 캐싱 &amp; 최적화</h2>
<h3 id="이미지-레이어란">이미지 레이어란?</h3>
<p>instruction으로 도커 이미지를 빌드한다는 것을 이해했습니다. 도커 이미지는 이미지 레이어가 모인 논리적 대상입니다. 즉, 도커 이미지를 구성하는 물리적으로 저장된 파일은 도커 엔진의 캐시에 저장된 이미지 레이어입니다. 이미지 레이어는 어떻게 생성될까요? Dockerfile의 instruction은 각각 하나의 이미지 레이어와 1:1로 연결됩니다. 즉, instruction이 실행될 때 이미지 레이어가 생성됩니다. 이미지 레이어는 디스크 용량과 관련됩니다. 어떻게 이미지 레이어가 차지하는 디스크 용량을 줄이고 관리할 수 있을까요? </p>
<h3 id="1-이미지-레이어는-여러-이미지가-공유할-수-있습니다">1. 이미지 레이어는 여러 이미지가 공유할 수 있습니다.</h3>
<ul>
<li>예를들어 diamol/node라는 이미지는 Node.js 런타임과 최소한의 운영체제를 포함합니다. 이때 other-node-app 이미지의 Dockerfile에서 FROM diamol/node를 지정합니다. other-node-app은 최소한의 운영체제 레이어와 Node.js 런타임을 포함합니다. 뿐만 아니라 diamol/node 이미지를 기반 이미지로 하므로 기반 이미지의 모든 레이어를 포함합니다. </li>
<li>이때 이미지 레이어를 여러 이미지가 공유한다면, 공유되는 레이어는 수정할 수 없습니다. 도커는 이미지 레이어를 read-only로 만들어 두어 이런 문제를 방지합니다. 이미지를 빌드하면서 레이어가 만들어지면 다른 이미지에서 재사용될 수 있습니다. 그러나 레이어를 수정할 수는 없습니다. </li>
</ul>
<h3 id="2-이미지-레이어는-캐싱할-수-있습니다">2. 이미지 레이어는 캐싱할 수 있습니다.</h3>
<ul>
<li><p>캐싱 메커니즘을 통해서 Dockerfile 스크립트를 최적화할 수 있습니다. <strong>최적화란 도커 이미지 용량을 줄이고 빌드 시간을 단축하는 것입니다.</strong> instruction의 결과가 이전 빌드와 같다면, 이전에 캐시된 레이어를 사용할 수 있습니다. 이런 방법으로 똑같은 instruction을 다시 실행하는 낭비를 줄일 수 있습니다. </p>
</li>
<li><p>도커는 캐시에 일치하는 레이어가 있는지 확인하기 위해 해시값을 사용합니다. 도커 이미지를 pull 받게 되면 마치 여러개로 분리된 조각을 내려받는 것처럼 보입니다. 이렇게 분리된 데이터를 레이어(Layer)라고 하고, hash로 구분합니다. 레이어가 업데이트 된다면 hash도 변경됩니다. </p>
</li>
</ul>
<pre><code>$ docker pull nginx:latest

Using default tag: latest
latest: Pulling from library/nginx
c499e6d256d6: Already exists
74cda408e262: Pull complete
ffadbd415ab7: Pull complete
Digest: sha256:282530fcb7cd19f3848c7b611043f82ae4be3781cb00105a1d593d7e6286b596
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest</code></pre><ul>
<li>여기서, Dockerfile에 정의된 모든 instruction이 레이어가 되는 것은 아닙니다. <strong>RUN, ADD, COPY</strong> 이 3가지 단계만이 레이어로 저장되고 그 외에 메타 정보를 다루는 <strong>CMD, LABEL, ENV, EXPOSE</strong> 등은 임시 레이어로 생성되지만 저장되지 않아 이미지 사이즈에 영향을 주지 않습니다. </li>
<li>기존 이미지 레이어에 해시값이 일치하는 것이 없다면 캐시 미스가 발생하고 해당 instruction이 실행됩니다. <strong>여기서 주목할 점은 한번 instruction이 실행되면 그 다음에 오는 instruction은 수정된 것이 없더라도 항상 실행됩니다.</strong> 이러한 연유로 잘 수정하지 않는 instruction이 앞으로 오고, 자주 수정되는 instruction이 뒤에 오도록 배치해야 합니다. 이렇게 해야 캐시에 저장된 이미지 레이어를 되도록 재사용할 수 있습니다. 이미지를 공유하는 과정에서 <strong>시간, 디스크 용량, 네트워크 대역폭 모두 절약할 수 있는</strong> 방법입니다. </li>
</ul>
<blockquote>
<p>ref: <a href="https://jonnung.dev/docker/2020/04/08/optimizing-docker-images/">https://jonnung.dev/docker/2020/04/08/optimizing-docker-images/</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[FastAPI - WSGI와 ASGI]]></title>
            <link>https://velog.io/@w_yoon/FastAPI-1-WSGI%EC%99%80-ASGI</link>
            <guid>https://velog.io/@w_yoon/FastAPI-1-WSGI%EC%99%80-ASGI</guid>
            <pubDate>Mon, 30 Oct 2023 14:37:16 GMT</pubDate>
            <description><![CDATA[<h2 id="fastapi는-무엇인가">FastAPI는 무엇인가?  </h2>
<h3 id="python-web-framework">Python web framework</h3>
<ol>
<li>데이터 타입을 엔드포인트로 명시하지 않아도 된다. </li>
<li>Uvicorn ASGI Server를 사용한다. </li>
</ol>
<ul>
<li>ASGI(Asynchronous Server Gateway Interface): 비동기 방식을 지원하는 웹 서버 </li>
<li>WSGI(Web Server Gateway Interface):웹소켓을 사용할 수 없고, HTTP/2 동시성을 적용할 수 없으며 파이썬 비동기를 사용할 수 없다는 한계가 있다. </li>
</ul>
<h3 id="cgi와-fastcgi">CGI와 FastCGI</h3>
<p>외부 어플리케이션과 웹 서버(nginx, Apache 등)와 연결할 때 사용하는 인터페이스는 보통 CGI(Common Gateway Interface)를 사용합니다. CGI는 웹 서버와 외부 프로그램을 연결해주는 표준화된 프로토콜입니다. </p>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/76808e0f-cca5-42fe-8951-028d66cf9585/image.png" alt=""></p>
<ul>
<li>Web server: 웹 서버의 역항은 정적인 요청을 서빙하거나 Reverse Proxy를 이용하여 어플리케이션 서버로 동적인 요청을 전달하는 용도이다. </li>
<li>CGI: 과거에는 정적 HTML 파일 하나를 가지고 웹 서비스를 했기 때문에 이러한 CGI가 필요하지 않았다. 하지만 웹에 대한 수요가 증가함에 따라 웹 서버가 처리할 수 없는 정보가 요청되었을 경우 그 처리를 외부 어플리케이션이 할 수 있도록 호출 함으로써 중계 역할을 한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/b28a8af1-a0c5-4b83-a7e1-894be66f7d9f/image.png" alt=""></p>
<p>그러나 CGI는 클라이언트의 요청이 발생할 때마다 프로세스를 추가로 생성하고 삭제하기를 반복한다. 이는 커널 리소스를 계속 생성/ 삭제하기 때문에 오버헤드가 심해지고, 성능 저하의 원인이 되기도 합니다. </p>
<p>현대의 웹 서비스처럼 빈번하게 REST API가 호출 되고, 요청과 응답을 수시로 반복하여 처리하는 곳에서 이러한 아키텍처는 맞지 않는다. 그래서 생긴 것이 FastCGI 이다. </p>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/bf600717-d140-49c5-b71e-577b1badcb7d/image.png" alt=""></p>
<p>FastCGI는 몇 번의 요청이 들어와도 하나의 프로세스만을 가지고 처리합니다. 즉 메모리에 하나의 프로그램만을 적재하여 계속 재활용하기 때문에 CGI에 비하여 오버헤드가 월등하게 감소한다. </p>
<p>Java의 Tomcat 또한 Web Server + FastCGI를 채택한 형태로 다수의 사용자 접속에 유리하다. JVM 계열의 언어로 서버 프로그램을 작성하면 JBoss, Tomcat 등의 웹 어플리케이션 서버를 사용하는게 보편적이지만 이외에도 CGI를 수동으로 붙여서 사용할 수 있는 방법도 있었다. </p>
<p>그러나 Python에는 이러한 WAS가 별도로 존재하지않으며 결국 우리가 CGI, FastCGI 등을 이용해서 원하는 WAS 형태를 만들어서 사용해야 하는데, 실제로 Python만의 게이트웨이 인터페이스가 존재합니다. </p>
<h4 id="was란">WAS란?</h4>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/cdfb77c9-c2b6-4f90-be50-8cc97d764031/image.png" alt=""></p>
<p>&quot;인터넷 상에서 HTTP 프로토콜을 통해 사용자 컴퓨터나 장치에 어플리케이션을 수행해주는 미들웨어로서, 주로 동적 서버 컨텐츠를 수행하는 것으로 웹 서버와 구별이 된다.&quot; </p>
<p>WAS는 웹 서버와 웹 컨테이너가 합쳐진 형태로, 웹 서버 단독으로는 처리할 수 없는 데이터베이스 조회나 다양한 로직 처리가 필요한 동적 컨텐츠를 제공한다. 덕분에 사용자의 다양한 요구에 맞춰 웹 서비스를 제공할 수 있다.</p>
<p>반면에 Web Server는 클라이언트(사용자)가 웹 브라우저에 어떠한 페이지 요청을 하면 웹 서버에서 그 요청을 받아 정적 컨텐츠를 제공하는 서버이다. 여기서 정적 컨텐츠란 단순 HTML 문서, CSS, Javascript, 이미지, 파일 등 즉시 응답 가능한 컨텐츠이다. </p>
<p>뿐만 아니라 웹 서버가 동적 컨텐츠를 요청 받으면 WAS에게 해당 요청을 넘겨주고, WAS에서 처리한 결과를 클라이언트(사용자)에게 서빙해주는 역할도 한다. </p>
<p>WAS 예: Tomcat 
Web Server: Apache</p>
<h3 id="그럼-was만-써도-될까-답은-no">그럼 WAS만 써도 될까? 답은 NO!</h3>
<p>WAS는 DB 조회 및 다양한 로직을 처리하는 데 집중해야 한다. 따라서 단순한 정적 컨텐츠는 웹 서버에게 맡기며 기능을 분리시켜 서버 부하를 방지한다. 만약 WAS가 정적 컨텐츠 요청까지 처리하면, 부하가 커지고 동적 컨텐츠 처리가 지연되면서 수행 속도가 느려지고 이로 인해 페이지 노출 시간이 늘어나는 문제가 발생하여 효율성이 크게 떨어진다. </p>
<blockquote>
<p>웹 서버를 WAS 앞에 두고 필요한 WAS들을 Web server에 플러그인 형태로 설정하면 더욱 효율적인 분산 처리가 가능하다. </p>
</blockquote>
<h3 id="근데-왜-tomcat이-아닌-apache-tomcat인가">근데 왜 Tomcat이 아닌 Apache Tomcat인가?</h3>
<p>앞에서 언급한대로 정적 컨텐츠를 처리하는 웹 서버에는 Apache가 있고, 동적 컨텐츠를 처리하는 WAS 서버에는 Tomcat이 있는데 Tomcat은 Apache Tomcat이라는 이름으로 많이 사용되어 혼란스러울 것이다. </p>
<p>붙여서 쓰는 이유는 2008년에 릴리즈 된 Tomcat 5.5 버전부터 정적 컨텐츠를 처리하는 기능이 추가되었는데, 이 기능이 순수 Apache를 사용하는 것과 성능적 차이가 전혀 없으며 Tomcat이 Apache의 기능을 포함하고 있기 때문에 Apache Tomcat이라고 부르고있다. </p>
<h2 id="wsgi">WSGI</h2>
<p>python 어플리케이션, 스크립트가 웹 서버와 통신하기 위한 인터페이스로써 CGI 디자인 패턴을 모태로 만들어졌으나 실제 CGI와는 다소 차이가 있다. </p>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/3dd58961-792f-4ca7-869f-df79d77db43d/image.png" alt=""></p>
<p>WSGI는 CGI와 동일하게 웹 서버와 애플리케이션 중간에 위치하는데, CGI와 다른점은 CGI는 매 요청마다 프로세스를 생성하고 WSGI는 한 프로세스에서 모든 요청을 받는다는 것입니다. 요약해서 CGI는 매 요청마다 커널 리소스를 추가/반납하고, WSGI는 많은 요청을 콜백으로 받아 처리하게 됩니다. </p>
<p>WSGI로 대표적인 두 가지 방법이 있습니다. </p>
<ol>
<li><p>nginx, apache에서 내장 모듈로 제공하는 server-often high profile 방식(ex. mode-wsgi, mod-python)</p>
</li>
<li><p>Python 코드로 작성된 Web App server(ex. gunicorn)</p>
</li>
</ol>
<p>결국 WSGI는 웹 서버와 애플리케이션 사이에 미들웨어 역할을 하며 기술적으로는 웹 서버, 애플리케이션 양쪽에서 WSGI에 대한 작동 코드가 필요한 Client-Server 모델을 응용한 것입니다. 웹 서버가 애플리케이션 코드를 직접적으로 읽을 수 없으므로 중간의 미들웨어가 해당 코드를 읽어서 반환해주는 방식입니다. </p>
<h2 id="asgi">ASGI</h2>
<p>WSGI만으로는 현대 웹 서비스의 대용량 트래픽 처리를 유연하게 하기가 어렵습니다. Python은 asyncio, coroutine과 같은 비동기 처리를 지원합니다. 그러나 WSGI는 동기 함수 처리만을 지원하여 여러 작업을 동시에 처리하는 것에 한계가 있습니다. 가령 현대 웹 서비스에는 웹 소켓 등을 사용한 실시간 채팅 서비스 등을 사용할 수도 있는데, WSGI로는 이러한 서비스를 구현하는 데 어려움이 있는 것이죠. </p>
<p>최근에는 Django 3.0 뿐만 아니라 FastAPI 등의 프레임워크에서도 ASGI를 적용하였습니다. WSGI와 다르게 요청을 비동기로 처리하며 Websocket 프로토콜과 HTTP 2.0을 지원합니다. </p>
<p>대표적인 ASGI Web app에는 uvicorn이 있습니다. uvicorn은 ASGI 기반의 웹 어플리케이션 서버로써 그 내장 모듈로 uvloop을 사용합니다. </p>
<blockquote>
<p><strong>_참고한 문서</strong> 
1.<a href="https://blog.neonkid.xyz/249">https://blog.neonkid.xyz/249</a>
2.<a href="https://velog.io/@crosstar1228/BackendFastAPI-%EC%9E%85%EB%AC%B8-1-Uvicorn-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-%EA%B0%84%EB%8B%A8%ED%95%9C-%EC%9B%B9-%EC%84%9C%EB%B2%84-%EA%B5%AC%ED%98%84">https://velog.io/@crosstar1228/BackendFastAPI-%EC%9E%85%EB%AC%B8-1-Uvicorn-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-%EA%B0%84%EB%8B%A8%ED%95%9C-%EC%9B%B9-%EC%84%9C%EB%B2%84-%EA%B5%AC%ED%98%84</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[3 - Docker 이미지 만들기 전에 Bash 익히기 ]]></title>
            <link>https://velog.io/@w_yoon/3-Docker-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%A7%8C%EB%93%A4%EA%B8%B0-%EC%A0%84%EC%97%90-Bash-%EC%9D%B5%ED%9E%88%EA%B8%B0</link>
            <guid>https://velog.io/@w_yoon/3-Docker-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%A7%8C%EB%93%A4%EA%B8%B0-%EC%A0%84%EC%97%90-Bash-%EC%9D%B5%ED%9E%88%EA%B8%B0</guid>
            <pubDate>Wed, 21 Jun 2023 08:28:30 GMT</pubDate>
            <description><![CDATA[<h1 id="bash-익히기">Bash 익히기</h1>
<p>Docker는 리눅스 기반이기 때문에 이미지를 생성할때 Bash(Bourne-again shell)을 주로 사용합니다. 이미지를 생성하기 전에 자주 사용하는 Bash 문법을 간단히 정리합니다. </p>
<h3 id="">&#39;&gt;&#39;</h3>
<p>출력 리다이렉션. 표준 출력을 파일로 저장합니다. </p>
<pre><code>$echo &quot;hello&quot; &gt; ./hello.txt</code></pre><h3 id="-1">&#39;&lt;&#39;</h3>
<p>입력 리다이렉션. 파일의 내용을 읽어 명령의 표준 입력으로 사용합니다. </p>
<pre><code>$cat &lt; ./hello.txt</code></pre><h3 id="-2">&#39;&gt;&gt;&#39;</h3>
<p>명령 실행의 표준 출력을 파일에 추가합니다. &#39;&gt;&#39;는 이미 있는 파일에 내용을 덮어쓰지만 &#39;&gt;&gt;&#39;는 파일 뒷부분에 내용을 추가합니다. </p>
<h3 id="2">&#39;2&gt;&#39;</h3>
<p>명령 실행의 표준 에러(stderr)를 파일로 저장합니다. </p>
<h3 id="2-1">&#39;2&gt;&gt;&#39;</h3>
<p>명령 실행의 표준 에러(stderr)를 파일에 추가합니다. </p>
<h3 id="-3">&#39;&amp;&gt;&#39;</h3>
<p>표준 출력과 표준 에러를 모두 파일로 저장합니다. </p>
<h3 id="12">&#39;1&gt;&amp;2&#39;</h3>
<p>표준 출력을 표준 에러로 보냅니다. echo 명령으로 문자열을 표준 출력으로 출력했지만 표준 에러로 보냈기 때문에 변수에는 문자열이 들어가지 않습니다. </p>
<pre><code>$ hello=$(echo &quot;hello world&quot; 1&gt;%2) 
$ echo $hello </code></pre><h3 id="21">&#39;2&gt;&amp;1&#39;</h3>
<p>표준 에러를 표준 출력으로 보냅니다. abcd라는 명령어는 없음므로 에러가 발생하지만 에러를 표준 출력으로 보낸 뒤 다시 /dev/null로 보냈기 때문에 아무것도 출력되지 않습니다. </p>
<pre><code>$adcd &gt; /dev/null 2&gt;%1</code></pre><h3 id="-4">&#39;|&#39;</h3>
<p>파이프. 명령 실행의 표준 출력을 다른 명령의 표준 입력으로 보냅니다. 즉 첫 번째 명령의 출력 값을 두 번째 명령에서 처리합니다. </p>
<pre><code>$ ls-al | grep .txt </code></pre><h3 id="-5">$</h3>
<p>bash의 변수입니다. 값을 저장할 때는 $를 붙이지 않고, 변수를 가져다 쓸 때만 $을 붙입니다. </p>
<pre><code>&amp; hello=&quot;hello world&quot; 
$ echo $hello 
hello world </code></pre><h3 id="--">&#39;$()&#39; / &#39;&#39;</h3>
<p>명령 실행 결과를 변수화합니다. 명령 실행 결과를 변수에 저장하거나 다른 명령의 매개 변수로 넘겨줄 때 사용합니다. 또는 문자열 안에 명령의 실행 결과를 넣을 때 사용합니다. </p>
<pre><code>$ sudo docker rm $(docker ps -aq) 
$ echo $(date) 
Tue Sep 9 21:24:30 KST 2014
$ sudo docker rm &#39;docker ps -aq&#39; 
$ echo &#39;date&#39;
Tue Sep 9 21:24:30 KST 2014</code></pre><h3 id="-6">&#39;&amp;&amp;&#39;</h3>
<p>한줄에서 명령을 여러 개 실행합니다. 단 앞에 있는 명령이 에러 없이 실행되어야 뒤에 오는 명령이 실행됩니다. </p>
<pre><code>$ make &amp;&amp; make install</code></pre><h3 id="-7">&#39;&#39;</h3>
<p>문자열입니다. &#39;&#39; 안에 들어있는 변수는 처리되지 않습니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[2 - Docker 이미지 의존관계와 컨테이너]]></title>
            <link>https://velog.io/@w_yoon/2-Docker-Image-Container</link>
            <guid>https://velog.io/@w_yoon/2-Docker-Image-Container</guid>
            <pubDate>Thu, 15 Jun 2023 07:36:00 GMT</pubDate>
            <description><![CDATA[<h1 id="base-image">Base Image</h1>
<p>Docker 이미지는 베이스 이미지에 필요한 프로그램 및 라이브러리, 소스를 설치한 뒤 파일 하나로 만든 것을 말합니다.</p>
<p>매번 베이스 이미지에 필요한 프로그램과 라이브러리, 소스를 설치하면 용량이 큰 이미지가 중복되어 생성될 것이라고 생각할 수 있습니다. Docker 이미지는 베이스 이미지에서 바뀐 부분만 이미지로 생성하고, 실행할 때는 베이스 이미지와 바뀐 부분을 합쳐서 실행합니다. </p>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/5b077009-866c-4e01-bc43-cf63bda401ef/image.png" alt=""></p>
<h4 id="유저-랜드">유저 랜드</h4>
<p>OS는 메모리 사용을 기준으로 커널 공가과 유저 공간으로 나눌 수 있습니다. 여기서 유저 공간에서 실행되는 실행 파일과 라이브러리를 Userland라고 합니다. 리눅스는 커널만으로 부팅할 수 없으므로 부팅에 필요한 최소 실행 파일과 라이브러리 조합을 뜻하기도 합니다. </p>
<h1 id="docker-이미지">Docker 이미지</h1>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/eea48dfa-2108-4809-9e6d-eb3fb263dfdd/image.png" alt=""></p>
<p>Docker 이미지는 16진수로 된 ID로 구분하고, 각각의 이미지는 독립적입니다. Docker 이미지는 통째로 생성되지 않습니다. 바뀐 부분만 생성한 뒤 부모 이미지를 계속 참조하는 방식으로 동작합니다. 이미지의 의존관계에 대해 Docker에서는 이를 레이어라고 합니다. </p>
<p>예를들어 위 그림에서 centos:centos6 이미지에 서비스 운영에 필요한 프로그램 설치한뒤 Docker 이미지를 생성하면 example:0.1과 같은 형태가 됩니다. </p>
<p>Docker 이미지는 파일이기 때문에 저장소에 올린 뒤 다른 곳에서 받을 수 있습니다. 그리고 저장소에 올릴 때는 자식 이미지, 부모 이미지를 모두 올립니다. 받을 때도 마찬가지로 부모 이미지를 함께 받습니다. 이후에는 내용이 바뀐 이미지만 주고받습니다. </p>
<h4 id="union-mount-union-file-system">Union mount, Union File System</h4>
<p>생성된 Docker 이미지는 읽기 전용 상태입니다. 여기서 내용이 바뀌면 이미지를 수정하지 않고, 쓰기 이미지를 생성한 뒤 내용을 기록합니다. 이러한 방식을 
Union mount라고 하며 Union mount를 지원하는 파일시스템을 Union File System이라 합니다. </p>
<h1 id="docker-container">Docker container</h1>
<h2 id="_image-build---create-n-container-_">_Image build -&gt; Create N container _</h2>
<p>Docker 컨테이너는 이미지를 실행한 상태입니다. 이미지로 여러개의 컨테이너를 만들 수 있습니다. 운영체제로 보면 이미지는 실행파일이고, 컨테이너는 프로세스입니다. 이미 실행된 컨테이너에서 변경된 부분을 이미지로 생성할 수도 있습니다. </p>
<p>Docker는 특정 파일 또는 스크립트를 위한 실행 환경으로 보면 됩니다. 서버 구성을 미리 해놓은 Docker 이미지를 사용하면 실행할 서버가 몇 개가 되든 손쉽게 해결할 수 있습니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[1 - Docker 시작하기: Docker를 왜 쓰는가? ]]></title>
            <link>https://velog.io/@w_yoon/1-Docker-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@w_yoon/1-Docker-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 15 Jun 2023 07:05:31 GMT</pubDate>
            <description><![CDATA[<h1 id="virtual-merchine">Virtual Merchine</h1>
<p>가상 머신은 편하지만 성능이 좋지 못 합니다. 가상 머신은 완전한 컴퓨터이기 때문에 항상 Guest OS를 설치해야하죠. 따라서 이미지 안에 OS가 포함되며, 가상화 이미지를 주고 받는 일은 부담스러운 일입니다. 
<img src="https://velog.velcdn.com/images/w_yoon/post/2a936f37-f085-4c89-81e5-5a442bee1eb6/image.png" alt=""></p>
<h1 id="docker">Docker</h1>
<p>Docker는 좀 더 경량화된 방식입니다. 게스트 OS를 설치하지 않습니다. Docker 이미지에 서버 운영을 위한 프로그램과 라이브러리만 격리해서 설치할 수 있고 OS 자원(시스템 콜)은 호스트와 공유합니다. 이렇게 되면 용량이 크게 줄어들었습니다. </p>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/4d79d903-3075-4d9e-ad28-71d809e6950f/image.png" alt=""></p>
<h2 id="docker는-무엇이-좋은가">Docker는 무엇이 좋은가?</h2>
<ol>
<li>하드웨어를 가상화하는 계층이 없기 때문에 메모리 접근, 파일시스템, 네트워크 속도가 가상 머신에 비해 월등히 빠릅니다. </li>
<li>이미지 생성 및 배포에 특화되었습니다. Git에서 소스를 관리하는 것처럼 이미지 버전 관리 기능을 제공한다. </li>
<li>중앙 관리를 위해 이미지를 저장소에 올리고, 받을 수 있다.(Push/Pull) 그리고 Docker 이미지를 공유할 수 있는 Docker Hub도 제공한다. </li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Jetty란? ]]></title>
            <link>https://velog.io/@w_yoon/Java-Jetty%EB%9E%80</link>
            <guid>https://velog.io/@w_yoon/Java-Jetty%EB%9E%80</guid>
            <pubDate>Fri, 13 Jan 2023 05:55:00 GMT</pubDate>
            <description><![CDATA[<h2 id="jetty">Jetty</h2>
<p>Jetty는 자바 HTTP 웹 서버이자 자바 서블릿 컨테이너다. 웹 서버가 보통 문서를 사람들에게 제공하는 것과 관련된 반면, 제티는 대규모 소프트웨어 프레임워크에서 기계와 기계의 커뮤니티케이션에 사용된다. </p>
<h3 id="servlet-container">Servlet container</h3>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/2790ca92-ced0-47f8-865f-0da1ad95d194/image.png" alt=""></p>
<p>서블릿이란 SUN사에서 제안한 웹서비스를 위한 인터페이스로, 원칙적으로는 javax.servlet.Servlet 인터페이스의 구현체다. 일반적인 자바 독립 실행 프로그램과 달리 main 메소드가 없으며, 서블릿 컨테이너에 등록된 후 서블릿 컨테이너에 의해 생성, 호출, 소멸이 이루어진다. 즉, 클라이언트가 request를 보내면 그에 대한 결과를 다시 전송해주어야 하는데, 이러한 역할을 하는 자바 프로그램이 바로 서블릿이다. </p>
<p>일반적으로 웹서버는 정적인 페이지만 제공하지만, 동적인 페이지를 제공할 수 있게 도와주는 어플리케이션이 서블릿이다. </p>
<h4 id="정적인-페이지">정적인 페이지</h4>
<p>서버에 미리 저장된 파일(HTML 파일, 이미지, javascript 파일)이 그대로 전달되는 웹 페이지. 즉 사용자는 서버에 저장된 데이터가 변경되지 않는 한 고정된 웹 페이지를 보게 됨</p>
<h4 id="동적인-페이지">동적인 페이지</h4>
<p>서버에 있는 데이터들을 스크립트에 의해 가공처리한 후 생성되어 전달되는 웹 페이지. 즉, 사용자는 상황, 시간, 요청 등에 따라 달라지는 웹 페이지를 보게 됨</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[gradlew(gradle wrapper) ]]></title>
            <link>https://velog.io/@w_yoon/gradlewgradle-wrapper%EB%9E%80</link>
            <guid>https://velog.io/@w_yoon/gradlewgradle-wrapper%EB%9E%80</guid>
            <pubDate>Fri, 21 Oct 2022 05:00:42 GMT</pubDate>
            <description><![CDATA[<p><a href="https://docs.gradle.org/current/userguide/what_is_gradle.html">https://docs.gradle.org/current/userguide/what_is_gradle.html</a></p>
<h2 id="gradle">gradle</h2>
<p>gradle은 거의 모든 소프트웨어를 빌드할 수 있을 만큼 충분히 유연하도록 설계된 
오픈 소스 빌드 자동화 도구이다.JVM에서 실행되며 이를 사용하려면 JDK가 설치되어 있어야 한다. </p>
<h2 id="gradlew">gradlew</h2>
<ul>
<li><p>gradle wrapper를 줄인 말로, 새로운 환경에서 프로젝트를 설정할 때 java나 gradle을 설치하지 않고 바로 빌드할 수 있게 해주는 역할을 한다. </p>
</li>
<li><p>gradlew는 shell script이며 gradelw.bat은 window batch script이다. </p>
</li>
<li><p>gradlew을 사용하는 가장 큰 이유는 아래와 같이 로컬 환경에서 빌드할 경우 로컬 환경에 설치된 java gradle 버전에 영향을 받게 되기 때문이다. </p>
</li>
</ul>
<p>$ ./gradlew build </p>
<ul>
<li>graldew을 이용하여 빌드하면 로컬 환경 java, gradle 버전과 상관없이 새로운 프로젝트를 빌드할 수 있다. </li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[API Gateway의 다양한 기능 (3) ]]></title>
            <link>https://velog.io/@w_yoon/API-Gateway%EC%9D%98-%EB%8B%A4%EC%96%91%ED%95%9C-%EA%B8%B0%EB%8A%A5-3</link>
            <guid>https://velog.io/@w_yoon/API-Gateway%EC%9D%98-%EB%8B%A4%EC%96%91%ED%95%9C-%EA%B8%B0%EB%8A%A5-3</guid>
            <pubDate>Fri, 02 Sep 2022 14:58:24 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이어서 API Gateway의 다양한 기능들에 대해 기술합니다. 
1.공통 로직 처리
2.Mediation : Message format transformation
3.프로토콜 변환
4.메시지 호출 패턴 변환 </p>
</blockquote>
<h3 id="공통-로직을-처리하여-중복-개발-비용을-줄이고-표준화-한다">공통 로직을 처리하여 중복 개발 비용을 줄이고 표준화 한다.</h3>
<p>앞서 API Gateway에서 인증과 인가 기능을 담당하는 것에 대해 이해했습니다. 한편으로 Authentication은 공통 로직이기 때문에 공통 계층에서 처리하게 되면 개발 중복을 줄일 수 있고 표준 준수가 더 쉽습니다. 공통적인 로깅도 마찬가지로 API Gateway에서 처리할 수 있습니다. </p>
<h3 id="메디에이션-기능mediation">메디에이션 기능(Mediation)</h3>
<ul>
<li>메디에이션이란 &quot;중재&quot; 또는 &quot;조정&quot;의 의미로, API 서버가 제공하는 API가 클라이언트가 원하는 API 형태와 다를때, API Gateway가 이를 변경해주는 기능이다. </li>
</ul>
<h4 id="--메시지-포맷-변환">- 메시지 포맷 변환</h4>
<ul>
<li><p>JSON으로 된 요청 메시지가 들어왔을 때, 이를 API 서버로 보낼때 변환해서 보내거나 API 서버에서 생성된 응답을 클라이언트에 리턴할때 변경해서 보내는 기능이다. </p>
</li>
<li><p>예를들어 클라이언트는 A라는 데이터만 필요한 경우, API 서버는 A부터 Z까지 데이터를 반환한다. 이 경우 모든 데이터를 받지않고 API Gateway에서 A만 리턴하도록 변경할 수 있다. 그러나 필요한 포맷에 맞는 API를 구성하는 것이 더 권장된다. </p>
</li>
</ul>
<h4 id="--프로토콜-변환">- 프로토콜 변환</h4>
<ul>
<li><p>프로토콜: 컴퓨터 사이에서 데이터를 교환하는 방식을 정의하는 규칙 체계입니다. 
프로토콜은 전송하고자 하는 데이터의 형식(Format), 부호화(Coding), 신호 레벨(Signal lebel)등을
규정합니다. 종류로는 HTTP, Telnet/ ASCII, JPEG, MIDI/ TCP, UDP/ IP, IPX...</p>
</li>
<li><p>다양한 서비스나 클라이언트를 지원하게 되면, 클라이언트나 서비스별로 다른 통신 프로토콜을 사용해야하는 경우가 있다. 웹에서는 JSON 기반의 REST가 많이 사용되나, 배나 비행기에 사용되는 센서들의 경우는 바이너리 기반의 경량 프로토콜을 사용하기도 한다. 이렇게 다양한 프로토콜을 지원해야할 때, 각 서비스들이 새롭게 구현하는 것이 아닌 API Gateway 계층에서 각 클라이언트에 맞는 프로토콜로 변환해주어 서비스할 수 있게 된다. </p>
</li>
</ul>
<h4 id="--메시지-호출-패턴-변환message-exchange-pattern">- 메시지 호출 패턴 변환(Message Exchange Pattern)</h4>
<ul>
<li><p>서버와 데이터를 주고 받는 2가지 방식 동기와 비동기. 동기는 서버가 요청한 작업을 끝낼때까지 기다리는통신으로 한번에 하니씩 통신하며 서버가 응답을 모두 끝내야 요청이 가능하다. 비동기는 서버가 작업을 끝낼때까지 기다리지 않는 통신이다. 서버에 요청이 저장 될 때까지 기다리지 않고 다른 작업을 진행할 수 있다. 
즉, 동시에 여러 통신이 가능하다. </p>
</li>
<li><p>API Gateway는 중간계층에서 동기 호출을 비동기 호출로 바꿔주거나 하나의 API 호출을 여러 데이터 센터로 복제 해준다거나 하는 형태의 메시징 패턴을 변화 시킬 수 있다. </p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/7d0e6cb8-f8f7-402c-917f-85eac12019ac/image.png" alt=""></p>
<ul>
<li>예를들어 로그를 수집하는 시스템에서 API gw 뒤에있는 로그저장 API 서버가 대용량 트래픽에 대한 대응능력이 없을때, API Gateway에서 메시지 큐를 이용하여 API 요청을 받고 바로 클라이언트에 ACK(확인 신호)를 준후에, 메시지큐 연동을 이용하여 메시지를 저장한 후 로그 저장 API 서버의 성능에 맞게 데이터를 흘려주는 방식입니다. 클라이언트 입장에서 동기 호출이나 실제 메시지 흐름은 큐를 이용한 비동기 구조입니다. </li>
</ul>
<h4 id="--messaage-queuemq란">- Messaage Queue(MQ)란?</h4>
<p>메시지 지향 미들웨어를 구현한 시스템을 의미합니다. 비동기 메시지를 사용하는 응용 프로그램 간의 데이터 송신 방법입니다. </p>
<ol>
<li>비동기: 큐(Queue)에 넣기 떄문에 나중에 처리할 수 있다. </li>
<li>비동조: 애플리케이션과 분리할 수 있다. </li>
<li>탄력성: 일부가 실패 시 전체가 영향을 받지 않는다. </li>
<li>과잉: 실패할 경우 재실행이 가능하다. </li>
<li>보증: 작업이 처리된 것을 확인 가능하다. </li>
<li>확장성: 다수의 프로세스들이 큐에 메시지를 보낼 수 있다. </li>
</ol>
<p>-메시지 큐잉(Message Queeing)은 대용량 데이터를 처리하기 위한 배치 작업이나, 채팅 서비스, 비동기 데이터를 처리할 때 사용한다. 정리하면, 프로세스 단위로 처리하는 웹 요청에 있어서 사용자가 많아지거나 데이터가 많아지면 요청에 대한 응답 시간이 증가한다. 이는 대기가 지연되고 서비스를 정상적으로 운용하는데 문제를 발생시킨다. 기존에 분산되어있던 데이터 처리를 한 곳에 집중하면서 메시지 브로커를 두어 필요한 프로그램에 작업을 분산시키는 방법을 사용하여 해결할 수 있다. </p>
<p>-오픈소스 메시지 큐 종류는 RabbitMQ, AcriveMQ, Kafka...등이 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[API Gateway와 Routing(2) ]]></title>
            <link>https://velog.io/@w_yoon/MSA%EC%99%80-API-Gateway%EC%97%90-%EB%8C%80%ED%95%9C-%EC%9D%B4%ED%95%B42</link>
            <guid>https://velog.io/@w_yoon/MSA%EC%99%80-API-Gateway%EC%97%90-%EB%8C%80%ED%95%9C-%EC%9D%B4%ED%95%B42</guid>
            <pubDate>Thu, 01 Sep 2022 09:31:45 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>API Gateway는 분산된 API 서버의 end point를 통합하고 기본적으로 API 호출을 위한 인증/ 인가 절차를 거칩니다. 그리고 API 호출을 라우팅할 수 있습니다! 알아봅시다. </p>
</blockquote>
<h3 id="road-balancer">Road Balancer</h3>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/4dd4fed9-359e-4b4f-a24f-805864b75c41/image.png" alt=""></p>
<ul>
<li>API gateway 뒷단에 다수의 API 서버가 있을 것입니다. 이때 다수의 API 서버로 부하를 분산하는 기능이 필요합니다. 각 서버의 하드웨어에 따라 부하의 가중치를 다르게 분산할 수도 있고, 로드 밸런싱이 일반적으로 가장 중요하게 쓰이는 상황은 서버 장애가 발생했을때 이를 감지하여 로드 밸런싱 리스트에서 제외하고 복구되었을때 다시 로드밸런싱 리스트에 포함하도록 한다. 
이러한 로드 밸런싱은 API 서버의 애플리케이션 상태를 인지해야 합니다. 따라서 IP 포트 상태뿐 아니라 쓰레드 수, 응답 시간 등으로 서버의 장애 상태를 파악할 수 있는 지표를 모니터링 해야합니다. </li>
</ul>
<h3 id="미들웨어로서-서비스-별-엔드포인트를-제공한다">미들웨어로서 서비스 별 엔드포인트를 제공한다.</h3>
<ul>
<li><p>같은 API를 여러개의 엔드포인트를 통해서 서비스를 제공할 수 있다. 예를들어 영상과 이미지를 처리하는 Media system을 다양한 서비스나 다양한 클라이언트에 제공할때, 각각 다른 서비스 별 또는 클라이언트 별로 다른 엔드포인트를 제공할 수 있다. </p>
</li>
<li><p>예를들어, Media system을 사용할 서비스가 커뮤니티 게시글/ 상품 상세/ 상품 후기를 지원합니다. 다음과 같이 클라이언트의 종류에 따라서 분리될 수 있습니다. 그리고 엔드포인트별로 노출하는 url을 다르게할 수 있습니다. </p>
</li>
</ul>
<blockquote>
<p>/community/media/... , /product/media/..., /review/media/...</p>
</blockquote>
<ul>
<li>멀티 서비스를 제공하는 플랫폼은 같은 API라도 클라이언트의 종류에 따라서 인증 방식, 보안 메커니즘, 포맷 형식이 다를 수 있기 때문에 각각 다른 API를 선별적으로 서비스 할 수 있도록 한다.</li>
</ul>
<h3 id="메시지-기반-라우팅">메시지 기반 라우팅</h3>
<ul>
<li><p>routing: 네트워크 안에서 통신 데이터를 보낼 때 최적의 경로를 선택하는 과정</p>
</li>
<li><p>메시지 내용을 기반으로 라우팅을 할 수 있다. 메시지는 REST API를 기준으로 HTTP URL, HTTP Header, HTTP Body 3가지로 구분된다. 메시지를 기반으로 라우팅 하기 위해서는 API gw가 이 메시지를 parsing 해야한다. </p>
</li>
<li><p>예를들어 글로벌 단위로 배포되는 시스템의 경우 country_code가 HTTP Body에 JSON으로 들어가 있다고 했을 때, API 호출에 대해서 라우팅 정보를 추출하기 위해서 매번 HTTP Body에 있는 JSON을 gw가 parsing 해야한다. 이는 경량화 목적의 gateway 역할에 부담을 준다. 따라서, 라우팅 정보를 Header로 옮긴다면 body를 parsing 하지않고 header만 parsing 한후, body 정보는 라우팅되는 서버로 그냥 forwarding만 해도 된다. </p>
</li>
</ul>
<blockquote>
<p>특정 조건에 따라 country_code = &quot;US&quot; 라는 메시지를 기준으로 라우팅 한다고 가정했을때, 중앙 집중형 시스템의 경우 각 지역에 있는 api gateway를 두고, 클라이언트는 미국 gateway를 호출할 것이다. 이때 데이터 복제가 필요할 수 있는데, 미국에 있는 gateway를 호출하면서 gw가 미국 API 서버와 유럽 API 서버를 동시에 호출해서 업데이트성 트렌젝션을 모든 데이터 센터에 복제함으로써 API를 통한 데이터 복제가 가능해진다. </p>
</blockquote>
<ul>
<li><p>따라서 메시지 기반 라우팅은 parsing에 대한 오버핸들링을 잘 고려하여, 가능한 HTTP URL이나 HTTP Header에 라우팅 필드를 넣는 것이 좋다. </p>
</li>
<li><p>HTTP Body의 데이터로 라우팅이 필요한 경우에는 호출 빈도가 적은 api라면 gateway에서 담당하고, 그게 아니라면 별도의 gateway 인스턴스, 즉 프로세스를 분리를 하거나 뒷단의 API 서버가 직접 라우팅을 하도록 할 수도 있을 것이다. </p>
</li>
</ul>
<blockquote>
<p><a href="https://bcho.tistory.com/1005?category=431297">https://bcho.tistory.com/1005?category=431297</a>
관련하여 잘 정리된 블로그의 도움을 많이 받았습니다. 좋은 글이니 읽어보세요 :) </p>
</blockquote>
<blockquote>
<p>다음 편에서는 공통로직 처리, 메시지 포맷 변환, 프로토콜 변환, aggregaion...등의 기능에 대해 작성해보겠습니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[MSA 아키텍쳐와 API Gateway의 이해 (1)]]></title>
            <link>https://velog.io/@w_yoon/MSA-%EC%95%84%ED%82%A4%ED%85%8D%EC%B3%90%EC%99%80-API-Gateway%EC%9D%98-%EC%9D%B4%ED%95%B4</link>
            <guid>https://velog.io/@w_yoon/MSA-%EC%95%84%ED%82%A4%ED%85%8D%EC%B3%90%EC%99%80-API-Gateway%EC%9D%98-%EC%9D%B4%ED%95%B4</guid>
            <pubDate>Thu, 01 Sep 2022 08:24:46 GMT</pubDate>
            <description><![CDATA[<p><strong>글을 시작하기에 앞서</strong></p>
<p>API 자동화 테스트를 구축하면서 어떻게 하면 Server-side에서 통합 테스트 시나리오를 구현할 수 있을까 고민했었다. 테스트 대상 프로덕트는 MSA를 지향하고 API gateway로 API 서버들을 엔드포인트를 통합하고 있었다. 따라서 로그인 기반의 API 서버를 테스트하려면 gw에서 정상적인 인증/인가 단계를 거쳐야했다. </p>
<p>당시에 api gateway 뒷단에서 인증 서버가 JSON Web token 방식으로의 전환을 위해 인증 개편을 진행하며 여러가지 노운이슈가 잔존했다. 자동화를 구축하는데 있어서 몇가지 문제를 발견했다. 내가 테스트 하고자 하는 대상은 API gateway 뒷단에 있는 API 서버였지만, 실제 User가 호출하는 엔드 포인트는 api gateway를 거친 통합 테스트 시나리오가 필요했다. </p>
<p>API 서버를 테스트하기 위해 api gw와 인증을 기술적으로 더 이해하기 위해 공부하고, 정상적인 사용자 인증 방식을 이해하기 위해 개발 스펙에 대해 서버 개발자들과 이야기를 많이 나누었다. 자동화 도중 token의 exp(유효기간)가 만료되는 문제도 있어서 JSON Web token 방식을 심층적으로 이해하고, payload를 parsing해서 exp의 validation을 판별하여 token을 재발급 받고 테스트를 위한 API를 호출 전 헤더에 배치하는 자동화 로직을 만들었다.</p>
<blockquote>
<p>POSTMAN의 pre-script에서 API를 호출하기 전 token의 exp를 먼저 판별하는 방식을 사용했습니다. </p>
</blockquote>
<p>이때 경험으로, 경량화된 서비스 개념과 미들웨어의 역할에 대해 더 알고싶어졌다. QA Engineering에 있어서도 자동화를 한다면, 자동화 대상이 되는 서비스의 아키텍처를 이해하는 것이 필수적이라고 생각한다. 아키텍처를 잘 몰라도 자동화는 할 수 있다. 하지만 반복적인 작업을 자동화하는 것과는 별개로 그것이 프로덕트 품질을 얼마나 효율적으로 컨트롤 할 수 있는지, 그래서 얼마나 리스크를 식별하고 나아가 줄일 수 있는지는 완전히 다른 이야기가 될 수 있다고 생각한다. 따라서 이번 글에서는 MSA 아키텍처와 API gateway에 대한 내용을 정리해보려고 한다. </p>
<h3 id="msa-그리고-api-gateway">MSA 그리고 API Gateway</h3>
<ul>
<li><p>MSA(Micro Service architecture)</p>
<ul>
<li>전통적인 웹 시스템 개발 스타일의 Monolithic Architecture에서 대규모 분산 웹시스템에 적합하게 경량화된 개념이다. 근간은 SOA(Service Oriented Architecture: 서비스 지향 아키텍처)에 두고 있다. 각 컴포너트를 서비스라는 개념으로 정의하고, 서비스는 일반적으로 도메인(업무)의 경계를 따른다. </li>
</ul>
</li>
<li><p>API gateway </p>
<ul>
<li>api 서버 앞단에서 모든 api 서버들의 엔드포인트를 단일화하여 통합하고 API에 대한 인증/인가 기능부터 메세지에 따라서 여러 서버로 라우팅하는 기능까지 다양한 기능을 추가로 제공한다. API gateway는 JSON/REST 기반의 최소한의 기능을 처리하는 경량화 서비스이다. MSA 아키텍쳐에서 API gateway가 어떤 역할들을 하는지 알아보자</li>
</ul>
</li>
</ul>
<h3 id="msa에서-api-gateway의-주요-기능">MSA에서 API Gateway의 주요 기능</h3>
<p>*<em>1. 마치 프록시 서버처럼 API 앞단에서 end point를 통합한다. *</em></p>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/29fc0724-ff9e-4e7a-8728-f55c2bd1f6fe/image.png" alt=""></p>
<pre><code>- 마이크로 서비스 아키텍처의 문제점 중의 하나는 서비스가 다른 서버들에 분리되기 때문에, API의 
end point가 각기 다르다는 것이다. 즉 서버의 URL이 모두 다르게 된다. API가 두 시스템, 
어플리케이션이 상호작용 할 수 있게 하는 프로토콜의 총 집합이라면 end point는 api가 서버에서
리소스에 접근할 수 있도록 가능하게 하는 URL이다. </code></pre><p>마이크로 서비스 아키텍쳐는 컴포넌트를 업무 단위로 잘게 쪼개는 방식을 지향하기 때문에, 컴포넌트의 url은 
회원 관리, 상품 구매, 포인트 적립 등과 같이 대규모 개발 시스템일 수록 더 많이 늘어나게 될 것이다. API를 사용하는 클라이언트에서 서버간 통신이나 서버간 API 통신의 경우 p2p(Point to Point)형태로 Topology(링크, 노드 등이 물리적으로 연결되는 방식)가 복잡해짐에 따라 향후 유지보수에 문제를 야기할 수 있다. 이러한 문제를 해결하기 위해 <strong>중앙에 api gw라는 허브를 배치시켜 서비스간 호출을 단순화 할 수 있다.</strong> 
<img src="https://velog.velcdn.com/images/w_yoon/post/32ba9a55-ec12-4ea7-8167-3292d8470702/image.png" alt=""></p>
<p>*<em>2. 가장 기본적인 기능은 API 호출에 대한 인증과 인가 *</em></p>
<ul>
<li><p>API를 호출하기 전 인증이 필요하다.
클라이언트를 인증하는 방법은 다양하다. id, password 입력또는 지문 등등. 인증이 완료되었다면 token을 발급하게 된다. 그 후는 발급 받은 token을 가지고 API를 호출할 수 있는 권한이 있는지 확인이 필요하다. token 자체가 이러한 정보를 갖는 형태를 클레임 기반의 token이라고 하는데, JWT(JSON Web Token) 방식이 이에 해당한다. 아래와 같은 흐름이다. </p>
<p>(1) 클라이언트는 API Gateway에 id, password를 전달한다. 
(2) API gateway는 전달 받은 인증정보를 인증 서버에 전달한다. 
(3) 인증 서버는 인증을 수행한다. 
(4) 인증이 성공할 경우 token과 함께 API gateway에 반환한다. 
(5) API gateway는 클라이언트에 token을 응답한다. 
(6) 클라이언트는 가지고있는 token으로 호출하고자 하는 API에 access 한다. 
   ( 이때, API에 호출할 수 있는 token인지 권한을 검증하는 단계를 api gw가 중간에서 결정한다.)</p>
</li>
</ul>
<ul>
<li>인증(Authentication)과 인가(Authorization)
인증은 API를 호출 하는 것이 철수가 맞다는 것을 확인해준다면, 인가는 철수가 관리자 페이지에 접근할 수 있는 관리자 권한을 가지고 있는지 확인해주는 것과 같다.** token에는 제한적으로 권한을 부여할 수 있다.** 직접 권한을 토큰에 연결하지 않고, ROLE이라는 개념을 두고 역할별로 권한을 연결한 다음에, 이 ROLE을 token에 부여하는 개념이다. *<em>일반 사용자용 기능들과 관리자용 기능들을 ROLE이라는 기준으로 분리하고, 이 ROLE을 token에 부여한다. 이를 RBAC(Role Based Access Control)이라고 한다. *</em></li>
</ul>
<blockquote>
<p><a href="https://bcho.tistory.com/1005?category=431297">https://bcho.tistory.com/1005?category=431297</a> 
  이 블로그에서 관련 내용이 아주 잘 정리되어 있어서 도움이 많이 되었습니다. 참고하여 글을 작성하였습니다. 
  다음 글에서는 API 라우팅 기능에 대해서 정리해보겠습니다. </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git 버전관리  _ Staging을 위한 명령어]]></title>
            <link>https://velog.io/@w_yoon/Git-%EB%B2%84%EC%A0%84%EA%B4%80%EB%A6%AC-1-Staging%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%AA%85%EB%A0%B9%EC%96%B4%EB%93%A4</link>
            <guid>https://velog.io/@w_yoon/Git-%EB%B2%84%EC%A0%84%EA%B4%80%EB%A6%AC-1-Staging%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%AA%85%EB%A0%B9%EC%96%B4%EB%93%A4</guid>
            <pubDate>Tue, 28 Jun 2022 14:30:23 GMT</pubDate>
            <description><![CDATA[<blockquote>
<ul>
<li>*<em>Git 버전관리는 왜 필요할까? *</em><ul>
<li>협업을 위해 버전관리는 필수입니다. 지속적으로 발생하는 수정 사항 단위로 버전을 구분하고 최종으로 업데이트 된 파일을 직관적으로 파악하는데 용이합니다. 저는 POSTMAN collection 그리고 environment file의 형상 및 버전관리를 위해 Git을 사용하였습니다. 그리고 jenkins에서 git으로부터 최산화된 코드를 불러와 자동으로 빌드할 수 있도록 하였습니다.</li>
</ul>
</li>
</ul>
</blockquote>
<h2 id="commit-">Commit ?</h2>
<p>코드에 수정 사항이 발생할 때 로컬에서 원격 저장소로 수정 사항을 반영하기 위해 커밋을 발생시킵니다. 
이 때 커밋 단위로 커밋 버전이 생성되며 이를 통해 버전관리가 가능합니다. 다만 우리는 commit 해서 원격 저장소에 수정사항을 직접 반영하기 전에 커밋할 작업 파일들을 먼저 선택할 수 있습니다. 이것을 Stage에 올린다고 표현합니다. </p>
<p>   <img src="https://velog.velcdn.com/images/w_yoon/post/a009f24c-5cca-4048-9612-c35aa3bf91b2/image.png" alt=""></p>
<h2 id="stage-it-">Stage it !</h2>
<h4 id="1-git-clone-repository-url-">(1) *<em>Git clone {repository url} *</em></h4>
<ul>
<li>내 로컬 저장소에 레파지토리 파일을 생성합니다. 로컬에서 한번만 실행하면 됩니다.</li>
<li>최초 접속 시 user.name과 personal access token을 입력합니다. 
<img src="https://velog.velcdn.com/images/w_yoon/post/d5a0149d-899c-4291-95e0-4b5612bed002/image.png" alt=""></li>
</ul>
<h4 id="2-cd-repository-file-adress-">(2) *<em>cd {repository file adress} *</em></h4>
<ul>
<li>로컬 저장소로 이동하기 
<img src="https://velog.velcdn.com/images/w_yoon/post/f2fa1d96-7605-440e-afa6-07dd5d2f10ed/image.png" alt=""></li>
</ul>
<h4 id="3-git-branch-git-checkout-branch-name-">(3) *<em>git branch/ git checkout {branch name} *</em></h4>
<ul>
<li>git branch 명령어로 현재 branch를 확인할 수 있습니다.</li>
<li>git checkout &quot;브랜치명&quot; 명령어로 원하는 branch로 전환할 수 있습니다.</li>
<li>git branch &quot;브랜치명&quot; 명령어로 branch를 생성할 수 있습니다. 
<img src="https://velog.velcdn.com/images/w_yoon/post/29ec9cc4-0851-439f-9419-776110b1972d/image.png" alt=""></li>
</ul>
<p>_[comment] 여기까지 되었다면 이제 커밋할 준비가 된 것 같습니다 :) _</p>
<h4 id="4-git-status">(4) <strong>git status</strong></h4>
<ul>
<li>수정사항이 발생한 파일을 로컬 저장소에 저장합니다. </li>
<li>git status 명렁어로 Tracked 상태의 파일을 확인할 수 있습니다. 아직 stage에 올리지 않았기에 로컬에 저장한 파일을 확인할 수 없습니다. 이 상태를 Untracked 상태라고 합니다. </li>
</ul>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/a9c8765e-390d-4f60-986f-47afb9fe7edd/image.png" alt=""><img src="https://velog.velcdn.com/images/w_yoon/post/78026577-4012-4542-9ac9-436cdd612c5f/image.png" alt=""></p>
<h4 id="5-git-add-file-name-">(5) *<em>git add {file name} *</em></h4>
<ul>
<li>수정사항이 발생한 파일을 커밋하기 전에 먼저 stage에 올립니다. </li>
<li>stage에 올린 후 git status 명령어로 커밋할 파일이 Untracked -&gt; Tracked 상태로 전환된 것을 확인할 수 있습니다. 상세한 상태는 Unmodified, Modified, Staged 중 Modified 입니다. 
staging area에 있는 파일들을 커밋하게 되면 해당 파일들은 하나의 커밋으로 저장된 후, 파일의 상태는 Unmodified로 내려오게 됩니다. Unmodified 상태의 파일들을 수정하게 되면 Modified 상태가 됩니다. </li>
</ul>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/96f5a770-3399-463d-bcc0-183549a5a878/image.png" alt=""></p>
<p><em>[comment] 여러개의 파일을 한번에 스테이지에 올리고 싶다면 git add {file1} {file2} ... {file3} 의 형식으로 가능합니다!</em></p>
<h4 id="6-git-commit--m-commit-message">(6) <strong>git commit -m {commit message}</strong></h4>
<ul>
<li>변경 사항에 대한 추적과 원활한 협업을 위해 수정 사항에 대한 간략한 내용을 커밋 메시지에 입력합니다. </li>
</ul>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/bdc0ba29-497b-4913-97f4-bfb481456668/image.png" alt=""></p>
<h4 id="7-git-push-origin-branch-name">(7) <strong>git push origin {branch name}</strong></h4>
<ul>
<li>로컬 저장소의 변경사항을 원격 저장소로 push 합니다. </li>
</ul>
<p><img src="https://velog.velcdn.com/images/w_yoon/post/df6d5c14-a3fd-4aad-89f1-3bdb9197e9af/image.png" alt=""></p>
<ul>
<li><p>혹시 원격 저장소에 연결이 되어있는지 확인이 필요하다면 git remote -v 명령어로 연결된 원격 저장소를 확인합니다. 
<img src="https://velog.velcdn.com/images/w_yoon/post/5a5787a5-56df-4215-b7f9-76c9e371f79d/image.png" alt=""></p>
</li>
<li><p>원격 저장소에 연결이 안되어있다면 다음 명령어로 연결해줍시다. 
  <strong>git remote add origin {repository url}</strong></p>
</li>
</ul>
<p><em>[comment] 이제 로컬에서 원격 저장소로 수정사항을 반영하고 커밋 버전으로 관리가 가능하게 되었습니다!
커밋 버전과 히스토리는 ** git log **명령어로 확인이 가능합니다.</em> <img src="https://velog.velcdn.com/images/w_yoon/post/d9992873-b4b0-489e-b90b-cfdede82632a/image.png" alt=""></p>
<h4 id="8-git-pull-">(8) *<em>git pull *</em></h4>
<ul>
<li>원격 저장소에서 변경사항이 있을때 원격 저장소와 로컬 저장소의 상태를 동일하게 업데이트할 수 있습니다. <img src="https://velog.velcdn.com/images/w_yoon/post/1a69cba0-dd46-4d38-ba41-21251c1e20f1/image.png" alt=""></li>
</ul>
<p>_[comment] 이미 업데이트 상태라고 하네요. 변경사항이 있다면 변경사항이 뜨겠죠? :) _</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[postman으로 api test하기(2) ]]></title>
            <link>https://velog.io/@w_yoon/postman%EC%9C%BC%EB%A1%9C-api-test%ED%95%98%EA%B8%B02</link>
            <guid>https://velog.io/@w_yoon/postman%EC%9C%BC%EB%A1%9C-api-test%ED%95%98%EA%B8%B02</guid>
            <pubDate>Wed, 02 Mar 2022 14:59:12 GMT</pubDate>
            <description><![CDATA[<h3 id="무엇을-테스트할-것인가">무엇을 테스트할 것인가?</h3>
<p><img src="https://images.velog.io/images/w_yoon/post/ee1f5671-4caf-4b40-abb2-f28487cc6315/image.png" alt="">
커뮤니티 서비스에서 가장 기본적이라고 할 수 있는 사용자 인터페이스인 게시글 생성/ 조회/ 수정/ 삭제 기능을 api test해볼 것이다. </p>
<h3 id="무엇을-위해서">무엇을 위해서?</h3>
<p><img src="https://images.velog.io/images/w_yoon/post/e969d2f7-21e9-4a8f-90e0-0100c5538f36/image.png" alt=""></p>
<p>1) 클라이언트 개발 완료 전에 서버 먼저 검증하여 테스트 시점을 앞당길 수 있고 발생 가능한 이슈를 빠르게 식별할 수 있다. 또한 QA 진행 가능한 상태인지 빠르게 Smoke Test 가능하다. 빌드에서 테스트를 시작하기 전 커뮤니티 도메인의 주요한 API들을 Server -side에서 사이드 이펙트를 자동으로 거르고 시작함으로써 테스트 비용과 지연 가능성을 줄이는 것을 목표로 한다.</p>
<p>2) 당시에 모바일 앱에서 인증 이슈로 인하여 로그인 세션이 포함된 쿠키를 삭제할 방법이 필요했다. (로그아웃을 했지만 로그인 세션이 초기화 되지않고 남아있는 노운이슈가 있는 상태...) 정상적인 통합 테스트를 위하여 api test를 통해 로그인 세션을 초기화하여 데이터를 생성하고 싶었다. </p>
<p>3) 반복 테스트에 대한 자동화 </p>
<h3 id="게시글을-create-read-update-delete하기">게시글을 Create/ Read/ Update/ Delete하기</h3>
<ul>
<li>HTTP 메소드를 사용하여 api test를 해보자. </li>
</ul>
<ol>
<li><p>로그인 - <strong>POST</strong>
로그인은 user email과 password를 body에 multipart-form-data 형식으로 보내줄 거기 때문에 POST 메소드를 사용한다. </p>
</li>
<li><p>내가 쓴 게시글 목록 조회 - <strong>GET</strong>
데이터 조회는 넘겨줄 body가 없다. GET 메소드를 쓴다. </p>
</li>
<li><p>게시글 생성 - *<em>POST *</em>
게시글을 생성하기 위해서는 로그인 정보가 꼭 필요하다. 로그인 후 생성된 쿠키를 Headers에 포함한다. 게시글 생성을 위한 데이터를 json 형식으로 body에 넣어 보내준다. </p>
</li>
<li><p>생성한 게시글 조회 - *<em>GET *</em>
방금 생성한 게시글의 postId를 collection 변수로 선언하고 고걸 가져와 조회한다. </p>
</li>
<li><p>게시글 수정 - *<em>PUT *</em>
방금 생성한 게시글의 postId를 가져오고 해당 게시글에 body를 새로 보내 대체시킨다. </p>
</li>
<li><p>게시글 삭제 - *<em>DELETE *</em>
방금 생성한 게시글의 postId를 가져와 해당 게시글을 삭제한다. </p>
</li>
</ol>
<h3 id="다음-글에서는">다음 글에서는</h3>
<p><img src="https://images.velog.io/images/w_yoon/post/01efb670-6d39-438e-82b7-32a5c6f5bf6f/image.png" alt=""></p>
<p>response에서 무엇을 얻어내 테스트 결과를 만들 것인지 작성해보겠습니다. </p>
<ul>
<li>response json data에서 데이터를 뽑아내 변수 선언하기</li>
<li>그 변수를 {uri}에 활용하여 가변적으로 api test하기</li>
<li>pre-request Script 작성하기 </li>
<li>test Script 작성하기 </li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[postman으로 api 테스트 하기(1)]]></title>
            <link>https://velog.io/@w_yoon/postman%EC%9C%BC%EB%A1%9C-api-%ED%85%8C%EC%8A%A4%ED%8A%B8-%ED%95%98%EA%B8%B01</link>
            <guid>https://velog.io/@w_yoon/postman%EC%9C%BC%EB%A1%9C-api-%ED%85%8C%EC%8A%A4%ED%8A%B8-%ED%95%98%EA%B8%B01</guid>
            <pubDate>Wed, 02 Mar 2022 14:23:23 GMT</pubDate>
            <description><![CDATA[<h2 id="-왜-api-테스트를-해야할까-">** 왜 api 테스트를 해야할까? **</h2>
<p><img src="https://images.velog.io/images/w_yoon/post/9dc0c414-a0b1-4668-8307-24b1645075a8/image.png" alt=""></p>
<ol>
<li><p>빠른 테스트 속도
API 문서를 기반으로 리퀘스트 호출, 리스폰스 확인으로 UI 테스트에 비해 속도가 빠르다.</p>
</li>
<li><p>모바일, PC OS 환경 영향을 받지 않는다.
클라이언트 테스트와 달리 대부분 API 테스트는 OS의 영향을 받지 않는다. 
(※물론 userAgent 관련된 API는 OS 영향을 받을 수도 있다.)</p>
</li>
<li><p>테스트 시점을 앞당길 수 있다.
클라이언트 개발이 완료되기 전에 API 테스트로 미리 기능 테스트 가능하다.</p>
</li>
<li><p>자동화로 리그레션 테스트 비용을 절감
수정된 API가 있을 경우 관련된 API의 리그레션 테스트를 자동화로 빠르게 테스트 가능하다.</p>
</li>
<li><p>테스트 커버리지를 높일 수 있다.
UI 테스트와 병행하여 테스트 커버리지를 높일 수 있다. </p>
</li>
</ol>
<h3 id="1--postman이란">1.  postman이란?</h3>
<p>API 개발을 위한 협업 플랫폼으로, API 구축의 단계를 단순화하고 협업을 능률화하여 더나은 API를 빠르게 만들 수 있다.</p>
<p>Postman을 통해서 서버의 요청/응답 상태를 확인할 수 있고, HTTP 메소드를 직관적으로 확인해볼 수 있는 편리한 인터페이스를 가지고 있다.</p>
<h3 id="2-postman을-선택한-이유"><strong>2. postman을 선택한 이유</strong></h3>
<p>HTTP 메소드로 API를 테스트하기에 가장 접근성 좋고 기본적인 테스트를 수행하기에 높은 활용도를 가지고 있는 trial version을 가지고 있다. Test suite를 관리하기에 직관적인 계층형 구조(Collection - (folder) - request)이고 java script를 사용한다. 개인적으로 python을 사용하여 api test를 해보는 것을 장기적인 목표로 두고 있지만 모델링 등에 시간을 줄이고 SWAGGER와 API 명세에 따라 모델링을 크게 신경쓰지 않더라도 직관적으로 테스트 케이스 추가 용이한 장점을 가지고 빠르게 api test를 도입하기 위해 선택했다. 
그리고 사내 몇몇 서버 개발자분들도 postman으로 단위테스트를 하는 것을 알게되면서 더 잘 소통할 수 있지 않을까라는 기대를 살짝 가져보았다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CI/ CD를 위한 테스트 방향성]]></title>
            <link>https://velog.io/@w_yoon/CI-CD%EB%A5%BC-%EC%9C%84%ED%95%9C-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%B0%A9%ED%96%A5%EC%84%B1</link>
            <guid>https://velog.io/@w_yoon/CI-CD%EB%A5%BC-%EC%9C%84%ED%95%9C-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%B0%A9%ED%96%A5%EC%84%B1</guid>
            <pubDate>Fri, 18 Feb 2022 16:14:16 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/w_yoon/post/ffe176f7-c923-429d-a34e-131413dcf2b2/image.png" alt=""></p>
<ul>
<li>어떤 프로덕트가 품질이 좋다고 할 수 있는가? <blockquote>
<p>이건 프로덕트마다 다르지 않을까 하는 생각이 요즘 새롭게 들고있다. 원래 생각이라면 기본적으로 기획대로 동작하며 기획되지 않은 예외 케이스들까지 탐색적으로 이슈 및 개선 사항을 찾아 좋은 UX를 제공하는 프로덕트가 품질이 높다고 생각했다. 소프트웨어를 사용자에게 빈번하게 전달할 수 있도록 하여 가치를 제공하고 제품이 실제로 어떻게 사용되는지 빠르게 피드백을 얻기 위해 지속적 통합 및 배포를 하는 조직에서는 어떻게 품질을 제고할 수 있을까? 더 빨리 전달해야한다는 비즈니스적 압박이 생산되는 제품의 품질을 저하해서는 안된다. 사업적으로 혁신적인 아이디어와 기능을 제공하더라도, 사용자는 안정적으로 작동하는 소프트웨어를 기대하기 때문이다. </p>
</blockquote>
</li>
</ul>
<ul>
<li>선형적 접근 방식을 넘어서 <blockquote>
<p>소프트웨어 테스트는 품질을 보장하는 데 필수적이다. QA 단계가 코드 개발 및 통합 이후의 단계가 된다면 릴리스 프로세스가 지연될 리스크를 안게 된다. 짧은 반복 주기와 애자일 접근 방식에서 새로운 코드가 적절히 작동하는지, 다른 코드의 손상은 없는지 빠르게 검증하는 일은 필수적일 것이다. 테스트는 파이프라인 전체의 여러 단계에서 수행되어야 할 것이다. CI/ CD의 핵심은 팀에서 최대한 빨리 문제를 파악할 수 있게 지원하는 긴밀한 피드백 루프이다. </p>
</blockquote>
</li>
</ul>
<ul>
<li>자동화는 수동 테스트의 종말일까? <blockquote>
<p>자동화는 리소스 효율을 높인다. 반복 작업에 시간을 소비하는 대신 테스터는 테스트 케이스를 정의하고, ATC를 작성하고, 탐색 테스트를 통해 창의성과 독창성을 발휘하여 기획과 개발에서 누락된 다양한 케이스에 대한 검증 하는데 집중할 수 있다. 탐색 테스트가 점차 수동적이고 반복적인 테스트로 변질되어서는 안된다. 탐색 테스트의 취지는 매번 동일한 테스트 세트를 수행하지 않는 것이다. 메뉴얼 테스트는 테스트의 목적이 될 수 없다. 테스터의 시간을 효율적으로 사용하려면 자동화된 테스트를 모두 통과한 후에 수동 테스트를 실시해야 한다. QA에게 무엇을 자동화 할지, 어떻게 자동화 할 수 있을지에 대한 고민은 이제 필수가 되어버린 것 같다. </p>
</blockquote>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>