<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>코딩하는 이채야채</title>
    <link>https://developeritchaeyachae.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 7 Jul 2026 04:54:57 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>이채야채</managingEditor>
    <item>
      <title>docker 구동</title>
      <link>https://developeritchaeyachae.tistory.com/399</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Dockerfile에 필요한것은&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-어떤 OS쓸건지&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;내프로그램 구동하려면 어떤짓을 해야하는지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;FROM 명령어&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;어떤 OS 환경에서&lt;/b&gt; 내 프로그램을 실행할지부터 정해야하는데 FROM으로 정의가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 Dockerfile은 &lt;b&gt;항상 FROM 부터&lt;/b&gt; 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FROM 뒤에 어떤 OS를 설치해서 시작할건지 정하면 되는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그건 Docker hub에서 찾아올 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1744335086806&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/*
1.Node.js 설치
2. express 설치
3. 코드작성
4. 코드실행 서버 실행
---&amp;gt; 귀찮으니까 밀키트로 만들고 실행하게끔 docker image를 만든다.
*/&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;npm install express를 해야하는 차례인데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RUN 명령어&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용하는 라이브러리를 하나하나 RUN 명령어로 집어넣는것은 비효율적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 라이브러리르 사용하고, 몇 버전을 사용하는지 적혀있는 package.json을 활용하는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;COPY 명령어&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. pakage.json 을 다른 컴퓨터에 복사하고 (COPY 명령어로)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. npm install 터미널에 입력&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;pre id=&quot;code_1744337625804&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM node:18.19.2

COPY . .&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;p data-ke-size=&quot;size16&quot;&gt;이미지의 디폴트 경로에 카피하면 더러울 수 있다. 그렇기에&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WORKDIR 명령어&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1744338223847&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM node:18.19.2
WORKDIR /app
COPY . .
RUN npm install&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;* 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;1. RUN npm install &amp;lt;- /bin/sh-c npm install 실행됨 (이방식은 &lt;b&gt;OS에 있는 기본 shell 이용해서&lt;/b&gt; 실행하라는 뜻)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. RUN [&quot;npm&quot;m &quot;install&quot;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CMD 명령어, ENTRYPOINT 명령어&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 터미널 명령어는 RUN 말고 CMD&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;EXPOSE 명령어&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1744344833909&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM node:18.19.2
WORKDIR /app
COPY . .
RUN [&quot;npm&quot;, &quot;install&quot;]
EXPOSE 2873
CMD [&quot;node&quot;, &quot;server.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;2873 포트를를 열어서 쓰겠다는 용도&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;port : 열려있으면 남들이 접속가능한곳&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;-- 터미널에 docker init 명령어를 쓰면 자동으로 채워준다.&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;내가 만든 docker 이미지를 만들기위해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;docker build를 하고 docker run을 해도, 2873 localhost port에서 아무런 내용물이없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 방식이든 Docker 컨테이너 내부에서 서버가 열린다면, 로컬에 접근하려면 무조건 포트연결(-p)을 명시적으로 설정해야한다.&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;Docker 컨테이너는 독립적인 네트워크 환경을 가지고있다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;781&quot; data-origin-height=&quot;394&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmO2L8/btsNhMUEmfP/S4AFLfRa6v7G3w44xbg5W0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmO2L8/btsNhMUEmfP/S4AFLfRa6v7G3w44xbg5W0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmO2L8/btsNhMUEmfP/S4AFLfRa6v7G3w44xbg5W0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmO2L8%2FbtsNhMUEmfP%2FS4AFLfRa6v7G3w44xbg5W0%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;532&quot; height=&quot;268&quot; data-origin-width=&quot;781&quot; data-origin-height=&quot;394&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서&lt;b&gt; 컨테이너의 포트를 로컬 머신으로 매핑(-p)&lt;/b&gt;해야 로컬에서 접근 할 수 있다.&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-filename=&quot;Screenshot from 2025-04-11 13-51-44.png&quot; data-origin-width=&quot;781&quot; data-origin-height=&quot;394&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjj63X/btsNgyaNSl5/ENMLQ7z7Mk3CXRzj5uT1K1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjj63X/btsNgyaNSl5/ENMLQ7z7Mk3CXRzj5uT1K1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjj63X/btsNgyaNSl5/ENMLQ7z7Mk3CXRzj5uT1K1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbjj63X%2FbtsNgyaNSl5%2FENMLQ7z7Mk3CXRzj5uT1K1%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;573&quot; height=&quot;289&quot; data-filename=&quot;Screenshot from 2025-04-11 13-51-44.png&quot; data-origin-width=&quot;781&quot; data-origin-height=&quot;394&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EXPOSE만 사용하고 -p 옵션이 없다면?&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;Docekr 컨테이너 내부에서는 서버가 정상 작동하지만, 로컬머신의 웹 브라우저로는 접근 불가능&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;docker run -d -p 2873:2873 도커미이지 이름&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;lt;명령어들&amp;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;docker ps&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;docker logs 컨테이너명&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;docker exec -it 컨테이너명 sh&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;ls, cd 등으로 경로이동 등 실제 개발모드일때 하던 짓을 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성능을 위한 docker build 시간 단축법&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;pre id=&quot;code_1744357404758&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM node:18.19.2
WORKDIR /app
COPY . .   &amp;lt;- 캐싱해둠
RUN [&quot;npm&quot;, &quot;install&quot;] &amp;lt;- 캐싱해둠
EXPOSE 2873
CMD [&quot;node&quot;, &quot;server.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;docekr build 할때 저번이랑 차이가 없으면 캐싱해둔 결과를 사용한다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들면, package.json 라이브러리 파일은 변동사항이 별로없다.&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. package.json 파일 먼저 옮기고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. npm install 실행&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;pre id=&quot;code_1744357562416&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM node:18.19.2
WORKDIR /app
COPY package*.json.
RUN [&quot;npm&quot;, &quot;ci&quot;] 

---------------------- 여기까지 캐싱이 잘되어있으면 좀 더 빠르게 된다.

COPY . . &amp;lt;- 소스코드 복사
EXPOSE 2873
CMD [&quot;node&quot;, &quot;server.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;npm install보다 npm 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;^4.21 에서 업데이트디ㅗ어서 ^4.2 로된다면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- npm install 하면 4.2가 설치된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;package-lock.json 파일 바탕으로 설치하라고 하는게 좋다.&quot; 그 명령어가 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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dockerfile에서 실행되는 것은 &lt;b&gt;ROOT 권한&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1744357782840&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM node:18.19.2
WORKDIR /app
COPY package*.json.
RUN [&quot;npm&quot;, &quot;ci&quot;] 

---------------------- 여기까지 캐싱이 잘되어있으면 좀 더 빠르게 된다.

COPY . . &amp;lt;- 소스코드 복사
EXPOSE 2873

USER sophie
CMD [&quot;node&quot;, &quot;server.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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;USER sophie를 하지않은 상태에서, 실행시켰을경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;docker에서 확인을 하기위해서 docker exec -it nodeserver:1 sh로 접근 한후 ls-ld를 했을때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;root가 아닌 sophie가 나와서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;root권한이라는 말이 너무 헷갈렸다.&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;chat gpt에 물어보니&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2025-04-11 17-23-13.png&quot; data-origin-width=&quot;1412&quot; data-origin-height=&quot;419&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VrhlJ/btsNi3H3E3W/ZucNxNsUsRdhv7lpV0xSZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VrhlJ/btsNi3H3E3W/ZucNxNsUsRdhv7lpV0xSZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VrhlJ/btsNi3H3E3W/ZucNxNsUsRdhv7lpV0xSZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVrhlJ%2FbtsNi3H3E3W%2FZucNxNsUsRdhv7lpV0xSZ0%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;1412&quot; height=&quot;419&quot; data-filename=&quot;Screenshot from 2025-04-11 17-23-13.png&quot; data-origin-width=&quot;1412&quot; data-origin-height=&quot;419&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표시만 sophie일뿐이고 root와 같은 역할을 하고있다고한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;USER 명령어&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;USER 명령어를 사용할때는, 실제로 있는 사용자를 써야지 실행이된다. 그렇기에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같은 명령어로 사용자 생성을 하는것이 USER 명령어를 쓸때 굉장히 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐면 -&amp;gt; 새로만든 컨테이너는 독립적인 네트워크를 가지고있는데 만들때, 생성된 사용자가 없을 가능성이 크기때문이다&lt;/p&gt;
&lt;pre id=&quot;code_1744360111382&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM node:18.12.0

# 사용자 생성
RUN useradd -m appuser

# 이 시점부터 appuser 권한으로 실행
USER appuser

WORKDIR /home/appuser/app
COPY . .
RUN npm install
CMD [&quot;node&quot;, &quot;server.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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너간의 통신 -Nginx, 정적파일?&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nginx&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;User -&amp;gt; Reverse proxy -&amp;gt; Web server&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;Reverse proxy의 장점 ==&amp;gt; Nginx&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;- https 인증서 설치가 쉽다.&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;- IP 차단 등&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;컴퓨터에서 nginx 실행시키기위해서는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. nginx 설치&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. nginx 설정파일 작성 -&amp;gt; conf&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. nginx 실행 명령어 입력&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;아래와 같이 defualt.conf 파일을 만들어서 사용할 수있다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1744594870556&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;server {
    listen 9710;
    server_name localhost;
    client_max_body_size 500M;

    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
        try_files $uri $uri/ /index.html;
    }

    location /api {
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $http_host;
        proxy_pass http://127.0.0.1:10000;
    }

    location /files {
        alias /usr/share/files;
        autoindex on;
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    }

    error_page 500 502 503 504 /50x.html;

    location = /50x.html {
        root /usr/share/nginx/html;
    }
}&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;/etc/nginx/conf.d/defualt.conf (자동파일 생성) =&amp;gt; 우선적용될 가능성이 크다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 프로젝트에서 사용하는 Dockerfile만 봐도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1744595927815&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM node:18.20.3 AS builder

WORKDIR /app

COPY . .

RUN yarn
RUN yarn build

FROM nginx:stable-alpine

RUN rm -rf /etc/nginx/conf.d/default.conf
RUN rm -rf /etc/nginx/nginx.conf

RUN mkdir -p /usr/share/files
RUN chown -R nginx:nginx /usr/share/files 

COPY --from=builder /app/dist /usr/share/nginx/html
COPY --from=builder /app/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/nginx/nginx.conf /etc/nginx/nginx.conf

EXPOSE 9710
CMD [&quot;nginx&quot;, &quot;-g&quot;, &quot;daemon off;&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rm -rf로 default설정 팡리과 nginx.conf를 삭제한후에 다시 복사하기에, 정상적으로 작동이된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 Nignx 설정 파일을 먼저 삭제하고, &lt;b&gt;그 후에 빌드한 결과물에서&amp;nbsp;&lt;/b&gt;커스텀 설정 파일을 복사하는 구조&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ㅡ래서 문제없이 default.conf와 nginx.conf로 덮어쓰기 되는 구조&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과 conf 파일들을 살펴보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발중에는 Nginx 컨테이너는 꺼져있고, &lt;b&gt;운영/배포시점만 Docker 빌드 결과로 만들어진 Nginx 이미지가 실행되도록&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;Dockerfile 구조는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;&lt;b&gt;빌드 전용 스테이지&lt;/b&gt;&quot;와 &quot;&lt;b&gt;운영용 스테이지&lt;/b&gt;&quot; 를 분리한 전형적인 멀티 스테이지 Dockerfile이다.&lt;/p&gt;
&lt;pre id=&quot;code_1744607598079&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM node:18.20.3 AS builder

WORKDIR /app
COPY . .
RUN yarn
RUN yarn build&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 포른트엔드 소스를 설치하고 빌드한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;dist/ 폴더가 생성&lt;/u&gt;되고, 이결과물이 실제로 Nginx에 복사된다. (dist 폴더가 복사된다.)&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;nginx단계 (운영용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1744607678325&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM nginx:stable-alpine

RUN rm -rf /etc/nginx/conf.d/default.conf
RUN rm -rf /etc/nginx/nginx.conf

RUN mkdir -p /usr/share/files
RUN chown -R nginx:nginx /usr/share/files 

COPY --from=builder /app/dist /usr/share/nginx/html
COPY --from=builder /app/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/nginx/nginx.conf /etc/nginx/nginx.conf&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;두번째 스에티지는 운영 시점에 사용될 Nginx 컨테이너를 구성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 서버가아닌 &lt;b&gt;정적 배포 서버&amp;nbsp;&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;&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;개발 중에는 yarn serve를 통해서 vue에서 제공하는 개발 서버를 사용한다.&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;운영/배포 시&lt;/b&gt;에는 Nginx가 필요하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발때 만들어놓은 Dockefile은 Nginx를 통해&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적 파일(dist/)를 /경로에 서빙하고&lt;/li&gt;
&lt;li&gt;/api요청은 백엔드 API 서버로 프록시하고&lt;/li&gt;
&lt;li&gt;/FILES 경로는 로컬 디렉토리 /usr/share/files를 서빙한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상황가능 여부이유&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 94px;&quot; border=&quot;1&quot; data-end=&quot;547&quot; data-start=&quot;309&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;547&quot; data-start=&quot;358&quot;&gt;
&lt;tr style=&quot;height: 42px;&quot; data-end=&quot;469&quot; data-start=&quot;358&quot;&gt;
&lt;td style=&quot;height: 42px;&quot; data-end=&quot;406&quot; data-start=&quot;358&quot;&gt;&lt;b&gt;nginx 없이 Vue dev 서버 (npm run serve)만 띄움&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 42px;&quot; data-end=&quot;430&quot; data-start=&quot;406&quot;&gt;⚠️ 로컬 테스트 O / 외부 접근 X&lt;/td&gt;
&lt;td style=&quot;height: 42px;&quot; data-end=&quot;469&quot; data-start=&quot;430&quot;&gt;개발용 서버는 외부 노출에 적합하지 않고 보안 취약, 설정 부족&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 42px;&quot; data-end=&quot;547&quot; data-start=&quot;470&quot;&gt;
&lt;td style=&quot;height: 42px;&quot; data-end=&quot;502&quot; data-start=&quot;470&quot;&gt;&lt;b&gt;nginx 등 웹서버로 dist/ 폴더를 제공&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 42px;&quot; data-end=&quot;509&quot; data-start=&quot;502&quot;&gt;✅ 가능&lt;/td&gt;
&lt;td style=&quot;height: 42px;&quot; data-end=&quot;547&quot; data-start=&quot;509&quot;&gt;웹브라우저 요청을 받아 실제 HTML, JS를 응답할 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉬어가기: 정적파일 /dist의 개념을 바로알기&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적파일: 서버가 요청이 들어올때 &lt;b&gt;변경없이 그대로&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;- html, css, js, png, svg, npm4, woff 등등&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 서버에서 그대로 보내는 파일 -&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;동적파일: 요청이 들어올때마다 서버가 &lt;b&gt;데이터를 처리해서 결과를 실시간으로 생성&lt;/b&gt;해서 응답하는 방식&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Node.js에서 res.send&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;그렇다면 프론트 프로젝트에서는 왜 build를 때리면 나오는 dist/가 정적 파일인가&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/ 디렉토리에서 .vue, .js, .ts, .scss 등등 작성&lt;/li&gt;
&lt;li&gt;개발중에는 npm run dev, yarn serve 등등 개&lt;b&gt;발 서버가 실시간 빌드&amp;nbsp;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;운영에서는 npm run build, yarn build로 &lt;span style=&quot;color: #ee2323;&quot;&gt;최적화된 번들파일을 생성 -&amp;gt; 이게 dist/&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;dist/ 안에는 보통 이렇게 셋팅된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1744608288532&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;├── index.html
├── assets/
│   ├── app.123abc.js
│   ├── style.456def.css&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 파일들은 서버에서 그냥 &quot;있는 그대로&quot; 보내기만 하면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변환, 렌더링 DB 연동없이도 사용자에게 보여줄수있다.&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;gt; 정적(static)&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;배포시에는 그렇다면 왜 정적파일&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;프론트엔드 앱은 Single Page Applicatoin 으로 대부분 구성이되어있고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 로직은 모두 javascript에 포함돼있으며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버는 그냥 index.html, .js, .css 등 파일만 내려주면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 정적 파일만으로 동작 할 쉬 있는 구조.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 배포시에는 dist만 있으면되는데 ---&amp;gt; 이게 프론트의 최종 산출물&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단계설명&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1545&quot; data-start=&quot;1327&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1545&quot; data-start=&quot;1355&quot;&gt;
&lt;tr data-end=&quot;1399&quot; data-start=&quot;1355&quot;&gt;
&lt;td data-end=&quot;1360&quot; data-start=&quot;1355&quot;&gt;개발&lt;/td&gt;
&lt;td data-end=&quot;1399&quot; data-start=&quot;1360&quot;&gt;src/에서 .vue, .js, .ts 등을 개발&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1437&quot; data-start=&quot;1400&quot;&gt;
&lt;td data-end=&quot;1405&quot; data-start=&quot;1400&quot;&gt;빌드&lt;/td&gt;
&lt;td data-end=&quot;1437&quot; data-start=&quot;1405&quot;&gt;yarn build &amp;rarr; dist/ 폴더 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1489&quot; data-start=&quot;1438&quot;&gt;
&lt;td data-end=&quot;1443&quot; data-start=&quot;1438&quot;&gt;배포&lt;/td&gt;
&lt;td data-end=&quot;1489&quot; data-start=&quot;1443&quot;&gt;dist/를 Nginx 또는 S3, Netlify 같은 정적 서버에 올림&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1545&quot; data-start=&quot;1490&quot;&gt;
&lt;td data-end=&quot;1495&quot; data-start=&quot;1490&quot;&gt;운영&lt;/td&gt;
&lt;td data-end=&quot;1545&quot; data-start=&quot;1495&quot;&gt;클라이언트는 index.html, .js, .css 등을 받아서 앱 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;정적 배포인데 왜 여전히 동적인 웹사이트 처럼 동작하는가&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;정적 배포 = 서버는 파일만 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적으로 보이는 이유 =브라우저가 javascript로 렌더링을 처리하기 때문&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. 정적 배포란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 nginx, s3등 단지 이파일들을 &quot;있는 그대로&quot; 제공한다.&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. 그런데 브라우저는 app.js를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;index.html 안에 포함된 &amp;lt;script src=&quot;/assets/app.js&quot;&amp;gt; 가 실행되면서&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;vue앱이 부팅된다.&lt;/li&gt;
&lt;li&gt;내부적으로 라우터가 활성화 되고&lt;/li&gt;
&lt;li&gt;필요한 데이터를 API 서버에서 가져오고&lt;/li&gt;
&lt;li&gt;DOM을 동적으로 렌더링 한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 실제로 &lt;b&gt;동적인 동작 은 서버가 아닌 브라우저(클라이언트)&lt;/b&gt; 에서 일어난다. --&amp;gt; CSR (Client-Side-Rendering)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1744608731402&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;역할	프론트엔드 개발자	백엔드 개발자
화면 구성	✅ HTML/CSS/JS 렌더링	❌
사용자 이벤트 처리	✅ 버튼 클릭, 폼 입력 등	❌
서버에 요청 보내기	✅ axios, fetch 등 사용	❌
요청 응답 처리	❌	✅ REST API, DB, 인증, 비즈니스 로직 등 처리
데이터베이스 연동	❌	✅&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1227&quot; data-start=&quot;1077&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1090&quot; data-start=&quot;1077&quot;&gt;사용자가 버튼 클릭&lt;/li&gt;
&lt;li data-end=&quot;1130&quot; data-start=&quot;1091&quot;&gt;프론트엔드에서 axios.get('/api/posts') 호출&lt;/li&gt;
&lt;li data-end=&quot;1159&quot; data-start=&quot;1131&quot;&gt;브라우저 &amp;rarr; 백엔드 서버에 HTTP 요청 전송&lt;/li&gt;
&lt;li data-end=&quot;1191&quot; data-start=&quot;1160&quot;&gt;백엔드 서버가 요청을 받아 DB 등에서 데이터 조회&lt;/li&gt;
&lt;li data-end=&quot;1207&quot; data-start=&quot;1192&quot;&gt;JSON으로 응답 반환&lt;/li&gt;
&lt;li data-end=&quot;1227&quot; data-start=&quot;1208&quot;&gt;프론트는 받아서 화면에 렌더링&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;------&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1087&quot; data-start=&quot;1056&quot;&gt;사용자가 &lt;a href=&quot;http://example.com&quot;&gt;http://example.com&lt;/a&gt; 접속&lt;/li&gt;
&lt;li data-end=&quot;1148&quot; data-start=&quot;1088&quot;&gt;Nginx나 S3가 index.html, app.js, style.css를 클라이언트에 전달&lt;/li&gt;
&lt;li data-end=&quot;1170&quot; data-start=&quot;1149&quot;&gt;브라우저에서 app.js 실행&lt;/li&gt;
&lt;li data-end=&quot;1210&quot; data-start=&quot;1171&quot;&gt;axios.get('/api/posts')로 API 요청 발생&lt;/li&gt;
&lt;li data-end=&quot;1234&quot; data-start=&quot;1211&quot;&gt;이 요청은 &lt;b&gt;백엔드 서버로 전송&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1264&quot; data-start=&quot;1235&quot;&gt;백엔드는 DB에서 게시글 조회 후 JSON 응답&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✔️&amp;nbsp;정적&amp;nbsp;파일을&amp;nbsp;서빙하는&amp;nbsp;서버(Nginx,&amp;nbsp;S3&amp;nbsp;등)&amp;nbsp;와&lt;br /&gt;✔️&amp;nbsp;동적&amp;nbsp;데이터를&amp;nbsp;처리하는&amp;nbsp;백엔드&amp;nbsp;서버(API&amp;nbsp;서버)&amp;nbsp;는&lt;br /&gt;▶️ 완전히 다른 역할을 하는 독립된 개념. &lt;b&gt;프론트 = 정적 파일 서버&lt;/b&gt;, &lt;b&gt;백엔드 = API 서버&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1744608920005&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; 이 둘을 하나로 묶는 docker-compose, 혹은 도메인/SSL 연동&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;nginx&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;localhost: 2870 으로 들어오면 localhost:2873 으로 보내기를 해보려는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열어봤자 2873으로 들어가지않는 이유는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상컴퓨터1과 가상컴퓨터2가 따로 존재하기때문이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2025-04-14 15-50-14.png&quot; data-origin-width=&quot;985&quot; data-origin-height=&quot;381&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTLA36/btsNkKPd9me/vmopN43ccytHkPl4dEKYN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTLA36/btsNkKPd9me/vmopN43ccytHkPl4dEKYN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTLA36/btsNkKPd9me/vmopN43ccytHkPl4dEKYN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTLA36%2FbtsNkKPd9me%2FvmopN43ccytHkPl4dEKYN1%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;640&quot; height=&quot;248&quot; data-filename=&quot;Screenshot from 2025-04-14 15-50-14.png&quot; data-origin-width=&quot;985&quot; data-origin-height=&quot;381&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;localhost:2870 으로 들어오면 내컴퓨터말고 가상컴퓨터2의 2873으로 보내야한다 (현 프로젝트에서 사용하는방법)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;back, front 각각의 port로 올리고, 역으로 가상컴퓨터2로 보내는 방식&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2025-04-14 15-51-46.png&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QKSo0/btsNkwdnqtM/6tFXU0rK9fvUowzLmX1im0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QKSo0/btsNkwdnqtM/6tFXU0rK9fvUowzLmX1im0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QKSo0/btsNkwdnqtM/6tFXU0rK9fvUowzLmX1im0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQKSo0%2FbtsNkwdnqtM%2F6tFXU0rK9fvUowzLmX1im0%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;468&quot; height=&quot;187&quot; data-filename=&quot;Screenshot from 2025-04-14 15-51-46.png&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이방식으로는 너무 어려우니까&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크를 하나 파고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상 IP주소를 파는것이 훨씬 빠르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너끼리는 Network를 만들어서 통신한다. (원래 프로젝트에서는 컨테이너를 2개만든것이 아니고 하나의 Dockerfile안에서 결정났었다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2025-04-14 15-52-34.png&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dL5TGI/btsNkwK8t9i/5UZZ3URuWSo5etnKOKPT31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dL5TGI/btsNkwK8t9i/5UZZ3URuWSo5etnKOKPT31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dL5TGI/btsNkwK8t9i/5UZZ3URuWSo5etnKOKPT31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdL5TGI%2FbtsNkwK8t9i%2F5UZZ3URuWSo5etnKOKPT31%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;535&quot; height=&quot;214&quot; data-filename=&quot;Screenshot from 2025-04-14 15-52-34.png&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Check&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 사용하는 방식으로 보면, 역방향으로 reverse 연결을 하는 방식.&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;포론트 nginx 컨테이너가 /api 요청을 127.0.0.1:1000 (localhost) 도는 .env에 host:포트로 설정된 외부 포트로 프록시하고,&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;Docker 기본적으로 컨테이너 내부에서 127.0.0.1은 그 컨테이너 내부 자신을 의미한다.&lt;/p&gt;
&lt;pre id=&quot;code_1744616522414&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;location /api {
    proxy_pass http://127.0.0.1:10000;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 설정은 프론트 컨테이너 내부에서 localhost:10000으로 무조건 프록시요청을 보내는것이다 --&amp;gt; 이방식은 백엔드에서 사용하는 api server의 port번호다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1744616654118&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[사용자 브라우저]
        │
        ▼
http://localhost:9710
        │
        ▼
[nginx 컨테이너:9710]
        │  (정적파일 서빙)
        │
        └── /api 요청 발생
                ▼
       proxy_pass http://127.0.0.1:10000;
                ▼
     [같은 컨테이너에서 127.0.0.1:10000 연결 시도]
                ▼
     [--network=&quot;host&quot; 옵션 덕분에 실제 PC의 10000 포트로 연결됨]
                ▼
     [호스트에서 실행 중인 백엔드 서버로 요청 전달 성공!]&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;p data-ke-size=&quot;size16&quot;&gt;docker&amp;nbsp;run&amp;nbsp;--network=host&amp;nbsp;-p&amp;nbsp;2870:2870&amp;nbsp;nginx:1&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;로 nginx를 띄우면 2870으로 가도, 2873 으로 매칭이된다.&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;Docker에서 &lt;b&gt;volume&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;컨테이너로 DB를 띄우면 문제가, 컨테이너를 껏다켜면 항상 안에있던 내용이 초기화 되고, DB에 있던 데이터도 날아간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 껏다켜도 데이터를 유지하고싶으면 volumne에 데이터를 복사하는 용으로 쓴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 하나의 하드디스크에 폴더 하나 만드는것&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;938&quot; data-origin-height=&quot;537&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w5Y1c/btsNmlBOjKx/ljgPc3fqPxXtS79Ed3RmG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w5Y1c/btsNmlBOjKx/ljgPc3fqPxXtS79Ed3RmG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w5Y1c/btsNmlBOjKx/ljgPc3fqPxXtS79Ed3RmG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw5Y1c%2FbtsNmlBOjKx%2FljgPc3fqPxXtS79Ed3RmG1%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;432&quot; height=&quot;537&quot; data-origin-width=&quot;938&quot; data-origin-height=&quot;537&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 디렉토리. 컨테이너 삭제후에도 보존되는 디렉토리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;호스트 os 기준으로 보자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/var/lib/docker/volumes/my-data/_data&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스 파일 시스템상의 실제 디렉토리인데, Docker가 자동으로 생성/관리해주는 구조이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker Compose&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Makefile과 Docekr Compose의 차이부터 알아보자&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;Makefile은 컴파일 빌드 자동화를 위해 사용되던 도구지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재는 Docker,Frontend, CI/CD등 다양한 곳에서 &lt;b&gt;쉘명령어를 자동으로 실행&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;핵심: &lt;b&gt;도커 명령어를 대신 실행하는 껍데기 스크립트&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;docker-compose는,&lt;b&gt; 여러개의 Docker 컨테이너를 한꺼번에 정의하고 실행&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;예를들면&lt;/p&gt;
&lt;pre id=&quot;code_1744697109627&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: '3'
services:
  frontend:
    build: ./frontend
    ports:
      - &quot;3000:3000&quot;

  backend:
    build: ./backend
    ports:
      - &quot;10000:10000&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;docker-compose up -&amp;gt; 프론트, 백엔드를 동시에 실행&lt;/li&gt;
&lt;li&gt;각 서비스 끼리 이름 기반으로 통신이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심: &lt;b&gt;여러 서비스를 한 세트로 정의하고 함께 관리&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;Docker compose는 docker 명령어들을 한 파일에 보관, 실행이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dcoker compose문법 즉 yaml 파일 형식에 맞춰서 만들어야한다.&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;lt;.yaml 파일 작성법&amp;gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;yaml파일이란 데이터 보관용 파일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.json 파일과 유사하다.&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;두번 스페이스바 치고서 그밑에 작성하기&lt;/p&gt;
&lt;pre id=&quot;code_1744698002667&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(docker-compose.yml)

services:
  컨테이너이름:
    image: 이미지이름
    ports: 
      - 내컴퓨터포트:컨테이너포트
    environment:
      - 환경변수이름=값
      - 환경변수이름=값&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;</description>
      <author>이채야채</author>
      <guid isPermaLink="true">https://developeritchaeyachae.tistory.com/399</guid>
      <comments>https://developeritchaeyachae.tistory.com/399#entry399comment</comments>
      <pubDate>Fri, 11 Apr 2025 13:31:43 +0900</pubDate>
    </item>
    <item>
      <title>LOAD BALANCING</title>
      <link>https://developeritchaeyachae.tistory.com/394</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Load =&amp;nbsp; 서버가 받는 부하 :&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;트래픽이 늘어났을때? 선택할 수 있는 방법이 2개가있다.&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.Vertical Scale up&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;span style=&quot;background-color: #ffc1c8;&quot;&gt;서버자체의&lt;/span&gt; &lt;span style=&quot;color: #000000; background-color: #ffc1c8;&quot;&gt;퍼포먼스&lt;/span&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;RAM이 4GB 였다면 그것을 32GB로 늘릴수도있고, 혹은 CPU가 옛날것이면, 더 좋은 CPU로&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 많은 코어를 가지고있는 CPU로 바꿀 수 가 있다.&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;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.Horizontal Scale out&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;분산시스템을 구축&lt;/span&gt; 이때 중요한게 바로 &lt;b&gt;로드밸런싱!!&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;어떻게, 분산 시키는지 결정하는 그 모듈이. 이 똑똑이가 바로 &lt;span style=&quot;background-color: #fff666;&quot;&gt;&lt;u&gt;로드 밸런서&lt;/u&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;&lt;b&gt;로드밸런싱 방식??&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. round robin&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러대의 서버가있을때 들어오는 request를&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;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.&amp;nbsp; random 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;운이 나쁘면 하나에 걸려서 부하가 걸릴수도있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 사실상은 유니폼하게 request를 받게된다.&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. smart - least connection&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역으로 얼마만큼의 컨넥션을 맺고있는지 알려준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;server a,b,c,d 있으면 a,b는 바쁘고 c,d가 여유롭다.&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;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;4.&amp;nbsp; smart - ratio&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미리 스펙을 개산 후 , ratio를 부여해서 그쪽으로 트래픽을 몰아주고 여러가지 분산 처리를 할 수있다.&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;b&gt;로드밸런싱 구축&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;두가지 방식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 소프트웨어 방식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Ha Proxy, Reverse Proxy(Nginx, Apache)&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. 하드웨어 방식&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;- L4 / L7 Switch&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 비싸지만 안정성이 높음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 아무다 IDC에 출입할 수없고 security적인 측면도 좋다&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;/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;SPOF : Single Point Of Failure&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;로드밸런서도 scale out을 해야한다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tms, tas같은 경우 로드밸런싱을 하고잇을까??&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;- yes.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nginx 자체적으로 로드밸런서를 가지고있고, 설정을 해줄 수가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 웹서버를 구동시키면 그 웹서버 nginx 나 apche 내부에서 로드밸런싱을 하게된다.&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;&amp;nbsp;&lt;/p&gt;</description>
      <author>이채야채</author>
      <guid isPermaLink="true">https://developeritchaeyachae.tistory.com/394</guid>
      <comments>https://developeritchaeyachae.tistory.com/394#entry394comment</comments>
      <pubDate>Fri, 14 Feb 2025 15:54:58 +0900</pubDate>
    </item>
    <item>
      <title>vue.config.js</title>
      <link>https://developeritchaeyachae.tistory.com/391</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;vue.config.js는 vue내부에서 언제 실행되나요?&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1322&quot; data-start=&quot;1277&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;vue-cli-service&lt;/span&gt;가 실행될 때 &lt;b&gt;초기 단계에서&lt;/b&gt; 로드됩니다.&lt;/li&gt;
&lt;li data-end=&quot;1448&quot; data-start=&quot;1323&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;vue-cli-service serve&lt;/span&gt; (개발 서버 실행) 또는 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;vue-cli-service build&lt;/span&gt; (빌드 실행) 시 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;vue.config.js&lt;/span&gt;를 읽어 Webpack 및 기타 툴의 설정을 동적으로 변경합니다.&lt;/li&gt;
&lt;li data-end=&quot;1540&quot; data-start=&quot;1449&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;vue.config.js&lt;/span&gt;는 Vue 프레임워크의 런타임이 아니라 &lt;b&gt;빌드 타임&lt;/b&gt;에서 실행되며, Webpack을 포함한 빌드 프로세스의 일부로 동작합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vue-cli-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;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;384&quot; data-start=&quot;294&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;vue-cli-servic&lt;/span&gt;e는 Vue CLI(@vue/cli)에 의해 설치되는 패키지로, Vue 프로젝트를 실행, 빌드, 테스트, 배포하는 데 사용됩니다.&lt;/li&gt;
&lt;li data-end=&quot;459&quot; data-start=&quot;385&quot;&gt;Vue 프레임워크 자체(vue 패키지)에는 포함되지 않으며, Vue 프로젝트를 편리하게 관리하기 위한 &lt;b&gt;빌드 도구&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li data-end=&quot;537&quot; data-start=&quot;460&quot;&gt;Webpack, Babel, ESLint 등의 빌드 관련 툴을 자동으로 설정하고, 필요에 따라 사용자 정의 설정을 반영할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론:&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2262&quot; data-start=&quot;2163&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;vue-cli-service&lt;/span&gt;는 Vue 프레임워크 내부에 존재하는 것이 아니라, &lt;b&gt;Vue CLI(@vue/cli)의 일부로 제공되는 독립적인 빌드 및 개발 도구&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li data-end=&quot;2341&quot; data-start=&quot;2263&quot;&gt;Vue 프로젝트를 실행, 빌드, 테스트하기 위해 사용되며,&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt; vue.config.js를 통해 Webpack 설정을 조정&lt;/span&gt;할 &lt;/span&gt;수 있습니다.&lt;/li&gt;
&lt;li data-is-last-node=&quot;&quot; data-end=&quot;2448&quot; data-start=&quot;2342&quot;&gt;Vue 프레임워크(vue 패키지)와는 별개이며, Vue의 UI 렌더링이나 반응형 시스템을 담당하는 것이 아니라, &lt;b&gt;Vue 프로젝트의 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;개발 및 빌드 환경&lt;/span&gt;을 관리하는 역할&lt;/b&gt;을 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vue.config.js의 샘플을 통해서 설정을 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1739411742229&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const { defineConfig } = require(&quot;@vue/cli-service&quot;);
const NodePolyfillPlugin = require(&quot;node-polyfill-webpack-plugin&quot;);

const API_IP = &quot;10.30.200.15&quot;;
const API_PORT = &quot;8090&quot;;

module.exports = defineConfig({
    transpileDependencies: true,
    configureWebpack: {
        plugins: [new NodePolyfillPlugin()],
    },
    chainWebpack: (config) =&amp;gt; {
        config.plugin(&quot;html&quot;).tap((args) =&amp;gt; {
            args[0].title = &quot;Laon Sentinel&quot;;
            return args;
        });
    },
    devServer: {
        proxy: {
            &quot;/api&quot;: {
                target: `http://${API_IP}:${API_PORT}/api/test`,
                changeOrigin: true,
                pathRewrite: {
                    &quot;^/api&quot;: &quot;&quot;,
                },
            },
            &quot;/prod&quot;: {
                target: &quot;http://10.30.8.12:10000/api/v1/sentinel&quot;,
                changeOrigin: true,
                pathRewrite: {
                    &quot;^/prod&quot;: &quot;&quot;,
                },
            },
        },
    },
    css: {
        loaderOptions: {
            sass: {
                additionalData: `@import &quot;@/assets/scss/abstracts/variable&quot;;`,
            },
        },
    },
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;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;1. 기본 설정 및 플러그인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1739412724046&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const { defineConfig } = require(&quot;@vue/cli-service&quot;);
const NodePolyfillPlugin = require(&quot;node-polyfill-webpack-plugin&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;295&quot; data-start=&quot;217&quot;&gt;defineConfig : Vue CLI 4.5 이상에서 defineConfig를 사용하면 자동 완성 및 타입 지원이 향상됩니다.&lt;/li&gt;
&lt;li data-end=&quot;465&quot; data-start=&quot;296&quot;&gt;NodePolyfillPlugin : Node.js의 일부 내장 모듈(fs, path, crypto 등)을 브라우저에서 사용할 수 있도록 Webpack에 폴리필(polyfill)을 추가하는 플러그인입니다. 이를 통해 브라우저 환경에서도 일부 Node.js API를 사용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. API 서버 IP 및 포트 정의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1739412755566&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const API_IP = &quot;10.30.200.15&quot;;
const API_PORT = &quot;8090&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;606&quot; data-start=&quot;574&quot;&gt;API 서버의 기본 IP와 포트를 정의하는 상수입니다.&lt;/li&gt;
&lt;li data-end=&quot;663&quot; data-start=&quot;607&quot;&gt;이후 devServer.proxy에서 이 값을 사용하여 API 요청을 프록시할 때 활용됩니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. module.exports 내 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1739412787622&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;module.exports = defineConfig({&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-start=&quot;607&quot; data-end=&quot;663&quot;&gt;defineConfig를 사용하여 Vue CLI 서비스의 설정을 정의합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;defineConfig를 사용하여 Vue CLI 서비스의 설정을 정의합니다.&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;4. transpileDependencies: true&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1739412886504&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;transpileDependencies: true,&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;947&quot; data-start=&quot;892&quot;&gt;Babel이 node_modules 안의 일부 패키지를 트랜스파일하도록 설정하는 옵션입니다.&lt;/li&gt;
&lt;li data-end=&quot;1028&quot; data-start=&quot;948&quot;&gt;보통 ES6+로 작성된 외부 라이브러리가 IE11 같은 구형 브라우저에서 실행되지 않을 경우, 이 옵션을 사용하여 트랜스파일할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. configureWebpack 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1739412923823&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;configureWebpack: {
    plugins: [new NodePolyfillPlugin()],
},&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1177&quot; data-start=&quot;1149&quot;&gt;Webpack 설정을 직접 수정하는 옵션입니다.&lt;/li&gt;
&lt;li data-end=&quot;1254&quot; data-start=&quot;1178&quot;&gt;NodePolyfillPlugin 플러그인을 추가하여 브라우저 환경에서도 일부 Node.js 모듈을 사용할 수 있도록 설정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. chainWebpack 설정 (HTML 타이틀 변경)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1739412951441&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chainWebpack: (config) =&amp;gt; {
    config.plugin(&quot;html&quot;).tap((args) =&amp;gt; {
        args[0].title = &quot;Laon Sentinel&quot;;
        return args;
    });
},&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1516&quot; data-start=&quot;1464&quot;&gt;chainWebpack은 Webpack의 설정을 체인 형태로 수정할 수 있도록 합니다.&lt;/li&gt;
&lt;li data-end=&quot;1644&quot; data-start=&quot;1517&quot;&gt;여기서는 Vue 프로젝트에서 index.html을 생성하는 &lt;b&gt;HTMLWebpackPlugin&lt;/b&gt;의 설정을 수정하여, 브라우저 탭에 표시될 기본 &lt;b&gt;타이틀(title)&lt;/b&gt; 을 &quot;Laon Sentinel&quot;로 변경합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. devServer 설정 (API 프록시)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1739412995215&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;devServer: {
    proxy: {
        &quot;/api&quot;: {
            target: `http://${API_IP}:${API_PORT}/api/test`,
            changeOrigin: true,
            pathRewrite: {
                &quot;^/api&quot;: &quot;&quot;,
            },
        },
        &quot;/prod&quot;: {
            target: &quot;http://10.30.8.12:10000/api/v1/sentinel&quot;,
            changeOrigin: true,
            pathRewrite: {
                &quot;^/prod&quot;: &quot;&quot;,
            },
        },
    },
},&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2239&quot; data-start=&quot;2130&quot;&gt;개발 서버(vue-cli-service serve) 실행 시 프록시(proxy) 설정을 적용하여, 특정 경로(/api, /prod)로 요청을 보낼 때 API 서버로 리다이렉트합니다.&lt;/li&gt;
&lt;li data-end=&quot;2755&quot; data-start=&quot;2240&quot;&gt;proxy 설정의 각 속성 설명:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2575&quot; data-start=&quot;2265&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2378&quot; data-start=&quot;2265&quot;&gt;&quot;/api&quot; : API 요청을 로컬 개발 서버(localhost:8080)가 아니라 &lt;b&gt;실제 API 서버&lt;/b&gt; (http://${API_IP}:${API_PORT}/api/test)로 보냄.&lt;/li&gt;
&lt;li data-end=&quot;2415&quot; data-start=&quot;2381&quot;&gt;target : 요청을 보낼 실제 API 서버의 주소.&lt;/li&gt;
&lt;li data-end=&quot;2491&quot; data-start=&quot;2418&quot;&gt;changeOrigin: true : 브라우저에서 요청할 때 &lt;b&gt;CORS 문제를 방지&lt;/b&gt;하기 위해 origin을 변경함.&lt;/li&gt;
&lt;li data-end=&quot;2572&quot; data-start=&quot;2494&quot;&gt;pathRewrite : 프록시 요청 시 경로 변경 (/api를 빈 문자열로 변환하여 실제 API 요청에서 /api를 제거).&lt;/li&gt;
&lt;/ul&gt;
예제:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2755&quot; data-start=&quot;2584&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2685&quot; data-start=&quot;2584&quot;&gt;클라이언트에서 http://localhost:8080/api/users 요청 &amp;rarr; http://10.30.200.15:8090/api/test/users로 변환되어 전송됨.&lt;/li&gt;
&lt;li data-end=&quot;2755&quot; data-start=&quot;2688&quot;&gt;/prod도 같은 방식으로 http://10.30.8.12:10000/api/v1/sentinel로 라우팅됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 설정을 통해:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3966&quot; data-start=&quot;3840&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3873&quot; data-start=&quot;3840&quot;&gt;개발 환경에서 API 요청이 자동으로 서버로 프록시되고,&lt;/li&gt;
&lt;li data-end=&quot;3924&quot; data-start=&quot;3874&quot;&gt;프로젝트의 index.html 타이틀이 &quot;Laon Sentinel&quot;로 설정되며,&lt;/li&gt;
&lt;li data-end=&quot;3966&quot; data-start=&quot;3925&quot;&gt;SCSS 전역 변수를 추가하는 등의 편리한 기능을 활용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>이채야채</author>
      <guid isPermaLink="true">https://developeritchaeyachae.tistory.com/391</guid>
      <comments>https://developeritchaeyachae.tistory.com/391#entry391comment</comments>
      <pubDate>Thu, 13 Feb 2025 11:22:20 +0900</pubDate>
    </item>
    <item>
      <title>gateway - self</title>
      <link>https://developeritchaeyachae.tistory.com/387</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;TODO : 에러코드 통일화, 상황에 알맞는 에러코드 사용하기,&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;1. /api/v1/user/self2 -&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1728965456468&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    getUserInfo: () =&amp;gt; {
        return get(GATEWAY_URLS.SELF, &quot;&quot;);
    },&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;TMS 사용하는곳&lt;/u&gt;&lt;br /&gt;세션확인을위해 router에서 접근할때마다 확인하는 용도&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;span style=&quot;color: #006dd7;&quot;&gt;TEST1&lt;/span&gt;: 로그인 안되어있어서 로그인페이지로 가야하는 상황(로그인 상태확인)&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;에러코드: 27001&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; -&amp;nbsp;user 아이디를 가져올수없음, 세션이 아이디x 세션 만료 혹은 확인할 수 없음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;수정사항(메시지) :&amp;nbsp; 사용자 ID를 가져오는 데 실패했습니다. /혹은/ 접근권한이 없습니다 (27001 코드 여기서만 사용하는방향으로)&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;2. /api/v1/user/self2/auth&lt;/p&gt;
&lt;pre id=&quot;code_1728965707884&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    requestLogin: ({ ID, Password }) =&amp;gt; {
        return post(GATEWAY_URLS.SELF, &quot;/auth&quot;, { ID, Password });
    },&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;* 유의사항: ID나, PASSWORD가 빈값일때는 프론트 내부에서 서버에 전송이안되도록 에러처리를 해놓음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- TAS도 내부에서 처리로직 있는지 확인&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;u&gt;사용하는곳&lt;/u&gt;&lt;br /&gt;로그인 페이지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;-&lt;span style=&quot;color: #006dd7;&quot;&gt;TEST1&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;:&lt;span&gt; 프론트에서 서버에 PARAM을 보낼때,&amp;nbsp; ID나 PASSWORD를 아예 빼먹을때(개발자 코드 문제)&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;에러코드: 27011 &lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; - &lt;span style=&quot;background-color: #ffffff; color: #dc362e; text-align: left;&quot;&gt;id or password is empty&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;수정사항(에러코드): 8000으로 수정.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;수정사항(에러메시지): 27011 - 입력값이 없습니다. (현재 빈값)&amp;nbsp;&amp;nbsp;&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;-&lt;span style=&quot;color: #006dd7;&quot;&gt;TEST2&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;:&lt;span&gt;&lt;span&gt; Password에 SHA256을 넣지않고 Password: 1234 로 보냈을때&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;에러코드: 8000&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;- &lt;span style=&quot;background-color: #ffffff; text-align: left;&quot;&gt;failed to bind json , json: cannot unmarshal number into Go struct field RequestUserLogin.Password of type string&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;** 8000일때는 메시지를 띄우면 x 내부에러. 2000번때일때만 error code를 띄우게 변경하기&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;문제없음&amp;nbsp;&amp;nbsp;&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;-&lt;span style=&quot;color: #006dd7;&quot;&gt;TEST3: &lt;span style=&quot;color: #333333;&quot;&gt;LAON2023 과, 비밀번호 제대로 쳤지만, LAON2023은 없는 아이디이고, 사용자가 비밀번호를 제대로쳤지만 PARAM이 안들어간경우(개발자문제 혹은 내부)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;에러코드: 27011&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #dc362e; text-align: left;&quot;&gt;id or password is empty&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Test1수정하면 자동 수정 8000으로 변경될것같음. (에러코드는 유지하지만, test1같은 경우를 8000으로 돌릴경우 27011코드는 나올일이 거의없을것같습니다)&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;-&lt;span style=&quot;color: #006dd7;&quot;&gt;TEST4:&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;LAON2023 과 비밀번호 제대로 쳤지만, LAON2023은 없는 아이디이고, 사용자가 비밀번호를 제대로쳤지만 SHA256문제가 생기도록 1234로 넣어봤을때(개발자 문제 혹은 내부문제)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;에러코드: 8000&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;-&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: left;&quot;&gt;failed to bind json , json: cannot unmarshal number into Go struct field RequestUserLogin.Password of type string&quot; 입력값이 잘못되었습니다&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: left;&quot;&gt;-&amp;gt; 백엔드 수선코드가 아이디확인 이전에 SHA256부터 감지하는것같음. DB를 찾기전에 RETURN?&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;-&lt;span style=&quot;color: #006dd7;&quot;&gt;TEST5: &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;LAON2023(없는 아이디) 과 비밀번호 제대로 친경우&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;에러코드: 27006 - &lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: left;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&quot;does not exist user id&quot;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;수정사항(에러메시지): 에러메시지 추가 27006 - 존재하지 않는 사용자.&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;-&lt;span style=&quot;color: #006dd7;&quot;&gt;TEST6:&lt;span style=&quot;color: #333333;&quot;&gt; laon(알맞은 사용자), laon2021!(사용자가 틀린비밀번호, SHA256은 재대로)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;에러코드: 27001 -&lt;span&gt; &lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: left;&quot;&gt;ErrorDetail: {FailCount: 3, FailTime: 0}} 아이디 또는 비밀번호를 잘못 입력하셨습니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;수정사항(에러메시지): 27001 코드를 쓰지않고, 27000 을 쓰는게 맞아보인다. -&amp;gt; TEST1에서 27001을 사용하고, 여기서는 비밀번호가 틀렸을때 에러코드에 초점을 맞추는게 좋지않을까? -&amp;gt; 아니면 TEST1부분을 수정하던가. 둘중하나 수정필요.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이유 : 아이디는 잘못 입력했을때, 존재하지않는 사용자라고 나오며, 빈값으로는 아예 보낼수가없기에 비번틀렸던거로 MESSAGE나 코드를 디테일하게 에러디테일 또한 failcount, failtime 비밀번호에 중점을 둔 사례&amp;nbsp;&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;-&lt;span style=&quot;color: #006dd7;&quot;&gt;TEST7:&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;laon3(알맞은 사용자 but 승인안해줌), laon2021!(사용자가 틀린비밀번호, SHA256은 재대로)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;에러코드: 27007 -&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt; &lt;span style=&quot;background-color: #ffffff; text-align: left;&quot;&gt;&quot;permission denined, permission = none&quot;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;수정사항(에러코드): 27007 -&amp;gt; 8000으로 수정.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;수정사항(메시지)&lt;span&gt;&amp;nbsp;&lt;/span&gt;:&amp;nbsp; 27007 에러메시지, (스웨거: 권한 에러 )-&amp;gt; 회원가입 승인 요청이 대기 중입니다. 에러코드 변경하거나 권한쪽을 하나 더 파던가해야할듯싶습니다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #409d00;&quot;&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;-&lt;span style=&quot;color: #006dd7;&quot;&gt;TEST8(성공사례) - &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: left;&quot;&gt;{StatusCode: 0, Message: &quot;성공&quot;, Data: {IsLogin: true, ID: &quot;laon&quot;, Permission: 3}}&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;&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: left;&quot;&gt;***이외: 90일 초과는 확인 불가. 로그인중이 아닙니다.? 나오는 상황&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;3. /api/v1/user/self2/password&lt;/p&gt;
&lt;pre id=&quot;code_1729053925059&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; changePassword: ({ ID, BeforePassword, AfterPassword }) =&amp;gt; {
        return put(GATEWAY_URLS.SELF, &quot;/password&quot;, {
            ID,
            BeforePassword,
            AfterPassword,
        });
    },&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&lt;span style=&quot;color: #006dd7;&quot;&gt;TEST1&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;:&lt;span&gt;&lt;span&gt; 없는 아이디, 위아래 똑같은 password - 프론트에서 막을예정&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;에러코드: &lt;span style=&quot;background-color: #ffffff; text-align: left;&quot;&gt;27010&lt;/span&gt; -&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;nbsp;&lt;span style=&quot;background-color: #ffffff;&quot;&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;-&lt;span style=&quot;color: #006dd7;&quot;&gt;TEST2&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;에러코드:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; text-align: left;&quot;&gt;27001&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;수정사항(메시지)&lt;span&gt;&amp;nbsp;&lt;/span&gt;:&amp;nbsp; &lt;span style=&quot;background-color: #ffffff; color: #172b4d; text-align: left;&quot;&gt;27000&lt;/span&gt; 수정 부탁합니다!&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;-&lt;span style=&quot;color: #006dd7;&quot;&gt;TEST2&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;: 없는&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;아이디, 현재 비밀번호 틀렸을경우&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;에러코드:&lt;/span&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; text-align: left;&quot;&gt;27006&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1728966077849&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; 	creatUserData: ({ ID, Password, Permission }) =&amp;gt; {
        return post(GATEWAY_URLS.SELF, &quot;&quot;, { ID, Password, Permission });
    },
    addPageNavigationHistory: ({ URL }) =&amp;gt; {
        return post(GATEWAY_URLS.SELF, &quot;/page&quot;, { URL });
    },
    changePassword: ({ ID, BeforePassword, AfterPassword }) =&amp;gt; {
        return put(GATEWAY_URLS.SELF, &quot;/password&quot;, {
            ID,
            BeforePassword,
            AfterPassword,
        });
    },
    extendPasswordExpiration: ({ ID, BeforePassword, AfterPassword }) =&amp;gt; {
        return put(GATEWAY_URLS.SELF, &quot;/password/extension&quot;, {
            ID,
            BeforePassword,
            AfterPassword,
        });
    },
    deleteUserData: ({ ID }) =&amp;gt; {
        return del(GATEWAY_URLS.SELF, &quot;&quot;, { ID });
    },
    requestLogout: () =&amp;gt; {
        return del(GATEWAY_URLS.SELF, &quot;/auth&quot;);
    },
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>이채야채</author>
      <guid isPermaLink="true">https://developeritchaeyachae.tistory.com/387</guid>
      <comments>https://developeritchaeyachae.tistory.com/387#entry387comment</comments>
      <pubDate>Tue, 15 Oct 2024 14:45:18 +0900</pubDate>
    </item>
    <item>
      <title>vue - slot</title>
      <link>https://developeritchaeyachae.tistory.com/376</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;vue는 slot을 사용하여 할 수 있는 일이 많이 있는듯 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자식컴포넌트에게 간단하게 무언가를 전달할수가있는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그때 사용하고 싶은 구간에서 slot태그를 사용해서 넣어본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716790465854&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup&amp;gt;
import SubmitButton from './SubmitButton.vue'
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;!-- 대체 텍스트 사용 --&amp;gt;
  &amp;lt;SubmitButton /&amp;gt;
  
  &amp;lt;!-- 사용자 정의 텍스트 제공 --&amp;gt;
  &amp;lt;SubmitButton&amp;gt;부모컴포넌트가이김&amp;lt;/SubmitButton&amp;gt;
&amp;lt;/template&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;이렇게 해줬을때,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자식 컴포넌트안에&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716790518720&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;button type=&quot;submit&quot;&amp;gt;
	  &amp;lt;slot&amp;gt;
    	제출 &amp;lt;!-- 대체 컨텐츠 --&amp;gt;
  	&amp;lt;/slot&amp;gt;
	&amp;lt;/button&amp;gt;
&amp;lt;/template&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;이렇게 사용했어도 버튼모양은 제출이 뜨는것이 아니고&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;좀더 심화하여,&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;/p&gt;
&lt;pre id=&quot;code_1716790613246&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;container&quot;&amp;gt;
  &amp;lt;header&amp;gt;
    &amp;lt;!-- 우리는 여기에 헤더 컨텐츠를 원합니다. --&amp;gt;
  &amp;lt;/header&amp;gt;
  &amp;lt;main&amp;gt;
    &amp;lt;!-- 우리는 여기에 메인 컨텐츠를 원합니다. --&amp;gt;
  &amp;lt;/main&amp;gt;
  &amp;lt;footer&amp;gt;
    &amp;lt;!-- 우리는 여기에 푸터 컨텐츠를 원합니다. --&amp;gt;
  &amp;lt;/footer&amp;gt;
&amp;lt;/div&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;위와같은 모양의 구조를 만든다고 가정해보자,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;name이라는 특수속성을 사용한다고 할때 마치 ID처럼 SLOT에게 이름을 부여해줄 수 잇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716790766391&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;container&quot;&amp;gt;
  &amp;lt;header&amp;gt;
    &amp;lt;slot name=&quot;header&quot;&amp;gt;&amp;lt;/slot&amp;gt;
  &amp;lt;/header&amp;gt;
  &amp;lt;main&amp;gt;
    &amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;
  &amp;lt;/main&amp;gt;
  &amp;lt;footer&amp;gt;
    &amp;lt;slot name=&quot;footer&quot;&amp;gt;&amp;lt;/slot&amp;gt;
  &amp;lt;/footer&amp;gt;
&amp;lt;/div&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;MAIN부분에 이름 속성없는 아이는 임시적으로 default라는 이름을 가지게도니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716790882373&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;BaseLayout&amp;gt;
  &amp;lt;template v-slot:header&amp;gt;
    &amp;lt;!-- 헤더 슬롯의 컨텐츠 --&amp;gt;
  &amp;lt;/template&amp;gt;
&amp;lt;/BaseLayout&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;이름있는 slot전달할때는 template을 함께 사용해서 전달을 해야한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1376&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rLc0Y/btsHCoFUxOd/65C2UytNKP5xkuyqouZQ40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rLc0Y/btsHCoFUxOd/65C2UytNKP5xkuyqouZQ40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rLc0Y/btsHCoFUxOd/65C2UytNKP5xkuyqouZQ40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrLc0Y%2FbtsHCoFUxOd%2F65C2UytNKP5xkuyqouZQ40%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;1376&quot; height=&quot;640&quot; data-origin-width=&quot;1376&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름있는 슬롯컨텐츠 전달할때 이렇게 사용해도된다&lt;/p&gt;
&lt;pre id=&quot;code_1716790942292&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;BaseLayout&amp;gt;
  &amp;lt;template #header&amp;gt;
    &amp;lt;h1&amp;gt;다음은 페이지 제목일 수 있습니다.&amp;lt;/h1&amp;gt;
  &amp;lt;/template&amp;gt;

  &amp;lt;template #default&amp;gt;
    &amp;lt;p&amp;gt;주요 내용에 대한 단락입니다.&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;그리고 또 하나.&amp;lt;/p&amp;gt;
  &amp;lt;/template&amp;gt;

  &amp;lt;template #footer&amp;gt;
    &amp;lt;p&amp;gt;다음은 연락처 정보입니다.&amp;lt;/p&amp;gt;
  &amp;lt;/template&amp;gt;
&amp;lt;/BaseLayout&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fff666;&quot;&gt;template 엘리먼트 내부의&amp;nbsp; 해당슬롯으로 전달된다.&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;자식부분에서 그렇담 어떻게 보여지는가?&lt;/p&gt;
&lt;pre id=&quot;code_1716791049373&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class=&quot;container&quot;&amp;gt;
    &amp;lt;header&amp;gt;
      &amp;lt;slot name=&quot;header&quot;&amp;gt;&amp;lt;/slot&amp;gt;
    &amp;lt;/header&amp;gt;
    &amp;lt;main&amp;gt;
      &amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;
    &amp;lt;/main&amp;gt;
    &amp;lt;footer&amp;gt;
      &amp;lt;slot name=&quot;footer&quot;&amp;gt;&amp;lt;/slot&amp;gt;
    &amp;lt;/footer&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;style&amp;gt;
  footer {
    border-top: 1px solid #ccc;
    color: #666;
    font-size: 0.8em;
  }
&amp;lt;/style&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;이름으로 엮어서, 여러가지 정보를 다 다르게 밑으로 내려줄수있다는 말이다.&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;</description>
      <author>이채야채</author>
      <guid isPermaLink="true">https://developeritchaeyachae.tistory.com/376</guid>
      <comments>https://developeritchaeyachae.tistory.com/376#entry376comment</comments>
      <pubDate>Mon, 27 May 2024 15:42:22 +0900</pubDate>
    </item>
    <item>
      <title>vue - watch</title>
      <link>https://developeritchaeyachae.tistory.com/375</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;watch사용시에 유의해야할 점.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 값참조&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716340956325&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const obj = reactive({ count: 0 })

// 이것은 작동하지 않습니다. watch()에 숫자를 전달하고 있기 때문입니다.
watch(obj.count, (count) =&amp;gt; {
  console.log(`Count는: ${count}입니다`)
})

// getter를 사용해야한다.
watch(
  () =&amp;gt; obj.count,
  (count) =&amp;gt; {
    console.log(`Count는: ${count}입니다`)
  }
)&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;2. 깊은감시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #e50000;&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #e50000;&quot;&gt;someObject&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #e50000;&quot;&gt;nestedProperty&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color: #a31515;&quot;&gt;'another value'&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;; 로 바꿀시에는,&amp;nbsp; 깊은감시로 참조를 할 수 있고,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얕은 감시에는&lt;span style=&quot;color: #000000;&quot;&gt; &lt;span style=&quot;text-align: left;&quot;&gt;state.&lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;someObject&lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt; = { &lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;nestedProperty&lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;'new value'&lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&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;&lt;span style=&quot;color: #000000;&quot;&gt;한단계 아래까지만 사용을 하고 있어서, 깊게 감시할 수 없다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716340653450&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup&amp;gt;
import { onMounted, ref, watch, reactive } from 'vue'

const state = reactive({
  someObject: {
    nestedProperty: 'value'
  }
});

// 기본 watch: 객체 자체가 교체될 때만 반응
watch(
  () =&amp;gt; state.someObject,
  (newValue, oldValue) =&amp;gt; {
    console.log('기본 watch:', newValue, oldValue);
  }
);

// deep watch: 객체의 모든 속성 변화를 감지
watch(
  () =&amp;gt; state.someObject,
  (newValue, oldValue) =&amp;gt; {
    console.log('deep watch:', newValue, oldValue);
  },
  { deep: true }
);

// 테스트 변화



const test = ()=&amp;gt;{
 // 기본 watch와 deep watch 모두 감지
state.someObject.nestedProperty = 'another value';
}
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  
  &amp;lt;div&amp;gt;
    &amp;lt;div disabled value=&quot;&quot;&amp;gt;깊음감시공부하기&amp;lt;/div&amp;gt;
    &amp;lt;div @click=&quot;test&quot;&amp;gt;가&amp;lt;/div&amp;gt;

  &amp;lt;/div&amp;gt;
&amp;lt;/template&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. immediate 옵션과 함께 사용할때와, 아닐때 차이는?&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을 걸어봤을때, count를 변경시키면 count가 변경될때만 변경이된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 &lt;span style=&quot;background-color: #fff666;&quot;&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;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;하지만 immediate: true 속성을 넣는다면, 최초에 mount될때 내부의 코드가 동작한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716341347838&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;첫 번째 경우:
2초 후에만 로그가 출력됩니다: Watch without immediate: 1 0
두 번째 경우:
컴포넌트가 마운트되자마자 로그가 출력됩니다: Watch with immediate: 0 undefined
2초 후에 다시 로그가 출력됩니다: Watch with immediate: 1 0&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;4. once감시자.&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;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;단 한번만 감시하고 이후부터는 감시하지않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;useEffect의 [상태] + [] 와 비슷한것같다.&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;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;5. watchEffect&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;immediate: true를 사용하지않고서 즉시 실행할수있게만들어준것?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&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;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;종속성을 명시적으로 지정할 필요없고, immdeditate기능이 탑재되어있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;하지만 의도하지않은 반응성상태까지 추적이된다. &lt;/span&gt;&lt;/p&gt;</description>
      <category>Vue</category>
      <author>이채야채</author>
      <guid isPermaLink="true">https://developeritchaeyachae.tistory.com/375</guid>
      <comments>https://developeritchaeyachae.tistory.com/375#entry375comment</comments>
      <pubDate>Wed, 22 May 2024 13:05:19 +0900</pubDate>
    </item>
    <item>
      <title>도커</title>
      <link>https://developeritchaeyachae.tistory.com/371</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;어플리케이션을 &lt;u&gt;패키징&lt;/u&gt; 할 수 있는 tool&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;b&gt;application&lt;/b&gt;, 그에필요한 &lt;b&gt;system tools&lt;/b&gt;, 환경설정, &lt;b&gt;dependencies&lt;/b&gt;를 하나로 묶어 = 컨테이너 (하나의 작은 소프트웨어 유닛)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 서버, 다른 PC&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;그 어떤것에도 쉽게 배포하고, 안정적으로 구동할 수 있게 도와주는 tool&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2024-05-17 09-12-42.png&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EovBp/btsHr8u9mFY/iMdVrKjlLZFeHqemSkP77k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EovBp/btsHr8u9mFY/iMdVrKjlLZFeHqemSkP77k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EovBp/btsHr8u9mFY/iMdVrKjlLZFeHqemSkP77k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEovBp%2FbtsHr8u9mFY%2FiMdVrKjlLZFeHqemSkP77k%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;544&quot; height=&quot;293&quot; data-filename=&quot;Screenshot from 2024-05-17 09-12-42.png&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테크놀로지가 복잡해짐에 따라서, 우리 어플리케이션 구동에는 꽤 많은 것들이 필요하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;node.js를 예로 들어보자, 우리의 소스파일(코드 친것) 만 서버에 배포하는것으로는&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;nodejs, npm 여러 라이브러리를 사용한다면, 여러 dependencies, configs(환경설정) 하는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모든 것들을 설정 해줘야한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2024-05-17 09-17-21.png&quot; data-origin-width=&quot;1009&quot; data-origin-height=&quot;518&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4MkPe/btsHrq4n8o2/Q9jcQmbTSD2n0bJ3UuGDn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4MkPe/btsHrq4n8o2/Q9jcQmbTSD2n0bJ3UuGDn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4MkPe/btsHrq4n8o2/Q9jcQmbTSD2n0bJ3UuGDn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4MkPe%2FbtsHrq4n8o2%2FQ9jcQmbTSD2n0bJ3UuGDn0%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;515&quot; height=&quot;264&quot; data-filename=&quot;Screenshot from 2024-05-17 09-17-21.png&quot; data-origin-width=&quot;1009&quot; data-origin-height=&quot;518&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버마다, 개발자들의 pc마다 이런 모든것들을 설치 하고 설정하는것은 꽤 번거롭고, 오류가 있을 수 있다.&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-filename=&quot;Screenshot from 2024-05-17 09-19-56.png&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;554&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bABWAK/btsHszF0m1c/LqowuPjQMdd4TyggH9bF70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bABWAK/btsHszF0m1c/LqowuPjQMdd4TyggH9bF70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bABWAK/btsHszF0m1c/LqowuPjQMdd4TyggH9bF70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbABWAK%2FbtsHszF0m1c%2FLqowuPjQMdd4TyggH9bF70%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;506&quot; height=&quot;269&quot; data-filename=&quot;Screenshot from 2024-05-17 09-19-56.png&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;554&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 pc에서 잘된다고 server에서 잘되지않을 수 있다. (버전이 달라서..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커안에는 그렇담 뭐뭐 포함 될 수 가 있을까?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2024-05-17 09-28-29.png&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;585&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIab5A/btsHtc4COwS/ByHBav8qGFcNiKY0ptrVz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIab5A/btsHtc4COwS/ByHBav8qGFcNiKY0ptrVz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIab5A/btsHtc4COwS/ByHBav8qGFcNiKY0ptrVz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIab5A%2FbtsHtc4COwS%2FByHBav8qGFcNiKY0ptrVz1%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;551&quot; height=&quot;424&quot; data-filename=&quot;Screenshot from 2024-05-17 09-28-29.png&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;585&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소스코드 app.js + 정상적으로 작동하기위한 node.js + 환경설정 configuration + npm + 여러 라이브러리들의&amp;nbsp; dependencies + 어플리케이션에 필요한 다양한 resource들&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;도커를 사용하여, 어디에서든, 어떤 pc에서도 동일하게 구동할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커의 container 그리고 vm?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2024-05-17 09-34-14.png&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;595&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DJ4CR/btsHtfAhrUp/ktuuAJiaYkk0UZ4BpUWeM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DJ4CR/btsHtfAhrUp/ktuuAJiaYkk0UZ4BpUWeM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DJ4CR/btsHtfAhrUp/ktuuAJiaYkk0UZ4BpUWeM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDJ4CR%2FbtsHtfAhrUp%2FktuuAJiaYkk0UZ4BpUWeM0%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;556&quot; height=&quot;319&quot; data-filename=&quot;Screenshot from 2024-05-17 09-34-14.png&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;595&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vm은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드웨어 Infrastructure위에 vmware나 virtualbox같은 hypervisor 소프트웨어을 이용하여, 각각의 가상의 머신을 만들 수 있다.&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;이 virtual machine을 이용해서 어플리케이션을 구동해야했는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 vm virtaul machine은 , 각각의 운영체제를 포함하고 있기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mac위에서 윈도우, 리눅스 동시에 구동 할 수 있다.&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;반면 container는 하드웨어에 설치된 운영체제 Host OS에서&amp;nbsp; container engine 소프트웨어를 설치하면 개별적인 컨테이너를 만들어서 각각의 고립된 환경에서 구동되게 해준다.&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-filename=&quot;Screenshot from 2024-05-17 09-48-17.png&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;595&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEhrBp/btsHq8v6rbC/Wm2WszIj35TEmqBuRs5tP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEhrBp/btsHq8v6rbC/Wm2WszIj35TEmqBuRs5tP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEhrBp/btsHq8v6rbC/Wm2WszIj35TEmqBuRs5tP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEhrBp%2FbtsHq8v6rbC%2FWm2WszIj35TEmqBuRs5tP1%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;656&quot; height=&quot;376&quot; data-filename=&quot;Screenshot from 2024-05-17 09-48-17.png&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;595&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;virtual machine 운영체제를 포함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제를 포함 x, container engine을 포함한 운영체제를 공유한다.&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;container engine중에 도커를 가장 많이 사용한다&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;&lt;span style=&quot;color: #5733b1;&quot;&gt;1.만들고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #5733b1;&quot;&gt;2.배포하고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #5733b1;&quot;&gt;3.구동한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2024-05-17 12-44-03.png&quot; data-origin-width=&quot;1035&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zjIzG/btsHtdCAEba/FubTflRW2eegN7W6MpNOY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zjIzG/btsHtdCAEba/FubTflRW2eegN7W6MpNOY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zjIzG/btsHtdCAEba/FubTflRW2eegN7W6MpNOY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzjIzG%2FbtsHtdCAEba%2FFubTflRW2eegN7W6MpNOY1%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;474&quot; height=&quot;250&quot; data-filename=&quot;Screenshot from 2024-05-17 12-44-03.png&quot; data-origin-width=&quot;1035&quot; data-origin-height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;1. Building Container&lt;/i&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;Dockerfile을 만들고 Image를 만들어서 Container를 구동한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2024-05-17 12-46-13.png&quot; data-origin-width=&quot;1035&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nVv17/btsHr8a03y6/TUDlZ3sRqz12uyxpdk8kp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nVv17/btsHr8a03y6/TUDlZ3sRqz12uyxpdk8kp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nVv17/btsHr8a03y6/TUDlZ3sRqz12uyxpdk8kp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnVv17%2FbtsHr8a03y6%2FTUDlZ3sRqz12uyxpdk8kp0%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;475&quot; height=&quot;251&quot; data-filename=&quot;Screenshot from 2024-05-17 12-46-13.png&quot; data-origin-width=&quot;1035&quot; data-origin-height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dockerfile은 컨테이너를 어떻게 만들어야하는지 설명서. 레시피이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.어플리케이션 구동위해 필요한 파일은 무엇인지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.어떤것들을 설치해야하는지 dependencies&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;4. 어떻게 구동해야하는지 스크립트 포함&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-filename=&quot;Screenshot from 2024-05-17 12-47-37.png&quot; data-origin-width=&quot;1035&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dy8Tv6/btsHq1KG7Mu/7dHne9xV9dA04PQkW5xy31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dy8Tv6/btsHq1KG7Mu/7dHne9xV9dA04PQkW5xy31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dy8Tv6/btsHq1KG7Mu/7dHne9xV9dA04PQkW5xy31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdy8Tv6%2FbtsHq1KG7Mu%2F7dHne9xV9dA04PQkW5xy31%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;241&quot; data-filename=&quot;Screenshot from 2024-05-17 12-47-37.png&quot; data-origin-width=&quot;1035&quot; data-origin-height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 작성한 dockerfile을 통해서 이미지를 만든다. =&amp;gt; 필요한것들을 찰칵 snapshot해서 이미지파일로 만든다. = 변경불가 불변의 상태&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;container는 샌드박스처럼 어플리케이션의 이미지를 고립된 환경에서 실행할 수 있는것. 컨테이너안에서 우리의 파일이 동작한다고 볼 수 있다.&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;즉 conatiner는 이미지파일을 이용해서 구동하는것!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2024-05-17 12-49-14.png&quot; data-origin-width=&quot;1035&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wkc3r/btsHrST0z9N/0oZqElsX2qv9KKYO9gVvh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wkc3r/btsHrST0z9N/0oZqElsX2qv9KKYO9gVvh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wkc3r/btsHrST0z9N/0oZqElsX2qv9KKYO9gVvh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwkc3r%2FbtsHrST0z9N%2F0oZqElsX2qv9KKYO9gVvh1%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;439&quot; height=&quot;232&quot; data-filename=&quot;Screenshot from 2024-05-17 12-49-14.png&quot; data-origin-width=&quot;1035&quot; data-origin-height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지를 class라고 생각한다. 청사진.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지를 이용해서 컨테이너를 만드는것 =&amp;gt; 인스턴스&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;span style=&quot;color: #5733b1;&quot;&gt;1.만들고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #5733b1;&quot;&gt;2.배포하고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #5733b1;&quot;&gt;3.구동한다.&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;&lt;span style=&quot;color: #333333;&quot;&gt;2번째 방법인 배포&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;&lt;span style=&quot;color: #5733b1;&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2. shippinig container&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;/span&gt;&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-filename=&quot;Screenshot from 2024-05-17 12-54-03.png&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;565&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLxCgV/btsHtj3LXrj/vPb4DQQXh7UKnS6sDXo4Q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLxCgV/btsHtj3LXrj/vPb4DQQXh7UKnS6sDXo4Q1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLxCgV/btsHtj3LXrj/vPb4DQQXh7UKnS6sDXo4Q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLxCgV%2FbtsHtj3LXrj%2FvPb4DQQXh7UKnS6sDXo4Q1%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;511&quot; height=&quot;279&quot; data-filename=&quot;Screenshot from 2024-05-17 12-54-03.png&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;565&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;local machine에서 이미지를 만들어서,-&amp;gt; github와 같은 container registry에서 image를 push하고 내가 만든이미지를 pull해서 가져와서 사용하면된다.&lt;br /&gt;&lt;/span&gt;&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-filename=&quot;Screenshot from 2024-05-17 12-54-32.png&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;565&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYCCb6/btsHrTyFGVc/mM8C5m9OoCiKNNITv0u611/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYCCb6/btsHrTyFGVc/mM8C5m9OoCiKNNITv0u611/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYCCb6/btsHrTyFGVc/mM8C5m9OoCiKNNITv0u611/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYCCb6%2FbtsHrTyFGVc%2FmM8C5m9OoCiKNNITv0u611%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;503&quot; height=&quot;275&quot; data-filename=&quot;Screenshot from 2024-05-17 12-54-32.png&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;565&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;docker와 같은 컨테이너 엔진이 꼭 필요하다!&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;public서비스 = docker hub&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;private서비스 = aws, google cloud, microsoft azure&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;우리가 사용하고있는 local machine에 도커를 설치하고, 서버에도 도커를 설치하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. build&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. image push하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. pull&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2024-05-17 12-56-26.png&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;565&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjqqSn/btsHsnlGu3l/ecXwzKQQk1Lpbna9ly8gB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjqqSn/btsHsnlGu3l/ecXwzKQQk1Lpbna9ly8gB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjqqSn/btsHsnlGu3l/ecXwzKQQk1Lpbna9ly8gB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjqqSn%2FbtsHsnlGu3l%2FecXwzKQQk1Lpbna9ly8gB1%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;556&quot; height=&quot;304&quot; data-filename=&quot;Screenshot from 2024-05-17 12-56-26.png&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;565&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>이채야채</author>
      <guid isPermaLink="true">https://developeritchaeyachae.tistory.com/371</guid>
      <comments>https://developeritchaeyachae.tistory.com/371#entry371comment</comments>
      <pubDate>Fri, 17 May 2024 10:06:27 +0900</pubDate>
    </item>
    <item>
      <title>vue - 계산된 속성:  computed</title>
      <link>https://developeritchaeyachae.tistory.com/369</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;pre id=&quot;code_1715761247475&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default {
  data() {
    return {
      author: {
        name: 'John Doe',
        books: [
          'Vue 2 - Advanced Guide',
          'Vue 3 - Basic Guide',
          'Vue 4 - The Mystery'
        ]
      }
    }
  }
}



&amp;lt;p&amp;gt;책을 가지고 있다:&amp;lt;/p&amp;gt;
&amp;lt;span&amp;gt;{{ author.books.length &amp;gt; 0 ? 'Yes' : 'No' }}&amp;lt;/span&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;위와 같은것은 좋은 예제가 아니다.&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;span style=&quot;color: #ee2323;&quot;&gt;계산된 속성을 사용해야한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1715761357350&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default {
  data() {
    return {
      author: {
        name: 'John Doe',
        books: [
          'Vue 2 - Advanced Guide',
          'Vue 3 - Basic Guide',
          'Vue 4 - The Mystery'
        ]
      }
    }
  },
  computed: {
    // 계산된 값을 반환하는 속성
    publishedBooksMessage() {
      // `this`는 컴포넌트 인스턴스를 가리킵니다.
      return this.author.books.length &amp;gt; 0 ? 'Yes' : 'No'
    }
  }
}&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;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;publishedBooksMessage 같은경우에는, author.books에 의존이된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼으로 methods의 어떤함수를 통해서 books를 변화시키면, computed의 값도 자동 바인딩된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1715761824572&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
export default {
  data() {
    return {
      author: {
        name: 'John Doe',
        books: [
          'Vue 2 - Advanced Guide',
          'Vue 3 - Basic Guide',
          'Vue 4 - The Mystery'
        ]
      }
    }
  },
  computed: {
    // 계산된 값을 반환하는 속성
    publishedBooksMessage() {
      // `this`는 컴포넌트 인스턴스를 가리킵니다.
      return this.author.books.length &amp;gt; 0 ? 'Yes' : 'No'
    }
  },
  methods: {
    test(){
      this.author.books = [];
    }
  }
}
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;p&amp;gt;책을 가지고 있다:&amp;lt;/p&amp;gt;
  &amp;lt;span&amp;gt;{{ author.books.length &amp;gt; 0 ? 'Yes' : 'No' }}&amp;lt;/span&amp;gt;
  &amp;lt;button @click=&quot;test&quot;&amp;gt;여기서뭔가&amp;lt;/button&amp;gt;
&amp;lt;/template&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;이렇게바꿔보니&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;span의 값이 yes에서 no로 바뀜을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계산된 캐싱 vs 메소드&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;span style=&quot;color: #ee2323;&quot;&gt;계산된 속성은 의존된 반응형을 기반으로 캐시&lt;/span&gt;된다. =&amp;gt; &lt;u&gt;useMemo사용&lt;/u&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;반면 메소드는 리렌더링이 될때마다 새로운 함수 호출&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;getter로서 Retrun된값이 원칙이긴하나, 수정을 할수도있는데&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_1715763672129&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default {
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe'
    }
  },
  computed: {
    fullName: {
      // getter
      get() {
        return this.firstName + ' ' + this.lastName
      },
      // setter
      set(newValue) {
        // 참고: 분해 할당 문법을 사용함.
        [this.firstName, this.lastName] = newValue.split(' ')
      }
    }
  }
}&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;p data-ke-size=&quot;size16&quot;&gt;newValue가 sophie lee라고 했을경우?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;firsName 이 sophie, name이 Lee로 state가 업데이트된다.&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;gt; pure하게 움직이자. read only로&amp;nbsp;&lt;/p&gt;</description>
      <category>Vue</category>
      <author>이채야채</author>
      <guid isPermaLink="true">https://developeritchaeyachae.tistory.com/369</guid>
      <comments>https://developeritchaeyachae.tistory.com/369#entry369comment</comments>
      <pubDate>Wed, 15 May 2024 17:47:07 +0900</pubDate>
    </item>
    <item>
      <title>vue - 반응형 기초</title>
      <link>https://developeritchaeyachae.tistory.com/368</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1. 반응형 &lt;span style=&quot;background-color: #fff666;&quot;&gt;상태&lt;/span&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;script안의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data(){} 보관함을 통하여 상태를 선언및 저장한다. (state처럼 this를 통하여 변경가능)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1715739380199&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default {
  data() {
    return {
      count: 1
    }
  },

  // `mounted`는 나중에 설명할 생명 주기 훅입니다.
  mounted() {
    // `this`는 컴포넌트 인스턴스를 나타냅니다.
    console.log(this.count) // =&amp;gt; 1

    // 값을 변경할 수 있습니다.
    this.count = 2
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드를 통해서 함수를 사용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1715758766716&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  },
  mounted() {
    // 메서드는 생명 주기 훅 또는 다른 메서드에서 호출할 수 있습니다!
    this.increment()
  }
}&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;메서드안에서 data의 state를 바꾸고싶다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무조건 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;this&lt;/span&gt;&lt;/b&gt;를 통해서 바꿔야한다. :: 완전중요:: 화살표함수의 this 같은경우는 state에 접근할수없음.&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;리액트와 마찬가지로 , dom업데이트는 동기적으로 진행되지않는다. (리액트의 배칭이랑 비슷한 느낌.?)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태관리후에 dom 업데이트 까지 기다리려면 nextTrick() api를 사용해야한다고 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1715759609578&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default {
  created() {
    // 이제 각 인스턴스는 자체적인 디바운스된 핸들러를 가집니다.
    this.debouncedClick = _.debounce(this.click, 500)
  },
  unmounted() {
    // 컴포넌트가 제거된 후 
    // 타이머를 취소하는 것은 좋은 방법입니다.
    this.debouncedClick.cancel()
  },
  methods: {
    click() {
      // ... 클릭에 응답 ...
    }
  }
}&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;(useEffect나, 앵귤러 ngOninit등에서 리사이즈 등록해서 사용하는 이벤트와 비슷 )&lt;/p&gt;</description>
      <category>Vue</category>
      <author>이채야채</author>
      <guid isPermaLink="true">https://developeritchaeyachae.tistory.com/368</guid>
      <comments>https://developeritchaeyachae.tistory.com/368#entry368comment</comments>
      <pubDate>Wed, 15 May 2024 11:33:25 +0900</pubDate>
    </item>
    <item>
      <title>vue - 템플릿 문법</title>
      <link>https://developeritchaeyachae.tistory.com/367</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;싱글파일컴포넌트&lt;/b&gt; (SFC) - 파일형식이다. =&amp;gt; 컴포넌트 정의하고 만든다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #fff666;&quot;&gt;Single-File-Component&lt;/span&gt; = JAVASCRIPT, HTML, CSS 를 하나의 파일로 묶는다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;API스타일&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 옵션 API - 회사 예전 코드 옵션으로 되어있음&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;data, method 등을 사용하여 표현&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;(리액트 상의 class로 사용이 가능하고, OOP적 사용으로 this 등이 들어감)&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 컴포지션API - 고도화 및 마이그레이션 시&amp;nbsp; 필요한 코드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;function 등을 사용하여 표현&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;size18&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;1. 여러 속성바인딩&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, class 등을 넣고서,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;v-bind를 사용하여 넣어주면 끝!&lt;/p&gt;
&lt;pre id=&quot;code_1715736020876&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;data() {
  return {
    objectOfAttrs: {
      id: 'container',
      class: 'wrapper'
    }
  }
}

&amp;lt;div v-bind=&quot;objectOfAttrs&quot;&amp;gt;&amp;lt;/div&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{{ message }} 를 사용하여 쓸수있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data 보관함에, message값을 넣어주면 된다.&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;리액트와 마찬가지고, 삼항연산식만 가능하고 var a = 1 과 같은 표현식은 불가능하다&lt;/p&gt;
&lt;pre id=&quot;code_1715736179381&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- 이것은 표현식이 아니라 선언식입니다: --&amp;gt;
{{ var a = 1 }}

&amp;lt;!-- 흐름 제어도 작동하지 않습니다. 삼항 표현식을 사용하십시오. --&amp;gt;
{{ if (ok) { return message } }}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&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;디렉티브란? v- 접두사를 가진것들을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예) v-html, v-bind, v-if&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;표현식 값이 변할때, Dom에 반응적으로 업데이트를 적용하는 것&lt;/p&gt;
&lt;pre id=&quot;code_1715736542895&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;p v-if=&quot;seen&quot;&amp;gt;이제 이것을 볼 수 있습니다.&amp;lt;/p&amp;gt;


seen은 true혹은 false의 boolean 타입&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;축약사용&lt;/p&gt;
&lt;pre id=&quot;code_1715736583942&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;a v-bind:href=&quot;url&quot;&amp;gt; ... &amp;lt;/a&amp;gt;

&amp;lt;!-- 단축 문법 --&amp;gt;
&amp;lt;a :href=&quot;url&quot;&amp;gt; ... &amp;lt;/a&amp;gt;



&amp;lt;a v-on:click=&quot;doSomething&quot;&amp;gt; ... &amp;lt;/a&amp;gt;

&amp;lt;!-- 단축 문법 --&amp;gt;
&amp;lt;a @click=&quot;doSomething&quot;&amp;gt; ... &amp;lt;/a&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Vue</category>
      <author>이채야채</author>
      <guid isPermaLink="true">https://developeritchaeyachae.tistory.com/367</guid>
      <comments>https://developeritchaeyachae.tistory.com/367#entry367comment</comments>
      <pubDate>Wed, 15 May 2024 10:23:07 +0900</pubDate>
    </item>
  </channel>
</rss>