docker-keycloak-prod

version: '3.8'

services:
  # MySQL 数据库
  mysql:
    container_name: keycloak-mysql
    image: mysql:8.4
    command: [
      "--character-set-server=utf8mb4",
      "--collation-server=utf8mb4_unicode_ci",
      "--lower-case-table-names=1",
      "--innodb-buffer-pool-size=512M",
      "--max-connections=200",
      "--slow-query-log=1",
      "--long-query-time=2"
    ]
    ports:
      - "127.0.0.1:3306:3306"  # 只绑定到本地接口
    volumes:
      - mysql_data:/var/lib/mysql
      - ./mysql/conf.d:/etc/mysql/conf.d:ro
      - ./mysql/logs:/var/log/mysql
      - ./backup:/backup:ro
    environment:
      MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password
      MYSQL_DATABASE: keycloak
      MYSQL_USER: keycloak
      MYSQL_PASSWORD_FILE: /run/secrets/mysql_keycloak_password
      TZ: Asia/Shanghai
    secrets:
      - mysql_root_password
      - mysql_keycloak_password
    networks:
      - keycloak-internal
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "keycloak", "-p$$(cat /run/secrets/mysql_keycloak_password)"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 30s
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    deploy:
      resources:
        limits:
          memory: 1G
          cpus: '1.0'
        reservations:
          memory: 512M
          cpus: '0.5'

  # Keycloak 身份认证服务
  keycloak:
    container_name: keycloak-app
    image: quay.io/keycloak/keycloak:26.2.5-0
    depends_on:
      mysql:
        condition: service_healthy
    ports:
      - "8443:8443"  # 只暴露HTTPS端口
    volumes:
      - ./keycloak/conf:/opt/keycloak/conf:ro
      - ./keycloak/themes:/opt/keycloak/themes:ro
      - ./keycloak/providers:/opt/keycloak/providers:ro
      - keycloak_data:/opt/keycloak/data
      - /etc/localtime:/etc/localtime:ro
    environment:
      # 管理员配置
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD_FILE: /run/secrets/keycloak_admin_password
      
      # 数据库配置
      KC_DB: mysql
      KC_DB_USERNAME: keycloak
      KC_DB_PASSWORD_FILE: /run/secrets/mysql_keycloak_password
      KC_DB_URL: jdbc:mysql://mysql:3306/keycloak?useSSL=true&requireSSL=true&verifyServerCertificate=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
      
      # 生产环境配置
      KC_HOSTNAME: your-domain.com  # 替换为实际域名
      KC_HOSTNAME_STRICT: "true"
      KC_HOSTNAME_STRICT_HTTPS: "true"
      KC_HTTP_ENABLED: "false"
      KC_HTTPS_CERTIFICATE_FILE: /opt/keycloak/conf/tls.crt
      KC_HTTPS_CERTIFICATE_KEY_FILE: /opt/keycloak/conf/tls.key
      
      # 性能和缓存配置
      KC_CACHE: ispn
      KC_CACHE_STACK: kubernetes
      
      # 日志配置
      KC_LOG_LEVEL: INFO
      KC_LOG_CONSOLE_OUTPUT: json
      
      # 安全配置
      KC_SPI_TRUSTSTORE_FILE_FILE: /opt/keycloak/conf/truststore.p12
      KC_SPI_TRUSTSTORE_FILE_PASSWORD_FILE: /run/secrets/truststore_password
      
      # JVM 配置
      JAVA_OPTS_APPEND: >-
        -Xms512m -Xmx1024m
        -XX:MetaspaceSize=96M
        -XX:MaxMetaspaceSize=256m
        -Djava.net.preferIPv4Stack=true
        -Dfile.encoding=UTF-8
    secrets:
      - keycloak_admin_password
      - mysql_keycloak_password
      - truststore_password
    networks:
      - keycloak-internal
      - keycloak-external
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "curl -f https://localhost:8443/health/ready || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "5"
    deploy:
      resources:
        limits:
          memory: 1.5G
          cpus: '2.0'
        reservations:
          memory: 1G
          cpus: '1.0'
    command:
      - start
      - --optimized

  # Nginx 反向代理 (可选)
  nginx:
    container_name: keycloak-nginx
    image: nginx:1.25-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - ./ssl:/etc/ssl/certs:ro
      - nginx_logs:/var/log/nginx
    depends_on:
      - keycloak
    networks:
      - keycloak-external
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "nginx", "-t"]
      interval: 30s
      timeout: 10s
      retries: 3
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

# 网络配置
networks:
  keycloak-internal:
    driver: bridge
    internal: true  # 内部网络,不能访问外网
  keycloak-external:
    driver: bridge

# 数据卷
volumes:
  mysql_data:
    driver: local
  keycloak_data:
    driver: local
  nginx_logs:
    driver: local

# 密钥管理
secrets:
  mysql_root_password:
    file: ./secrets/mysql_root_password.txt
  mysql_keycloak_password:
    file: ./secrets/mysql_keycloak_password.txt
  keycloak_admin_password:
    file: ./secrets/keycloak_admin_password.txt
  truststore_password:
    file: ./secrets/truststore_password.txt

Last updated

Was this helpful?