Docker series
[ - ] Docker 개념정리 포스팅 [https://jizard.tistory.com/322]
[ x ] Docker 실습 포스팅
Project File Tree
├── app
│ ├── Dockerfile
│ ├── index.js
│ ├── node_modules
│ ├── package-lock.json
│ └── package.json
├── docker-compose.yml
├── mysql
│ └── Dockerfile
└── nginx
├── Dockerfile
└── default.conf
*Github에서 전체 프로젝트 소스보기 [https://github.com/lx5475/Docker-]
Docker를 사용하여 독립된 환경에서 mysql와 nginx를 구동하는 Node.js 앱 환경을 구성해보도록 하자. Node.js 앱의 내용은 mysql 연결이 잘 되는지 확인하는 코드다. app/index.js
에서 다음과 같은 정보로 Mysql 커넥션 풀을 생성하고, 커넥션을 얻을 수 있다면 "Connection success"를 출력하고, 그렇지않으면 에러 메세지를 출력한다.
app.get('/db_check', (req, res) => {
if (!pool) {
var pool = mysql.createPool({
host: "docker-mysql",
user: "root",
password: "nodejs",
database: "db_sample",
port: 3306
});
}
pool.getConnection((err, connection) => {
if (err) {
console.log(err);
res.send(err.message);
} else {
connection.release();
res.send("Connection success")
}
});
})
위 파일 트리에 보면 app, mysql, nginx 폴더마다 Dockerfile
들이 보인다. Dockerfile
은 일종의 매크로를 적어둔 것과 같고, 이를 이용해 Docker 이미지를 생성할 수 있다.
Dockerfile 명령문 알아보기
Dockerfile 예시를 보면서 간단한 Docker DSL을 알아보자. 아래는 app/Dockerfile
의 내용이다.
# Base 이미지를 nodeJS alpine 버전으로 사용
FROM node:alpine
# 작업 디렉토리 전환
WORKDIR /usr/src/app
# local 컴터에있는 package.json 파일을 현재 워킹 디렉토리에 복사
COPY package*.json ./
# local machine 에서 npm install 실행
RUN npm install
COPY . .
EXPOSE 5000
ENTRYPOINT ["node"]
CMD ["index.js"]
FROM
이미지는 마치 웨하스처럼 레이어를 쌓아가면서 중첩하여 사용할 수 있는데, 가장 기본이 되는 베이스 이미지를 지정해주기 위해 FROM
명령문을 사용한다. 아래와 같은 용법으로 사용할 수 있다.
FROM <이미지>:<버전>
FROM <이미지> # 생략시 latest이다.
WORKDIR
작업 디렉토리를 전환하는 것이다. WORKDIR
로 디렉토리를 전환하면 이후 명령어는 모두 해당 디렉토리를 기준으로 수행된다.
COPY
호스트 컴퓨터에있는 파일을 Docker 이미지 내의 파일시스템으로 복사한다.
COPY <host src> <dest>
EXPOSE
컨테이너가 리스닝할 포트를 설정한다. 나중에 docker compose YAML 설정을 통해서 포트를 설정해도 되므로 생략해도 된다.
CMD
컨테이너를 띄울때 실행할 커맨드 또는 ENTRYPOINT
명령문의 커맨드에 인자를 덧붙일때 사용할 수 있다. RUN
명령문도 비슷하게 명령어를 실행할때 사용되는데, 둘의 차이를 기억하자.
- RUN: 이미지 빌드시 항상 실행됨
- CMD: 컨테이너 생성시에만 실행됨
CMD ["node", "index.js"] # 다음 문장과 동일한표현 = node index.js
ENTRYPOINT
사실 예제에서 CMD \["node", "index.js"\]
처럼 해주어도 되지만 굳이 ENTRYPOINT
를 설정해준 이유가 있다. ENTRYPOINT
명령문은 컨테이너가 실행될때 같이 실행되고, 컨테이너가 종료될때 같이 종료되기 때문이다. Node.js 앱을 위한 컨테이너이기 때문에 컨테이너와 애플리케이션의 생명주기를 같이 맞춰주어야 할 필요성이있다.
Dockerfile 주요 명령문을 알아보았으니 나머지 Dockerfile 내용들도 대충 어떤일을 하는 것인지 알 수 있을 것이다.
========= mysql/Dockerfile =========
FROM mysql
CMD ["mysqld"]
========= nginx/Dockerfile =========
FROM nginx
COPY default.conf /etc/nginx/conf.d/default.conf
Dockerfile로 이미지 만들기
우리는 Docker compose를 이용할 것이지만 Docker run
과 build
도 알아둘 필요성이 있기에 짚고넘어간다.
docker build
명령어로 louloulou라는 Tag 이름으로 현재 디렉토리에 위치한 Dockerfile
을 토대로 이미지를 생성하는 명령어다. Dockerfile 내용은 위에서 본 app/Dockerfile
과 같다.
docker build -t louloulou .
이미지가 생성된 후 아래처럼 만들어진 이미지를 볼 수 있다. (왤케 용량커?!ㅋㅋㅋㅋㅋ)
$ docker images
REPOSITORY TAG IMAGE ID SIZE
louloulou latest 000050dcd617 1.01GB
이제 이 이미지를 실행시켜 컨테이너가 동작하도록 해보자. localhost:8080
에 들어가면 정상적으로 Express 작동되는 중...
$ docker run -dp 8080:5000 louloulou
2933930471f63c81dcc3040d472748efbe5ebeb1ae6e03647468073135cb9c4f
이제 진행중인 container 목록에 방금 만든 컨테이너가 뜬다.
$ docker ps
CONTAINER ID IMAGE STATUS PORTS
2933930471f6 louloulou Up 2 minutes 0.0.0.0:8080->5000/tcp
얼마든지 멈추고, 얼마든지 삭제할 수 있다.
$ docker stop 2933930471f6
2933930471f6 # 스톱~
$ docker rm 2933930471f6
2933930471f6 # 삭제~
Nginx 세팅
크게 특별한 세팅은 없다. 하지만 proxy\_pass
를 nodeserver라는 이름의 host와 5000번 port를 사용했다는 것을 눈여겨보면된다.
server {
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://nodeserver:5000;
}
}
어벤져스 어셈블, Docker Compose!
매번 변화가있을때마다 각각의 Dockerfile을 통해 이미지를 만들필요없이 docker-compose.yml
설정파일 하나를 만들어두면 일괄적으로 생성할 수 있다. 세부 설정들도 가능한데, 같이 알아보자.
version: "3.8"
services:
mysql:
container_name: "nodeserver-mysql"
restart: unless-stopped
hostname: "docker-mysql"
build:
context: ./mysql
ports:
- "6603:3306"
environment:
- MYSQL_ROOT_PASSWORD=nodejs
nodeserver:
container_name: "nodeserver-app"
restart: unless-stopped
depends_on:
- mysql
build:
context: ./app
ports:
- "5000:5000"
nginx:
container_name: "nodeserver-nginx"
restart: always
build:
context: ./nginx
ports:
- "80:80"
가장 위쪽에 version에는 스키마 버전을 정의해야한다. 여기에서 현재 스키마 버전과 호환성 매트릭스를 확인 할 수 있는데 대부분의 경우 가장 최신버전을 사용하는 것이 좋다.
services에는 서비스 항목과 컨테이너 이미지를 정의한다.
- container_name: 만들어질 컨테이너 이름을 정의
- hostname: 컨테이너 내의 hostname이다. 컨테이너간의 통신에서 DNS 처럼 쓰인다. 위에서 index.js에서 mysql 연결시 "docker-mysql"이라는 hostname을 사용하는 것을 볼 수 있다.
- restart: Docker가 종료되었을때 해당 컨테이너가 실행될지 옵션이다. 많이 쓰이는 것은 no
/ unless-stopped
/ always
. nginx는 대개 일부러 멈춰놓지는 않기때문에 always 옵션을 주었다.
ㄴ **no**: 실행하지 않음
ㄴ **unless-stopped:** 컨테이너를 명시적으로 멈추기전까지 항상 재시작
ㄴ **always**: 항상 재시작
- build - context: docker build 명령을 실행할 디렉토리 경로다.
- ports: 앞쪽 포트는 호스트 컴퓨터의 포트, 뒷쪽 포트는 Docker 내부에서 사용하는 포트다. 앞쪽 포트를 6603으로 세팅해두면 호스트 컴퓨터에서 mysql -h127.0.0.1 --port 6603
명령어를 통해 접근 가능하다!
- environment: 환경변수를 지정해 줄 수 있다.
- depends_on: 서비스간의 종속성을 추가하여 순차적인 실행을 할 수 있도록 해준다. 여기에서는 mysql을 먼저 실행한 뒤에 nodeserver가 실행될 수 있도록 했다.
docker-compose.yml
을 모두 작성했다면 이제 실행해볼 차례다. 여러 컨테이너를 생성해서 Docker 고래등에 적재(up)하고 하역(down)하는 것을 상상하면 이 명령어들이 좀 귀여워보일지도?!
# docker-compose.yml에 정의된 컨테이너를 한번에 생성하고 실행한다 (*올린다).
# -d 옵션은 백그라운드에서 띄우기 위해 넣는다.
# --build 옵션을 넣을 수도 있는데, 이 옵션이 있으면 캐시된 이미지를 체크하지않고 무지성으로
# 새로 빌드를 하기때문에 소스가 수정되었을때 넣어주면 좋다.
$ docker-compose up -d
# docker-compose.yml에 정의된 컨테이너를 한번에 정지시키고 삭제한다 (*내린다).
$ docker-compose down
# docker-compose.yml에 정의된 컨테이너 중 내려가있는 컨테이너를 올리기 위해서 사용한다.
$ docker-compose start <container_name>
# docker-compose.yml에 정의된 컨테이너 중 올라가있는 컨테이너를 내리기 위해서 사용한다.
$ docker-compose stop <container_name>
docker compose up --build -d
를 통해 성공적으로 컨테이너들을 올리고나서 docker ps
를 때려보면 이렇게 성공적으로 컨테이너들이 올라간것이 보인다.
$ docker ps
CONTAINER ID IMAGE PORTS
39a83afb462b docker_practice_nodeserver 0.0.0.0:5000->5000/tcp
cd258df8c429 docker_practice_mysql 33060/tcp, 0.0.0.0:6603->3306/tcp
0686be3171d4 docker_practice_nginx 0.0.0.0:80->80/tcp
걸어서 컨테이너 속으로
localhost/db_check
으로 가서 mysql이 제대로 연결되었나 확인해보면 이렇게 오류 메세지가 뜬다. 말 그대로 db_sample
이라는 데이터베이스가 없다는 것인데, 보통은 초기 설정 sql 을 같이 넣어서 이미지를 생성하지만 우리는 그러지 않았기 때문에 저렇게 오류가난다. Docker 컨테이너 내부로 들어가서 database를 직접 만들어보자.
$ docker exec -it <mysql 컨테이너의 ID> bash
명령어를 치면 컨테이너의 파일 시스템 속으로 들어갈 수 있다.
root@docker-mysql:/# mysql -u root -p
Enter password: nodejs
mysql> create database db_sample;
데이터베이스를 만든 직후 localhost/db_check
을 새로고침하면 다음과 같이 제대로 연결되었다는 메세지가 뜬다!
참고자료
https://www.daleseo.com/dockerfile/
https://docs.microsoft.com/ko-kr/visualstudio/docker/tutorials/use-docker-compose
'프로그래밍 > Docker' 카테고리의 다른 글
open /Users/<USER>/.docker/buildx/current: permission denied 오류 해결방법 (0) | 2023.10.03 |
---|---|
Docker에서 shellscript crontab으로 돌리기 (0) | 2022.06.18 |
[Docker] swarm을 알아보자 (0) | 2022.06.01 |
Docker 컨테이너와 이미지의 개념과 강점 알아보기 (0) | 2022.01.04 |