Deploy Using Github Actions - asp.net-core

I am using Github as my source control, and using Github Actions as my CI/CD solution. I have a dedicated Windows Server somewhere, which accepts the published version of my repo.
I have a Github Action, which does Built, Test, Publish and Deploy (using FTP). I am not convinced with the "Deploy" idea. for example lets say my website has a huge codebase, and then FTPing everytime when we make a commit (Push) is NOT really a productive idea (i am publishing the published directory...not the Source Code to my server). Sometimes FTPing simply does not work, due to IIS Locking the files. what is the most reliable way to publish/deploy files to a remote server using Github Actions (or any other provider).
below is my sample Yaml file...
name: .NET Core
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
- name: Setup .NET Core
uses: actions/setup-dotnet#v1
with:
dotnet-version: 2.1
- name: Install dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --no-restore --verbosity normal
- name: Run the Publish
run: dotnet publish --configuration Release --no-restore --output ./publish
- name: FTP-Deploy-Action
uses: sebastianpopp/ftp-action#releases/v2
with:
host: my_host
user: my_user
password: ${{ secrets.FTP_PASSWORD }}
localDir: "/home/runner/work/CiTest/CiTest/CiTest/publish"
remoteDir: "CI-Test"

I wanted to add an answer to this question because Rosco's answer helped me, but I have more to contribute.
We've set up a self-hosted runner on the internal IIS server we want to deploy to. So our GitHub Actions flow looks a bit like yours to begin with (up to the dotnet publish command), but then has some extra bits.
First, still in the cloud, we "upload" artifacts from the build (I'm replacing our project name with "Foo"):
- name: Upload a Build Artifact
uses: actions/upload-artifact#v2.2.1
with:
name: application
path: /home/runner/work/Foo/Foo/Foo/bin/Release/net5.0/publish/
Then we have a whole new job that runs on prem:
deploy:
needs: build
runs-on: self-hosted
steps:
- name: Take application offline
run: New-Item -Type File -Name app_offline.htm -Path E:\Foo -Force
- name: Download new binaries over the top of the app
uses: actions/download-artifact#v2
with:
name: application
path: E:\Foo
- name: Bring the app back online
run: Remove-Item E:\Foo\app_offline.htm
So this creates an app_offline.htm file in our website folder (E:\Foo), then pulls the artifacts down from GitHub directly into that folder. When it's done, it deletes the app_offline.htm file and the site starts again.
It works a treat! Obviously keen to hear feedback from others if you think I'm doing something wrong, but I wanted to get that up here because this question ranks pretty highly when you search for "github actions deploy iis".

Since you have a dedicated server for your application, I would recommend using a Github self-hosted runner.
You install the runner service on your server and then the Github CI/CD build process runs on your dedicated server.
The build script can build your app then stop the IIS site locally which prevents locked files.
After that it can copy (or robocopy) the new build into the app folder.
Gitlab also has self-hosted runners.

Related

Github Actions fails to deploy AspDotNetCore MVC 6.0 to Azure App Service Linux but says Deployment Successful

I have an Asp.Net Core MVC 6.0 application.
It contains multiple class library projects.
It is also running Asp.Net Identity.
The project is also hosted in a Github repository.
The application builds and runs fine locally, however, I have added a Github Action for deploying the website to an Azure App Service Linux box, and whilst the deployment says it was successful, the website never gets deployed to Azure.
Here is the website running fine locally:
Here is the Github Action deployment status:
Here is the Azure App Service page, following the "successful" deployment status on Github Actions:
Additional Information
I can also see that an issue has been opened here whereby the user reports that the issue was to do with Asp.Net Identity, and that they had to downgrade the version from .Net 6 to .Net 5, to get it to deploy successfully.
Questions:
Does anyone have any insights into why this isn't working?
How do I debug this scenario?
UPDATE 1:
Following some debugging, I can see that the secret I created on Github Actions (which stores the publishing profile for the Azure Web App Service Server , is actually blank, despite me adding the secret value multiple times).
Is this a bug in Github? Does anyone else have the same problem?
UPDATE 2:
I have visited the KUDU site for the azure app service (https://houseplatform.scm.azurewebsites.net/newui).
I then checked the contents under the ../site/wwwroot and I can see that there is no file named hostingstart.html (but there a lot of DLLs for all the class library projects from the source code).
Here is my YAML file:
name: Build and deploy ASP.Net Core app to an Azure Web App
env:
AZURE_WEBAPP_NAME: house-platform-dev # set this to the name of your Azure Web App
AZURE_WEBAPP_PACKAGE_PATH: '.' # set this to the path to your web app project, defaults to the repository root
DOTNET_VERSION: '6.0' # set this to the .NET Core version to use
on:
push:
branches: [ "master" ]
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v3
- name: Set up .NET Core
uses: actions/setup-dotnet#v2
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Set up dependency caching for faster builds
uses: actions/cache#v3
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: Build with dotnet
run: dotnet build --configuration Release
- name: dotnet publish
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/myapp
- name: Upload artifact for deployment job
uses: actions/upload-artifact#v3
with:
name: .net-app
path: ${{env.DOTNET_ROOT}}/myapp
deploy:
permissions:
contents: none
runs-on: ubuntu-latest
needs: build
environment:
name: 'Development'
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
steps:
- name: Download artifact from build job
uses: actions/download-artifact#v3
with:
name: .net-app
- name: Deploy to Azure Web App
id: deploy-to-webapp
uses: azure/webapps-deploy#v2
with:
app-name: ${{ env.AZURE_WEBAPP_NAME }}
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
package: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }}
Assume your app service name is HousePlatform, please follow my steps to troubleshoot the issue. If you provide more details, I also will update this answer.
Steps:
Go to the kudu site via the link : https://HousePlatform.scm.azurewebsites.net/newui
Check the contents under the ../site/wwwroot.
If it's empty or just have a hostingstart.html file like my sample picture, it means deploy failed. We need to check the .yml file, you can find it under the .github/workflows in github repo.
If the contents under the ../site/wwwroot like locals, it means it deployed successfully. Then we can move to step 5.
Navigate to Configuration, click the General settings, then find Startup Command. We can refer the official doc to add the startup command.

Serverless.yml - Epilogue

One magical day I found a reference to an 'epilogue' key to be used in the Serverless.yml file. It's the best. We use it to cleanup after testing that occurs inside our CI/CD pipeline.
- name: Test Integration
dependencies:
- Deploy Dev
task:
jobs:
- name: Test endpoints
commands:
- cache restore
- checkout
- sem-version python 3.8
- cd integration_tests
- pip install -r requirements.txt
- // our various testing scripts...
epilogue:
always: // This runs, no matter what. There are other options!!
commands:
- python3 99_cleanup.py
secrets:
- name: secret_things_go_here
Today, I don't want epilogue: always: , but rather epilogue: when it doesn't fail: . I cannot find one shred of documentation about this option. Nothing to even explain how I got here in the first place.
Oh, internet: How do I run something only when my tests have passed?
WOO!
I was barking up the wrong tree. The solution is within SemaphoreCI, not Serverless.
https://docs.semaphoreci.com/reference/pipeline-yaml-reference/#the-epilogue-property
Options include: on_pass and on_fail.
Whew.

Deploy from gitlab pipeline to IIS in shared server - .Net Core 2.2 application

I would like to deploy my code from gitlab to my shared server IIS running under Plesk.
It is a .Net Core 2.2 application.
I tried on the pipeline the command.
publish-to-dev:
stage: publish-to-dev
image: mcr.microsoft.com/dotnet/sdk:3.1-focal
#image: mcr.microsoft.com/dotnet/core/sdk:2.2
script:
- 'dotnet build'
- 'dotnet publish /p:PublishProfile="devCoreMoocapps2" /p:Username="$MsDeployUserName" /p:Password="$MsDeployPassword" /p:AllowUntrustedCertificate=true'
Where $MsDeployUserName and $MsDeployPassword are variables defined in gitlab.
I am getting the following error
/usr/share/dotnet/sdk/3.1.414/Sdks/Microsoft.NET.Sdk.Publish/targets/PublishTargets/Microsoft.NET.Sdk.Publish.MSDeploy.targets(171,5): error MSB6004: The specified task executable location "%ProgramW6432%/IIS/Microsoft Web Deploy V3/msdeploy.exe" is invalid.
Looks like the path is not valid: "%ProgramW6432%/IIS/Microsoft Web Deploy V3/msdeploy.exe" is invalid.
Do you guys have a workaround for this problem?

How to run a Kotlin script on GitHub Actions?

I want to run Kotlin scripts in CI without relying on a Gradle project, so I can easily do operations that would be hard to program using shell/bash/batch, and so that I can use libraries if needed.
Having the Kotlin script run only on Ubuntu/Linux is fine, though ideally, there's a way to make it run on Windows and macOS targets as well for platform specific projects.
UPDATE: Kotlin is now pre-installed on GitHub Actions runners, no need to install it beforehand anymore.
First, ensure that you have a proper Kotlin script, ending in .kts, or better, .main.kts as that latter one will be recognized better by the IDE (e.g. IntelliJ IDEA, Android Studio), especially when it comes to autocompletion and type analysis.
Second, ensure that its first line is the shebang pointing to the right place:
#!/usr/bin/env kotlin
That will be helpful to test the script locally before running in CI, as the IDE will show a run button in the gutter, next to the shebang.
If you add the execute permission to the file (chmod +x YouScript.main.kts on Linux/macOS), you'll also be able to run it just like any other script, without having to type kotlinc -script before, and that will apply on GitHub Actions as well.
Finally, here's an example manual GitHub Action (aka. workflow file) that will take an input and pass it to your Kotlin script (usable in the args property/parameter) after it installed Kotlin:
name: Run Kotlin script
on:
workflow_dispatch:
inputs:
awesome-input:
description: 'Awesome parameter'
default: 'You'
required: true
jobs:
awesome-action:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
- name: Run Kotlin script
run: kotlinc -script ./YourScript.main.kts ${{ github.event.inputs.awesome-input }}
Note that if the script has the execute (x) permission, as I told previously, you can remove the kotlinc -script part and it will still run.
Bonus: it is possible to have Kotlin code directly in the workflow file (though I'd not recommend doing it), by using kotlin as a shell.
See this YouTrack comment to see how: https://youtrack.jetbrains.com/issue/KT-43534#focus=Comments-27-4640716.0-0
Kotlin runner is now pre-installed on GitHub Actions environments (GitHub issue, YouTube video).
Refer to the GitHub Actions runner images1 to see all the installed software.
So, you can easily run your .main.kts scripts like this:
name: Example
on:
push:
branches:
- main
jobs:
example-action:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v3
- name: Run the script
run: kotlin /path/in/repo/to/my-script.main.kts
And here is an example my-script.main.kts file:
#file:JvmName("MyScript")
#file:CompilerOptions("-jvm-target", "11")
#file:Repository("https://repo.maven.apache.org/maven2")
// #file:DependsOn("com.example:library:1.2.3")
import java.io.File
val input = File("README.md") // Assuming you ran checkout before
val output = File("result.txt")
val readmeFirstLine = input.readLines().first()
output.writeText(readmeFirstLine)
There is also a GitHub action called setup-kotlin that lets you install your desired version of Kotlin and also provides some more features. Check out this issue.
...
- uses: actions/checkout#v3
- uses: fwilhe2/setup-kotlin#main
with:
version: 1.7.0
- name: Run the script
run: kotlin /path/in/repo/to/my-script.main.kts
It was previously called virtual environments

Google Cloud Builds, How to speed up build time of application(npm packages)

My web application runs in Google Cloud Platform, lately I realized that application's build time takes really long, especially when you are testing a feature, let say refresh the page, you can see that it takes really long to start application. What I am looking for is how to speed up this process. I am using docker images to build on google cloud registry. I do not want to re-build all npm packages every time, when there is an update in some npm packages then I want to re-build application.
here is the my cloudbuild.yaml file for polymer
steps:
- name: 'gcr.io/cloud-builders/docker'
args: [ 'build', '-t', 'gcr.io/$PROJECT_ID/myapp-polymer', '.' ]
images:
- 'gcr.io/$PROJECT_ID/myapp-polymer'
then here is the my main cloudbuild.yaml file
steps:
- name: 'gcr.io/cloud-builders/npm'
args: ['--prefix', 'myapp','install']
- name: 'gcr.io/cloud-builders/npm'
args: ['--prefix', 'myapp/functions', 'install']
- name: 'gcr.io/$PROJECT_ID/myapp-polymer'
args: ['cd', 'myapp']
- name: 'gcr.io/$PROJECT_ID/myapp-polymer'
args: ['build']
I read Google Cloud API especially section "Speeding up your Builds" (https://cloud.google.com/cloud-build/docs/speeding-up-builds)
I think it just cache build images and using it. Are there any way that I can cache specifically npm packages, dependencies etc in Google Cloud so that I do not have to build every time whole application? My main goal is to reduce build time, speed up build process.
Thanks!
Have you tried Kaniko? It can save the cache in gcr.io and and if you have built your Dockerfile with right steps (see https://cloud.google.com/blog/products/gcp/7-best-practices-for-building-containers), it should save you a lot of time. Here is the cloudbuild.yaml example:
- name: 'gcr.io/kaniko-project/executor:latest'
args:
- --destination=gcr.io/$PROJECT_ID/image
- --cache=true
- --cache-ttl=XXh
More info: https://cloud.google.com/cloud-build/docs/kaniko-cache
You could use docker.
Put your npm application into docker. Then you can push your docker image (upload some layers of your docker image) to a cloud registry, e.g. gcr (Google Cloud Registry). Before your build step, you could pull your image from gcr.
This is what the build step would approximately look like:
- name: 'gcr.io/cloud-builders/docker'
args: [
'build',
'-t', 'test_image',
'-f', 'Dockerfile',
'.'
]
id: 'build_test_image'