My previous blog posts talks about built-in container support in the .NET SDK. It allows you to create and publish Docker images for your .NET applications without writing any Dockerfile. I also showed how to use the Chiseled Ubuntu base images optimized for .NET and containers. We saw how to publish your Docker images using the .NET SDK to GitHub Packages / Container Registry.

Today, I want to show you how to publish your Docker images using the .NET SDK to GitHub Container Registry using GitHub Actions. It brings us to the next level of automation.

Introduction

GitHub Container Registry is a package hosting service that allows you to host your Docker images and other container images in one place. It integrates with GitHub and GitHub Actions. You can use GitHub Actions to build and publish your Docker images to GitHub Container Registry. You can also use GitHub Actions to build and publish your Docker images to other container registries such as Docker Hub, Azure Container Registry, and Amazon Elastic Container Registry.

Combining GitHub Actions and the .NET SDK makes the whole experience easy and more consistent.

GitHub Packages / Container Registry publish profile

We configure the .NET SDK container building tools using a profile.
It can specify the base image and the target tags. The profile file is a XML file named after the publish profile. Later, you select the publish profile using the PublishProfile property in the GitHub Action.

As we want to publish our Docker images to GitHub Container Registry, we specify the ContainerRegistry property to ghcr.io. We also set the ContainerRepository property to the name of the image we want to publish. The ContainerRepository is configured as a path using your GitHub username, laurentkempe, then / and the image’s name.

github.pubxml
1
2
3
4
5
6
7
8
9
10
11
12
13
<Project>
<PropertyGroup>
<EnableSdkContainerSupport>true</EnableSdkContainerSupport>
<WebPublishMethod>Container</WebPublishMethod>
<ContainerBaseImage>mcr.microsoft.com/dotnet/aspnet:7.0</ContainerBaseImage>
<ContainerImageTag>1.0.0</ContainerImageTag>
<ContainerRegistry>ghcr.io</ContainerRegistry>
<ContainerRepository>laurentkempe/containerplayground</ContainerRepository>
</PropertyGroup>
<ItemGroup>
<ContainerPort Include="80" Type="tcp" />
</ItemGroup>
</Project>

Publishing images using GitHub Actions

To be able to publish your Docker images to GitHub Container Registry, you need to create a GitHub Actions workflow. A GitHub Actions workflow is a set of instructions executed when a specific event occurs. For example, you can create a workflow executed when a new tag getting pushed to the repository. You can also create a workflow executed when a pull request get created or triggered manually.

Here is an example of a GitHub action using the .NET SDK container building tools to publish a .NET project to GitHub Container Registry using a .NET publish profile:

.github/workflows/publish-to-github-container-registry.yml
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
name: Publish to GitHub Container Registry

on:
# trigger manual workflow
workflow_dispatch:
# trigger workflow on push to master when changes happen in one folder
push:
branches:
- main
paths:
- 'PublishGitHubAction/**'

jobs:
publish:
runs-on: ubuntu-latest

permissions:
packages: write
contents: read

steps:
- name: Checkout
uses: actions/checkout@v2

- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: '7.x'

- name: Login to GitHub Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Publish and push the container image
run: |
dotnet publish --os linux --arch x64 -c Release /p:PublishProfile=github

The publish job is triggered when a git push is made on the main branch matching a path or can be triggered manually. It sets the permissions granted to the GITHUB_TOKEN for the actions in this job. It uses the checkout action to checkout the repository, the setup-dotnet action to install the .NET 7 SDK, the docker/login-action action to login to GitHub Container Registry, and the run action to publish the project using the .NET SDK pushing the container image to GitHub Container Registry.

Failing

Following those steps and running the GitHub Action, you will get the following errors error CONTAINER1013 and CONTAINER1001:

1
Error: /home/runner/.dotnet/sdk/7.0.403/Containers/build/Microsoft.NET.Build.Containers.targets(201,5): error CONTAINER1013: Failed to push to the output registry: CONTAINER1001: Failed to upload blob using POST https://ghcr.io/v2/laurentkempe/containerplayground/blobs/uploads/; received status code 'Forbidden'. [/home/runner/work/containerPlayground/containerPlayground/PublishGitHubAction/PublishGitHubAction.csproj]

GitHub Packages supports the GITHUB_TOKEN for easy and secure authentication in your workflows.

Using the GITHUB_TOKEN, instead of a personal access token (classic) with the repo scope, increases the security of your repository as you don’t need to use a long-lived personal access token that offers unnecessary access to the repository where your workflow is run.

To be able to publish from a GitHub Action to GitHub Container Registry using GITHUB_TOKEN, you need to ensure your package has access to your workflow. You must add the repository where the workflow is stored to your package. Then, use the Role drop-down menu to select the write role.

Manage Actions access

Follow the following four steps from this page to fix the issue.

Success

You can now manually trigger the GitHub Action and see it succeed.

GitHub Action succeed

And the package is published to GitHub Container Registry.

GitHub Action Package

Testing the image

The GitHub Action combined with the publishing profile will create a Docker image named ghcr.io/laurentkempe/containerplayground:1.0.1.

First login to the GitHub Container Registry using the following command using a Personal Access Token with the read:packages scope:

1
docker login ghcr.io -u USERNAME

You will then be able to pull it using the following command:

1
docker pull ghcr.io/laurentkempe/containerplayground:1.0.1

or run it

1
docker run -it --rm -p 8080:80 ghcr.io/laurentkempe/containerplayground:1.0.1

GitHub Action Package Docker Run

Finally, browse to http://localhost:8080/ to see the “Hello World!” message.

Conclusion

In this blog post, we saw how to publish Docker images to GitHub Container Registry using GitHub Actions and the .NET SDK. We saw how to create a GitHub Actions workflow triggered when a git push is made on the main branch matching a path or can be triggered manually.

I hope this helps. If you have any questions, please leave a comment.

References

My older blog posts on the subject

Others

Get the source code on GitHub laurentkempe/containerPlayground/PublishGitHubAction.