背景:
windows系统下生成的jar包通过FTP上传到linux服务器,然后通过XShell进行jar包的发布,这样反复了几个月后,开发阶段需要频繁更新包的部署。个人觉得很繁琐,想一键式把这个工作做了,不想经常花时间发布。前几天去了解了下Docker+Jenkins的方式,但是过于麻烦,对我个人学习时间和成本比较高。从而衍生出想用自己比较拿手的C#编写一个小工具解决我这个问题
需求:
windows环境jar包部署到linux服务器,一键操作
下载:
https://files.cnblogs.com/files/shexunyu/Linux%E9%83%A8%E7%BD%B2%E5%B0%8F%E5%B7%A5%E5%85%B7V2.zip
https://pan.baidu.com/s/15HpNjKDBiuLf7mNgSlbDFw 提取码:pk5n
小工具:
界面
程序构建方式
1.通过Neget安装SSH.NET
2.后端代码
1.设计器代码
namespace Deploy
{
partial class DeployFrm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null; /// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
} #region Windows Form Designer generated code /// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.txtLocalFilePath = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.txtServerFilePath = new System.Windows.Forms.TextBox();
this.txtPort = new System.Windows.Forms.TextBox();
this.label8 = new System.Windows.Forms.Label();
this.IP = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.txtPassword = new System.Windows.Forms.TextBox();
this.label5 = new System.Windows.Forms.Label();
this.txtUserName = new System.Windows.Forms.TextBox();
this.txtIP = new System.Windows.Forms.TextBox();
this.txtServerDirectory = new System.Windows.Forms.TextBox();
this.btnConnection = new System.Windows.Forms.Button();
this.btnUpload = new System.Windows.Forms.Button();
this.btnRun = new System.Windows.Forms.Button();
this.label7 = new System.Windows.Forms.Label();
this.txtLog = new System.Windows.Forms.TextBox();
this.btnSaveInfo = new System.Windows.Forms.Button();
this.btnStop = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(, );
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(, );
this.label1.TabIndex = ;
this.label1.Text = "LocalFilePath:";
//
// txtLocalFilePath
//
this.txtLocalFilePath.Location = new System.Drawing.Point(, );
this.txtLocalFilePath.Name = "txtLocalFilePath";
this.txtLocalFilePath.Size = new System.Drawing.Size(, );
this.txtLocalFilePath.TabIndex = ;
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(, );
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(, );
this.label2.TabIndex = ;
this.label2.Text = "ServerFilePath:";
//
// txtServerFilePath
//
this.txtServerFilePath.Location = new System.Drawing.Point(, );
this.txtServerFilePath.Name = "txtServerFilePath";
this.txtServerFilePath.Size = new System.Drawing.Size(, );
this.txtServerFilePath.TabIndex = ;
//
// txtPort
//
this.txtPort.Location = new System.Drawing.Point(, );
this.txtPort.Name = "txtPort";
this.txtPort.Size = new System.Drawing.Size(, );
this.txtPort.TabIndex = ;
//
// label8
//
this.label8.AutoSize = true;
this.label8.Location = new System.Drawing.Point(, );
this.label8.Name = "label8";
this.label8.Size = new System.Drawing.Size(, );
this.label8.TabIndex = ;
this.label8.Text = "Port:";
//
// IP
//
this.IP.AutoSize = true;
this.IP.Location = new System.Drawing.Point(, );
this.IP.Name = "IP";
this.IP.Size = new System.Drawing.Size(, );
this.IP.TabIndex = ;
this.IP.Text = "IP:";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(, );
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(, );
this.label3.TabIndex = ;
this.label3.Text = "ServerDirectory:";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(, );
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(, );
this.label4.TabIndex = ;
this.label4.Text = "UserName:";
//
// txtPassword
//
this.txtPassword.Location = new System.Drawing.Point(, );
this.txtPassword.Name = "txtPassword";
this.txtPassword.Size = new System.Drawing.Size(, );
this.txtPassword.TabIndex = ;
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(, );
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(, );
this.label5.TabIndex = ;
this.label5.Text = "Password:";
//
// txtUserName
//
this.txtUserName.Location = new System.Drawing.Point(, );
this.txtUserName.Name = "txtUserName";
this.txtUserName.Size = new System.Drawing.Size(, );
this.txtUserName.TabIndex = ;
//
// txtIP
//
this.txtIP.Location = new System.Drawing.Point(, );
this.txtIP.Name = "txtIP";
this.txtIP.Size = new System.Drawing.Size(, );
this.txtIP.TabIndex = ;
//
// txtServerDirectory
//
this.txtServerDirectory.Location = new System.Drawing.Point(, );
this.txtServerDirectory.Name = "txtServerDirectory";
this.txtServerDirectory.Size = new System.Drawing.Size(, );
this.txtServerDirectory.TabIndex = ;
//
// btnConnection
//
this.btnConnection.Location = new System.Drawing.Point(, );
this.btnConnection.Name = "btnConnection";
this.btnConnection.Size = new System.Drawing.Size(, );
this.btnConnection.TabIndex = ;
this.btnConnection.Text = "Connection";
this.btnConnection.UseVisualStyleBackColor = true;
this.btnConnection.Click += new System.EventHandler(this.btnConnection_Click);
//
// btnUpload
//
this.btnUpload.Location = new System.Drawing.Point(, );
this.btnUpload.Name = "btnUpload";
this.btnUpload.Size = new System.Drawing.Size(, );
this.btnUpload.TabIndex = ;
this.btnUpload.Text = "Upload";
this.btnUpload.UseVisualStyleBackColor = true;
this.btnUpload.Click += new System.EventHandler(this.btnUpload_Click);
//
// btnRun
//
this.btnRun.Location = new System.Drawing.Point(, );
this.btnRun.Name = "btnRun";
this.btnRun.Size = new System.Drawing.Size(, );
this.btnRun.TabIndex = ;
this.btnRun.Text = "Run";
this.btnRun.UseVisualStyleBackColor = true;
this.btnRun.Click += new System.EventHandler(this.btnRun_Click);
//
// label7
//
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(, );
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(, );
this.label7.TabIndex = ;
this.label7.Text = "Log:";
//
// txtLog
//
this.txtLog.Location = new System.Drawing.Point(, );
this.txtLog.Multiline = true;
this.txtLog.Name = "txtLog";
this.txtLog.Size = new System.Drawing.Size(, );
this.txtLog.TabIndex = ;
//
// btnSaveInfo
//
this.btnSaveInfo.Location = new System.Drawing.Point(, );
this.btnSaveInfo.Name = "btnSaveInfo";
this.btnSaveInfo.Size = new System.Drawing.Size(, );
this.btnSaveInfo.TabIndex = ;
this.btnSaveInfo.Text = "SaveInfo";
this.btnSaveInfo.UseVisualStyleBackColor = true;
this.btnSaveInfo.Click += new System.EventHandler(this.btnSaveInfo_Click);
//
// btnStop
//
this.btnStop.Location = new System.Drawing.Point(, );
this.btnStop.Name = "btnStop";
this.btnStop.Size = new System.Drawing.Size(, );
this.btnStop.TabIndex = ;
this.btnStop.Text = "Stop";
this.btnStop.UseVisualStyleBackColor = true;
this.btnStop.Click += new System.EventHandler(this.btnStop_Click);
//
// DeployFrm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(, );
this.Controls.Add(this.btnStop);
this.Controls.Add(this.btnSaveInfo);
this.Controls.Add(this.txtLog);
this.Controls.Add(this.label7);
this.Controls.Add(this.btnRun);
this.Controls.Add(this.btnUpload);
this.Controls.Add(this.btnConnection);
this.Controls.Add(this.txtPort);
this.Controls.Add(this.label8);
this.Controls.Add(this.IP);
this.Controls.Add(this.label3);
this.Controls.Add(this.label4);
this.Controls.Add(this.txtPassword);
this.Controls.Add(this.label5);
this.Controls.Add(this.txtUserName);
this.Controls.Add(this.txtIP);
this.Controls.Add(this.txtServerDirectory);
this.Controls.Add(this.txtServerFilePath);
this.Controls.Add(this.label2);
this.Controls.Add(this.txtLocalFilePath);
this.Controls.Add(this.label1);
this.Name = "DeployFrm";
this.Text = "DeployFrm";
this.Load += new System.EventHandler(this.DeployFrm_Load);
this.ResumeLayout(false);
this.PerformLayout(); } #endregion private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox txtLocalFilePath;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox txtServerFilePath;
private System.Windows.Forms.TextBox txtPort;
private System.Windows.Forms.Label label8;
private System.Windows.Forms.Label IP;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.TextBox txtPassword;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.TextBox txtUserName;
private System.Windows.Forms.TextBox txtIP;
private System.Windows.Forms.TextBox txtServerDirectory;
private System.Windows.Forms.Button btnConnection;
private System.Windows.Forms.Button btnUpload;
private System.Windows.Forms.Button btnRun;
private System.Windows.Forms.Label label7;
private System.Windows.Forms.TextBox txtLog;
private System.Windows.Forms.Button btnSaveInfo;
private System.Windows.Forms.Button btnStop;
}
}
2.业务代码
using Renci.SshNet;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Windows.Forms; namespace Deploy
{
public partial class DeployFrm : Form
{
public DeployFrm()
{
InitializeComponent();
deployBus.TxtLog = this.txtLog;
} public static DeployBusness deployBus = new DeployBusness(); public Deploy GetDeploy()
{
DateTime dt = DateTime.Parse("2019-09-30");
if (DateTime.Now > dt)
{
throw new Exception("请联系shexun进行版本更新");
}
var deploy = new Deploy(this.txtIP.Text, this.txtPort.Text, this.txtServerDirectory.Text, this.txtUserName.Text, this.txtPassword.Text, this.txtLocalFilePath.Text, this.txtServerFilePath.Text, "");
return deploy;
} public void LoadInfo()
{
var deploy = deployBus.ReadInfo();
if (deploy != null)
{
this.txtIP.Text = deploy.Host;
this.txtPort.Text = deploy.Port;
this.txtServerDirectory.Text = deploy.ServerDirectory;
this.txtUserName.Text = deploy.UserName;
this.txtPassword.Text = deploy.Password;
this.txtLocalFilePath.Text = deploy.LocalFilePath;
this.txtServerFilePath.Text = deploy.ServerFilePath; }
} private void btnUpload_Click(object sender, EventArgs e)
{
try
{
deployBus.Upload(GetDeploy());
}
catch (Exception ex)
{
deployBus.ShowLog(ex.Message);
}
} private void btnRun_Click(object sender, EventArgs e)
{
try
{
deployBus.Run(GetDeploy());
}
catch (Exception ex)
{
deployBus.ShowLog(ex.Message);
}
} private void btnSaveInfo_Click(object sender, EventArgs e)
{
try
{
deployBus.SaveInfo(GetDeploy());
}
catch (Exception ex)
{
deployBus.ShowLog(ex.Message);
}
} private void DeployFrm_Load(object sender, EventArgs e)
{
try
{
LoadInfo();
}
catch (Exception ex)
{
deployBus.ShowLog(ex.Message);
}
} private void btnStop_Click(object sender, EventArgs e)
{
try
{
deployBus.Stop(GetDeploy());
}
catch (Exception ex)
{
deployBus.ShowLog(ex.Message);
}
} private void btnBackUp_Click(object sender, EventArgs e)
{
} private void btnConnection_Click(object sender, EventArgs e)
{
try
{
deployBus.Connection(GetDeploy());
}
catch (Exception ex)
{
deployBus.ShowLog(ex.Message);
}
}
/// <summary>
/// 部署类
/// </summary>
[DataContract]
public class Deploy
{ public Deploy(string Host, string Port, string ServerDirectory, string UserName, string Password, string LocalFilePath, string ServerFilePath, string Log)
{
this.Host = Host != null ? Host.Trim() : null;
this.Port = Port != null ? Port.Trim() : null;
this.ServerDirectory = ServerDirectory != null ? ServerDirectory.Trim() : null;
this.UserName = UserName != null ? UserName.Trim() : null;
this.Password = Password != null ? Password.Trim() : null;
this.LocalFilePath = LocalFilePath != null ? LocalFilePath.Trim() : null;
this.ServerFilePath = ServerFilePath != null ? ServerFilePath.Trim() : null;
this.Log = Log != null ? Log.Trim() : null;
} [DataMember]
public string Host { get; set; }
[DataMember]
public string Port { get; set; }
[DataMember]
public string ServerDirectory { get; set; }
[DataMember]
public string UserName { get; set; }
[DataMember]
public string Password { get; set; }
[DataMember]
public string LocalFilePath { get; set; }
[DataMember]
public string ServerFilePath { get; set; }
[DataMember]
public string Log { get; set; }
} public class DeployBusness
{ public TextBox TxtLog { get; set; } public emAction EmAction { get; set; } public enum emAction { ___, Connection, Upload, BackUp, Run, Stop, SaveInfo, ReadInfo, Download }
public void ShowLog(string log)
{
string logStr = "";
logStr = EmAction.ToString();
var defaultNull = - logStr.Length;
if (defaultNull > )
{
string temp = "";
for (int i = ; i < defaultNull; i++)
{
temp += " ";
}
logStr += temp;
}
logStr += " => [ " + DateTime.Now.ToString() + " ] ";
logStr += log + "。\r\n";
if (this.TxtLog != null)
{
TxtLog.Text += logStr;
}
EmAction = emAction.___;
} public bool Connection(Deploy deploy)
{
this.EmAction = emAction.Connection;
using (var client = new SftpClient(deploy.Host, int.Parse(deploy.Port), deploy.UserName, deploy.Password)) //创建连接对象
{
client.Connect(); //连接
this.ShowLog("连接服务器成功");
}
return true;
} public bool BackUp(Deploy deploy)
{
//对应的服务未停止不能进行上传 this.EmAction = emAction.BackUp;
using (var client = new SftpClient(deploy.Host, int.Parse(deploy.Port), deploy.UserName, deploy.Password)) //创建连接对象
{
client.Connect(); //连接
var fileName = Path.GetFileName(deploy.ServerFilePath);
var changeDir = deploy.ServerFilePath.Replace(fileName, "");
client.ChangeDirectory(changeDir); //切换目录
//复制文件到新的文件目录 using (var fileStream = new FileStream(deploy.LocalFilePath, FileMode.Open))
{
this.ShowLog("正在上传文件,请稍等......");
client.BufferSize = * ; // bypass Payload error large
client.UploadFile(fileStream, fileName); //上传文件
this.ShowLog("上传文件成功");
}
}
return true;
} public bool Upload(Deploy deploy)
{
//对应的服务未停止不能进行上传 this.EmAction = emAction.Upload;
using (var client = new SftpClient(deploy.Host, int.Parse(deploy.Port), deploy.UserName, deploy.Password)) //创建连接对象
{
client.Connect(); //连接
var fileName = Path.GetFileName(deploy.ServerFilePath);
var changeDir = deploy.ServerFilePath.Replace(fileName, "");
client.ChangeDirectory(changeDir); //切换目录
using (var fileStream = new FileStream(deploy.LocalFilePath, FileMode.Open))
{
this.ShowLog("正在上传文件,请稍等......");
client.BufferSize = * ; // bypass Payload error large
client.UploadFile(fileStream, fileName); //上传文件
this.ShowLog("上传文件成功");
}
}
return true;
} public void Run(Deploy deploy)
{
this.EmAction = emAction.Run;
var con = new ConnectionInfo(deploy.Host, int.Parse(deploy.Port), deploy.UserName,
new AuthenticationMethod[]{
// Pasword based Authentication
new PasswordAuthenticationMethod(deploy.UserName,deploy.Password)
});
// Execute (SHELL) Commands
using (var sshclient = new SshClient(con))
{
sshclient.Connect();
this.ShowLog("连接服务器成功");
var psResevice = sshclient.CreateCommand("ps -ef").Execute();
var runList = new List<string>();
string[] lines = psResevice.Split('\n'); //用\n表示换行符 注意是char类型 分割行
var fileName = Path.GetFileName(deploy.ServerFilePath);
foreach (var item in lines)
{
if (item.Contains(fileName))
{
runList.Add(item);
this.ShowLog("找到服务:" + item);
}
} foreach (var item in runList)
{
var temp = item.Substring(, );
var pid = temp.Substring(, - ).Trim();
//获取到PID
var msg = sshclient.CreateCommand("kill -9 " + pid).Execute();
this.ShowLog("关闭服务PID:" + pid);
}
//更新文件 成功后执行命令
var changeDir = deploy.ServerFilePath.Replace(fileName, "").TrimEnd('/');
var command = "nohup java -jar " + fileName + ">>m.out.log 2>&1 &";
var msg2 = sshclient.CreateCommand("cd " + changeDir + ";" + command).Execute();
this.ShowLog("启动服务成功");
}
} public void Stop(Deploy deploy)
{
this.EmAction = emAction.Stop;
var con = new ConnectionInfo(deploy.Host, int.Parse(deploy.Port), deploy.UserName,
new AuthenticationMethod[]{
// Pasword based Authentication
new PasswordAuthenticationMethod(deploy.UserName,deploy.Password)
});
// Execute (SHELL) Commands
using (var sshclient = new SshClient(con))
{
sshclient.Connect();
var psResevice = sshclient.CreateCommand("ps -ef").Execute();
string[] lines = psResevice.Split('\n'); //用\n表示换行符 注意是char类型 分割行
var fileName = Path.GetFileName(deploy.ServerFilePath);
if (lines != null && lines.Length > )
{
this.ShowLog("存在" + lines.Length.ToString() + "个服务");
}
foreach (var item in lines)
{
if (item.Contains(fileName))
{
this.ShowLog("找到服务:" + item);
var temp = item.Substring(, );
var pid = temp.Substring(, - ).Trim();
//获取到PID
var msg = sshclient.CreateCommand("kill -9 " + pid).Execute(); }
}
psResevice = sshclient.CreateCommand("ps -ef").Execute();
lines = psResevice.Split('\n'); //用\n表示换行符 注意是char类型 分割行
var stopStatus = false;
foreach (var item in lines)
{
if (item.Contains(fileName))
{
stopStatus = true;
}
}
if (!stopStatus)
{
this.ShowLog("停止服务成功");
} }
} /// <summary>
/// 读取信息
/// </summary>
public Deploy ReadInfo()
{
this.EmAction = emAction.ReadInfo;
string path = AppDomain.CurrentDomain.BaseDirectory + @"Temp\Record\";
var defaultFileName = "Info.txt";
string fileFullPath = path + defaultFileName;
//加载对应的文件目录的所有文件
if (File.Exists(fileFullPath))
{
string info = File.ReadAllText(fileFullPath);
this.ShowLog("读取配置成功");
//反序列化
var deploy = MySerializer.JsonToObject<Deploy>(info);
return deploy;
} return null;
} /// <summary>
/// 保存信息
/// </summary>
public void SaveInfo(Deploy deploy)
{
this.EmAction = emAction.SaveInfo;
string path = AppDomain.CurrentDomain.BaseDirectory + @"Temp\Record\";
var fileFullPath = path + "Info.txt";
StreamWriter sw;
if (File.Exists(fileFullPath))
{
File.Delete(fileFullPath);
}
var info = MySerializer.ObjectToJson(deploy);
sw = File.CreateText(fileFullPath);
sw.WriteLine(info);
sw.Close();
this.ShowLog("保存配置成功");
} } public class MySerializer
{
/// <summary>
/// 将对象序列化为json字符串
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="t">实例</param>
/// <returns>json字符串</returns>
public static string ObjectToJson<T>(T t) where T : class
{
DataContractJsonSerializer formatter = new DataContractJsonSerializer(typeof(T));
using (MemoryStream stream = new MemoryStream())
{
formatter.WriteObject(stream, t);
string result = System.Text.Encoding.UTF8.GetString(stream.ToArray());
return result;
}
} /// <summary>
/// json字符串转成对象
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="json">json格式字符串</param>
/// <returns>对象</returns>
public static T JsonToObject<T>(string json) where T : class
{
DataContractJsonSerializer formatter = new DataContractJsonSerializer(typeof(T));
using (MemoryStream stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(json)))
{
T result = formatter.ReadObject(stream) as T;
return result;
}
}
}
}
}
总结:此工具我已分享给小组的开发同事一起使用,目前也有考虑在此基础上增加新的小功能,有兴趣的朋友请评论留言。