I'm trying to deploy my application which consists of Angular and ASP.NET. I've managed to successfully publish the app with docker. When I launch application with docker and call any method from swagger I get 404. How can I fix this?
Maybe it is because docker is launched on localhost and tries to make request to localhost, not the container. Nevertheless, I think that if the localhost was launched successfully the requests should also work(?).
One more question is - how do I launch my Angular app with docker? When I run the docker, api is the only project that is launched. You may notice that I've excluded Angular app from csproj because I've added additional steps to build it in dockerfile.
Please feel free to ask me any details.
Additional Information:
[Route("api/[controller]")]
[ApiController]
public class PingController : ControllerBase
{
[HttpGet("ping")]
public int Ping()
{
return 1;
}
}
dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
# Setup NodeJs
RUN apt-get update && \
apt-get install -y wget && \
apt-get install -y gnupg2 && \
wget -qO- https://deb.nodesource.com/setup_16.x | bash - && \
apt-get install -y build-essential nodejs
# End setup
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["SelfWebsiteApi/SelfWebsiteApi.csproj", "SelfWebsiteApi/"]
RUN dotnet restore "SelfWebsiteApi/SelfWebsiteApi.csproj"
COPY . .
WORKDIR "/src/SelfWebsiteApi"
RUN dotnet build "SelfWebsiteApi.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "SelfWebsiteApi.csproj" -c Release -o /app/publish
#Angular build
FROM node as nodebuilder
# set working directory
RUN mkdir /usr/src/app
WORKDIR /usr/src/app
# add `/usr/src/app/node_modules/.bin` to $PATH
ENV PATH /usr/src/app/node_modules/.bin:$PATH
# install and cache app dependencies
COPY SelfWebsiteApi/SelfWebsiteAngular/package.json /usr/src/app/package.json
RUN npm install
RUN npm install -g #angular/cli --unsafe
# add app
COPY SelfWebsiteApi/SelfWebsiteAngular/. /usr/src/app
RUN npm run build --prod
#End Angular build
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
RUN mkdir -p /app/SelfWebsiteAngular/dist
COPY --from=nodebuilder /usr/src/app/dist/. /app/SelfWebsiteAngular/dist/
ENTRYPOINT ["dotnet", "SelfWebsiteApi.dll"]
csproj:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<SpaRoot>SelfWebsiteAngular\</SpaRoot>
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
<UserSecretsId>57cd274b-65dd-4fa0-938b-cdb4fb135876</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="11.0.1" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.5" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.15.1" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>
<ItemGroup>
<Content Remove="$(SpaRoot)**" />
<None Remove="$(SpaRoot)**" />
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
</ItemGroup>
<!--<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build - -prod" />
<ItemGroup>
<DistFiles Include="$(SpaRoot)dist\**" />
<ResolvedFileToPublish Include="#(DistFiles->'%(FullPath)')" Exclude="#(ResolvedFileToPublish)">
<RelativePath>%(DistFiles.Identity)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
</Target>-->
</Project>
program.cs:
var builder = WebApplication.CreateBuilder(args);
var origin = builder.Configuration.GetValue<string>("SelfWebsiteAngular:Name");
var angularLink = builder.Configuration.GetValue<string>("SelfWebsiteAngular:Link");
builder.Services.AddCors(options =>
{
options.AddPolicy(origin, builder =>
{
builder.WithOrigins(angularLink)
//.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<SelfWebsiteContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("SelfWebsiteDatabase")));
builder.Services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration.GetValue<string>("Settings:ServerLink"),
ValidAudience = builder.Configuration.GetValue<string>("Settings:ServerLink"),
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(
builder.Configuration.GetValue<string>("Settings:Authorization:SymmetricSecurityKey"))),
};
});
builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
builder.Services.AddTransient<ITokenService, TokenService>();
builder.Services.AddTransient<IAuthService, AuthService>();
builder.Services.AddTransient<IResumeService, ResumeService>();
builder.Services.AddTransient<ILinkService, LinkService>();
builder.Services.AddTransient<ISectionService, SectionService>();
builder.Services.AddSingleton<IMapperProvider, MapperProvider>();
builder.Services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "SelfWebsiteAngular/dist";
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseStaticFiles();
//if (!app.Environment.IsDevelopment())
//{
app.UseSpaStaticFiles();
//}
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "SelfWebsiteAngular";
//if (app.Environment.IsDevelopment())
//{
spa.UseAngularCliServer(npmScript: "start");
// spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
//}
});
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(origin);
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
Swagger is, by default, only available when the environment is 'Development'. Containers, by default, aren't development.
The code that does that is this in Program.cs
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
There are multiple ways to make Swagger available in a container.
You can permanently make it available by removing the if in the above code so it becomes
app.UseSwagger();
app.UseSwaggerUI();
You can also set the environment in the image to Development by setting ASPNETCORE_ENVIRONMENT like this
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
ENV ASPNETCORE_ENVIRONMENT=Development
# Setup NodeJs
RUN apt-get update && \
apt-get install -y wget && \
apt-get install -y gnupg2 && \
wget -qO- https://deb.nodesource.com/setup_16.x | bash - && \
apt-get install -y build-essential nodejs
# End setup
WORKDIR /app
EXPOSE 80
EXPOSE 443
A third option is to pass the environment variable on your docker run command by adding an -e ASPNETCORE_ENVIRONMENT=Development option to the command.
Which solution you should choose depends on how permanently you want to make Swagger available.
Try
app.UseRouting();
and also then
app.UseAuthorization();
because for me worked normally without this configuration in debug mode but it didn't work in Docker.
Related
I have a next.config.js
module.exports = {
.........
env: {
BASE_URL: 'http://xx.xx.xx.xx:8000',
},
............
};
Now I want to change the BASE_URL while building docker image
my Dockerfile file
FROM node:16-alpine3.14
WORKDIR /usr/app
COPY ./package.json ./
RUN yarn install
ENV BASE_URL=http://yy.yyy.yy.yy:80
# Copy all files
COPY ./ ./
RUN yarn build
So passing ENV BASE_URL=http://yy.yyy.yy.yy:80 in Dockerfile will it help to change the BASE_URL: 'http://xx.xx.xx.xx:8000' in the next.config.js
Or what the way i can change the BASE_URL
ENV BASE_URL=http://yy.yyy.yy.yy:80 in your docker file will set an environment variable BASE_URL to it's value, you need to read it for that variable.
//next.config.js
module.exports = {
.........
env: {
BASE_URL: process.env.BASE_URL || 'http://xx.xx.xx.xx:8000', //read the value from env id empty use default value.
},
............
};
I would like to know how to update the connection chain from a docker command.
Example for Wordpress:
docker run --name myWordpress -d -p 8080:80 -e WORDPRESS_DB_HOST=123.123.123.123:3306 -e WORDPRESS_DB_USER=rootUser -e WORDPRESS_DB_PASSWORD=password ....
I have a blazor server application that needs to connect to a MySQL database, here's the connection chain (appsetting.json)
"ConnectionStrings": {
"MySqlConnection": "server=YourDatabase;user id=username;password=YourPassword;database=yourDb"
},
I'd like to be able to do a docker command:
docker run -d -e server=123.123.123.123 -e uid=UserName -e password=MyPass ...
and update the file appsetting.json, but How ?
Thanks for help.
I found a solution.
My appsetting.json
"ConnectionStrings": {
"MySqlConnection": "server=YOURDATABASE;user id=USERNAME;password=YOURPASSWORD;database=YOURDB"
}
In my Startup.cs
public void ConfigureServices(IServiceCollection services)
{
string connectionDb = Configuration.GetConnectionString("MySqlConnection");
string databaseAddress = Environment.GetEnvironmentVariable("DB_HOST");
string login = Environment.GetEnvironmentVariable("LOGIN_DB");
string mdp = Environment.GetEnvironmentVariable("PASSWORD_DB");
string dbName = Environment.GetEnvironmentVariable("DB_NAME");
connectionDb = connectionDb.Replace("USERNAME", login)
.Replace("YOURPASSWORD", mdp)
.Replace("YOURDB", dbName)
.Replace("YOURDATABASE", databaseAddress);
services.AddDbContext<ApplicationDbContext>(options => options.UseMySql(connectionDb, ServerVersion.AutoDetect(connectionDb)));
// Service SQL de AccessData.
services.AddSingleton(new SqlContextAccess(connectionDb));
...
My Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
ENV DB_HOST="YourAddressdatabase"
ENV LOGIN_DB="YourLogin"
ENV PASSWORD_DB="YourPassword"
ENV DB_NAME="YourDbName"
...
and my docker command :
docker run -d -p 3030:80 \
-e LOGIN_DB=myLogin \
-e PASSWORD_DB=SuperPassword \
-e DB_NAME=nameOfMydb \
-e DB_HOST=123.123.123.123 \
--name test myImage:latest
I have to build stop when unit test fail through docker file. I am using .NET Framework (not Dot.Net Core). I have to write command either in power shell script or Docker file (if Unit test fail then build should be stop before execute next line of docker file.
.NET Framework 4.7.2
Docker Window container only
Unit test project (Nunit)
Asp.Net WebForms (old)
Nunit test runner
Steps,
I have create project for Unit test + WebForm + Class library.
I have created powershell script for run unit test project using Nunit test runner.
I have added path for script in docker file.
I have attached Docker file and power-shell script .
Docker file code here
`# escape=`
FROM mcr.microsoft.com/dotnet/framework/sdk:4.8-20200512-windowsservercore-ltsc2019
WORKDIR /src
COPY ./POC.Web/POC.Web.csproj ./POC.Web/
COPY ./POC.Entites/POC.Entites.csproj ./POC.Entites/
COPY ./POC.Business.Layer/POC.Business.Layer.csproj ./POC.Business.Layer/
COPY ./POC.UnitTests/POC.UnitTests.csproj ./POC.UnitTests/
COPY ./POC.UnitTests/packages.config ./POC.UnitTests/
COPY ./MttcPoc.sln .
RUN nuget restore MttcPoc.sln
COPY . .
RUN msbuild POC.UnitTests/POC.UnitTests.csproj /p:OutputPath=c:/out/tests
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop';"]
# testResult variable using in shellscript to get the result of unit test
ENV testResult="Passed"
RUN nuget install NUnit.Runners
COPY ./startuptest.ps1 /
RUN /startuptest.ps1
#RUN IF $testResult == "Passed" EXIT 0 ELSE EXIT -1
RUN if [ "$testResult" = "Passed" ] ; then true ; else false; fi
ENTRYPOINT ["powershell", "/startuptest.ps1"]
#*****************************************************
#Below line should not execute if unit test fail
FROM mcr.microsoft.com/dotnet/framework/aspnet:4.8-20200512-windowsservercore-ltsc2019
ENV APP_ROOT=/inetpub/wwwroot `
CONNECTIONSTRINGS_CONFIG_MAP="" `
dockercomposeKey="From Docker file"
WORKDIR ${APP_ROOT}
RUN Import-Module WebAdministration; `
Set-ItemProperty -Path 'IIS:\AppPools\DefaultAppPool' -Name processModel.identityType -Value LocalSystem; `
New-WebApplication -Name 'app' -Site 'Default Web Site' -PhysicalPath $env:APP_ROOT
COPY ./startup.ps1 /
RUN /startup.ps1
#ENTRYPOINT ["powershell", "/startup.ps1"]
COPY --from=build c:/out/_PublishedWebsites/POC.Web ${APP_ROOT}
#************************************************************************`
Powershell script code here
$ProjectDir = "."
$OutDir = "$ProjectDir\testresults"
$testProjectPath = "c:\out\tests\POC.UnitTests.dll"
# Set nunit path test runner
$nunit_path = "$ProjectDir\NUnit.ConsoleRunner.3.11.1\tools\nunit3-console.exe"
# Run NUnit3 tests
& $nunit_path $testProjectPath --framework=net-4.7.2 --work=$OutDir
[XML]$resultDetails = Get-Content .\$OutDir\TestResult.xml
Write-Output $resultDetails
$string = "test-run"
Write-Output $resultDetails.$string.result
$env:testResult = $resultDetails.$string.result
#Passed
#Failed
#Below line added for if test fail then exit from docker build
If ($resultDetails.$string.result -eq 'Passed') {
Write-Output "Test passed"
Write-Output $env:testResult
return true
}else{
Write-Output "Test failed"
Write-Output $env:testResult
return -1
}
I am running this following pipeline which has stage "Build + Sonarscanner Analysis" for dotnetcore 2.2
The stage is set as follows
I have installed the tool in Global Configuration as suggested by
Sonarqube Documentation
Defined the tool in the environment as following
// Tools
MSBUILD_SQ_SCANNER_HOME = tool name: 'Scanner_for_MSBuild_4.7', type: 'hudson.plugins.sonar.MsBuildSQRunnerInstallation'
Pipeline Stage
stage ('Build + SonarQube analysis') {
agent {
docker {
image 'mcr.microsoft.com/dotnet/core/sdk:2.2'
}
}
steps {
dir ("app") {
withSonarQubeEnv('local') {
sh "dotnet ${MSBUILD_SQ_SCANNER_HOME}/SonarScanner.MSBuild.dll begin /k:\"Testing-Local\""
sh "dotnet build ${env.DotnetProjectName}"
sh "dotnet ${MSBUILD_SQ_SCANNER_HOME}/SonarScanner.MSBuild.dll end"
}
}
}
}
Result
I am getting the SonarScanner.MSBuild.dll is not executable as seen below
Verfication
The dll exists and the permissions is assigned to Jenkins
The dll is executable
The dll when run manually in that path - it runs
Directly added the path for the dll, It has the same result
stage ('Build + SonarQube analysis') {
agent {
docker {
image 'mcr.microsoft.com/dotnet/core/sdk:2.2'
}
}
steps {
dir ("app") {
withSonarQubeEnv('local') {
sh "dotnet /var/lib/jenkins/tools/hudson.plugins.sonar.MsBuildSQRunnerInstallation/Scanner_for_MSBuild_4.7/SonarScanner.MSBuild.dll begin /k:\"Testing-Local\""
sh "dotnet build ${env.DotnetProjectName}"
sh "dotnet var/lib/jenkins/tools/hudson.plugins.sonar.MsBuildSQRunnerInstallation/Scanner_for_MSBuild_4.7/SonarScanner.MSBuild.dll end"
}
}
}
}
Thanks for the help in advance.
I was able to solve this,
1. Installed the SonarScanner for dotnetcore in Jenkins Tools
The path for the sonarscanner will be the same as before
Default Path
/var/lib/jenkins/tools/hudson.plugins.sonar.MsBuildSQRunnerInstallation/Scanner_for_MSBuild_4.7/SonarScanner.MSBuild.dll
2. Initialize the tool in Jenkinsfile
// Tools
MSBUILD_SQ_SCANNER_HOME = tool name: 'Scanner_for_MSBuild_4.7', type: 'hudson.plugins.sonar.MsBuildSQRunnerInstallation'
stage ('Build + SonarQube analysis')
agent {
docker {
image 'mcr.microsoft.com/dotnet/core/sdk:2.2'
args '-v ${MSBUILD_SQ_SCANNER_HOME}:/opt/sonarscanner'
}
}
steps {
dir ("app") {
withSonarQubeEnv('local') {
sh "dotnet /opt/sonarscanner/SonarScanner.MSBuild.dll begin /k:\"Testing-Local\""
sh "dotnet build ${env.DotnetProjectName}"
sh "dotnet /opt/sonarscanner/SonarScanner.MSBuild.dll end"
}
}
}
}
How it works?
I am mounting the sonarscanner to the official docker image at the path /opt/sonarscanner/
With the mounted file as an argument for docker container during initialization, now the dll is avaliable for the docker dotnet command
I am trying to use pre and post build in my Visual Studio 2015 (TACO) project. As outlined in PreBuildEvent and PostBuildEvent on Visual Studio 2015 Tools for Apache Cordova I have added <Target> elements to my .jsproj file so that it now ends as shown:
<Import Project="_apacheCordovaProjectSourceItems.Targets" Condition="Exists('_apacheCordovaProjectSourceItems.Targets')" />
<Target Name="BeforeBuild">
<Exec Command="if $(ConfigurationName) == Release (echo ** Before Build **)" />
<Exec Command="attrib -R "$(ProjectDir)\platforms\*.*" /S" IgnoreExitCode="true" />
</Target>
<Target Name="AfterBuild">
<Exec Command="if $(ConfigurationName) == Release (echo ** After Build **)" />
<Exec Command="if $(ConfigurationName) == Release (xcopy "$(TargetDir)*.*" "$(SolutionDir)..\..\Binaries\$(PlatformName)\*.*" /Y /S /E /F /I)" />
</Target>
</Project>
My problem is that both the BeforeBuild and AfterBuild events fire at the beginning of the build
1>------ Build started: Project: MyProject, Configuration: Release Android ------
1> ** Before Build **
1> ** After Build **
1> D:\Workspaces\Products\MyProduct\Projects\Main\Sources\Apps\MyProject\bin\Android\Release\android-release-unsigned.apk -> D:\Workspaces\Products\MyProduct\Projects\Binaries\Android\android-release-unsigned.apk
1> D:\Workspaces\Products\MyProduct\Projects\Main\Sources\Apps\MyProject\bin\Android\Release\manifest-merger-release-report.txt -> D:\Workspaces\Products\MyProduct\Projects\Binaries\Android\manifest-merger-release-report.txt
1> 2 File(s) copied
1> Your environment has been set up for using Node.js 0.12.2 (ia32) and npm.
1> ... [Rest of output omitted] ...
Can anybody shed some light on why this is, or how I can get the post build event to run after the build has completed?
After banging my head against a wall for a while I gave up on the Visual Studio AfterBuild event and used a hook for the Cordova after_build one. It fires a bit earlier in the whole build process, but was good enough for my requirements. I'll post the gist of what it entails in case others need to do a similar thing.
Find the config.xml in Solution Explorer, right click on it and select View Code
In the config.xml add a <hook> section as follows
<platform name="android">
<hook type="after_build" src="scripts/afterbuild-copy-to-drop.js" />
</platform>
Here I am hooking into the after_build event for an Android build only.
Now create a scripts folder at the root of the project, ie the same level as the plugins and www folders.
Create a JavaScript file in here with a name that matches the src attribute in the hook definition, ie 'afterbuild-copy-to-drop.js'.
In this script file write the required code. Here is mine
module.exports = function (ctx) {
console.log('Executing custom "' + ctx.hook + '" hook for ' + ctx.opts.platforms);
var path = ctx.requireCordovaModule('path'),
shell = ctx.requireCordovaModule('shelljs');
// make sure we are in a release build
var isRelease = (ctx.cmdLine.indexOf('--configuration Release') >= 0);
var solutionRoot = path.join(ctx.opts.projectRoot, '../..');
var dropRoot = path.join(solutionRoot, '../../Binaries/Release/Apps');
if (isRelease){
if (ctx.opts.platforms == 'android') {
var platformRoot = path.join(ctx.opts.projectRoot, 'platforms/android');
var apkFileLocation = path.join(platformRoot, 'build/outputs/apk/android-release.apk');
dropRoot = path.join(dropRoot, 'Android');
var dropApkFileLocation = path.join(dropRoot, 'my-app.apk');
console.log('------ Making directory \'' + dropRoot + '\'');
shell.mkdir('-p', dropRoot);
console.log('------ Copying \'' + apkFileLocation + '\' to ' + dropApkFileLocation + '\'');
shell.cp('-f', apkFileLocation, dropApkFileLocation);
}
}
console.log('Finished executing "' + ctx.hook + '" hook for ' + ctx.opts.platforms);
};
Further information on hooks can be found at https://cordova.apache.org/docs/en/dev/guide/appdev/hooks/