Skip to content

前置知识 ​

安装orbstack ​

orbstack是一个在MacOS上新起的Docker方案,它采用了与docker-linux不同的上下文,安装使用linux虚拟机非常方便

但缺点在于dockerhub与docker desktop强绑定,如果需要将镜像上传到dockerhub上,还是使用docker desktop吧。

安装CentOS ​

查看Linux防火墙 ​

查看防火墙状态:systemctl status firewalld

开启防火墙:systemctl start firewalld

关闭防火墙:systemctl stop firewalld

开启防火墙:service firewalld start

开机禁止启动防火墙:systemctl disable firewalld.service

开机允许启动防火墙:systemctl unmask firewalld.service、systemctl start firewalld.service

设置某个服务开机自启动:systemctl enable [...]

查看Linux端口是否对外开放 ​

1、查询已经对外开放的端口:netstat -anp

2、查看防火墙所有开放的端口:firewall-cmd --zone=public --list-ports

3、查询指定端口是否已经开放:firewall-cmd --query-port=8848/tcp

返回yes/no。此时也有可能返回firewalld is not running,此时需要打开防火墙在开放端口。

开放Linux某个端口 ​

添加指定需要开放的端口:firewall-cmd --add-port=8848/tcp --permanent

重载入添加的端口,配置立即生效:firewall-cmd --reload

查询指定端口是否开启成功:firewall-cmd --query-port=8848/tcp

解决Windows端口占用 ​

查看占用端口的进程号

shell
netstat -ano | findstr '被占用的端口号'

根据进程号杀掉占用的进程

shell
taskkill /F /PID '进程号'

Docker 端口暴露安全防护规范 ​

Docker 绝大多数安全风险源于配置不规范。

Docker 安全核心:零公网裸曝、权限最小化、资源可信化。严格执行即可覆盖绝大多数生产安全风险。

本文总结三条生产环境核心防护标准,规避未授权访问、容器逃逸、服务器沦陷风险。

禁止端口裸曝公网 ​

命令中最好不要写 -H tcp://0.0.0.0:2375

最佳实践:常规环境仅保留本地 Socket 访问,关闭外网监听。特殊运维需开放端口时,强制配置 IP 白名单 + TLS 认证。

最小权限运行,禁用特权容器 ​

命令中最好不要写 --privileged ,特权模式会击穿容器隔离,造成高危逃逸漏洞。

最佳实践:统一以 --user 低权限用户启动容器,生产环境严禁使用特权参数。

版本与镜像可信管控 ​

旧版 Docker 存在已知漏洞,非可信镜像普遍携带后门、木马程序。

最佳实践:保持 Docker 为最新稳定版;业务镜像仅使用官方及权威厂商源,杜绝不明镜像。

Docker使用相关命令 ​

安装Docker ​

  1. 卸载系统之前的 docker

    shell
    sudo yum remove docker \
    docker-client \
    docker-client-latest \
    docker-common \
    docker-latest \
    docker-latest-logrotate \
    docker-logrotate \
    docker-engine
  2. 安装 Docker-CE

    安装必须的依赖

    shell
    sudo yum install -y yum-utils \
    device-mapper-persistent-data \
    lvm2

    设置 docker repo 的 yum 位置

    shell
    sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

    安装 docker,以及 docker-cli

    shell
    sudo yum install docker-ce docker-ce-cli containerd.io
  3. 启动Docker

    shell
    sudo systemctl start docker
  4. 设置Docker开机自启

    shell
    sudo systemctl enable docker
  5. 配置镜像加速(Ubuntu、CentOS)

    shell
    sudo mkdir -p /etc/docker
    sudo tee /etc/docker/daemon.json <<-'EOF'
    {
        "registry-mirrors": [
            "https://uf5mphyd.mirror.aliyuncs.com",
            "https://dockerproxy.com",
            "https://mirror.baidubce.com",
            "https://docker.m.daocloud.io",
            "https://docker.nju.edu.cn",
            "https://docker.mirrors.sjtug.sjtu.edu.cn"
        ]
    }
    EOF
    sudo systemctl daemon-reload
    sudo systemctl restart docker

    Docker终极配置

    shell
    {  
      "builder": {    
      "gc": {      
        "defaultKeepStorage": "20GB",      
        "enabled": true    
        }  
      },  
      "experimental": false,  
      "registry-mirrors": [    
        "https://docker.hpcloud.cloud",    
        "https://docker.m.daocloud.io",    
        "https://docker.unsee.tech",    
        "https://docker.1panel.live",    
        "http://mirrors.ustc.edu.cn",    
        "https://docker.chenby.cn",    
        "http://mirror.azure.cn",    
        "https://dockerpull.org",    
        "https://dockerhub.icu",    
        "https://hub.rat.dev"  
      ]
    }
  6. Docker中文文档

    [docker 中文文档](docker 中文文档 | 简果网 (simapple.com))

    docker中文文档 (菜鸟笔记)

常用命令 ​

镜像 ​

拉取镜像

shell
docker pull [image]:[version]

查看已下载的镜像

shell
docker images

查看镜像详情

shell
docker inspect [IMAGE_ID]

删除镜像

shell
docker rmi [image]

加载镜像

shell
docker load -i [saved_image].tar

保存镜像

shell
docker save -o [saved_image].tar [image]:[version]

推送镜像

shell
docker push

构建镜像

shell
docker build -f Dockerfile --platform linux/arm64 -t axiom-ml:1.0.0 .
shell
docker build -f Dockerfile --platform linux/amd64 -t axiom-ml:1.0.0 .
shell
shell
docker build \
  -t axiom-ml:1.0.0 \
  -f Dockerfile \
  --build-arg ENVIRONMENT=prod \
  --platform linux/amd64 \
  --progress=plain \
  --no-cache \
  .
参数作用
-t, --tag指定镜像名和版本,例如 my-app:1.0.0
-f, --file指定 Dockerfile,例如 -f Dockerfile.prod
--build-arg给 Dockerfile 的 ARG 传参
--no-cache不使用构建缓存,全部重建
--pull构建前尝试拉取最新基础镜像
--platform指定目标平台,如 linux/amd64
--target多阶段构建时指定目标阶段
--progress=plain输出完整构建日志,排错很好用
-q, --quiet静默构建,只输出最终结果
--network指定构建阶段的网络模式

清理构建的缓存:

查看当前构建缓存占用

shell
docker system df
docker system df -v

清理无用的构建缓存

shell
docker builder prune

清理所有未使用的构建缓存,不仅删除 dangling cache,还删除所有当前没有被使用的构建缓存

shell
docker builder prune -a

容器 ​

第一次运行容器时,运行以下命令构建容器

shell
docker run \
-p [port_linux]:[port_container]  \
--name [container_name] \
-v [uri_linux]:[uri_container] \
-v [volume]:[uri_container] \
-d \
[image]:[version] \
...

启动容器

shell
docker start [container]

重启容器

shell
docker restart [container]

停止容器

shell
docker stop [container]

强制停止容器

shell
docker kill [container]

删除容器

shell
docker rm (-f) [container]

暂停容器

shell
docker pause [container]

恢复容器

shell
docker unpause [container]

查看容器的详情

shell
docker inspect [container]

查看正在运行的(所有)容器

shell
docker ps (-a)

查看容器的日志(跟随刷新)

shell
docker logs [container] (-f)

容器内部 ​

在容器中执行命令

shell
docker exec [...]

进入容器文件系统

shell
docker exec -it [container] /bin/bash
docker exec -it [container] bash

查看容器的端口映射

shell
docker port [container]

image-20230725224300588

  • port/tcp 表示容器内部的端口号和协议类型;
  • 0.0.0.0:port1->port2/tcp 表示将主机的port1端口映射到容器内部的port2端口,0.0.0.0表示监听所有的网络接口,:::表示监听所有的IPv6网络接口。

设置容器的自动启动

shell
sudo docker update [container] --restart=always

数据卷 ​

创建数据卷

shell
docker volume create [volume]

查看所有数据卷

shell
docker volume ls

查看数据卷的详情

shell
docker volume inspect [volume]

删除数据卷

shell
docker volume rm [volume]

删除未使用的数据卷

shell
docker volume prune [volume]

Compose命令 ​

后台启动

shell
docker compose -f docker-compose.yml up -d

up:创建并启动 compose 文件里的服务

-d:后台运行,detached mode

重新构建后启动

shell
docker compose up -d --build

适合改了 Dockerfile 或源码镜像需要重新构建的时候

停止容器

shell
docker compose -f docker-compose.yml stop

停止并删除容器、网络

shell
docker compose -f docker-compose.yml down

停止并删除容器、网络、数据卷(慎用)

shell
docker compose -f docker-compose.yml down -v

重启服务

shell
docker compose -f docker-compose.yml restart (服务名)

查看服务状态

shell
docker compose -f docker-compose.yml ps

查看日志

shell
docker compose -f docker-compose.yml log --tail=100 -f (服务名)

构建自定义镜像 ​

shell
docker build -t [image]:[version] ./[uri_dockerfile]

uri_dockerfile目录下必须包含"DockerFile"和"Dockerfile中需要的文件"

部署微服务集群 ​

在docker-compose.yml中配置好

shell
docker-compose up -d

管理镜像 ​

云服务 ​

这里用阿里云演示一下:

  • 在云服务里搜索ACR
  • 启用个人版实例
  • 创建仓库

接下来跟着官方的操作指南走:

1. 终端登录阿里云 Container Registry

shell
docker login --username=01Peatd crpi-a6ogksurcntjl4t0.cn-hangzhou.personal.cr.aliyuncs.com

2. 将镜像推送到Registry

shell
docker tag [ImageId] crpi-a6ogksurcntjl4t0.cn-hangzhou.personal.cr.aliyuncs.com/01petard/print-service:1.1-arm64
shell
docker push crpi-a6ogksurcntjl4t0.cn-hangzhou.personal.cr.aliyuncs.com/01petard/print-service:1.1-arm64

3. 从Registry中拉取镜像

shell
$ docker pull crpi-a6ogksurcntjl4t0.cn-hangzhou.personal.cr.aliyuncs.com/01petard/print-service:[镜像版本号]

本地化部署 ​

TODO

容器快速部署命令速查 ​

部署Portainer ​

Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。

拉取Portainer镜像

英文版:

shell
docker pull portainer/portainer-ce

汉化版

shell
docker pull 6053537/portainer-ce

创建实例并启动

shell
docker run -d --restart=always --name=portainer -p 9:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data 6053537/portainer-ce

Portainer的默认账号和密码是:admin/admin,第一次进入需要创建用户,同时会提示你修改密码

部署MySQL 5.7 ​

下载mysql5.7镜像文件

shell
docker pull mysql:5.7

创建实例并启动

(Mysql5.7)(存在问题,暂未解决)

shell
docker run \
-p 3306:3306 \
--name mysql \
--restart=always \
-v /mydata/mysql/conf:/etc/mysql/conf.d \
-v /mydata/mysql/data:/var/lib/mysql \
-v /mydata/mysql/log:/var/log/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7

参数说明: -p 3306:3306:将容器的 3306 端口映射到主机的 3306 端口 -v /mydata/mysql/conf:/etc/mysql:将配置文件夹挂载到主机 -v /mydata/mysql/log:/var/log/mysql:将日志文件夹挂载到主机 -v /mydata/mysql/data:/var/lib/mysql/:将配置文件夹挂载到主机 -e MYSQL_ROOT_PASSWORD=root:初始化 root 用户的密码

配置mysql

shell
vi /mydata/mysql/conf/my.cnf

适合Mysql5.7

shell
[mysqld]
skip-grant-tables
user=mysql
character-set-server=utf8
default_authentication_plugin=mysql_native_password
secure_file_priv=/var/lib/mysql
expire_logs_days=7
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
max_connections=1000

init_connect='SET collation_connection = utf8_unicode_ci' init_connect='SET NAMES utf8' character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve

[client]
default-character-set=utf8

[mysql]
default-character-set=utf8

进入容器的mysql命令行

shell
docker exec -it mysql mysql -uroot -proot

设置远程访问

shell
grant all privileges on *.* to 'root'@'%' identified by 'root' with grant option;
flush privileges;

部署MySQL 8 ​

shell
docker run \
  -p 3306:3306 \
  --privileged=true \
  --name mysql8 \
  --restart=always \
  -v ~/mydata/mysql8/conf:/etc/mysql/conf.d \
  -v ~/mydata/mysql8/data:/var/lib/mysql \
  -v ~/mydata/mysql8/log:/var/log/mysql \
  -e MYSQL_ROOT_PASSWORD=root \
  -d mysql:latest

参数说明: -p 3306:3306:将容器的 3306 端口映射到主机的 3306 端口 -v /mydata/mysql/conf:/etc/mysql:将配置文件夹挂载到主机 -v /mydata/mysql/log:/var/log/mysql:将日志文件夹挂载到主机 -v /mydata/mysql/data:/var/lib/mysql/:将配置文件夹挂载到主机 -e MYSQL_ROOT_PASSWORD=root:初始化 root 用户的密码

配置mysql

shell
vi /mydata/mysql/conf/my.cnf

适合Mysql8

shell
[mysqld]
skip-grant-tables
user=mysql
character-set-server=utf8
default_authentication_plugin=mysql_native_password
secure_file_priv=/var/lib/mysql
expire_logs_days=7
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
max_connections=1000
 
[client]
default-character-set=utf8
 
[mysql]
default-character-set=utf8

进入容器的mysql命令行

shell
docker exec -it mysql mysql -uroot -proot

设置远程访问

shell
grant all privileges on *.* to 'root'@'%' identified by 'root' with grant option;
flush privileges;

部署MySQL 8(通用) ​

shell
docker pull mysql
shell
docker volume create data_mysql
shell
docker run --name mysql \
-v data_mysql:/var/lib/mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql
shell
docker run \
  --name mysql \
  --restart unless-stopped \
  -v my_mysql_data:/var/lib/mysql \
  -p 3306:3306 \
  -d mysql:8.0.32

部署PostGreSQL ​

shell
docker pull postgres:17
shell
docker run -d \
  --name postgres-17 \
  -e POSTGRES_USER=postgres \
  -e POSTGRES_PASSWORD=app_password \
  -e POSTGRES_DB=init_db \
  -p 5432:5432 \
  -v pg-data:/var/lib/postgresql/data \
  postgres:17

部署PgVector ​

PgVector是一款基于PostgreSQL的扩展插件,虽然在连接作为数据库时与PostgreSQL、MySQL看起来一样,但它和PostgreSQL其实并不是同一个东西,在开发时所采用的ORM框架也不同,因此可以将其单独作为一种数据库列出来。

xfg版:

shell
docker pull registry.cn-hangzhou.aliyuncs.com/xfg-studio/pgvector:v0.5.0
shell
docker run -d \
  --name vector_db \
  -e POSTGRES_USER=root \
  -e POSTGRES_PASSWORD=kjiolluy711 \
  -e POSTGRES_DB=ai-rag-knowledge \
  -e PGPASSWORD=kjiolluy711 \
  -v $(pwd)/pgvector/sql/init.sql:/docker-entrypoint-initdb.d/init.sql \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  -p 5432:5432 \
  --health-cmd="pg_isready -U root -d ai-rag-knowledge" \
  --health-interval=2s \
  --health-timeout=20s \
  --health-retries=10 \
  registry.cn-hangzhou.aliyuncs.com/xfg-studio/pgvector:v0.5.0
shell
docker run -d \
  --name vector_db \
  -e POSTGRES_USER=postgres \
  -e POSTGRES_PASSWORD=app_password \
  -e POSTGRES_DB=ai-rag-knowledge \
  -e PGPASSWORD=app_password \
  -v $(pwd)/pgvector/sql/init.sql:/docker-entrypoint-initdb.d/init.sql \
  -p 5432:5432 \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  --health-cmd "pg_isready -U postgres -d ai-rag-knowledge" \
  --health-interval=2s \
  --health-timeout=20s \
  --health-retries=10 \
  registry.cn-hangzhou.aliyuncs.com/xfg-studio/pgvector:v0.5.0

这个有点复杂了,我不太建议


“舒适”版:pg16 + pgvector 0.8.2(之所以舒适,是因为这个镜像自动适配linux/amd64 / linux/arm64)

shell
docker run -d \
  --name pgvector \
  -p 5532:5432 \
  -e POSTGRES_DB=axiom_platform_suite \
  -e POSTGRES_USER=pguser_H2o2D1 \
  -e POSTGRES_PASSWORD=PgVector_9sK27pR2 \
  -v pgvector-data:/var/lib/postgresql/data \
  pgvector/pgvector:pg16

docker run -d \
  --name pgvector-test \
  -p 15532:5432 \
  -e POSTGRES_DB=axiom_platform_suite \
  -e POSTGRES_USER=pguser_O9sM2c \
  -e POSTGRES_PASSWORD=PgVector_Lk7Rt92 \
  -v pgvector-test-data:/var/lib/postgresql/data \
  pgvector/pgvector:pg16

官方版(推荐):

shell
docker run -d \
  --name postgres \
  --restart unless-stopped \
  -e POSTGRES_USER=postgres \
  -e POSTGRES_PASSWORD=app_password \
  -p 35432:5432 \
  -v pgvector-data:/var/lib/postgresql/data \
  pgvector/pgvector:0.8.6-pg17
shell
docker run -d \
  --name postgres-fabric \
  --restart unless-stopped \
  -e POSTGRES_USER=postgres \
  -e POSTGRES_PASSWORD=app_password \
  -p 35432:5432 \
  -v pgvector-fabric:/var/lib/postgresql/data \
  pgvector/pgvector:0.8.6-pg17

扩展验证

sql
CREATE EXTENSION IF NOT EXISTS vector;
SELECT extname, extversion FROM pg_extension WHERE extname='vector';

部署MongoDB ​

shell
docker pull mongo:8.0
shell
docker run -d \
  --name mongo-8 \
  -e MONGO_INITDB_ROOT_USERNAME=admin \
  -e MONGO_INITDB_ROOT_PASSWORD=app_password \
  -p 27017:27017 \
  -v mongodata:/data/db \
  --restart unless-stopped \
  mongo:8.0

Mongo的GUI工具可以用官方的MongoDB Compass

  • Project是投影,用于指定返回哪些字段;
  • Sort是排序字段,-1 是降序,1 是升序;
  • Collation用于处理多语言排序(如中文拼音排序),一般不需要修改
  • Skip / Limit 是分页,Skip: 跳过前 N 条记录(类似 offset),Limit: 返回最多 N 条记录(类似 limit);
  • Index Hint 是索引提示,指定用哪个索引执行查询

具体界面如下:

image-20260118003754323

部署Redis(入门) ​

下载最新的镜像

shell
docker pull redis

创建实例并启动

shell
mkdir -p /mydata/redis/conf
shell
touch /mydata/redis/conf/redis.conf
shell
docker run -p 6379:6379 --name redis --restart=always \
-v /mydata/redis/data:/data \
-v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf

参数说明: -p 6379:6379:将容器的 6379 端口映射到Linux机的 6379 端口 -v /mydata/redis/data:/data:将redis数据库挂载到主机 -v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf:将配置文件夹挂载到主机 -d redis redis-server /etc/redis/redis.conf:使用redis-server命令将使用配置运行

shell
mkdir -p /mydata/redis2/conf
touch /mydata/redis2/conf/redis.conf
docker run -p 6380:6379 --name redis2 -v /mydata/redis2/data:/data \
-v /mydata/redis2/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf

参数说明: -p 6380:6379:将容器的 6379 端口映射到Linux机的 6380 端口

shell
mkdir -p /mydata/redis3/conf
touch /mydata/redis3/conf/redis.conf
docker run -p 6381:6379 --name redis3 -v /mydata/redis3/data:/data \
-v /mydata/redis3/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf

使用redis镜像执行redis-cli命令连接

shell
docker exec -it redis redis-cli

或 进入部署的redis命令行

docker exec -it redis redis-cli

Redis配置文件需要修改的项

shell
# 注释掉这部分,不限制redis只能本地访问
bind 127.0.0.1
# 关闭保护模式,不限制为本地访问
protected-mode no
# (必改)是否开启守护线程,守护线程可后台运行,除非kill进程。改为yes会使配置文件方式启动redis失败!!
daemonize no


# 是否压缩,建议开启,否则rdb文件会变得巨大
rdbcompression yes
# (可选)RDB文件名称
dbfilename mydump.rdb
# (可选)数据库个数
databases 16
# rdb文件保存的路径目录
dir ./

# (可选)开启AOF持久化
appendonly yes
# AOF文件比上次文件增长超过多少百分比则出发重写,默认100%
auto-aof-rewrite-percentage 100
# AOF文件体积最小多大以上才触发重写,默认:64mb
auto-aof-rewrite-min-size 64mb

Redis持久化的RDB和AOF对比

RDBAOF
持久化方式定时对整个内存做快照记录每一次执行的命令
数据完整性不完整,两次备份之间会丢失相对完整,取决于刷盘策略
文件大小会有压缩,文件体积小记录命令,文件体积很大
宕机恢复速度很快慢
数据恢复优先级低,因为数据完整性不如AOF高,因为数据完整性更高
系统资源占用高,大量CPU和内存消耗低,主要占用磁盘IO资源,且重写时会占用大量CPU资源和内存资源
使用场景可以容忍数分钟的数据丢失,追求更快的启动速度对数据安全性要求较高

配置Redis(通用) ​

最小化部署,采用精简镜像

shell
docker run \
  --name redis \
  --restart unless-stopped \
  -v my_redis_data:/data \
  -p 6379:6379 \
  -d redis:8.4.4-alpine \
  redis-server \
  --appendonly yes \
  --requirepass app_password

配置Redis主从集群(2节点,1主1从) ​

1、用Docker部署好三台Redis

主机redis,ip地址:192.168.113.132:6379

从机redis2,ip地址:192.168.113.132:6380

从机redis3,ip地址:192.168.113.132:6381

image-20230907171409814

2 在从机上配置主机ip

进入redis2容器内部,配置主机ip

shell
docker exec -it redis2 bash
shell
redis-cli
shell
slaveof 192.168.113.132 6379
或
replicaof 192.168.113.132 6379

另一个从机重复以上步骤:

shell
docker exec -it redis3 bash
shell
redis-cli
shell
slaveof 192.168.113.132 6379
或
replicaof 192.168.113.132 6379

3、在主机上查看主从配置结果

shell
info replication

image-20230907172256490

至此,Redis主从配置就好了!比单独部署更方便!

4、 主从数据同步原理

全量同步的流程:

  • slave节点请求增量同步
  • master节点判断replid,发现不一致,拒绝增量同步
  • master将完整内存数据生成RDB,发送RDB到slave
  • slave清空本地数据,加载master的RDB
  • master将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave
  • slave执行接收到的命令,保持与master之间的同步

增量同步的流程:

master节点和slave节点中维护了一个环形数组(前文提到的repl_baklog)和一个指针为offset。

slave来申请增量同步,带着replid和offset,然后master根据获取offset之后的数据,将其发送给slave,slave进行同步。

  • 此时会出现一个问题,当slave下限太久时,master中存储的数据已经超过了这个repl_baklog的上线,因此就需要重新进行全量同步。

配置Redis主从集群(6节点,3主3从) ​

创建redis集群 ​

在Docker下安装单节点的Redis很简单,如果要创建redis cluster,并且要从外部访问,大概率会遇到一些麻烦。

img

Bitnami提供了一个redis-cluster镜像[1],我们可以使用下面的文件来创建一个3主3从的redis集群。

yaml
name: cluster
services:
  redis-node-0:
    image: docker.io/bitnami/redis-cluster:7.0
    volumes:
      - redis-cluster_data-0:/bitnami/redis/data
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
      - REDIS_PORT_NUMBER=7000
      - REDIS_NODES=redis-node-0:7000 redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 redis-node-4:7004 redis-node-5:7005
    ports:
      - 7000:7000
      # redis cluster bus port,默认使用 redis port + 10000
      - 17000:17000 

  redis-node-1:
    image: docker.io/bitnami/redis-cluster:7.0
    volumes:
      - redis-cluster_data-1:/bitnami/redis/data
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
      - REDIS_PORT_NUMBER=7001
      - REDIS_NODES=redis-node-0:7000 redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 redis-node-4:7004 redis-node-5:7005
    ports:
      - 7001:7001
      - 17001:17001

  redis-node-2:
    image: docker.io/bitnami/redis-cluster:7.0
    volumes:
      - redis-cluster_data-2:/bitnami/redis/data
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
      - REDIS_PORT_NUMBER=7002
      - REDIS_NODES=redis-node-0:7000 redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 redis-node-4:7004 redis-node-5:7005
    ports:
      - 7002:7002
      - 17002:17002

  redis-node-3:
    image: docker.io/bitnami/redis-cluster:7.0
    volumes:
      - redis-cluster_data-3:/bitnami/redis/data
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
      - REDIS_PORT_NUMBER=7003
      - REDIS_NODES=redis-node-0:7000 redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 redis-node-4:7004 redis-node-5:7005
    ports:
      - 7003:7003
      - 17003:17003

  redis-node-4:
    image: docker.io/bitnami/redis-cluster:7.0
    volumes:
      - redis-cluster_data-4:/bitnami/redis/data
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
      - REDIS_PORT_NUMBER=7004
      - REDIS_NODES=redis-node-0:7000 redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 redis-node-4:7004 redis-node-5:7005
    ports:
      - 7004:7004
      - 17004:17004

  redis-node-5:
    image: docker.io/bitnami/redis-cluster:7.0
    volumes:
      - redis-cluster_data-5:/bitnami/redis/data
    depends_on:
      - redis-node-0
      - redis-node-1
      - redis-node-2
      - redis-node-3
      - redis-node-4
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
      - REDIS_PORT_NUMBER=7005
      - REDIS_NODES=redis-node-0:7000 redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 redis-node-4:7004 redis-node-5:7005
      - REDIS_CLUSTER_REPLICAS=1
      - REDIS_CLUSTER_CREATOR=yes
    ports:
      - 7005:7005
      - 17005:17005
      
volumes:
  redis-cluster_data-0:
  redis-cluster_data-1:
  redis-cluster_data-2:
  redis-cluster_data-3:
  redis-cluster_data-4:
  redis-cluster_data-5:

问题 ​

这样创建的集群有一个问题,只能在容器内访问,无法在本机或者外部访问。

容器内访问:

bash
docker run -it --rm --network=cluster_default redis \
           redis-cli -h cluster-redis-node-0-1 -p 7000 -c

从本机访问会出错:

python
# pip3 install redis-py-cluster -i https://mirrors.aliyun.com/pypi/simple/
from rediscluster import RedisCluster as Redis
rc = Redis(host='localhost', port=7000, decode_responses=True, socket_timeout=1)
rc.set("a", "b") 
print(rc.get("a"))

错误提示:

rediscluster.exceptions.RedisClusterException: ERROR sending 'config get cluster-require-full-coverage' command to redis server:

我们可以看到,返回给客户端的IP地址是172.21.0.5,这个是容器的内部IP,本机无法访问。

img

原因 ​

Redis会自动探测IP,由于无法探测到宿主机的IP,因此返回给客户端是docker的内部IP。

img

在Redis的官网文档中给出了解释[2]:Redis Cluster不支持NAT(网络地址转发),也就无法使用Docker进行端口映射。如果要使用Docker,需要使用host网络模式,这种模式直接使用主机的网络命名空间,不需要转发。

很不幸,host模式只能在linux下使用,在windows下和Mac使用Docker Desktop是不支持host网络的[3]。

img

解决方案 ​

从Redis 4.0[4]开始,加入的对NAT和Docker的支持。

在redis.conf文件中,通过配置cluster-announce-ip、cluster-announce-port和cluster-announce-bus-port这三个属性来公布可以外部访问的IP(例如主机IP或公网IP)和端口。

这种方式类似于kafka中的advertised.listeners。

这样子,redis返回给客户端的IP地址就是cluster-announce-ip ,而不再是自动探测到的容器内部IP。

plain
########################## CLUSTER DOCKER/NAT support  ########################

# In certain deployments, Redis Cluster nodes address discovery fails, because
# addresses are NAT-ted or because ports are forwarded (the typical case is
# Docker and other containers).
#
# In order to make Redis Cluster working in such environments, a static
# configuration where each node knows its public address is needed. The
# following four options are used for this scope, and are:
#
# * cluster-announce-ip
# * cluster-announce-port
# * cluster-announce-tls-port
# * cluster-announce-bus-port
#
# Each instructs the node about its address, client ports (for connections
# without and with TLS) and cluster message bus port. The information is then
# published in the header of the bus packets so that other nodes will be able to
# correctly map the address of the node publishing the information.
#
# If cluster-tls is set to yes and cluster-announce-tls-port is omitted or set
# to zero, then cluster-announce-port refers to the TLS port. Note also that
# cluster-announce-tls-port has no effect if cluster-tls is set to no.
#
# If the above options are not used, the normal Redis Cluster auto-detection
# will be used instead.
#
# Note that when remapped, the bus port may not be at the fixed offset of
# clients port + 10000, so you can specify any port and bus-port depending
# on how they get remapped. If the bus-port is not set, a fixed offset of
# 10000 will be used as usual.
#
# Example:
#
# cluster-announce-ip 10.1.1.5
# cluster-announce-tls-port 6379
# cluster-announce-port 0
# cluster-announce-bus-port 6380

按照这个思路,修改后的docker-compose.yaml文件如下:

yaml
name: cluster
services:
  redis-node-0:
    image: docker.io/bitnami/redis-cluster:7.0
    volumes:
      - redis-cluster_data-0:/bitnami/redis/data
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
      - REDIS_PORT_NUMBER=7000
      - REDIS_CLUSTER_ANNOUNCE_PORT=7000
      - REDIS_CLUSTER_ANNOUNCE_IP=10.150.36.72 # 主机IP或公网IP,不要使用127.0.0.1或localhost
      - REDIS_CLUSTER_ANNOUNCE_BUS_PORT=17000
      - REDIS_CLUSTER_DYNAMIC_IPS=no
      - REDIS_NODES=redis-node-0:7000 redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 redis-node-4:7004 redis-node-5:7005
    ports:
      - 7000:7000
      - 17000:17000

  redis-node-1:
    image: docker.io/bitnami/redis-cluster:7.0
    volumes:
      - redis-cluster_data-1:/bitnami/redis/data
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
      - REDIS_PORT_NUMBER=7001
      - REDIS_CLUSTER_ANNOUNCE_PORT=7001
      - REDIS_CLUSTER_ANNOUNCE_BUS_PORT=17001
      - REDIS_CLUSTER_ANNOUNCE_IP=10.150.36.72
      - REDIS_CLUSTER_DYNAMIC_IPS=no
      - REDIS_NODES=redis-node-0:7000 redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 redis-node-4:7004 redis-node-5:7005
    ports:
      - 7001:7001
      - 17001:17001

  redis-node-2:
    image: docker.io/bitnami/redis-cluster:7.0
    volumes:
      - redis-cluster_data-2:/bitnami/redis/data
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
      - REDIS_PORT_NUMBER=7002
      - REDIS_CLUSTER_ANNOUNCE_PORT=7002
      - REDIS_CLUSTER_ANNOUNCE_BUS_PORT=17002
      - REDIS_CLUSTER_ANNOUNCE_IP=10.150.36.72
      - REDIS_CLUSTER_DYNAMIC_IPS=no
      - REDIS_NODES=redis-node-0:7000 redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 redis-node-4:7004 redis-node-5:7005
    ports:
      - 7002:7002
      - 17002:17002

  redis-node-3:
    image: docker.io/bitnami/redis-cluster:7.0
    volumes:
      - redis-cluster_data-3:/bitnami/redis/data
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
      - REDIS_PORT_NUMBER=7003
      - REDIS_CLUSTER_ANNOUNCE_PORT=7003
      - REDIS_CLUSTER_ANNOUNCE_BUS_PORT=17003
      - REDIS_CLUSTER_ANNOUNCE_IP=10.150.36.72
      - REDIS_CLUSTER_DYNAMIC_IPS=no
      - REDIS_NODES=redis-node-0:7000 redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 redis-node-4:7004 redis-node-5:7005
    ports:
      - 7003:7003
      - 17003:17003

  redis-node-4:
    image: docker.io/bitnami/redis-cluster:7.0
    volumes:
      - redis-cluster_data-4:/bitnami/redis/data
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
      - REDIS_PORT_NUMBER=7004
      - REDIS_CLUSTER_ANNOUNCE_PORT=7004
      - REDIS_CLUSTER_ANNOUNCE_BUS_PORT=17004
      - REDIS_CLUSTER_ANNOUNCE_IP=10.150.36.72
      - REDIS_CLUSTER_DYNAMIC_IPS=no
      - REDIS_NODES=redis-node-0:7000 redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 redis-node-4:7004 redis-node-5:7005
    ports:
      - 7004:7004
      - 17004:17004

  redis-node-5:
    image: docker.io/bitnami/redis-cluster:7.0
    volumes:
      - redis-cluster_data-5:/bitnami/redis/data
    depends_on:
      - redis-node-0
      - redis-node-1
      - redis-node-2
      - redis-node-3
      - redis-node-4
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
      - REDIS_CLUSTER_REPLICAS=1
      - REDIS_PORT_NUMBER=7005
      - REDIS_CLUSTER_ANNOUNCE_PORT=7005
      - REDIS_CLUSTER_ANNOUNCE_BUS_PORT=17005
      - REDIS_CLUSTER_ANNOUNCE_IP=10.150.36.72
      - REDIS_CLUSTER_DYNAMIC_IPS=no
      - REDIS_NODES=redis-node-0:7000 redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 redis-node-4:7004 redis-node-5:7005
      - REDIS_CLUSTER_CREATOR=yes
    ports:
      - 7005:7005
      - 17005:17005

volumes:
  redis-cluster_data-0:
  redis-cluster_data-1:
  redis-cluster_data-2:
  redis-cluster_data-3:
  redis-cluster_data-4:
  redis-cluster_data-5:

注意:

  1. REDIS_CLUSTER_ANNOUNCE_IP不能使用127.0.0.1和localhost
  2. REDIS_CLUSTER_DYNAMIC_IPS必须设置为no[5],否则REDIS_CLUSTER_ANNOUNCE_IP不会生效

重新创建容器前,需要删除之前的卷(volumn),否则启动会报错。

bash
docker compose down && docker volume prune -f
docker compose up -d

这样,就可以从外部和本机访问redis cluster了。


参考文档:

[1] https://hub.docker.com/r/bitnami/redis-cluster

[2] https://redis.io/docs/management/scaling/

[3] https://docs.docker.com/network/host/

[4] https://raw.githubusercontent.com/antirez/redis/4.0/00-RELEASENOTES

[5] https://github.com/bitnami/containers/blob/main/bitnami/redis-cluster/7.0/debian-11/rootfs/opt/bitnami/scripts/librediscluster.sh#L83

[6] https://redis-py.readthedocs.io/en/stable/clustering.html

[7] https://github.com/bitnami/charts/tree/main/bitnami/redis-cluster

部署Redisearch(已过时) ​

Redisearch是一款基于Redis的向量化内存型数据库

shell
docker run -d \
  -p 6379:6379 \
  --name redissearch \
  --restart=unless-stopped \
  redislabs/redisearch

部署Redis-stack ​

redis-stack是redissearch的继任者

arm版

shell
docker pull redis/redis-stack:7.4.0-v8-arm64
shell
docker run -d \
  --name redis-stack \
  --restart=unless-stopped \
  -p 6379:6379 \
  -p 8001:8001 \
  -v redis-stack-data:/data \
  -e REDIS_ARGS="--appendonly yes --requirepass app_password" \
  redis/redis-stack:7.4.0-v8-arm64
shell
docker exec -it redis-stack redis-cli

x86版

shell
docker pull redis/redis-stack:7.4.0-v8-x86_64
shell
docker run -d \
  --name redis-stack \
  --restart=unless-stopped \
  -p 6379:6379 \
  -p 8001:8001 \
  -v redis-stack-data:/data \
  -e REDIS_ARGS="--appendonly yes --requirepass app_password" \
  redis/redis-stack:7.4.0-v8-x86_64

也可以用不带RedisInsight的版本:

shell
docker pull redis/redis-stack-server:7.4.0-v8-arm64
shell
docker run -d \
  --name redis-stack \
  --restart=unless-stopped \
  -p 6379:6379 \
  -v redis-stack-data:/data \
  -e REDIS_ARGS='--appendonly yes --requirepass app_password' \
  redis/redis-stack-server:7.4.0-v8-arm64
shell
docker pull redis/redis-stack-server:7.4.0-v8-x86_64
shell
docker run -d \
  --name redis-stack \
  --restart=unless-stopped \
  -p 6379:6379 \
  -v redis-stack-data:/data \
  -e REDIS_ARGS='--appendonly yes --requirepass app_password' \
  redis/redis-stack-server:7.4.0-v8-x86_64

进入容器

shell
docker exec -it redis-stack redis-cli
AUTH app_password

或

docker exec -it redis-stack redis-cli -a app_password

验证 Redis Stack 模块

shell
MODULE LIST

部署Nacos 2.x ​

2.x的nacos不需要身份验证,所以比较适合学习,但是生产应该用最新的3.x及以后。

MacOS部署nacos

shell
docker run -d \
  --name nacos-standalone \
  -e MODE=standalone \
  -p 8848:8848 \
  nacos/nacos-server:v2.5.1

也可以去nacos官网下载2.x的版本,然后用下面的命令使用

shell
cd ./nacos-server-2.5.1
# 启动
sh ./bin/startup.sh -m standalone
# 关闭
sh ./bin/shutdown.sh

之所以不用3.x是因为,nacos 3.0以后需要用token了,比较费事,自己学习太麻烦了

Windows部署nacos

下载nacos安装包:https://github.com/alibaba/nacos/releases

进入bin目录下运行如下命令,前台启动:

shell
startup.cmd -m standalone

Linux部署nacos

Linux下使用nacos的其实和MacOS是一样的,用容器即可,但这里介绍一种外部存储配置的方式来部署。

先远程连接服务器数据库,创建nacos数据库

sql
CREATE database if NOT EXISTS `nacos_config` default character set utf8mb4 collate utf8mb4_unicode_ci;
use `nacos_config`;
 
/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info   */
/******************************************/
CREATE TABLE `config_info` (
                              `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
                              `data_id` varchar(255) NOT NULL COMMENT 'data_id',
                              `group_id` varchar(255) DEFAULT NULL,
                              `content` longtext NOT NULL COMMENT 'content',
                              `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
                              `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
                              `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
                              `src_user` text COMMENT 'source user',
                              `src_ip` varchar(20) DEFAULT NULL COMMENT 'source ip',
                              `app_name` varchar(128) DEFAULT NULL,
                              `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
                              `c_desc` varchar(256) DEFAULT NULL,
                              `c_use` varchar(64) DEFAULT NULL,
                              `effect` varchar(64) DEFAULT NULL,
                              `type` varchar(64) DEFAULT NULL,
                              `c_schema` text,
                              PRIMARY KEY (`id`),
                              UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_aggr   */
/******************************************/
CREATE TABLE `config_info_aggr` (
                                   `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
                                   `data_id` varchar(255) NOT NULL COMMENT 'data_id',
                                   `group_id` varchar(255) NOT NULL COMMENT 'group_id',
                                   `datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
                                   `content` longtext NOT NULL COMMENT '内容',
                                   `gmt_modified` datetime NOT NULL COMMENT '修改时间',
                                   `app_name` varchar(128) DEFAULT NULL,
                                   `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
                                   PRIMARY KEY (`id`),
                                   UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';


/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_beta   */
/******************************************/
CREATE TABLE `config_info_beta` (
                                   `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
                                   `data_id` varchar(255) NOT NULL COMMENT 'data_id',
                                   `group_id` varchar(128) NOT NULL COMMENT 'group_id',
                                   `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
                                   `content` longtext NOT NULL COMMENT 'content',
                                   `beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
                                   `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
                                   `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
                                   `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
                                   `src_user` text COMMENT 'source user',
                                   `src_ip` varchar(20) DEFAULT NULL COMMENT 'source ip',
                                   `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
                                   PRIMARY KEY (`id`),
                                   UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_tag   */
/******************************************/
CREATE TABLE `config_info_tag` (
                                  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
                                  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
                                  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
                                  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
                                  `tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
                                  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
                                  `content` longtext NOT NULL COMMENT 'content',
                                  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
                                  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
                                  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
                                  `src_user` text COMMENT 'source user',
                                  `src_ip` varchar(20) DEFAULT NULL COMMENT 'source ip',
                                  PRIMARY KEY (`id`),
                                  UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_tags_relation   */
/******************************************/
CREATE TABLE `config_tags_relation` (
                                       `id` bigint(20) NOT NULL COMMENT 'id',
                                       `tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
                                       `tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
                                       `data_id` varchar(255) NOT NULL COMMENT 'data_id',
                                       `group_id` varchar(128) NOT NULL COMMENT 'group_id',
                                       `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
                                       `nid` bigint(20) NOT NULL AUTO_INCREMENT,
                                       PRIMARY KEY (`nid`),
                                       UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
                                       KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = group_capacity   */
/******************************************/
CREATE TABLE `group_capacity` (
                                 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
                                 `group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
                                 `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
                                 `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
                                 `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
                                 `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值',
                                 `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
                                 `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
                                 `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
                                 `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
                                 PRIMARY KEY (`id`),
                                 UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = his_config_info   */
/******************************************/
CREATE TABLE `his_config_info` (
                                  `id` bigint(64) unsigned NOT NULL,
                                  `nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
                                  `data_id` varchar(255) NOT NULL,
                                  `group_id` varchar(128) NOT NULL,
                                  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
                                  `content` longtext NOT NULL,
                                  `md5` varchar(32) DEFAULT NULL,
                                  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
                                  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
                                  `src_user` text,
                                  `src_ip` varchar(20) DEFAULT NULL,
                                  `op_type` char(10) DEFAULT NULL,
                                  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
                                  PRIMARY KEY (`nid`),
                                  KEY `idx_gmt_create` (`gmt_create`),
                                  KEY `idx_gmt_modified` (`gmt_modified`),
                                  KEY `idx_did` (`data_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';


/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = tenant_capacity   */
/******************************************/
CREATE TABLE `tenant_capacity` (
                                  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
                                  `tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
                                  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
                                  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
                                  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
                                  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',
                                  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
                                  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
                                  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
                                  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
                                  PRIMARY KEY (`id`),
                                  UNIQUE KEY `uk_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';


CREATE TABLE `tenant_info` (
                              `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
                              `kp` varchar(128) NOT NULL COMMENT 'kp',
                              `tenant_id` varchar(128) default '' COMMENT 'tenant_id',
                              `tenant_name` varchar(128) default '' COMMENT 'tenant_name',
                              `tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
                              `create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
                              `gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
                              `gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
                              PRIMARY KEY (`id`),
                              UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
                              KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';

CREATE TABLE `users` (
                        `username` varchar(50) NOT NULL PRIMARY KEY,
                        `password` varchar(500) NOT NULL,
                        `enabled` boolean NOT NULL
);

CREATE TABLE `roles` (
                        `username` varchar(50) NOT NULL,
                        `role` varchar(50) NOT NULL,
                        UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
);

CREATE TABLE `permissions` (
                              `role` varchar(50) NOT NULL,
                              `resource` varchar(255) NOT NULL,
                              `action` varchar(8) NOT NULL,
                              UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
);

INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);

INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');

拉取对应的镜像文件

shell
docker pull nacos/nacos-server

挂载目录

shell
mkdir -p /mydata/nacos/data/
mkdir -p /mydata/nacos/logs/
mkdir -p /mydata/nacos/init.d/

修改nacos配置文件

shell
vi /mydata/nacos/init.d/custom.properties
server.contextPath=/nacos
server.servlet.contextPath=/nacos
server.port=8848
 
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://localhost:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true #这里需要修改端口
db.user=root #用户名
db.password=root #密码
 
nacos.cmdb.dumpTaskInterval=3600
nacos.cmdb.eventTaskInterval=10
nacos.cmdb.labelTaskInterval=300
nacos.cmdb.loadDataAtStart=false
management.metrics.export.elastic.enabled=false
management.metrics.export.influx.enabled=false
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i
nacos.security.ignore.urls=/,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/v1/auth/login,/v1/console/health/**,/v1/cs/**,/v1/ns/**,/v1/cmdb/**,/actuator/**,/v1/console/server/**
nacos.naming.distro.taskDispatchThreadCount=1
nacos.naming.distro.taskDispatchPeriod=200
nacos.naming.distro.batchSyncKeyCount=1000
nacos.naming.distro.initDataRatio=0.9
nacos.naming.distro.syncRetryDelay=5000
nacos.naming.data.warmup=true
nacos.naming.expireInstance=true

启动nacos容器:

shell
docker run \
--name nacos -d \
-p 8848:8848 \
--privileged=true \
--restart=always \
-e JVM_XMS=256m -e JVM_XMX=256m \
-e MODE=standalone \
-e PREFER_HOST_MODE=hostname \
-v /mydata/nacos/nacos/data:/home/nacos/data \
-v /mydata/nacos/logs:/home/nacos/logs \
-v /mydata/nacos/init.d/custom.properties:/home/nacos/init.d/custom.properties \
nacos/nacos-server

(排错用)进入nacos容器编辑配置文件

docker exec -it nacos bash
cd conf
ll
vim application.properties

此时nacos容器就安装成功了可以打开浏览器进行登录:

shell
https://192.168.113.132:8848/nacos
账号:nacos
密码:nacos

最后设置nacos自启动:

shell
docker update --restart=always nacos

部署Nacos 3.2.2 ​

shell
docker run --name nacos-standalone \
 -e MODE=standalone \
 -e NACOS_AUTH_TOKEN=ZmxhZ3N5c3RlbTkyOWhhbmRzaG91NzQzN2RzODk0c2Y1Njc4OWRz \
 -e NACOS_AUTH_IDENTITY_KEY=nacos-2026-admin-inner-key \
 -e NACOS_AUTH_IDENTITY_VALUE=9sD7fG2pR5bN8vC3xJ6mT0kL1zQ4aS7dF2hJ5gN8bP0vC3xZ6mT1rS9 \
 -p 28080:8080 \
 -p 28848:8848 \
 -p 29848:9848 \
 -d nacos/nacos-server:v3.2.2

8080:Nacos 浏览器访问控制台

8848:Nacos HTTP 接口调试

9848:Nacos 微服务客户端 gRPC 通信

部署RabbitMQ ​

拉取镜像

shell
docker pull rabbitmq:4.1.2-management-alpine

或本地加载

shell
docker load -i mq.tar

启动MQ

-e RABBITMQ_DEFAULT_USER=rabbitmq \ 后台管理界面的用户名、密码 -e RABBITMQ_DEFAULT_PASS=rabbitmq
-p 15672:15672 \ 后台管理界面的端口 -p 5672:5672 \ 消息通信的端口

shell
sudo docker run \
 -e RABBITMQ_DEFAULT_USER=mq \
 -e RABBITMQ_DEFAULT_PASS=mq \
 --name mq \
 --hostname mq \
 -p 15672:15672 \
 -p 5672:5672 \
 -d rabbitmq:4.1.2-management-alpine

部署RocketMQ ​

以5.3.3版本为例,可根据需求更换版本

shell
sudo docker pull rocketmqinc/rocketmq

拉取RocketMQ控制台镜像,用于可视化管理,可选

shell
sudo docker pull styletang/rocketmq-console-ng

创建并启动 NameServer 容器

上述命令解释:

  • -d:以后台运行模式启动容器。
  • --name rmqnamesrv:为容器指定名称为rmqnamesrv。
  • -e "MAX_POSSIBLE_HEAP=100000000":设置 JVM 最大堆内存,可根据实际情况调整。
  • -p 9876:9876:将容器内的 9876 端口映射到宿主机的 9876 端口,方便外部访问。
  • sh mqnamesrv:在容器内执行启动 NameServer 的命令。
shell
sudo docker run -d \
--name rmqnamesrv \
-e "MAX_POSSIBLE_HEAP=100000000" \
-p 9876:9876 \
rocketmqinc/rocketmq sh mqnamesrv

创建并启动 Broker 容器

上述命令解释:

  • --link rmqnamesrv:namesrv:创建与rmqnamesrv容器的链接,并将其别名为namesrv,方便在 Broker 容器内通过别名访问 NameServer。
  • -e "NAMESRV_ADDR=namesrv:9876":设置 Broker 要连接的 NameServer 地址。
  • -p 10909:10909 -p 10911:10911:分别映射 Broker 的快速监听端口和监听端口到宿主机。
  • sh mqbroker -n namesrv:9876:在容器内执行启动 Broker 的命令,并指定 NameServer 地址。
shell
sudo docker run -d \
--name rmqbroker \
--link rmqnamesrv:namesrv \
-e "NAMESRV_ADDR=namesrv:9876" \
-e "MAX_POSSIBLE_HEAP=200000000" \
-p 10909:10909 \
-p 10911:10911 \
rocketmqinc/rocketmq sh mqbroker -n namesrv:9876

(可选)创建并启动 RocketMQ Dashboard 容器

上述命令解释:

  • -e "JAVA_OPTS=-Drocketmq.namesrv.addr=宿主机IP:9876 -Dcom.rocketmq.sendMessageWithVIPChannel=false":设置控制台连接的 NameServer 地址,宿主机IP需替换为实际运行 Docker 的主机 IP。
  • -p 8080:8080:将容器内的 8080 端口映射到宿主机的 8080 端口,通过浏览器访问http://宿主机IP:8080即可打开控制台。
shell
sudo docker run -d \
--name rmqconsole \
-e "JAVA_OPTS=-Drocketmq.namesrv.addr=localhost:9876 -Dcom.rocketmq.sendMessageWithVIPChannel=false" \
-p 8080:8080 \
styletang/rocketmq-console-ng

验证 RocketMQ 运行

  • 发送消息:进入 RocketMQ 镜像容器内部,执行发送消息命令。

    shell
    sudo docker exec -it rmqbroker sh
    cd /opt/rocketmq/bin
    ./tools.sh org.apache.rocketmq.example.quickstart.Producer
  • 接收消息:同样在容器内执行接收消息命令。

    shell
    ./tools.sh org.apache.rocketmq.example.quickstart.Consumer

关闭容器

shell
docker stop rmqnamesrv rmqbroker rmqconsole  # 停止所有相关容器,根据实际情况调整容器名称
docker rm rmqnamesrv rmqbroker rmqconsole  # 删除容器

部署Elasticsearch ​

es与mysql的概念名词对比

es与mysql对比

es的mapping属性解析

es的mapping属性解析

安装es(本地+在线) ​

本地安装

拉取/加载镜像

shell
docker load -i es.tar

运行docker命令,部署单点es:

命令解释:

- `-e "cluster.name=es-docker-cluster"`:设置集群名称
- `-e "http.host=0.0.0.0"`:监听的地址,可以外网访问
- `-e "ES_JAVA_OPTS=-Xms512m -Xmx512m"`:内存大小
- `-e "discovery.type=single-node"`:非集群模式
- `-v es-data:/usr/share/elasticsearch/data`:挂载逻辑卷,绑定es的数据目录
- `-v es-logs:/usr/share/elasticsearch/logs`:挂载逻辑卷,绑定es的日志目录
- `-v es-plugins:/usr/share/elasticsearch/plugins`:挂载逻辑卷,绑定es的插件目录
- `--privileged`:授予逻辑卷访问权
- `--network es-net` :加入一个名为es-net的网络中
- `-p 9200:9200`:暴露给http的端口
- `-p 9300:9300`:暴露给其他节点互联的端口
sh
docker run -d \
	--name es \
    -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
    -e "discovery.type=single-node" \
    -v es-data:/usr/share/elasticsearch/data \
    -v es-plugins:/usr/share/elasticsearch/plugins \
    -v es-logs:/usr/share/elasticsearch/logs \
    --privileged \
    --network es-net \
    -p 9200:9200 \
    -p 9300:9300 \
elasticsearch:7.12.1

在浏览器中输入:http://192.168.113.132:9200 即可看到elasticsearch的响应结果

在线安装

拉取镜像

shell
docker pull elasticsearch:7.4.0

创建容器

shell
docker run -id --name elasticsearch -d \
    --restart=always \
    -p 9200:9200 -p 9300:9300 \
    -v /usr/share/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
    -e "discovery.type=single-node" \
elasticsearch:7.4.0

配置IK分词器(与上文中的usr/share/elasticsearch/plugins保持一致)

shell
#切换目录
cd /usr/share/elasticsearch/plugins

#新建目录
mkdir analysis-ik
cd analysis-ik

#root根目录中拷贝文件
mv elasticsearch-analysis-ik-7.4.0.zip /usr/share/elasticsearch/plugins/analysis-ik

#解压文件
cd /usr/share/elasticsearch/plugins/analysis-ik
unzip elasticsearch-analysis-ik-7.4.0.zip

安装IK分词器(本地+在线) ​

在线安装

shell
# 进入容器内部
docker exec -it elasticsearch /bin/bash

# 在线下载并安装
./bin/elasticsearch-plugin  install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.12.1/elasticsearch-analysis-ik-7.12.1.zip

#退出
exit
#重启容器
docker restart elasticsearch

离线安装

查看elasticsearch的数据卷目录

shell
docker volume inspect es-plugins

显示结果:

json
[
   {
      "CreatedAt": "2022-05-06T10:06:34+08:00",
      "Driver": "local",
      "Labels": null,
      "Mountpoint": "/var/lib/docker/volumes/es-plugins/_data",
      "Name": "es-plugins",
      "Options": null,
      "Scope": "local"
   }
]

将ik文件夹上传到/var/lib/docker/volumes/es-plugins/_data目录下

重启容器

shell
docker restart es

查看日志,发现加载ik插件,就说明安装成功了

sh
docker logs -f es

测试IK分词器

  • ik_smart:最少切分
  • ik_max_word:最细切分
GET /_analyze
{
  "analyzer": "ik_max_word",
  "text": "黑马程序员学习java太棒了"
}

扩展词词典 && 停用词词典 ​

前往/var/lib/docker/volumes/es-plugins/_data/ik/config目录下,编辑IKAnalyzer.cfg.xml文件,添加扩展词词典ext.dic和停用词词典stop.dic

注意当前文件的编码必须是 UTF-8 格式,严禁使用Windows记事本编辑

重启elasticsearch和kibana

shell
docker restart elasticsearch
docker restart kibana

查看日志,发现日志中已经成功加载ext.dic和stop.dic配置文件

sh
docker logs -f es

部署kibana(可视化管理es) ​

创建网络

需要让es和kibana容器互联,因此需要创建一个网络

shell
docker network create es-net

拉取/加载镜像

shell
docker load -i kibana.tar

部署kibana

  • --network es-net :加入一个名为es-net的网络中,与elasticsearch在同一个网络中
  • -e ELASTICSEARCH_HOSTS=http://es:9200":设置elasticsearch的地址,因为kibana已经与elasticsearch在一个网络,因此可以用容器名直接访问elasticsearch
  • -p 5601:5601:端口映射配置
shell
docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \
--network=es-net \
-p 5601:5601  \
kibana:7.12.1

此时,在浏览器输入地址访问:http://192.168.113.132:5601,即可看到结果

部署Nginx ​

Nginx基本命令

开启服务:start nginx 直接点击Nginx目录下的nginx.exe

快速停止服务:nginx -s stop

重启服务:nginx -s reload

有序停止服务:nginx -s quit

其他命令重启、关闭nginx:ps -ef | grep nginx

强制停止Nginx:pkill -9 nginx

从容停止Nginx:kill -QUIT 主进程号

快速停止Nginx:kill -TERM 主进程号

平滑重启nginx:kill -HUP 主进程号

拉取镜像

docker pull nginx

简单上手

shell
docker run --restart=always --name=nginx -p 80:80 -d nginx

创建数据卷文件

shell
mkdir /mydata/nginx/conf/
touch /mydata/nginx/conf/nginx.conf
shell
mkdir /mydata/nginx/conf.d/
touch /mydata/nginx/conf.d/default.conf
mkdir /mydata/nginx/log/
shell
mkdir /mydata/nginx/html/
shell
mkdir /mydata/nginx/conf/leadnews/

创建容器

shell
docker run \
  -p 80:80 \
  --name nginx \
  --restart=always \
  -v /mydata/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
  -v /mydata/nginx/conf/leadnews/:/etc/nginx/leadnews/ \
  -v /mydata/nginx/html:/usr/share/nginx/html \
  -v /mydata/nginx/logs:/var/log/nginx \
  -d nginx

需要手写挂载的数据卷

/etc/nginx/nginx.conf

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

/etc/nginx/conf.d/default.conf

server {
    listen       80;
    server_name  localhost;

    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

自定义配置文件

upstream  heima-app-gateway{
    server localhost:51601;
}

server {
	listen 8801;
	location / {
		root D:/Projects_Java/workspace_heima-leadnews/app-web/;
		index index.html;
	}
	
	location ~/app/(.*) {
		proxy_pass http://heima-app-gateway/$1;
		proxy_set_header HOST $host;  # 不改变源请求头的值
		proxy_pass_request_body on;  #开启获取请求体
		proxy_pass_request_headers on;  #开启获取请求头
		proxy_set_header X-Real-IP $remote_addr;   # 记录真实发出请求的客户端IP
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  #记录代理信息
	}
}

部署MinIO ​

拉取镜像

shell
docker pull minio/minio

创建容器(minio端口默认是9000,但是会和Portainer端口冲突,所以这里改成了9100)

现在需要增加额外一个端口号用于web管理 --console-address “:9090” ;API管理地址 --console-address “:9000”

shell
docker run -d \
  --name minio \
  --restart always \
  -p 9100:9000 \
  -p 9001:9001 \
  -e MINIO_ROOT_USER=admin \
  -e MINIO_ROOT_PASSWORD=minio_admin66668888 \
  -v ./minio-data:/data \
  minio/minio:RELEASE.2025-07-23T15-54-02Z \
  server /data --console-address ":9001"

web管理地址:http://192.168.113.132:9001/

API管理地址:http://192.168.113.132:9100/

安装1Panel管理工具 ​

建议内存不低于4G安装此工具,如果内存2G会很卡

安装步骤参考文档:

1Panel文档:https://1panel.cn/docs/installation/online_installation/

我在虚拟机里安装了,非常简单,结果如下:

1Panel安装完成

辣位大人的语音合成器 ​

xijinping615/xi-jinping-tts Tags | Docker Hub

拉取镜像

shell
docker pull xijinping615/xi-jinping-tts

运行容器

shell
docker run --rm -it -p 8501:8501 xijinping615/xi-jinping-tts

然后在浏览器中打开:http://192.168.113.132:8501/

部署Kafka(已过时) ​

拉取zookeeper镜像

shell
docker pull zookeeper:3.4.14

创建zookeeper容器

shell
docker run -d --name zookeeper -p 2181:2181 zookeeper:3.4.14

拉取kafka镜像

shell
docker pull wurstmeister/kafka:2.12-2.3.1

创建kafka容器

shell
docker run -d --name kafka \
--env KAFKA_ADVERTISED_HOST_NAME=192.168.179.129 \
--env KAFKA_ZOOKEEPER_CONNECT=192.168.179.129:2181 \
--env KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.179.129:9092 \
--env KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 \
--env KAFKA_HEAP_OPTS="-Xmx256M -Xms256M" \
--net=host wurstmeister/kafka:2.12-2.3.1

如果是云主机,需要把--net=host改成-p 9092:9092(个人未验证过)

部署Kafka(单节点) ​

shell
cat > kafka_server_jaas.conf <<EOF
KafkaServer {
  org.apache.kafka.common.security.plain.PlainLoginModule required
  username="admin"
  password="admin123"
  user_admin="admin123";
};
EOF
shell
docker run -d \
  --name kafka \
  -p 9092:9092 \
  -v $(pwd)/kafka_server_jaas.conf:/etc/kafka/kafka_server_jaas.conf \
  -e KAFKA_NODE_ID=1 \
  -e KAFKA_PROCESS_ROLES=broker,controller \
  -e KAFKA_LISTENERS=SASL_PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093 \
  -e KAFKA_ADVERTISED_LISTENERS=SASL_PLAINTEXT://115.29.215.180:9092 \
  -e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,SASL_PLAINTEXT:SASL_PLAINTEXT \
  -e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
  -e KAFKA_CONTROLLER_QUORUM_VOTERS=1@127.0.0.1:9093 \
  -e KAFKA_INTER_BROKER_LISTENER_NAME=SASL_PLAINTEXT \
  -e KAFKA_SASL_ENABLED_MECHANISMS=PLAIN \
  -e KAFKA_SASL_MECHANISM_INTER_BROKER_PROTOCOL=PLAIN \
  -e KAFKA_AUTO_CREATE_TOPICS_ENABLE=true \
  -e KAFKA_OPTS="-Djava.security.auth.login.config=/etc/kafka/kafka_server_jaas.conf" \
  -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \
  -e KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=1 \
  -e KAFKA_TRANSACTION_STATE_LOG_MIN_ISR=1 \
  apache/kafka:4.0.0

手动管理 Topic(生产环境)

进入容器:

docker exec -it kafka bash

创建认证配置:

cat > /tmp/client.properties <<EOF
security.protocol=SASL_PLAINTEXT
sasl.mechanism=PLAIN
sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required username="admin" password="admin123";
EOF

查看所有 topic:

shell
sh /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --command-config /tmp/client.properties --list

查看某个 topic 详情:(输出会包含:分区数、副本数、leader、ISR 状态)

shell
sh /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --command-config /tmp/client.properties --describe --topic dev_test

创建 topic:

sh /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --command-config /tmp/client.properties --create --partitions 1 --replication-factor 1 --topic dev_test

删除命令:

shell
sh /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --command-config /tmp/client.properties --delete --topic dev_test

topic 命名规范

业务域.事件

例如:

order.create
order.pay
order.cancel
user.register
sms.send

部署MongoDB ​

拉取镜像

shell
docker pull mongo

创建容器

shell
docker run -di --name mongo-service --restart=always -p 27017:27017 -v ~/data/mongodata:/data mongo

yml配置

yaml
server:
   port: 9998
spring:
   data:
      mongodb:
         host: 192.168.200.130
         port: 27017
         database: leadnews-history

部署OpenLDAP ​

镜像仓库:https://hub.docker.com/r/osixia/openldap/tags

下面👇这个命令可能有点老了,但还是记录一下吧,如果追求新鲜就pull最新版吧

参考视频:https://www.bilibili.com/video/BV1UK411c7we/

shell
docker run -p 389:389 -p 636:636 \
  --name my-openldap-container \
  --env LDAP_TLS_VERIFY_CLIENT="never" \
  --env LDAP_ORGANISATION="Aishangwei" \
  --env LDAP_DOMAIN="xiodi.cn" \
  --env LDAP_ADMIN_PASSWORD="Xiodi.cn123" \
  -v /data/ldap/data:/var/lib/ldap \
  -v /data/ldap/conf:/etc/ldap/slapd.d \
  --detach osixia/openldap:1.3.0

下载Apache Directory Studio,什么系统就点哪个html页面去下载

这里具体讲下mac版的问题,可能会遇到如下错误:

img

如果遇到这个问题,可以参考这篇博客,具体做法就是安装x86版的jdk:

shell
arch -x86_64 brew install oracle-jdk

安装末尾遇到了一些错误,但是并没有影响系统jdk版本,而且Apache Directory Studio也顺利启动了,于是就不追究了。

image-20250611213732254

然后就是部署docker容器了,之后用Apache Directory Studio连接就行了

image-20250611213918869image-20250611213931043image-20250611213902146

部署kkfileview ​

这个是第三方构建,如果后续需要部署并投入实际生产了,最好再确认一下最新的版本

shell
docker run -d \
  --name kkfileview \
  --restart unless-stopped \
  -p 8012:8012 \
  ghcr.io/zhuyifeiruichuang/kkfileview:5.0.2

官方从 4.4.0 起默认拒绝未配置的外部来源,以防止 SSRF。官方安全配置说明

需要给容器增加:

environment:
  KK_TRUST_HOST: "115.29.215.180,zjubjyjy.oss-cn-hangzhou.aliyuncs.com"
  KK_NOT_TRUST_HOST: "localhost,127.0.0.1,169.254.*"
shell
docker run -d \
  --name kkfileview \
  --restart unless-stopped \
  -p 8012:8012 \
  -e KK_TRUST_HOST="115.29.215.180,zjubjyjy.oss-cn-hangzhou.aliyuncs.com" \
  ghcr.io/zhuyifeiruichuang/kkfileview:5.0.2

如果服务器拉去镜像很慢,可以用下面这招:

本地导出镜像

shell
docker pull \
  --platform linux/amd64 \
  ghcr.io/zhuyifeiruichuang/kkfileview:5.0.2
shell
docker image inspect \
  ghcr.io/zhuyifeiruichuang/kkfileview:5.0.2 \
  --format 'Architecture={{.Architecture}} OS={{.Os}} Size={{.Size}}'
shell
docker tag \
  ghcr.io/zhuyifeiruichuang/kkfileview:5.0.2 \
  kkfileview-offline:5.0.2-amd64

服务器上建好文件夹

shell
mkdir -p /opt/docker-images

本地上传

shell
scp -i ~/.ssh/id_ed25519b ./kkfileview-5.0.2-amd64.tar root@115.29.215.180:/opt/docker-images/

服务器加载镜像并创建容器

shell
docker load -i kkfileview-5.0.2-amd64.tar.gz
shell
docker image inspect \
  kkfileview-offline:5.0.2-amd64 \
  --format 'Architecture={{.Architecture}} OS={{.Os}} Size={{.Size}}'
shell
docker run -d \
  --name kkfileview \
  --restart unless-stopped \
  -p 127.0.0.1:8012:8012 \
  -e KK_BASE_URL="http://115.29.215.180/preview/" \
  -e KK_TRUST_HOST="115.29.215.180,zjubjyjy.oss-cn-hangzhou.aliyuncs.com" \
  -e KK_NOT_TRUST_HOST="localhost,127.0.0.1" \
  ghcr.io/zhuyifeiruichuang/kkfileview:5.0.2

部署Jenkins ​

TODO

容器化部署的 Jenkins 如何配置 Maven 镜像源加速 ​

问题的根源是Jenkins读不到宿主机的.m2里配置

宿主机
│
├── ~/.m2/settings.xml        # Jenkins 根本看不到,除非挂载
│
└── Jenkins Container
    │
    ├── /var/jenkins_home
    │
    ├── Maven
    │   └── bin/mvn
    │
    └── ~/.m2/settings.xml    # Maven真正读取这个

所以解决思路是进入容器配置镜像源加速

  1. 先进入容器
shell
docker exec -it jenkins bash
  1. 找到jenkins_home,一般容器都不是以root用户运行的,因此需要进入一个特殊的目录
shell
cd /var/jenkins_home
  1. 里面大概率是没有.m2文件的,但是可以读到,所以就手动创建一个
shell
mkdir -p /var/jenkins_home/.m2
shell
cd .m2
shell
touch settings.xml
shell
cat > settings.xml <<'EOF'
<?xml version="1.0" encoding="UTF-8"?>

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                              https://maven.apache.org/xsd/settings-1.0.0.xsd">

    <mirrors>
        <mirror>
            <id>aliyun</id>
            <name>Aliyun Maven Mirror</name>
            <url>https://maven.aliyun.com/repository/public</url>
            <mirrorOf>*</mirrorOf>
        </mirror>
    </mirrors>

</settings>
EOF
  1. 验证是否已经配置成功,先找一下mvn的位置
shell
find /var/jenkins_home/tools -type f -name mvn 2>/dev/null

输出类似:/var/jenkins_home/tools/hudson.tasks.Maven_MavenInstallation/Maven-3.9/bin/mvn

  1. 看一下是否成功
shell
/var/jenkins_home/tools/hudson.tasks.Maven_MavenInstallation/Maven-3.9/bin/mvn \
	help:effective-settings
image-20260825221016888

安装其他版本JDK ​

以安装JDK25为例

思路是:

当前 Jenkins 本身跑在 Docker 容器里 → 进入 Jenkins 容器 → 在容器内部安装 JDK 25 → 在 Jenkins「Tools」里把这个 JDK 25 配进去 → Jenkinsfile 使用它。

  1. 先找到 Jenkins 容器,进入容器,并切 root:
docker exec -u root -it jenkins bash

先确认环境,Jenkins 官方镜像通常是 Debian 系:

cat /etc/os-release
uname -m
  1. 在 Jenkins 容器里安装 Temurin JDK 25

先安装添加软件源需要的工具:

apt-get update

apt-get install -y \
  wget \
  gpg \
  ca-certificates \
  apt-transport-https

添加 Eclipse Adoptium 软件源:

wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public \
  | gpg --dearmor \
  > /etc/apt/trusted.gpg.d/adoptium.gpg

获取当前 Debian codename:

. /etc/os-release
echo "$VERSION_CODENAME"

然后添加源:

echo "deb https://packages.adoptium.net/artifactory/deb ${VERSION_CODENAME} main" \
  > /etc/apt/sources.list.d/adoptium.list

更新:

apt-get update

安装:

apt-get install -y temurin-25-jdk
  1. 找到 JDK 25 的 JAVA_HOME

执行:

ls -al /usr/lib/jvm/

通常会看到:

temurin-25-jdk-amd64

所以路径大概率是:

/usr/lib/jvm/temurin-25-jdk-amd64

你可以直接验证:

/usr/lib/jvm/temurin-25-jdk-amd64/bin/java -version

如果路径名称和我这里不同,就执行:

find /usr/lib/jvm -maxdepth 2 -type f -name java

或者:

dpkg -L temurin-25-jdk | grep '/bin/java$'

即可找到准确位置。

  1. Jenkins 页面配置 JDK 25
image-20260909090420520

安装完成后,浏览器打开 Jenkins:

Manage Jenkins
→ Tools
→ JDK installations

添加一个 JDK:

image-20260909090448557
Name:
JDK-25

JAVA_HOME:
/usr/lib/jvm/temurin-25-jdk-amd64
  1. Jenkinsfile 加上 JDK

你当前 Jenkinsfile 是:

tools {
    maven 'Maven-3.9'
}

改成:

tools {
    jdk 'JDK-25'
    maven 'Maven-3.9'
}

当前 Jenkinsfile 确实只声明了 Maven,没有声明 JDK。

  1. 不需要改 Jenkins 自己正在使用的 Java 21

最终应该是:

/opt/java/openjdk
└── Java 21
    └── Jenkins 自己运行

/usr/lib/jvm/temurin-25-jdk-amd64
└── Java 25
    └── Maven 构建项目

不需要执行:

update-alternatives --config java

也不用改容器全局 JAVA_HOME。

部署fetcher-mcp ​

开源项目,仓库地址:https://github.com/jae-jae/fetcher-mcp

shell
docker run -d --name fetcher-mcp -p 13000:3000 ghcr.io/jae-jae/fetcher-mcp:latest

评论

所有文章版权皆归博主所有,仅供学习参考。