# Deploy Document เอกสารสำหรับการติดตั้งระบบของ BMA HRMS โปรแกรมในยุคปัจจุบันจะทำงานบนเทคโนโลยีคอนเทนเนอร์ เพื่อยืดหยุ่นในการทำงาน ตั้งแต่การพัฒนา ทดสอบและ ใช้งานจริง (Production) จำเป็นต้องเข้าใจการทำงาน Docker เสียก่อน เมื่อเข้าใจหลักการทำงานแล้ว ในอนาคตมีบริการเพิ่มเติมเข้ามาก็จะใช้รูปแบบเดียวกันในการตั้งค่า ## ติดตั้ง Docker Docker คอนเทนเนอร์สามารถเรียนรู้ ตั้งค่า ดูแล รักษาได้ง่ายและรวดเร็ว รองรับการขยายตัว สามารถเพิ่มคลัสเตอร์ได้ง่าย และสามารถปรับเปลี่ยนเป็น Kubernates ได้ในอนาคต สำหรับเอกสารนี้จะเป็นการติดตั้ง Docker บน debian 12 การติดตั้งโดยละเอียดดูได้จาก [คู่มือในเวปของ Docker](https://docs.docker.com/engine/install/debian/) วิธีการติดตั้งแบบย่อผ่าน [convenience script](https://docs.docker.com/engine/install/debian/#install-using-the-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 ที่ใช้ ```sh 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 ในโฟลเดอร์ที่เรียกคำสั่ง) ```sh 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 ```sh mkdir -p simple-web/html cd simple-web nano compose.yaml nano html/index.html ``` ไฟล์ compose.yaml ```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) ```sh 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) ```sh 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 ให้เหมาะสม ```yaml 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 > ```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 ที่ตั้งไว้ ```sh 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 ได้ด้วยคำสั่งนี้(การเซ็ตค่าจะอยู่ในหัวข้ออื่น) ```sh 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 ```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 ```sh 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 ```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 ```sh 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 ```sh 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 สามารถสิ่งเปิดปิดแก้ไขการทำงานของคอนเทนเนอร์ได้ เฉพาะผู้ดูแลระดับสูงถึงจะเข้าใช้งานส่วนนี้ ```sh 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 ```sh 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 ดังนั้นควรอ้างเป็นโดเมนเต็มแทน ```sh 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 มีไฟล์คอนฟิกสองไฟล์ ```sh nano edm_config/keycloak.json nano elasticsearch_config/config.yaml ``` edm_config/keycloak.json ```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 ```yaml network.host: 0.0.0.0 s3.client.default.endpoint: bma-hrms-s3.bangkok.go.th ``` EDM Route ```sh 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 ให้ควรใช้ ใช้ภายในเสำหรับนักพัฒนาเท่านั้น ```sh 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" } } }' ```