一、博客前言
在企业后端、物联网、大数据、中台项目中,经常需要一次性部署全套中间件基础设施。手动逐个搭建、配权限、改配置、建目录、处理容器权限报错,极其繁琐且容易出问题。
本文提供一份生产可用、一键执行、零手动干预、解决所有容器权限坑的完整部署脚本,一次性搭建:
- Redis 6.2
- RabbitMQ 3.13
- Elasticsearch 8.17.2 + Kibana 8.17.2
- MongoDB 8.0.3
- InfluxDB 2.7.10
- EMQX 5.8.8 物联网MQTT网关
- SQL Server 2022 (彻底解决 /.system 权限拒绝报错)
脚本自动完成:私有仓库配置、目录创建、配置文件生成、精准权限适配、全局网络创建、镜像拉取、服务启动、账号初始化、密码重置、RabbitMQ虚拟主机/用户初始化,部署完成自动销毁脚本,干净整洁。
二、整体架构与目录结构
**1.**部署根目录
统一部署路径:/home/appInfrastructure
**2.**完整目录结构
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| bash appInfrastructure/ ├── redis/ # 缓存服务 ├── rabbitmq/ # 消息队列 ├── es-kibana/ # 日志检索引擎 ├── mongodb/ # NoSQL数据库 ├── influxdb/ # 时序数据库 ├── emqx/ # MQTT物联网网关 ├── sqlserver/ # 关系型数据库 │ ├── data/ # 数据持久化 │ ├── logs/ # 日志目录 │ └── backup/ # 数据库备份目录 └── docker-compose.yml |
三、核心解决的经典坑点(重点)
这是全网很多部署脚本的通病,本文全部修复:
1. SQL Server 2022****致命权限问题
错误日志:
|----------------------------------------------------------------------------------------------------------------|
| bash /opt/mssql/bin/sqlservr: Error: The system directory /.system could not be created. Permission denied |
根源 :SQL Server2022 Linux 容器默认非 root 运行,内部用户 mssql UID=10001,绝大多数脚本写错为 1001 或 root 权限,导致启动失败。
本文精准修复:
|-------------------------------------------------------------------------------------|
| bash sudo chown -R 10001:10001 ./sqlserver/data ./sqlserver/logs ./sqlserver/backup |
**2.**各中间件专属 UID 权限适配
不同容器内部运行用户UID不同,脚本单独适配:
- Redis / RabbitMQ / MongoDB:999
- ES / InfluxDB / EMQX:1000
- SQL Server:10001 (独家关键修复)
**3.**日志目录单独放开权限
数据目录严格权限、日志目录宽松可读,兼顾安全 + 运维排查。
**4.**自动配置私有 Docker HTTP 仓库
自动写入 daemon.json、重启Docker,无需手动改配置。
**5.**全局统一网络 internal-net
所有服务互通,微服务架构标准组网方式。
四、一键部署完整脚本(可直接落地)
新建文件deploy-all.sh,写入以下全部内容:
bash
#!/bin/bash
set -e
echo "============================================="
echo " 基础设施一键部署脚本 (专属配置版) "
echo "============================================="
# 核心配置
BASE_DIR="/home/appInfrastructure"
REGISTRY="10.31.20.13:8081"
IMAGE_PREFIX="${REGISTRY}/public-docker"
# ===================== 自动配置Docker信任HTTP仓库 =====================
echo "0. 自动配置Docker信任HTTP仓库..."
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json > /dev/null <<EOF
{
"insecure-registries": ["10.31.20.13:8081"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
echo "✅ Docker HTTP仓库配置完成,等待服务重启..."
sleep 5
# ==========================================================================
# 1. 初始化工作目录
echo "1. 初始化工作目录..."
sudo mkdir -p ${BASE_DIR}
cd ${BASE_DIR}
# ===================== 第一步:创建所有服务目录(先建目录,防止报错)=====================
echo "2. 创建服务目录结构..."
# Redis
sudo mkdir -p ./redis/data ./redis/logs
# RabbitMQ
sudo mkdir -p ./rabbitmq/data ./rabbitmq/logs
# MongoDB
sudo mkdir -p ./mongodb/data ./mongodb/logs
# ES & Kibana
sudo mkdir -p ./es-kibana/es/master/{conf,data,logs,plugins}
sudo mkdir -p ./es-kibana/kibana
# InfluxDB
sudo mkdir -p ./influxdb/data ./influxdb/config ./influxdb/logs
# EMQX
sudo mkdir -p ./emqx/data ./emqx/log
# SQL Server 目录(新增backup备份目录)
sudo mkdir -p ./sqlserver/data ./sqlserver/logs ./sqlserver/backup
# ====================================================================================
# 2. 写入配置文件(目录已创建,无报错)
echo "3. 写入服务配置文件..."
# Redis配置
cat > ./redis/redis.conf <<'EOF'
bind 0.0.0.0
protected-mode no
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize no
pidfile /var/run/redis_6379.pid
loglevel notice
logfile ""
databases 48
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
save 3600 1
save 300 100
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir ./
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-diskless-load disabled
repl-disable-tcp-nodelay no
replica-priority 100
acllog-max-len 128
requirepass shhy123#
maxclients 10000
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
appendonly yes
appendfilename "append.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
EOF
# Elasticsearch配置
cat > ./es-kibana/es/master/conf/elasticsearch.yml <<'EOF'
cluster.name: "elasticsearch"
cluster.max_shards_per_node: 12000
network.host: 0.0.0.0
xpack.security.enabled: true
http.cors.enabled: true
http.cors.allow-origin: "*"
http.cors.allow-headers: "Authorization, Content-Type, X-Requested-With"
EOF
# Kibana配置
cat > ./es-kibana/kibana/kibana.yml <<'EOF'
server.port: 5601
server.host: "0.0.0.0"
elasticsearch.hosts: ["http://es:9200"]
i18n.locale: "zh-CN"
elasticsearch.username: kibana_system
elasticsearch.password: shhy123#
EOF
# 3. 生成docker-compose.yml
echo "4. 生成Docker编排文件..."
cat > docker-compose.yml <<EOF
networks:
internal-net:
external: true
services:
redis:
image: ${IMAGE_PREFIX}/redis:6.2.0
container_name: redis6
restart: always
ports:
- "6379:6379"
volumes:
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
- ./redis/data:/data:rw
- ./redis/logs:/var/log/redis:rw
environment:
- TZ=Asia/Shanghai
command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 3
networks:
- internal-net
rabbitmq:
image: ${IMAGE_PREFIX}/rabbitmq:3.13-management
container_name: rabbitmq
restart: always
hostname: rabbitmq
environment:
- RABBITMQ_DEFAULT_VHOST=my_vhost
- RABBITMQ_DEFAULT_USER=admin
- RABBITMQ_DEFAULT_PASS=shhy123#
volumes:
- ./rabbitmq/data:/var/lib/rabbitmq:rw
- ./rabbitmq/logs:/var/log/rabbitmq:rw
ports:
- "4369:4369"
- "5672:5672"
- "15672:15672"
- "25672:25672"
cap_add:
- CAP_SYS_NICE
networks:
- internal-net
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "ping"]
interval: 10s
timeout: 5s
retries: 3
es:
image: ${IMAGE_PREFIX}/elasticsearch:8.17.2
container_name: es
restart: always
hostname: es
environment:
- "ES_JAVA_OPTS=-Xms2048m -Xmx2048m"
- "discovery.type=single-node"
- "cluster.name=elasticsearch-spc"
- "ELASTIC_PASSWORD=shhy123#"
- "TAKE_FILE_OWNERSHIP=true"
- TZ=Asia/Shanghai
volumes:
- ./es-kibana/es/master/conf/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro
- ./es-kibana/es/master/data:/usr/share/elasticsearch/data:rw
- ./es-kibana/es/master/logs:/usr/share/elasticsearch/logs:rw
- ./es-kibana/es/master/plugins:/usr/share/elasticsearch/plugins:rw
ports:
- "9200:9200"
- "9300:9300"
networks:
- internal-net
healthcheck:
test: ["CMD", "curl", "-s", "-u", "elastic:\$\$ELASTIC_PASSWORD", "http://localhost:9200/_cluster/health"]
interval: 15s
timeout: 10s
retries: 3
kibana:
image: ${IMAGE_PREFIX}/kibana:8.17.2
container_name: kibana
restart: always
hostname: kibana
environment:
- TZ=Asia/Shanghai
- "elasticsearch.hosts=http://es:9200"
- "elasticsearch.username=kibana_system"
- "elasticsearch.password=shhy123#"
- "NODE_OPTIONS=--openssl-legacy-provider=false"
volumes:
- ./es-kibana/kibana/kibana.yml:/usr/share/kibana/config/kibana.yml:ro
ports:
- "5601:5601"
networks:
- internal-net
depends_on:
- es
healthcheck:
test: ["CMD", "curl", "-s", "http://localhost:5601/api/status"]
interval: 15s
timeout: 10s
retries: 3
mongodb:
image: ${IMAGE_PREFIX}/mongo:8.0.3
container_name: mongodb
restart: always
hostname: mongodb
environment:
- TZ=Asia/Shanghai
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=shhy123#
volumes:
- ./mongodb/data:/data/db:rw
- ./mongodb/logs:/var/log/mongodb:rw
ports:
- "27017:27017"
networks:
- internal-net
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')", "-u", "admin", "-p", "shhy123#", "--authenticationDatabase", "admin"]
interval: 10s
timeout: 5s
retries: 3
influxdb:
image: ${IMAGE_PREFIX}/influxdb:2.7.10
container_name: influxdb
restart: always
hostname: influxdb
environment:
- TZ=Asia/Shanghai
- DOCKER_INFLUXDB_INIT_MODE=setup
- DOCKER_INFLUXDB_INIT_USERNAME=admin
- DOCKER_INFLUXDB_INIT_PASSWORD=shhy123#
- DOCKER_INFLUXDB_INIT_ORG=my_org
- DOCKER_INFLUXDB_INIT_BUCKET=default_bucket
- DOCKER_INFLUXDB_INIT_RETENTION=30d
- DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=my_secret_token_123
volumes:
- ./influxdb/data:/var/lib/influxdb2:rw
- ./influxdb/config:/etc/influxdb2:rw
- ./influxdb/logs:/var/log/influxdb2:rw
ports:
- "8086:8086"
networks:
- internal-net
healthcheck:
test: ["CMD", "curl", "-s", "-o", "/dev/null", "http://localhost:8086/health"]
interval: 10s
timeout: 5s
retries: 3
emqx:
image: ${IMAGE_PREFIX}/emqx/emqx:5.8.8
container_name: emqx
restart: always
hostname: emqx
environment:
- TZ=Asia/Shanghai
- EMQX_NODE_NAME=emqx@127.0.0.1
- EMQX_CLUSTER__DISCOVERY_STRATEGY=static
- EMQX_LISTENER_TCP_DEFAULT_BIND=0.0.0.0:1883
- EMQX_LISTENER_WS_DEFAULT_BIND=0.0.0.0:8083
- EMQX_LOG_LEVEL=info
- EMQX_LOG_CONSOLE_ENABLE=true
- EMQX_NODE_PROCESS_LIMIT=2097152
- EMQX_NODE_MAX_PORTS=1048576
- EMQX_NODE_COOKIE=emqx_secret_cookie_123
volumes:
- ./emqx/data:/opt/emqx/data:rw
- ./emqx/log:/opt/emqx/log:rw
- /etc/localtime:/etc/localtime:ro
ports:
- "1883:1883"
- "8083:8083"
- "8084:8084"
- "8883:8883"
- "18083:18083"
networks:
- internal-net
healthcheck:
test: ["CMD", "/opt/emqx/bin/emqx", "ctl", "status"]
interval: 20s
timeout: 25s
retries: 10
start_period: 60s
deploy:
resources:
limits:
cpus: '1'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
sqlserver:
image: ${IMAGE_PREFIX}/mssql/server:2022-latest
container_name: sqlserver2022
restart: always
hostname: sqlserver
environment:
- TZ=Asia/Shanghai
- ACCEPT_EULA=Y
- SA_PASSWORD=shhy123#
- MSSQL_PID=Express
volumes:
- ./sqlserver/data:/var/opt/mssql:rw
- ./sqlserver/logs:/var/log/mssql:rw
- ./sqlserver/backup:/var/opt/mssql/backup:rw
- /etc/localtime:/etc/localtime:ro
ports:
- "1433:1433"
networks:
- internal-net
healthcheck:
test: ["CMD-SHELL", "pidof sqlservr"]
interval: 15s
timeout: 10s
retries: 5
start_period: 40s
EOF
# ===================== 【核心】权限配置 =====================
echo "5. 配置服务权限..."
sudo chown -R 999:999 ./redis/data ./redis/logs
sudo chmod -R 755 ./redis
sudo chmod -R 777 ./redis/logs
sudo chown -R 999:999 ./rabbitmq/data ./rabbitmq/logs
sudo chmod -R 755 ./rabbitmq
sudo chmod -R 700 ./rabbitmq/data
sudo chmod -R 777 ./rabbitmq/logs
sudo chown -R 999:999 ./mongodb/data ./mongodb/logs
sudo chmod -R 755 ./mongodb
sudo chmod -R 777 ./mongodb/logs
sudo chown -R 1000:1000 ./es-kibana/es/master/data ./es-kibana/es/master/logs ./es-kibana/es/master/plugins
sudo chmod -R 755 ./es-kibana
sudo chmod -R 777 ./es-kibana/es/master/logs
sudo chown -R 1000:1000 ./influxdb/data ./influxdb/config ./influxdb/logs
sudo chmod -R 755 ./influxdb
sudo chmod -R 777 ./influxdb/logs
sudo chown -R 1000:1000 ./emqx/data ./emqx/log
sudo chmod -R 755 ./emqx
sudo chmod -R 700 ./emqx/data
sudo chmod -R 777 ./emqx/log
# SQL Server 目录权限(新增backup备份目录)
sudo chown -R 10001:10001 ./sqlserver/data ./sqlserver/logs ./sqlserver/backup
sudo chmod -R 770 ./sqlserver
sudo chmod -R 777 ./sqlserver/logs ./sqlserver/backup
# ====================================================================================
# 登录私有仓库
echo "6. 登录私有镜像仓库..."
sudo docker login ${REGISTRY}
# ========== 前置:先手动创建全局共享网络 internal-net ==========
echo "7. 检查并创建全局共享网络 internal-net"
if ! docker network inspect internal-net >/dev/null 2>&1; then
docker network create internal-net
echo "✅ 全局网络 internal-net 创建完成"
else
echo "✅ 全局网络 internal-net 已存在,跳过创建"
fi
# ==============================================================
# 拉取镜像
echo "8. 拉取服务镜像..."
sudo docker compose pull
# 启动服务
echo "9. 启动所有服务..."
sudo docker compose up -d
# 设置Kibana密码
echo "10. 等待ES启动完成(100秒)..."
sleep 100
echo "11. 设置Kibana密码..."
echo "y" | docker exec -i es /usr/share/elasticsearch/bin/elasticsearch-reset-password -u kibana_system -i -b << EOF
shhy123#
shhy123#
EOF
echo "✅ Kibana密码已成功设置为: shhy123#"
# 强制创建 / 虚拟主机
echo "12. 等待rabbitmq启动完成(100秒)..."
sleep 100
echo "创建虚拟主机 / ..."
docker exec rabbitmq rabbitmqctl add_vhost / 2>/dev/null || true
echo "13. 开始创建RabbitMQ用户 spcmq 密码 123456,并赋予 management 权限..."
docker exec rabbitmq rabbitmqctl add_user spcmq 123456 2>/dev/null || true
docker exec rabbitmq rabbitmqctl set_user_tags spcmq management
docker exec rabbitmq rabbitmqctl set_permissions -p / spcmq ".*" ".*" ".*"
echo "✅ RabbitMQ 虚拟主机 / + 用户 spcmq 配置完成"
# 等待SQL Server就绪提示
echo "14. 等待SQL Server启动完成(60秒)..."
sleep 60
echo "✅ SQL Server 2022 部署完成,账号:sa / 密码:shhy123#"
echo "✅ 备份文件存放路径:宿主机 ./sqlserver/backup 容器内 /var/opt/mssql/backup"
echo "============================================="
echo " 部署完成!🎉 "
echo " 所有服务权限已按规范配置完成"
echo " RabbitMQ 新增用户:spcmq / 123456 (management)"
echo " RabbitMQ 虚拟主机:/"
echo " SQL Server 账号:sa / 密码:shhy123# 端口:1433"
echo " SQL Server 备份目录:./sqlserver/backup"
echo " 查看状态:docker compose ps"
echo "============================================="
# 自动删除脚本自身
rm -f -- "$0"
五、部署执行步骤
**1.**赋予执行权限
|-----------------------------|
| bash chmod +x deploy-all.sh |
**2.**一键执行部署
|----------------------|
| bash ./deploy-all.sh |
六、所有服务账号密码清单(统一整理)
Redis
密码:shhy123#
RabbitMQ
默认管理员:admin / shhy123#
业务用户:spcmq / 123456
虚拟主机:/、my_vhost
Elasticsearch
超级管理员:elastic / shhy123#
Kibana系统用户:kibana_system / shhy123#
MongoDB
账号:admin / shhy123#
InfluxDB
账号:admin / shhy123#
SQL Server 2022
账号:sa / shhy123#
备份目录:宿主机 /home/appInfrastructure/sqlserver/backup
七、常用运维命令
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| bash # 查看所有服务状态 docker compose ps # 重启全部服务 docker compose restart # 停止所有服务(保留数据) docker compose down # 彻底销毁重建(数据保留) docker compose down && docker compose up -d # 查看某服务日志 docker logs -f sqlserver2022 |
八、总结
本脚本是生产级的全套中间件部署方案:
- 全自动无人值守部署
- 精准适配各容器UID权限,彻底杜绝权限报错
- 自动初始化账号、虚拟主机、密码、配置
- 部署完成自销毁,服务器环境干净
可直接用于:项目初始化、测试环境、预生产环境、物联网平台、数据中台、微服务基础设施搭建。