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

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.

Related

ASPNET Core 3.1 - Dockerfile changes don´t work when run in Visual Studio

I run a web api (ASPNETCore 3.1 - API) in Visual Studio 2019 (F5 in Debug mode), I use Docker (for Linux), when I change Dockerfile and run application, the changes don´t work.
Example:
I put the RUN touch test.txt and ENV my_variable value in Dockerfile, but the file and variable are not created.
Does anyone know why?
Nothing like reading the official documentation...
https://learn.microsoft.com/en-us/visualstudio/containers/container-build?view=vs-2019#debugging
Debugging
When building in Debug configuration, there are several optimizations that Visual Studio does that help with the performance of the build process for containerized projects. The build process for containerized apps is not as straightforward as simply following the steps outlined in the Dockerfile. Building in a container is much slower than building on the local machine. So, when you build in the Debug configuration, Visual Studio actually builds your projects on the local machine, and then shares the output folder to the container using volume mounting. A build with this optimization enabled is called a Fast mode build.
In Fast mode, Visual Studio calls docker build with an argument that tells Docker to build only the base stage. Visual Studio handles the rest of the process without regard to the contents of the Dockerfile. So, when you modify your Dockerfile, such as to customize the container environment or install additional dependencies, you should put your modifications in the first stage. Any custom steps placed in the Dockerfile's build, publish, or final stages will not be executed.
This performance optimization only occurs when you build in the Debug configuration. In the Release configuration, the build occurs in the container as specified in the Dockerfile.
I put RUN touch test.txt and ENV my_variable value in the first lines (where Dockerfile build base stage) and it works.
A tip refers to RUN touch test.txt, this needs to be executed (WORKDIR) in another folder different from the folder mapped with the source code in the hostlocal (/app).
Example:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /tmp
RUN touch teste.txt
WORKDIR /app
ENV my_variable value
EXPOSE 80
EXPOSE 443
My final Dockerfile is:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /tmp
RUN touch teste.txt
RUN echo "teste1" > teste1.txt
WORKDIR /app
ENV my_variable value
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["MyTestProject/TestProject.csproj", "MyTestProject/"]
RUN dotnet restore "MyTestProject/TestProject.csproj"
COPY . .
WORKDIR "/src/MyTestProject"
RUN dotnet build "TestProject.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "TestProject.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENV my_variable value
RUN touch teste.txt
ENTRYPOINT ["dotnet", "TestProject.dll"]
You can choose to include additional environment files to be passed to the docker run command by adding the following tag DockerfileRunEnvironmentFiles inside the propertygroup in your .csproj file:
<PropertyGroup>
<DockerfileRunEnvironmentFiles>your_env_file.env</DockerfileRunEnvironmentFiles>
...
...
<PropertyGroup>
your_env_file.env:
PAT=[Personal Access Token]
PROJECT=[Azure DevOps Project URL]
VARIABLE=[Filename of the variable file including extension]
WORKSPACE=[Name of the default workspace]
For the problem about the arguments not being passed you can add this to your csproj:
<PropertyGroup>
<DockerDebuggeeArguments>touch test.txt</DockerDebuggeeArguments>
...
...
</PropertyGroup>
Found here: https://learn.microsoft.com/en-us/visualstudio/containers/container-msbuild-properties?view=vs-2019

Visual Studio docker support doesn't work with CI/CD

I have a solution that has the following projects:
ServiceStackDockerTest
ServiceStackDockerTest.ServiceModel
ServiceStackDockerTest.ServiceInterface
When I add docker support inside visual studio this is the docker file that is added.
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY ServiceStackDockerTest/ServiceStackDockerTest.csproj ServiceStackDockerTest/
COPY ServiceStackDockerTest.ServiceModel/ServiceStackDockerTest.ServiceModel.csproj ServiceStackDockerTest.ServiceModel/
COPY ServiceStackDockerTest.ServiceInterface/ServiceStackDockerTest.ServiceInterface.csproj ServiceStackDockerTest.ServiceInterface/
RUN dotnet restore ServiceStackDockerTest/ServiceStackDockerTest.csproj
COPY . .
WORKDIR /src/ServiceStackDockerTest
RUN dotnet build ServiceStackDockerTest.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish ServiceStackDockerTest.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "ServiceStackDockerTest.dll"]
It adds the docker file inside the startup project (/ServiceStackDockerTest).
This works perfectly fine inside visual studio. The image builds and runs when I debug and my breakpoints are hit.
However when I try to build this image normally using docker it doesn't work as it cannot find the path of the .csproj files.
I think this happens because Visual Studio is using volume sharing so it has access to the parent folders or it is changing the scope the Dockerfile is run in somehow.
However, in my CI pipeline it runs docker build on ServiceStackDockerTest/Dockerfile which copies this folder to docker and does not have access to it's parent folders. The paths in VS dockerfile are all from the parent directory to where the docker file is located.
Why has Microsoft built in their support like this? Surely building the dockerfile inside a CI pipeline is a common task.
What is the best way to fix this so I still can debug inside the container with live reload inside Visual Studio but also build the image in my CI pipeline?
So the answer to this is actually very simple. In CI pipeline just change the build context to the parent folder.
To build locally run this from parent folder docker build -f SSDockerTest2\Dockerfile . and then it runs it in context of parent direcory.

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

Use custom Visual Studio run configuration with Docker

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

teamcity and docker integration

Has anyone used Teamcity's artifacts in a new build for docker? What I'd like to automate is take the artifacts produced by teamcity, and then create a new docker image with those artifacts. I couldn't really find any tutorials online. I saw that Docker could integrate with bitbucket and github, but I wasn't really sure if that was the same thing. My base image should have mono and a few other things installed. Installing mono is not part of my source so I wasn't sure if the github integration would work.
Docker can copy an artifact from a remote URL ( https://docs.docker.com/reference/builder/#add ) and TeamCity exposes URL patterns that you can use to download build artifacts from outside TeamCity ( https://confluence.jetbrains.com/display/TCD9/Patterns+For+Accessing+Build+Artifacts ). If you combine those two, you can create a Docker file that creates a new image with the given artifact.
Like this:
ADD http://localhost:8111/guestAuth/repository/download/BuildName/latest.lastSuccessful/artifactName.war /opt/wildfly/standalone/deployments/
I have never worked with teamcity but in general this should be possible. You should first create a base image with everything you need lets call it "crystal/base".
The in your teamcity setup generate your artifact.
In the same directory as the artifact add a Dockerfile with the following:
from crystal/base
ADD artifactFile /var/location_inside_container/artifactFile
CMD ["commandToUserArtifact.sh"]
Lastly, build you new docker container with
docker build -t crystal/dependent .

Resources