Express+Mongodb 动态注入 mongodb 密码实践记录
初衷
简单介绍下如何在 express
项目下配合 docker-compose
动态注入 mongodb
账号密码,项目目录在下方,但不涉及具体项目如何运行,只介绍如何使用。
项目目录
📦backend
┣ 📂db
┃ ┗ 📜index.ts
┣ 📂interface
┣ 📂middleware
┣ 📂models
┣ 📂routes
┣ 📂utils
┣ 📜.dockerignore
┣ 📜.eslintrc.js
┣ 📜.gitignore
┣ 📜Dockerfile
┣ 📜README.md
┣ 📜app.ts
┣ 📜build.sh // 注入 mongodb 密码和单个库密码
┣ 📜dev.env // 开发环境变量
┣ 📜docker-compose.yml // 生成项目和 mongodb 镜像
┣ 📜mongo-init.sh // 初始化账号密码
┣ 📜package-lock.json
┣ 📜package.json
┣ 📜prod.env // 生产环境变量
┗ 📜tsconfig.json
环境文件
dev.env
NODE_ENV=dev
PORT=3981
# MONGODB_URL=mongodb://localhost:27017/auto-answer
MONGODB_URL=mongodb://mongodb:27017/auto-answer
MONGO_INITDB_ROOT_USERNAME=root
MONGO_INITDB_ROOT_PASSWORD=123456
MONGO_USERNAME=admin
MONGO_PASSWORD=test123456
MONGO_HOST=localhost
MONGO_PORT=27017
MONGO_INITDB_DATABASE=auto-answer
prod.env
NODE_ENV=production
PORT=3981
# MONGODB_URL=mongodb://localhost:27017/auto-answer
MONGODB_URL=mongodb://mongodb:27017/auto-answer
MONGO_INITDB_ROOT_USERNAME=root
MONGO_INITDB_ROOT_PASSWORD=123456
MONGO_USERNAME=admin
MONGO_PASSWORD=test123456
MONGO_HOST=mongodb
MONGO_PORT=27017
MONGO_INITDB_DATABASE=auto-answer
构建运行 compose 脚本 build.sh
#!/bin/bash
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]
then
echo "Need input with build env('prod' or 'dev') or MONGO_INITDB_ROOT_PASSWORD or MONGO_PASSWORD!"
exit 1
else
echo $1
echo $2
echo $3
env MACHINE_ENV=$1 MONGO_INITDB_ROOT_PASSWORD=$2 MONGO_PASSWORD=$3 docker-compose -p auto-answer-backend-hub up -d
fi
# 通过 sh build.sh 传参数
构建 compose 只需要运行下方命令即可(这里需要注意命令需要在 dockerfile
和 compose
构建完成之后运行)
sh build.sh MACHINE_ENV MONGO_INITDB_ROOT_PASSWORD MONGO_PASSWORD
将上述 MONGO_INITDB_ROOT_PASSWORD
、MONGO_PASSWORD
替换成你所有需要的密码
MACHINE_ENV
为上面项目目录中的 dev
或 prod
,可根据需求更改。
构建 Dockerfile
FROM node:16.0.0
LABEL maintainer="webB1anyaoyao@gmail.com"
COPY . /app
WORKDIR /app
RUN npm install
RUN ls
RUN npm run build
EXPOSE 3981
CMD [ "npm", "start"]
构建 docker-compose.yml
version: "3"
services:
app:
container_name: auto-answer-backend-hub
restart: on-failure
env_file:
- ${MACHINE_ENV}.env
environment:
- NODE_ENV=${MACHINE_ENV}
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD}
- MONGO_PASSWORD=${MONGO_PASSWORD}
build: ./
ports:
- "3981:3981"
# volumes:
# - .:/app
depends_on:
- mongodb
mongodb:
container_name: auto-answer-mongo-hub
image: mongo:4.0.8
env_file:
- ${MACHINE_ENV}.env
environment:
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD}
- MONGO_PASSWORD=${MONGO_PASSWORD}
volumes:
- ~/data:/data/db
- ./mongo-init.sh:/docker-entrypoint-initdb.d/mongo-init.sh:ro
ports:
- "27017:27017"
env_file
:为环境变量文件,${MACHINE_ENV}.env
的MACHINE_EN
为运行build.sh
注入的变量environment
: 环境变量如果和env_file
相同,将会覆盖env_file
中变量,上述docker-compose.yml
中通过运行build.sh
注入的变量覆盖了MONGO_INITDB_ROOT_PASSWORD
和MONGO_PASSWORD
可以让数据库密码变成动态的
mongo-init.sh
生成 mongodb 脚本
mongo -- "$MONGO_INITDB_DATABASE" <<EOF
db.createUser({
user: "$MONGO_USERNAME",
pwd: "$MONGO_PASSWORD",
roles: [
{ role: "readWrite", db: "$MONGO_INITDB_DATABASE" }
]
})
EOF
数据连接
文件位置./db/index.ts
import mongoose from 'mongoose'
const {
MONGO_USERNAME = 'admin',
MONGO_PASSWORD = 'test123456',
MONGO_HOST = 'localhost',
MONGO_PORT = '27017',
MONGO_INITDB_DATABASE = 'auto-answer'
} = process.env
let uri = ''
// 通过环境变量判断,切换连接 mongodb 的 uri
if (process.env.NODE_ENV === 'dev' || !process.env.NODE_ENV) {
uri = `mongodb://${MONGO_HOST}:${MONGO_PORT}/${MONGO_INITDB_DATABASE}`
} else {
uri = `mongodb://${MONGO_USERNAME}:${encodeURIComponent(MONGO_PASSWORD)}@${MONGO_HOST}:${MONGO_PORT}/${MONGO_INITDB_DATABASE}`
}
console.log(uri)
// mongodb://admin:test123456@localhost:27017/auto-answer
mongoose.connect(uri, {
// authSource: 'admin'
}, () => {
console.log('connect!')
})
const db = mongoose.connection
db.once('open', () => {
console.log('db is connect!')
})
db.on('error', error => {
console.log(error)
})
db.on('close', () => {
console.log('db is closed!')
})
export default mongoose
验证
完成上面的步骤基本上就能通过 compose
运行后端的项目了,在项目目录通过命令:
sh build.sh MACHINE_ENV MONGO_INITDB_ROOT_PASSWORD MONGO_PASSWORD
就会运行 compose
生成两个容器:
- auto-answer-backend-hub:后端服务
- auto-answer-mongo-hub:数据库服务
通过 docker
命令进入到 mongodb
容器:
docker exec -it auto-answer-mongo-hub /bin/base
进入后,输入 mongo
进入 mongo
:
mongo
这时候输入 show dbs
,因为我们开启了数据库权限是看不到数据的
验证 root 用户
- 进入
admin
> use admin
switched to db admin
- 使用
db.auth
db.auth('root', MONGO_INITDB_ROOT_PASSWORD)
上面的 root
为环境文件中的 MONGO_INITDB_ROOT_USERNAME
,MONGO_INITDB_ROOT_PASSWORD
为运行 sh
脚本是注入的密码(这里需要更换成自己的密码)。
如果密码账号和密码正确的话会出现以下提示:
> db.auth('root', MONGO_INITDB_ROOT_PASSWORD)
1
这时可以查看所有数据库
> show dbs
admin 0.000GB
auto-answer 0.000GB
config 0.000GB
local 0.000GB
验证工作库
我们在mongo-init.sh
中通过:
db.createUser({
user: "$MONGO_USERNAME",
pwd: "$MONGO_PASSWORD",
roles: [
{ role: "readWrite", db: "$MONGO_INITDB_DATABASE" }
]
})
生成了MONGO_INITDB_DATABASE
,而这里的MONGO_INITDB_DATABASE
就是我们环境变量中设置的auto-answer
然后我们退出 mongo
后重新进入 auto-answer
:
> exit
bye
root@a25acd1cd787:/# mongo
MongoDB shell version v4.0.8
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("1179501c-6e50-433b-90dc-db828be7c467") }
MongoDB server version: 4.0.8
> show dbs
> use auto-answer
switched to db auto-answer
> show collections
Warning: unable to run listCollections, attempting to approximate collection names by parsing connectionStatus
这时可以发现 auto-answer
下没有任何表,下一步进行 db.auth
> db.auth(MONGO_USERNAME, MONGO_PASSWORD)
1
> show dbs
auto-answer 0.000GB
> show collections
airs
cookers
上面的 MONGO_USERNAME
是环境变量中的用户名(需替换成自己的),MONGO_PASSWORD
是通过 sh
注入的生成用户的密码。
至此完成所有操作。