docker-compose를 사용해 node.js 서버와 mysql db 서버 컨테이너를 만들고 node.js 서버에서 mysql db 서버에 연결을 시도하면, closed 오류가 발생한다. 이는 node.js 서버가 mysql db에 연결을 시도할 때, 아직 mysql db 서버가 완전히 실행되지 않았기 때문에 발생하는 문제이다.
이를 해결하기 위해 node.js 서버가 mysql db 서버 구동 완료 후에 실행될 수 있게 해야 한다.
이는 node.js와 mysql 외의 다른 서버와 DB에 모두 적용가능한 방법이다.
디렉토리 구조
📦
┣ 📂 db
┃ ┣ 📂 conf.d # MySQL configuraiton (선택)
┃ ┃ ┗ 📜 my.cnf
┃ ┣ 📂 initdb.d # MySQL 초기 DB 설정 (선택)
┃ ┃ ┣ 📜c reate_table.sql # 초기 테이블 생성 (선택)
┃ ┃ ┗ 📜 insert_data.sql # 초기 데이터 삽입 (선택)
┣ 📂 server
┃ ┣ 📂 node_modules
┃ ┣ 📜. dockerignore
┃ ┣ 📜 docker-entrypoint.sh
┃ ┣ 📜 Dockerfile
┃ ┣ 📜 index.js
┃ ┣ 📜 package-lock.json
┃ ┗ 📜 package.json
┗ 📜 docker-compose.yml
이 중 필수적으로 봐야할 파일들은 다음과 같다.
- docker-compse.yml
- server
- Dockerfile
- docker-entrypoint.sh
docker-compose.yml
사실 docker-compose에는 컨테이너 생성 순서와 관련해 depends_on 이 존재한다. 하지만, 기억해야할 것은 depends_on은 컨테이너의 생성 자체에만 관여하기 때문에, 컨테이너 내부에서 서버가 완전히 실행된 상태를 고려해주지는 않는다는 점이다.
# docker-compose.yml
version: "3.8"
services:
server:
container_name: server_app
build:
context: ./server
dockerfile: Dockerfile
ports:
- 5000:5000
volumes:
- ./server:/app
depends_on:
- mysql_db
stdin_open: true
tty: true
networks:
- app-tier
environment:
- DB_HOST=mysql_db # ip or localhost가 들어갈 수 있는데, 연결할 DB 컨테이너를 작성한다.
- DB_PORT=3306
- DB_USER={user 이름}
- DB_PASSWORD={user의 password}
- DB_DATABASE={데이터베이스 이름}
mysql_db:
image: mysql
volumes:
- db/data:/var/lib/mysql
- ./db/conf.d:/etc/mysql/conf.d
- ./db/initdb.d:/docker-entrypoint-initdb.d
ports:
- 3306:3306
environment:
- MYSQL_DATABASE={데이터베이스 이름}
- MYSQL_USER={user 이름}
- MYSQL_PASSWORD={user의 password}
- MYSQL_ROOT_HOST=% # 전체 ip (host)에 대해
- MYSQL_ROOT_PASSWORD={root 계정 비밀번호}
- TZ=Asia/Seoul
restart: unless-stopped
networks:
- app-tier
networks:
app-tier:
driver: bridge
volumes:
db:
중괄호로 표시된 것들은 본인 프로젝트 설정에 따라 작성하면 된다.
예를 들어, "user0" 계정을 사용하고 싶다면, DB_USER=user0으로 작성하면 된다.
.dockerignore
.gitignore
/node_modules
server (node.js)
Dockerfile
dockerize 모듈은 docker-compose에서 docker 컨테이너 간의 실행 순서를 동기화해주는 역할을 수행한다.
dockerize 모듈을 설치한 후, docker-entrypoint.sh 파일을 컨테이너에서 실행시켜 실행 순서를 동기화한다.
FROM node:latest
ENV DOCKERIZE_VERSION v0.2.0
RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
&& tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
WORKDIR /app
COPY ./package*.json ./
RUN npm install --silent
COPY docker-entrypoint.sh ./
# RUN chmod +x docker-entrypoint.sh
ENTRYPOINT ./docker-entrypoint.sh
EXPOSE 3000
docker-entrypoint.sh
#!/bin/bash
echo "wait mysql_db server"
dockerize -wait tcp://mysql_db:3306 -timeout 20s
echo "start node server"
node index.js
실행 결과
[오류] docker-entrypoint.sh: Permission denied
서버 컨테이너에서 아래와 같은 권한 오류가 발생할 수 있는데, 이는 .sh 파일 실행에 대한 권한 오류이다.
아래 코드로 해결이 되어야 하지만, 나는 여전히 오류가 발생했다.
RUN chmod +x docker-entrypoint.sh
[해결]
Stackoverflow에 이 오류에 관한 글이 있었고, 여기서도 chmod를 하라는 얘기들이 있었다.
그 중, 답변의 이 부분에서 해결법을 찾았다.
Alternately, you can ensure that the local copy referenced by the Dockerfile is executable, and then use
COPY (which is explicitly documented to retain metadata).
(도커 말고) 그냥 터미널에서 ./docker-entrypoint.sh를 실행했을 때, 똑같이 권한 오류가 발생했다. 따라서, 복사하려던 원본 파일 자체의 권한을 먼저 바꿔주었다.
# ./server
chmod +x docker-entrypoint.sh
다시 docker compose up을 실행했을 때, 정상적으로 컨테이커가 실행됨을 확인했다.
이제 문제없이 잘 작동된다!!
참고
'💻 Study > Docker 도커' 카테고리의 다른 글
Docker 사용법: 기본 커맨드 (0) | 2024.06.28 |
---|---|
[Error] The path {path} is not shared from the host and is not known to Docker. (0) | 2024.06.25 |
Docker/docker-compose 설치 및 사용법: Ubuntu (0) | 2021.05.28 |