应用层迁移

目标:通过本次应用迁移实验,使学员掌握了解常见Java的应用环境的迁移。

应用迁移

在云计算时代,由于功耗低、高性能以及指令集的优势,越来越多的云厂商开始选择基于ARM 体系来构建云服务。小汪公司的业务系统主要采用的是基于Java环境的应用,IT部正在对于系统从X86迁移到ARM 环境提出了质疑,业务系统迁移到新的ARM 架构中是否能够正常运维,迁移的可行性等问题困扰着IT和业务部门。

那么常规的应用迁移步骤,如Java Python Go C++,不同语言如何迁移?

解释型或编译成字节码型语言 – 开箱即用

Python, Java, Ruby, PHP, Node.js, many others
.NET Core supports Linux and arm64

编译型语言– 基于ARM的编译器进行重新编译

C, C++, Go , Rust

由于小汪公司应用使用的是Java技术栈,我们需要考虑应用的兼容性(ARM 平台兼容的JVM),迁移源和目标的系统环境,确认是否使用那些第三方的库,依赖包的重新编译等。 虽然Java本身可开销即用,但Java JAR可以包含特定于体系结构的共享库(例如Java工厂中包含了Go语言开发的shared library给Java主工程调用),检查JAR是否包含此类共享库的一种快速方法是简单地将其解压缩,并检查是否有任何结果文件是共享库,以及是否缺少aarch64(arm64)共享库, 小技巧是共享库一定以.so结尾. (so ==share object)

unzip redisson-tomcat-9-3.14.1.jar
cd redisson-tomcat-9-3.14.1
find . -name "*.so" | xargs flie

同时设计应用迁移我们还需要考虑整体迁移带来的配置信息的变更影响,例如数据库和Web服务器的关联配置。在应用架构中是否有配置中心,是否使用Router 53这类域名代理可以全局改动上下游配置地址

Java 迁移实验手册

实验流程:

1.应用评估,考虑约束和迁移步骤;

2.目标端主机基础环境安装和配置;

3.修改应用源码,重新打包应用;

4.修改应用配置文件,启动应用程序;

5.测试应用与数据层交互。

1. 应用评估

从X86到ARM 环境,我们首先需要对迁移的环境做评估,应该包含以下几个纬度

  • 目标端硬件信息收集
  • 目标端的软件栈信息收集
  • 迁移分析,对收集到的信息做分析,主要分为代码迁移和软件包迁移
  • 架构中上下游组件endpoint变更对应用配置带来的影响

根据调研会议,小汪公司的应用包含如下软件包,经过检查不包含跨语言共享库:

    redisson-all-3.14.1.jar
    redisson-tomcat-9-3.14.1.jar
    apache-tomcat-9.0.41.tar.gz
    sample-webapp.war

其中sample-webapp中硬编码了配置信息,redisson的两个可包通过tomcat配置文件进行配置

调研会上同时了解到,客户没有配置中心和DNS cname服务,上下游关联的endpoint均硬编码在代码和配置文件中

分析小结:

  • Java程序是基于jvm区运行的,所以需要使用ARM 平台兼容的JVM。
  • Java应用会关联架构上下游组件,硬编码和配置文件均需变更为新的有效地址,硬编码要在源码中变更,配置文件的则修改配置文件,无需源码层操作。

2. 目标端主机安装和配置

创建EC2,在左侧的控制台导航菜单选择EC2 DashboardEC2控制面板

验证控制台右上角的Region(区域)是否与本次实验的Region值一致,然后从列表中选择 Launch instance(启动实例)下拉菜单,启动实例

选择启动实例 注意:架构处的下拉框请选中 64位(ARM ),如下图

启动实例的参数如下:

创建EC2如下:

  • 名称: Graviton_Target-App
  • 实例类型:c6g.large
  • Amazon Machine Image(AMI): Amazon Linux 2 AMI(HVM)
  • 架构:64位(***ARM*** )
  • 密钥对名称:ee-default-keypair.pem
  • VPC: Graviton-GameDay-VPCStack-xxxxxxxx
  • 子网组:Private subnet 1A
  • 安全组:选择一个安全组 Graviton-GameDay-SecurityGroupStack-xxxxxxx-AppServerSecurityGroup
  • 实例实例:1

最后点击启动实例按钮在,请在summary(汇总)核对下参数信息。 启动完毕EC2后,可以悬着 View all instance(查看所有实例),等待实例的状态显示为Running(正在运行),这表示实例已完成启动。

3. 应用迁移实施

3.1使用登录SSM的远程连接管理器或者Putty连接到堡垒机

登录到堡垒机后再登录到应用服务器,请您记录下源java的Private IP DNS name如下图所示

在堡垒机上使用ssh命令登录后端机器,输入

ssh -i ee-default-keypair.pem ec2-user@<your-app-Private-name>

其中 ee-default-keypair.pem替换为您秘钥的文件名,<your-app-Private-name>替换为您在控制塔查看的redis的Private IP DNS name,输入yes以便确定连接

3.2 部署应用相关的ARM 环境中的JVM环境,依赖包等

AWS extras了流行的软件包,在任何平台安装常用的软件包非常简单,现在我们在Java目标机上使用安装基础配置,输入


sudo yum -y update -y
sudo amazon-linux-extras install java-openjdk11 -y

3.3 由于Java硬编码需要在代码中改写新的Mysql和Redis地址,我们需要打开应用源码修改并且重新打包

首先我们安装打包工具 maven

cd /home/ec2-user/
wget https://dlcdn.apache.org/maven/maven-3/3.8.6/binaries/apache-maven-3.8.6-bin.tar.gz
tar -zvxf apache-maven-3.8.6-bin.tar.gz
sudo mv apache-maven-3.8.6 /usr/local/maven

使用命名 vim ~/.bashrc 添加以下环境变量,便于我们日常使用命令

sudo su
vim ~/.bashrc

添加以下路径

export MAVEN_HOME=/usr/local/maven
export PATH=$PATH:$MAVEN_HOME/bin

在编辑器下按下esc建,使用命令:wq命令保存并退出VIM编辑器

使用source ~/.bashrc命令生效

source ~/.bashrc

3.4 下载源码文件,并进行数据层新地址配置

下载源码文件,请输入以下命令

sudo mkdir /home/ec2-user/code/
sudo wget https://awspsa-quickstart.s3.cn-northwest-1.amazonaws.com.cn/gravitongameday/code/code.tar.gz
sudo tar -zxvf code.tar.gz

sudo mkdir /home/ec2-user/config/
sudo wget https://awspsa-quickstart.s3.cn-northwest-1.amazonaws.com.cn/gravitongameday/config/tomcat.service -O /home/ec2-user/config/tomcat.service
sudo wget https://awspsa-quickstart.s3.cn-northwest-1.amazonaws.com.cn/gravitongameday/config/server.xml -O /home/ec2-user/config/server.xml 
sudo wget https://awspsa-quickstart.s3.cn-northwest-1.amazonaws.com.cn/gravitongameday/config/context.xml -O /home/ec2-user/config/context.xml
sudo wget https://awspsa-quickstart.s3.cn-northwest-1.amazonaws.com.cn/gravitongameday/config/httpd.conf -O /home/ec2-user/config/httpd.conf
sudo wget https://awspsa-quickstart.s3.cn-northwest-1.amazonaws.com.cn/gravitongameday/config/redisson.yaml -O /home/ec2-user/config/redisson.yaml
sudo wget https://awspsa-quickstart.s3.cn-northwest-1.amazonaws.com.cn/gravitongameday/config/webappdb_create_tables.sql -O /home/ec2-user/config/webappdb_create_tables.sql
sleep 1

使用编辑器打开源码文件

要编辑源码文件,请输入以下命令

sudo chmod 744 /home/ec2-user/code/sample-webapp/src/main/java/com/sample/app/usermanagement/dao/UserDAO.java
vim /home/ec2-user/code/sample-webapp/src/main/java/com/sample/app/usermanagement/dao/UserDAO.java

您可以阅读代码,这是一个逻辑简单的对联系人进行增删改查去操作mysql的代码,我们需要在public class UserDAO中修改新的数据库地址

请替换为您Graviton Mysql 实例私有域名地址,并将用户名进行更新,如果您没有自定义,您的用户名是graviton密码是GravitonGameDay@2022

在编辑器下按下esc建,使用命令:wq命令保存并退出VIM编辑器

3.5 使用maven重新打包应用,并将新的War包移动到正确路径

使用maven打包应用 请使用以下命令

cd /home/ec2-user/code/sample-webapp
mvn clean install

打包成功,得到如下反馈

....................
[INFO] 
[INFO] --- maven-war-plugin:3.3.1:war (default-war) @ sample-webapp ---
[INFO] Packaging webapp
[INFO] Assembling webapp [sample-webapp] in [/home/ec2-user/code/sample-webapp/target/sample-webapp]
[INFO] Processing war project
[INFO] Copying webapp resources [/home/ec2-user/code/sample-webapp/src/main/webapp]
[INFO] Building war: /home/ec2-user/code/sample-webapp/target/sample-webapp.war
[INFO] 
[INFO] --- maven-install-plugin:2.4:install (default-install) @ sample-webapp ---
[INFO] Installing /home/ec2-user/code/sample-webapp/target/sample-webapp.war to /root/.m2/repository/com/sample/app/sample-webapp/1.0/sample-webapp-1.0.war
[INFO] Installing /home/ec2-user/code/sample-webapp/pom.xml to /root/.m2/repository/com/sample/app/sample-webapp/1.0/sample-webapp-1.0.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  3.028 s
[INFO] Finished at: 2022-09-09T05:34:32Z
[INFO] ------------------------------------------------------------------------

部署tomcat 请使用以下命令

cd /home/ec2-user/code/
useradd -d /usr/share/tomcat -s /bin/nologin tomcat
cp -rf /home/ec2-user/config/tomcat.service /etc/systemd/system/tomcat.service
tar -zxvf /home/ec2-user/code/apache-tomcat-*.tar.gz
sleep 1
cp -rf /home/ec2-user/code/apache-tomcat-9.0.41/* /usr/share/tomcat
chown -R tomcat:tomcat /usr/share/tomcat/
systemctl daemon-reload
systemctl start tomcat
systemctl enable tomcat
yum install -y mysql
yum install -y ruby
cd /home/ec2-user

复制tomcat配置文件到应用路径 请使用以下命令

sudo cp /home/ec2-user/code/redisson-all-3.14.1.jar /usr/share/tomcat/lib/redisson-all-3.14.1.jar
sudo cp /home/ec2-user/code/redisson-tomcat-9-3.14.1.jar /usr/share/tomcat/lib/redisson-tomcat-9-3.14.1.jar
sudo cp /home/ec2-user/config/server.xml /usr/share/tomcat/conf/server.xml
sudo cp /home/ec2-user/code/sample-webapp/target/sample-webapp.war /usr/share/tomcat/webapps/sample-webapp.war

复制tomcat配置文件到应用路径

编辑配置文件,进行数据层新地址配置 编写Mysql配置文件,请输入以下命令


sudo cat << EOF >  /usr/share/tomcat/conf/context.xml
<?xml version='1.0' encoding='utf-8'?>
<Context>
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <Manager className="org.redisson.tomcat.RedissonSessionManager"
        configPath="\${catalina.base}/conf/redisson.yaml" 
        readMode="REDIS" updateMode="AFTER_REQUEST" broadcastSessionEvents="false"
        keyPrefix=""/>
    <Resource name="jdbc/webappdb" auth="Container" type="javax.sql.DataSource"
               maxTotal="100" maxIdle="30" maxWaitMillis="10000"
               username="$DBMasterUsername" password="$DBMasterUserPassword" driverClassName="com.mysql.jdbc.Driver"
               url="jdbc:mysql://$MySQLEndpoint:3306/webappdb"/>
</Context>
EOF

sudo vim /usr/share/tomcat/conf/context.xml

请将$DBMasterUsername,$DBMasterUserPassword,$MySQLEndpoint替换为Graviton Mysql的配置信息,如我们在Java代码中的改动一样,用户名是graviton密码是GravitonGameDay@2022,MySQLEndpoint是你graviton的mysql地址

完成替换后在编辑器下按下esc建,使用命令:wq命令保存并退出VIM编辑器

编写Redis配置文件,请输入以下命令

sudo cat << EOF >  /usr/share/tomcat/conf/redisson.yaml
singleServerConfig:
    idleConnectionTimeout: 10000
    connectTimeout: 10000
    timeout: 3000
    retryAttempts: 3
    retryInterval: 1500
    password: null
    subscriptionsPerConnection: 5
    clientName: null
    address: "redis://$RedisEndpoint:6379"
    subscriptionConnectionMinimumIdleSize: 1
    subscriptionConnectionPoolSize: 50
    connectionMinimumIdleSize: 10
    connectionPoolSize: 64
    database: 0
    dnsMonitoringInterval: 5000
threads: 0
nettyThreads: 0
EOF

sudo vim /usr/share/tomcat/conf/redisson.yaml

请将$RedisEndpoint替换为Graviton Redis的配置信息,填入该实例的Private IP DNS name

给应用包授权并重启tomcat服务

sudo chown tomcat:tomcat /usr/share/tomcat/lib/redisson-all-3.14.1.jar
sudo chown tomcat:tomcat /usr/share/tomcat/lib/redisson-tomcat-9-3.14.1.jar
sudo systemctl restart tomcat
sudo systemctl status tomcat

4.应用测试和验证

在您的APP服务器上Curl一下8080端口,请输入以下命令

curl 127.0.0.1:8080/sample-webapp/

您将得到如下返回,是我们Contact Management应用系统的前端代码

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Login</title>
<link rel="stylesheet"
        href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
        integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
        crossorigin="anonymous">
</head>
<body>
        <div class="container col-md-5">
                <div class="card">
                        <div class="card-body">
                                        <form action="j_security_check" method="post">
                                <caption>
                                        <h2>
                                                Wellcome to Graviton Game Day
                                        </h2>
                                        <h2>
                                                Login to Contact Management
.......
.......
                                                name="j_password">
                        </div>
                </div>
        </div>
</body>

至此,您完成了应用层的迁移,并且验证了应用层验证与迁移后数据层的调用测试


而如果您的CURL命令得到404等其他报错,说明您并没有正确完成实验。可推断您的任一迁移环节出现笔误或缺失,您可以查看tomcat 日志进行排错,要打印tomcat日志,请输入:

cat /usr/share/tomcat/logs/catalina.out

请留意任何failed相关的日志,例如以下日志表达不能连接到redis服务器,经过排查了解到redis服务没有启动.

13-Sep-2022 07:49:13.211 SEVERE [main] org.apache.catalina.core.StandardContext.startInternal The session manager failed to start
        org.apache.catalina.LifecycleException: org.redisson.client.RedisConnectionException: Unable to connect to Redis server: ip-10-0-3-152.ec2.internal/10.0.3.152:6379

您也可以与现场导师讨论您的报错原因。

Appendix

  • Go迁移的案例
  • Python迁移 X86-ARM
  • C++从X86-ARM