Containerizing a C# hello world app

I’ve always wanted to have my own little Kubernetes cluster somewhere and I finally decided to create one with Civo. But I had no idea what to run on it. So, this little post is about how I went about creating a hello-world application to run on my cluster!

If you only want to see the code, here you go.

The application itself is a simple C# file inspired by Jess Frazelle’s much cooler party-clippy:

1const string CLIPPY = @"         
2        
3         __                 
4        /  \        _____________ 
5        |  |       /             \
6        @  @       | It looks    |
7        || ||      | like you    |
8        || ||    CLIPPY);
9app.Run();

main.cs Next, I put together a Dockerfile. After some googling around, I decided to use the ubuntu chiseled docker image ubuntu/dotnet-deps. I’ve only ever used alpine or debian for C# applications, so this was a first!

 1FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build-env
 2WORKDIR /app
 3
 4COPY ./src ./src
 5RUN dotnet publish -c Release -r linux-x64 --self-contained -o /app/out ./src/clippy.csproj
 6
 7FROM ubuntu/dotnet-deps:7.0_edge AS final
 8
 9LABEL org.opencontainers.image.source="https://github.com/gldraphael/clippy"
10LABEL org.opencontainers.image.description="A simple hello world application."
11
12ENV \
13    # Configure web servers to bind to port 80 when present
14    ASPNETCORE_URLS=http://+:80      \
15    # Enable detection of running in a container
16    DOTNET_RUNNING_IN_CONTAINER=true \
17    # Disable globalization
18    DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
19
20EXPOSE 80
21
22WORKDIR /app
23COPY --from=build-env /app/out .
24ENTRYPOINT ["./clippy"]

Dockerfile At this point, I had something I could run in a container.

Now that I had a working docker image, I wanted to be able to publish this to GitHub packages using GitHub actions. This bit was actually the easiest. I literally just pasted this example from the documentation, and it just worked!

 1# pull the latest image
 2docker pull ghcr.io/gldraphael/clippy:main
 3
 4# run it in the background
 5docker run -it -d -p 8080:80 --name clippy --rm ghcr.io/gldraphael/clippy:main
 6
 7# curl it
 8curl localhost:8080
 9
10# once you're done, stop it to delete it
11docker stop clippy

This also happens to be the first time I’ve ever used GitHub packages. Another first. Yay!

Next, I wanted a helm chart. Creating the chart itself was easy. helm create chart did it. I only had to go in and update a few things (like change the app name from chart to clippy, update the image to use, and so on).

Trouble was, I wasn’t even sure if GitHub container registry supported OCI artifacts yet. Lucky for me, Niklas Metje documented this on his blog. I just had to figure out the workflow file. I ended up using Stefan Prodan’s podinfo project as an example and decided to go with something like this:

 1name: Push helm chart
 2
 3on:
 4  push:
 5    branches: ['main']
 6
 7env:
 8  REGISTRY: ghcr.io
 9
10jobs:
11  build-and-push-image:
12    runs-on: ubuntu-latest
13    permissions:
14      contents: read
15      packages: write
16
17    steps:
18      - name: Checkout repository
19        uses: actions/checkout@v3
20
21      - name: Setup Helm
22        uses: azure/setup-helm@v3
23        with:
24          version: v3.11.3
25
26      - name: Log in to the Container registry
27        uses: docker/login-action@v2
28        with:
29          registry: ${{ env.REGISTRY }}
30          username: ${{ github.actor }}
31          password: ${{ secrets.GITHUB_TOKEN }}
32      
33      - name: Publish Helm chart to GHCR
34        run: |
35          helm package chart
36          export CHART_VERSION=$(grep 'version:' ./chart/Chart.yaml | tail -n1 | awk '{ print $2 }')
37          helm push clippy-$CHART_VERSION.tgz oci://${{ env.REGISTRY }}/gldraphael/charts
38          rm clippy-$CHART_VERSION.tgz

The action seems to push a chart ok, but I’m yet to actually run this on a cluster. Next weekend!

<< Previous Post

|

Next Post >>

#Docker #C# #Clippy