Container toplogy
๐ ์ฌ์ ์ค๋น
๋จผ์ express ์ฑ์ ๊ฒฝ์ฐ redis ์ฐ๋์ด ํ์ํ๋ express ์ฑ์ ์ปจํ ์ด๋๋ก ๊ธฐ๋ํ๊ธฐ ์ ์ redis ์ปจํ ์ด๋๊ฐ ๋จผ์ ์์ฑ๋์ด ์์ด์ผ ํ๋ค.
์ปจํ ์ด๋ ๊ฐ์ ๊ฒฉ๋ฆฌ๋ ๋คํธ์ํฌ์์ ๋์ํ๋ ๋ ๋์ค ์ปจํ ์ด๋์ express ์ปจํ ์ด๋๋ฅผ ๊ฐ์ ๋คํธ์ํฌ์ ๋ฌถ์ด์ค์ผ ํ๋ค.
"express-net" ์ด๋ผ๋ ๋์ปค ๋คํธ์ํฌ๋ฅผ ๋ง๋ค์ด์ฃผ์.
$ docker network create express-net์ด์ ์ปจํ
์ด๋ ์์ฑ ์ --network ์ต์
์ ์ค์ ๋ ์ปจํ
์ด๋๋ฅผ ๊ฐ์ ๋คํธ์ํฌ์ ๋ฌถ์ด์ฃผ๊ธฐ๋ง ํ๋ฉด ๋์ด๋ค.
express ์ปจํ ์ด๋์ ๊ฒฝ์ฐ ์๋ ๋จ๊ณ๋ค์ ๋ฐ๋ผํ๋ฉฐ ์ฒ์ฒํ ์งํํด๋ณด๋๋ก ํ๊ณ , ๋จผ์ redis ์ปจํ ์ด๋๋ฅผ ๋ฏธ๋ฆฌ ์์ฑํด์ฃผ๋๋ก ํ๊ฒ ๋ค.
$ docker run -d -it --name redis --network=express-net redis:latest์ ์์ ์ผ๋ก ๋ ๋์ค ์ปจํ ์ด๋๊ฐ ์์ฑ๋์๋ค๋ฉด ์ด์ ์๋ ๋ฐฐํฌ ๋จ๊ณ๋ค์ ๋ฐ๋ผํด๋ณด๋๋ก ํ์.
๐ฟ ๋ฐฐํฌ
ํ๋ก์ ํธ ํด๋ ๊ตฌ์กฐ๋ ์๋์ ๊ฐ๋ค.
$ tree -L 2 .
.
โโโ Dockerfile
โโโ app
โ โโโ app.ts
โ โโโ index.test.ts
โ โโโ index.ts
โโโ dockerignore
โโโ github_team_workflows
โ โโโ deploy.yaml
โ โโโ test.yaml
โโโ jest.config.js
โโโ package-lock.json
โโโ package.json
โโโ scripts
โ โโโ kill-app.sh
โ โโโ start-app.sh
โโโ tsconfig.jsonDockerfile ๋ด์ฉ์ ๊ธฐ๋ฐ์ผ๋ก ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ ๊ฒ๋ถํฐ ์บ์ ํ์ฉ, ๋ฉํฐ ์คํ ์ด์ง ๋น๋ ๋ฑ์ ์ ์ฉํ๋ฉด์ Dockerfile์ ๋จ๊ณ ๋ณ๋ก ๊ฐ์ ํด ๋๊ฐ ๊ฒ์ด๋ค.
์๋ ๋ด์ฉ๋ค์ ์ฒ์ฒํ ๋ฐ๋ผํด๋๋ก ํ์.
โข App ์ด๋ฏธ์ง ์์ฑ
์ด์ ์ ๋ง๋ [Deploy] ๊ฐ์์๋ฒ(Virtual Machine)์ node API ๋ฐฐํฌํ๊ธฐ - AWS Lightsail express ์ฑ์ ๋์ปค ์ด๋ฏธ์ง๋ก ๋ง๋ค์ด ๋ณผ ๊ฒ์ด๋ค.
base ์ด๋ฏธ์ง์ ๊ฒฝ์ฐ node.js ์์ ๊ณต์์ ์ผ๋ก ๊ด๋ฆฌํ๋ ๋
ธ๋๊ธฐ๋ฐ ๋์ปค ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ ๊ฑฐ๋ค.
(node:latest - Dockerhub)
ํ์ฌ ํ๋ก์ ํธ ๊ฒฝ๋ก์ Dockerfile์ ์์ฑํ ํ ์๋ ์ฝ๋๋ฅผ ๋ถ์ฌ๋ฃ๊ธฐ ํ๋๋ก ํ์.
FROM node:18
COPY ./ ./
RUN npm install -D
RUN npm run build
CMD [ "npm", "run", "start"]์ด์ ์ Dockerfile์ ๊ธฐ๋ฐ์ผ๋ก ๋์ปค ์ด๋ฏธ์ง๋ฅผ ์์ฑํด๋ณด์.
$ docker build --tag yshrim12/express -f Dockerfile .์์ฑ๋ ์ด๋ฏธ์ง๋ฅผ ํ์ธํด๋ณด์.
$ docker images yshrim12/express
REPOSITORY TAG IMAGE ID CREATED SIZE
yshrim12/express latest 52c6374c7939 About a minute ago 1.18GB์ข
์์ฑ ์ค์น ๋ฐ ๋น๋ ๊ณผ์ ์ด ํฌํจ๋์ด ์์ด ์ฉ๋(1.18GB)์ด ์๋นํ ํฌ๊ฒ ๋์จ๋ค.
์๋ ๋จ๊ณ๋ฅผ ์ง๋๋ค๋ณด๋ฉด ์ฉ๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ๋ ๋์ค๋ ๊ณ์ ๋ฐ๋ผํด๋ณด์.
express ์ปจํ ์ด๋๋ฅผ ์์ฑํด๋ณด์!
$ docker run -d -it --name express -p 4000:4000 --network=express-net yshrim12/expressexpress ์ปจํ ์ด๋ ์ํ์ ๋ก๊ทธ๋ฅผ ์กฐํํด๋ณด์.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a9573eaad2d4 yshrim12/express "docker-entrypoint.sโฆ" 41 seconds ago Up 40 seconds 0.0.0.0:4000->4000/tcp, :::4000->4000/tcp express
$ docker logs express
> express@1.0.0 start
> node build/index.js
trying to start server
App listening at port 4000์ ์์ ์ผ๋ก ์คํ๋จ์ ๋ณผ ์ ์๋ค.
โข .env ๋ถ๋ฆฌ
์์์ ์์ฑํ Dockerfile์๋ ์น๋ช ์ ์ธ ๋จ์ ์ด ํ๋ ์๋ค.
๋ฐ๋ก Dockerfile์ COPY ./ ./ ์ด ๋ถ๋ถ์ธ๋ฐ, .env ํ๊ฒฝ ๋ณ์๋ฅผ ํฌํจํ ํ์ฌ ํ๋ก์ ํธ ๊ฒฝ๋ก์ ์๋ ๋ชจ๋ ํ์ผ์ด express ์ปจํ
์ด๋๋ก ์ฎ๊ฒจ์ง๋ค๋ ์ ์ด๋ค.
๋ง์ฝ .env ํ์ผ์ด ํฌํจ๋ ์ด๋ฏธ์ง๋ฅผ Docker hub๋ ๋ค๋ฅธ regisry ์ ์ฅ์์ ํผ๋ธ๋ฆญ์ผ๋ก ๋ฐฐํฌ๋ฅผ ํ๊ฒ๋๋ฉด ๋ณด์์ ๋ฏผ๊ฐํ ํ๊ฒฝ ๋ณ์ ๋ด์ฉ๋ค์ด ๋ชจ๋ ๋
ธ์ถ๋๋ ๊ฒ์ด๋ค.
์ด๋ฌํ ์ ์ ์๋ฐฉํ ์ ์๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ด ์๋ค. ๋ฐ๋ก .dockerignore ํ์ผ์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค. git์๋ `.gitignore`๊ฐ ์๋ ๊ฒ ์ฒ๋ผ ๋์ปค์๋ `.dockerignore`๊ฐ ์กด์ฌํ๋ค.
ํ์ฌ .gitignore์๋ ์๋์ ๊ฐ์ ๋๋ ํ ๋ฆฌ ๋ฐ ํ์ผ๋ค์ด ํฌํจ๋์ด์๋ค.
$ cat .gitignore
.env
node_modules/
build/
.DS_STORE/
app_log/.dockerignore์๋ ์ปจํ ์ด๋์ ํฌํจ๋์ง ์์ ํ์ผ ๋ฐ ๋๋ ํ ๋ฆฌ๋ฅผ ์ถ๊ฐํด์ฃผ๋ฉด ๋๋ค.
$ cat .dockerignore
.git/
.gitignore
Dockerfile
.env.sample
.env
.github/
github_team_workflows/์ด์ .dockerignore๋ฅผ ์ถ๊ฐํ์ผ๋ ์ด๋ฏธ์ง๋ฅผ ๋ค์ ๋น๋ํ ํ ์ปจํ ์ด๋๋ฅผ ์คํํด๋ณด์!
$ docker build --tag yshrim12/express .$ docker run -d -it --name express -p 4000:4000 --network=express-net yshrim12/express๊ทธ๋ฐ๋ฐ express ์ปจํ ์ด๋๊ฐ ์ ๋๋ก ์คํ๋์ง๊ฐ ์๋๋ค!
$ docker logs express
> express@1.0.0 start
> node build/index.js
/build/index.js:44
throw new Error("PORT is required");
^
Error: PORT is required
at Object.<anonymous> (/build/index.js:44:11)
at Module._compile (node:internal/modules/cjs/loader:1356:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1414:10)
at Module.load (node:internal/modules/cjs/loader:1197:32)
at Module._load (node:internal/modules/cjs/loader:1013:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:128:12)
at node:internal/main/run_main_module:28:49
Node.js v18.19.0PORT ํ๊ฒฝ ๋ณ์๊ฐ ๋น ๊ฐ์ผ๋ก ๋์ด๊ฐ ๊ฒ ๊ฐ๋ค. ์ด์ ๊ฐ ๋ญ๊น?
๐บ ํธ๋ฌ๋ธ ์ํ
์ด์ฐ๋ณด๋ฉด ๋น์ฐํ ์ ๊ธฐ์ด๋ค. .dockerignore์ ๋ฑ๋ก๋ ํ์ผ ๋ฐ ํด๋๋ ์ปจํ ์ด๋ ๋น๋ ๊ณผ์ ์ ํฌํจ๋์ง ์๋๋ค.
๊ทธ ๋ง์ธ ์ฆ์จ, .env ํ์ผ ๋ํ ์ปจํ ์ด๋์ ์ฌ๋ผ๊ฐ์ง ์๋๋ค๋ ๊ฒ! ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ฝ๋์์ ํ๊ฒฝ ๋ณ์๋ฅผ ์ฝ์ด๋ค์ผ ์ ์๊ฒ ๋ ๊ฒ์ด๋ค.
๋์ปค์๋ --env-file ์ด๋ผ๋ ์ต์
์ด ์กด์ฌํ๋ค. ํ๊ฒฝ ๋ณ์ ํ์ผ์ --env-file๋ก ์ปจํ
์ด๋์ ๋ฑ๋กํ ์ ์๊ฒ๋๋ ๊ฑฐ๋ค.
--env-file๋ก ํ๊ฒฝ ๋ณ์ ํ์ผ์ ๋ฑ๋กํ ๊ฒฝ์ฐ ์ปจํ
์ด๋์๋ ํด๋น ํ์ผ์ ๋ด์ฉ์ ๊ฐ์ง๊ณ ์ปจํ
์ด๋์ ํ๊ฒฝ ๋ณ์๊ฐ ๋ฑ๋ก๋๊ฒ ๋๋ค.
๋จผ์ , ๊ธฐ์กด ์ค๋ฅ๊ฐ ๋ ์ปจํ ์ด๋๋ฅผ ์์ ๋ฒ๋ฆฌ์.
$ docker rm express๊ทธ๋ฐ ๋ค์์ ๋ค์ --env-file ์ต์
์ ์ ์ฉํ์ฌ ๋ค์ ์ปจํ
์ด๋๋ฅผ ์คํํด๋ณด์.
$ docker run -d -it --name express --env-file=.env --network=express-net -p 4000:4000 yshrim12/expressexpress ์ปจํ ์ด๋ ๋ก๊ทธ๋ฅผ ๋ค์ ํ์ธํด๋ณด์.
$ docker logs express
> express@1.0.0 start
> node build/index.js
trying to start server
App listening at port 4000์ด์ ๋ ์ ์์ ์ผ๋ก ์คํ๋๋ค!
โข ๋์ปค ์บ์ ํ์ฉ
๋น๋ ๊ณผ์ ์ ์ํฉ์ ๋ฐ๋ผ์ ๋งค์ฐ ์ค๋ ๊ฑธ๋ฆด ์ ์๊ฒ ๋๋ค.
๋์ปค๋ ์ด๋ฏธ์ง ๋น๋ ํ๋ก์ธ์ค์์ ์บ์ฑ์ ์ฌ์ฉํ์ฌ ํจ์จ์ฑ์ ๋์ด๊ณ ๋น๋ ์๊ฐ์ ๋จ์ถํ ์ ์๋ค. ์บ์ฑ์ ์ด์ ๋น๋์์ ์์ฑ๋ ์ฐ์ถ๋ฌผ์ ์ฌ์ฌ์ฉํจ์ผ๋ก์จ ์ค๋ณต ์์ ์ ํผํ๊ณ , ๋ณ๊ฒฝ ์ฌํญ์ด ์๋ ๋ถ๋ถ์ ๋ค์ ๊ณ์ฐํ์ง ์๋๋ก ๋์์ค๋ค.
์ด๋ ๋ค์๊ณผ ๊ฐ์ ์ด์ ์ ์ ๊ณตํ๋ค.
- ๋น ๋ฅธ ๋น๋ ์๋: ์ด๋ฏธ์ง ๋น๋ ์ค์ ๋ณ๊ฒฝ๋์ง ์์ ๋ถ๋ถ์ ์ด์ ์ ์บ์๋ ๋ ์ด์ด๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น ๋ถ๋ถ์ ๋ค์ ๋น๋ํ์ง ์์๋ ๋ฉ๋๋ค. ์ด๊ฒ์ ์ ๋ฐ์ ์ผ๋ก ๋น๋ ์๊ฐ์ ํฌ๊ฒ ๋จ์ถ์์ผ์ค๋๋ค.
- ํจ์จ์ ์ธ ๋ฆฌ์์ค ์ฌ์ฉ: ์ด๋ฏธ์ง ๋น๋ ๊ณผ์ ์์ ๋ณ๊ฒฝ๋์ง ์์ ๋ถ๋ถ์ ์ฌ์ฌ์ฉ๋๋ฏ๋ก, ๋ถํ์ํ ์์ ์๋น๋ฅผ ์ค์ฌ์ค๋๋ค.
- ์ผ๊ด์ฑ ์๋ ํ๊ฒฝ: ์บ์ฑ์ ํตํด ๋์ผํ Dockerfile์ ์ฌ์ฉํ์ฌ ์ผ๊ด๋ ํ๊ฒฝ์์ ์ด๋ฏธ์ง๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ๋ณ๊ฒฝ๋ ๋ถ๋ถ๋ง ์๋ก ๋น๋๋๊ณ , ๋๋จธ์ง๋ ์ด์ ์ ๋ ์ด์ด๋ฅผ ์ฌ์ฉํจ์ผ๋ก์จ ์ผ๊ด์ฑ์ ์ ์งํฉ๋๋ค.
- ๋ ์์ ์ด๋ฏธ์ง ํฌ๊ธฐ: ์ด์ ๋ ์ด์ด๊ฐ ์ฌ์ฌ์ฉ๋๋ฉด์ ์ค๋ณต์ด ์ค์ด๋ค๊ณ , ๊ฒฐ๊ณผ์ ์ผ๋ก ์ด๋ฏธ์ง ํฌ๊ธฐ๊ฐ ์ค์ด๋ญ๋๋ค.
์ผ๋ฐ์ ์ผ๋ก Dockerfile์์ ๊ฐ ๋ช
๋ น์ ๊ฐ๊ฐ์ ๋ ์ด์ด๋ก ์์ฑ๋๋ค. ์ด ๋๋ฌธ์ Docker๋ ๊ฐ ๋จ๊ณ๋ฅผ ์บ์ํ๊ณ , ์ด์ ์ ๋น๋๋ ์บ์๋ฅผ ํ์ฉํ์ฌ ๋ณ๊ฒฝ๋ ๋ถ๋ถ๋ง ๋ค์ ๋น๋ํ๊ฒ ๋๋ ๊ฒ์ด๋ค. ํ์ง๋ง ์บ์๋ ์ ์ ํ๊ฒ ์ฌ์ฉํด์ผ ํ๋ฉฐ, ๋๋ก๋ ์บ์๋ฅผ ๋ฌด์ํ๊ณ ๋ค์ ๋น๋ํด์ผ ํ๋ ๊ฒฝ์ฐ๋ ์๋ค.
(์: ์ข
์์ฑ์ด๋ ์์ค ์ฝ๋ ๋ณ๊ฒฝ ๋ฑ)
์ข์ Dockerfile์ ์์ฑํ์ฌ ์บ์๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ๋ฉด ๋ ๋น ๋ฅด๊ณ ํจ์จ์ ์ธ ์ด๋ฏธ์ง ๋น๋๋ฅผ ํ ์ ์๋ค. ์ฐ๋ฆฌ๋ ์บ์ฑ์ ์ฌ์ฉํ์ฌ ๊ธฐ์กด Dockerfile์ ๊ฐ์ ์์ผ๋ณด์.
FROM node:18-alpine
COPY ./package*.json ./
RUN npm install -D
COPY ./ ./
RUN npm run build
CMD [ "npm", "run", "start" ]์ ๋ด์ฉ์ ๊ธฐ๋ฐ์ผ๋ก ์ด๋ฏธ์ง๋ฅผ ๋ค์ ๋น๋ํด๋ณด์.
$ docker build --tag yshrim12/express -f Dockerfile .
[+] Building 37.8s (10/10) FINISHED docker:default
=> [internal] load .dockerignore 0.0s
=> => transferring context: 117B 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 162B 0.0s
=> [internal] load metadata for docker.io/library/node:18-alpine 1.5s
=> CACHED [1/5] FROM docker.io/library/node:18-alpine@sha256:4bdb3f3105718f0742bc8d64bb4e36e8f955 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 481B 0.0s
=> [2/5] COPY ./package*.json ./ 0.0s
=> [3/5] RUN npm install -D 30.6s
=> [4/5] COPY ./ ./ 0.0s
=> [5/5] RUN npm run build 4.4s
=> exporting to image 1.3s
=> => exporting layers 1.3s
=> => writing image sha256:9ec2f8e209a06aa85fba42bb92d502037384c40158c116b1dd51985a488c71bb 0.0s
=> => naming to docker.io/yshrim12/express์ต์ด ๋น๋์ 37.8s๊ฐ ๊ฑธ๋ฆฐ ๊ฒ์ ํ์ธํ ์ ์๋ค.
app/app.ts์ ์์ค ์ฝ๋์์ ์ผ๋ถ๋ถ์ ๋ณ๊ฒฝํด๋ณด์.
...
app.get("/", (request, response) => {
response.status(200).send("hello from express, new image");๋ค์ ์ด๋ฏธ์ง๋ฅผ ๋น๋ํด๋ณด์!
$ docker build --tag yshrim12/express -f Dockerfile .
[+] Building 5.2s (10/10) FINISHED docker:default
=> [internal] load .dockerignore 0.0s
=> => transferring context: 117B 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 162B 0.0s
=> [internal] load metadata for docker.io/library/node:18-alpine 0.7s
=> [1/5] FROM docker.io/library/node:18-alpine@sha256:4bdb3f3105718f0742bc8d64bb4e36e8f955ebbee29 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 1.17kB 0.0s
=> CACHED [2/5] COPY ./package*.json ./ 0.0s
=> CACHED [3/5] RUN npm install -D 0.0s
=> [4/5] COPY ./ ./ 0.0s
=> [5/5] RUN npm run build 4.4s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:f17d4f25c30b976c803ba5942e9b0731d3876764a899510b0a1fd7ee1b44fdbd 0.0s
=> => naming to docker.io/yshrim12/express์บ์ฑ ๋๋ถ์ 5.2์ด ๋ฐ์ ๊ฑธ๋ฆฌ์ง ์์ ๊ฒ์ ํ์ธํ ์๊ฐ ์๋ค!
โข Multi stage build
Dockerfile์ ๊ฒฝ์ฐ build์ production ์คํ ์ด์ง๋ฅผ ๊ฐ๊ฐ ๋ถ๋ฆฌํ์ฌ ๋์ปค ์ด๋ฏธ์ง๋ฅผ ๊ฒฝ๋ํ ์ํฌ ์ ์๋ค.
์ด์ ์ด๋ฏธ์ง์ ๊ฒฝ์ฐ ์์กด์ฑ์ผ๋ก ์ถ๊ฐ๋ ํจํค์ง๋ค์ ์ค์นํ๊ณ , ๋น๋๊ณผ์ ๊น์ง ํฌํจ๋๋ค ๋ณด๋ ์๋นํ ํฐ ์ฉ๋์ผ๋ก ํ์ํ๊ฒ ๋๋ค.
๊ธฐ์กด์ ์ฌ์ฉํ๋ ์ด๋ฏธ์ง์ฒ๋ผ ๋น๋์ ์คํ ๊ณผ์ ์ ๋ชจ๋ ๋ด์๋ ์๊ด์ ์์ง๋ง ๋น๋์ ์คํ์ ๋๋๋ Builder pattern๋ ์กด์ฌํ๋ค.
Builder image์์๋ ์ฑ ๋น๋์ ํ์ํ ์์กด์ฑ ์ค์น์, ๋น๋ ํ ๋ฐ์ด๋๋ฆฌ๋ฅผ ์์ฑํ๊ณ
์ค์ ๋ก ๋์ํ๋ Running image์์๋ Builder image๋ก๋ถํฐ ๋ฐ์ด๋๋ฆฌ๋ง ๋ฐ์์ ์คํํ๋ ๋ฐฉ์์ด๋ค. ์ด๋ฌํ ๊ณผ์ ์ ๊ฑฐ์น๋ฉด ๊ฒฐ๊ตญ Build์๋ง ํ์ํ ๋ถํ์ํ ๋๊ตฌ, ๋ผ์ด๋ธ๋ฌ๋ฆฌ, ์ด๋ฏธ์ง ๋ด ํ์ผ๋ค์ ์ ์ธํ๊ณ ์์ฃผ ์ปดํฉํธํ ์ด๋ฏธ์ง์์ ๋ฐ์ด๋๋ฆฌ๋ง ๊ฐ์ง๊ณ ์ฑ์ ์คํ์ํฌ ์ ์๊ฒ๋๋ค.
์ฌ์ฉ๋ฒ์ ์์ฃผ ๋จ์ํ๋ค. ํ ํ์ผ์์ Base ์ด๋ฏธ์ง๋ฅผ ๋ฐ๊ฟ ์ฌ์ฉํ๋ฉด ๋ง์น 2๊ฐ ์ด์์ Dockerfile์ด ์๋ ๊ฒ๊ณผ ๋์ผํ๊ฒ ๋น๋ ์ํ์ด ๊ฐ๋ฅํ๋ค. Builder์์ ๋น๋ํ ๋ฐ์ด๋๋ฆฌ๋ฅผ ์คํํ ์ด๋ฏธ์ง๋ก ์ ๋ฌํด์ฃผ๊ธฐ ์ํด์ COPY์ --from ์ต์
์ ํตํด ์คํ ์ด๋ฏธ์ง๋ก ์ ๋ฌํด์ค ์ ์๋ค.
๊ธฐ์กด Dockerfile์ ์๋์ ๊ฐ์ด ์์ ํ์. ๋ฒ ์ด์ค ์ด๋ฏธ์ง๋ ๊ธฐ์กด node:18 ์ด๋ฏธ์ง๊ฐ ์๋ ๊ฒฝ๋ นํ ์ด๋ฏธ์ง์ธ node:18-alpine ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๋ค.
# Build Stage
FROM node:18-alpine AS builder
COPY ./package*.json ./
RUN npm install -D
COPY ./ ./
RUN npm run build
# Production Stage
FROM node:18-alpine AS prod
COPY ./build ./build
COPY ./package*.json ./
RUN npm install --only=production
CMD [ "npm", "run", "start" ]์ Dockerfile์ ๊ธฐ๋ฐ์ผ๋ก ์ ์ด๋ฏธ์ง๋ฅผ ๋น๋ํด๋ณด์.
$ docker build --tag yshrim12/express-light -f Dockerfile .์ ์ด๋ฏธ์ง(yshrim12/express-light)๋ฅผ ํ์ธํด๋ณด์.
$ docker images yshrim12/express-light
REPOSITORY TAG IMAGE ID CREATED SIZE
yshrim12/express-light latest 72b5b7354731 2 minutes ago 176MB์ฉ๋์ด ๋งค์ฐ ๊ฒฝ๋ํ ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค!
์ ์ด๋ฏธ์ง๋ก ์ปจํ ์ด๋๋ฅผ ์คํํด๋ณด์.
$ docker run -d -it --name express -p 4000:4000 --env-file=.env --network=express-net yshrim12/express-lightexpress ์ฑ์ด ์ ์์ ์ผ๋ก ์คํ๋๊ณ ์๋์ง ์ปจํ ์ด๋ ๋ก๊ทธ๋ฅผ ํ์ธํด๋ณด์.
$ docker logs express
> express@1.0.0 start
> node build/index.js
trying to start server
App listening at port 4000โข WORKDIR ์ ์ฉ
ํ์ฌ ์์ฑ๋ express ์ปจํ
์ด๋์ ์ ๊ทผํ์ฌ ls -lh / ๋ช
๋ น์ด๋ฅผ ์คํํด๋ณด์.
$ docker exec express ls -lh /
total 264K
drwxr-xr-x 1 root root 4.0K Dec 2 01:26 bin
drwxr-xr-x 2 root root 4.0K Dec 3 08:20 build
drwxr-xr-x 5 root root 360 Dec 3 08:29 dev
drwxr-xr-x 1 root root 4.0K Dec 3 08:29 etc
drwxr-xr-x 1 root root 4.0K Dec 2 01:26 home
drwxr-xr-x 1 root root 4.0K Dec 2 01:26 lib
drwxr-xr-x 5 root root 4.0K Nov 30 09:32 media
drwxr-xr-x 2 root root 4.0K Nov 30 09:32 mnt
drwxr-xr-x 75 root root 12.0K Dec 3 08:28 node_modules
drwxr-xr-x 1 root root 4.0K Dec 2 01:26 opt
-rw-rw-r-- 1 root root 181.6K Dec 3 08:28 package-lock.json
-rw-rw-r-- 1 root root 784 Dec 1 11:17 package.json
dr-xr-xr-x 326 root root 0 Dec 3 08:29 proc
drwx------ 1 root root 4.0K Dec 3 08:34 root
drwxr-xr-x 2 root root 4.0K Nov 30 09:32 run
drwxr-xr-x 2 root root 4.0K Nov 30 09:32 sbin
drwxr-xr-x 2 root root 4.0K Nov 30 09:32 srv
dr-xr-xr-x 13 root root 0 Dec 3 08:29 sys
drwxrwxrwt 1 root root 4.0K Dec 2 01:26 tmp
drwxr-xr-x 1 root root 4.0K Dec 2 01:26 usr
drwxr-xr-x 12 root root 4.0K Nov 30 09:32 var/ ๊ฒฝ๋ก์ node_modules ๋ฑ ํจํค์ง ๋ชจ๋ ๋ฐ build ํด๋ ๋ฑ์ด ๋๋ถ๋ฌ์ ธ ์๋ ๊ฒ์ ์ ์๊ฐ ์๋ค.
์ ๋ ๊ฒ ํด๋์ผ๋ฉด ๊ฐ๋
์ฑ์ด ์์ข๊ณ ์ ์ง๋ณด์๊ฐ ํ๊ธฐ ํ๋ค๋ฟ๋๋ฌ ๋ณผ๋ฅจ ์ก๊ธฐ๋ ์๋นํ ๋ฒ๊ฑฐ๋ก์์ง ์ ์๋ค.
์์ ๊ฐ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ Dockerfile์์๋ WORKDIR ์ด๋ผ๋ ์ต์
์ ์ ๊ณตํ๊ณ ์๋ค.
WORKDIR์ Dockerfile์์ ์์
๋๋ ํ ๋ฆฌ๋ฅผ ์ค์ ํ๋ ๋ฐ ์ฌ์ฉ๋๋ค. ์ด ๋ช
๋ น์ ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก ์ ์ฉํ๋ค.
- ์์ ๋๋ ํ ๋ฆฌ ์ค์ : WORKDIR ๋ช ๋ น์ ์ปจํ ์ด๋ ๋ด๋ถ์์ ์คํ๋ ๋ช ๋ น์ด๋ ํ์ผ ์์ ์ ์ํ ๊ธฐ๋ณธ ๋๋ ํ ๋ฆฌ๋ฅผ ์ค์ ํฉ๋๋ค. ์ด๋ ๊ฒ ํจ์ผ๋ก์จ ๋ช ๋ น์ ์คํํ๋ ๋์ ๊ฒฝ๋ก๋ฅผ ์ง์ ํ ํ์ ์์ด ์๋ ๊ฒฝ๋ก๋ก ์์ ํ ์ ์๊ฒ ๋ฉ๋๋ค.
๊ฐ๋ ์ฑ ๋ฐ ์ ์ง๋ณด์: Dockerfile์ ์์ฑํ ๋ WORKDIR๋ฅผ ์ฌ์ฉํ๋ฉด ๋ช ๋ น์ ๊ฐ๋ ์ฑ์ ๋์ฌ์ค๋๋ค. ์์ ๋๋ ํ ๋ฆฌ๋ฅผ ์ค์ ํ๋ฉด ํด๋น ๋๋ ํ ๋ฆฌ ๋ด์์์ ๋ชจ๋ ์์ ์ด ๋ช ํํด์ง๋ฏ๋ก, Dockerfile์ ์ดํดํ๊ณ ์ ์ง๋ณด์ํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.๊ฒฝ๋ก ์ถฉ๋ ๋ฐฉ์ง: ์ปจํ ์ด๋ ๋ด๋ถ์์ ๊ฒฝ๋ก ์ถฉ๋์ ๋ฐฉ์งํ๊ธฐ ์ํด WORKDIR๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์์ ๋๋ ํ ๋ฆฌ๋ฅผ ์ค์ ํจ์ผ๋ก์จ ๋ค๋ฅธ ๋๋ ํ ๋ฆฌ์์ ํผ๋์ ์ค์ด๊ณ ๋ช ์์ ์ธ ๊ฒฝ๋ก๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
WORKDIR์ ๊ธฐ์กด Dockerfile์ ์ ์ฉํด๋ณด์!
# Build Stage
FROM node:18-alpine AS builder
WORKDIR /builder
COPY ./package*.json ./
RUN npm install -D
COPY ./ ./
RUN npm run build
# Production Stage
FROM node:18-alpine AS prod
WORKDIR /prod
COPY /builder/build ./build
COPY ./builder/package*.json ./
RUN npm install --only=production
CMD [ "npm", "run", "start" ]์ด๋ฏธ์ง๋ฅผ ์ฌ๋น๋ ํ๋๋ก ํ์.
$ docker build --tag yshrim12/express-light .์ฌ๋น๋๋ ์ด๋ฏธ์ง๋ก ์ปจํ ์ด๋๋ฅผ ์คํํด๋ณด์.
$ docker run -d -it --name express -p 4000:4000 --env-file=.env --network=express-net yshrim12/express-lightexpress ์ปจํ
์ด๋์ pwd ๋ช
๋ น์ ๋ ๋ ค๋ณด์.
$ docker exec express pwd
/prodํ์ฌ ๊ฒฝ๋ก๊ฐ /prod์ ์๋ค๊ณ ๋์จ๋ค.
์ด๋ Dockerfile์์ prod stage์ WORKDIR์ด /prod๋ก ์ค์ ํด๋จ๊ธฐ ๋๋ฌธ์ด๋ค.
โข Docker volume ์ ์ฉ
์์ค์ฝ๋ ์ค์๊ฐ ๋๊ธฐํ๋ฅผ ์ํด Docker Volume์ ์ ์ฉํด๋ณผ ๊ฒ์ด๋ค.
๋จผ์ ๊ฐ๋ฐ์ฉ Dockerfile์ ๋ง๋ค์ด์ฃผ์.
(./Dockerfile.dev)
FROM node:18-alpine
WORKDIR /my-app
RUN npm install -g nodemon
COPY ./package*.json ./
RUN npm install -D
COPY ./ ./
RUN npm run build
CMD ["npm", "run", "dev"]ํด๋น Dockerfile์ ๊ธฐ๋ฐ์ผ๋ก ์๋ก์ด ์ด๋ฏธ์ง๋ฅผ ์์ฑํ์.
$ docker build --tag yshrim12/express-dev -f Dockerfile.dev .volume ์ต์ ์ ์ ์ฉํ์ฌ ์ปจํ ์ด๋๋ฅผ ๋ง๋ค์ด๋ณด์.
$ docker run -d -it --name express-dev -p 4000:4000 \
--env-file=.env --network=express-net \
-v "$(pwd)/app:/my-app/app" \
yshrim12/express-dev์ปจํ ์ด๋๊ฐ ์ ์คํ๋๋์ง ๋ก๊ทธ๋ฅผ ์ดํด๋ณด์.
$ docker logs express-dev
9:14:41 AM - File change detected. Starting incremental compilation...
[0]
[1] [nodemon] restarting due to changes...
[0]
[0] 9:14:42 AM - Found 0 errors. Watching for file changes.
[1] [nodemon] restarting due to changes...
[1] [nodemon] starting `node build/index.js`
[1] trying to start server
[1] App listening at port 4000์ด์ ๋ก์ปฌ์์ ๋ณ๊ฒฝ๋ ์ฝ๋๊ฐ ์ปจํ ์ด๋์์๋ nodemon์ ํตํด ์ค์๊ฐ์ผ๋ก ๊ฐ์ง๋๊ณ ๋ณ๊ฒฝ๋๋์ง ํ์ธํด๋ณด์.
๋จผ์ ๋ก์ปฌ์์ app/app.ts ์์ค์ฝ๋ ์ผ๋ถ๋ถ์ ์๋์ฒ๋ผ ๋ณ๊ฒฝํ์.
...
app.get("/", (request, response) => {
response.status(200).send("hello from express, Added volume options!");์ฝ๋๋ฅผ ๋ณ๊ฒฝํ์ผ๋ฉด curl localhost:4000 ๋ช
๋ น์ ๋ ๋ ค ๋ณ๊ฒฝ๋ ๊ฐ์ผ๋ก ์ถ๋ ฅ๋๋์ง ํ์ธํ์.
$ curl localhost:4000
hello from express, Added volume options!๐ฅ Docker-Compose๋ก ๊ฐํธํ๊ฒ ๊ฐ๋ฐํ๊ธฐ
๋งค๋ฒ docker run์ผ๋ก ์ปจํ
์ด๋๋ฅผ ๋์ด๋ค๋ ๊ฒ์ด ์ผ๋ง๋ ๊ท์ฐฎ๊ณ ๋ฒ๊ฑฐ๋ก์ด๊ฐ?
์ด๋ฐ ์ค์ ๋ค์ Docker Compose๋ก ์ ์ฅํ์ฌ ๊ฐ๋จํ๊ฒ ์คํํด๋ณผ ์ ์๋ค!
๐ก Docker Compose ๋ฅผ ์ ์์ฑํ๋ ค๋ฉด YAML ๋ฌธ๋ฒ์ ๋ํด ์๊ณ ์์ด์ผ ํ๋ค. ๊ด๋ จ ๋ด์ฉ์ ์๋ ํฌ์คํ ์ ์ฐธ๊ณ ํ๋๋ก ํ์.
YAML ์ดํดํ๊ธฐ - WTT DevlogDocker Compose ๊ด๋ จ ๋ฌธ๋ฒ์ด๋ ๋ด์ฉ๋ค์ ์๋ ํฌ์คํ ๋ค์ ์ฐธ๊ณ ํ๋๋ก ํ์.
Docker-Compose - WTT Devlog
ํ์ฌ ํ๋ก์ ํธ ๊ฒฝ๋ก์ docker-compose.yaml ๋ ํ์ผ์ ๋ง๋ค๊ณ ์๋ ์ค์ ๋ค์ ๋ถ์ฌ๋ฃ๊ธฐ ํ์.
version: "3.2"
services:
express:
depends_on:
- "redis"
build:
context: .
dockerfile: Dockerfile.dev
restart: always
volumes:
- type: bind
source: "./app"
target: "/my-app/app"
ports:
- "4000:4000"
env_file:
- ".env"
environment:
REDIS_URL: "redis://redis:6379"
PORT: 4000
networks:
- "express-net"
container_name: express-dev
redis:
image: redis:alpine
restart: always
volumes:
- type: volume
source: "data"
target: "/data"
networks:
- "express-net"
container_name: redis
volumes:
data: {}
networks:
express-net:
driver: bridge
external: falsedocker-compose.yaml ํ์ผ ์์ฑ์ด ๋ชจ๋ ๋๋ฌ๋ค๋ฉด ์ด์ ์ปจํ ์ด๋๋ฅผ ๋ฐฐํฌํด๋ณด์!
$ docker-compose up -d --build์ปจํ ์ด๋๊ฐ ์ ์์ ์ผ๋ก ์คํ๋๋์ง ํ์ธํ์.
$ docker-compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
express-dev express-express "docker-entrypoint.sโฆ" express About a minute ago Up About a minute 0.0.0.0:4000->4000/tcp, :::4000->4000/tcp
redis redis:alpine "docker-entrypoint.sโฆ" redis About a minute ago Up About a minute 6379/tcp๋ง๋ฌด๋ฆฌ
์ด๋ ๊ฒ ์ ํต์ ์ธ ๋ฐฉ์์ผ๋ก ๊ฐ์์๋ฒ์ ๋ฐฐํฌํ๋ ๋ฒ๋ถํฐ ๋์ปค๋ก ๋ฐฐํฌํ๋ ๋ฒ ๊น์ง ์ดํด๋ณด์๋ค.
์ด์ ์ฐจํ์ ์์ฑ๋ ํฌ์คํ ์์๋ AWS ๋ณด์ ๊ด๋ จ ๋ฐ ECS, AWS Image Registry , Docker-Compose๋ก CI, AWS OpenID Connect ๋ฑ์ ํ์ฉํ์ฌ ์ปจํ ์ด๋๋ฅผ ํ์ฉํ ์๋ฒฝํ CI/CD ํ์ดํ๋ผ์ธ์ ๊ตฌ์ถํด๋ณผ ๊ฒ์ด๋ค!
