Programming Language

[Docker] SvelteKit + MongoDB + Tailwind CSS dockerizing - MongoServerError: Authentication failed.

LeeJaeJun 2024. 7. 24. 00:47
728x90
반응형

SvelteKit과 Tailwind CSS에 대한 도커 이미지는 정상적으로 만들어졌지만, 컨테이너에 올려서 DB와 연결시키려고 하니

다음과 같은 에러가 나타났다.

app | Error fetching memo: MongoServerError: Authentication failed. 
app | at Connection.sendCommand (/app/node_modules/mongoose/node_modules/mongodb/lib/
cmap/connection.js:297:27) mongo | {"t":{"$date":"2024-07-23T01:31:24.857+00:00"},"s":"
I", "c":"NETWORK", "id":22944, "ctx":"conn3","msg":"Connection ended","attr":{"remote":
"172.19.0.3:45378","uuid":{"uuid":{"$uuid":"ef48d134-dbb4-4ffa-842f-b164b2676dcc"}},"
connectionId":3,"connectionCount":0}} app | at process.processTicksAndRejections (node:
internal/process/task_queues:95:5) app | at async Connection.command (/app/node_modules
/mongoose/node_modules/mongodb/lib/cmap/connection.js:325:26) app | at async executeScr
am (/app/node_modules/mongoose/node_modules/mongodb/lib/cmap/auth/scram.js:79:22) app 
| at async ScramSHA1.auth (/app/node_modules/mongoose/node_modules/mongodb/lib/cmap/aut
h/scram.js:39:16) app | at async performInitialHandshake (/app/node_modules/mongoose/n
ode_modules/mongodb/lib/cmap/connect.js:101:13) app | at async connect (/app/node_modul
es/mongoose/node_modules/mongodb/lib/cmap/connect.js:19:9) { app | errorResponse: { app
| ok: 0, app | errmsg: 'Authentication failed.', app | code: 18, app | codeName: 'Authe
nticationFailed' app | }, app | ok: 0, app | code: 18, app | codeName: 'AuthenticationF
ailed', app | connectionGeneration: 0, app | [Symbol(errorLabels)]: Set(2) { 'Handsha
keError', 'ResetPool' }

MONGODB_URI=mongodb://root:example@mongo:27017/memo_database

이런 식으로 루트의 username과 password를 사용하였지만 권한 부족이라고 에러가 떴기에 의아 했습니다.

 


원인과 해결법

MongoDB는 사용자를 생성할 때 특정 데이터베이스에 속한 사용자로 생성합니다. 기본적으로, admin 데이터베이스에 생성된 사용자는 모든 데이터베이스에 접근할 수 있는 권한을 가지지만, 다른 데이터베이스(memo_database등)에 사용자 정보를 저장하고 인증하려고 하면 admin 데이터베이스를 참조해야 합니다. 따라서 createUser로 한번 더 user를 만들어서 접속을 해야 합니다. 혹은 MongoDB에서 애플리케이션이 접근할 사용자 계정을 admin 데이터베이스가 아닌 애플리케이션이 실제로 접근하는 데이터베이스(memo_database)에 생성해야 합니다.

 

mongoDB에서 직접 createUser를 해도 되지만 init-mongo.js파일을 루트폴더에 만들어서 docker-compose.yml에서 활용할 수 있도록 하였습니다.

// init-mongo.js
db = db.getSiblingDB('memo_database');
db.createUser({
  user: "memo_user",
  pwd: "password123",
  roles: [{ role: "readWrite", db: "memo_database" }]
});
# DockerFile
# 빌드 단계
FROM node:18-alpine AS builder

# 작업 디렉토리 생성
WORKDIR /app

# 소스 코드 복사
COPY . .

# 종속성 설치
RUN npm install

# TailwindCSS 빌드
RUN npx tailwindcss -i ./src/app.css -o ./static/build/tailwind.css

# 환경 변수 설정
COPY .env .env
RUN export $(cat .env | xargs) && npm run build

# 프로덕션 이미지
FROM node:18-alpine

# 작업 디렉토리 생성
WORKDIR /app

# 빌드된 파일 및 필요한 파일 복사
COPY --from=builder /app/build /app/build
COPY --from=builder /app/static /app/static
COPY --from=builder /app/package.json /app/package-lock.json /app/

# 프로덕션 종속성 설치
RUN npm install --production && \
  npm cache clean --force

# 환경 변수 설정 (실행 단계)
ENV MONGODB_URI=mongodb://memo_user:1234@mongo:27017/memo_database

# 애플리케이션 실행
CMD ["node", "build/index.js"]
# docker-compose.yml
version: '3.8'

services:
  mongo:
    image: mongo:latest
    container_name: mongo
    ports:
      - "27017:27017"
    networks:
      - app-network
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: example
    volumes:
      - mongo-data:/data/db
      - ./init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js:ro

  app:
    build: .
    container_name: app
    ports:
      - "3000:3000"
    networks:
      - app-network
    env_file:
      - .env
    depends_on:
      - mongo

volumes:
  mongo-data:

networks:
  app-network:
    driver: bridge
// database.js (mongoDB 연결하는 파일)
import mongoose from 'mongoose';
import dotenv from 'dotenv';

dotenv.config();

const MONGODB_URI = process.env.MONGODB_URI;

if (!MONGODB_URI) {
    throw new Error('Please define the MONGODB_URI environment variable inside .env');
}

export async function connectToDatabase() {
    if (mongoose.connection.readyState >= 1) return;

    try {
        await mongoose.connect(MONGODB_URI, {
            useNewUrlParser: true,
            useUnifiedTopology: true,
        });
        console.log('Successfully connected to MongoDB');
    } catch (error) {
        console.error('Error connecting to MongoDB:', error);
        throw new Error('Failed to connect to MongoDB');
    }
}
728x90
반응형