ข้ามไปยังเนื้อหา

Dev vs Production Mode

Keycloak มีสองโหมดการเริ่มต้น: start-dev สำหรับ development และ start สำหรับ production ทั้งสองใช้แทนกันไม่ได้ — start-dev มีการประนีประนอมหลายอย่างที่ไม่ปลอดภัยสำหรับสภาพแวดล้อมจริง การเข้าใจความแตกต่างนี้สำคัญก่อนที่คุณจะก้าวข้ามการเรียนรู้บน local

start-dev ถูกออกแบบมาเพื่อให้เริ่มต้นได้รวดเร็ว โดยใช้ embedded H2 in-memory database (ข้อมูลจะหายเมื่อ restart), เปิดใช้ HTTP (ไม่มี TLS), ปิดการตรวจสอบ hostname และผ่อนปรน security checks หลายอย่าง ใช้โหมดนี้เฉพาะบน localhost ตอนเรียนรู้ Keycloak เท่านั้น

Terminal window
docker run --name keycloak -p 8080:8080 \
-e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
-e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \
quay.io/keycloak/keycloak:latest start-dev

start คือคำสั่งสำหรับ production ซึ่งต้องการ external database, hostname ที่แน่นอน และ HTTPS (หรือ reverse proxy ที่กำหนดค่าไว้) Keycloak จะปฏิเสธการ start ใน production mode หากไม่มีการกำหนดค่า hostname และ TLS ที่ถูกต้อง environment variable ที่สำคัญมีดังนี้:

Environment variablePurposeExample
KC_DBvendor ของ databasepostgres
KC_DB_URLJDBC connection URLjdbc:postgresql://db:5432/keycloak
KC_DB_USERNAMEชื่อผู้ใช้ DBkeycloak
KC_DB_PASSWORDรหัสผ่าน DBchangeme
KC_HOSTNAMEhostname สาธารณะของ Keycloakauth.example.com
KC_PROXY_HEADERSไว้วางใจ proxy headers (xforwarded หรือ forwarded)xforwarded
KC_HTTP_ENABLEDอนุญาต HTTP (จำเป็นเมื่อ proxy ทำ TLS termination)true
docker run --name keycloak -p 8080:8080 \
  -e KC_DB=postgres \
  -e KC_DB_URL=jdbc:postgresql://db:5432/keycloak \
  -e KC_DB_USERNAME=keycloak \
  -e KC_DB_PASSWORD=changeme \
  -e KC_HOSTNAME=auth.example.com \
  -e KC_PROXY_HEADERS=xforwarded \
  -e KC_HTTP_ENABLED=true \
  quay.io/keycloak/keycloak:latest start

สำหรับ production Keycloak แนะนำให้รัน kc.sh build (หรือ kc.bat build) ภายใน image ก่อนที่จะ start ซึ่งจะ pre-process configuration และลดเวลา startup ลงอย่างมาก Dockerfile สำหรับ production โดยทั่วไปใช้ two-stage build: stage หนึ่งรัน kc.sh build และอีก stage คัดลอก distribution ที่ build แล้วมารัน kc.sh start

Terminal window
# Stage 1: build
FROM quay.io/keycloak/keycloak:latest AS builder
RUN /opt/keycloak/bin/kc.sh build --db=postgres
# Stage 2: run
FROM quay.io/keycloak/keycloak:latest
COPY --from=builder /opt/keycloak/ /opt/keycloak/
ENTRYPOINT ["/opt/keycloak/bin/kc.sh", "start"]
ตัวเลือกBenefitCost
start-dev (development mode)Setup เร็ว ไม่ต้องมี TLS certificate, hostname หรือ external database — เหมาะกับการเรียนรู้และ local developmentไม่มี TLS, ข้าม hostname check, ใช้ in-memory H2 database ที่ข้อมูลหายทุกครั้งที่ restart — ใช้ใน production ไม่ได้
start (production mode)บังคับให้กำหนด TLS/hostname/database ให้ถูกต้องก่อน start ได้จริง ป้องกันการ deploy ที่ไม่ปลอดภัยโดยไม่ตั้งใจต้องเตรียม external database, certificate และ reverse proxy configuration ล่วงหน้า — setup ใช้เวลานานกว่า
  • รัน start-dev ใน production เพราะ setup ง่ายกว่า — ทีมที่รีบ deploy มักลืมสลับไปใช้ start ทำให้ระบบไม่มี TLS และข้อมูลอยู่ใน in-memory database ที่หายทุกครั้งที่ container restart
  • ลืมตั้งค่า KC_HOSTNAME ให้ตรงกับ domain จริง — ถ้า hostname ไม่ตรง token ที่ issue ออกมาจะมี issuer URL ผิด ทำให้แอปที่ validate token อย่างเข้มงวด reject token ทั้งหมด
  • เปิด KC_HTTP_ENABLED=true โดยไม่มี reverse proxy ทำ TLS termination จริง — ค่านี้ควรใช้เฉพาะเมื่อมี proxy อย่าง Nginx หรือ load balancer จัดการ TLS ให้แล้วเท่านั้น ไม่ใช่เปิดทิ้งไว้เฉยๆ บน public endpoint

💡 ตัวอย่างจากของจริง

องค์กรที่ทำ SSO consolidation — บริษัทที่มีแอปภายในหลายสิบระบบมักย้ายทุกแอปมาใช้ Keycloak instance เดียวใน production mode พร้อม external PostgreSQL และ TLS ผ่าน load balancer เพื่อให้พนักงาน login ครั้งเดียวเข้าทุกระบบ

Red Hat build of Keycloak (RH-SSO) — เวอร์ชัน supported ของ Red Hat ใช้หลักการเดียวกันคือบังคับ production mode configuration (DB, hostname, TLS) ก่อน deploy จริง เพื่อป้องกันลูกค้าตั้งค่าระบบแบบไม่ปลอดภัยโดยไม่ตั้งใจ

start-dev ใช้ database อะไร?
environment variable ใดที่กำหนด public hostname ใน production mode?
จุดประสงค์ของการรัน kc.sh build ก่อน kc.sh start ใน production คืออะไร?
ควรใช้ค่า KC_PROXY_HEADERS ใดเมื่อ Keycloak อยู่หลัง Nginx หรือ load balancer ที่ set X-Forwarded-* headers?