개발/devOps

[docker] 쉽고 빠른 서비스를 향해 (2)

김키쿠 2023. 11. 21. 17:04

https://kiku99.tistory.com/13

 

[docker] 쉽고 빠른 서비스를 향해 (1)

때는 바야흐로 2020년. 코로나로 인해 비대면 수업을 하던 시절이었다. 1년동안 아무도 학교에 나오지 않았고, 학과 회장 선거에 비상이 걸렸다. 왜나하면 선거 투표는 항상 대면으로 진행했으까.

kiku99.tistory.com

지난 글에서 말했던 대로 docker volume을 사용해서 환경변수 파일을 컨테이너에 주입해 보기로 했다. 참고로 현재 작성 시점은 테스트 성공까지 확인한 후다. 따라서 내가 겪었던 우여곡절 순으로 글을 써볼 생각이다.

 

1. 볼륨을 src 디렉토리에 직접 연결해 보자!

 

처음 생각해 본 건 환경변수 파일을 가진 호스트 볼륨을 도커 workdir인 src 디렉토리와 연결하자라는 생각이었다. 도커파일을 보면 workdir이 src 디렉토리라는 것을 알 수 있다.

FROM node:20  

ENV SERVICE_PORT 3001
ENV SRC_DIR /tmp/src

COPY src ${SRC_DIR}
ARG CACHEBUST=1
WORKDIR ${SRC_DIR}

RUN apt update && apt upgrade -y
RUN npm install yarn
RUN yarn global add forever
RUN yarn global add nodemon

EXPOSE ${SERVICE_PORT}

CMD ["yarn", "dev"]
docker run -v /secret/.env:/tmp/src sevote

 

하지만 오류를 내뱉으며 실패했는데 도커 이미지 작업 경로와 호스트 볼륨이 겹치면 안 되는 것으로 추측 중이다. 따라서 src 경로 안에 환경변수 파일을 넣어주려던 첫 번째 계획은 실패했다.

2. dockerfile에서 환경변수 파일을 copy 해보자!


그러면 볼륨은 다른 경로에 만들어주고 도커파일에서 cp 명령어를 통해 환경변수 파일을 src 디렉토리로 복사해오면 되지 않겠는가? 

FROM node:20  

ENV SERVICE_PORT 3001
ENV SRC_DIR /tmp/src

COPY src ${SRC_DIR}
ARG CACHEBUST=1
WORKDIR ${SRC_DIR}

RUN cp ../../secret/.env ./

RUN apt update && apt upgrade -y
RUN npm install yarn
RUN yarn global add forever
RUN yarn global add nodemon

EXPOSE ${SERVICE_PORT}

CMD ["yarn", "dev"]

 

라는 생각은 아주 멍청한 생각이었다. 도커 이미지를 빌드할 때 당연히 볼륨을 가리키는 경로에는 아무것도 없기 때문에 빌드조차 되지 않는 것이었다. (바보)

3. 코드를 수정해 볼륨과 연결하자!


이건 조금 늦게 떠오른 생각인데 소스코드를 수정하는 방법이었다. 꼭 환경변수가 src 디렉토리 안에 있지 않아도 된다는 생각을 왜 못했을까..? 코드에서 경로 수정만 해주면 된다고 생각했다. 하지만 예상치 못한 문제가 발생하는데...

 

 

바로 js파일을 못읽는 문제였다. export를 해야되는데 export가 뭔지 모르면 어떡하니..ㅜ

 

폭풍 구글링을 해본 결과 es6 버전으로 작성된 소스코드와는 다르게 common 문법으로 작성해보라는 글을 보았고 다음과 같이 코드를 수정했다.

 

 

환경변수 파일을 가져오는 경로를 볼륨을 연결한 컨테이너 내부 경로로 바꿔주고 import 대신 require문으로 변수를 가져왔다. 물론 환경변수 파일도 module.export 형태로 수정했다.

 

 

결과는 대성공! 되게 간단하게 해결한 것 처럼 보이지만 꽤 시행착오를 겪었다.. 하지만 이제 시작이다. 잘 빌드된 도커 이미지를 허브에 올리고 프로덕션 서버에서 환경을 만들어줘야 한다. 개발 환경은 윈도우지만 프로덕션 환경은 리눅스기 때문에 아마 포트포워딩 명령어가 조금 다를것이다. 일단 도커 허브에 먼저 올려보자.

 

 

도커 허브에 올린 이미지를 프로덕션 서버에서 pull 해온다. 컨테이너를 실행하기 앞서 secret 디렉터리와 그 안에 환경변수 파일도 만들어 주어야 한다.

 

또한 mongodb가 localhost에서 동작하므로 도커 컨테이너와 호스트 localhost를 연결해 줄 필요가 있다.

 

여기서 윈도우 환경에서는 host ip를 host.docker.internal로 설정해 호스트의 localhost와 연결했지만 리눅스에서는 조금 다르다. host.docker.internal 명령어를 사용할 수 없으므로 host ip를 직접 명시해주거나 ex) 192.xxx.xxx.xxx 아니면 컨테이너 실행시 --network="host" 옵션을 통해 호스트의 localhost 연결할 수 있다.

 

따라서 다음의 명령어를 통해 컨테이너를 최종적으로 실행할 수 있었다.

sudo docker run -it --name sevote -v /home/ampm/secret:/secret -p 10011:10011 ampmjbnu/sevote:0.0.1

 

포트포워딩 옵션을 보면 알 수 있듯이 10011 포트를 통해 외부에서 컨테이너로 접근할 수 있다.

 

 

잘 동작한다! 이제 CI/CD pipeline 구축과 앞으로의 메인테이너를 위한 리드미를 예쁘게 작성하는 일만 남았다.