Skip to content

15 - Deploy

Deploy

Deploy your ASP.NET Core MVC App into cloud – MS Azure

Several ways how to do it

  • Full bare metal server
  • Virtual server
  • App hosting (azure) (deployable directly from Rider)
  • Most standardized way – containers – Docker

Docker

Docker

Docker desktop

Download and install docker desktop for your platform (apple m1 is fully supported)

Its free!

https://hub.docker.com

When you create a docker image of your app, you need to upload it to somewhere – so hosting can download it from there. Typically, docker hosts do not allow direct uploads! Docker hub is free service to host your public images.

Dockerfile

  • Create Dockerfile in solution folder
  • It uses two ready-made base images from MS (based on Debian 10)
  • sdk:6.0 – for building (or :latest)
    Full .net core sdk
  • aspnet:6.0 – for running (or :latest)
    This image only contains .net core and ASP.NET runtime – its smaller
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /app

# copy csproj and restore as distinct layers
COPY *.sln .
# copy ALL the projects
COPY WebApp/*.csproj ./WebApp/
RUN dotnet restore

# copy everything else and build app
# copy all the projects
COPY WebApp/. ./WebApp/
WORKDIR /app/WebApp
RUN dotnet publish -c Release -o out


FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS runtime
WORKDIR /app
COPY --from=build /app/WebApp/out ./
ENTRYPOINT ["dotnet", "WebApp.dll"]

.dockerignore

To keep size even more down and control the bin/obj directory problems - add .dockerignore

1
2
3
4
5
6
7
**/bin
**/obj
**/out
**/.vscode
**/.vs
.dotnet
.Microsoft.DotNet.ImageBuilder

DB connections strings

Take care of DB strings in image.
- In Dockerfile

1
2
FROM mcr.microsoft.com/dotnet/aspnet:latest AS runtime
ENV ConnectionStrings:SqlServerConnection="Server=sql.akaver.com,1533;…”
  • or set env variables externally when image is starting up

dockerfile full example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
FROM mcr.microsoft.com/dotnet/sdk:latest AS build
WORKDIR /app
EXPOSE 80

# copy csproj and restore as distinct layers
COPY *.props .
COPY *.sln .

COPY BLL.App/*.csproj ./BLL.App/
COPY BLL.App.DTO/*.csproj ./BLL.App.DTO/
COPY BLL.Base/*.csproj ./BLL.Base/
COPY Contracts.BLL.App/*.csproj ./Contracts.BLL.App/
COPY Contracts.BLL.Base/*.csproj ./Contracts.BLL.Base/

COPY Contracts.DAL.App/*.csproj ./Contracts.DAL.App/
COPY Contracts.DAL.Base/*.csproj ./Contracts.DAL.Base/
COPY DAL.App.DTO/*.csproj ./DAL.App.DTO/
COPY DAL.App.EF/*.csproj ./DAL.App.EF/
COPY DAL.Base/*.csproj ./DAL.Base/
COPY DAL.Base.EF/*.csproj ./DAL.Base.EF/

COPY Contracts.Domain/*.csproj ./Contracts.Domain/
COPY Domain.App/*.csproj ./Domain.App/
COPY Domain.Base/*.csproj ./Domain.Base/

COPY PublicApi.DTO.v1/*.csproj ./PublicApi.DTO.v1/
COPY Extensions/*.csproj ./Extensions/

COPY WebApp/*.csproj ./WebApp/

RUN dotnet restore

# copy everything else and build app
COPY BLL.App/. ./BLL.App/
COPY BLL.App.DTO/. ./BLL.App.DTO/
COPY BLL.Base/. ./BLL.Base/
COPY Contracts.BLL.App/. ./Contracts.BLL.App/
COPY Contracts.BLL.Base/. ./Contracts.BLL.Base/

COPY Contracts.DAL.App/. ./Contracts.DAL.App/
COPY Contracts.DAL.Base/. ./Contracts.DAL.Base/
COPY DAL.App.DTO/. ./DAL.App.DTO/
COPY DAL.App.EF/. ./DAL.App.EF/
COPY DAL.Base/. ./DAL.Base/
COPY DAL.Base.EF/. ./DAL.Base.EF/

COPY Contracts.Domain/. ./Contracts.Domain/
COPY Domain.App/. ./Domain.App/
COPY Domain.Base/. ./Domain.Base/

COPY PublicApi.DTO.v1/. ./PublicApi.DTO.v1/
COPY Extensions/. ./Extensions/

COPY WebApp/. ./WebApp/

WORKDIR /app/WebApp
RUN dotnet publish -c Release -o out



FROM mcr.microsoft.com/dotnet/core/aspnet:latest AS runtime
WORKDIR /app
EXPOSE 80
ENV ConnectionStrings:SqlServerConnection="Server=alpha.akaver.com,1533;User Id=student;Password=Student.Bad.password.0;Database=akaver_sportmap_123;MultipleActiveResultSets=true"
COPY --from=build /app/WebApp/out ./
ENTRYPOINT ["dotnet", "WebApp.dll"]

Build image

  • Build your app into docker image
    > docker build -t webapp .

  • Run it locally via docker (set envs for db if needed)
    > docker run --name webapp_docker --rm -it -p 8000:80 webapp

    • -p 8000:80 – map port 8000 (local machine) to docker port 80
    • --name webapp_docker – name of instance
    • -it – interactive (can close down with ctrl-c)
    • --rm - clean resources after closing down


Open browser to http://localhost:8000/

Publish image

  • Tag your docker image (needed for publishing) > docker tag webapp akaver/webapp:test

  • Publish your docker image to registry
    > docker login -u [username] -p [password]
    > docker push akaver/webapp:test  

  • Check your image in Docker Hub

Docker

Docker

Deploy - Azure

  • Create Azure account, (using your TalTech Uni-Id)
    • Sadly, no student support currently – or maybe it works for you! (has worked randomly)
  • Activate free plan (or pay-as-you-go)

Docker

Azure Basics

  • Create new resource group - easy to kill everything later in one go
  • Instance name – some_website_name.azurewebsites.net
  • Publish: Docker image
  • Operating system: Linux
  • Location: North Europe
  • Sku and size: Free F1

Docker

Azure Docker

  • Options: Single Container
  • Image Source: Docker Hub
  • Access Type: Public
  • Image and tag: [your_repo/your_image:your_tag]

Docker

  • Create!

Docker

  • Ca 2 min later

Docker

Container update

  • Get the webhook url for docker registry – this notifies the Azure when new image is available.
  • Deployment Center > Webhook URL

Docker

Monitor your app

Docker

Docker

M1 (Apple silicon)

2023 info

Use arm sdk for build and x86 image for runtime.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build

WORKDIR /src

# copy csproj and restore as distinct layers
COPY *.props .
COPY *.sln .

# copy all the projects from host to image
# Base
COPY BLL.Contracts.Base/*.csproj ./BLL.Contracts.Base/
COPY Contracts.Base/*.csproj ./Contracts.Base/
COPY DAL.Contracts.Base/*.csproj ./DAL.Contracts.Base/
COPY Domain.Contracts.Base/*.csproj ./Domain.Contracts.Base/
COPY BLL.Base/*.csproj ./BLL.Base/
COPY DAL.Base/*.csproj ./DAL.Base/
COPY DAL.EF.Base/*.csproj ./DAL.EF.Base/
COPY Domain.Base/*.csproj ./Domain.Base/
COPY Helpers.Base/*.csproj ./Helpers.Base/

# App
COPY BLL.Contracts.App/*.csproj ./BLL.Contracts.App/
COPY DAL.Contracts.App/*.csproj ./DAL.Contracts.App/
COPY BLL.App/*.csproj ./BLL.App/
COPY BLL.DTO/*.csproj ./BLL.DTO/
COPY DAL.DTO/*.csproj ./DAL.DTO/
COPY DAL.EF.App/*.csproj ./DAL.EF.App/
COPY Domain.App/*.csproj ./Domain.App/
COPY Public.DTO/*.csproj ./Public.DTO/
COPY Resources.App/*.csproj ./Resources.App/

COPY Tests/*.csproj ./Tests/

COPY WebApp/*.csproj ./WebApp/

RUN dotnet restore

# copy everything else and build app
# Base
COPY BLL.Contracts.Base/. ./BLL.Contracts.Base/
COPY Contracts.Base/. ./Contracts.Base/
COPY DAL.Contracts.Base/. ./DAL.Contracts.Base/
COPY Domain.Contracts.Base/. ./Domain.Contracts.Base/
COPY BLL.Base/. ./BLL.Base/
COPY DAL.Base/. ./DAL.Base/
COPY DAL.EF.Base/. ./DAL.EF.Base/
COPY Domain.Base/. ./Domain.Base/
COPY Helpers.Base/. ./Helpers.Base/

# App
COPY BLL.Contracts.App/. ./BLL.Contracts.App/
COPY DAL.Contracts.App/. ./DAL.Contracts.App/
COPY BLL.App/. ./BLL.App/
COPY BLL.DTO/. ./BLL.DTO/
COPY DAL.DTO/. ./DAL.DTO/
COPY DAL.EF.App/. ./DAL.EF.App/
COPY Domain.App/. ./Domain.App/
COPY Public.DTO/. ./Public.DTO/
COPY Resources.App/. ./Resources.App/

COPY Tests/. ./Tests/

COPY WebApp/. ./WebApp/

WORKDIR /src/WebApp
RUN dotnet publish -c Release -o out


FROM mcr.microsoft.com/dotnet/aspnet:7.0-bullseye-slim-amd64 AS runtime
WORKDIR /app
EXPOSE 80

COPY --from=build /src/WebApp/out ./

ENTRYPOINT ["dotnet", "WebApp.dll"]

Build x86 image, retag, push -> configure azure

1
2
3
docker buildx build --progress=plain  -t webapp:latest .
docker tag webapp akaver/aw-struct-train-dist-22-23s-app:latest
docker push  akaver/aw-struct-train-dist-22-23s-app:latest