add git-based chatapp testbox deploy
This commit is contained in:
parent
78d27a45b3
commit
10174681a5
243
testbox/.env.example
Normal file
243
testbox/.env.example
Normal file
@ -0,0 +1,243 @@
|
||||
# Host and public entry
|
||||
TESTBOX_DOMAIN=jvapi-test.haiyihy.com
|
||||
TESTBOX_PUBLIC_BASE_URL=https://jvapi-test.haiyihy.com
|
||||
TESTBOX_ADMIN_DOMAIN=yumi-test-admi.haiyihy.com
|
||||
TESTBOX_ADMIN_PUBLIC_BASE_URL=https://yumi-test-admi.haiyihy.com
|
||||
TESTBOX_ADMIN_API_BASE_URL=https://yumi-test-admi.haiyihy.com/console
|
||||
TESTBOX_ADMIN_OSS_URL=
|
||||
|
||||
# Infra credentials. Change these before first production-like test.
|
||||
MYSQL_DATABASE=likei
|
||||
MYSQL_USER=likei
|
||||
MYSQL_PASSWORD=change-me-likei
|
||||
MYSQL_ROOT_PASSWORD=change-me-root
|
||||
REDIS_PASSWORD=
|
||||
NACOS_USERNAME=nacos
|
||||
NACOS_PASSWORD=nacos
|
||||
NACOS_NAMESPACE_ID=RedCircleServiceTest
|
||||
NACOS_NAMESPACE_NAME=RedCircleServiceTest
|
||||
|
||||
# Java runtime. Jar is built with Maven profile "test" for Nacos namespace,
|
||||
# but runtime profile stays prod so existing profile groups still load.
|
||||
SERVER_PROFILE_ACTIVE=prod
|
||||
JAVA_XMS=128m
|
||||
JAVA_XMX_SMALL=384m
|
||||
JAVA_XMX_MEDIUM=512m
|
||||
JAVA_METASPACE=192m
|
||||
|
||||
# Nacos-resolved placeholders used by chatapp3-java/nacos_config.
|
||||
LIKEI_MYSQL_JDBC_URL=jdbc:p6spy:mysql://mysql:3306/likei?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
|
||||
LIKEI_MYSQL_USERNAME=likei
|
||||
LIKEI_MYSQL_PASSWORD=change-me-likei
|
||||
LIKEI_REDIS_HOST=redis
|
||||
LIKEI_REDIS_PORT=6379
|
||||
LIKEI_REDIS_DATABASE=0
|
||||
LIKEI_MONGO_URI=mongodb://mongo:27017/tarab_all
|
||||
|
||||
# RocketMQ is deployed locally. Keep Java producer disabled first so service
|
||||
# startup is stable; flip to false when you want to test MQ paths.
|
||||
LIKEI_ROCKETMQ_ACCESS_KEY=test
|
||||
LIKEI_ROCKETMQ_SECRET_KEY=test
|
||||
LIKEI_ROCKETMQ_ENDPOINT=rocketmq-proxy:8081
|
||||
LIKEI_ROCKETMQ_LOCAL_DISABLE=true
|
||||
|
||||
# Payment provider placeholders used by rc-service-order. These test defaults
|
||||
# only keep the service bootable; replace them when testing real payment flows.
|
||||
LIKEI_PAY_WEB_PAY_BASE_URL=https://jvapi-test.haiyihy.com
|
||||
LIKEI_PAY_WEB_PAY_RESULT_PAGE=/pay/result
|
||||
LIKEI_PAY_WEB_PAY_RECHARGE_PAGE=/pay/recharge
|
||||
LIKEI_PAY_WEB_PAY_COLLECTION_PAGE=/pay/collection
|
||||
LIKEI_GOOGLE_PAY_GLOBAL_SERVER_ACCOUNT=test
|
||||
LIKEI_GOOGLE_PAY_GLOBAL_PATCH_JSON=payfile/likei_google_pay.json
|
||||
LIKEI_GOOGLE_PAY_TAXAB_SERVER_ACCOUNT=test
|
||||
LIKEI_GOOGLE_PAY_TAXAB_PUBLIC_KEY=test
|
||||
LIKEI_GOOGLE_PAY_TAXAB_PATCH_JSON=payfile/likei_google_pay.json
|
||||
LIKEI_PAYPAL_MERCHANT_ID=test
|
||||
LIKEI_PAYPAL_SECRET_KEY=test
|
||||
LIKEI_PAYPAL_DEV_MERCHANT_ID=test
|
||||
LIKEI_PAYPAL_DEV_SECRET_KEY=test
|
||||
LIKEI_HUAWEI_GRANT_TYPE=client_credentials
|
||||
LIKEI_HUAWEI_CLIENT_SECRET=test
|
||||
LIKEI_HUAWEI_CLIENT_ID=test
|
||||
LIKEI_HUAWEI_OAUTH_LOGIN_URL=https://oauth-login.cloud.huawei.com/oauth2/v3/token
|
||||
LIKEI_HUAWEI_IAP_PUBLIC_KEY=test
|
||||
LIKEI_PAYERMAX_SECRET_KEY=test
|
||||
LIKEI_PAYERMAX_MERCHANT_ID=test
|
||||
LIKEI_PAYERMAX_RSA_PRIVATE_KEY=test
|
||||
LIKEI_PAYERMAX_RSA_PUBLIC_KEY=test
|
||||
LIKEI_PAYERMAX_PLATFORM_RSA_PUBLIC_KEY=test
|
||||
LIKEI_PAYERMAX_APP_ID=test
|
||||
LIKEI_PAYERMAX_GATEWAY_BASE_URL=https://pay-gate-uat.payermax.com
|
||||
LIKEI_PAYERMAX_ENABLE_REAL_TIME_EXCHANGE_RATE=false
|
||||
LIKEI_AIRWALLEX_CLIENT_ID=test
|
||||
LIKEI_AIRWALLEX_API_KEY=test
|
||||
LIKEI_AIRWALLEX_BASE_URL=https://api-demo.airwallex.com
|
||||
LIKEI_PAYNICORN_APP_KEY=test
|
||||
LIKEI_PAYNICORN_MERCHANT_SECRET=test
|
||||
LIKEI_CLIPSPAY_MERCHANT_NO=test
|
||||
LIKEI_CLIPSPAY_MD5_SECRET_KEY=test
|
||||
LIKEI_CLIPSPAY_TERMINAL_NO=test
|
||||
LIKEI_CLIPSPAY_TERMINAL_KEY=test
|
||||
LIKEI_CLIPSPAY_NOTIFY_URL=https://jvapi-test.haiyihy.com/play-server-notice/clipspay
|
||||
LIKEI_CLIPSPAY_PLACE_ORDER_API=https://example.invalid
|
||||
LIKEI_CLIPSPAY_REDIRECT_RESULT=https://jvapi-test.haiyihy.com/pay/result
|
||||
LIKEI_ORDER_TELEGRAM_BOT_TOKEN=test
|
||||
LIKEI_ORDER_TELEGRAM_WEBHOOK_URL=https://jvapi-test.haiyihy.com
|
||||
|
||||
# Generic Java placeholder defaults for single-node smoke testing.
|
||||
LIKEI_FRAMEWORK_NACOS_STOP_KEY=test
|
||||
GAME_INTERNAL_CALLBACK_SECRET=test-game-callback-secret
|
||||
GAME_LUCKY_GIFT_GO_URL=http://golang:2900
|
||||
LUCKY_GIFT_GO_ENABLED=false
|
||||
LUCKY_GIFT_GO_TIMEOUT_MILLIS=3000
|
||||
LUCKY_GIFT_API_ENABLED=false
|
||||
LUCKY_GIFT_API_DEFAULT_URL=https://example.invalid
|
||||
LUCKY_GIFT_API_CONFIG_1_STANDARD_ID=1
|
||||
LUCKY_GIFT_API_CONFIG_1_URL=https://example.invalid
|
||||
LUCKY_GIFT_API_CONFIG_2_STANDARD_ID=2
|
||||
LUCKY_GIFT_API_CONFIG_2_URL=https://example.invalid
|
||||
INVITE_CAMPAIGN_GO_ENABLED=false
|
||||
INVITE_CAMPAIGN_GO_TIMEOUT_MILLIS=3000
|
||||
INVITE_CAMPAIGN_GO_URL=http://golang:2900
|
||||
LIKEI_WALLET_MYSQL_JDBC_URL=jdbc:p6spy:mysql://mysql:3306/likei?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
|
||||
LIKEI_PAY_FACTORY_CONFIG_CACHE_TTL_SECONDS=300
|
||||
LIKEI_RTC_APP_ID=test
|
||||
LIKEI_RTC_AUTH_KEY=test
|
||||
LIKEI_RTC_CERTIFICATE=test
|
||||
LIKEI_RTC_KILL_ROOM_URL=https://example.invalid
|
||||
LIKEI_AGORA_APP_CERTIFICATE=test
|
||||
LIKEI_AGORA_AUTH_KEY=test
|
||||
LIKEI_AGORA_TOKEN_EXPIRE_SECOND=3600
|
||||
LIKEI_AGORA_PRIVILEGE_EXPIRE_SECOND=3600
|
||||
LIKEI_IM_APP_ID=1400000000
|
||||
LIKEI_IM_KEY=test
|
||||
LIKEI_IM_IDENTIFIER=administrator
|
||||
LIKEI_IM_BASE_ENDPOINT=https://console.tim.qq.com
|
||||
LIKEI_IM_NOTICE_ACCOUNT=notice
|
||||
LIKEI_IM_NEWSLETTER_ACCOUNT=newsletter
|
||||
LIKEI_IM_BROADCAST_GROUP_LOTFUN=test-lotfun
|
||||
LIKEI_IM_BROADCAST_GROUP_LIKEI=test-likei
|
||||
LIKEI_TRTC_SECRET_ID=test
|
||||
LIKEI_TRTC_SECRET_KEY=test
|
||||
LIKEI_TRTC_ENDPOINT=https://trtc.tencentcloudapi.com
|
||||
LIKEI_TRTC_SDK_APP_ID=1400000000
|
||||
LIKEI_TENCENT_COS_ENABLED=false
|
||||
LIKEI_TENCENT_COS_SECRET_ID=test
|
||||
LIKEI_TENCENT_COS_SECRET_KEY=test
|
||||
LIKEI_TENCENT_COS_BUCKET=test
|
||||
LIKEI_TENCENT_COS_REGION=ap-jakarta
|
||||
LIKEI_TENCENT_COS_ACCESS_URL=https://example.invalid
|
||||
LIKEI_TENCENT_CLS_SECRET_ID=test
|
||||
LIKEI_TENCENT_CLS_SECRET_KEY=test
|
||||
LIKEI_TENCENT_CLS_ENDPOINT=https://cls.tencentcloudapi.com
|
||||
LIKEI_TENCENT_CLS_REGION=ap-jakarta
|
||||
LIKEI_TENCENT_CLOUD_IMS_SECRET_ID=test
|
||||
LIKEI_TENCENT_CLOUD_IMS_SECRET_KEY=test
|
||||
LIKEI_TENCENT_CLOUD_IMS_ENDPOINT=https://ims.tencentcloudapi.com
|
||||
LIKEI_TENCENT_CLOUD_IMS_REGION=ap-jakarta
|
||||
LIKEI_ALIYUN_OSS_ENDPOINT=oss-ap-southeast-1.aliyuncs.com
|
||||
LIKEI_ALIYUN_OSS_BUCKET_NAME=test
|
||||
LIKEI_ALIYUN_OSS_ACCESS_URL=https://example.invalid
|
||||
LIKEI_ALIYUN_OSS_ACCESS_KEY_ID=test
|
||||
LIKEI_ALIYUN_OSS_ACCESS_KEY_SECRET=test
|
||||
LIKEI_ALIYUN_STS_ENDPOINT=sts.aliyuncs.com
|
||||
LIKEI_ALIYUN_STS_ROLE_ARN=test
|
||||
LIKEI_SMS_ALIYUN_ENABLED=false
|
||||
LIKEI_SMS_ALIYUN_SIGN_NAME=test
|
||||
LIKEI_SMS_ALIYUN_ACCESS_KEY_ID=test
|
||||
LIKEI_SMS_ALIYUN_ACCESS_KEY_SECRET=test
|
||||
LIKEI_SMS_ALIYUN_ENDPOINT=dysmsapi.aliyuncs.com
|
||||
LIKEI_CENSOR_ACTIVE=qcloud
|
||||
LIKEI_CENSOR_TUPU_ENABLED=false
|
||||
LIKEI_AI_MINIMAX_URL=https://example.invalid
|
||||
LIKEI_AI_MINIMAX_AUTHORIZATION=test
|
||||
LIKEI_AI_MINIMAX_MODEL=test
|
||||
LIKEI_AI_QIANFAN_URL=https://example.invalid
|
||||
LIKEI_AI_QIANFAN_APP_ID=test
|
||||
LIKEI_AI_QIANFAN_AUTHORIZATION=test
|
||||
LIKEI_AI_QIANFAN_MODEL=test
|
||||
LIKEI_AI_TTS_URL=https://example.invalid
|
||||
LIKEI_AI_TTS_MODEL=test
|
||||
LIKEI_TELEGRAM_BOT_TOKEN=test
|
||||
LIKEI_TELEGRAM_MONITOR_CHAT_ID_1=0
|
||||
LIKEI_TELEGRAM_MONITOR_ALERT_LIMIT_SECONDS=300
|
||||
LIKEI_TELEGRAM_MONITOR_PROXY_HOST=
|
||||
LIKEI_TELEGRAM_MONITOR_PROXY_PORT=0
|
||||
LIKEI_VISUAL_MONITOR_USERNAME=admin
|
||||
LIKEI_VISUAL_MONITOR_PASSWORD=admin
|
||||
LIKEI_GAME_SUD_APP_ID=test
|
||||
LIKEI_GAME_SUD_APP_KEY=test
|
||||
LIKEI_GAME_SUD_APP_SECRET=test
|
||||
LIKEI_GAME_SUD_APP_CHANNEL=test
|
||||
LIKEI_GAME_BAISHUN_APP_ID=test
|
||||
LIKEI_GAME_BAISHUN_APP_KEY=test
|
||||
LIKEI_GAME_BAISHUN_APP_CHANNEL=test
|
||||
LIKEI_GAME_BAISHUN2FUN_APP_ID=test
|
||||
LIKEI_GAME_BAISHUN2FUN_APP_KEY=test
|
||||
LIKEI_GAME_BAISHUN2FUN_APP_CHANNEL=test
|
||||
LIKEI_GAME_HKYS_SIGN_KEY=test
|
||||
LIKEI_GAME_HOTGAME_SIGN_KEY=test
|
||||
LIKEI_YOMI_AES_KEY=test-yomi-aes-key
|
||||
|
||||
# Gateway route targets inside the compose network.
|
||||
LIKEI_GATEWAY_ROUTE_AUTH_URI=http://auth:1000
|
||||
LIKEI_GATEWAY_ROUTE_EXTERNAL_URI=http://external:3000
|
||||
LIKEI_GATEWAY_ROUTE_ORDER_URI=http://order:2600
|
||||
LIKEI_GATEWAY_ROUTE_WALLET_URI=http://wallet:2000
|
||||
LIKEI_GATEWAY_ROUTE_LIVE_URI=http://live:2500
|
||||
LIKEI_GATEWAY_ROUTE_OTHER_URI=http://other:2400
|
||||
LIKEI_GATEWAY_ROUTE_GO_URI=http://golang:2900
|
||||
LIKEI_GATEWAY_ROUTE_INVITE_PUBLIC_URI=http://golang:2900
|
||||
LIKEI_GATEWAY_ROUTE_INVITE_APP_URI=http://golang:2900
|
||||
LIKEI_GATEWAY_ROUTE_REGISTER_REWARD_APP_URI=http://golang:2900
|
||||
LIKEI_GATEWAY_ROUTE_INVITE_INTERNAL_URI=http://golang:2900
|
||||
LIKEI_GATEWAY_ROUTE_GAME_APP_URI=http://golang:2900
|
||||
LIKEI_GATEWAY_ROUTE_GAME_INTERNAL_URI=http://golang:2900
|
||||
LIKEI_GATEWAY_ROUTE_GAME_BAISHUN_URI=http://golang:2900
|
||||
LIKEI_GATEWAY_ROUTE_FORWARD_URI=http://other:2400
|
||||
LIKEI_GATEWAY_FORWARD_ROUTE_AES_KEY=test-forward-route-aes-key
|
||||
LIKEI_GATEWAY_FORWARD_AES_KEY=test-forward-aes-key
|
||||
|
||||
# Go API / cron.
|
||||
CHATAPP_HTTP_LISTEN_ADDR=:2900
|
||||
CHATAPP_HTTP_INTERNAL_CALLBACK_SECRET=test-internal-callback-secret
|
||||
CHATAPP_STORE_MYSQL_DSN=likei:change-me-likei@tcp(mysql:3306)/likei?charset=utf8mb4&parseTime=True&loc=Local
|
||||
CHATAPP_STORE_REDIS_ADDR=redis:6379
|
||||
CHATAPP_STORE_REDIS_PASSWORD=
|
||||
CHATAPP_STORE_REDIS_DB=0
|
||||
CHATAPP_JAVA_AUTH_BASE_URL=http://auth:1000
|
||||
CHATAPP_JAVA_CONSOLE_BASE_URL=http://console:2700/console
|
||||
CHATAPP_JAVA_DEVICE_BASE_URL=http://other:2400
|
||||
CHATAPP_JAVA_APP_BASE_URL=http://other:2400
|
||||
CHATAPP_JAVA_BRIDGE_BASE_URL=http://console:2700/console
|
||||
CHATAPP_JAVA_EXTERNAL_BASE_URL=http://external:3000
|
||||
CHATAPP_JAVA_OTHER_BASE_URL=http://other:2400
|
||||
CHATAPP_JAVA_ORDER_BASE_URL=http://order:2600
|
||||
CHATAPP_JAVA_WALLET_BASE_URL=http://wallet:2000
|
||||
CHATAPP_INVITE_PUBLIC_BASE_URL=https://jvapi-test.haiyihy.com
|
||||
CHATAPP_GAME_OPEN_PUBLIC_BASE_URL=https://jvapi-test.haiyihy.com
|
||||
CHATAPP_WEEK_STAR_TIMEZONE=Asia/Riyadh
|
||||
CHATAPP_ROOM_TURNOVER_REWARD_TIMEZONE=Asia/Riyadh
|
||||
CHATAPP_WEEK_STAR_SETTLE_INTERVAL_SECONDS=60
|
||||
CHATAPP_ROOM_TURNOVER_REWARD_SETTLE_INTERVAL_SECONDS=60
|
||||
CHATAPP_WEEK_STAR_ROCKETMQ_ENABLED=false
|
||||
CHATAPP_WEEK_STAR_ROCKETMQ_ENDPOINT=rocketmq-proxy:8081
|
||||
CHATAPP_WEEK_STAR_ROCKETMQ_ACCESS_KEY=test
|
||||
CHATAPP_WEEK_STAR_ROCKETMQ_ACCESS_SECRET=test
|
||||
|
||||
# Source locations on the testbox. sync-to-testbox.sh populates these.
|
||||
TESTBOX_MONITOR_REPO_URL=git@gitea.haiyihy.com:hy/hy-app-monitor.git
|
||||
TESTBOX_MONITOR_BRANCH=main
|
||||
JAVA_REPO_URL=git@gitea.haiyihy.com:hy/chatapp3-java.git
|
||||
JAVA_BRANCH=main
|
||||
GOLANG_REPO_URL=git@gitea.haiyihy.com:hy/chatapp3-golang.git
|
||||
GOLANG_BRANCH=main
|
||||
CRON_REPO_URL=git@gitea.haiyihy.com:hy/chatapp-cron.git
|
||||
CRON_BRANCH=main
|
||||
ADMIN_REPO_URL=git@gitea.haiyihy.com:hy/chatapp3-admin.git
|
||||
ADMIN_BRANCH=main
|
||||
TESTBOX_SRC_ROOT=/opt/chatapp-test/sources
|
||||
JAVA_SOURCE_DIR=/opt/chatapp-test/sources/chatapp3-java
|
||||
GOLANG_SOURCE_DIR=/opt/chatapp-test/sources/chatapp3-golang
|
||||
CRON_SOURCE_DIR=/opt/chatapp-test/sources/chatapp-cron
|
||||
ADMIN_SOURCE_DIR=/opt/chatapp-test/sources/chatapp3-admin
|
||||
4
testbox/.gitignore
vendored
Normal file
4
testbox/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
.env
|
||||
mysql/baseline/*.sql
|
||||
!mysql/baseline/README.md
|
||||
!mysql/baseline/.gitkeep
|
||||
17
testbox/Caddyfile
Normal file
17
testbox/Caddyfile
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
email admin@haiyihy.com
|
||||
}
|
||||
|
||||
{$TESTBOX_DOMAIN} {
|
||||
encode zstd gzip
|
||||
reverse_proxy gateway:8080
|
||||
}
|
||||
|
||||
{$TESTBOX_ADMIN_DOMAIN} {
|
||||
encode zstd gzip
|
||||
|
||||
@console path /console /console/*
|
||||
reverse_proxy @console gateway:8080
|
||||
|
||||
reverse_proxy admin:8080
|
||||
}
|
||||
98
testbox/README.md
Normal file
98
testbox/README.md
Normal file
@ -0,0 +1,98 @@
|
||||
# Chatapp testbox
|
||||
|
||||
Single-node test environment for chatapp Java services, Go API, cron worker,
|
||||
and local infra.
|
||||
|
||||
Public API entry:
|
||||
|
||||
```text
|
||||
https://jvapi-test.haiyihy.com
|
||||
```
|
||||
|
||||
## What runs here
|
||||
|
||||
- MySQL 8.0
|
||||
- Redis 7
|
||||
- MongoDB 7
|
||||
- Nacos standalone, namespace `RedCircleServiceTest`
|
||||
- RocketMQ namesrv/broker/proxy
|
||||
- Java: auth, gateway, external, console, other, live, wallet, order
|
||||
- Go: chatapp3-golang API
|
||||
- Cron: chatapp-cron week-star worker
|
||||
- Admin: chatapp3-admin at `https://yumi-test-admi.haiyihy.com`
|
||||
- Caddy for HTTPS reverse proxy to gateway
|
||||
|
||||
## First deployment
|
||||
|
||||
Make sure SSH works first:
|
||||
|
||||
```bash
|
||||
ssh root@43.165.195.39 'hostname'
|
||||
```
|
||||
|
||||
Then trigger a git-based deploy:
|
||||
|
||||
```bash
|
||||
cd /Users/hy/Documents/haiyi/hy-app-monitor
|
||||
bash testbox/scripts/deploy-from-git.sh root@43.165.195.39
|
||||
```
|
||||
|
||||
The script only SSHes to the testbox. The server pulls these git repositories,
|
||||
installs Docker on the testbox, starts infra, imports Nacos configs, applies
|
||||
MySQL baseline files, builds images, and starts apps:
|
||||
|
||||
```text
|
||||
git@gitea.haiyihy.com:hy/hy-app-monitor.git
|
||||
git@gitea.haiyihy.com:hy/chatapp3-java.git
|
||||
git@gitea.haiyihy.com:hy/chatapp3-golang.git
|
||||
git@gitea.haiyihy.com:hy/chatapp-cron.git
|
||||
git@gitea.haiyihy.com:hy/chatapp3-admin.git
|
||||
```
|
||||
|
||||
After first deployment, you can run the deploy directly on the server:
|
||||
|
||||
```bash
|
||||
ssh root@43.165.195.39 'bash /opt/chatapp-test/scripts/deploy-from-git-remote.sh'
|
||||
```
|
||||
|
||||
The runtime `.env` stays on the server at `/opt/chatapp-test/.env`; git deploys
|
||||
do not overwrite it.
|
||||
|
||||
## MySQL baseline
|
||||
|
||||
Java services need real schema and base config rows. Put sanitized SQL files in:
|
||||
|
||||
```text
|
||||
testbox/mysql/baseline/
|
||||
```
|
||||
|
||||
They are applied in lexical order. Recommended:
|
||||
|
||||
```text
|
||||
10-schema.sql
|
||||
20-base-data.sql
|
||||
```
|
||||
|
||||
The deploy script then applies Go migrations from `chatapp3-golang/migrations`
|
||||
and Java incremental SQL from `chatapp3-java/sql`.
|
||||
|
||||
## Runtime commands on the server
|
||||
|
||||
```bash
|
||||
cd /opt/chatapp-test
|
||||
docker compose --env-file .env -f docker-compose.infra.yml -f docker-compose.apps.yml ps
|
||||
docker compose --env-file .env -f docker-compose.infra.yml -f docker-compose.apps.yml logs -f gateway
|
||||
docker compose --env-file .env -f docker-compose.infra.yml -f docker-compose.apps.yml restart other
|
||||
```
|
||||
|
||||
Local-only infra ports on the server:
|
||||
|
||||
```text
|
||||
127.0.0.1:3306 MySQL
|
||||
127.0.0.1:6379 Redis
|
||||
127.0.0.1:27017 Mongo
|
||||
127.0.0.1:8848 Nacos
|
||||
127.0.0.1:8081 RocketMQ proxy
|
||||
```
|
||||
|
||||
Only `80/443` are intended to be public.
|
||||
11
testbox/config/rocketmq/broker.conf
Normal file
11
testbox/config/rocketmq/broker.conf
Normal file
@ -0,0 +1,11 @@
|
||||
brokerClusterName=DefaultCluster
|
||||
brokerName=broker-a
|
||||
brokerId=0
|
||||
deleteWhen=04
|
||||
fileReservedTime=48
|
||||
brokerRole=ASYNC_MASTER
|
||||
flushDiskType=ASYNC_FLUSH
|
||||
autoCreateTopicEnable=true
|
||||
autoCreateSubscriptionGroup=true
|
||||
listenPort=10911
|
||||
namesrvAddr=rocketmq-namesrv:9876
|
||||
302
testbox/docker-compose.apps.yml
Normal file
302
testbox/docker-compose.apps.yml
Normal file
@ -0,0 +1,302 @@
|
||||
x-java-env: &java-env
|
||||
NACOS_HOST: nacos
|
||||
NACOS_PORT: "8848"
|
||||
NACOS_USERNAME: ${NACOS_USERNAME}
|
||||
NACOS_PASSWORD: ${NACOS_PASSWORD}
|
||||
SERVER_PROFILE_ACTIVE: ${SERVER_PROFILE_ACTIVE}
|
||||
LIKEI_MYSQL_JDBC_URL: ${LIKEI_MYSQL_JDBC_URL}
|
||||
LIKEI_MYSQL_USERNAME: ${LIKEI_MYSQL_USERNAME}
|
||||
LIKEI_MYSQL_PASSWORD: ${LIKEI_MYSQL_PASSWORD}
|
||||
LIKEI_REDIS_HOST: ${LIKEI_REDIS_HOST}
|
||||
LIKEI_REDIS_PORT: ${LIKEI_REDIS_PORT}
|
||||
LIKEI_REDIS_DATABASE: ${LIKEI_REDIS_DATABASE}
|
||||
LIKEI_MONGO_URI: ${LIKEI_MONGO_URI}
|
||||
LIKEI_ROCKETMQ_ACCESS_KEY: ${LIKEI_ROCKETMQ_ACCESS_KEY}
|
||||
LIKEI_ROCKETMQ_SECRET_KEY: ${LIKEI_ROCKETMQ_SECRET_KEY}
|
||||
LIKEI_ROCKETMQ_ENDPOINT: ${LIKEI_ROCKETMQ_ENDPOINT}
|
||||
LIKEI_ROCKETMQ_LOCAL_DISABLE: ${LIKEI_ROCKETMQ_LOCAL_DISABLE}
|
||||
LIKEI_GATEWAY_ROUTE_AUTH_URI: ${LIKEI_GATEWAY_ROUTE_AUTH_URI}
|
||||
LIKEI_GATEWAY_ROUTE_EXTERNAL_URI: ${LIKEI_GATEWAY_ROUTE_EXTERNAL_URI}
|
||||
LIKEI_GATEWAY_ROUTE_ORDER_URI: ${LIKEI_GATEWAY_ROUTE_ORDER_URI}
|
||||
LIKEI_GATEWAY_ROUTE_WALLET_URI: ${LIKEI_GATEWAY_ROUTE_WALLET_URI}
|
||||
LIKEI_GATEWAY_ROUTE_LIVE_URI: ${LIKEI_GATEWAY_ROUTE_LIVE_URI}
|
||||
LIKEI_GATEWAY_ROUTE_OTHER_URI: ${LIKEI_GATEWAY_ROUTE_OTHER_URI}
|
||||
LIKEI_GATEWAY_ROUTE_GO_URI: ${LIKEI_GATEWAY_ROUTE_GO_URI}
|
||||
LIKEI_GATEWAY_ROUTE_INVITE_PUBLIC_URI: ${LIKEI_GATEWAY_ROUTE_INVITE_PUBLIC_URI}
|
||||
LIKEI_GATEWAY_ROUTE_INVITE_APP_URI: ${LIKEI_GATEWAY_ROUTE_INVITE_APP_URI}
|
||||
LIKEI_GATEWAY_ROUTE_REGISTER_REWARD_APP_URI: ${LIKEI_GATEWAY_ROUTE_REGISTER_REWARD_APP_URI}
|
||||
LIKEI_GATEWAY_ROUTE_INVITE_INTERNAL_URI: ${LIKEI_GATEWAY_ROUTE_INVITE_INTERNAL_URI}
|
||||
LIKEI_GATEWAY_ROUTE_GAME_APP_URI: ${LIKEI_GATEWAY_ROUTE_GAME_APP_URI}
|
||||
LIKEI_GATEWAY_ROUTE_GAME_INTERNAL_URI: ${LIKEI_GATEWAY_ROUTE_GAME_INTERNAL_URI}
|
||||
LIKEI_GATEWAY_ROUTE_GAME_BAISHUN_URI: ${LIKEI_GATEWAY_ROUTE_GAME_BAISHUN_URI}
|
||||
LIKEI_GATEWAY_ROUTE_FORWARD_URI: ${LIKEI_GATEWAY_ROUTE_FORWARD_URI}
|
||||
LIKEI_GATEWAY_FORWARD_ROUTE_AES_KEY: ${LIKEI_GATEWAY_FORWARD_ROUTE_AES_KEY}
|
||||
LIKEI_GATEWAY_FORWARD_AES_KEY: ${LIKEI_GATEWAY_FORWARD_AES_KEY}
|
||||
|
||||
x-java-small: &java-small
|
||||
JVM_OPTION: "-Xms${JAVA_XMS} -Xmx${JAVA_XMX_SMALL} -XX:MaxMetaspaceSize=${JAVA_METASPACE} -Djava.security.egd=file:/dev/./urandom"
|
||||
|
||||
x-java-medium: &java-medium
|
||||
JVM_OPTION: "-Xms${JAVA_XMS} -Xmx${JAVA_XMX_MEDIUM} -XX:MaxMetaspaceSize=${JAVA_METASPACE} -Djava.security.egd=file:/dev/./urandom"
|
||||
|
||||
x-app-depends: &app-depends
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
mongo:
|
||||
condition: service_healthy
|
||||
nacos:
|
||||
condition: service_healthy
|
||||
|
||||
services:
|
||||
auth:
|
||||
build:
|
||||
context: ${JAVA_SOURCE_DIR}/rc-auth
|
||||
args:
|
||||
SERVICE_VERSION: testbox
|
||||
image: chatapp-test/auth:testbox
|
||||
container_name: chatapp-test-auth
|
||||
restart: unless-stopped
|
||||
depends_on: *app-depends
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
<<: [*java-env, *java-small]
|
||||
SERVER_PORT: "1000"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:1000/actuator/health | grep -q UP"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 40
|
||||
|
||||
wallet:
|
||||
build:
|
||||
context: ${JAVA_SOURCE_DIR}/rc-service/rc-service-wallet
|
||||
args:
|
||||
SERVICE_VERSION: testbox
|
||||
image: chatapp-test/wallet:testbox
|
||||
container_name: chatapp-test-wallet
|
||||
restart: unless-stopped
|
||||
depends_on: *app-depends
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
<<: [*java-env, *java-medium]
|
||||
SERVER_PORT: "2000"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:2000/actuator/health | grep -q UP"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 40
|
||||
|
||||
other:
|
||||
build:
|
||||
context: ${JAVA_SOURCE_DIR}/rc-service/rc-service-other
|
||||
args:
|
||||
SERVICE_VERSION: testbox
|
||||
image: chatapp-test/other:testbox
|
||||
container_name: chatapp-test-other
|
||||
restart: unless-stopped
|
||||
depends_on: *app-depends
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
<<: [*java-env, *java-medium]
|
||||
SERVER_PORT: "2400"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:2400/actuator/health | grep -q UP"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 40
|
||||
|
||||
live:
|
||||
build:
|
||||
context: ${JAVA_SOURCE_DIR}/rc-service/rc-service-live
|
||||
args:
|
||||
SERVICE_VERSION: testbox
|
||||
image: chatapp-test/live:testbox
|
||||
container_name: chatapp-test-live
|
||||
restart: unless-stopped
|
||||
depends_on: *app-depends
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
<<: [*java-env, *java-small]
|
||||
SERVER_PORT: "2500"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:2500/actuator/health | grep -q UP"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 40
|
||||
|
||||
order:
|
||||
build:
|
||||
context: ${JAVA_SOURCE_DIR}/rc-service/rc-service-order
|
||||
args:
|
||||
SERVICE_VERSION: testbox
|
||||
image: chatapp-test/order:testbox
|
||||
container_name: chatapp-test-order
|
||||
restart: unless-stopped
|
||||
depends_on: *app-depends
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
<<: [*java-env, *java-medium]
|
||||
SERVER_PORT: "2600"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:2600/actuator/health | grep -q UP"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 40
|
||||
|
||||
console:
|
||||
build:
|
||||
context: ${JAVA_SOURCE_DIR}/rc-service/rc-service-console
|
||||
args:
|
||||
SERVICE_VERSION: testbox
|
||||
image: chatapp-test/console:testbox
|
||||
container_name: chatapp-test-console
|
||||
restart: unless-stopped
|
||||
depends_on: *app-depends
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
<<: [*java-env, *java-medium]
|
||||
SERVER_PORT: "2700"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:2700/console/actuator/health | grep -q UP"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 40
|
||||
|
||||
external:
|
||||
build:
|
||||
context: ${JAVA_SOURCE_DIR}/rc-service/rc-service-external
|
||||
args:
|
||||
SERVICE_VERSION: testbox
|
||||
image: chatapp-test/external:testbox
|
||||
container_name: chatapp-test-external
|
||||
restart: unless-stopped
|
||||
depends_on: *app-depends
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
<<: [*java-env, *java-small]
|
||||
SERVER_PORT: "3000"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3000/actuator/health | grep -q UP"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 40
|
||||
|
||||
golang:
|
||||
build:
|
||||
context: ${GOLANG_SOURCE_DIR}
|
||||
args:
|
||||
APP_VERSION: testbox
|
||||
image: chatapp-test/golang:testbox
|
||||
container_name: chatapp-test-golang
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
env_file:
|
||||
- .env
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:2900/health | grep -q ok"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
|
||||
chatapp-cron:
|
||||
build:
|
||||
context: ${CRON_SOURCE_DIR}
|
||||
args:
|
||||
APP_VERSION: testbox
|
||||
image: chatapp-test/chatapp-cron:testbox
|
||||
container_name: chatapp-test-cron
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
other:
|
||||
condition: service_started
|
||||
wallet:
|
||||
condition: service_started
|
||||
env_file:
|
||||
- .env
|
||||
|
||||
admin:
|
||||
image: chatapp-test/admin:testbox
|
||||
container_name: chatapp-test-admin
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:8080/ | grep -qi '<!doctype html'"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
|
||||
gateway:
|
||||
build:
|
||||
context: ${JAVA_SOURCE_DIR}/rc-gateway
|
||||
args:
|
||||
SERVICE_VERSION: testbox
|
||||
image: chatapp-test/gateway:testbox
|
||||
container_name: chatapp-test-gateway
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
auth:
|
||||
condition: service_started
|
||||
other:
|
||||
condition: service_started
|
||||
wallet:
|
||||
condition: service_started
|
||||
order:
|
||||
condition: service_started
|
||||
live:
|
||||
condition: service_started
|
||||
external:
|
||||
condition: service_started
|
||||
golang:
|
||||
condition: service_started
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
<<: [*java-env, *java-medium]
|
||||
SERVER_PORT: "8080"
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:8080/health || wget -qO- http://127.0.0.1:8080/actuator/health"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 40
|
||||
|
||||
caddy:
|
||||
image: caddy:2.8-alpine
|
||||
container_name: chatapp-test-caddy
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
gateway:
|
||||
condition: service_started
|
||||
admin:
|
||||
condition: service_started
|
||||
environment:
|
||||
TESTBOX_DOMAIN: ${TESTBOX_DOMAIN}
|
||||
TESTBOX_ADMIN_DOMAIN: ${TESTBOX_ADMIN_DOMAIN}
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
- caddy-data:/data
|
||||
- caddy-config:/config
|
||||
|
||||
volumes:
|
||||
caddy-data:
|
||||
caddy-config:
|
||||
153
testbox/docker-compose.infra.yml
Normal file
153
testbox/docker-compose.infra.yml
Normal file
@ -0,0 +1,153 @@
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
container_name: chatapp-test-mysql
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- --character-set-server=utf8mb4
|
||||
- --collation-server=utf8mb4_unicode_ci
|
||||
- --default-time-zone=+08:00
|
||||
- --max_connections=300
|
||||
- --innodb_buffer_pool_size=2G
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
MYSQL_DATABASE: ${MYSQL_DATABASE}
|
||||
MYSQL_USER: ${MYSQL_USER}
|
||||
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||
TZ: Asia/Shanghai
|
||||
ports:
|
||||
- "127.0.0.1:3306:3306"
|
||||
volumes:
|
||||
- mysql-data:/var/lib/mysql
|
||||
- ./mysql/init:/docker-entrypoint-initdb.d:ro
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -uroot -p$${MYSQL_ROOT_PASSWORD} --silent"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
|
||||
redis:
|
||||
image: redis:7.2-alpine
|
||||
container_name: chatapp-test-redis
|
||||
restart: unless-stopped
|
||||
command: >
|
||||
sh -lc 'if [ -n "$$REDIS_PASSWORD" ]; then
|
||||
exec redis-server --appendonly yes --requirepass "$$REDIS_PASSWORD";
|
||||
else exec redis-server --appendonly yes; fi'
|
||||
environment:
|
||||
REDIS_PASSWORD: ${REDIS_PASSWORD}
|
||||
TZ: Asia/Shanghai
|
||||
ports:
|
||||
- "127.0.0.1:6379:6379"
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "redis-cli ping | grep -q PONG"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
|
||||
mongo:
|
||||
image: mongo:7.0
|
||||
container_name: chatapp-test-mongo
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
ports:
|
||||
- "127.0.0.1:27017:27017"
|
||||
volumes:
|
||||
- mongo-data:/data/db
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mongosh --quiet --eval 'db.runCommand({ ping: 1 }).ok' | grep -q 1"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
|
||||
nacos:
|
||||
image: nacos/nacos-server:v2.3.2
|
||||
container_name: chatapp-test-nacos
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MODE: standalone
|
||||
PREFER_HOST_MODE: hostname
|
||||
NACOS_AUTH_ENABLE: "false"
|
||||
JVM_XMS: 512m
|
||||
JVM_XMX: 512m
|
||||
JVM_XMN: 256m
|
||||
TZ: Asia/Shanghai
|
||||
ports:
|
||||
- "127.0.0.1:8848:8848"
|
||||
- "127.0.0.1:9848:9848"
|
||||
volumes:
|
||||
- nacos-data:/home/nacos/data
|
||||
- nacos-logs:/home/nacos/logs
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:8848/nacos/v1/console/health/readiness | grep -Eq '^(UP|OK)$'"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 60
|
||||
|
||||
rocketmq-namesrv:
|
||||
image: apache/rocketmq:5.3.1
|
||||
container_name: chatapp-test-rocketmq-namesrv
|
||||
user: root
|
||||
restart: unless-stopped
|
||||
command: sh mqnamesrv
|
||||
environment:
|
||||
JAVA_OPT_EXT: "-Xms256m -Xmx256m -Xmn128m"
|
||||
TZ: Asia/Shanghai
|
||||
ports:
|
||||
- "127.0.0.1:9876:9876"
|
||||
volumes:
|
||||
- rocketmq-namesrv-logs:/home/rocketmq/logs
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "bash -lc '</dev/tcp/127.0.0.1/9876'"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
|
||||
rocketmq-broker:
|
||||
image: apache/rocketmq:5.3.1
|
||||
container_name: chatapp-test-rocketmq-broker
|
||||
user: root
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
rocketmq-namesrv:
|
||||
condition: service_started
|
||||
command: sh mqbroker -n rocketmq-namesrv:9876 -c /home/rocketmq/conf/broker.conf
|
||||
environment:
|
||||
JAVA_OPT_EXT: "-Xms512m -Xmx512m -Xmn256m"
|
||||
TZ: Asia/Shanghai
|
||||
ports:
|
||||
- "127.0.0.1:10909:10909"
|
||||
- "127.0.0.1:10911:10911"
|
||||
volumes:
|
||||
- ./config/rocketmq/broker.conf:/home/rocketmq/conf/broker.conf:ro
|
||||
- rocketmq-broker-store:/home/rocketmq/store
|
||||
- rocketmq-broker-logs:/home/rocketmq/logs
|
||||
|
||||
rocketmq-proxy:
|
||||
image: apache/rocketmq:5.3.1
|
||||
container_name: chatapp-test-rocketmq-proxy
|
||||
user: root
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
rocketmq-broker:
|
||||
condition: service_started
|
||||
command: sh mqproxy -n rocketmq-namesrv:9876
|
||||
environment:
|
||||
JAVA_OPT_EXT: "-Xms256m -Xmx256m -Xmn128m"
|
||||
TZ: Asia/Shanghai
|
||||
ports:
|
||||
- "127.0.0.1:8081:8081"
|
||||
- "127.0.0.1:8082:8080"
|
||||
|
||||
volumes:
|
||||
mysql-data:
|
||||
redis-data:
|
||||
mongo-data:
|
||||
nacos-data:
|
||||
nacos-logs:
|
||||
rocketmq-namesrv-logs:
|
||||
rocketmq-broker-store:
|
||||
rocketmq-broker-logs:
|
||||
34
testbox/docker/chatapp3-admin.Dockerfile
Normal file
34
testbox/docker/chatapp3-admin.Dockerfile
Normal file
@ -0,0 +1,34 @@
|
||||
# syntax=docker/dockerfile:1.7
|
||||
FROM node:22-slim AS builder
|
||||
|
||||
ARG ADMIN_API_BASE_URL=/console
|
||||
ARG ADMIN_OSS_URL=
|
||||
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
ENV NODE_OPTIONS="--max-old-space-size=8192"
|
||||
ENV TZ="Asia/Shanghai"
|
||||
ENV CI="true"
|
||||
|
||||
RUN npm i -g corepack && corepack enable
|
||||
|
||||
WORKDIR /app
|
||||
COPY . /app
|
||||
|
||||
RUN sed -i "s#^VITE_GLOB_API_URL=.*#VITE_GLOB_API_URL=${ADMIN_API_BASE_URL}#" apps/.env.production \
|
||||
&& sed -i "s#^VITE_GLOB_OSS_URL=.*#VITE_GLOB_OSS_URL=${ADMIN_OSS_URL}#" apps/.env.production
|
||||
|
||||
RUN pnpm install --frozen-lockfile
|
||||
RUN pnpm run build:antdv-next
|
||||
|
||||
FROM nginx:stable-alpine
|
||||
|
||||
RUN echo "types { application/javascript js mjs; }" > /etc/nginx/conf.d/mjs.conf \
|
||||
&& rm -rf /etc/nginx/conf.d/default.conf
|
||||
|
||||
COPY --from=builder /app/apps/dist /usr/share/nginx/html
|
||||
COPY --from=builder /app/scripts/deploy/nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
0
testbox/mysql/baseline/.gitkeep
Normal file
0
testbox/mysql/baseline/.gitkeep
Normal file
8
testbox/mysql/baseline/README.md
Normal file
8
testbox/mysql/baseline/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
Put repeatable test baseline SQL files here.
|
||||
|
||||
Suggested files:
|
||||
|
||||
- 10-schema.sql: schema-only dump from production.
|
||||
- 20-base-data.sql: whitelisted config/base data only.
|
||||
|
||||
The deploy script applies files in lexical order before Go migrations.
|
||||
1
testbox/mysql/init/00-create-db.sql
Normal file
1
testbox/mysql/init/00-create-db.sql
Normal file
@ -0,0 +1 @@
|
||||
CREATE DATABASE IF NOT EXISTS `likei` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
70
testbox/scripts/apply-mysql-baseline.sh
Executable file
70
testbox/scripts/apply-mysql-baseline.sh
Executable file
@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
env_value() {
|
||||
python3 "$ROOT_DIR/scripts/env-value.py" "$ROOT_DIR/.env" "$1" "${2:-}"
|
||||
}
|
||||
|
||||
MYSQL_CONTAINER="${MYSQL_CONTAINER:-$(env_value MYSQL_CONTAINER chatapp-test-mysql)}"
|
||||
MYSQL_DATABASE="${MYSQL_DATABASE:-$(env_value MYSQL_DATABASE likei)}"
|
||||
MYSQL_ROOT_PASSWORD="${MYSQL_ROOT_PASSWORD:-$(env_value MYSQL_ROOT_PASSWORD)}"
|
||||
GOLANG_SOURCE_DIR="${GOLANG_SOURCE_DIR:-$(env_value GOLANG_SOURCE_DIR "$ROOT_DIR/sources/chatapp3-golang")}"
|
||||
JAVA_SOURCE_DIR="${JAVA_SOURCE_DIR:-$(env_value JAVA_SOURCE_DIR "$ROOT_DIR/sources/chatapp3-java")}"
|
||||
TESTBOX_APPLY_JAVA_SQL="${TESTBOX_APPLY_JAVA_SQL:-$(env_value TESTBOX_APPLY_JAVA_SQL 1)}"
|
||||
|
||||
if [ -z "$MYSQL_ROOT_PASSWORD" ]; then
|
||||
echo "MYSQL_ROOT_PASSWORD is required" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mysql_exec() {
|
||||
docker exec -i "$MYSQL_CONTAINER" mysql -uroot -p"$MYSQL_ROOT_PASSWORD" "$@"
|
||||
}
|
||||
|
||||
echo "waiting mysql..."
|
||||
for _ in $(seq 1 90); do
|
||||
if docker exec "$MYSQL_CONTAINER" mysqladmin ping -h 127.0.0.1 -uroot -p"$MYSQL_ROOT_PASSWORD" --silent >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
mysql_exec -e "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
||||
|
||||
shopt -s nullglob
|
||||
baseline_files=("$ROOT_DIR"/mysql/baseline/*.sql)
|
||||
if [ "${#baseline_files[@]}" -eq 0 ]; then
|
||||
echo "warn: no mysql baseline SQL found in mysql/baseline; Java services need schema/base data before full use" >&2
|
||||
else
|
||||
for sql in "${baseline_files[@]}"; do
|
||||
echo "applying baseline $(basename "$sql")"
|
||||
mysql_exec "$MYSQL_DATABASE" < "$sql"
|
||||
done
|
||||
fi
|
||||
|
||||
GO_MIGRATIONS_DIR="$GOLANG_SOURCE_DIR/migrations"
|
||||
if [ -d "$GO_MIGRATIONS_DIR" ]; then
|
||||
for sql in "$GO_MIGRATIONS_DIR"/*.sql; do
|
||||
[ -f "$sql" ] || continue
|
||||
echo "applying go migration $(basename "$sql")"
|
||||
mysql_exec "$MYSQL_DATABASE" < "$sql" || {
|
||||
echo "warn: go migration failed, continuing: $sql" >&2
|
||||
}
|
||||
done
|
||||
fi
|
||||
|
||||
JAVA_SQL_DIR="$JAVA_SOURCE_DIR/sql"
|
||||
if [ "${TESTBOX_APPLY_JAVA_SQL:-1}" = "1" ] && [ -d "$JAVA_SQL_DIR" ]; then
|
||||
for sql in "$JAVA_SQL_DIR"/*.sql; do
|
||||
[ -f "$sql" ] || continue
|
||||
echo "applying java sql $(basename "$sql")"
|
||||
mysql_exec "$MYSQL_DATABASE" < "$sql" || {
|
||||
echo "warn: java sql failed, continuing: $sql" >&2
|
||||
}
|
||||
done
|
||||
fi
|
||||
|
||||
echo "mysql baseline step done"
|
||||
47
testbox/scripts/bootstrap-server.sh
Executable file
47
testbox/scripts/bootstrap-server.sh
Executable file
@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "bootstrap-server.sh must run as root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
install_packages() {
|
||||
if command -v dnf >/dev/null 2>&1; then
|
||||
dnf -y install curl rsync git tar gzip python3 python3-pip dnf-plugins-core ca-certificates java-17-openjdk-devel maven >/dev/null
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
dnf -y install docker docker-compose-plugin >/dev/null 2>&1 || {
|
||||
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo >/dev/null
|
||||
dnf -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null
|
||||
}
|
||||
fi
|
||||
elif command -v apt-get >/dev/null 2>&1; then
|
||||
apt-get update >/dev/null
|
||||
apt-get install -y curl rsync git tar gzip python3 python3-pip ca-certificates openjdk-17-jdk maven docker.io docker-compose-plugin >/dev/null
|
||||
else
|
||||
echo "unsupported Linux distribution: missing dnf/apt-get" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
install_packages
|
||||
|
||||
systemctl enable --now docker >/dev/null
|
||||
|
||||
mkdir -p "$ROOT_DIR"/{sources,mysql/baseline,run,logs}
|
||||
sysctl -w vm.max_map_count=262144 >/dev/null || true
|
||||
|
||||
if command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active --quiet firewalld; then
|
||||
firewall-cmd --add-service=http --permanent >/dev/null || true
|
||||
firewall-cmd --add-service=https --permanent >/dev/null || true
|
||||
firewall-cmd --reload >/dev/null || true
|
||||
fi
|
||||
|
||||
if [ ! -f "$ROOT_DIR/.env" ]; then
|
||||
cp "$ROOT_DIR/.env.example" "$ROOT_DIR/.env"
|
||||
echo "created $ROOT_DIR/.env from example; please review passwords before real use" >&2
|
||||
fi
|
||||
|
||||
docker compose version
|
||||
43
testbox/scripts/build-images.sh
Executable file
43
testbox/scripts/build-images.sh
Executable file
@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
env_value() {
|
||||
python3 "$ROOT_DIR/scripts/env-value.py" "$ROOT_DIR/.env" "$1" "${2:-}"
|
||||
}
|
||||
|
||||
JAVA_SOURCE_DIR="${JAVA_SOURCE_DIR:-$(env_value JAVA_SOURCE_DIR "$ROOT_DIR/sources/chatapp3-java")}"
|
||||
ADMIN_SOURCE_DIR="${ADMIN_SOURCE_DIR:-$(env_value ADMIN_SOURCE_DIR "$ROOT_DIR/sources/chatapp3-admin")}"
|
||||
TESTBOX_ADMIN_API_BASE_URL="${TESTBOX_ADMIN_API_BASE_URL:-$(env_value TESTBOX_ADMIN_API_BASE_URL "https://yumi-test-admi.haiyihy.com/console")}"
|
||||
TESTBOX_ADMIN_OSS_URL="${TESTBOX_ADMIN_OSS_URL:-$(env_value TESTBOX_ADMIN_OSS_URL "")}"
|
||||
|
||||
if [ ! -d "$JAVA_SOURCE_DIR" ]; then
|
||||
echo "missing JAVA_SOURCE_DIR: $JAVA_SOURCE_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$ADMIN_SOURCE_DIR" ]; then
|
||||
echo "missing ADMIN_SOURCE_DIR: $ADMIN_SOURCE_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$JAVA_SOURCE_DIR"
|
||||
if [ -x ./ci/install-private-maven.sh ]; then
|
||||
./ci/install-private-maven.sh
|
||||
fi
|
||||
|
||||
JAVA_MODULES="rc-auth,rc-gateway,rc-service/rc-service-external/external-start,rc-service/rc-service-console/console-start,rc-service/rc-service-other/other-start,rc-service/rc-service-live/live-start,rc-service/rc-service-wallet/wallet-start,rc-service/rc-service-order/order-start"
|
||||
mvn -Ptest -T 1C -pl "$JAVA_MODULES" -am -Dmaven.test.skip=true package
|
||||
|
||||
cd "$ROOT_DIR"
|
||||
docker compose --env-file .env -f docker-compose.infra.yml -f docker-compose.apps.yml build \
|
||||
auth gateway external console other live wallet order golang chatapp-cron
|
||||
|
||||
docker build \
|
||||
-f "$ROOT_DIR/docker/chatapp3-admin.Dockerfile" \
|
||||
--build-arg "ADMIN_API_BASE_URL=$TESTBOX_ADMIN_API_BASE_URL" \
|
||||
--build-arg "ADMIN_OSS_URL=$TESTBOX_ADMIN_OSS_URL" \
|
||||
-t chatapp-test/admin:testbox \
|
||||
"$ADMIN_SOURCE_DIR"
|
||||
19
testbox/scripts/create-rocketmq-topics.sh
Executable file
19
testbox/scripts/create-rocketmq-topics.sh
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
NAMESRV="${ROCKETMQ_NAMESRV_ADDR:-rocketmq-namesrv:9876}"
|
||||
CLUSTER="${ROCKETMQ_CLUSTER:-DefaultCluster}"
|
||||
BROKER_CONTAINER="${ROCKETMQ_BROKER_CONTAINER:-chatapp-test-rocketmq-broker}"
|
||||
MQADMIN="/home/rocketmq/rocketmq-5.3.1/bin/mqadmin"
|
||||
|
||||
topics=(
|
||||
RC_DEFAULT_APP_ORDINARY
|
||||
RC_DEFAULT_APP_DELAYED
|
||||
RC_DEFAULT_APP_ORDER
|
||||
)
|
||||
|
||||
for topic in "${topics[@]}"; do
|
||||
docker exec "$BROKER_CONTAINER" sh -lc \
|
||||
"$MQADMIN updateTopic -n '$NAMESRV' -c '$CLUSTER' -t '$topic' >/dev/null"
|
||||
echo "rocketmq topic ok: $topic"
|
||||
done
|
||||
30
testbox/scripts/deploy-all.sh
Executable file
30
testbox/scripts/deploy-all.sh
Executable file
@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
if [ ! -f .env ]; then
|
||||
cp .env.example .env
|
||||
echo "created .env from .env.example; edit credentials and rerun" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
scripts/merge-env-defaults.sh .env .env.example
|
||||
|
||||
COMPOSE=(docker compose --env-file .env -f docker-compose.infra.yml -f docker-compose.apps.yml)
|
||||
|
||||
"${COMPOSE[@]}" up -d mysql redis mongo nacos rocketmq-namesrv rocketmq-broker rocketmq-proxy
|
||||
|
||||
python3 scripts/import-nacos-configs.py
|
||||
scripts/create-rocketmq-topics.sh
|
||||
scripts/apply-mysql-baseline.sh
|
||||
scripts/build-images.sh
|
||||
|
||||
"${COMPOSE[@]}" up -d auth wallet other live order console external golang gateway chatapp-cron admin caddy
|
||||
|
||||
echo
|
||||
echo "testbox status:"
|
||||
"${COMPOSE[@]}" ps
|
||||
echo
|
||||
echo "public url: ${TESTBOX_PUBLIC_BASE_URL:-https://jvapi-test.haiyihy.com}"
|
||||
100
testbox/scripts/deploy-from-git-remote.sh
Executable file
100
testbox/scripts/deploy-from-git-remote.sh
Executable file
@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
REMOTE_DIR="${REMOTE_DIR:-/opt/chatapp-test}"
|
||||
MONITOR_CHECKOUT_DIR="${MONITOR_CHECKOUT_DIR:-$REMOTE_DIR/git/hy-app-monitor}"
|
||||
export GIT_SSH_COMMAND="${GIT_SSH_COMMAND:-ssh -o StrictHostKeyChecking=accept-new}"
|
||||
|
||||
env_file_value() {
|
||||
local key="$1"
|
||||
local file="${2:-$REMOTE_DIR/.env}"
|
||||
[ -f "$file" ] || return 0
|
||||
awk -v key="$key" '
|
||||
BEGIN { FS = "=" }
|
||||
$1 == key {
|
||||
sub(/^[^=]*=/, "")
|
||||
gsub(/^[ \t"'"'"']+|[ \t"'"'"']+$/, "")
|
||||
print
|
||||
exit
|
||||
}
|
||||
' "$file"
|
||||
}
|
||||
|
||||
MONITOR_REPO_URL="${MONITOR_REPO_URL:-$(env_file_value TESTBOX_MONITOR_REPO_URL)}"
|
||||
MONITOR_REPO_URL="${MONITOR_REPO_URL:-git@gitea.haiyihy.com:hy/hy-app-monitor.git}"
|
||||
MONITOR_BRANCH="${MONITOR_BRANCH:-$(env_file_value TESTBOX_MONITOR_BRANCH)}"
|
||||
MONITOR_BRANCH="${MONITOR_BRANCH:-main}"
|
||||
|
||||
sync_repo() {
|
||||
local dir="$1"
|
||||
local url="$2"
|
||||
local branch="$3"
|
||||
local stamp
|
||||
|
||||
mkdir -p "$(dirname "$dir")"
|
||||
|
||||
if [ -e "$dir" ] && [ ! -d "$dir/.git" ]; then
|
||||
stamp="$(date +%Y%m%d%H%M%S)"
|
||||
mv "$dir" "$dir.pre-git-$stamp"
|
||||
echo "moved non-git directory to $dir.pre-git-$stamp"
|
||||
fi
|
||||
|
||||
if [ ! -d "$dir/.git" ]; then
|
||||
git clone --branch "$branch" "$url" "$dir"
|
||||
fi
|
||||
|
||||
git -C "$dir" remote set-url origin "$url"
|
||||
git -C "$dir" fetch --prune origin "$branch"
|
||||
git -C "$dir" checkout -B "$branch" "origin/$branch"
|
||||
git -C "$dir" reset --hard "origin/$branch"
|
||||
}
|
||||
|
||||
sync_repo "$MONITOR_CHECKOUT_DIR" "$MONITOR_REPO_URL" "$MONITOR_BRANCH"
|
||||
|
||||
latest_script="$MONITOR_CHECKOUT_DIR/testbox/scripts/deploy-from-git-remote.sh"
|
||||
current_script="${BASH_SOURCE[0]}"
|
||||
if [ "${TESTBOX_REMOTE_DEPLOY_BOOTSTRAPPED:-0}" != "1" ] && [ "$current_script" != "$latest_script" ]; then
|
||||
export TESTBOX_REMOTE_DEPLOY_BOOTSTRAPPED=1
|
||||
exec bash "$latest_script"
|
||||
fi
|
||||
|
||||
mkdir -p "$REMOTE_DIR"/{git,sources,run,logs}
|
||||
|
||||
rsync --archive --delete \
|
||||
--exclude ".env" \
|
||||
--exclude "git" \
|
||||
--exclude "sources" \
|
||||
--exclude "run" \
|
||||
--exclude "logs" \
|
||||
--exclude "mysql/baseline/*.sql" \
|
||||
"$MONITOR_CHECKOUT_DIR/testbox/" "$REMOTE_DIR/"
|
||||
|
||||
bash "$REMOTE_DIR/scripts/bootstrap-server.sh"
|
||||
bash "$REMOTE_DIR/scripts/merge-env-defaults.sh" "$REMOTE_DIR/.env" "$REMOTE_DIR/.env.example"
|
||||
|
||||
env_value() {
|
||||
python3 "$REMOTE_DIR/scripts/env-value.py" "$REMOTE_DIR/.env" "$1" "${2:-}"
|
||||
}
|
||||
|
||||
JAVA_REPO_URL="$(env_value JAVA_REPO_URL git@gitea.haiyihy.com:hy/chatapp3-java.git)"
|
||||
JAVA_BRANCH="$(env_value JAVA_BRANCH main)"
|
||||
GOLANG_REPO_URL="$(env_value GOLANG_REPO_URL git@gitea.haiyihy.com:hy/chatapp3-golang.git)"
|
||||
GOLANG_BRANCH="$(env_value GOLANG_BRANCH main)"
|
||||
CRON_REPO_URL="$(env_value CRON_REPO_URL git@gitea.haiyihy.com:hy/chatapp-cron.git)"
|
||||
CRON_BRANCH="$(env_value CRON_BRANCH main)"
|
||||
ADMIN_REPO_URL="$(env_value ADMIN_REPO_URL git@gitea.haiyihy.com:hy/chatapp3-admin.git)"
|
||||
ADMIN_BRANCH="$(env_value ADMIN_BRANCH main)"
|
||||
|
||||
JAVA_SOURCE_DIR="$(env_value JAVA_SOURCE_DIR "$REMOTE_DIR/sources/chatapp3-java")"
|
||||
GOLANG_SOURCE_DIR="$(env_value GOLANG_SOURCE_DIR "$REMOTE_DIR/sources/chatapp3-golang")"
|
||||
CRON_SOURCE_DIR="$(env_value CRON_SOURCE_DIR "$REMOTE_DIR/sources/chatapp-cron")"
|
||||
ADMIN_SOURCE_DIR="$(env_value ADMIN_SOURCE_DIR "$REMOTE_DIR/sources/chatapp3-admin")"
|
||||
|
||||
echo "updating source repos from git..."
|
||||
sync_repo "$JAVA_SOURCE_DIR" "$JAVA_REPO_URL" "$JAVA_BRANCH"
|
||||
sync_repo "$GOLANG_SOURCE_DIR" "$GOLANG_REPO_URL" "$GOLANG_BRANCH"
|
||||
sync_repo "$CRON_SOURCE_DIR" "$CRON_REPO_URL" "$CRON_BRANCH"
|
||||
sync_repo "$ADMIN_SOURCE_DIR" "$ADMIN_REPO_URL" "$ADMIN_BRANCH"
|
||||
|
||||
cd "$REMOTE_DIR"
|
||||
bash scripts/deploy-all.sh
|
||||
64
testbox/scripts/deploy-from-git.sh
Executable file
64
testbox/scripts/deploy-from-git.sh
Executable file
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
REMOTE="${1:-root@43.165.195.39}"
|
||||
REMOTE_DIR="${REMOTE_DIR:-/opt/chatapp-test}"
|
||||
MONITOR_REPO_URL="${MONITOR_REPO_URL:-git@gitea.haiyihy.com:hy/hy-app-monitor.git}"
|
||||
MONITOR_BRANCH="${MONITOR_BRANCH:-main}"
|
||||
MONITOR_CHECKOUT_DIR="${MONITOR_CHECKOUT_DIR:-$REMOTE_DIR/git/hy-app-monitor}"
|
||||
|
||||
ssh "$REMOTE" \
|
||||
"REMOTE_DIR='$REMOTE_DIR' MONITOR_REPO_URL='$MONITOR_REPO_URL' MONITOR_BRANCH='$MONITOR_BRANCH' MONITOR_CHECKOUT_DIR='$MONITOR_CHECKOUT_DIR' bash -s" <<'REMOTE_BOOTSTRAP'
|
||||
set -euo pipefail
|
||||
|
||||
REMOTE_DIR="${REMOTE_DIR:-/opt/chatapp-test}"
|
||||
MONITOR_REPO_URL="${MONITOR_REPO_URL:-git@gitea.haiyihy.com:hy/hy-app-monitor.git}"
|
||||
MONITOR_BRANCH="${MONITOR_BRANCH:-main}"
|
||||
MONITOR_CHECKOUT_DIR="${MONITOR_CHECKOUT_DIR:-$REMOTE_DIR/git/hy-app-monitor}"
|
||||
export GIT_SSH_COMMAND="${GIT_SSH_COMMAND:-ssh -o StrictHostKeyChecking=accept-new}"
|
||||
|
||||
install_minimal_packages() {
|
||||
if command -v git >/dev/null 2>&1 && command -v rsync >/dev/null 2>&1; then
|
||||
return
|
||||
fi
|
||||
|
||||
if command -v dnf >/dev/null 2>&1; then
|
||||
dnf -y install git rsync ca-certificates >/dev/null
|
||||
elif command -v apt-get >/dev/null 2>&1; then
|
||||
apt-get update >/dev/null
|
||||
apt-get install -y git rsync ca-certificates >/dev/null
|
||||
else
|
||||
echo "unsupported Linux distribution: missing dnf/apt-get" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
sync_repo() {
|
||||
local dir="$1"
|
||||
local url="$2"
|
||||
local branch="$3"
|
||||
local stamp
|
||||
|
||||
mkdir -p "$(dirname "$dir")"
|
||||
|
||||
if [ -e "$dir" ] && [ ! -d "$dir/.git" ]; then
|
||||
stamp="$(date +%Y%m%d%H%M%S)"
|
||||
mv "$dir" "$dir.pre-git-$stamp"
|
||||
echo "moved non-git directory to $dir.pre-git-$stamp"
|
||||
fi
|
||||
|
||||
if [ ! -d "$dir/.git" ]; then
|
||||
git clone --branch "$branch" "$url" "$dir"
|
||||
fi
|
||||
|
||||
git -C "$dir" remote set-url origin "$url"
|
||||
git -C "$dir" fetch --prune origin "$branch"
|
||||
git -C "$dir" checkout -B "$branch" "origin/$branch"
|
||||
git -C "$dir" reset --hard "origin/$branch"
|
||||
}
|
||||
|
||||
install_minimal_packages
|
||||
sync_repo "$MONITOR_CHECKOUT_DIR" "$MONITOR_REPO_URL" "$MONITOR_BRANCH"
|
||||
|
||||
exec bash "$MONITOR_CHECKOUT_DIR/testbox/scripts/deploy-from-git-remote.sh"
|
||||
REMOTE_BOOTSTRAP
|
||||
31
testbox/scripts/env-value.py
Executable file
31
testbox/scripts/env-value.py
Executable file
@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def read_value(path: Path, key: str, default: str) -> str:
|
||||
if not path.exists():
|
||||
return default
|
||||
for raw in path.read_text(encoding="utf-8").splitlines():
|
||||
line = raw.strip()
|
||||
if not line or line.startswith("#") or "=" not in line:
|
||||
continue
|
||||
name, value = line.split("=", 1)
|
||||
if name.strip() == key:
|
||||
return value.strip().strip('"').strip("'")
|
||||
return default
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if len(sys.argv) < 3:
|
||||
print("usage: env-value.py ENV_FILE KEY [DEFAULT]", file=sys.stderr)
|
||||
return 2
|
||||
default = sys.argv[3] if len(sys.argv) > 3 else ""
|
||||
print(read_value(Path(sys.argv[1]), sys.argv[2], default))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
108
testbox/scripts/import-nacos-configs.py
Executable file
108
testbox/scripts/import-nacos-configs.py
Executable file
@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import time
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
ENV_PATH = ROOT / ".env"
|
||||
|
||||
|
||||
def load_env(path: Path) -> dict[str, str]:
|
||||
values: dict[str, str] = {}
|
||||
if not path.exists():
|
||||
return values
|
||||
for raw in path.read_text(encoding="utf-8").splitlines():
|
||||
line = raw.strip()
|
||||
if not line or line.startswith("#") or "=" not in line:
|
||||
continue
|
||||
key, value = line.split("=", 1)
|
||||
values[key.strip()] = value.strip().strip('"').strip("'")
|
||||
return values
|
||||
|
||||
|
||||
ENV = {**load_env(ENV_PATH), **os.environ}
|
||||
NACOS_BASE_URL = ENV.get("NACOS_BASE_URL", "http://127.0.0.1:8848").rstrip("/")
|
||||
NAMESPACE_ID = ENV.get("NACOS_NAMESPACE_ID", "RedCircleServiceTest")
|
||||
NAMESPACE_NAME = ENV.get("NACOS_NAMESPACE_NAME", NAMESPACE_ID)
|
||||
JAVA_SOURCE_DIR = Path(ENV.get("JAVA_SOURCE_DIR", str(ROOT / "sources" / "chatapp3-java")))
|
||||
|
||||
|
||||
def request(method: str, path: str, data: dict[str, str] | None = None) -> str:
|
||||
url = f"{NACOS_BASE_URL}{path}"
|
||||
body = None
|
||||
headers = {"User-Agent": "chatapp-testbox/1.0"}
|
||||
if data is not None:
|
||||
body = urllib.parse.urlencode(data).encode("utf-8")
|
||||
headers["Content-Type"] = "application/x-www-form-urlencoded; charset=utf-8"
|
||||
req = urllib.request.Request(url, data=body, headers=headers, method=method)
|
||||
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||
return resp.read().decode("utf-8", errors="replace")
|
||||
|
||||
|
||||
def wait_nacos() -> None:
|
||||
for _ in range(90):
|
||||
try:
|
||||
text = request("GET", "/nacos/v1/console/health/readiness")
|
||||
if "UP" in text or "OK" in text:
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
time.sleep(2)
|
||||
raise RuntimeError("nacos readiness timeout")
|
||||
|
||||
|
||||
def ensure_namespace() -> None:
|
||||
data = {
|
||||
"customNamespaceId": NAMESPACE_ID,
|
||||
"namespaceName": NAMESPACE_NAME,
|
||||
"namespaceDesc": "single-node chatapp testbox",
|
||||
}
|
||||
try:
|
||||
request("POST", "/nacos/v1/console/namespaces", data)
|
||||
except Exception as exc:
|
||||
print(f"warn: namespace create skipped: {exc}", file=sys.stderr)
|
||||
|
||||
|
||||
def publish_config(group: str, data_id: str, content: str) -> None:
|
||||
payload = {
|
||||
"tenant": NAMESPACE_ID,
|
||||
"group": group,
|
||||
"dataId": data_id,
|
||||
"type": "yaml" if data_id.endswith((".yml", ".yaml")) else "text",
|
||||
"content": content,
|
||||
}
|
||||
result = request("POST", "/nacos/v1/cs/configs", payload).strip()
|
||||
if result.lower() == "false":
|
||||
raise RuntimeError(f"nacos rejected config {group}/{data_id}")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
config_root = JAVA_SOURCE_DIR / "nacos_config"
|
||||
if not config_root.is_dir():
|
||||
raise RuntimeError(f"missing nacos_config: {config_root}")
|
||||
|
||||
wait_nacos()
|
||||
ensure_namespace()
|
||||
|
||||
count = 0
|
||||
for path in sorted(config_root.glob("*/*")):
|
||||
if not path.is_file():
|
||||
continue
|
||||
group = path.parent.name
|
||||
data_id = path.name
|
||||
publish_config(group, data_id, path.read_text(encoding="utf-8"))
|
||||
count += 1
|
||||
print(f"published {group}/{data_id}")
|
||||
|
||||
print(f"nacos import ok: namespace={NAMESPACE_ID} configs={count}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
32
testbox/scripts/merge-env-defaults.sh
Executable file
32
testbox/scripts/merge-env-defaults.sh
Executable file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
env_file="${1:-.env}"
|
||||
defaults_file="${2:-.env.example}"
|
||||
|
||||
if [ ! -f "$env_file" ] || [ ! -f "$defaults_file" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
added=0
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
trimmed="${line#"${line%%[![:space:]]*}"}"
|
||||
if [ -z "$trimmed" ] || [[ "$trimmed" == \#* ]] || [[ "$trimmed" != *=* ]]; then
|
||||
continue
|
||||
fi
|
||||
key="${trimmed%%=*}"
|
||||
if ! grep -qE "^${key}=" "$env_file"; then
|
||||
if [ "$added" -eq 0 ]; then
|
||||
{
|
||||
echo
|
||||
echo "# Added from .env.example on $(date +%F)"
|
||||
} >> "$env_file"
|
||||
fi
|
||||
echo "$trimmed" >> "$env_file"
|
||||
added=$((added + 1))
|
||||
fi
|
||||
done < "$defaults_file"
|
||||
|
||||
if [ "$added" -gt 0 ]; then
|
||||
echo "merged $added missing env defaults into $env_file"
|
||||
fi
|
||||
10
testbox/scripts/sync-to-testbox.sh
Executable file
10
testbox/scripts/sync-to-testbox.sh
Executable file
@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
REMOTE="${1:-root@43.165.195.39}"
|
||||
|
||||
echo "sync-to-testbox.sh is now a git-based deploy wrapper."
|
||||
echo "No local source files or local .env will be copied."
|
||||
exec "$ROOT_DIR/scripts/deploy-from-git.sh" "$REMOTE"
|
||||
Loading…
x
Reference in New Issue
Block a user