Use custom Visual Studio run configuration with Docker - visual-studio

I'm in the process of setting up a .NET Core project with Docker in Visual Studio 2017. I've created the project and added the docker-compose to the solution, and everything works.
But somehow, the VS won't build and run Docker with any configurations, other than Debug and Release.
I've created solution and project configurations named Preproduction and selected it, as well as created a docker-compose.vs.preproduction.yml file.
But when I run the preproduction configuration, the project runs as if Release was selected instead. The Build Output console also shows the following:
Debug
*docker-compose -f "docker-compose.yml" -f "docker-compose.override.yml" -f "docker-compose.vs.debug.yml" -p dockercompose3979710767*
Release
*docker-compose -f "docker-compose.yml" -f "docker-compose.override.yml" -f "docker-compose.vs.release.yml" -p dockercompose3979710767*
Preproduction
*docker-compose -f "docker-compose.yml" -f "docker-compose.override.yml" -f "docker-compose.vs.release.yml" -p dockercompose3979710767*
Notice the second yml file.
Somehow it uses the release file, and not the custom configuration file I've added.
Does anyone have any idea how to solve this, so docker will use my custom configurations?

Unfortunately it is not possible. After spending a lot of time to figure it out, it turned out that those two filenames are hardcoded into a DLL. Everything which is not 'DEBUG' will use the 'RELEASE' files.
Using different docker-compose.yml files by referencing them from different folder could be a solution, but since it is not a standard project but a Docker project, you don't have access to the post build events to copy the required files there. Furthermore you cannot have multiple Dockerfile, because it is also based on name convention.
You can use one version to develop and test, defined in the included files and create a script which builds everything manually based on your existing compose files and your extra.

I provide some non-standard solution for this issue can be solved. Here we go:
1) Get dnSPY tool (https://github.com/0xd4d/dnSpy/releases)
2) Install it
3) Find file Microsoft.Docker.dll (For me it was in "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Sdks\Microsoft.Docker.Sdk\tools" way.)
4) Get copy of this file (copy in some directory for example).
5) Open this dll in dnSpy.exe
6)Go Microsoft.Docker (version number) -> Microsoft.Docker.dll -> DockerComposeClient class -> MergedDockerComposeDocumentProvider private class -> GetDocuments private method
7) In this method you can see all file pathes and files used for build
8) RightClick on necessary string -> Edit IL Instructions
9) Edit what you need (as for me I was able to change docker-compose.override.yml to docker-compose.development.yml)
10) Save change
11) File -> Save Module and saving your upgraded DLL.
WHOILA!!! Actually
you must restart VS and maybe docker. After this your changes will be apply to pipeline build. Enjoy

Related

Need assistance with Dockerfile and Kubernetes for .AspNetCore service

My docker build is failing due to the following error:
COPY failed: CreateFile \?\C:\ProgramData\Docker\tmp\docker-builder117584470\Aeros.Services.Kubernetes\Aeros.Services.Kubernetes.csproj: The system cannot find the path specified.
I am fairly new to docker and have went with the basic project template that is set up when you create a Kubernetes container project template, so I'd figure it would work out of the box, but I'm mistaken.
I'm having problems trying to figure out what it's attempting to due in the temp directory structure and the reason it is failing. Can anyone offer some assistance? I've done some searching and others have said the default docker template was incorrect in Visual Studio, but I'm not seeing any of the files being copied over to the temp directory to begin with, so figuring out what is going on is being rather problematic at the time.
Here is the docker file, the only thing I've added is a publishingProfile arg so I can tell it which profile to use in the Build and Publish steps :
ARG publishingProfile
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY ["Aeros.Services.Kubernetes/Aeros.Services.Kubernetes.csproj", "Aeros.Services.Kubernetes/"]
RUN dotnet restore "Aeros.Services.Kubernetes/Aeros.Services.Kubernetes.csproj"
COPY . ./
WORKDIR "/src/Aeros.Services.Kubernetes"
RUN dotnet build "Aeros.Services.Kubernetes.csproj" -c $publishingProfile -o /app
FROM build AS publish
RUN dotnet publish "Aeros.Services.Kubernetes.csproj" -c $publishingProfile -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Aeros.Services.Kubernetes.dll"]
I haven't touched the yaml file, but if you need that I can provide it as well. Again, all I've done with this is add a few NuGet packages to the project reference. Build in VisualStudio runs fine, but the docker command:
docker build . --build-arg publishingProfile=Release
is failing with the error mentioned above.
Can someone be so kind as to offer some enlightenment? Thanks!
Edit 1:
I am executing this from the project's folder via a PowerShell command line.
Leandro's comments helped come across the solution.
So first a rundown of that COPY command, it takes two parameters, source and destination.
Within the template for the Dockerfile for Visual Studio, it includes the folder location of the .csproj file it is attempting to copy. In my case, the command read as follows:
COPY ["Aeros.Services.Kubernetes/Aeros.Services.Kubernetes.csproj", "Aeros.Services.Kubernetes/"]
So it is looking for my Aeros.Services.Kubernetes.csproj file in the Aeros.Services.Kubernetes project folder and copying it to the Aeros.Services.Kubernetes folder in the src folder of Docker.
The problem with this is that if you use the default setup, your dockerfile is included inside the project folder. If you are executing the docker build from within the project folder, the syntax for the COPY command is actually looking in the wrong file location. For instance, if your project is TestApp.csproj located in the TestApp project folder, and you are executing the Docker build command for the dockerfile within the same folder, the syntax for that COPY command:
COPY ["TestApp/TestApp.csproj", "TestApp/"]
is actually looking for: TestApp/TestApp/TestApp.csproj.
The correct syntax for the COPY command in this situation should be:
COPY ["TestApp.csproj", "TestApp/"]
since you are already within the TestApp project folder.
Another problem with the default template that may trouble some is that it doesn't copy the web files for the project either, so once you get past the COPY and dotnet restore steps, you will fail during the BUILD with a:
CSC : error CS5001: Program does not contain a static 'Main' method
suitable for an entry point
This is resolved by adding:
COPY . ./
following your RUN dotnet restore command to copy your files.
Once these pieces have been addressed in the default template provided, everything should be functioning as expected.
Thanks for the help!
In which line the problem happens? I do not remember if docker build shows it.
Where are you executing this build? The problem is that it is not finding the file you are trying to copy. It should be local to where the command is executed.
I saw now, the problem is on the first COPY.

visual studio 2017 docker-compose override and prod actions on build

To my understanding from the Visual studio multi environment docker docs here you can have multiple yml files for each of your environments. It says that the docker-compose.override.yml is used for development. I created a docker-compose.prod.yml like it says in this link but it doesn't run when I build under release, override continues to run. I am following the directions here which says to change configuration to release and build which should build the project for prod.
Not sure if this is related but I also noticed the prod is not nested like override is in the project.
I need to have two different compose files for prod and for dev but it seems override is not ignored when building for release and prod is not used.
Any ideas on how to get two different docker-compose files based on the environment? Just changing to release and building doesn't work as expected. Is the only way to do command line? Also, why doesn't prod nest?
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
A little late to the party but I faced the same challenge and found the solution below, hope it helps someone else out there.
If you want different behavior based on the build configuration (for
example, Debug or Release), add configuration-specific docker-compose
files. The files should be named according to the build configuration
(for example, docker-compose.vs.debug.yml and
docker-compose.vs.release.yml) and placed in the same location as the
docker-compose-override.yml file.
More info here

How to Build & Push Container from docker-compose.ci.build.yml File

I am using ASP.NET Core and have used Visual Studio's Add Docker Support feature to get started. This adds a docker-compose.ci.build.yml file to my project which is supposed to be used on a CI server.
How do I build my Docker image from a compose file and push the image to my private Docker registry. I've tried the docker-compose build command:
docker-compose -f docker-compose.ci.build.yml build
However this outputs an error:
ci-build uses an image, skipping
I ran into a number of issues getting this to build initially. Fixes for me included updating Visual Studio 2017 to Update 4, updating the Visual Studio Tools for Docker extension, and updating/consolidating NuGet package references. In addition, in docker-compose.ci.build.yml I had to change the build image to microsoft/aspnetcore-build:1.0-2.0-stretch (see this GitHub issue for more details).
Assuming the docker-compose configurations are the same/similar to the default generated ones, try the following script:
$ docker-compose -f docker-compose.ci.build.yml up
$ docker-compose -f docker-compose.yml build
Bringing "up" docker-compose.ci.build.yml simply builds the project and then exits. The artifacts are published to the obj/Docker/publish folder. The "build" docker-compose.yml actually builds and tags the images using the artifacts from the obj/Docker/publish folder. I clean up at the end of my build script with the following:
$ docker-compose -f docker-compose.ci.build.yml down
For reference/inspiration-- This is working on a custom Linux build server and producing four Docker images from a single solution-- two ASP.NET Core apps and two .NET Core apps.
I managed to build docker container without docker-compose.ci.build.yml. I used .Net Core tasks to build and publish .Net Core app to "obj/Docker/publish" folder as dockerfile expects and then used docker-compose task to build the container and push it to private container repository.

Dependencies not getting updated in TFS Build Server

I have created a Smart Device CAB Deployment Project and contains dependencies eg: Test.dll.
Where Test is a seperate class library. I have created a build definition for this solution(contains Test Proj + CAB deployment Proj). When i trigger queue new build for this definition Test.dll is not getting updated in CAB deployment project in Build Agent folder of TFS Server.
PLease let me know how can i reload this dependencies on checking in / queuing new build.
Thanks in advance
Check your Workspace option on Process tab. It should be All or Outputs if you wish to have always fresh version. None option is for incremental builds. If your project is really small "All" is the best option for you.
All - erase entire workspace and download and build everything again
Outputs - like All but only output bin folders are erased and new
version is downloaded (get latest version) from source control.
(incremental get) (like Rebuild (cleen + build) in your solution)
None - sources are build incrementally. Like Get latest version +
Build command in VS

How to compile a project with app and library in the same workspace with different configuration names?

I am developing an app and I am using an open source component.
I have a workspace containing both MyApp.xcodeproj and Component.xcodeproj. My app has three configurations: Debug, App Store and In House but the component has only two: Debug and Release
In the Debug configuration, everything works fine, but I can't compile my app in App Store or In House configuration because the configuration names do not match. I get a file not found error when trying to #import <Component/Component.h>
I need both App Store and In House configurations and I would really like to avoid modifying the component's configurations in order to ease future updates of the component.
I know I could use CocoaPods to solve this issue but I would like to know if there is a simple solution in Xcode
You can get your project to compile with some tweaks to your app’s settings.
I suggest you to modify all settings at the project level so that all your targets can inherit these settings.
Add a new DEFAULT_CONFIGURATION user-defined setting and define your configuration mapping. This is how it should look like:
Set FRAMEWORK_SEARCH_PATHS to $(BUILD_DIR)/$(DEFAULT_CONFIGURATION)-$(PLATFORM_NAME) for all configurations, add Any OS X SDK variants and set the value to $(BUILD_DIR)/$(DEFAULT_CONFIGURATION). Set HEADER_SEARCH_PATHS to $(FRAMEWORK_SEARCH_PATHS)/include and LIBRARY_SEARCH_PATHS to $(FRAMEWORK_SEARCH_PATHS). This is how it should look like:
This step is quite tedious, it can be automated with the xcproj tool and by running this script in your project directory. Edit your configurations mapping as needed.
#!/bin/bash
CONFIGURATIONS=( "App Store:Release" "In House:Release" "Debug:Debug" )
for CONFIGURATION in "${CONFIGURATIONS[#]}"; do
xcproj --configuration "${CONFIGURATION%%:*}" write-build-setting DEFAULT_CONFIGURATION "${CONFIGURATION#*:}"
done
xcproj write-build-setting 'FRAMEWORK_SEARCH_PATHS' '$(BUILD_DIR)/$(DEFAULT_CONFIGURATION)-$(PLATFORM_NAME)'
xcproj write-build-setting 'FRAMEWORK_SEARCH_PATHS[sdk=macosx*]' '$(BUILD_DIR)/$(DEFAULT_CONFIGURATION)'
xcproj write-build-setting 'HEADER_SEARCH_PATHS' '$(FRAMEWORK_SEARCH_PATHS)/include'
xcproj write-build-setting 'LIBRARY_SEARCH_PATHS' '$(FRAMEWORK_SEARCH_PATHS)'
If the component is distributed as a static library, you are done here. If the component comes as a framework you have to update its path reference by editing your project.pbxproj file in a text editor. In the PBXFileReference section (under /* Begin PBXFileReference section */) find Component.framework and update its path like this:
name = Component.framework; path = "../$(DEFAULT_CONFIGURATION)/Component.framework"; sourceTree = BUILT_PRODUCTS_DIR; };
Also make sure that the sourceTree is set to BUILT_PRODUCTS_DIR, i.e. relative to built products. Once you edited the project file, this should look like:
Your project should now build as expected.
I had this same problem, but I had multiple configurations (Debug, TestFlight, Release, Enterprise) in my app, and the bolded configurations would always fail to build cause it couldn't find the frameworks. I really didn't want to mess with the project settings of my sub projects in order to make updating them easy.
The answer I found was to just update the framework search path to account for the fact that the frameworks would be dropped in Release (or whatever the default configuration is set to) of the sub projects.
Specifically I set it to:
$(BUILD_DIR)/Release-$(PLATFORM_NAME)
I set it to be recursive too. This works both for Simulator and Device, building in Xcode and command line.
I solved it in the following way,
In my dependency project,
Project -> Target -> Build Phases, added new Run Script
TARGET_DIR="Build"
TARGET_FILE="${TARGET_DIR}/${FULL_PRODUCT_NAME}"
mkdir -p ${TARGET_DIR}
rm -rf ${TARGET_FILE}
cp -rf "${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}" ${TARGET_DIR}
After the every build, I copy the build to my Build directory inside the project.
And from the main project,
Project -> Target -> General, I drag and dropped the dependency Framework (which is inside dependency project's Build folder)
then,
Project -> Target -> Build Settings -> Framework Search Paths, under my custom Build Configuration, I added the following
$(PROJECT_DIR)/../DependencyProject/Build
The folder is relative to my main project, and this should be relative to your project.
Then in my all the schemes, I added a Pre-actions script for Build with
rm -Rf "${PROJECT_DIR}/../DependencyProject/Build"
Also you need to select the app against Provide build settings from drop down.

Resources