Closed oliver-dungey closed 5 years ago
It looks like there is a target runtime for Alpine Linux named linux-musl-x64
, found it here: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
Not managed to build Evolve with that yet but looks possible.
Ok, so it was a simple step to build it and it run's on Alpine very nicely: dotnet build 'Evolve.Cli' --configuration Release --runtime linux-musl-x64
Would be nice to have an official Alpine release from GitHub.
@lecaillon The use case for Alpine Linux is:
And we love Evolve because it's a like for like match to Flyway which we use with all our Java applications and have done for a number of years.
Did you manage to generate a single binary, or you just used the result of the dotnet build 'Evolve.Cli' --configuration Release --runtime linux-musl-x64
command ?
@lecaillon I just tar.gz
the build output as that is the easiest format to install on Docker containers. Here is the directory listing after the build - there are a couple of .so
(shared object libraries) so you need a little bit more than the basic dll:
PS E:\Evolve\src\Evolve.Cli\bin\Release\netcoreapp2.2\linux-musl-x64> dir
Directory: E:\Evolve\src\Evolve.Cli\bin\Release\netcoreapp2.2\linux-musl-x64
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 30/10/2019 08:43 122216 Evolve.Cli.Cli
-a---- 30/10/2019 08:43 58074 Evolve.Cli.deps.json
-a---- 30/10/2019 08:43 15360 Evolve.Cli.dll
-a---- 30/10/2019 08:43 2376 Evolve.Cli.pdb
-a---- 30/10/2019 08:43 246 Evolve.Cli.runtimeconfig.dev.json
-a---- 30/10/2019 08:43 28 Evolve.Cli.runtimeconfig.json
-a---- 30/10/2019 08:43 153088 Evolve.dll
-a---- 30/10/2019 08:43 40728 Evolve.pdb
-a---- 10/11/2018 23:33 719376 libhostfxr.so
-a---- 10/11/2018 23:34 735752 libhostpolicy.so
And this is my build script that I'm running on Ubuntu Agents in our Azure DevOps pipeline:
#!/bin/bash
# Uncomment to debug
# set -x
# Build the Evolve database migration CLI for Alpine Linux direct from the GitHub source
# (they don't build Alpine as a standard target)
rootDir=$(pwd)
# Clear down any previous git clone
rm -rf Evolve \
&& git clone https://github.com/lecaillon/Evolve.git \
&& cd Evolve/src \
&& dotnet build 'Evolve.Cli' --configuration Release --runtime linux-musl-x64 \
&& cd Evolve.Cli/bin/Release/netcoreapp2.2/linux-musl-x64 \
&& tar -zcvf ${rootDir}/pipeline-utils/linux/alpine/evolve-cli.tar.gz . \
&& echo 'Evolve CLI Build Complete'
@lecaillon An aside - some of my colleagues don't like the idea of the container startup race condition I am creating with this pattern i.e. 10 containers starting at the same time trying to create/migrate the database but it is a rock solid pattern as all the migration uses database level locking and creating the initial database is pretty much instant. Just for reference this is the sort of code I put in my Docker container startup (the Python code just attempts to create the database and CRUD user, if they already exist an exception is caught and it just returns success). The credentials for the admin/CRUD user are all sourced from the AWS Systems Manager Parameter store. When we launch the application it runs using the CRUD user to reduce the security threat of running an application with DBA creds:
# Create the database if it isn't there already
python3 /opt/ssp/bin/SQLServerDatabaseInitiator.py \
--server ${dbHost} \
--port ${dbPort} \
--db ${dbName} \
--admin-user ${dbAdminUser} \
--admin-password ${dbAdminPassword} \
--crud-user ${dbCrudUser} \
--crud-password ${dbCrudPassword}
error=$?
if [ $error -ne 0 ]; then
log_error_exit "Failed to create [$dbName] database and CRUD user with error code [$error]"
fi
# Run the database migrations
dotnet /opt/evolve/Evolve.Cli.dll migrate sqlserver -c "${dbAdminConnectionString}" -l /opt/ssp/sql
error=$?
if [ $error -ne 0 ]; then
log_error_exit "Failed to run Evolve database migrations with error code [$error]"
fi
Superb!
Thank's for the insights. I'm going to try to build the release using the "new" .NET Core 3 PublishTrimmed
option, because the MSBuild task ILLink.Tasks
I currently use, does not work for a linux-musl-x64
build. And then use warp to package it in a self-contained single binary.
@lecaillon Thanks for giving thought cycles to my use case, much appreciated. I really like the idea of a single binary although not sure if I can use as I am stuck on .NET 2.2 at the moment due to constraints in the applications I'm deploying. So in my Dockerfile I reference the Microsoft 2.2 base image:
FROM microsoft/dotnet:2.2-aspnetcore-runtime-alpine
No problem, the runtime is included in the "package". It would be another asset available in the releases page. At least it is the idea ^^
See the Linux version for an example: evolve_2.3.0_Linux-64bit.tar.gz
@lecaillon that would be fantastic, and hopefully would get Evolve a bit more exposure in the Docker world.
When I will have something (soon hopefully) I will use you to be my beta tester for that part ;) Thx again Oliver
@lecaillon cool, very happy to do that. Let me know if you need any further info.
And by the way you never noticed the release section where the Evolve CLI is avalable for Windows and Linux as a single self contained binary. If no, I could perhaps make a clearer statement about it in the doc ...?
And another (and last I hope ^^) question, could you confirmed that this Evolve CLI does not work in a Docker Alpine image. Thx
I built Evolve.CLI with the linux-musl-x64
RID and then use warp to produce the self-contained single binary you can find here
Feel free to test it and tell me if it works for you. (I've got a little doubt about the warp package on an Alpine release.)
PS: This binary (like all Evolve.CLI releases) embeds the netcore3 runtime. No need to install it.
@lecaillon No problem, I will try and get to testing today and get back to you
You said,
all the migration uses database level locking
I remind you Evolve uses a session level lock to coordinate the migrations on multiple nodes. This prevents two distinct Evolve executions from executing an Evolve command on the same database at the same time. See Configuration section, option: Evolve.EnableClusterMode
In other words, only one instance of Evolve runs at a time.
So you don't have to manage it in your migrations (if I understood correctly what you described)
@lecaillon thanks, that's brilliant - I had totally missed that option and will use it. I was relying on your session locks but hadn't spotted I needed to enable it!
I hadn't noticed that the releases are a single binary as there wasn't an Alpine one to try. I just tried the Linux release on Fedora and it works great. I've also tried the evolve-musl
binary from your link but something isn't working right as all I get is:
bash-5.0# ./evolve-musl
bash: ./evolve-musl: No such file or directory
Which is kind of odd, I've tried downloading it a few times but it stays as:
-rwxr-xr-x 1 root root 20997424 Nov 1 11:03 evolve-musl
Ok, I think wrap's not working on Alpine release. I will try something else in order to produce a single file for Evolve Alpine.
Anyway, Evolve.EnableClusterMode is true by default, no need to specify it. I was just thinking that you were taking care of that part in each of your migration script. My bad.
I use the new .NET Core 3 option PublishSingleFile
instead of Warp. Here is the result you can try: Evolve-CLI
The advantages are it is an entirely self-contained single binary that includes the runtime. So no dependency on anything. The drawback is the size. Warp is currently more efficient. I went from 20 MB to 50 MB.
Please tell me if it works for a start ^^ and if the size is not a no go in your use case.
I have just given the new 50MB file a quick basic startup test. It starts and has the appearance that it works but not quite as it dumped a core file on asking for the help:
bash-5.0# ./evolve-cli
The Command field is required.
Specify --help for a list of available options and commands.
bash-5.0# ./evolve-cli --help
less: unrecognized option: K
BusyBox v1.30.1 (2019-06-12 17:51:55 UTC) multi-call binary.
Usage: less [-EFIMmNSRh~] [FILE]...
View FILE (or stdin) one screenful at a time
-E Quit once the end of a file is reached
-F Quit if entire file fits on first screen
-I Ignore case in all searches
-M,-m Display status line with line numbers
and percentage through the file
-N Prefix line number to each line
-S Truncate long lines
-R Remove color escape codes in input
-~ Suppress ~s displayed past EOF
Unhandled exception. System.IO.IOException: Broken pipe
at System.IO.FileStream.WriteNative(ReadOnlySpan`1 source)
at System.IO.FileStream.FlushWriteBuffer()
at System.IO.FileStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.StreamWriter.CloseStreamFromDispose(Boolean disposing)
at System.IO.StreamWriter.Dispose(Boolean disposing)
at System.IO.TextWriter.Dispose()
at McMaster.Extensions.CommandLineUtils.Pager.Dispose()
at McMaster.Extensions.CommandLineUtils.CommandLineApplication.ShowHelp(Boolean usePager)
at McMaster.Extensions.CommandLineUtils.CommandLineProcessor.ProcessOption(OptionArgument arg)
at McMaster.Extensions.CommandLineUtils.CommandLineProcessor.ProcessNext()
at McMaster.Extensions.CommandLineUtils.CommandLineProcessor.Process()
at McMaster.Extensions.CommandLineUtils.CommandLineApplication.Parse(String[] args)
at McMaster.Extensions.CommandLineUtils.CommandLineApplication.ExecuteAsync(String[] args, CancellationToken cancellationToken)
at McMaster.Extensions.CommandLineUtils.CommandLineApplication.ExecuteAsync[TApp](CommandLineContext context, CancellationToken cancellationToken)
at McMaster.Extensions.CommandLineUtils.CommandLineApplication.Execute[TApp](CommandLineContext context)
at McMaster.Extensions.CommandLineUtils.CommandLineApplication.Execute[TApp](IConsole console, String[] args)
at McMaster.Extensions.CommandLineUtils.CommandLineApplication.Execute[TApp](String[] args)
at Evolve.Cli.Program.Main(String[] args)
Aborted (core dumped)
I also compared the size of your single binary with the size of the multi file build I'm running:
bash-5.0# du -sh evolve
57.2M evolve
So I suspect your build must very close to working. It was a while back that I put together my Docker build and I've just noticed that I'm not actually running the CLI but the DLL version with this command:
dotnet /opt/evolve/Evolve.Cli.dll migrate mysql -c "$dbAdminConnectionString" -l /opt/sql
I was just hacking when I got it working and haven't been back to try the CLI - I was struggling with VisualStudio basics as I haven't done any Windows development since about 2005 and so was just happy it was running on Alpine. Out of interest this is the directory listing of the only version I have fully built and fully tested - there is a lot of files and I'm not sure all of them are required:
ash-5.0# ls -al
total 58580
drwxrwx--x 1 root root 12288 Nov 1 12:01 .
drwxr-xr-x 1 root root 4096 Nov 1 12:01 ..
-rw-r--r-- 1 root root 665088 Apr 2 2019 Cassandra.dll
-rw-r--r-- 1 root root 122216 May 21 10:13 Evolve.Cli.Cli
-rw-r--r-- 1 root root 54541 May 22 08:26 Evolve.Cli.deps.json
-rw-r--r-- 1 root root 15360 May 22 08:26 Evolve.Cli.dll
-rw-r--r-- 1 root root 2396 May 22 08:26 Evolve.Cli.pdb
-rw-r--r-- 1 root root 246 May 22 08:26 Evolve.Cli.runtimeconfig.dev.json
-rw-r--r-- 1 root root 28 May 22 08:26 Evolve.Cli.runtimeconfig.json
-rw-r--r-- 1 root root 136704 May 22 08:25 Evolve.dll
-rw-r--r-- 1 root root 35072 May 22 08:25 Evolve.pdb
-rw-r--r-- 1 root root 141288 Apr 11 2019 McMaster.Extensions.CommandLineUtils.dll
-rw-r--r-- 1 root root 35840 Jun 22 2016 Microsoft.Extensions.DependencyInjection.Abstractions.dll
-rw-r--r-- 1 root root 43512 Jun 22 2016 Microsoft.Extensions.Logging.Abstractions.dll
-rw-r--r-- 1 root root 18424 Jun 22 2016 Microsoft.Extensions.Logging.dll
-rw-r--r-- 1 root root 10240 Mar 22 2019 Microsoft.Win32.Primitives.dll
-rw-r--r-- 1 root root 45200 May 22 07:23 Microsoft.Win32.Registry.dll
-rw-r--r-- 1 root root 416256 May 11 19:32 MySqlConnector.dll
-rw-r--r-- 1 root root 731136 Apr 11 2019 Npgsql.dll
-rw-r--r-- 1 root root 2644400 Mar 3 2019 SQLite.Interop.dll
-rw-r--r-- 1 root root 4608 Mar 22 2019 System.Buffers.dll
-rw-r--r-- 1 root root 198656 Mar 22 2019 System.Collections.Concurrent.dll
-rw-r--r-- 1 root root 653824 Mar 22 2019 System.Collections.Immutable.dll
-rw-r--r-- 1 root root 88064 Mar 22 2019 System.Collections.NonGeneric.dll
-rw-r--r-- 1 root root 80896 Mar 22 2019 System.Collections.Specialized.dll
-rw-r--r-- 1 root root 326144 Mar 22 2019 System.Collections.dll
-rw-r--r-- 1 root root 140288 Mar 22 2019 System.ComponentModel.Annotations.dll
-rw-r--r-- 1 root root 44032 Mar 22 2019 System.ComponentModel.Primitives.dll
-rw-r--r-- 1 root root 668160 Mar 22 2019 System.ComponentModel.TypeConverter.dll
-rw-r--r-- 1 root root 6144 Mar 22 2019 System.ComponentModel.dll
-rw-r--r-- 1 root root 189440 Mar 22 2019 System.Console.dll
-rw-r--r-- 1 root root 2872320 Mar 22 2019 System.Data.Common.dll
-rw-r--r-- 1 root root 350208 Mar 3 2019 System.Data.SQLite.dll
-rw-r--r-- 1 root root 943152 Apr 24 2019 System.Data.SqlClient.dll
-rw-r--r-- 1 root root 4608 Mar 22 2019 System.Diagnostics.Debug.dll
-rw-r--r-- 1 root root 57344 Mar 22 2019 System.Diagnostics.DiagnosticSource.dll
-rw-r--r-- 1 root root 27648 Mar 22 2019 System.Diagnostics.FileVersionInfo.dll
-rw-r--r-- 1 root root 186880 Mar 22 2019 System.Diagnostics.Process.dll
-rw-r--r-- 1 root root 23552 Mar 22 2019 System.Diagnostics.StackTrace.dll
-rw-r--r-- 1 root root 6144 Mar 22 2019 System.Diagnostics.Tools.dll
-rw-r--r-- 1 root root 114688 Mar 22 2019 System.Diagnostics.TraceSource.dll
-rw-r--r-- 1 root root 26112 Mar 22 2019 System.Diagnostics.Tracing.dll
-rw-r--r-- 1 root root 92672 Mar 22 2019 System.Drawing.Primitives.dll
-rw-r--r-- 1 root root 95560 Mar 21 2019 System.Globalization.Native.so
-rw-r--r-- 1 root root 4608 Mar 22 2019 System.Globalization.dll
-rw-r--r-- 1 root root 801160 Mar 21 2019 System.IO.Compression.Native.so
-rw-r--r-- 1 root root 257536 Mar 22 2019 System.IO.Compression.dll
-rw-r--r-- 1 root root 202240 Mar 22 2019 System.IO.FileSystem.dll
-rw-r--r-- 1 root root 57344 Mar 22 2019 System.IO.MemoryMappedFiles.dll
-rw-r--r-- 1 root root 112128 Mar 22 2019 System.IO.Pipes.dll
-rw-r--r-- 1 root root 1620480 Mar 22 2019 System.Linq.Expressions.dll
-rw-r--r-- 1 root root 427520 Mar 22 2019 System.Linq.dll
-rw-r--r-- 1 root root 245760 Mar 22 2019 System.Memory.dll
-rw-r--r-- 1 root root 59528 Mar 21 2019 System.Native.so
-rw-r--r-- 1 root root 14392 Mar 21 2019 System.Net.Http.Native.so
-rw-r--r-- 1 root root 1184768 Mar 22 2019 System.Net.Http.dll
-rw-r--r-- 1 root root 69120 Mar 22 2019 System.Net.NameResolution.dll
-rw-r--r-- 1 root root 148480 Mar 22 2019 System.Net.NetworkInformation.dll
-rw-r--r-- 1 root root 201216 Mar 22 2019 System.Net.Primitives.dll
-rw-r--r-- 1 root root 337408 Mar 22 2019 System.Net.Requests.dll
-rw-r--r-- 1 root root 10416 Mar 21 2019 System.Net.Security.Native.so
-rw-r--r-- 1 root root 497152 Mar 22 2019 System.Net.Security.dll
-rw-r--r-- 1 root root 24064 Mar 22 2019 System.Net.ServicePoint.dll
-rw-r--r-- 1 root root 570880 Mar 22 2019 System.Net.Sockets.dll
-rw-r--r-- 1 root root 56832 Mar 22 2019 System.Net.WebHeaderCollection.dll
-rw-r--r-- 1 root root 76288 Mar 22 2019 System.ObjectModel.dll
-rw-r--r-- 1 root root 11768832 Mar 21 2019 System.Private.CoreLib.dll
-rw-r--r-- 1 root root 230400 Mar 22 2019 System.Private.Uri.dll
-rw-r--r-- 1 root root 8493568 Mar 22 2019 System.Private.Xml.dll
-rw-r--r-- 1 root root 4608 Mar 22 2019 System.Reflection.Emit.ILGeneration.dll
-rw-r--r-- 1 root root 4608 Mar 22 2019 System.Reflection.Emit.Lightweight.dll
-rw-r--r-- 1 root root 4608 Mar 22 2019 System.Reflection.Emit.dll
-rw-r--r-- 1 root root 1069056 Mar 22 2019 System.Reflection.Metadata.dll
-rw-r--r-- 1 root root 5120 Mar 22 2019 System.Reflection.Primitives.dll
-rw-r--r-- 1 root root 5632 Mar 22 2019 System.Reflection.dll
-rw-r--r-- 1 root root 4608 Mar 22 2019 System.Resources.ResourceManager.dll
-rw-r--r-- 1 root root 33280 Mar 22 2019 System.Resources.Writer.dll
-rw-r--r-- 1 root root 23088 Sep 18 2018 System.Runtime.CompilerServices.Unsafe.dll
-rw-r--r-- 1 root root 384512 Mar 22 2019 System.Runtime.Extensions.dll
-rw-r--r-- 1 root root 14848 Mar 22 2019 System.Runtime.InteropServices.RuntimeInformation.dll
-rw-r--r-- 1 root root 36352 Mar 22 2019 System.Runtime.InteropServices.dll
-rw-r--r-- 1 root root 187904 Mar 22 2019 System.Runtime.Numerics.dll
-rw-r--r-- 1 root root 288256 Mar 22 2019 System.Runtime.Serialization.Formatters.dll
-rw-r--r-- 1 root root 16896 Mar 22 2019 System.Runtime.Serialization.Primitives.dll
-rw-r--r-- 1 root root 39424 Mar 22 2019 System.Runtime.dll
-rw-r--r-- 1 root root 54416 May 22 07:21 System.Security.AccessControl.dll
-rw-r--r-- 1 root root 78336 Mar 22 2019 System.Security.Claims.dll
-rw-r--r-- 1 root root 357888 Mar 22 2019 System.Security.Cryptography.Algorithms.dll
-rw-r--r-- 1 root root 62976 Mar 22 2019 System.Security.Cryptography.Encoding.dll
-rw-r--r-- 1 root root 141616 Mar 21 2019 System.Security.Cryptography.Native.OpenSsl.so
-rw-r--r-- 1 root root 156672 Mar 22 2019 System.Security.Cryptography.OpenSsl.dll
-rw-r--r-- 1 root root 79872 Mar 22 2019 System.Security.Cryptography.Primitives.dll
-rw-r--r-- 1 root root 436224 Mar 22 2019 System.Security.Cryptography.X509Certificates.dll
-rw-r--r-- 1 root root 29184 Mar 22 2019 System.Security.Principal.Windows.dll
-rw-r--r-- 1 root root 5120 Mar 22 2019 System.Security.Principal.dll
-rw-r--r-- 1 root root 758928 May 22 07:19 System.Text.Encoding.CodePages.dll
-rw-r--r-- 1 root root 4608 Mar 22 2019 System.Text.Encoding.Extensions.dll
-rw-r--r-- 1 root root 365568 Mar 22 2019 System.Text.RegularExpressions.dll
-rw-r--r-- 1 root root 5120 Mar 22 2019 System.Threading.Tasks.Extensions.dll
-rw-r--r-- 1 root root 5632 Mar 22 2019 System.Threading.Tasks.dll
-rw-r--r-- 1 root root 31232 Mar 22 2019 System.Threading.Thread.dll
-rw-r--r-- 1 root root 4608 Mar 22 2019 System.Threading.ThreadPool.dll
-rw-r--r-- 1 root root 4608 Mar 22 2019 System.Threading.Timer.dll
-rw-r--r-- 1 root root 66560 Mar 22 2019 System.Threading.dll
-rw-r--r-- 1 root root 341504 Mar 22 2019 System.Transactions.Local.dll
-rw-r--r-- 1 root root 11776 Mar 22 2019 System.Xml.ReaderWriter.dll
-rw-r--r-- 1 root root 7168 Mar 22 2019 System.Xml.XmlSerializer.dll
-rw-r--r-- 1 root root 3117400 Mar 21 2019 libclrjit.so
-rw-r--r-- 1 root root 10136712 Mar 21 2019 libcoreclr.so
-rw-r--r-- 1 root root 719376 Mar 22 2019 libhostfxr.so
-rw-r--r-- 1 root root 735752 Mar 22 2019 libhostpolicy.so
-rw-r--r-- 1 root root 96768 Mar 22 2019 netstandard.dll
Ok so not that simple to have the CLI running on Alpine.
Can you explain in detail when Evolve runs, what start it, when the app runs, what start it ? Not sure I cleary understood it yet :)
Can you give me a dockerfile or at least an example that I can work on on my side that mimics your usage ?
Thx Oliver
Sorry haven't had time to get together a nice set of working files for you yet but it's on my urgent list!
Let's move to this issue #144 now :)
Love your software - I've been using Flyway for years and Evolve is perfect for my dotnet needs, thanks for sharing it with the world.
I am running Alpine Linux on my Docker containers and struggling to get Evolve to work due to dynamic linking problems. No problems on Fedora and other distros but Alpine uses
muscl
instead ofglibc
(see: https://stackoverflow.com/questions/37818831/is-there-a-best-practice-on-setting-up-glibc-on-docker-alpine-linux-base-image).Here is the crux of the matter (after installing
libc6-compat
package which fixed one of the dependency issues):I'm not familiar enough with cross compiling to know what the best answer is, looking at your source code it's all C# so not quite sure what's going on.