feat(health): 为全部12个微服务添加Docker健康检查

## 变更概要
所有后端微服务均增加 Docker HEALTHCHECK 指令,统一通过 GET /health
端点检测服务存活状态。解决 `docker ps` 中13个容器无 (healthy) 状态的问题。

## NestJS 服务 (9个)
- auth-service (:3010), user-service (:3001), issuer-service (:3002),
  clearing-service (:3004), compliance-service (:3005), ai-service (:3006),
  notification-service (:3008), telemetry-service (:3011), admin-service (:3012)
- 7个服务的 app.module.ts 新增 `import { HealthModule } from '@genex/common'`
  注册标准健康检查控制器 (GET /health, /health/ready, /health/live)
- telemetry-service 和 admin-service 已有自建 HealthController,无需导入
- Dockerfile: HEALTHCHECK --interval=30s --start-period=15s --retries=3

## Go 服务 (3个)
- trading-service (:3003), translate-service (:3007), chain-indexer (:3009)
- 已有 /health 端点 (Gin 路由),仅 Dockerfile 添加 HEALTHCHECK
- Dockerfile: HEALTHCHECK --interval=30s --start-period=10s --retries=3

## Kafka Connect
- docker-compose.yml 添加 healthcheck (curl http://localhost:8083/)

## 健康检查方式
- 所有服务统一使用 `wget --spider http://localhost:PORT/health`
  (node:20-alpine 和 alpine:3.19 均自带 BusyBox wget)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-02-20 05:39:25 -08:00
parent 0b1de382b0
commit c5787020d2
20 changed files with 44 additions and 0 deletions

View File

@ -154,6 +154,12 @@ services:
OFFSET_FLUSH_TIMEOUT_MS: 5000 OFFSET_FLUSH_TIMEOUT_MS: 5000
ports: ports:
- "127.0.0.1:48083:8083" - "127.0.0.1:48083:8083"
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8083/ || exit 1"]
interval: 30s
timeout: 10s
start_period: 30s
retries: 3
depends_on: depends_on:
kafka: kafka:
condition: service_healthy condition: service_healthy

View File

@ -29,4 +29,6 @@ COPY --from=builder /app/services/admin-service/node_modules ./node_modules
COPY --from=builder /app/services/admin-service/package.json ./ COPY --from=builder /app/services/admin-service/package.json ./
USER node USER node
EXPOSE 3012 EXPOSE 3012
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3012/health || exit 1
CMD ["dumb-init", "node", "dist/main"] CMD ["dumb-init", "node", "dist/main"]

View File

@ -29,4 +29,6 @@ COPY --from=builder /app/services/ai-service/node_modules ./node_modules
COPY --from=builder /app/services/ai-service/package.json ./ COPY --from=builder /app/services/ai-service/package.json ./
USER node USER node
EXPOSE 3006 EXPOSE 3006
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3006/health || exit 1
CMD ["dumb-init", "node", "dist/main"] CMD ["dumb-init", "node", "dist/main"]

View File

@ -2,10 +2,12 @@ import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config'; import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { ThrottlerModule } from '@nestjs/throttler'; import { ThrottlerModule } from '@nestjs/throttler';
import { HealthModule } from '@genex/common';
import { AiModule } from './ai.module'; import { AiModule } from './ai.module';
@Module({ @Module({
imports: [ imports: [
HealthModule,
ConfigModule.forRoot({ isGlobal: true }), ConfigModule.forRoot({ isGlobal: true }),
TypeOrmModule.forRoot({ TypeOrmModule.forRoot({
type: 'postgres', type: 'postgres',

View File

@ -29,4 +29,6 @@ COPY --from=builder /app/services/auth-service/node_modules ./node_modules
COPY --from=builder /app/services/auth-service/package.json ./ COPY --from=builder /app/services/auth-service/package.json ./
USER node USER node
EXPOSE 3010 EXPOSE 3010
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3010/health || exit 1
CMD ["dumb-init", "node", "dist/main"] CMD ["dumb-init", "node", "dist/main"]

View File

@ -1,10 +1,12 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { ThrottlerModule } from '@nestjs/throttler'; import { ThrottlerModule } from '@nestjs/throttler';
import { HealthModule } from '@genex/common';
import { AuthModule } from './auth.module'; import { AuthModule } from './auth.module';
@Module({ @Module({
imports: [ imports: [
HealthModule,
TypeOrmModule.forRoot({ TypeOrmModule.forRoot({
type: 'postgres', type: 'postgres',
host: process.env.DB_HOST || 'localhost', host: process.env.DB_HOST || 'localhost',

View File

@ -11,4 +11,6 @@ WORKDIR /app
COPY --from=builder /server . COPY --from=builder /server .
USER nobody:nobody USER nobody:nobody
EXPOSE 3009 EXPOSE 3009
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3009/health || exit 1
CMD ["./server"] CMD ["./server"]

View File

@ -29,4 +29,6 @@ COPY --from=builder /app/services/clearing-service/node_modules ./node_modules
COPY --from=builder /app/services/clearing-service/package.json ./ COPY --from=builder /app/services/clearing-service/package.json ./
USER node USER node
EXPOSE 3004 EXPOSE 3004
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3004/health || exit 1
CMD ["dumb-init", "node", "dist/main"] CMD ["dumb-init", "node", "dist/main"]

View File

@ -1,10 +1,12 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { ThrottlerModule } from '@nestjs/throttler'; import { ThrottlerModule } from '@nestjs/throttler';
import { HealthModule } from '@genex/common';
import { ClearingModule } from './clearing.module'; import { ClearingModule } from './clearing.module';
@Module({ @Module({
imports: [ imports: [
HealthModule,
TypeOrmModule.forRoot({ TypeOrmModule.forRoot({
type: 'postgres', type: 'postgres',
host: process.env.DB_HOST || 'localhost', host: process.env.DB_HOST || 'localhost',

View File

@ -29,4 +29,6 @@ COPY --from=builder /app/services/compliance-service/node_modules ./node_modules
COPY --from=builder /app/services/compliance-service/package.json ./ COPY --from=builder /app/services/compliance-service/package.json ./
USER node USER node
EXPOSE 3005 EXPOSE 3005
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3005/health || exit 1
CMD ["dumb-init", "node", "dist/main"] CMD ["dumb-init", "node", "dist/main"]

View File

@ -1,10 +1,12 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { ThrottlerModule } from '@nestjs/throttler'; import { ThrottlerModule } from '@nestjs/throttler';
import { HealthModule } from '@genex/common';
import { ComplianceModule } from './compliance.module'; import { ComplianceModule } from './compliance.module';
@Module({ @Module({
imports: [ imports: [
HealthModule,
TypeOrmModule.forRoot({ TypeOrmModule.forRoot({
type: 'postgres', type: 'postgres',
host: process.env.DB_HOST || 'localhost', host: process.env.DB_HOST || 'localhost',

View File

@ -29,4 +29,6 @@ COPY --from=builder /app/services/issuer-service/node_modules ./node_modules
COPY --from=builder /app/services/issuer-service/package.json ./ COPY --from=builder /app/services/issuer-service/package.json ./
USER node USER node
EXPOSE 3002 EXPOSE 3002
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3002/health || exit 1
CMD ["dumb-init", "node", "dist/main"] CMD ["dumb-init", "node", "dist/main"]

View File

@ -1,10 +1,12 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { ThrottlerModule } from '@nestjs/throttler'; import { ThrottlerModule } from '@nestjs/throttler';
import { HealthModule } from '@genex/common';
import { IssuerModule } from './issuer.module'; import { IssuerModule } from './issuer.module';
@Module({ @Module({
imports: [ imports: [
HealthModule,
TypeOrmModule.forRoot({ TypeOrmModule.forRoot({
type: 'postgres', type: 'postgres',
host: process.env.DB_HOST || 'localhost', host: process.env.DB_HOST || 'localhost',

View File

@ -29,4 +29,6 @@ COPY --from=builder /app/services/notification-service/node_modules ./node_modul
COPY --from=builder /app/services/notification-service/package.json ./ COPY --from=builder /app/services/notification-service/package.json ./
USER node USER node
EXPOSE 3008 EXPOSE 3008
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3008/health || exit 1
CMD ["dumb-init", "node", "dist/main"] CMD ["dumb-init", "node", "dist/main"]

View File

@ -1,10 +1,12 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { ThrottlerModule } from '@nestjs/throttler'; import { ThrottlerModule } from '@nestjs/throttler';
import { HealthModule } from '@genex/common';
import { NotificationModule } from './notification.module'; import { NotificationModule } from './notification.module';
@Module({ @Module({
imports: [ imports: [
HealthModule,
TypeOrmModule.forRoot({ TypeOrmModule.forRoot({
type: 'postgres', type: 'postgres',
host: process.env.DB_HOST || 'localhost', host: process.env.DB_HOST || 'localhost',

View File

@ -29,4 +29,6 @@ COPY --from=builder /app/services/telemetry-service/node_modules ./node_modules
COPY --from=builder /app/services/telemetry-service/package.json ./ COPY --from=builder /app/services/telemetry-service/package.json ./
USER node USER node
EXPOSE 3011 EXPOSE 3011
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3011/health || exit 1
CMD ["dumb-init", "node", "dist/main"] CMD ["dumb-init", "node", "dist/main"]

View File

@ -11,4 +11,6 @@ WORKDIR /app
COPY --from=builder /server . COPY --from=builder /server .
USER nobody:nobody USER nobody:nobody
EXPOSE 3003 EXPOSE 3003
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3003/health || exit 1
CMD ["./server"] CMD ["./server"]

View File

@ -11,4 +11,6 @@ WORKDIR /app
COPY --from=builder /server . COPY --from=builder /server .
USER nobody:nobody USER nobody:nobody
EXPOSE 3007 EXPOSE 3007
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3007/health || exit 1
CMD ["./server"] CMD ["./server"]

View File

@ -29,4 +29,6 @@ COPY --from=builder /app/services/user-service/node_modules ./node_modules
COPY --from=builder /app/services/user-service/package.json ./ COPY --from=builder /app/services/user-service/package.json ./
USER node USER node
EXPOSE 3001 EXPOSE 3001
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3001/health || exit 1
CMD ["dumb-init", "node", "dist/main"] CMD ["dumb-init", "node", "dist/main"]

View File

@ -1,10 +1,12 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { ThrottlerModule } from '@nestjs/throttler'; import { ThrottlerModule } from '@nestjs/throttler';
import { HealthModule } from '@genex/common';
import { UserModule } from './user.module'; import { UserModule } from './user.module';
@Module({ @Module({
imports: [ imports: [
HealthModule,
TypeOrmModule.forRoot({ TypeOrmModule.forRoot({
type: 'postgres', type: 'postgres',
host: process.env.DB_HOST || 'localhost', host: process.env.DB_HOST || 'localhost',