How Do I Package a Java or Tomcat Application?
ServiceStage allows you to compress a Java or Tomcat application into a .zip or .tar.gz package for deploying a component on a VM.
Application Package Directory Structure
- Example Java application package: https://github.com/servicestage-demo/example/tree/master/servicestage-vm-demo/demoJavaExample.zip
- Example Tomcat application package: https://github.com/servicestage-demo/example/tree/master/servicestage-vm-demo/demoTomcatExample.zip
The following uses the Java application package demoJavaExample.zip to illustrate the application package directory structure:
demoJavaExample/ │ ├── scripts/ │ │ ├── pre-stop.sh │ │ ├── stop.sh │ │ ├── uninstall.sh │ │ ├── install.sh │ │ ├── start.sh │ │ ├── check.sh │ │ ├── post-start.sh ├── packages/ │ │ ├── weather-1.0.0.jar ├── config/ │ │ ├── system.cfg ├── appspec.yml
The prefix of the package name must be the same as the directory name of the decompressed file. For example, a package named demoJavaExample.zip will have a directory after decompression named demoJavaExample.
The directories and files in the application package are described as follows:
- scripts: (mandatory) stores script files executed in each application lifecycle.
- packages: (mandatory) stores application JAR or WAR packages.
- config: (mandatory) stores application configuration information. For Java applications, the system.cfg file is stored. For Tomcat applications, the system.cfg, logging.properties, and server.xml files are stored.
- appspec.yml: (mandatory) records the lifecycle definition and also specifies information such as health check.
appspec.yml File Description
As shown in the following, the appspec.yml file defines the entire deployment process, and the environment variables and health check information used during deployment.
spec: # Custom user for application running. deps: - name: "@os/linux/user@1.0" user: www group: www home: /home/www # Directly import the environment variables of the application lifecycle script. env: - name: APP_ENV value: "{{app.env}}" # Import the environment variables of the application lifecycle script in the /opt/application/${appName}/${appVersion}/${instanceId}/servicestage-vmapp/application.conf file as a file. value: - name: APP_VALUE value: "{{app.value}}" # Application health check. probes: # Interface health check. # health: # exec: # method: GET # request: http://127.0.0.1:8080/healthcheck # timeout: 5 # Script command health check. liveness: exec: command: - ps -ef | grep ${APP_HOME}/apache-tomcat-*/bin/bootstrap.jar | grep -v grep # Currently, only APP_HOME can be used to obtain environment variables. timeout: 300 runas: www # Application lifecycle script. lifecycle: install: - command: scripts/install.sh timeout: 300 check: - command: scripts/check.sh timeout: 300 runas: www start: - command: scripts/start.sh timeout: 300 runas: www post-start: - command: scripts/post-start.sh timeout: 300 runas: www pre-stop: - command: scripts/pre-stop.sh timeout: 300 runas: www stop: - command: scripts/stop.sh timeout: 300 runas: www uninstall: - command: scripts/uninstall.sh timeout: 300
- deps: defines the custom user for application running. Set this field by referring to the following example.
deps: - name: "@os/linux/user@1.0" user: www group: www home: /home/www
- env: records the environment variables during the running of each script. The environment variables can be directly imported during script running.
- value: saved in the ${APP_HOME}/servicestage-vmapp/application.conf file. To use these values in the script, run the following command at the beginning of the script:
#!/bin/bash . ${APP_HOME}/servicestage-vmapp/application.conf # dosomething
- probes: records either health check command or interface, or both.
- health: accesses the health check interface to check the component status.
- method: HTTP method used to access the interface.
- request: access address.
- body: request body.
- timeout: timeout interval, in seconds.
- liveness: runs a command to check the component status.
- command: command used to check the status.
- runas: Linux user who runs the command. You are advised to set this parameter to www or leave it empty.
- timeout: timeout interval, in seconds.
- lifecycle: script or command executed in each lifecycle.
- command: script file to be executed. The value must be a file path relative to the ${APP_HOME} directory.
- timeout: timeout interval, in seconds.
- runas: user who executes the command. Must be www or left empty.
Lifecycle execution sequence:
- Deployment sequence: ServiceStage installation technology stack + install.sh -> start.sh -> check.sh -> post-start.sh
- Upgrade/Rollback sequence: ServiceStage installation technology stack + install.sh -> pre-stop.sh -> stop.sh -> uninstall.sh + ServiceStage uninstallation technology stack -> start.sh -> check.sh ->post-start.sh
- Deletion sequence: pre-stop.sh -> stop.sh -> uninstall.sh + ServiceStage
config Description
- system.cfg file
- Set the config parameter.
When creating a component based on a VM, you can set some configuration items by referring to Adding a Configuration Item. ServiceStage stores the configured configuration items in the ${APP_HOME}/config/system.cfg file as key-value pairs. You can also preset some configuration parameters in the config file. Example:
# Format of the content stored in the system.cfg file key1=value1 key2=value2
- Reference the config parameter.
Example:
#!/bin/bash . ${APP_HOME}/config/system.cfg . ${APP_HOME}/config/user_config.cfg echo ${key1}
- Set the config parameter.
- server.xml file
- logging.properties file
packages Directory Description
This folder holds the JAR and WAR packages to be executed when running commands in the script.
scripts Directory Description
This folder stores the scripts executed in each lifecycle of an application.
Default System Configurations
The default configurations are stored in the ${APP_HOME}/servicestage-vmapp/application.conf file. The file content is:
export LOG_PATH=/var/log/application/zqb-4-vm-wqd-2-7f6fbc/3c719644-f9f5-46b4-a06a-61fcf163e5b5 export APP_HOME=/opt/application/zqb-4-vm-wqd-2-7f6fbc/2023.1207.11314/3c719644-f9f5-46b4-a06a-61fcf163e5b5 export TOMCAT_STACK_HOME=/opt/application/zqb-4-vm-wqd-2-7f6fbc/2023.1207.11314/3c719644-f9f5-46b4-a06a-61fcf163e5b5/apache-tomcat-8.5.82 export JRE_STACK_HOME=/opt/application/zqb-4-vm-wqd-2-7f6fbc/2023.1207.11314/3c719644-f9f5-46b4-a06a-61fcf163e5b5/jre1.8 export APP_VALUE="{{app.value}}" export APP_USER=www export APP_GROUP=www
- LOG_PATH: log recording path. Application logs are recorded in the log file in LOG_PATH and named {lifecycle}_app.log.
- APP_HOME: records the running environment of the current application.
- TOMCAT_STACK_HOME: home directory of Tomcat.
- JRE_STACK_HOME: home directory of JRE.
- APP_VALUE: environment variable specified in appspec.yml.
- APP_USER: the file's user.
- APP_GROUP: the file's owner group.
Default system configurations are not directly displayed in environment variables. The available script environment variables are: APP_HOME, those specified in appspec.yml, and those specified in Adding a Component Environment Variable.
Script Writing Description
The directory structure for executing scripts on ServiceStage is:
APP_HOME/ │ ├── scripts/ │ │ ├── pre-stop.sh │ │ ├── stop.sh │ │ ├── uninstall.sh │ │ ├── install.sh │ │ ├── start.sh │ │ ├── check.sh │ │ ├── post-start.sh │ ├──packages/ │ │ ├── my-app.jar/my-app.war ├── config/ │ │ ├── system.cfg ├── servicestage-vmapp/ │ │ ├── application.conf ├── jre1.8 ├── apache-tomcat-8.5.82
- When writing scripts, go to the ${APP_HOME} directory to obtain the locations of other files.
- To obtain the location of JRE or Tomcat, run the following commands at the beginning of the script. Use ${APP_HOME}/servicestage-vmapp/application.conf to load environment variables and then use ${JRE_STACK_HOME} or ${TOMCAT_STACK_HOME} to obtain the values.
- ServiceStage reports logs in the ${LOG_PATH} directory. Therefore, record them in the log file in the ${LOG_PATH} directory and name them {lifecycle}_app.log to facilitate subsequent log reporting.
- It is recommended that the script start with the following lines to obtain environment variables and user configurations, and specify the technology stack home directory, log output path, and current execution address.
#!/bin/bash # Obtain user configurations and specify environment variables. . ${APP_HOME}/config/system.cfg . ${APP_HOME}/servicestage-vmapp/application.conf # Specify the technology stack home directory. JRE_HOME=${JRE_STACK_HOME} TOMCAT_HOME=${TOMCAT_STACK_HOME} # Specify the log output path. installLog="${LOG_PATH}/install_app.log" # Method of printing logs. function writeLog() { msg="$1\n" printf "[`date '+%Y-%m-%d %H:%M:%S'`] $msg" | sudo tee -a ${installLog}; } writeLog "-----begin!------"
server.xml Description of Tomcat
- When creating the Tomcat component, you can prepare the server.xml file in advance and copy the file to the Tomcat directory. (You are advised to perform this step in the install lifecycle.)
#!/bin/bash . ${APP_HOME}/servicestage-vmapp/application.conf cp ${APP_HOME}/conf/server.xml ${TOMCAT_STACK_HOME}/conf/server.xml
- ServiceStage presets a server.xml file in ${TOMCAT_STACK_HOME}/conf/server.xml. The file contains four placeholders. You need to replace them by referring to the following code:
#!/bin/bash . ${APP_HOME}/servicestage-vmapp/application.conf function replacePara() { sWord=$1 dWord=$2 theFile=$3 if [[ "$sWord" == "" || "$theFile" == "" ]] then writeLog "[ERROR] ReplacePara has empty param, \$1:$sWord, \$3:$theFile" return 1 fi if [[ ! -f ${theFile} ]] then writeLog "[ERROR] File $theFile does not exist." return 1 fi count=`grep -c "$sWord" ${theFile}` if [[ "${count}" == "0" ]];then return 0 fi sed "s#$sWord#${dWord}#g" ${theFile} > ${theFile}.temp if [[ "$?" != "0" ]] then writeLog "[ERROR] Sed command in replacePara error." return 1 fi mv -f ${theFile}.temp ${theFile} } replacePara "@{LOG_FILE_PATH_APP}" "${LOG_FILE_PATH_APP}" ${TOMCAT_HOME}/conf/server.xml replacePara "@{http_port}" "${instance_port_port}" ${TOMCAT_HOME}/conf/server.xml replacePara "@{server_port}" "${server_port}" ${TOMCAT_HOME}/conf/server.xml replacePara "@{APP_PACKAGE_NAME}" "examples.war" ${TOMCAT_HOME}/conf/server.xml
- @{server_port}: port number of the Tomcat server.
- @{APP_PACKAGE_NAME}: path of the WAR package relative to ${TOMCAT_STACK_HOME}.
- @{http_port}: port number of the Tomcat connector.
- @{LOG_FILE_PATH_APP}: path for printing Tomcat logs.
logging.properties Description of Tomcat
Prepare the logging.properties file and copy it to the Tomcat directory. Example of copying the code:
#!/bin/bash . ${APP_HOME}/servicestage-vmapp/application.conf cp ${APP_HOME}/conf/logging.properties ${TOMCAT_STACK_HOME}/conf/logging.properties
The logging.properties file contains the following information, where @{LOG_FILE_PATH_APP} is the actual log directory.
handlers = 1catalina.org.apache.juli.AsyncFileHandler, 2localhost.org.apache.juli.AsyncFileHandler, 3manager.org.apache.juli.AsyncFileHandler, 4host-manager.org.apache.juli.AsyncFileHandler, java.util.logging.ConsoleHandler .handlers = 1catalina.org.apache.juli.AsyncFileHandler, java.util.logging.ConsoleHandler 1catalina.org.apache.juli.AsyncFileHandler.level = FINE 1catalina.org.apache.juli.AsyncFileHandler.directory = @{LOG_FILE_PATH_APP} 1catalina.org.apache.juli.AsyncFileHandler.prefix = catalina. 2localhost.org.apache.juli.AsyncFileHandler.level = FINE 2localhost.org.apache.juli.AsyncFileHandler.directory = @{LOG_FILE_PATH_APP} 2localhost.org.apache.juli.AsyncFileHandler.prefix = localhost. 3manager.org.apache.juli.AsyncFileHandler.level = FINE 3manager.org.apache.juli.AsyncFileHandler.directory = @{LOG_FILE_PATH_APP} 3manager.org.apache.juli.AsyncFileHandler.prefix = manager. 4host-manager.org.apache.juli.AsyncFileHandler.level = FINE 4host-manager.org.apache.juli.AsyncFileHandler.directory = @{LOG_FILE_PATH_APP} 4host-manager.org.apache.juli.AsyncFileHandler.prefix = host-manager. java.util.logging.ConsoleHandler.level = FINE java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = 2localhost.org.apache.juli.AsyncFileHandler org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = 3manager.org.apache.juli.AsyncFileHandler org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level = INFO org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers = 4host-manager.org.apache.juli.AsyncFileHandler org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = 2localhost.org.apache.juli.AsyncFileHandler org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = 3manager.org.apache.juli.AsyncFileHandler org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level = INFO org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers = 4host-manager.org.apache.juli.AsyncFileHandler
FAQ
- How do I run a script as user root?
- Write the content to be executed by user root into the root-install.sh script.
- Run the following statement in the install.sh script to be executed. ${ROOT_PASSWORD} is the password of user root, and the content in the double quotation marks after -c is the command to be executed. Environment variables will be lost after you switch user, so add the required environment variables before sh.
echo "${ROOT_PASSWORD}" | su - root -c "APP_HOME=${APP_HOME} sh root-install.sh"
- If you get the error message "su: Permission denied", find the /etc/pam.d/su file and comment out "auth required pam_wheel.so use_uid."
Feedback
Was this page helpful?
Provide feedbackThank you very much for your feedback. We will continue working to improve the documentation.See the reply and handling status in My Cloud VOC.
For any further questions, feel free to contact us through the chatbot.
Chatbot