{
    "componentChunkName": "component---src-templates-blog-post-js",
    "path": "/20-04-22-cra-dockerize/",
    "result": {"data":{"site":{"siteMetadata":{"title":"irrationnelle","author":"irrationnelle","siteUrl":"https://dev.rase.blog","comment":{"disqusShortName":"","utterances":"irrationnelle/devlog"},"sponsor":{"buyMeACoffeeId":""}}},"markdownRemark":{"id":"c3a22a65-aa0c-5526-883b-e7a14cfe1acd","excerpt":"Hello Docker 토이 프로젝트에 CI/CD 를 붙이다가 Docker 를 오랜만에 다시 만지게 되었다. 평소 TIL 리포에만 글을 남기다가 오랜만에 블로그를 작성하는데 형식이나 친절도는 TIL 와 거의 비슷할 것 같다. CRA 로 간단한 react 앱 만들기 Dockerize 프로젝트를 Docker 컨테이너에 담는 작업을 dockerize…","html":"<h1 id=\"hello-docker\" style=\"position:relative;\"><a href=\"#hello-docker\" aria-label=\"hello docker permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Hello Docker</h1>\n<p>토이 프로젝트에 CI/CD 를 붙이다가 Docker 를 오랜만에 다시 만지게 되었다.</p>\n<p>평소 <a href=\"https://github.com/irrationnelle/TIL\">TIL</a> 리포에만 글을 남기다가 오랜만에 블로그를 작성하는데 형식이나 친절도는 TIL 와 거의 비슷할 것 같다.</p>\n<h1 id=\"cra-로-간단한-react-앱-만들기\" style=\"position:relative;\"><a href=\"#cra-%EB%A1%9C-%EA%B0%84%EB%8B%A8%ED%95%9C-react-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0\" aria-label=\"cra 로 간단한 react 앱 만들기 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>CRA 로 간단한 react 앱 만들기</h1>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">$ npx create-react-app example\n$ <span class=\"token builtin class-name\">cd</span> example <span class=\"token comment\"># 생성한 프로젝트의 디렉토리의 root 폴더에서 이어지는 작업을 한다.</span></code></pre></div>\n<h1 id=\"dockerize\" style=\"position:relative;\"><a href=\"#dockerize\" aria-label=\"dockerize permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Dockerize</h1>\n<p>프로젝트를 Docker 컨테이너에 담는 작업을 dockerize 라고들 하는 것 같다.</p>\n<p>먼저 프로젝트의 루트 디렉토리에서 <code class=\"language-text\">Dockerfile</code> 을 생성한다.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">$ <span class=\"token function\">vim</span> Dockerfile</code></pre></div>\n<p>내용은 다음과 같이 채워넣었다.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">FROM mhart/alpine-node:latest\nWORKDIR /app\n\nCOPY package*.json ./\nRUN npm install\nCOPY . ./\nEXPOSE 3000\n\nCMD [\"npm\", \"start\"]  </code></pre></div>\n<p>여기서 혼동했던 것 중 하나는 <code class=\"language-text\">WORKDIR</code> 부분인데, 이건 생성하려는 docker 컨테이너 내부의 위치를 이야기 한다.</p>\n<p>즉 위와 같은 설정값으로 docker image 를 빌드하면 나중에 docker 컨테이너 내부에서 <code class=\"language-text\">~/app</code> 내부에 우리가 작업한 프로젝트들이 담겨있는 것을 확인할 수 있다.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">vim</span> .dockerignore</code></pre></div>\n<p>컨테이너에 담지 않을 내용도 추가해준다.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">node_modules</code></pre></div>\n<p>참고사항으로 <code class=\"language-text\">mhart/alpine-node:latest</code> 는 다운로드 수는 많은 docker 이미지이지만 docker hub 로부터 인증받은 repo는 아니다. 나는 오늘(20. 04. 22) 기준으로 나온 <code class=\"language-text\">node 14.0.0</code> 을 사용하기 위해 이 이미지 기반으로 컨테이너를 만들었다.</p>\n<p>그럼 이제 docker 컨테이너 이미지를 빌드한다.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">$ <span class=\"token function\">docker</span> build -t alpine_node:dev <span class=\"token builtin class-name\">.</span> <span class=\"token comment\"># 여기서 :dev 는 태그값이다</span></code></pre></div>\n<h1 id=\"docker-컨테이너-실행\" style=\"position:relative;\"><a href=\"#docker-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EC%8B%A4%ED%96%89\" aria-label=\"docker 컨테이너 실행 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>docker 컨테이너 실행</h1>\n<p><code class=\"language-text\">$ docker run -it -v ${PWD}:/app -p 3002:3000 --rm -d --name alpine_node_test alpine_node</code></p>\n<ul>\n<li>\n<p><code class=\"language-text\">-it</code> : 컨테이너의 입출력을 interactive 하게 하는 옵션과 TTY 터미널을 애뮬레이션 해주는 옵션(<a href=\"https://www.popit.kr/%EA%B0%9C%EB%B0%9C%EC%9E%90%EA%B0%80-%EC%B2%98%EC%9D%8C-docker-%EC%A0%91%ED%95%A0%EB%95%8C-%EC%98%A4%EB%8A%94-%EB%A9%98%EB%B6%95-%EB%AA%87%EA%B0%80%EC%A7%80/\">출처: 개발자가 처음 Docker 접할때 오는 멘붕 몇가지</a>). 이 옵션이 없으면 CRA 앱이 실행이 안 되는데 출처의 해당 블로그에서 그 이유를 알 수 있었다.</p>\n</li>\n<li>\n<p><code class=\"language-text\">-v ${PWD}:/app</code> : 현재 프로젝트를 docker 컨테이너의 <code class=\"language-text\">/app</code> 디렉토리에서 마운트하는 옵션인데, 이 옵션이 있으면 docker 컨테이너 외부의 실제 코드 작성과 수정들이 docker 컨테이너 내부와 연동한다. 기껏 docker 로 환경 구성을 했는데 실제 개발은 컨테이너 외부에서 진행하면 의미가 없다는 측면에서 코드 개발은 docker 컨테이너 내부에서 이루어져야 한다고 생각했는데, 이 방법으로 그것을 가능케 하는 것 같다.</p>\n</li>\n<li>\n<p><code class=\"language-text\">-p 3002:3000</code> : docker 컨테이너 내부에서는 <code class=\"language-text\">3000</code> 포트에 응하는 것을 docker 컨테이너 외부에서는 <code class=\"language-text\">3002</code> 포트에 응하도록 한다. 카카오맵 API 사용시 <code class=\"language-text\">http://localhost:3002</code> 를 플랫폼에 추가해줘야 sdk 를 정상적으로 호출할 수 있다.</p>\n</li>\n<li>\n<p><code class=\"language-text\">--rm</code> : docker 컨테이너 종료시 자동으로 컨테이너 삭제</p>\n</li>\n<li>\n<p><code class=\"language-text\">-d</code> : docker 컨테이너의 백그라운드에서 프로젝트 실행</p>\n</li>\n</ul>\n<p>대략적인 옵션 설명은 여기까지 하면 될 것 같다.</p>\n<p>이렇게 한 뒤 브라우저를 작동시켜서 <code class=\"language-text\">http://localhost:3002</code> 로 접속하면 CRA 앱 실행을 확인할 수 있다.</p>\n<p>docker 컨테이너를 종료하고 싶을 땐</p>\n<p><code class=\"language-text\">docker ps</code> 로 컨테이너 id 를 확인하고</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">$ <span class=\"token function\">docker</span> stop <span class=\"token punctuation\">[</span>container_id<span class=\"token punctuation\">]</span> <span class=\"token comment\"># [] 는 안 넣어줘도 된다.</span></code></pre></div>\n<p>로 종료한다.</p>\n<h1 id=\"이외의-참고할-것들\" style=\"position:relative;\"><a href=\"#%EC%9D%B4%EC%99%B8%EC%9D%98-%EC%B0%B8%EA%B3%A0%ED%95%A0-%EA%B2%83%EB%93%A4\" aria-label=\"이외의 참고할 것들 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>이외의 참고할 것들</h1>\n<p>생성한 docker 컨테이너 내부에 접속하고 싶을 때는 다음 명령어를 사용한다.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">$ <span class=\"token function\">docker</span> run -it -p <span class=\"token number\">3002</span>:3000 --rm -d --name alpine_node_test alpine_node /bin/sh\n$ <span class=\"token function\">docker</span> <span class=\"token builtin class-name\">exec</span> -it alpine_node_test /bin/sh <span class=\"token comment\"># alpine linux 에는 bash 가 기본설치 되어있지 않아서 /bin/sh 를 이용한다</span></code></pre></div>\n<p>위 명령어를 실행하면 docker 내부 컨테이너의 쉘 실행을 확인할 수 있다.</p>","frontmatter":{"title":"CRA 앱 Dockerize 하기","date":"April 22, 2020"}}},"pageContext":{"slug":"/20-04-22-cra-dockerize/","previous":{"fields":{"slug":"/19-12-18-list-value-control/"},"frontmatter":{"title":"list comprehension 과 map","category":"Python","draft":false}},"next":{"fields":{"slug":"/20-07-16-test-and-spec/"},"frontmatter":{"title":"TDD 와BDD, 그리고 명세(spec)에 대하여","category":"Devops","draft":false}}}},
    "staticQueryHashes": ["3128451518","3474900066"]}