hrms-manual/public/documents/chapter-4-superadmin-build-and-deploy.md
2024-11-11 10:47:04 +07:00

41 KiB

Deploy Document

เอกสารสำหรับการติดตั้งระบบของ BMA HRMS โปรแกรมในยุคปัจจุบันจะทำงานบนเทคโนโลยีคอนเทนเนอร์ เพื่อยืดหยุ่นในการทำงาน ตั้งแต่การพัฒนา ทดสอบและ ใช้งานจริง (Production) จำเป็นต้องเข้าใจการทำงาน Docker เสียก่อน เมื่อเข้าใจหลักการทำงานแล้ว ในอนาคตมีบริการเพิ่มเติมเข้ามาก็จะใช้รูปแบบเดียวกันในการตั้งค่า

ติดตั้ง Docker

Docker คอนเทนเนอร์สามารถเรียนรู้ ตั้งค่า ดูแล รักษาได้ง่ายและรวดเร็ว รองรับการขยายตัว สามารถเพิ่มคลัสเตอร์ได้ง่าย และสามารถปรับเปลี่ยนเป็น Kubernates ได้ในอนาคต สำหรับเอกสารนี้จะเป็นการติดตั้ง Docker บน debian 12 การติดตั้งโดยละเอียดดูได้จาก คู่มือในเวปของ Docker วิธีการติดตั้งแบบย่อผ่าน convenience script ทำตามวิธีการนี้

sudo apt install curl
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker user_name
sudo usermod -aG sudo user_name

แทน user_name ด้วยยูสเซอร์ที่ใช้ดูแลระบบ ในตัวอย่างให้สิทธิ์ sudo ด้วยเพื่อจะได้มีสิทธิ์ในจัดการไฟล์ที่เกิดจาก docker

คำสั่ง Docker พื้นฐาน

คำสั่งพื้นฐานของ docker ที่ใช้

docker ps       # ดูรายการคอนเทนเนอร์ที่รันอยู่ในระบบ
docker images   # ดูรายการอิมเมจที่มีในระบบ
docker pull [image_name:tag]        # ดึงอิมเมจมาในระบบ
docker network ls                   # แสดงรายการเน็ตเวิร์กของ docker
docker network crate [network_name] # สร้างเน็ตเวิร์กของ docker

docker compose จะรันคอนเทนเนอร์ของ docker หลายๆตัวพร้อมกันได้ โดยดูการตั้งค่าจากไฟล์ compose.yaml หรือ docker-compose.yaml ที่อยู่ในโฟลเดอร์ที่เรียกคำสั่ง ในการทำงานทั่วไปเพื่อที่จะให้ง่ายต่อการใช้งาน จะใช้ docker compose เป็นหลัก

คำสั่ง docker compose พื้นฐาน (ต้องมีไฟล์ compose ในโฟลเดอร์ที่เรียกคำสั่ง)

docker compose ps
docker compose up -d
docker compose up -d [service_name]

โฟลเดอร์ที่ใช้เริ่มต้นสร้างโปรแกรม บริการต่างๆในหัวข้อต่อๆไปจะสร้างภายใต้ ~/docker/hrms และใช้เน็ตเวิร์กชื่อ hrms ในการสื่อสารระหว่างกัน

docker network create hrms
mkdir -p ~/docker/hrms
cd ~/docker/hrms

ทดสอบการทำงานของ docker ให้สร้างโฟลเดอร์ simple-web มีไฟล์ compose.yaml สร้างโฟลเดอร์ html แล้วสร้างไฟล์ html/index.html ในโฟลเดอร์นั้นพร้อมเนื้อหาเรียกคำสั่ง docker compose up -d เป็นตัวอย่างแบบง่ายเพื่อใช้งาน nginx ไฟล์เวปเก็บในโฟลเดอร์ เปิดพอร์ต 9082 บนเครื่องโฮส ถ้าไม่สั่งหยุดการทำงานจะเริ่มเองถ้าโฮสเปิดขึ้นมาใหม่ ทำงานในเน็ตเวิร์ก hrms

mkdir -p simple-web/html
cd simple-web
nano compose.yaml
nano html/index.html

ไฟล์ compose.yaml

services:
  web:
    image: nginx
    volumes:
     - ./html:/usr/share/nginx/html:ro
    ports:
     - "9082:80"
    restart: unless-stopped
    networks:
      hrms:
networks:
  hrms:
    external: true

Services

การออกแบบใช้สถาปัตยกรรม Microservice จะประกอบจากหลาย Service เพื่อความเป็นระเบียบจะแบ่งไว้สามโฟลเดอร์ apisix(API Gateway), bmahrms-service(3rd Party service), bmahrms(HRMS services)

mkdir -P apisix
mkdir -p bmahrms-service/{edm_config,elasticsearch_config,init_mysql,keycloak_config,report-server-templates}
ืืmkdir -p bmahrms-service/report-server-templates/{docx,xlsx}
mkdir -p bmahrms

APISIX

ทำหน้าที่จัดการ https, limit, security, load balance,reverse proxy, และ route ใน Microservice ก่อนใช้งานให้ตั้งค่าโดเมนกับ Public IP ให้เรียบร้อยแล้ว Forward Port 80/443 มาที่เครื่องนี้ การตั้งค่า route จะทำผ่าน curl(Web API)

mkdir -p apisix/apisix_conf/
nano apisix/apisix_conf/config.yaml # configuration
nano apisix/compose.yaml            # compose file
docker compose up -d

apisix/apisix_conf/config.yaml เป็นไฟล์คอนฟิกของ APISIX แก้ค่า put_admin_api_key_here, allow_admin ให้เหมาะสม

apisix:
  node_listen: 9080              # APISIX listening port
  enable_ipv6: false
  enable_control: true
  control:
    ip: "0.0.0.0"
    port: 9092
deployment:
  admin:
    allow_admin:               # https://nginx.org/en/docs/http/ngx_http_access_module.html#allow
      - 0.0.0.0/0              # We need to restrict ip access rules for security. 0.0.0.0/0 is for test.
    admin_key:
      - name: "admin"
        key: put_admin_api_key_here
        role: admin                 # admin: manage all configuration data
  etcd:
    host:                           # it's possible to define multiple etcd hosts addresses of the same etcd cluster.
      - "http://etcd:2379"          # multiple etcd address
    prefix: "/apisix"               # apisix configurations prefix
    timeout: 30                     # 30 seconds
plugin_attr:
  prometheus:
    export_addr:
      ip: "0.0.0.0"
      port: 9091

apisix/compose.yaml >

services:
  apisix:
    image: apache/apisix:${APISIX_IMAGE_TAG:-3.9.0-debian}
    restart: always
    environment:
      - TZ=Asia/Bangkok
    volumes:
      - ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro
    depends_on:
      - etcd
    ports:
      - "9180:9180/tcp"
      - "80:9080/tcp"
      - "9091:9091/tcp"
      - "443:9443/tcp"
      - "9092:9092/tcp"
    networks:
      hrms:
      apisix:
  etcd:
    image: bitnami/etcd:3.5.11
    restart: always
    volumes:
      - etcd_data:/bitnami/etcd
    environment:
      ETCD_ENABLE_V2: "true"
      ALLOW_NONE_AUTHENTICATION: "yes"
      ETCD_ADVERTISE_CLIENT_URLS: "http://etcd:2379"
      ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2379"
      TZ: "Asia/Bangkok"
    ports:
      - "2379:2379/tcp"
    networks:
      apisix:
networks:
  hrms:
    external: true
  apisix:
    driver: bridge

volumes:
  etcd_data:
    driver: local

วิธีการติดตั้ง certificate(HTTPS) เนื่องจากของ *bangkok.go.th มี intermediate certificate ให้นำ root CA รวมกับ intermediate เพื่อให้พร้อมใช้งาน การตั้งค่า APISIX จะทำผ่าน Web API ใช้ curl และ api-key ที่ตั้งไว้

cat star_bangkok.go.th_2024.crt 'GeoTrust TLS RSA CA G1.crt' >  star_bangkok.go.th_2024.ca-bundle
# ใส่ใน APISIX
curl http://127.0.0.1:9180/apisix/admin/ssls/1 \
-H 'X-API-KEY: put_admin_api_key_here' -X PUT -d '
{
     "cert" : "'"$(cat star_bangkok.go.th_2024.ca-bundle)"'",
     "key": "'"$(cat star_bangkok.go.th_2024.key)"'",
     "snis": ["*.bangkok.go.th"]
}'

ถ้ามีการเซ็ต route ผ่าน APISIX สามารถทดสอบ ผ่าน curl ได้ด้วยคำสั่งนี้(การเซ็ตค่าจะอยู่ในหัวข้ออื่น)

curl https://bma-hrms-id.bangkok.go.th -vvv

3rd Party Service (bmahrms-service)

โปรแกรมที่พัฒนาโดย 3rd Party หรือ Frappet ถูกใช้โดยโปรแกรมของ HRMS จะแยกมาใส่โฟลเดอร์ bmahrms-service การติดตั้งให้นำ compose.yaml และ คอนฟิกมาใส่โฟลเดอร์ bmahrms-service ให้เรียบร้อยก่อนใช้งาน สร้างโฟลเดอร์แต่ละ servie ทำดังนี้

  • Keycloak(bmahrms-postgres bmahrms-id) เซิร์ฟเวอร์สำหรับจัดการยูสเซอร์และการ Authentication ในระบบ
  • MySQL(bmahrms-mysql) เป็นฐานข้อมูลของระบบ
  • MiniO(bmahrms-s3) เป็น Object Storage ใช้สำหรับเก็บไฟล์ประสิทธิ์ภาพสูงสามารถรับโหลดหนัก การเรียกใช้รวมเร็วปลอดภัยกว่าระบบไฟล์ทั่วไป สามารถขยายเพิ่มได้ในอนาคต ถูกใช้ในหลายระบบที่ต้องการเก็บไฟล์
  • Windmill รันโฟลว์การทำงานอัตโนมัติจากสคริปต์ หลักๆใช้เพื่อรันตัวสำรองข้อมูล
  • Portainer(bmahrms-portainer) ระบบจัดการ container มี UI ใช้งานง่าย
  • RabbitMQ(bmahrms-mq) ระบบจัดคิวในการสือสารใน Microservice ทำให้รับโหลดหนักๆในช่วงเวลาสั้นๆได้ เช่นระบบการลงเวลา EDM
  • Frappet Report Server(bmahrms-report-server) ใช้สำหรับสร้างรายงานจากเอกสารต้นแบบที่ออกแบบเองได้ ส่งออกเป็น docx, xlsx, pdf
  • Frappet EDM(bmahrms-edm,bmahrms-elasticsearch,bmahrms-kibana,bmahrms-mq) ใช้สำหรับจัดการเอกสารที่ปลอดภัยรองรับโหลดจำนวนมากได้ จะมีระบบย่อยเบื่องหลังหลายตัว

docker/bmahrms-service/compose.yaml

networks:
  hrms:
    external: true
#clear all volume: docker volume rm $(docker volume ls -q | grep bmahrms-service)
# clear one volume docker volume rm bmahrms-service_mysql_data
volumes:
  keycloak_data:
  minio_data: {}
  rabbitmq_data:
  elasticsearch_data:
  postgres_data:
  mysql_data:
  kibana_data: 
services:    
  bmahrms-id:
    image: quay.io/keycloak/keycloak:22.0.0
    restart: unless-stopped
    env_file: "service.env"
    depends_on:
      - bmahrms-postgres
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - keycloak_data:/opt/keycloak/data
      - ./keycloak_config:/keycloak_config:ro
    command:
      - start-dev
      - --features=token-exchange
      - --https-certificate-file=/keycloak_config/keycloak.crt 
      - --https-certificate-key-file=/keycloak_config/keycloak.pem
      - --http-enabled=true
    networks:
      - hrms
  bmahrms-postgres:
    image: postgres:15.3
    restart: unless-stopped
    env_file: "service.env"    
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - hrms
  bmahrms-s3:
    image: minio/minio:RELEASE.2024-07-16T23-46-41Z
    env_file: "service.env"
    # mem_limit: "1g"
    restart: unless-stopped
    command: server --console-address ":9001"(bmahrms-postgres bmahrms-id)  /data
    volumes:
      - minio_data:/data
    networks:
      - hrms
  bmahrms-mq:
    image: rabbitmq:3-management-alpine
    env_file: "service.env"
    mem_limit: "1g"
    restart: unless-stopped
    environment:
      - TZ=Asia/Bangkok
      - RABBITMQ_DEFAULT_USER=admin
      - RABBITMQ_DEFAULT_PASS=MQ_PASSWORD
    ports:
      - 5672:5672
      # - 9122:15672 # UI
    volumes:
      - rabbitmq_data:/var/lib/rabbitmq/
    networks:
      - hrms
  bmahrms-mysql:
    image: mysql:8.0.17
    env_file: "service.env"
    command: [ "--max_connections=5000" ]
    restart: unless-stopped
    ports:
      - "9123:3306"
    volumes:
      - mysql_data:/var/lib/mysql
      - ./init_mysql:/docker-entrypoint-initdb.d/:ro
    networks:
      - hrms
  bmahrms-report-server:
    image: docker.frappet.com/demo/report-server:latest
    restart: unless-stopped
    mem_limit: 1000m
    volumes:
      - ./report-server-templates:/app/templates
    networks:
      - hrms
  bmahrms-elasticsearch:
    image: docker.frappet.com/core/elasticsearch-icu:8.14.3
    env_file: "service.env" 
    mem_limit: "4g"
    volumes:
      - elasticsearch_data:/usr/share/elasticsearch/data
      - ./elasticsearch_config/config.yaml:/usr/share/elasticsearch/config/elasticsearch.yml
    restart: unless-stopped
    # disable ulimits for Proxmox LXC
    # ulimits:
    #   memlock:
    #     soft: -1
    #     hard: -1
    networks:
      - hrms
  bmahrms-kibana:
    image: docker.elastic.co/kibana/kibana:8.14.3
    env_file: "service.env" 
    depends_on:
      - bmahrms-elasticsearch
    volumes:
      - kibana_data:/usr/share/kibana/data
    ports:
     - 2130:5601
    restart: always
    networks:
      - hrms
  bmahrms-edm:
    image: docker.frappet.com/edm/core
    restart: unless-stopped
    volumes:
      - ./edm_config/keycloak.json:/app/static/keycloak.json:ro
    environment:
      - PUBLIC_KEY=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvfonxaaTELBLHYHTUxateIYMdjGP/yKuzTnNmuinplH2e0QbDJ2q7NsQh2X0YndiQ1uJEU5dFWWFi1D8TEnoVmqW7dxoQ1yXdNB1GvUbhgdT2btoRzzbXeluIVM2oNPtTHu5q5yhnEq/3ldWIkJwQjEkoKv50biDUSTxA0c/R3BLTIMIO6ZUe4ael06e34iSxdP3Dyw3IKTEHaqG1d37SMhfaZ25lA8QGjygiq733l2PfBiVgnjqcy+uvyXkWTjthTNSic3eaSXiIEtxyC4kAGrR/3qClZC8JEgf6mOFmoHna/eSStYodCTOj7SVUmujlMyvE8mGI9BslU/n4RLCuQIDAQAB
      - REALM_URL=https://bma-hrms-id.bangkok.go.th/realms/EDM
      - PREFERRED_AUTH=online
      - MANAGEMENT_ROLE=doc-management
      - MINIO_HOST=bmahrms-s3.bangkok.go.th
      - MINIO_PORT=443
      - MINIO_SSL=true
      - MINIO_ACCESS_KEY=dIYTJ2nXmD9cDln7yrwE
      - MINIO_SECRET_KEY=pENPrGWpkngbLHnPBBh0dp2BoMQL5KZH60MucN6I
      # Bucket notification event needed to be configured
      # Can use prepare script to create bucket
      - MINIO_BUCKET=edm
      - ELASTICSEARCH_PROTOCOL=http
      - ELASTICSEARCH_HOST=bmahrms-elasticsearch
      - ELASTICSEARCH_PORT=9200
      # Can use prepare script
      - ELASTICSEARCH_INDEX=edm-index
      - AMQ_URL=amqp://admin:admin123456@bmahrms-mq:5672
      - AMQ_QUEUE=edm
      - NODE_TLS_REJECT_UNAUTHORIZED=false
    extra_hosts:
      - bma-hrms-id.bangkok.go.th:192.168.2.101
    depends_on:
      - bmahrms-postgres

    networks:
      - hrms
  bmahrms-portainer:
    image: portainer/portainer-ce:2.20.3
    volumes:
      - portainer_data:/data
      - /var/run/docker.sock:/var/run/docker.sock
    restart: unless-stopped
    networks:
      - hrms

รันคำสั่งดังนี้ในตัวอย่างเรียกใช้งาน Keycloak จะใช้ 2 service ตัวอย่างนี้จะเรียกใช้ฐานข้อมูลแล้วค่อยเรียกใช้โปรแกรม keycloak

docker compose up -d bmahrms-postgres 
docker compose up -d bmahrms-id

BMA HRMS Service

ระบบที่พัฒนาเพื่อ HRMS โดยเฉพาะ จะมี 3 ไฟล์

  • be.env ค่าคอนฟิกของ Backend
  • fe.env ค่าตอนฟิกของ Frontend
  • compose.yaml คอนฟิกของ Docker

โปรแกรม Frntend เป็นส่วนของหน้าเวปเพื่อใช้งาน

  • bmahrms เว็บไซต์สำหรับ Officer
  • bmahrms-user เว็บไซต์ ระบบบริการเจ้าของข้อมูล
  • bmahrms-admin ระบบ Admin
  • bmahrms-checkin เว็บไซต์ ระบบลงเวลา
  • bmahrms-publish เว็บไซต์ เผยแพร่ผลงาน
  • bmahrms-candidate-register เว็บไซต์สำหรับรับสมัครสอบคัดเลือก
  • bmahrms-qualifying-exam-cms เว็บไซต์ศูนย์ข้อมูลการสรรหาบุคคลของกรุงเทพมหานคร(CMS)
  • bmahrms-manual ระบบคู่มือ
  • bmahrms-faq เว็บไซต์ FAQ
  • bmahrms-logs-n-backup Backup and Logs

โปรแกรม Backend ถูกเรียกใช้โดย Frontend อีกที

  • bmahrms-report
  • bmahrms-recruit
  • bmahrms-insignia
  • bmahrms-recruit-exam
  • bmahrms-org-employee
  • bmahrms-placement
  • bmahrms-retirement
  • bmahrms-report-v2
  • bmahrms-probation
  • bmahrms-command
  • bmahrms-discipline
  • bmahrms-evaluation
  • bmahrms-leave
  • bmahrms-org
  • bmahrms-salary
  • bmahrms-development
  • bmahrms-kpi

docker/bmahrms/fe.env แก้ตัวแปร VITE_CLIENTSECRET_KEYCLOAK KC_SERVICE_ACCOUNT_SECRET

# Frontend Global
TZ=Asia/Bangkok
VITE_COMPETITIVE_EXAM_PANEL=https://bma-hrms-dashboard.bangkok.go.th/goto/KO0GpSu4z?orgId=1
VITE_QUALIFY_DISABLE_EMAM_PANEL=https://bma-hrms-dashboard.bangkok.go.th/goto/dQQzpIX4z?orgId=1
VITE_QUALIFY_EXAM_PANEL=https://bma-hrms-dashboard.bangkok.go.th/goto/cj1ZtIX4z?orgId=1
VITE_S3CLUSTER_PUBLIC_URL=https://bma-hrms-s3.bangkok.go.th/bma-ehr-fpt/organization/strueture/
VITE_REALM_KEYCLOAK=bma-ehr
VITE_URL_KEYCLOAK=https://bma-hrms-id.bangkok.go.th
VITE_CLIENTID_KEYCLOAK: "gettoken"
VITE_CLIENTSECRET_KEYCLOAK: put_client_secret_keycloak_here
VITE_API_REPORT_URL=https://bma-hrms.bangkok.go.th/api/v1/report-template
# เผยแพร่ผลงาน
VITE_API_PUBLISH_URL=https://bma-hrms-publish.bangkok.go.th

# Admin 
VITE_API_URI_CONFIG=https://bma-hris.bangkok.go.th/api/v1
KC_URL=https://bma-hrms-id.bangkok.go.th
KC_REALM=bma-ehr
KC_SERVICE_ACCOUNT_CLIENT_ID=bma-ehr-dev
KC_SERVICE_ACCOUNT_SECRET=put_service_account_secret_here
MANAGEMENT_ROLE=storage_management

docker/bmahrms/be.env แก้ค่าของ DB_PASSWORD,AUTH_PUBLIC_KEY, MINIO_KEY, MINIO_SECRET, STORAGE_SECRET,KC_SERVICE_ACCOUNT_SECRET,REDIS_HOST,KEYCLOAK_KEY,AUTH_PUBLIC_KEY, PUBLIC_KEY

# Backend Global
TZ=Asia/Bangkok
ASPNETCORE_ENVIRONMENT=Development
APP_HOST=0.0.0.0
APP_PORT=80
HOST=0.0.0.0
PORT=80
DB_HOST=bmahrms-mysql
DB_PORT=3306
DB_USERNAME=root
DB_NAME=bma_ehr_organization_demo 
DB_PASSWORD=DB_PASSWORD
AUTH_REALM_URL=https://bmahrms-id.bangkok.go.th/realms/bma-ehr
AUTH_PUBLIC_KEY=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkOrQxwoFeJE5TPXeSGL8IRDYVEL1OzmBuywNAzsL9vdcDUrjRA+Ocfp1pwLxXbNPacIgVmP1G+Cf3Steyp5ZeYAGL3u/MRHhUZA1tRbJ9sT+i/JzubmJCs9uF2pV9dLyT6kP7ZjKXmFBzHcXTS/GZMRtz8HZjB6ZzegFtV2oIrQq4+zo4BlzIAI6vaZfKn/JrTjJEbti0RQcqWfIldE918SQvZHzi3Upgn+OBopSRCrF7z3a7FEjYI1Vny42f5dBUcAmDDxOKqoJN09ArYchWkiDGvfpVarsclodptAGKwLuIDwDm9T9cnBUcBzWKNkwpQD3LvydOFVJRBqHAOrfEQIDAQAB
AUTH_PREFERRED_MODE=online
API=https://bma-hrms.bangkok.go.th/api/v1/
SECRET_KEY=put_secret_key_here
MINIO_HOST=https://bmahrms-s3.bangkok.go.th
MINIO_PORT=9000
MINIO_ACCESS_KEY=MINIO_KEY
MINIO_SECRET_KEY=MINIO_SECRET
MINIO_BUCKET=bma-ehr-fpt
API_URL=https://bmahrms.bangkok.go.th/api/v1
STORAGE_URL=https://bmahrms-edm.bangkok.go.th/api
STORAGE_REALM_URL=https://edm-id.bangkok.go.th/realms/EDM
STORAGE_SECRET=put_storage_secret_here
KC_URL=https://bmahris-id.bangkok.go.th
KC_REALM=bma-ehr
KC_SERVICE_ACCOUNT_CLIENT_ID=bma-ehr-dev
KC_SERVICE_ACCOUNT_SECRET=put_account_secret_here
MANAGEMENT_ROLE=storage_management
REDIS_HOST=192.168.1.81
REDIS_PORT=6379

KEYCLOAK_URL=https://bma-hrms-id.bangkok.go.th/realms/bma-ehr
KEYCLOAK_KEY=CNnpzJkwbk7jvI5Lb6gP5_Ok0WpDJJ50Mn0aD55Bd5E
KEYCLOAK_REALM=bma-ehr

PUBLIC_KEY=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvYg0ZJvH6HgNOzyPp7PCvY3bJwD9WdsNn6gZbuvIfqJQZ8iSH1t0p3fgODO/fqwcj9UFeh1bVFOSjuW+JpnPehROqzt81KNl9zLLNXoN4LimReQHaMM3dU7DCbRylgVCouIDvObyjg8G+Cy5lZvFKWym/DPwGVpSdbvDZJ83qxq2dp7GJXS8PhOvA+MB1K009/jW5pBTUwNArLjoFccr+gIYIiOJDg2rYyIF3fDkwyWkuxr6xRt10+BRJytselwy/18kbDuJxVPaapdgTXI6wLzx7HWcDk30n5EvhJEumnIPpRst8gucqNYmB4MH+vsyoxV5WLuO3qmVRzFbtAppRQIDAQAB
REALM_URL=https://bmahrms-id.bangkok.go.th/realms/bma-ehr
PREFERRED_MODE=online
PREFERRED_AUTH=online

ELASTICSEARCH_PROTOCOL=http
ELASTICSEARCH_HOST=bmahrms-elasticsearch
ELASTICSEARCH_PORT=9200
ELASTICSEARCH_INDEX=bma-ehr-log-index

docker/bmahrms/compose.yaml

networks:
  hrms:
    external: true
services:
  # Start Frontend Section
  # เว็บไซต์สำหรับ Officer
  bmahrms:
    container_name: bmahrms
    image: docker.frappet.com/ehr/bma-ehr-app:latest
    restart: always
    env_file: "fe.env"
    ports:
      - "6021:80"
    networks:
      - hrms
  # เว็บไซต์สำหรับรับสมัครสอบคัดเลือก
  bmahrms-candidate-register:
    image: docker.frappet.com/ehr/bma-ehr-recruit-exam:latest
    container_name: bmahrms-candidate-register
    env_file: "fe.env"
    restart: always
    environment:
      VITE_API_URI_CONFIG: "https://bmahrms.bangkok.go.th/api"
      VITE_CLIENTID_KEYCLOAK: "bma-ehr-exam-vue3"
    ports:
      - "6022:80"
    networks:
      - hrms
  # เว็บไซต์ศูนย์ข้อมูลการสรรหาบุคคลของกรุงเทพมหานคร(CMS)
  # CMS ระบบสมัครสอบ
  bmahrms-qualifying-exam-cms:
    image: docker.frappet.com/demo/qualifying-exam-cms:latest
    container_name: bmahrms-qualifying-exam-cms
    restart: always
    env_file: "fe.env"
    ports:
      - "6023:80"
    environment:
      API_CMS_URL: "https://bmahrms.bangkok.go.th/api/v1/cms"
      API_QUALIFYING_URL: "https://bmahrms.bangkok.go.th/api/v1/cms"
      API_COMPETITIVE_URL: "https://bmahrms.bangkok.go.th/api/v1/recruit"
      PUBLIC_URL_REGISTER_QUALIFY_EXAM: "https://bmahrms-apply.bangkok.go.th"
    networks:
      - hrms
  # ระบบคู่มือ
  bmahrms-manual:
    image: docker.frappet.com/ehr/bma-ehr-manual:latest
    container_name: bmahrms-manual
    restart: always
    env_file: "fe.env"
    ports:
      - "6024:80"
    networks:
      - hrms
  # เว็บไซต์ ระบบบริการเจ้าของข้อมูล
  bmahrms-user:
    image: docker.frappet.com/ehr/bma-ehr-user:latest
    container_name: bmahrms-user
    restart: always
    env_file: "fe.env"
    ports:
      - "6025:8087"
    networks:
      - hrms
  # เว็บไซต์ ระบบลงเวลา
  bmahrms-checkin:
    image: docker.frappet.com/ehr/bma-ehr-checkin:latest
    container_name: bmahrms-checkin
    restart: always
    env_file: "fe.env"
    ports:
      - "6026:80"
    networks:
      - hrms
  # เว็บไซต์ เผยแพร่ผลงาน
  bmahrms-publish:
    image: docker.frappet.com/ehr/bma-ehr-publish:latest
    container_name: bmahrms-publish
    restart: always
    env_file: "fe.env"
    ports:
      - "6027:80"
    environment:
      VITE_API_URI_CONFIG: "https://bmahrms.bangkok.go.th/api/v1"
      VITE_API_PUBLISH_URL: "https://bmahrms.bangkok.go.th/api/v1/evaluation"
    networks:
      - hrms
  # เว็บไซต์ FAQ
  bmahrms-faq:
    image: docker.frappet.com/ehr/bma-ehr-faq:latest
    container_name: bmahrms-faq
    restart: always
    env_file: "fe.env"
    ports:
      - "6028:80"
    networks:
      - hrms
  # ระบบ Admin
  bmahrms-admin:
    container_name: bmahrms-admin
    image: docker.frappet.com/ehr/bma-ehr-admin:latest
    env_file: "fe.env"
    restart: always
    ports:
      - "6029:8086"
    environment:
      VITE_CLIENTID_KEYCLOAK: "HRIS_ADMIN"
      VITE_API_URI_CONFIG: "https://bma-hrms.bangkok.go.th/api/v1"
      KC_REALM: "bma-ehr"
      KC_SERVICE_ACCOUNT_CLIENT_ID: "bma-ehr-dev"
      KC_SERVICE_ACCOUNT_SECRET: "f2mp7Xj4nz6gbgITve9J7AHXZI8dRhOd"
      MANAGEMENT_ROLE: "storage_management"
    networks:
      - hrms
  # Backup and Logs
  bmahrms-logs-n-backup:
    container_name: bmahrms-logs-n-backup
    image: docker.frappet.com/ehr/bma-ehr-log-backup:latest
    restart: always
    env_file: "fe.env"
    ports:
      - 6030:3000
    environment:
      - KC_REALM_URL=https://bma-hrms-id.bangkok.go.th/realms/bma-ehr
      - ELASTICSEARCH_PROTOCOL=http
      - ELASTICSEARCH_HOST=192.168.1.40
      - ELASTICSEARCH_PORT=9200
      - ELASTICSEARCH_INDEX=bma-ehr-log-dotcom-index
      - APP_HOST=0.0.0.0
      - APP_PORT=3000
      - WINDMILL_URL=http://host.docker.internal:20001
      - WINDMILL_WORKSPACE=bma-ehr
      - WINDMILL_BACKUP_FLOW_PATH=f/flow/full_backup_s3_mysql
      - WINDMILL_RESTORE_FLOW_PATH=f/flow/full_restore_s3_mysql
      - WINDMILL_BACKUP_DELETE_SCRIPT_PATH=f/flow/delete_backup_s3_mysql
      - WINDMILL_BACKUP_LIST_SCRIPT_PATH=f/flow/list_backup_s3_mysql
      - WINDMILL_API_KEY=I843JmwwcRKouMnE1DkTBRjiKl6yzkXM
      - DB_HOST="bma-mysql-ehr"
      - DB_PORT=3306
      - DB_USERNAME=root
      - DB_PASSWORD=adminVM123
      - DB_LIST=bma_ehr,bma_ehr_development,bma_ehr_discipline,bma_ehr_evaluation,bma_ehr_exam,bma_ehr_history,bma_ehr_kpi,bma_ehr_leave,bma_ehr_organization,bma_ehr_probation,bma_ehr_salary,bma_ehr_support,bma_recruit
      - MAIN_MINIO_USE_SSL=true
      - MAIN_MINIO_HOST=bma-hrms-s3.bangkok.go.th
      - MAIN_MINIO_PORT=443
      - MAIN_MINIO_ACCESS_KEY=put_minio_access_key_here
      - MAIN_MINIO_SECRET_KEY=put_minio_secret_key_here
      - MAIN_MINIO_BUCKET=bma-ehr-fpt
      - BACKUP_MINIO_USE_SSL=true
      - BACKUP_MINIO_HOST=bma-hrms-s3.bangkok.go.th
      - BACKUP_MINIO_PORT=443
      - BACKUP_MINIO_ACCESS_KEY=put_backup_minio_access_key_here
      - BACKUP_MINIO_SECRET_KEY=put_backup_minio_secret_key_here
      - BACKUP_MINIO_BUCKET=bma-ehr-fpt-backup-dotcom
    extra_hosts:
      - host.docker.internal:host-gateway
    networks:
      - hrms
  # End Frontend Section

  # Start Backend Section
  bmahrms-report:
    image: docker.frappet.com/ehr/bma-ehr-report-service:latest
    container_name: bmahrms-report
    env_file: "be.env"
    restart: always
    # ports:
    #   - "7020:80"
    volumes:
      - ./wwwroot:/app/wwwroot
      - ./appsettings-report.json:/app/appsettings.json
      - ./appsettings-report.json:/app/appsettings.Development.json
    networks:
      - hrms

  bmahrms-recruit:
    container_name: bmahrms-recruit
    image: docker.frappet.com/ehr/bma-ehr-recruit-service:latest
    restart: always
    env_file: "be.env"
    # ports:
    #   - "7021:80"
    volumes:
      - ./wwwroot:/app/wwwroot
      - ./appsettings-recruit.json:/app/appsettings.json
      - ./appsettings-recruit.json:/app/appsettings.Development.json
    networks:
      - hrms

  bmahrms-insignia:
    image: docker.frappet.com/ehr/bma-ehr-insignia-service:latest
    container_name: bmahrms-insignia
    restart: always
    env_file: "be.env"
    # ports:
    #   - "7022:80"
    volumes:
      - ./wwwroot:/app/wwwroot
      - ./appsettings-combine.json:/app/appsettings.json
      - ./appsettings-combine.json:/app/appsettings.Development.json
    networks:
      - hrms

  bmahrms-recruit-exam:
    image: docker.frappet.com/ehr/bma-ehr-recruit-exam-service:latest
    container_name: bmahrms-recruit-exam
    restart: always
    env_file: "be.env"
    # ports:
    #   - "7023:80"
    volumes:
      - ./wwwroot:/app/wwwroot
      - ./appsettings-recruit-exam.json:/app/appsettings.json
      - ./appsettings-recruit-exam.json:/app/appsettings.Development.json
    networks:
      - hrms

  bmahrms-org-employee:
    image: docker.frappet.com/ehr/bma-ehr-org-employee-service:latest
    container_name: bmahrms-org-employee
    restart: always
    env_file: "be.env"
    # ports:
    #   - "7024:80"
    volumes:
      - ./wwwroot:/app/wwwroot
      - ./appsettings-combine.json:/app/appsettings.json
      - ./appsettings-combine.json:/app/appsettings.Development.json
    networks:
      - hrms

  bmahrms-placement:
    image: docker.frappet.com/ehr/bma-ehr-placement-service:latest
    container_name: bmahrms-placement
    restart: always
    env_file: "be.env"
    # ports:
    #   - "7025:80"
    volumes:
      - ./wwwroot:/app/wwwroot
      - ./appsettings-combine.json:/app/appsettings.json
      - ./appsettings-combine.json:/app/appsettings.Development.json
    networks:
      - hrms

  bmahrms-retirement:
    image: docker.frappet.com/ehr/bma-ehr-retirement-service:latest
    container_name: bmahrms-retirement
    restart: always
    env_file: "be.env"
    # ports:
    #   - "7026:80"
    volumes:
      - ./wwwroot:/app/wwwroot
      - ./appsettings-combine.json:/app/appsettings.json
      - ./appsettings-combine.json:/app/appsettings.Development.json
    networks:
      - hrms

  bmahrms-report-v2:
    image: docker.frappet.com/ehr/bma-ehr-report-v2-service:latest
    container_name: bmahrms-report-v2
    restart: always
    env_file: "be.env"
    # ports:
    #   - "7027:80"
    volumes:
      - ./wwwroot:/app/wwwroot
      - ./appsettings-report-v2.json:/app/appsettings.json
      - ./appsettings-report-v2.json:/app/appsettings.Development.json
    networks:
      - hrms

  bmahrms-probation:
    image: docker.frappet.com/ehr/bma-ehr-node-service:latest
    container_name: bmahrms-probation
    restart: always
    env_file: "be.env"
    # ports:
    #   - "7028:80"
    environment:
      DB_NAME: "bma_ehr_probation"
    networks:
      - hrms

  bmahrms-command:
    image: docker.frappet.com/ehr/bma-ehr-command-service:latest
    container_name: bmahrms-command
    restart: always
    env_file: "be.env"
    # ports:
    #   - "7029:80"
    volumes:
      - ./wwwroot:/app/wwwroot
      - ./appsettings-combine.json:/app/appsettings.json
      - ./appsettings-combine.json:/app/appsettings.Development.json
    networks:
      - hrms

  bmahrms-discipline:
    image: docker.frappet.com/ehr/bma-ehr-discipline-service:latest
    container_name: bmahrms-discipline
    restart: always
    # env_file: "be.env"
    # ports:
    #   - "7030:80"
    volumes:
      - ./wwwroot:/app/wwwroot
      - ./appsettings-combine.json:/app/appsettings.json
      - ./appsettings-combine.json:/app/appsettings.Development.json
    networks:
      - hrms

  bmahrms-evaluation:
    image: docker.frappet.com/ehr/bma-ehr-evaluation-service:latest
    container_name: bmahrms-evaluation
    restart: always
    env_file: "be.env"
    # ports:
    #   - "7031:80"
    environment:
      DB_NAME: "bma_ehr_evaluation"
    networks:
      - hrms

  bmahrms-leave:
    image: docker.frappet.com/ehr/bma-ehr-leave-service:latest
    container_name: bmahrms-leave
    restart: always
    env_file: "be.env"
    # ports:
    #   - "7032:80"
    volumes:
      - ./wwwroot:/app/wwwroot
      - ./appsettings-combine.json:/app/appsettings.json
      - ./appsettings-combine.json:/app/appsettings.Development.json
    networks:
      - hrms

  bmahrms-org:
    image: docker.frappet.com/ehr/bma-ehr-org-service:latest
    container_name: bmahrms-org
    restart: always
    env_file: "be.env"
    # ports:
    #   - "7033:80"
    environment:
      DB_NAME: "bma_ehr_organization"
    networks:
      - hrms

  bmahrms-salary:
    image: docker.frappet.com/ehr/bma-ehr-salary-service:latest
    container_name: bmahrms-salary
    restart: always
    env_file: "be.env"
    # ports:
    #   - "7034:80"
    environment:
      DB_NAME: "bma_ehr_salary"
    networks:
      - hrms

  bmahrms-development:
    image: docker.frappet.com/ehr/bma-ehr-development-service:latest
    container_name: bmahrms-development
    restart: always
    env_file: "be.env"
    # ports:
    #   - "7035:80"
    environment:
      DB_NAME: "bma_ehr_development"
    networks:
      - hrms

  bmahrms-kpi:
    image: docker.frappet.com/ehr/bma-ehr-kpi-service:latest
    container_name: bmahrms-kpi
    restart: always
    env_file: "be.env"
    # ports:
    #   - "7036:80"
    environment:
      DB_NAME: "bma_ehr_kpi"
    networks:
      - hrms
  # End Backend Section

Configuration

การตั้งค่าเฉพาะของแต่ละ service และการตั้งค่า route การตั้งค่า route ส่วนใหญ่จะทำคล้ายๆกัน ส่วนที่เป็น Frontend จะเป็นการเซ็ตโดเมน(URL)ของแต่ละโปรแกรม ส่วนที่เป็น Backend จะเป็นการรวมหลาย backend เข้าในโดเมนเดียวกันแต่อยู่คนละ Subfolder ซึ่งเป็นการรวม Microservice เข้าด้วยกัน

keycloak (bmahrms-id)

ใช้สำหรับการ login ในระบบ (Identity Server) การสือสารหลัง API Gateway จะเป็น https แบบ self-signed

cd bmahrms-service/keycloak_config
openssl genrsa -out keycloak.key 2048
openssl req -new -x509 -sha256 -key keycloak.key -out keycloak.crt -days 3650
cp keycloak.key keycloak.pem
cat keycloak.crt >> keycloak.pem
cd ..

Keycloak Route

curl "http://127.0.0.1:9180/apisix/admin/routes" \
-H "X-API-KEY: put_admin_api_key_here" -X PUT -d '
{
  "id": "bmahrms-id",
  "host": "bma-hrms-id.bangkok.go.th",
  "uri": "/*",
  "upstream": {
    "scheme": "https",
    "type": "roundrobin",
    "nodes": {
      "bmahrms-id:8443": 1
    }
  }
}'

Portainer ()

เป็นโปรแกรมสำหรับบริหารจัดการ container สามารถสิ่งเปิดปิดแก้ไขการทำงานของคอนเทนเนอร์ได้ เฉพาะผู้ดูแลระดับสูงถึงจะเข้าใช้งานส่วนนี้

curl "http://127.0.0.1:9180/apisix/admin/routes" \
-H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f2" -X PUT -d '
{
  "id": "bmahrms-portainer",
  "host": "bmahrms-portainer.bangkok.go.th",
  "uri": "/*",
  "upstream": {
    "type": "roundrobin",
    "nodes": {
      "bmahrms-portainer:9000": 1
    }
  }
}'

MySQL(bmahrms-postgres)

init_mysql/*.sql เป็นที่เก็บ SQL Script สำหรับสร้างฐานข้อมูลตั้งต้น จะถูกเรียกใช้ครั้งแรกตอนเริ่มฐานข้อมูลเป็นข้อมูลตั้งต้นของระบบ เนื่องจากไฟล์มีขนาดใหญ่หลายบรรทัดจะไม่ใส่ในเอกสารนี้

Report Server

เป็น Microservice ใช้สำหรับการออกรายงาน ไม่จำเป็นต้องมี domain ของตัวเอง ให้เป็น path ในโดเมนที่มีอยู่ได้ ให้นำไฟล์ต้นแบบซึ่งสร้างจาก MS Word และ Excel มาไว้ที่โฟลเดอร์นี้ report-server-template/docx/.docx, report-server-template/xlsx/.xlsx

curl "http://127.0.0.1:9180/apisix/admin/routes" \
-H "X-API-KEY: put_admin_api_key_here" -X PUT -d '
{
  "id": "bmahrms-report-server",
  "hosts": ["bma-hrms.bangkok.go.th","bma-hrms-user.bangkok.go.th"],
  "uris": ["/api/v1/report-template/*"],
  "upstream": {
    "type": "roundrobin",
    "nodes": {
      "bmahrms-report-server:80": 1
    }
  }
}'

MiniO

Object Storage ใช้เพื่อเก็บไฟล์ของระบบถูกใช้โดย HRMS และ EDM Route จะมีส่วน API กับ console การทำ route จะให้ console อยู่ใต้ subfoler https://domain/console ในการติดตั้งบน production อาจจะไม่ได้อยู่ใน node เดียวกับ hrms และ apisix ดังนั้นควรอ้างเป็นโดเมนเต็มแทน

curl "http://127.0.0.1:9180/apisix/admin/routes" \
-H "X-API-KEY: put_admin_api_key_here" -X PUT -d '
{
  "id": "bmahrms-s3",
  "host": "bma-hrms-s3.bangkok.go.th",
  "uri": "/*",
  "upstream": {
    "type": "roundrobin",
    "nodes": {
      "bmahrms-s3:9000": 1
    }
  }
}'
# test
curl -k -I https://bma-hrms-s3.bangkok.go.th/minio/health/live

curl "http://127.0.0.1:9180/apisix/admin/routes" \
-H "X-API-KEY: put_admin_api_key_here" -X PUT -d '
{
  "id": "bmahrms-s3-console",
  "host": "bma-hrms-s3.bangkok.go.th",
  "uri": "/console/*",
  "plugins": {
    "proxy-rewrite": {
      "regex_uri": ["^/console/(.*)","/$1"]
    }
  },
  "upstream": {
    "type": "roundrobin",
    "nodes": {
      "bmahrms-s3:9001": 1
    }
  }
}'

EDM (Enterprixe Document Management)

เป็นระบบจัดการเอกสารภายใน ประกอบไปด้วยโปรแกรมหลายตัว

  • EDM ตัวโปรแกรมหลัก
  • Elasticsearch ฐานข้อมูลดัชนีเอกสารเพื่อการค้นหาภาษาไทยแบบซับซ้อน อ้างผ่าน IP/PORT ไม่มี Route สู่ภายนอก
  • Kibana ใน WebUI การจัดการ Elasticsearch มี Route ใช้เฉพาะนักพัฒนา
  • RabbitMQ จัดการคิวงาน มี Route ใช้เฉพาะนักพัฒนา
  • MiniO ใช้เพื่อเก็บไฟล์ต่างๆ มีหน้า console ใช้เฉพาะนักพัฒนา

นอกเหนือจาก compose.yaml มีไฟล์คอนฟิกสองไฟล์

nano edm_config/keycloak.json
nano elasticsearch_config/config.yaml

edm_config/keycloak.json

{
  "realm": "EDM",
  "auth-server-url": "https://bma-hrms-id.bangkok.go.th/",
  "ssl-required": "external",
  "resource": "EDM-V1",
  "public-client": true,
  "confidential-port": 0
}

elasticsearch_config/config.yaml

network.host: 0.0.0.0
s3.client.default.endpoint: bma-hrms-s3.bangkok.go.th

EDM Route

curl "http://127.0.0.1:9180/apisix/admin/routes" \
-H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f2" -X PUT -d '
{
  "id": "bmahrms-edm",
  "host": "bma-hrms-edm.bangkok.go.th",
  "uri": "/*",
  "upstream": {
    "type": "roundrobin",
    "nodes": {
      "bmahrms-edm:80": 1
    }
  }
}'

Kibana Route เป็น UI สำหรับ Elasticsearch สามารถใช้แบบ HTTP ตรงๆได้ผ่าน VPN ถ้า โดยทั่วไปใช้ผ่านเน็ตเวิร์กภายใน API gateway จะช่วยทำ Basic Authentication และ https ให้ควรใช้ ใช้ภายในเสำหรับนักพัฒนาเท่านั้น

curl "http://127.0.0.1:9180/apisix/admin/routes" \
-H "X-API-KEY: put_admin_api_key_here" -X PUT -d '
{
  "id": "bmahrms-kibana",
  "host": "bma-hrms-kibana.bangkok.go.th",
  "uri": "/*",
  "plugins": {
        "basic-auth": {}
  },
  "upstream": {
    "type": "roundrobin",
    "nodes": {
      "bmahrms-kibana:5601": 1
    }
  }
}'
# Basic Authentication
curl http://127.0.0.1:9180/apisix/admin/consumers \
-H 'X-API-KEY: put_admin_api_key_here' -X PUT -d '
{
    "username": "admin",
    "plugins": {
        "basic-auth": {
            "username": "admin",
            "password": "kibana-password-here"
        }
    }
}'