<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>퉁그리노트</title>
    <link>https://toongri.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 8 Jul 2026 00:06:09 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>퉁그리</managingEditor>
    <item>
      <title>[DevOps] AWS CDK</title>
      <link>https://toongri.tistory.com/100</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;AWS CDK(AWS Cloud Development Kit)는 현대적&lt;span&gt; &lt;/span&gt;프로그래밍&lt;span&gt; &lt;/span&gt;언어를&lt;span&gt; &lt;/span&gt;사용하여&lt;span&gt; &lt;/span&gt;클라우드&lt;span&gt; &lt;/span&gt;인프라를&lt;span&gt; &lt;/span&gt;코드로&lt;span&gt; &lt;/span&gt;정의하고&lt;span&gt; AWS CloudFormation&lt;/span&gt;을&lt;span&gt; &lt;/span&gt;통해&lt;span&gt; &lt;/span&gt;배포하는&lt;span&gt; &lt;/span&gt;오픈&lt;span&gt; &lt;/span&gt;소스&lt;span&gt; &lt;/span&gt;소프트웨어&lt;span&gt; &lt;/span&gt;개발&lt;span&gt; &lt;/span&gt;프레임워크이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콘솔을 사용하지 않고 Iac를 사용하며 생기는 장점은 코드를 통해 인프라를 관리하고 프로비저닝 함으로써, 오류감소, 비용 절감, 일관성, 버전 관리 등이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Iac(Infrastructure as Code) 코드형 인프라는 수동 프로세스가 아닌 코드를 통해 인프라를 관리하고 프로비저닝하는 것을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 Iac에 비해 cdk가 주는 장점은 AWS Toolkit 활용이 가능하며, 상위 레벨의 다양한 언어로 구현가능하다는 장점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 프로비저닝 : it 인프라를 설정하는 프로세스. 사용자와 시스템에서 사용할 수 있도록, 데이터와 리소스에 대한 액세스를 관리하는 데 필요한 단계를 지칭하기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;cdk 프로젝트의 기본 구조&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;763&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpo4y2/btrIin7BKpm/PyHsiKPnMICXyFRlkvdmt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpo4y2/btrIin7BKpm/PyHsiKPnMICXyFRlkvdmt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpo4y2/btrIin7BKpm/PyHsiKPnMICXyFRlkvdmt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbpo4y2%2FbtrIin7BKpm%2FPyHsiKPnMICXyFRlkvdmt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;763&quot; height=&quot;432&quot; data-origin-width=&quot;763&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cdk는 aws 환경에 배포할 수 있는 스택 및 하나 이상의 스택 모음인 앱으로 함께 구성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1409&quot; data-origin-height=&quot;575&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbyg7q/btrIeLm4gKF/KqkmtejtDOBcdj0z3dlQRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbyg7q/btrIeLm4gKF/KqkmtejtDOBcdj0z3dlQRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbyg7q/btrIeLm4gKF/KqkmtejtDOBcdj0z3dlQRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcbyg7q%2FbtrIeLm4gKF%2FKqkmtejtDOBcdj0z3dlQRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1409&quot; height=&quot;575&quot; data-origin-width=&quot;1409&quot; data-origin-height=&quot;575&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bin에 들어가는 파일은 cdk 프로젝트의 진입점이다. lib에서 만든 스택들을 이 곳에 불러와야 사용할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6번째 줄처럼 스택들을 생성하여 연결하는 역할을 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1411&quot; data-origin-height=&quot;582&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pPXYX/btrIn0o4uhp/hcCBxnaIxNQuIzqhkCm83K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pPXYX/btrIn0o4uhp/hcCBxnaIxNQuIzqhkCm83K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pPXYX/btrIn0o4uhp/hcCBxnaIxNQuIzqhkCm83K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpPXYX%2FbtrIn0o4uhp%2FhcCBxnaIxNQuIzqhkCm83K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1411&quot; height=&quot;582&quot; data-origin-width=&quot;1411&quot; data-origin-height=&quot;582&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;lib폴더안에 있는 파일들은 bin에 들어있는 파일들의 스택들을 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스택 클래스들은 기본적으로 Stack클래스를 상속받으며 생성자를 통해서 AWS서비스들을 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드의 내용은 sqs(amazon simple queue service)와 sns(amazon simple notification service)을 만들어서 연결을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sqs는 기본적으로 첫번째 파라미터로 scope, 두번째 파라미터로 id를, 세번째 파라미터로  props를 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sns는 기본적으로 props를 따로 받지 않고, addSubscription이라는 함수를 통해 sqs를 이어 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;cdk 배포&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;457&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVKBss/btrIekQUk34/3kNCOpiyj8UqyHqX3As4d0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVKBss/btrIekQUk34/3kNCOpiyj8UqyHqX3As4d0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVKBss/btrIekQUk34/3kNCOpiyj8UqyHqX3As4d0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVKBss%2FbtrIekQUk34%2F3kNCOpiyj8UqyHqX3As4d0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;457&quot; height=&quot;242&quot; data-origin-width=&quot;457&quot; data-origin-height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. cdk synth =&amp;gt; cdk -&amp;gt; cloudformation 템플릿으로 변환하는 명령어이다. 명령어 실행 후에 cdk.out 이라는 폴더에서 cloudformation으로 어떻게 변환되었는지 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. cdk diff =&amp;gt; 기존의 배포되어있는 스택과 비교하여 어떤 점이 변경되었는가를 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.5 cdk bootstrap =&amp;gt; 최초에 deploy전 실행을 해줘야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3 cdk deploy and y =&amp;gt; 배포 명령어이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4 cdk destroy =&amp;gt; 스택을 지우는 명령어이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;aws cdk api 독스 주소&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/v2/docs/aws-construct-library.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.aws.amazon.com/cdk/api/v2/docs/aws-construct-library.html&lt;/a&gt;&lt;/p&gt;</description>
      <category>DevOps</category>
      <author>퉁그리</author>
      <guid isPermaLink="true">https://toongri.tistory.com/100</guid>
      <comments>https://toongri.tistory.com/100#entry100comment</comments>
      <pubDate>Tue, 26 Jul 2022 20:11:16 +0900</pubDate>
    </item>
    <item>
      <title>[DevOps] Dockerfile 명령어</title>
      <link>https://toongri.tistory.com/99</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;도커를 활용해 컨테이너화를 시키는 데에 있어서 필수적인 작업 중 하나는 docker image를 생성하는 것이며, 이는 프로젝트 최상위 디렉토리에서 Dockerfile을 통해 생성하고 설정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dockerfile은 Docker image을 어떠한 과정을 통해 빌드가 되는지를 담고 있는 파일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;포맷&lt;/h3&gt;
&lt;pre id=&quot;code_1658378174031&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;명령어(INSTRUCTION) 인자(arguments)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 명령문은 명령어로 시작하고 여러개의 인자로 끝난다. 인자와 구분이 쉽도록 명령어는 대문자로 써주는 것이 관례이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;FROM&lt;/h3&gt;
&lt;pre id=&quot;code_1658378330750&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM &amp;lt;이미지&amp;gt;
FROM &amp;lt;이미지&amp;gt;:&amp;lt;태그&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 Docker 이미지는 base 이미지부터 시작해서 기존 이미지 위에 새로운 이미지를 중첩해서 여러 단계의 이미지 층(layer)을 쌓아가며 만들어진다. FROM 명령문은 이 base 이미지를 지정해주기 위해서 사용되는데, 보통 Dockerfile 내에서 최상단에 위치한다. base 이미지는 일반적으로 Docker hub와 같은 Docker Hub와 같은 Docker repository에 올려놓은 잘 알려준 공개 이미지인 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Ubuntu 최신 버전을 base 이미지로 사용&lt;/p&gt;
&lt;pre id=&quot;code_1658379197410&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM ubuntu:latest&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- NodeJS 12를 base 이미지로 사용&lt;/p&gt;
&lt;pre id=&quot;code_1658379242148&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM node:12&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Python 3.8(alpine 리눅스 기반)을 base 이미지로 사용&lt;/p&gt;
&lt;pre id=&quot;code_1658379277663&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM python:3.8-alpine&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;WORKDIR&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WORKDIR 명령문은 컨테이너 상에서 작업 디렉토리로 전환을 위해서 사용된다. WORKDIR 명령문으로 작업 디렉토리를 전환하면 그 이후에 등장하는 모든 RUN, CMD, ENTRYPOINT, COPY, ADD 명령문은 해당 디렉토리를 기준으로 실행된다.&lt;/p&gt;
&lt;pre id=&quot;code_1658379491219&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;WORKDIR &amp;lt;이동할 경로&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;RUN&lt;/h3&gt;
&lt;pre id=&quot;code_1658379661027&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RUN [&quot;&amp;lt;커맨드&amp;gt;&quot;, &quot;&amp;lt;파라미터1&amp;gt;&quot;, &quot;&amp;lt;파라미터2&amp;gt;&quot;]
RUN&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RUN 명령문은 이미지 빌드 과정에서 필요한 커맨드를 실행하기 위해서 사용된다. RUN 명령문으로 할 수 있는 작업은 많지만 보통 이미지 안에 특정 소프트웨어를 설치하기 위해서 많이 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- curl 도구 설치&lt;/p&gt;
&lt;pre id=&quot;code_1658380089191&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RUN apk add curl&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- npm 패키지 설치&lt;/p&gt;
&lt;pre id=&quot;code_1658380111945&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RUN npm install --silent&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- pip 패키지 설치&lt;/p&gt;
&lt;pre id=&quot;code_1658380136851&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RUN pip install -r requirements.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- apache 서버를 설치&lt;/p&gt;
&lt;pre id=&quot;code_1658393791924&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RUN apt-get install -y apache&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ENTRYPOINT 명령문&lt;/h3&gt;
&lt;pre id=&quot;code_1658380239441&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ENTRYPOINT [&quot;&amp;lt;커맨드&amp;gt;&quot;, &quot;&amp;lt;파라미터1&amp;gt;&quot;, &quot;&amp;lt;파라미터2&amp;gt;&quot;]
ENTRYPOINT &amp;lt;전체 커맨드&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ENTRYPOINT 명령문은 이미지를 컨테이너로 띄울 때 항상 실행되야 하는 커맨드를 지정할 때 사용한다. ENTRYPOINT 명령문은 Docker 이미지를 마치 하나의 실행 파일처럼 사용할 때 유용하다. 그 이유는 컨테이너가 뜰 때 ENTRYPOINT 명령문으로 지정된 커맨드가 실행되고, 이 커맨드로 실행된 프로세스가 죽을 때, 컨테이너도 따라서 종료되기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- npm start 스크립트 실행&lt;/p&gt;
&lt;pre id=&quot;code_1658380618824&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ENTRYPOINT [&quot;npm&quot;, &quot;start&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Django 서버 실행&lt;/p&gt;
&lt;pre id=&quot;code_1658380648902&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ENTRYPOINT [&quot;python&quot;, &quot;manage.py&quot;, &quot;runserver&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CMD&lt;/h3&gt;
&lt;pre id=&quot;code_1658380783958&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CMD [&quot;&amp;lt;커맨드&amp;gt;&quot;, &quot;&amp;lt;파라미터1&amp;gt;&quot;, &quot;&amp;lt;파라미터2&amp;gt;&quot;]
CMD [&quot;&amp;lt;파라미터1&amp;gt;&quot;, &quot;&amp;lt;파라미터2&amp;gt;&quot;]
CMD &amp;lt;전체 커맨드&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CMD 명령문은 해당 이미지를 컨테이너로 띄울 때 디폴트로 실행할 커맨드나, ENTRYPOINT 명령문으로 지정된 커맨드에 디폴트로 넘길 파라미터를 지정할 때 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1658381188811&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ENTRYPOINT [&quot;node&quot;]
CMD [&quot;index.js&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;node 커맨드로 디폴트값을 index.js로 실행하되, docker run 커맨드에 인자가 있고 해당 인자를 실행하고 싶은 경우, 다음과 같이 Dockerfile을 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- node index.js 실행&lt;/p&gt;
&lt;pre id=&quot;code_1658381341122&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run test&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- node main.js 실행&lt;/p&gt;
&lt;pre id=&quot;code_1658381397367&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run test main.js&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CMD와 RUN 명령은 구분점이 있는데, RUN 명령문은 이미지 빌드 시 항상 실행되며, 한 Dockerfile에 여러 개의 RUN 명령문을 선언할 수 있습니다. CMD 명령문은 이미지를 container로 띄울 때 딱 한번 실행 기회를 가지게 되며, 이 기회마저도 docker run 커맨드에 인자를 넘길 경우 상실하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1658381529927&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CMD [&quot;echo&quot;, &quot;Hi&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 Dockerfile 파일에 Hi를 출력하는 CMD 명령문이 있을 때, 인자없이 이미지를 실행하면 Hi가 출력되지만, 인자로 대신 실행될 커맨드를 넘기면 해당 인자가 출력되는 것을 알 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1658381830680&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker run test
Hi
$ docker run test echo Bye
Bye&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;EXPOSE&lt;/h3&gt;
&lt;pre id=&quot;code_1658382093165&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;EXPOSE &amp;lt;포트&amp;gt;
EXPOSE &amp;lt;포트&amp;gt;/&amp;lt;프로토콜&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EXPOSE 명령문은 네트워크 상에서 컨테이너로 들어오는 트래픽(traffic)을 리스닝하는 포트와 프로토콜을 지정하기 위해서 사용된다. 프로토콜은 TCP와 UDP 중 선택할 수 있는데 지정하지 않으면 TCP가 기본값으로 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 주의할 점은 EXPOSE 명령문으로 지정된 포트는 해당 컨테이너의 내부에서만 유효하며, 호스트(host) 컴퓨터에서는 이 포트를 바로 접근을 할 수 있는 것은 아니라는 것이다. 호스트 컴퓨터로부터 해당 포트로의 접근을 허용하려면, docker run 커맨드를 -p 옵션을 통해 호스트 컴퓨터의 특정 포트를 포워딩(forwarding)시켜줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 80/TCP 포트로 리스닝&lt;/p&gt;
&lt;pre id=&quot;code_1658382286545&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;EXPOSE 80&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 9999/UDP 포트로 리스닝&lt;/p&gt;
&lt;pre id=&quot;code_1658382316492&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;EXPOSE 9999/udp&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;COPY/ADD&lt;/h3&gt;
&lt;pre id=&quot;code_1658382544832&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;COPY &amp;lt;src&amp;gt;... &amp;lt;dest&amp;gt;
COPY [&quot;&amp;lt;src&amp;gt;&quot;, ..., &quot;&amp;lt;dest&amp;gt;&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;COPY 명령문은 호스트 컴퓨터에 있는 디렉토리나 파일을 Docker 이미지의 파일 시스템으로 복사하기 위해서 사용된다. 절대 경로와 상대 경로를 모두 지원하며, 상대 경로를 사용할 때는 이전에 등장하는 WORKDIR 명령문으로 작업 디렉토리를 어디로 전환을 해놨는지 고려해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- package.json 파일만 복사&lt;/p&gt;
&lt;pre id=&quot;code_1658382834731&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;COPY package.json package.json&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이미지를 빌드한 디렉토리의 모든 파일을 컨테이너의 app/ 디렉토리로 복사&lt;/p&gt;
&lt;pre id=&quot;code_1658382861055&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;WORKDIR app/
COPY . .&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ADD 명령문은 좀 더 파워풀한 COPY 명령문이다. ADD 명령문은 일반 파일 뿐만 아니라 압축 파일이나 네트워크 상의 파일도 사용할 수 있다. 이렇게 특수한 파일을 다루는 것이 아니라면 COPY 명령문을 사용하는 것이 권장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ENV&lt;/h3&gt;
&lt;pre id=&quot;code_1658383034006&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ENV &amp;lt;키&amp;gt; &amp;lt;값&amp;gt;
ENV &amp;lt;키&amp;gt;=&amp;lt;값&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ENV 명령문은 환경 변수를 설정하기 위해 사용한다. ENV 명령문으로 설정된 환경 변수는 이미지 빌드 시에도 사용됨은 물론이고, 해당 컨테이너에서 돌아가는 애플리케이션도 접근할 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- NODE_ENV 환경 변수를 production 으로 설정&lt;/p&gt;
&lt;pre id=&quot;code_1658390793294&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ENV NODE_ENV production&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 예를 들어 MYSQL 설치 시 패스워드와 데이터베이스 설정&lt;/p&gt;
&lt;pre id=&quot;code_1658393933228&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM mysql
ENV MYSQL_ROOT_PASSWORD=1234
ENV MYSQL_DATABASE=testdb&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ARG 명령문&lt;/h3&gt;
&lt;pre id=&quot;code_1658391259492&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ARG &amp;lt;이름&amp;gt;
ARG &amp;lt;이름&amp;gt;=&amp;lt;기본 값&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ARG 명령문은 docker build 커맨드로 이미지를 빌드 시, --build-arg 옵션을 통해 넘길 수 있는 인자를 정의하기 위해 사용한다. 예를 들어, Dockerfile에 다음과 같이 ARG 명령문으로 port를 인자로 선언해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1658391527809&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ARG port&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 docker build 커맨드에 --build-arg 옵션에 port 값을 넘길 수가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1658391570791&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker build --build-arg port=8080 .&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인자의 디폴트 값을 지정해주면, --build-arg 옵션으로 해당 인자가 넘어오지 않았을 때 사용된다.&lt;/p&gt;
&lt;pre id=&quot;code_1658391602955&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ARG port=8080&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정된 인자 값은 다음과 같이 ${인자명} 형태로 읽어서 사용 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1658391830162&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CMD start.sh -h 127.0.0.1 -p ${port}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ENV 와 달리 ARG로 설정한 값은 이미지가 빌드되는 동안에만 유효하니 주의를 해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : &lt;a href=&quot;https://www.daleseo.com/dockerfile/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.daleseo.com/dockerfile/&lt;/a&gt;&lt;/p&gt;</description>
      <category>DevOps</category>
      <author>퉁그리</author>
      <guid isPermaLink="true">https://toongri.tistory.com/99</guid>
      <comments>https://toongri.tistory.com/99#entry99comment</comments>
      <pubDate>Thu, 21 Jul 2022 17:24:25 +0900</pubDate>
    </item>
    <item>
      <title>[DevOps]DevOps</title>
      <link>https://toongri.tistory.com/98</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;DevOps(이하 데브옵스)는 Development + Operation의 합성어로 개발담당자와 운영담당자가 연계하하여 소통, 협업 및 통합을 강조하는 개발 환경, 문화, 방법론 등을 아우르는 말이다. 다시 말해 데브옵스는 어떤 요구사항을 효율적으로 만족시키기 위하여, 일을 자동화하며 변경사항 지표들을 측정하고, 공유하며, 이 모든 결과물들을 지속적으로 축적해 나아가는 문화를 만들어가는 철학, 방법론, 기술등을 의미한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데브옵스의 장점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데브옵스를 적용하는데에 있어 가져올 수 있는 장점은 이와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 속도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소통의 딜레이와 난이도가 줄어들면서 작업 속도가 빨라지고 이에 따라 시장 변화에 잘 적응하고 효율적으로 비즈니스 성과를 창출할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 빠른 배포&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 기능의 릴리스와 버그 수정 속도가 빨라질수록 경쟁 우위를 차지할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 안정성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션 업데이트와 인프라 변경의 품질 보장, 지속적 통합 및 지속저 전달과 같은 방식을 통해 변경 사항이 제대로 안전하게 작동하는지 테스트가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 확장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;규모에 따라 인스턴스를 단일부터 수천개까지 확장할 수 있으며 인프라와 개발 프로세스 운영, 관리가 가능하고 자동화와 일관성이 지원되므로 위험을 줄이면서 복잡한 시스템 또는 변화하는 시스템을 효율적으로 관리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 협업 강화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자와 운영 부서 간의 효율적인 협력을 통해 효과적인 팀 구축이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 보안&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동화된 규정 준수 정책, 세분화된 제어 및 구성 관리 기술 사용을 통해 보안을 높은 수준으로 유지할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데브옵스 툴체인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데브옵스 툴체인은 데브옵스 적용이 가능한 툴을 묶어 하나의 체인 형식으로 모든 과정(기획-개발-빌드-테스트-릴리즈-배포-운영-모니터링)을 묶어 사용하는 개념이다. 툴체인을 기반한 툴들이 있는데, 이러한 툴들의 목표는 파이프라인의 다양한 단계를 추가로 간소화하고, 단축하고, 자동화하는 것이다. 또한 이러한 툴 중 다수는 자동화, 협업 및 개발-운영 팀 간의 통합에 대한 핵심 데브옵스 원칙을 손쉽게 준수할 수있도록 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GwHrW/btrHxVoxYV4/vP4B24dEm4BHNkJxr5pHSk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GwHrW/btrHxVoxYV4/vP4B24dEm4BHNkJxr5pHSk/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GwHrW/btrHxVoxYV4/vP4B24dEm4BHNkJxr5pHSk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGwHrW%2FbtrHxVoxYV4%2FvP4B24dEm4BHNkJxr5pHSk%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;450&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;450&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 DevOps 툴체인과 툴의 예이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기획&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목적을 수행하기 앞서 방법이나 절차 등을 미리 생각하여 계획&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) Jira, Git&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 개발&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 개발 및 검토, 버전 관리 도구, 코드 병합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) GitHub, GitLab, Bitbucket, Stash&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 빌드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지속적 통합(CI) 도구, 빌드 상태&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) Docker, Ansible, Gradle, Maven&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 테스트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 및 결과가 성능을 결정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) JUnit, Assertion, Codeception, Selenium&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 배포 &amp;amp; 릴리즈&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변경사항 관리, 릴리즈 승인, 릴리즈 자동화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) Jenkins, Kubernetes, Docker, Jira, OpenStack, Chef&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 운영&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션 관리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) Puppet, Anabilities, PowerShell&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 모니터링&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션 성능 모니터링, 최종 사용자 경험&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) New Relic, Datadog, Grafana, Slack&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DevOps 구현의 주요 성과&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 지속적인 배포(CD : Continuous Deployment)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CD는 개발자가 개발을 기획하고, 개발하고, 빌드하고 결과물이 테스트 후에 안정적으로 운영 환경에 배포가 되고 또한 서비스가 죽지 않게 무정지로 배포하는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포 이후에는 이 서비스가 정말로 안정적인지 지속적으로 모니터링하고, 이 배포 파이프라인의 과정에서 특정 이벤트가 발생하면, 그걸 실시간으로 알림을 받을 수 있도록 구성해 놓는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 지속적인 통합(CI : Continuous Integration)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CI는 지속적으로 품질관리를 적용하는 프로세스를 실행하는 것이다. 작은 단위의 작업과 빈번한 적용을 기반으로 하는 작업은 소프트웨어의 질적인 향상과 소프트웨어를 배포하는데 걸리는 시간을 줄여 재작업의 비용과 시간을 줄이는데에 초점이 맞추어져 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 탄력적인 확장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적절한 리소스를 사용하고 예외적인 상황에 유연하게 대처할 수 잇도록 하는것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 자동화된 모니터링&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보안 이슈, 운영 환경에서 락이 발생하는지, 즉시 반응, 즉시 대응 할 수 있는지 환경을 만들어놔야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 : &lt;a href=&quot;https://aws.amazon.com/ko/devops/what-is-devops/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://aws.amazon.com/ko/devops/what-is-devops/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%8D%B0%EB%B8%8C%EC%98%B5%EC%8A%A4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ko.wikipedia.org/wiki/%EB%8D%B0%EB%B8%8C%EC%98%B5%EC%8A%A4&lt;/a&gt;&lt;/p&gt;</description>
      <category>DevOps</category>
      <author>퉁그리</author>
      <guid isPermaLink="true">https://toongri.tistory.com/98</guid>
      <comments>https://toongri.tistory.com/98#entry98comment</comments>
      <pubDate>Sun, 17 Jul 2022 15:55:58 +0900</pubDate>
    </item>
    <item>
      <title>[JS] async, await 함수</title>
      <link>https://toongri.tistory.com/97</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;async 함수는 비동기 작업을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;new Promise를 리턴하던 함수를 조금씩 수정하면 async함수로 변환이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 함수에 async 키워드를 붙인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- new Promise 리턴을 없애고 executor 내용만 남긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- resolve(value); 부분을 return value;로 변경한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- rejuect(new Error()); 부분을 throw new Error(...);로 수정한다.&lt;/p&gt;
&lt;pre id=&quot;code_1657268532729&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function startAsync(age) {
  return new Promise((resolve, reject) =&amp;gt; {
    if (age &amp;gt; 20)
      resolve('${age}');    
    else
      reject(new Error('error'));
  });
}

async function startAsync(age) {
  if (age &amp;gt; 20)
    return '${age}';
  else
    throw new Error(error);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 바꿀 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 함수를 async 함수로 바꾸면서 알 수 있는 내용은 async함수는 promise객체 자체를 리턴한다라는 것이다. 때문에 일반함수와 사용법을 달리해야만 한다. 이 불편함을 줄이기 위해 나온 문법이 await다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1657269865682&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function setTimeoutPromise(ms) {
  return new Promise((resolve, reject) =&amp;gt; {
    setTimeout(() =&amp;gt; resolve(), ms);
  });
}

async function startAsync(age) {
  if (age &amp;gt; 20)
    return '${age}';
  else
    throw new Error('${age}');
}

async function startAsyncJobs() {
  await setTimeoutPromise(1000);
  
  const pms1 = startAsync(25);
  try {
    const value = await pms1;
    console.log(value);
  } catch (e) {
    console.error(e);
  }
  const pms2 = startAsync(15);
  try {
    const value = await pms2;
    console.log(value);
  } catch (e) {
    console.error(e);
  }
}

startAsyncJobs();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;await의 특징은 이렇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 문법적으로 await p[[Promise 객체]] 이렇게 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. await은 Promise가 완료될 때까지 기다린다.(동기식)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. await은 resolve를 리턴한다. reject가 발생하는 건에 대해선 예외를 발생시킨다. 때문에 기존의 async함수를 쓰는것과 다르게 await을 쓸 때는 try catch를 써야한다.&lt;/p&gt;</description>
      <category>JS &amp;amp; TS</category>
      <author>퉁그리</author>
      <guid isPermaLink="true">https://toongri.tistory.com/97</guid>
      <comments>https://toongri.tistory.com/97#entry97comment</comments>
      <pubDate>Fri, 8 Jul 2022 17:54:48 +0900</pubDate>
    </item>
    <item>
      <title>[JS] Promise</title>
      <link>https://toongri.tistory.com/96</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Promise는 비공기 작업의 단위이다. Promise를 사용하는 가장 정석적인 방법은 new Promise()를 활용한 다음과 같은 방법이다.&lt;/p&gt;
&lt;pre id=&quot;code_1657088028589&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const pms = new Promise((resolve, reject) =&amp;gt; {
	// 비동기 작업
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Promise의 생성자는 함수를 인자로 받는데 이 함수를 executor라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;executor는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 첫번째 인자로 resolve를 받고, 두번째 인자로 reject를 받는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. resolve는 executor 내에서 호출할 수 있는 또 다른 함수이며, resolve를 호출한다는 것은 작업의 성공을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. reject 또한 executor내에서 호출할 수 있는 함수이며, reject를 호출한다는 것은 작업의 실패를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Promise의 특징은 new Promise(...)하는 순간 할당된 비동기 작업이 바로 시작되는 것이다. 작업이 끝나면 다음 동작을 설정할 수 있으며, 그 동작이 바로 then메소드와 catch메소드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;then 메소드는 해당 Promise 작업이 성공했을 때의 동작을 지정하며, 인자로 함수를 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;catch 메소드는 해당 Promise 작업이 실패했을 때의 동작을 지정하며, 인자로 함수를 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 두 함수는 체인 형태로 활용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1657088748717&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const pms = new Promise((resolve, reject) =&amp;gt; {
	resolve();
})
pms
	.then(() =&amp;gt; {
    	console.log(&quot;then!&quot;);
    })
    .catch(() =&amp;gt; {
    	console.log(&quot;catch!&quot;);
    })&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음의 코드는 then! 하나만을 출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 pms의 Promise가 resolve하나만을 호출하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Promise는 new Promise(...)를 하는 순간 비동기 작업이 시작된다. 때문에 같은 비동기 작업을 수행할 때마다 new Promise를 해줘야만 하는데 사실 그건 비효율적이다. 그것보단 new Promise를 리턴해주는 함수를 하나 만들어 사용하는 것이 효율적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1657089909674&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function startAsync(age){
	return new Promise((resolve, reject) =&amp;gt; {
    	if(age &amp;gt; 20) resolve('${age}');
        else reject(new Error('${age}'));
    });
}

setTimeout(() =&amp;gt; {
	const pms = startAsync(25);
    pms
    	.then((value) =&amp;gt; {
        	console.log(value);
        })
        .catch((error) =&amp;gt; {
        	console.log(error);
        });
    const pms2 = startAsync(25);
    pms2
    	.then(() =&amp;gt; {
        	console.log(&quot;2 then&quot;);
        })
        .catch(() =&amp;gt; {
        	console.log(&quot;2 catch&quot;)
        });
}, 1000);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JS &amp;amp; TS</category>
      <author>퉁그리</author>
      <guid isPermaLink="true">https://toongri.tistory.com/96</guid>
      <comments>https://toongri.tistory.com/96#entry96comment</comments>
      <pubDate>Fri, 8 Jul 2022 16:29:04 +0900</pubDate>
    </item>
    <item>
      <title>[JS] 화살표 함수</title>
      <link>https://toongri.tistory.com/95</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이제 function을 굳이 명시 하지 않더라도 화살표 함수를 통해 대체할 수 있게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656398959947&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function a(x, y) {
  return x + y;
}

var b = (x, y) =&amp;gt; {
  return x + y;
}

var c = (x, y) =&amp;gt; x + y;

var d = (x, y) =&amp;gt; (x + y);

function a2(x) {
  return !x;
}

var b2 = x =&amp;gt; !x;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 a는 이제 b, c, d의 방식으로 표시할 수 있고, a2도 b2처럼 표할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 내용이 return 뿐인 경우 c처럼 생략할 수 있으며, 매개변수가 하나인 경우 b2처럼 괄호 생략이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;return이 생략이 되더라도 가시성을 위해 d처럼 괄호로 감싸는 것을 추천한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화살표함수와 function()은 this에서 차이가 있는데&lt;/p&gt;
&lt;pre id=&quot;code_1656399750295&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var relationship1 = {
  name: 'zero',
  friends: ['nero', 'hero', 'xero'],
  logFriends: function() {
    var that = this;
    this.friends.forEach(function (friend){
      console.log(that.name, friend);
    });
  },
};
relationship1.logFriends();

var relationship2 = {
  name: 'zero',
  friends: ['nero', 'hero', 'xero'],
  logFriends() {
    this.friends.forEach(friend =&amp;gt; {
      console.log(this.name, friend);
    });
  },
};
relationship2.logFriends();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화살표 함수는 relationship2에서 보이듯 화살표 함수의 부모 함수의 this을 물려받는 반면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;function()은 본인만의 this을 갖는다. 때문에 부모의 this을 쓰기 위해 relationship1처럼 변수를 새로 선언하여 부모의 this을 끌어와야한다.&lt;/p&gt;</description>
      <category>JS &amp;amp; TS</category>
      <author>퉁그리</author>
      <guid isPermaLink="true">https://toongri.tistory.com/95</guid>
      <comments>https://toongri.tistory.com/95#entry95comment</comments>
      <pubDate>Tue, 28 Jun 2022 16:05:10 +0900</pubDate>
    </item>
    <item>
      <title>[JS] 객체 리터럴</title>
      <link>https://toongri.tistory.com/94</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;ES6 버전에서 객체 리터럴이라는 기능이 추가되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656398420851&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let sayNode = function(){
  console.log('Node');
}

let es = 'ES';
let oldObject = {
  sayJS: function() {
    console.log('JS');
  },
  sayNode: sayNode,
};
oldObject[es + 6] = 'Fantastic';
oldObject.sayNode(); // Node
oldObject.sayJS(); // JS
console.log(oldObject.ES6); // Fantastic

let newObject = {
  sayJS() {
    console.log('JS');
  },
  sayNode,
  [es + 6]: 'Fantastic',
};
newObject.sayNode(); // Node
newObject.sayJS(); // JS
console.log(newObject.ES6); // Fantastic&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;oldObject와 newObject를 비교하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sayJS 같은 경우 function과 콜론을 붙이지 않고 좀 더 직관적으로 쓸 수 있게 되었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sayNode와 같이 키와 밸류가 같을 경우 하나만 명시할 수 있도록 바뀌었으며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ES6과 같이 동적 속성을 안에서도 선언할 수 있도록 바뀌었다.&lt;/p&gt;</description>
      <category>JS &amp;amp; TS</category>
      <author>퉁그리</author>
      <guid isPermaLink="true">https://toongri.tistory.com/94</guid>
      <comments>https://toongri.tistory.com/94#entry94comment</comments>
      <pubDate>Tue, 28 Jun 2022 15:44:37 +0900</pubDate>
    </item>
    <item>
      <title>[JS] 이벤트 기반의 js, 이벤트 루프</title>
      <link>https://toongri.tistory.com/93</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 기반이란 이벤트가 발생할 때 미리 저장해둔 작업을 수행하는 방식을 의미.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 기반 시스템에서는 특정 이벤트가 발생할 때 무엇을 할지 미리 등록해두어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 이벤트 리스너에 콜백 함수를 등록한다고 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드도 이벤트 기반 방식으로 동작하며, 이벤트가 발생하면 이벤트 리스너에 등록해둔 콜백 함수를 호출하고, 발생한 이벤트가 없거나 발생했던 이벤트를 다 처리하면, 다음 이벤트가 발생할 때까지 대기한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 시간 이후에 코드를 실행하는 setTimeout을 사용하면 특이한 상황이 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656390227486&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function run() {
  console.log('3초 후 실행');
}
console.log('시작');
setTimeout(run, 3000);
console.log('끝');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시작&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;끝&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3초 후 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3초 뒤에 run함수를 실행하는 코드이다. 예상했던 결과는 3초가 밀려도 '3초 후 실행'이 나오고 끝이 뒤따라오는 것인데, 예상과 달랐다. 이를 파악하기 위해서는 이벤트 루프, 태스크 큐, 백그라운드를 알아야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이벤트 루프 : 이벤트 발생 시 호출할 콜백 함수들을 관리하고, 호출된 콜백 함수의 실행 순서를 결정하는 역할을 담당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 백그라운드 : setTimeout 같은 타이머나 이벤트 리스너들이 대기하는 곳이다. 자바스크립트가 아닌 다른 언어로 작성된 프로그램이 봐도 무방. 여러 작업이 동시에 실행될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 태스크 큐 : 이벤트 발생 후, 백그라운드에서는 태스크 큐로 타이머나 이벤트 리스너의 콜백 함수를 보낸다. 콜백들은 보통 완료된 순서대로 줄을 서 있지만 특정한 경우에는 순서가 바뀌기도 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ashcg/btrFWyvJtIM/JxJ3xquoaLkl2EnRHc3h91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ashcg/btrFWyvJtIM/JxJ3xquoaLkl2EnRHc3h91/img.png&quot; data-alt=&quot;이벤트 루프&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ashcg/btrFWyvJtIM/JxJ3xquoaLkl2EnRHc3h91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAshcg%2FbtrFWyvJtIM%2FJxJ3xquoaLkl2EnRHc3h91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;698&quot; height=&quot;608&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;608&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이벤트 루프&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드 내용을 풀면 다음과 같이 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 콜 스택에 전역 컨택스트인 anonymous가 처음으로 들어가고, setTimeout이 들어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 콜 스택은 last in first out이기 때문에 setTimeout이 먼저 실행된다. setTimeout이 실행되면 타이머와 함께 run 콜백을 백그라운드로 보내고, setTimeout이 콜 스택에서 빠지며 그 후 anonymous가 콜 스택에서 빠진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 백그라운드에서는 3초 이후 run 함수를 태스크 큐로 보낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 이벤트는 콜 스택이 비어 있으면 태스크 큐에서 함수를 하나씨 가져와 콜 스택에 넣고 실행한다. anonymous까지 실행이 완료되면 태스크 큐에서 run함수를 가져와 콜 스택에 올려 실행할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 이유 때문에 setTimeout은 시간을 보장하여 실행해 주는 것이 아닌, 최소딜레이에 가깝다. 콜 스택에 함수들이 너무 많이 들어 있으면 시간이 지나도 함수가 실행되지 않을 수 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : https://www.inflearn.com/course/노드-교과서/lecture/56870?volume=1.00&amp;amp;speed=1.75&amp;amp;tab=curriculum&lt;/p&gt;</description>
      <category>JS &amp;amp; TS</category>
      <author>퉁그리</author>
      <guid isPermaLink="true">https://toongri.tistory.com/93</guid>
      <comments>https://toongri.tistory.com/93#entry93comment</comments>
      <pubDate>Tue, 28 Jun 2022 14:31:02 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Spring Data JPA의 save 함수 구조</title>
      <link>https://toongri.tistory.com/92</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Data JPA의 save함수의 구조는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1655466058391&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public &amp;lt;S extends T&amp;gt; S save(S entity) {

	if (entityInformation.isNew(entity)) { // 1
		em.persist(entity); // 2
		return entity; // 3
	} else { // 4
		return em.merge(entity); // 5
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번의 isNew 함수를 통해 매개변수로 들어온 entity가 새로운 entity인지, 이미 저장된 entity인지 체크한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 레퍼런스 타입(String, Long...)일 경우 null값이면 새로운 entity로 판단한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 기본 타입(Primitive Type)[int, long, char etc..]일 경우 값이 0이면 새로운 entity로 판단한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 id 생성 방식이 @GeneratedValue이라면 엔티티가 저장되기 전에는 id값이 null이거나 0이기 때문에 2번, 3번을 차례로 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2번과정을 진행한 entity의 id값에는 @GeneragedValue 속성에 맞게 값이 채워져 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 id값이 @GeneratedValue방식이 아니라 사용자가 직접 입력하는 값이라면 어떤식으로 판별할까&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 아무런 설정이 되있지 않다면, id값에는 보통 값이 채워져 있을 것이기 때문에, 1번구간을 넘어가지 못하고 4번으로 넘어가 merge를 하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;merge을 하게 될 경우 해당 entity가 데이터베이스에 존재하는지 체크하기 위해 select 쿼리가 한번 발생하게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1029&quot; data-origin-height=&quot;748&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNqZXb/btrE3ZV0QOP/FpK5P13wKMtMW5n2CZEVbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNqZXb/btrE3ZV0QOP/FpK5P13wKMtMW5n2CZEVbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNqZXb/btrE3ZV0QOP/FpK5P13wKMtMW5n2CZEVbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNqZXb%2FbtrE3ZV0QOP%2FFpK5P13wKMtMW5n2CZEVbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1029&quot; height=&quot;748&quot; data-origin-width=&quot;1029&quot; data-origin-height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;insert가 발생하기 전 select가 한번 발생하는 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 @GeneratedValue을 쓰지 않은 채로 별다른 설정이 없으면 매 저장시마다 Select 쿼리가 한번씩 발생할 수 밖에 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 다음과 같이 문제를 해결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1655467534221&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
@Getter
@EntityListeners(AuditingEntityListener.class)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Movie implements Persistable&amp;lt;Long&amp;gt; {

    @Id
    @Column(name=&quot;movie_id&quot;)
    private Long id;

    private String title;
    private String thumbnail;
    private String directorName;
    private Integer year;
    private String naverUrl;
    private String nation;
    private Double popularity;
    private String actors;

    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createdDate;

    private LocalDateTime lastModifiedDate;

    @Override
    public boolean isNew() {
        return getCreatedDate() == null;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 entity에 Persistable&amp;lt;id타입&amp;gt;을 상속받아 isNew을 커스텀할 수 있는 방법이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 이용해 createDate이나 다른 기타 판별방식을 활용해 select 쿼리를 안나갈 수 있도록 할 수 있다.&lt;/p&gt;</description>
      <category>Spring</category>
      <author>퉁그리</author>
      <guid isPermaLink="true">https://toongri.tistory.com/92</guid>
      <comments>https://toongri.tistory.com/92#entry92comment</comments>
      <pubDate>Fri, 17 Jun 2022 21:09:16 +0900</pubDate>
    </item>
    <item>
      <title>[Spring boot] spring boot batch 관계도</title>
      <link>https://toongri.tistory.com/91</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;641&quot; data-origin-height=&quot;281&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9yBEB/btrBsZr1vR9/uwcekp79zIkeW6Cf7vozIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9yBEB/btrBsZr1vR9/uwcekp79zIkeW6Cf7vozIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9yBEB/btrBsZr1vR9/uwcekp79zIkeW6Cf7vozIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9yBEB%2FbtrBsZr1vR9%2Fuwcekp79zIkeW6Cf7vozIK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;641&quot; height=&quot;281&quot; data-origin-width=&quot;641&quot; data-origin-height=&quot;281&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;spring boot batch는 JobRepository라는 큰 구조에서 JobLauncher, Job, Step 3단계로 나눠볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Step&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본구조는 Step에서 정의된다. 1개의 Step은 읽고, 처리하고, 저장하는 구조를 가지고 있는 가장 실질적인 배치처리를 담당하는 도메인 객체이다. 그리고 이 Step들이 이루어져 Job을 표현한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Job&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 Job은 여러개의 Step으로 이루어져 있다. Job 객체는 JobBuilderFactory에서 생성된 JobBuilder를 통해 Job을 생성할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1) JobBuilerFactory&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1651981955086&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class JobBuilderFactory {

	private JobRepository jobRepository;

	public JobBuilderFactory(JobRepository jobRepository) {  // 1
		this.jobRepository = jobRepository;
	}

	public JobBuilder get(String name) {  // 2
		JobBuilder builder = new JobBuilder(name).repository(jobRepository);
		return builder;
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. JobBuilderFactory의 생성자를 통해 JobRepository을 주입한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JobBuilder가 생성되기 전에 미리 주입받은 JobRepository을 쓰기 때문에 모든 JobBuilder는 동일한 JobRepository을 사용하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. get메소드을 통해 name을 입력받아 새로운 JobBuilder을 리턴받을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) JobBuiler&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JobBuilderFactory을 통해 JobBuilder를 반환을 받게되면, 이를 통해 Job을 생성할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1652166645075&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class JobBuilder extends JobBuilderHelper&amp;lt;JobBuilder&amp;gt; {

	public JobBuilder(String name) {
		super(name);
	}

	public SimpleJobBuilder start(Step step) {
		return new SimpleJobBuilder(this).start(step);
	}

	public JobFlowBuilder start(Flow flow) {
		return new FlowJobBuilder(this).start(flow);
	}

	public JobFlowBuilder flow(Step step) {
		return new FlowJobBuilder(this).start(step);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각 다르게 정의된 2개의 start 메소드와 1개의 flow 메소드가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 용도에 따라 골라 쓸 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Job Repository&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;641&quot; data-origin-height=&quot;281&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E8Dq3/btrBLGx4Sdv/ckVy8E6zzK11UvDp4e31y1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E8Dq3/btrBLGx4Sdv/ckVy8E6zzK11UvDp4e31y1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E8Dq3/btrBLGx4Sdv/ckVy8E6zzK11UvDp4e31y1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE8Dq3%2FbtrBLGx4Sdv%2FckVy8E6zzK11UvDp4e31y1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;641&quot; height=&quot;281&quot; data-origin-width=&quot;641&quot; data-origin-height=&quot;281&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배치처리는 일정한 주기 간격으로 특정 조건을 가진 데이터를 읽어와서 처리하고 저장하는 구조를 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 작업이 매번 반복되다 보면 Job이 몇번 실행되었고, 언제 실행되었는지 기록이 되어야 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 처리 정보를 메타데이터 형식으로 저장하여 관리하는 곳이 JobRepository다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Job이 실행될 때마다 JobRepository에서는 배치 실행에 관련된 정보를 담는 도메인인 JobExcustion을 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처 :&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ahndy84.tistory.com/18&quot;&gt;[spring boot batch] 1. 간단한 대용량 배치처리, 스프링부트배치 (tistory.com)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring</category>
      <author>퉁그리</author>
      <guid isPermaLink="true">https://toongri.tistory.com/91</guid>
      <comments>https://toongri.tistory.com/91#entry91comment</comments>
      <pubDate>Tue, 10 May 2022 16:33:14 +0900</pubDate>
    </item>
  </channel>
</rss>