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.json
Dockerfile ๋ด์ฉ์ ๊ธฐ๋ฐ์ผ๋ก ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ ๊ฒ๋ถํฐ ์บ์ ํ์ฉ, ๋ฉํฐ ์คํ ์ด์ง ๋น๋ ๋ฑ์ ์ ์ฉํ๋ฉด์ 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/express
express ์ปจํ ์ด๋ ์ํ์ ๋ก๊ทธ๋ฅผ ์กฐํํด๋ณด์.
$ 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.0
PORT ํ๊ฒฝ ๋ณ์๊ฐ ๋น ๊ฐ์ผ๋ก ๋์ด๊ฐ ๊ฒ ๊ฐ๋ค. ์ด์ ๊ฐ ๋ญ๊น?
๐บ ํธ๋ฌ๋ธ ์ํ
์ด์ฐ๋ณด๋ฉด ๋น์ฐํ ์ ๊ธฐ์ด๋ค. .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/express
express ์ปจํ ์ด๋ ๋ก๊ทธ๋ฅผ ๋ค์ ํ์ธํด๋ณด์.
$ 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-light
express ์ฑ์ด ์ ์์ ์ผ๋ก ์คํ๋๊ณ ์๋์ง ์ปจํ ์ด๋ ๋ก๊ทธ๋ฅผ ํ์ธํด๋ณด์.
$ 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-light
express ์ปจํ
์ด๋์ 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: false
docker-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 ํ์ดํ๋ผ์ธ์ ๊ตฌ์ถํด๋ณผ ๊ฒ์ด๋ค!