9.Practice and Sample
9.Practice and Sample
Execute wings-init-project.sh
to generate a template project.
9.1.Pre-Requisite
Basic knowledge and hands-on ability,
- Understand
maven
, what is missing, what to learn. - Understand
spring*
,see official documentation
x 3! - Understand
mysql*
mysql database
Directory conventions
WINGS_DIR
- the project root of wings_bootWINGS_BIN
-WINGS_DIR
/observe/scriptsPROJECT_DIR
- the directory of the sample project, e.g.good-demo
PROJECT_PCD
- CodeName of the sample project, e.g.good
9.2.DIY Environment
Sample scripts for new project and command to package,
# asdf shell java temurin-17.0.9+9
mvn -v # show version of maven and java
#> Apache Maven 3.8.7 (b89d5959fcde851dcb1c8946a785a163f14e1e29)
#> Java version: 17.0.9, vendor: Eclipse Adoptium
WINGS_DIR=~/Workspace/github.com/professional-wings
WINGS_BIN=$WINGS_BOOT/observe/scripts
PROJECT_DIR=~/Workspace/good-demo
PROJECT_PCD=good
# create new project by template
$WINGS_BIN/wings-init-project.sh
Database, default H2, you can build Mysql Docker, the sample script as follows,
# set env
PASS=S4f3_Password@MoilionCircle
# create a mysql docker
docker run -d \
--name good-mysql-8.0 \
-e MYSQL_DATABASE=wings_example \
-e MYSQL_ROOT_PASSWORD=${PASS} \
-p 3306:3306 \
mysql:8.0
9.3.App Deployment
Softlink(ln -s
) wings-starter.sh to some execution location, using good-devops
as an example.
cd $PROJECT_DIR
# Create a boot script, one boot.jar corresponds to one pair of `.sh` and `.env`
ln -s $WINGS_BIN/wings-starter.sh ${PROJECT_PCD}-devops-starter.sh
# Copy the content of wings-starter.env and
# save it with the same name as the boot script (different extname)
cp $WINGS_BIN/wings-starter.env ${PROJECT_PCD}-devops-starter.env
# good is the default codename, if it has been changed, it must be modified,
# otherwise the jar cannot be found
sed -i '' "s:../../:./:" ${PROJECT_PCD}-devops-starter.env
sed -i '' "s:winx-:./${PROJECT_PCD}-:g" ${PROJECT_PCD}-devops-starter.env
In env, port,jar,log is easy to understand and can be configured according to project needs. BOOT_CNF is used to replace the default config at runtime, the structure is as follows.
├── application.properties // application level config
├── wings-conf // auto config, override on demand
│ └── spring-datasource.properties
9.4.Reverse Proxy
The general config, including forced https, .git protection, and frontend and backend separation.
upstream good_admin {
ip_hash;
server good_appser_01:8090;
server good_appser_02:8090;
keepalive 300; # long conn
}
server {
listen 80;
listen 443 ssl;
server_name admin.moilioncircle.com;
access_log /data/logs/nginx/admin.moilioncircle.com-access.log;
error_log /data/logs/nginx/admin.moilioncircle.com-error.log;
ssl_certificate /data/nginx/cert/moilioncircle.com/fullchain.pem;
ssl_certificate_key /data/nginx/cert/moilioncircle.com/privkey.pem;
#if ($scheme = http) {
# return 301 https://$host$request_uri;
#}
# Defensive settings to protect .git
location .git {
access_log off;
log_not_found off;
deny all;
}
# backend, resource url in res-id-{base64_urlsafe}.{pdf} format
location ~* (\.json|/res-id-[\-=_0-9a-z]+\.[0-9a-z]+)$ {
proxy_pass http://good_admin;
proxy_http_version 1.1;
proxy_cache_bypass $http_upgrade;
proxy_set_header Connection ""; # long conn
#proxy_set_header Connection "upgrade"; # ws
#proxy_set_header Upgrade $http_upgrade; # ws
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect http:// $scheme://; # https
}
# frontend
location / {
#add_header 'Access-Control-Allow-Origin' '*'; #Allow CORS
root /data/static/good-admin-spa/;
if ($request_filename ~* \.(html|htm)$){
add_header Cache-Control no-cache,no-store,max-age=0,must-revalidate;
}
}
}
9.5.Stress Testing
Stress test, must be ulimit -n
above 10k, same intranet to ignore bandwidth limit.
cd $PROJECT_DIR
# package and start
mvn -U clean package
./${PROJECT_PCD}-devops-starter.sh start
# Ctrl-C to stop log output
./${PROJECT_PCD}-devops-starter.sh stop
Using jmeter to simulate 10K*50 requests
ulimit -n 45535
JVM_ARGS="-Xmx8G -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:G1ReservePercent=20"
rm -rf ${PROJECT_PCD}-devops/target/load-test/ &&\
mkdir -p ${PROJECT_PCD}-devops/target/load-test/report
jmeter -n \
-t ${PROJECT_PCD}-devops/src/test/jmeter/load-test.jmx \
-l ${PROJECT_PCD}-devops/target/load-test/load-test.jtl \
-j ${PROJECT_PCD}-devops/target/load-test/load-test.log \
-e -o ${PROJECT_PCD}-devops/target/load-test/report
9.6.Security Option
The default password in wings project is ${random.uuid}
or environment variable. In actual production, some need to set to fixed password. Password strength, must be more than 32-bit random characters, alphanumeric case mix is best.
DING_TALK_TOKEN
- System variable, boot-admin login passwordwings.silencer.encrypt.leap-code
- Pseudo-random number, can keep itwings.silencer.encrypt.crc8-long
- Add crc checksum to number, can keep itwings.silencer.encrypt.aes-key.*
- SHOULD changewings.slardar.hazelcast.cluster-name
- hazelcast clust name, MUST change
In example project, use DING_TALK_TOKEN
as default password
spring.boot.admin.client.username
- boot.admin server-side username, SHOULD changespring.boot.admin.client.password
- boot.admin server-side password, MUST changespring.boot.admin.client.instance.metadata.user.name
- client-side username, SHOULD changespring.boot.admin.client.instance.metadata.user.password
- client-side password, MUST change
The default values for all of the above config items should be based on the corresponding manual or source code to avoid the security implications of outdated documentation.
9.7.Start-up Args
In springboot3(after java17), add-opens
must be set correctly to avoid illegal-access
. Wings set correctly in pom.xml and starter.sh, with the following files and variable names.
/pom.xml
-javaopenArgLine
with reason/observe/scripts/wings-starter.sh
-JDK9_ARG
<arg>
- must be specified with=
, space is supported in shell
The details of add-opens
are as follows, handle line breaks when using
--add-modules=java.se
--add-exports=java.base/jdk.internal.ref=ALL-UNNAMED
--add-opens=java.base/java.io=ALL-UNNAMED
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED
--add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.net=ALL-UNNAMED
--add-opens=java.base/java.nio=ALL-UNNAMED
--add-opens=java.base/java.util=ALL-UNNAMED
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED
--add-opens=java.base/sun.security.x509=ALL-UNNAMED
--add-opens=java.management/sun.management=ALL-UNNAMED
--add-opens=jdk.management/com.sun.management.internal=ALL-UNNAMED
--add-opens=jdk.unsupported/sun.misc=ALL-UNNAMED