diff --git a/.travis.yml b/.travis.yml index 431a50cf..a081c2c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ branches: script: - if [ "$TRAVIS_OS_NAME" = "osx" ]; then ./build.sh --target=ci ; fi - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then tag=`date +%Y%m%d%H%M` ; export imagetag="jijiechen/dotnetclub:$tag" ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then tag=`date -u +%Y%m%d%H%M` ; export imagetag="jijiechen/dotnetclub:$tag" ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then ./build-linux.sh --target=ci --imagetag="$imagetag" ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ] && [ "$DOCKER_USERNAME" != "" ]; then docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD && docker push $imagetag ; fi diff --git a/DockerFile b/DockerFile index fb9e0e9a..19bf9de7 100644 --- a/DockerFile +++ b/DockerFile @@ -1,7 +1,7 @@ # How to run this image? # 1. (optional) At (WorkDir), Create your appsettings.json or appsettings..json # 2. (optional) At (WorkDir), Create your database file -# 3. execute docker run -d -v (WorkDir):/club-data -p 5000:5000 jijiechen/dotnetclub +# 3. Execute docker run -d -v (WorkDir):/club-data -p 5000:5000 jijiechen/dotnetclub @@ -12,10 +12,12 @@ VOLUME /club-data COPY . /club-app + RUN useradd --uid 5000 --create-home --home /home/clubadm clubadm RUN chown -R clubadm /home/clubadm RUN chown -R clubadm /club-data + USER clubadm WORKDIR /club-data ENTRYPOINT ["dotnet", "/club-app/Discussion.Web.dll", "--webroot", "/club-app/wwwroot"] diff --git a/OpenAspNetOrg.sln b/OpenAspNetOrg.sln index a4d9b287..59f2121f 100644 --- a/OpenAspNetOrg.sln +++ b/OpenAspNetOrg.sln @@ -20,6 +20,8 @@ ProjectSection(SolutionItems) = preProject Readme.md = Readme.md .gitignore = .gitignore DockerFile = DockerFile + deploy-on-hyper.sh = deploy-on-hyper.sh + upgrade-from-existing.sh = upgrade-from-existing.sh EndProjectSection EndProject Global diff --git a/build.cake b/build.cake index 9d94ff0b..69595084 100644 --- a/build.cake +++ b/build.cake @@ -82,6 +82,11 @@ Task("package") } CopyFile("./DockerFile", "./src/Discussion.Web/publish/DockerFile"); + + CopyFile("./upgrade-from-existing.sh", "./src/Discussion.Web/publish/upgrade-from-existing.sh "); + CopyFile("src/Discussion.Migrations/bin/Release/netcoreapp2.1/Discussion.Migrations.deps.json", "./src/Discussion.Web/publish/Discussion.Migrations.deps.json"); + CopyFile("src/Discussion.Migrations/bin/Release/netcoreapp2.1/Discussion.Migrations.runtimeconfig.json", "./src/Discussion.Web/publish/Discussion.Migrations.runtimeconfig.json"); + Execute($"docker build ./src/Discussion.Web/publish -t {imagetag} -f ./src/Discussion.Web/publish/DockerFile"); } }); diff --git a/deploy-on-hyper.sh b/deploy-on-hyper.sh new file mode 100755 index 00000000..e50da4f0 --- /dev/null +++ b/deploy-on-hyper.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +set -e + +oldVer=$1 +newVer=$2 + +RED=`tput setaf 1` +GREEN=`tput setaf 2` +NC=`tput sgr0` # no color + + +if [ "$newVer" == "" ] || [ "$oldVer" == "" ]; then + echo "${RED}请指定要从哪个版本升级到哪个版本!${NC}" + echo "${RED}比如,从第 001 升级到 003,请指定 deploy-on-hyper.sh 001 003${NC}" + exit 1 +fi + + +new_image="jijiechen/dotnetclub:$newVer" + +if [ "$oldVer" == "0" ]; then + # 首次安装时,创建 volume + hyper volume create --size=10 --name clubdata + + hyper run -d --name volumes -v clubdata:/club-data --size S3 --restart always hyperhq/nfs-server + + hyper exec volumes mkdir /club-data/$newVer + hyper exec volumes chmod -R 777 /club-data/$newVer + hyper exec -i volumes tee /club-data/$newVer/appsettings.Production.json < ./src/Discussion.Web/appsettings.Production.json +else + # 从旧版本升级到新版本 + hyper run --rm --name upgrade --volumes-from volumes --entrypoint "/club-app/upgrade-from-existing.sh" $new_image $oldVer $newVer +fi + + +# 运行新版本的程序 +hyper run -d -p 80:5000 --name "club$newVer" \ + --volumes-from volumes --size S4 --restart always \ + -e "ASPNETCORE_contentRoot=/club-data/$newVer" --workdir /club-data/$newVer $new_image + +# 分配新的 fip +fip=`hyper fip allocate --yes 1` +hyper fip attach $fip "club$newVer" + + +# 输出部署结果 +echo "" +echo "${GREEN}A new version ($new_image) is deployed at IP:$fip${NC}" + +# todo: your dns??? \ No newline at end of file diff --git a/src/Discussion.Migrations/Discussion.Migrations.csproj b/src/Discussion.Migrations/Discussion.Migrations.csproj index 1d5b8c16..2c706341 100644 --- a/src/Discussion.Migrations/Discussion.Migrations.csproj +++ b/src/Discussion.Migrations/Discussion.Migrations.csproj @@ -1,8 +1,12 @@  netcoreapp2.1 + Exe + + + \ No newline at end of file diff --git a/src/Discussion.Migrations/Supporting/SqliteMigrator.cs b/src/Discussion.Migrations/Supporting/SqliteMigrator.cs new file mode 100644 index 00000000..1f136d90 --- /dev/null +++ b/src/Discussion.Migrations/Supporting/SqliteMigrator.cs @@ -0,0 +1,81 @@ +using System; +using System.IO; +using FluentMigrator.Runner; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace Discussion.Migrations.Supporting +{ + public static class SqliteMigrator + { + static void Main(string[] args) + { + var connectionString = args != null && args.Length > 0 ? args[0] : null; + if (string.IsNullOrWhiteSpace(connectionString)) + { + PrintError("Please specify a connection string for the Sqlite db."); + Environment.Exit(1); + return; + } + + Console.WriteLine($"Starting migrating..."); + + try + { + Migrate(connectionString, null); + } + catch (Exception e) + { + PrintError(e.ToString()); + Environment.Exit(4); + } + + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("Migrating completed successfully"); + Console.ResetColor(); + } + + static void PrintError(string message) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.Error.WriteLine(message); + Console.ResetColor(); + } + + + public static void Migrate(string connectionString, Action configureLogging) + { + var services = CreateServices(connectionString, configureLogging); + + using (var scope = services.CreateScope()) + { + UpdateDatabase(scope.ServiceProvider); + } + + (services as IDisposable)?.Dispose(); + } + + private static IServiceProvider CreateServices(string connectionString, Action configureLogging) + { + return new ServiceCollection() + .AddFluentMigratorCore() + .ConfigureRunner(rb => rb + .AddSQLite() + .WithGlobalConnectionString(connectionString) + .ScanIn(typeof(CreateArticleTable).Assembly).For.Migrations()) + .AddLogging(logging => + { + logging.AddFluentMigratorConsole(); + configureLogging?.Invoke(logging); + }) + .BuildServiceProvider(false); + } + + + private static void UpdateDatabase(IServiceProvider serviceProvider) + { + var runner = serviceProvider.GetRequiredService(); + runner.MigrateUp(); + } + } +} \ No newline at end of file diff --git a/src/Discussion.Web/ApplicationSupport/DataInfrastructure.cs b/src/Discussion.Web/ApplicationSupport/DataInfrastructure.cs index 34b57d3b..8144e70d 100644 --- a/src/Discussion.Web/ApplicationSupport/DataInfrastructure.cs +++ b/src/Discussion.Web/ApplicationSupport/DataInfrastructure.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Discussion.Migrations.Supporting; using Discussion.Web.Data; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -53,7 +54,7 @@ static void InitializeDatabase(string connectionString, ILogger logger, { logger.LogCritical("正在创建新的数据库结构..."); - DatabaseMigrator.Migrate(connectionString, loggingConfiguration); + SqliteMigrator.Migrate(connectionString, logging => Configurer.ConfigureFileLogging(logging, true, loggingConfiguration)); logger.LogCritical("数据库结构创建完成"); } diff --git a/src/Discussion.Web/ApplicationSupport/DatabaseMigrator.cs b/src/Discussion.Web/ApplicationSupport/DatabaseMigrator.cs deleted file mode 100644 index 2976b198..00000000 --- a/src/Discussion.Web/ApplicationSupport/DatabaseMigrator.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using System; -using Discussion.Migrations; -using FluentMigrator.Runner; -using Microsoft.Extensions.Configuration; - - -namespace Discussion.Web.ApplicationSupport -{ - public static class DatabaseMigrator - { - public static void Migrate(string connectionString, IConfiguration loggingConfiguration) - { - var services = CreateServices(connectionString, loggingConfiguration); - - using (var scope = services.CreateScope()) - { - UpdateDatabase(scope.ServiceProvider); - } - - (services as IDisposable)?.Dispose(); - } - - private static IServiceProvider CreateServices(string connectionString, IConfiguration loggingConfiguration) - { - return new ServiceCollection() - .AddFluentMigratorCore() - .ConfigureRunner(rb => rb - .AddSQLite() - .WithGlobalConnectionString(connectionString) - .ScanIn(typeof(CreateArticleTable).Assembly).For.Migrations()) - .AddLogging(logging => - { - logging.AddFluentMigratorConsole(); - Configurer.ConfigureFileLogging(logging, true, loggingConfiguration); - }) - .BuildServiceProvider(false); - } - - - private static void UpdateDatabase(IServiceProvider serviceProvider) - { - var runner = serviceProvider.GetRequiredService(); - runner.MigrateUp(); - } - } -} \ No newline at end of file diff --git a/src/Discussion.Web/Discussion.Web.csproj b/src/Discussion.Web/Discussion.Web.csproj index 6b611a6b..e2c08e4b 100755 --- a/src/Discussion.Web/Discussion.Web.csproj +++ b/src/Discussion.Web/Discussion.Web.csproj @@ -21,7 +21,6 @@ - diff --git a/upgrade-from-existing.sh b/upgrade-from-existing.sh new file mode 100755 index 00000000..a6879e11 --- /dev/null +++ b/upgrade-from-existing.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# this script is executed in an transitional upgrading image + +set -e + +oldVer=$1 +newVer=$2 + + +# todo: Make existing site readonly + + + +if [ ! -d /club-data/$newVer/ ]; then + mkdir /club-data/$newVer/ + chmod -R 777 /club-data/$newVer/ +fi + +cp /club-data/$oldVer/appsettings.Production.json /club-data/$newVer/ +cp /club-data/$oldVer/dotnetclub.db /club-data/$newVer/ + + +dotnet /club-app/Discussion.Migrations.dll "Data Source=/club-data/$newVer/dotnetclub.db" + +