版本比较

标识

  • 该行被添加。
  • 该行被删除。
  • 格式已经改变。

MySQL

开发中,最常用的应该就是数据库了。创建如下目录结构,并添加相关相关文件:

代码块
languageplain
$ tree
.
├── README.adoc
├── clean.sh
├── data
│   └── mysql
│       └── .gitkeep
├── docker
│   ├── config
│   │   └── mysql
│   │       └── init.sql
│   ├── env
│   │   └── mysql.env
│   └── images
│       └── mysql.dockerfile
└── docker-compose.yml

先来看一下 docker-compose.yml 文件的内容:

代码块
languageyaml
services:
  mysql:
    container_name: mysql
    build:
      context: .
      dockerfile: ./docker/images/mysql.dockerfile
    image: example/mysql:8.4
    env_file:
      - ./docker/env/mysql.env
    volumes:
      - ./data/mysql:/var/lib/mysql
    ports:
      - "3306:3306"
    healthcheck:
      test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
      interval: 5s
      timeout: 10s
      retries: 10

由于 MySQL 的官方镜像只是提供了数据库软件,需要将初始化脚本在数据库内执行一遍。所以,基于 mysql:8.4 重新构建私有镜像。./docker/images/mysql.dockerfile

代码块
languageplain
FROM mysql:8.4
ADD ./docker/config/mysql/init.sql /docker-entrypoint-initdb.d/mysql-init.sql 
RUN chown -R mysql:mysql /docker-entrypoint-initdb.d/*.sql
EXPOSE 3306
CMD ["mysqld", "--character-set-server=utf8mb4", "--collation-server=utf8mb4_0900_ai_ci"]
信息
特别说明一下:由于 docker-compose.yml 中将构建上下文 context 设置成了“当前目录”,那么构建文件中的目录必须使用以 docker-compose.yml 文件所在目录的相对路径。通过 ./docker/env/mysql.env 文件设置一下 root 用户的密码:

./docker/env/mysql.env

代码块
languageplain
MYSQL_ROOT_PASSWORD=123456
LANG=C.UTF-8

如果有多个组件依赖 MySQL,还可以通过初始化脚本给各个组件创建不同的数据库、账户和密码。示例初始化脚本如下:./docker/config/mysql/init.sql  -- https://stackoverflow.com/a/52899915

代码块
languagesql
-- create databases
CREATE DATABASE IF NOT EXISTS `diguage`;

-- create root user and grant rights
-- https://stackoverflow.com/a/16592722
CREATE USER IF NOT EXISTS 'diguage'@'%' IDENTIFIED BY '123456';
GRANT ALL ON diguage.* TO 'diguage'@'%';

FLUSH PRIVILEGES;

登录验证:

$ mysql -h127.0.0.1 -uroot -p123456

NACOS

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个由阿里巴巴推出的,更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

1、在 ./docker/config/mysql/init.sql 文件中增加初始化数据库、账户和密码的 SQL 语句。

代码块
languagesql
CREATE USER IF NOT EXISTS 'nacos'@'%' IDENTIFIED BY '123456';
GRANT ALL ON nacos.* TO 'nacos'@'%';

2、添加数据库初始化脚本 ./docker/config/nacos/mysql-schema.sql docker/images/mysql.dockerfile 中。

代码块
languageplain
# https://raw.githubusercontent.com/alibaba/nacos/develop/distribution/conf/mysql-schema.sql
# 在文件头加一句 SQL:  use nacos;
ADD ./docker/config/nacos/mysql-schema.sql /docker-entrypoint-initdb.d/nacos-mysql.sql

3、添加必要的环境变量配置文件 ./docker/env/nacos.env。

代码块
languageplain
PREFER_HOST_MODE=hostname
MODE=standalone
SPRING_DATASOURCE_PLATFORM=mysql
MYSQL_SERVICE_HOST=mysql
MYSQL_SERVICE_DB_NAME=nacos
MYSQL_SERVICE_PORT=3306
MYSQL_SERVICE_USER=nacos
MYSQL_SERVICE_PASSWORD=123456
MYSQL_SERVICE_DB_PARAM=characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
NACOS_AUTH_IDENTITY_KEY=2222
NACOS_AUTH_IDENTITY_VALUE=2xxx
NACOS_AUTH_TOKEN=SecretKey012345678901234567890123456789012345678901234567890123456789

4、docker-compose.yml 的内容最后一起给出。下同,不在赘述。

验证网页: http://127.0.0.1:8848/nacos/ ,监控数据见: http://localhost:8848/nacos/actuator/prometheus

Prometheus

部署好 NACOS,下面来部署一下 Prometheus,并且用 Prometheus 来监控 NACOS。

1、增加配置文件: ./docker/config/prometheus/prometheus.yml。

代码块
languageyaml
# my global config
global:
  scrape_interval: 5s # Set the scrape interval to every 5 seconds. Default is every 1 minute.
  evaluation_interval: 5s # Evaluate rules every 5 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
    - static_configs:
        - targets:
          # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: 'prometheus'

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: [ 'localhost:9090' ]

  - job_name: 'nacos' 
    metrics_path: '/nacos/actuator/prometheus'
    static_configs:
      - targets: [ 'nacos:8848' ]

接入新应用需要的配置

2、由于 NACOS 官方镜像内置的配置文件没有开启 Prometheus 监控。所以,需要增加一个配置文件,并将其挂载到容器里:./docker/config/nacos/application.properties:/home/nacos/conf/application.properties

代码块
languageplain
# spring
server.servlet.contextPath=${SERVER_SERVLET_CONTEXTPATH:/nacos}
server.contextPath=/nacos
server.port=${NACOS_APPLICATION_PORT:8848}
server.tomcat.accesslog.max-days=30
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i
server.tomcat.accesslog.enabled=${TOMCAT_ACCESSLOG_ENABLED:false}
server.error.include-message=ALWAYS
# default current work dir
server.tomcat.basedir=file:.
#*************** Config Module Related Configurations ***************#
### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced.
#spring.datasource.platform=${SPRING_DATASOURCE_PLATFORM:}
spring.sql.init.platform=${SPRING_DATASOURCE_PLATFORM:}
nacos.cmdb.dumpTaskInterval=3600
nacos.cmdb.eventTaskInterval=10
nacos.cmdb.labelTaskInterval=300
nacos.cmdb.loadDataAtStart=false
db.num=${MYSQL_DATABASE_NUM:1}
db.url.0=jdbc:mysql://${MYSQL_SERVICE_HOST}:${MYSQL_SERVICE_PORT:3306}/${MYSQL_SERVICE_DB_NAME}?${MYSQL_SERVICE_DB_PARAM:characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false}
db.user.0=${MYSQL_SERVICE_USER}
db.password.0=${MYSQL_SERVICE_PASSWORD}
## DB connection pool settings
db.pool.config.connectionTimeout=${DB_POOL_CONNECTION_TIMEOUT:30000}
db.pool.config.validationTimeout=10000
db.pool.config.maximumPoolSize=20
db.pool.config.minimumIdle=2
### The auth system to use, currently only 'nacos' and 'ldap' is supported:
nacos.core.auth.system.type=${NACOS_AUTH_SYSTEM_TYPE:nacos}
### worked when nacos.core.auth.system.type=nacos
### The token expiration in seconds:
nacos.core.auth.plugin.nacos.token.expire.seconds=${NACOS_AUTH_TOKEN_EXPIRE_SECONDS:18000}
### The default token:
nacos.core.auth.plugin.nacos.token.secret.key=${NACOS_AUTH_TOKEN:}
### Turn on/off caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.
nacos.core.auth.caching.enabled=${NACOS_AUTH_CACHE_ENABLE:false}
nacos.core.auth.enable.userAgentAuthWhite=${NACOS_AUTH_USER_AGENT_AUTH_WHITE_ENABLE:false}
nacos.core.auth.server.identity.key=${NACOS_AUTH_IDENTITY_KEY:}
nacos.core.auth.server.identity.value=${NACOS_AUTH_IDENTITY_VALUE:}
## spring security config
### turn off security
nacos.security.ignore.urls=${NACOS_SECURITY_IGNORE_URLS:/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**}
# metrics for elastic search
management.endpoints.web.exposure.include=*  
management.metrics.export.elastic.enabled=false
management.metrics.export.influx.enabled=false
nacos.naming.distro.taskDispatchThreadCount=10
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.console.ui.enabled=true
nacos.core.param.check.enabled=true

新增配置。

验证网页: 新增配置。验证网页: http://localhost:9090/

Grafana

在监控可视化方面,Grafana 还是更胜一筹。下面以 NACOS 为例,看看如何基于 Prometheus 的监控数据来做监控和报警。配置方面很简单,只需要将 Grafana 加入到 docker-compose.yml 即可。启动后,主要是在 UI 页面进行操作。

  1. 添加 Prometheus 类型的 Data Source。
  2. 添加监控面板,将 模板 导入即可。

操作细节见 Nacos 监控手册

信息
提醒:常用软件的 Grafana 监控面板不需要自己配置,可以在 Grafana dashboards 页面搜索,选择合适的面板,下载 JSON 导入即可。

Micrometer - Spring Boot 3 DataBase Sample 中看到,可以将配置文件直接挂载到 Grafana 中,这样应该就无需配置。但是,尝试后,数据不通,后续还要再研究一下怎么优化。

验证网页: http://localhost:3000/ , 账户密码: admin/admin

业务应用接入

将业务应用接入到 Prometheus,就需要业务应用将相关监控数据暴露出来。Spring Boot 已经有相关 Starter,可以直接使用。步骤如下:

1、添加相关依赖

代码块
languagexml
<!-- spring-boot-actuator依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- prometheus依赖 -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

2、添加相关配置,暴露监测数据端口。配置完成后,启动应用即可在 http://localhost:8081/actuator/prometheus 中看到相关监控数据。

代码块
languageplain
# application.properties 添加以下配置用于暴露指标
spring.application.name=diguage-order

management.server.port=8081
management.endpoints.web.exposure.include=*
management.metrics.tags.application=${spring.application.name}

3、在 ./docker/config/prometheus/prometheus.yml 中配置拉取任务:

代码块
languageyaml
- job_name: 'diguage-order'
  metrics_path: '/actuator/prometheus'
  static_configs:
    - targets: [ 'diguage-order:8848' ] 

这里的域名与 docker-compose.yml 中配置的名称相对应。

4、将应用打包,接入到 docker-compose.yml 中,即可一起启动接入到系统中。

Elasticsearch

由于 Elasticsearch 8+ 的版本修改了安全策略,不允许 Kibana 使用超级管理员 elastic 连接 Elasticsearch,这里选用 7.x 版本做演示。

信息
提醒,在设置 Elasticsearch 的超级管理员 elastic 的账户密码时,如果密码是全部的阿拉伯数字,那么需要用双引号或者单引号括起来。

在测试中,还遇到一个磁盘过载导致的只读问题。解决方式如下:

1、curl -X GET "localhost:9200/_cat/allocation?v&pretty" 查看磁盘使用情况

2、解除只读状态

代码块
languagebash
$ curl -X PUT "localhost:9200/test/_settings" -H 'Content-Type: application/json' -d'
{
  "index.blocks.read_only_allow_delete": null
}'


3、调整磁盘使用阈值

代码块
languagebash
$ curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
  "persistent": {
    "cluster.routing.allocation.disk.watermark.flood_stage": "97%", 
    "cluster.routing.allocation.disk.watermark.high": "90%", 
    "cluster.routing.allocation.disk.watermark.low": "85%",  
    "cluster.info.update.interval": "1m" 
  }
}'
  • 当磁盘使用超过这个百分比时,索引会被设置为只读。
  • 当磁盘使用超过这个百分比时,Elasticsearch 会尝试将分片迁移到磁盘使用较少的节点。
  • 当磁盘使用超过这个百分比时,会触发分片的重新分配。
  • 更新磁盘使用信息的间隔时间。

Kibana

配置好 Elasticsearch 的网址、账户、密码就可以启动访问了。

Fluentd

安装 Fluentd,通过 Fluentd 把 NACOS 和业务应用的日志传输到 Elasticsearch。目前先把 NACOS 的日志接入到 Elasticsearch。这里需要一个配置文件,用于知名日志的来源及去向:./docker/config/fluentd/fluent.conf

代码块
languageplain
<source>
  @type monitor_agent
  port 9880  # HTTP 监控端口,默认为 9880
</source>

<source> 
  @type tail
  path "/var/log/nacos/nacos.log"    # NACOS 的日志路径
  pos_file "/fluentd/log/nacos.pos"  # 记录日志读取进度
  tag "nacos.*"
  <parse>
    @type "none" # 如果 NACOS 日志是纯文本格式,可以选择 `none` 或其他解析方式
  </parse>
</source>

<match nacos.**> 
  @type elasticsearch
  host "elasticsearch"    # Elasticsearch 的服务名
  port 9200
  logstash_format true    # 格式化为 logstash 格式
  logstash_prefix "nacos" # 索引前缀
  include_tag_key true
  flush_interval 5s
  <buffer>
    flush_interval 5s
  </buffer>
</match>

接入成功后,curl http://localhost:9200/nacos*/_search?pretty 验证 NACOS 日志接入到 Elasticsearch。下面重点介绍一下遇到的几个问题:

插件缺失导致的启动失败

由于需求将日志输送到 Elasticsearch,这就需要 fluent-plugin-elasticsearch 插件。容器中,默认是没有安装的,启动时就会导致失败。

两种解决办法:

  1. 基于官方镜像,在里面装上插件,再打包一个新镜像。
  2. 在 docker-compose.yml 中通过 command 指令,运行 Fluentd 时安装 fluent-plugin-elasticsearch 插件。

为了简单起见,直接选择第二种方案。安装命令是: command: ["sh", "-c", "gem install fluent-plugin-elasticsearch --no-document && fluentd -c /fluentd/etc/fluent.conf"]。

由于权限导致的安装失败

配置上述命令后,启动就遇到了该错误: ERROR: While executing gem …​ (Gem::FilePermissionError) You don’t have write permissions for the /usr/lib/ruby/gems/3.2.0 directory.。

这是由于默认以 fluent 运行的,该用户对 /usr/lib/ruby/gems/3.2.0 没有写权限。所以,在安装插件时,就会报错。

解决方案: 通过在 docker-compose.yml 中增加 user: root 配置,使用 root 来运行容器。

健康检查

尝试了三种方案:

  1. 启用 monitor_agent 插件,监控 9880 端口。失败!
  2. 使用 nc 检查 Fluentd 监听的 24224 端口。失败!
  3. 最后通过使用 test: [ "CMD-SHELL", "pgrep fluentd || exit 1" ] 来查看 Fluentd 的进程方式。成功!

链路追踪

站在更高的视角去看,链路追踪其实是可观测性的一部分。日志、追踪、度量,三者是相辅相成的。

可观测性

在 OpenTelemetry 出现之前,日志、追踪、度量是分离的,三者各各自为战。而 OpenTelemetry 的出现,则是试图将三者统一。目前 OpenTelemetry 是云原生架构中,最炙手可热的分布式链路追踪解决方案,它提供了一套相关标准,各个厂商可以在这套标准之上进行各种各样的组件开发,大家可以根据自己的需要,选择不同的组件,进行可插拔式的安装。

OpenTelemetry 的野心

OpenTelemetry

OpenTelemetry 并不需要在 Docker 中启动或者配置什么。在目前的架构中,Jaeger 是作为 OpenTelemetry 的一个实现来出现的。 OpenTelemetry 需要做的就是下载一个 Java Agent,执行 docker/config/opentelemetry/download-opentelemetry-agent.sh 脚本即可下载最新版的 Java Agent。在业务应用启动时,增加如下 JVM 参数:

代码块
languageplain
-javaagent:/path/to/opentelemetry-javaagent.jar
-Dotel.service.name=<业务系统名称>
-Dotel.traces.exporter=otlp 
-Dotel.exporter.otlp.endpoint="http://localhost:4318" 
-Dotel.exporter.otlp.protocol=http/protobuf 
-Dotel.logs.exporter=console  
-Dotel.metrics.exporter=prometheus 
-Dotel.exporter.prometheus.port=8079 
-Dotel.metric.export.interval=1000 
  1. 选择 otlp exporter
  2. otlp exporter 的网址
  3. 传输协议。这个必须和 otel.exporter.otlp.endpoint 配置项及 Jaeger 暴露的端口相对应,否则传输失败。
  4. 将日志输出到控制台。
  5. 将 Metrics 信息导出到 Prometheus
  6. Metrics 导出的端口。Prometheus 会从端口号拉去,路径是 /metrics。
  7. Metrics 统计间隔。

应用启动后,可以在 Prometheus 的配置文件 docker/config/prometheus/prometheus.yml 中增加相关配置:

代码块
languageyaml
# 业务系统:商城
- job_name: 'mall-system'
  metrics_path: '/metrics'
  static_configs:
    - targets: ['host.docker.internal:8099'] 

这样就会 Prometheus 定期去拉取业务系统的监控信息,可以在 http://localhost:9090/targets 页面看到系统的运行状况。详细配置见: OpenTelemetry Configure the SDK

Jaeger

http://localhost:16686

最新版的 Jaeger 都被集成到了 jaegertracing/all-in-one 这个一个镜像中。简化了很多配置。将官方文档中,启动 Docker 的参数改成 Docker Compose 配置即可。初次使用 Jaeger,肯定会惊讶于它居然需要这么多端口号,具体端口号的解释见: Jaeger Getting Started

尾部采样

尾部采样是通过考虑 Trace 内的全部或大部分 Span 来决定对 Trace 进行采样。尾部采样允许您根据从 Trace 的不同部分使用的特定条件对 Trace 进行采样,而头部采样则不具有此选项。

利用 OpenTelemetry Collector 来实现尾部采样。私以为尾部采样最大的优势是可以根据“问题”进行采样,比如耗时比较高的采样,再比如链路中出现错误,进行采样。OpenTelemetry Collector 的配置:docker/config/opentelemetry/otel-collector-config.yaml

代码块
languageyaml
# https://opentelemetry.io/docs/collector/configuration/
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors: ${file:/etc/otelcol-contrib/tail_sampling_config.yaml}

exporters:
  otlp:
    endpoint: jaeger:4317
    tls:
      insecure: true # 根据实际情况配置 TLS

extensions:
  health_check:
  pprof:
  zpages:

service:
  extensions: [ health_check, pprof, zpages ]
  pipelines:
    traces:
      receivers: [ otlp ]
      processors: [ tail_sampling, batch ]
      exporters: [ otlp ]

这里展示三种采样示例:①超长耗时采样;②错误请求采样;③百分比随机采样:

代码块
languageyaml
tail_sampling:
  # 在采样决策之前等待的时间。这个时间允许 collector 收集更多的
  # 追踪数据,以便基于更完整的信息进行决策。5s 表示等待 5 秒后进行采样决策。
  # 确保采样决策基于完整的追踪数据,而不是追踪开始后的即时数据。
  decision_wait: 5s
  # 决定如何批量处理追踪数据。具体来说,这是一个用于批处理采样决策的追踪数量阈值。
  # 100 表示每处理 100 个追踪数据后进行一次采样决策。
  # 优化性能,通过批量处理减少资源消耗。
  num_traces: 100
  # 预期每秒钟接收的新追踪数量。这个参数用于调整采样策略的性能和资源使用。
  # 10 表示预期每秒钟有 10 个新追踪到达。
  # 帮助处理器优化其内部数据结构和性能,以适应流量模式。
  expected_new_traces_per_sec: 10
  # 配置用于存储已采样追踪的缓存设置。
  decision_cache:
    # 缓存中可存储的已采样追踪的最大数量。500 表示缓存最多存储 500 个已采样的追踪。
    # 控制缓存的大小,防止内存占用过高。
    sampled_cache_size: 500
  # 定义一组采样策略,决定哪些追踪应被采样(保留)或丢弃。采样决策按顺序应用,直到一个策略匹配。
  policies:
    [
      # 基于追踪的延迟时间来决定是否采样。延迟阈值(毫秒)。
      # 有助于识别和分析性能瓶颈或异常延迟的追踪。
      {
        name: test-policy-2,
        type: latency,
        # 如果一个追踪的总延迟时间超过 119 毫秒,则该追踪将被采样。延迟阈值(毫秒)。
        latency: { threshold_ms: 119 }
      },

      # 基于概率进行采样,即以一定的概率采样追踪数据。
      # 用于控制采样率,以在保持数据质量的同时减少数据量。
      {
        name: test-policy-4,
        type: probabilistic,
        # hash_salt:用于哈希计算的盐值。
        # sampling_percentage:采样百分比,20 表示 20% 的追踪将被采样。
        probabilistic: {
          hash_salt: "39b68c2b07f28452df4e64357e749139",
          sampling_percentage: 20
        }
      },

      # 基于追踪的状态码来决定是否采样。
      # 用于重点关注有错误或未设置状态码的追踪,以便快速识别和修复问题。
      {
        name: test-policy-5,
        type: status_code,
        # status_codes:要匹配的状态码列表。
        status_code: { status_codes: [ ERROR ] }
      },
    ]

尾部采样的配置文件在 docker/config/opentelemetry/tail_sampling_config.yaml。,

完整 docker-compose.yml

代码块
languageyaml
services:
  # mysql -h127.0.0.1 -uroot -p123456
  mysql:
    container_name: mysql
    build:
      context: .
      dockerfile: ./docker/images/mysql.dockerfile
    image: example/mysql:8.4
    environment:
      - TZ=Asia/Shanghai  # 设置时区为上海时间
    env_file:
      - ./docker/env/mysql.env
    volumes:
      - ./data/mysql:/var/lib/mysql
    ports:
      - "3306:3306"
    healthcheck:
      test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
      interval: 30s  # 每 30 秒检查一次
      timeout: 10s   # 请求超时时间为 10 秒
      retries: 5     # 如果检查失败,最多重试 5 次
      start_period: 60s  # 等待 60 秒后再开始进行 healthcheck

  # Nacos: http://127.0.0.1:8848/nacos/
  # http://localhost:8848/nacos/actuator/prometheus
  # http://localhost:8848/nacos/actuator/health
  nacos:
    image: nacos/nacos-server:${NACOS_VERSION:-latest}
    container_name: nacos
    environment:
      - TZ=Asia/Shanghai  # 设置时区为上海时间
    env_file:
      - ./docker/env/nacos.env
    volumes:
      - ./docker/config/nacos/application.properties:/home/nacos/conf/application.properties
      - nacos_log:/home/nacos/logs
    ports:
      - "8848:8848"
      - "9848:9848"
    restart: on-failure
    healthcheck:
      test: [ "CMD", "curl", "-f", "http://localhost:8848/nacos/actuator/health" ]
      interval: 30s  # 每 30 秒检查一次
      timeout: 10s   # 请求超时时间为 10 秒
      retries: 5     # 如果检查失败,最多重试 5 次
      start_period: 60s  # 等待 60 秒后再开始进行 healthcheck
    depends_on:
      mysql:
        condition: service_healthy

  # Prometheus: http://localhost:9090/
  # http://localhost:9090/-/healthy
  prometheus:
    image: prom/prometheus:${PROMETHEUS_VERSION:-latest}
    container_name: prometheus
    environment:
      - TZ=Asia/Shanghai  # 设置时区为上海时间
    command:
      - --config.file=/etc/prometheus/prometheus.yml
    volumes:
      - ./docker/config/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
    ports:
      - 9090:9090
    restart: on-failure
    healthcheck:
      test: [ "CMD", "wget", "--spider", "http://localhost:9090/-/healthy" ]
      interval: 30s  # 每 30 秒检查一次
      timeout: 10s   # 请求超时时间为 10 秒
      retries: 5     # 如果检查失败,最多重试 5 次
      start_period: 60s  # 等待 60 秒后再开始进行 healthcheck
    depends_on:
      - nacos

  # Grafana: http://localhost:3000/
  # admin/admin
  grafana:
    container_name: grafana
    image: grafana/grafana:${GRAFANA_VERSION:-latest}
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=admin
      - TZ=Asia/Shanghai  # 设置时区为上海时间
    volumes:
      - ./data/grafana:/var/lib/grafana  # 将主机目录映射到 Grafana 容器内的 /var/lib/grafana
    ports:
      - 3000:3000
    restart: on-failure
    healthcheck:
      test: [ "CMD", "curl", "-f", "http://localhost:3000/api/health" ]
      interval: 30s  # 每 30 秒检查一次
      timeout: 10s   # 请求超时时间为 10 秒
      retries: 5     # 如果检查失败,最多重试 5 次
      start_period: 60s  # 等待 60 秒后再开始进行 healthcheck
    depends_on:
      - prometheus

  # ElasticSearch http://localhost:9200/
  # http://localhost:9200/_cluster/health
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:${ELASTICSEARCH_VERSION:-7.17.24}
    container_name: elasticsearch
    environment:
      - discovery.type=single-node
      - ELASTIC_PASSWORD='123456'  # 设置 elastic 用户的默认密码
      - TZ=Asia/Shanghai  # 设置时区为上海时间
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - ./data/elasticsearch:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"
      - "9300:9300"
    healthcheck:
      test: [ "CMD-SHELL", "curl -fsSL http://localhost:9200/_cluster/health || exit 1" ]
      interval: 30s  # 每 30 秒检查一次
      timeout: 10s   # 请求超时时间为 10 秒
      retries: 5     # 如果检查失败,最多重试 5 次
      start_period: 60s  # 等待 60 秒后再开始进行 healthcheck

  # Kibana http://localhost:5601
  # http://localhost:5601/api/status
  kibana:
    image: docker.elastic.co/kibana/kibana:${KIBANA_VERSION:-7.17.24}
    container_name: kibana
    environment:
      - ELASTICSEARCH_URL=http://elasticsearch:9200
      - ELASTICSEARCH_USERNAME=elastic
      - ELASTICSEARCH_PASSWORD='123456'
      - TZ=Asia/Shanghai  # 设置时区为上海时间
    ports:
      - "5601:5601"
    restart: on-failure
    healthcheck:
      test: [ "CMD", "curl", "-f", "http://localhost:5601/api/status" ]
      interval: 30s  # 每 30 秒检查一次
      timeout: 10s   # 请求超时时间为 10 秒
      retries: 5     # 如果检查失败,最多重试 5 次
      start_period: 60s  # 等待 60 秒后再开始进行 healthcheck
    depends_on:
      - elasticsearch

  # Fluentd http://localhost:9880/api/plugins.json 插件的安装情况
  fluentd:
    image: fluentd:${FLUENTD_VERSION:-latest}
    container_name: fluentd
    user: root  # 使用 root 用户安装插件
    ports:
      - "24224:24224"
      - "9880:9880"  # 开启监控端口
    volumes:
      - ./docker/config/fluentd/fluent.conf:/fluentd/etc/fluent.conf  # 挂载 Fluentd 配置文件
      - ./data/fluentd:/fluentd/log  # 持久化 Fluentd 数据目录
      - nacos_log:/var/log/nacos  # 挂载 NACOS 日志目录
    environment:
      FLUENT_ELASTICSEARCH_HOST: elasticsearch
      FLUENT_ELASTICSEARCH_PORT: 9200
      TZ: Asia/Shanghai  # 设置时区为上海时间
    # command: ["sh", "-c", "gem install fluent-plugin-elasticsearch --no-document && fluentd -c /fluentd/etc/fluent.conf"]
    command: [ "sh", "-c", "gem install fluent-plugin-elasticsearch --no-document && chown -R fluent /usr/lib/ruby/gems && fluentd -c /fluentd/etc/fluent.conf" ]
    healthcheck:
      test: [ "CMD-SHELL", "pgrep fluentd || exit 1" ]
      interval: 30s  # 每 30 秒检查一次
      timeout: 10s   # 请求超时时间为 10 秒
      retries: 5     # 如果检查失败,最多重试 5 次
      start_period: 60s  # 等待 60 秒后再开始进行 healthcheck
    depends_on:
      - elasticsearch

  # Jaeger: http://localhost:16686
  jaeger:
    image: jaegertracing/all-in-one:${JAEGER_VERSION:-latest}
    container_name: jaeger
    environment:
      - TZ=Asia/Shanghai  # 设置时区为上海时间
    ports:
      - "16686:16686"  # Jaeger UI
      - "14268:14268"  # Jaeger Collector HTTP, accept jaeger.thrift directly from clients
      - "14250:14250"  # Jaeger Collector gRPC, accept model.proto
      - "14317:4317"  # accept OpenTelemetry Protocol (OTLP) over gRPC
      - "14318:4318"  # accept OpenTelemetry Protocol (OTLP) over HTTP
      - "9411:9411" # Zipkin compatible endpoint (optional)
      - "6831:6831/udp"  # accept jaeger.thrift over Thrift-compact protocol (used by most SDKs)
      - "6832:6832/udp" # accept jaeger.thrift over Thrift-binary protocol (used by Node.js SDK)
      - "5775:5775/udp" # (deprecated) accept zipkin.thrift over compact Thrift protocol (used by legacy clients only)
      - "5778:5778"   # serve configs (sampling, etc.)
    # https://www.jaegertracing.io/docs/1.62/getting-started/ 各端口用途
    healthcheck:
      test: [ "CMD", "wget", "--spider", "http://localhost:16686/" ]
      interval: 30s  # 每 30 秒检查一次
      timeout: 10s   # 请求超时时间为 10 秒
      retries: 5     # 如果检查失败,最多重试 5 次
      start_period: 60s  # 等待 60 秒后再开始进行 healthcheck

  otel-collector:
    image: otel/opentelemetry-collector-contrib:${OPEN_TELEMETRY_COLLECTOR_VERSION:-latest}
    container_name: otel-collector
    environment:
      - TZ=Asia/Shanghai  # 设置时区为上海时间
    volumes:
      - ./docker/config/opentelemetry/otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml
      - ./docker/config/opentelemetry/tail_sampling_config.yaml:/etc/otelcol-contrib/tail_sampling_config.yaml
    ports:
      - 1888:1888 # pprof extension
      - 8888:8888 # Prometheus metrics exposed by the Collector
      - 8889:8889 # Prometheus exporter metrics
      - 13133:13133 # health_check extension
      - 4317:4317 # OTLP gRPC receiver
      - 4318:4318 # OTLP http receiver
      - 55679:55679 # zpages extension
    depends_on:
      - jaeger

volumes:
  nacos_log:

参考


目录