{"id":8718,"date":"2021-06-01T21:51:39","date_gmt":"2021-06-01T21:51:39","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=8718"},"modified":"2023-05-24T08:16:45","modified_gmt":"2023-05-24T08:16:45","slug":"deploying-an-asp-net-core-application-into-a-docker-image-within-kubernetes","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/deploying-an-asp-net-core-application-into-a-docker-image-within-kubernetes\/","title":{"rendered":"Deploying an ASP.NET core application into a Docker image within Kubernetes"},"content":{"rendered":"<p>In the previous post we looked and an &#8220;off the shelf&#8221; image of nginx, which we deployed to Kubernetes and were able to access externally using Ingress. This post follows on from that one, so do refer back to it if you have any issues with the following configurations etc.<\/p>\n<p>Let&#8217;s look at the steps for deploying our own Docker image to k8s and better still let&#8217;s deploy a dotnet core webapp.<\/p>\n<p><em>Note: Kubernetes is deprecating its support for Docker, however this does not mean we cannot deployed docker images, just that we need to use the docker shim or generated container-d (or other container) images.<\/em><\/p>\n<p><strong>The App<\/strong><\/p>\n<p>We&#8217;ll create a standard dotnet ASP.NET core Razor application which you can obviously do what you wish to, but we&#8217;ll take the default implementation and turn this into a docker image and then deploy it to k8s.<\/p>\n<p>So to start with&#8230;<\/p>\n<ul>\n<li>Create a .NET core Razor application (mine&#8217;s named razordemo), you can do this from Visual Studio or using\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\ndotnet new webapp -o razordemo --no-https -f net5.0\r\n<\/pre>\n<\/li>\n<li>If you&#8217;re running this on a remote machine don&#8217;t forget to change launchSettings.json localhost to 0.0.0.0 if you need to.<\/li>\n<li>Run dotnet build<\/li>\n<\/ul>\n<p>It&#8217;d be good to see this is all working, so if let&#8217;s run the demo using<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndotnet run\r\n<\/pre>\n<p>Now use your browser to access http:\/\/your-server-ip:5000\/ and you should see the Razor demo home page, or use curl to see if you get valid HTML returned, i.e.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ncurl http:\/\/your-server-ip:5000\r\n<\/pre>\n<p><strong>Generating the Docker image<\/strong><\/p>\n<p><em>Note: If you changed launchSettings.json to use 0.0.0.0, reset this to localhost.<\/em><\/p>\n<p>Here&#8217;s the Dockerfile for building an image, it&#8217;s basically going to publish a release build of our Razor application then set up the image to run the razordemo.dll via dotnet from a Docker instance.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nFROM mcr.microsoft.com\/dotnet\/sdk:5.0 AS build\r\nWORKDIR \/src\r\nCOPY razordemo.csproj .\r\nRUN dotnet restore\r\nCOPY . .\r\nRUN dotnet publish -c release -o \/app\r\n\r\nFROM mcr.microsoft.com\/dotnet\/aspnet:5.0\r\nWORKDIR \/app\r\nCOPY --from=build \/app .\r\nENTRYPOINT &#x5B;&quot;dotnet&quot;, &quot;razordemo.dll&quot;]\r\n<\/pre>\n<p>Now run docker build using the following<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndocker build . -t razordemo --no-cache\r\n<\/pre>\n<p>If you want to check the image works as expect then run the following<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndocker run -d -p 5000:80 razordemo \r\n<\/pre>\n<p>Now check the image is running okay by using curl as we did previously. If all worked you should see the Razor demo home page again, but now we&#8217;re seeing if within the docker instance.<\/p>\n<p><strong>Docker in the local registry<\/strong><\/p>\n<p>Next up, we want to deploy this docker image to k8s.<\/p>\n<p>k8s will try to get an image from a remote registry and we don&#8217;t want to deploy this image outside of our network, so we need to rebuild the image, slightly differently using<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndocker build . -t localhost:32000\/razordemo --no-cache\r\n<\/pre>\n<p><em>Reference: see <a href=\"https:\/\/microk8s.io\/docs\/registry-built-in\" rel=\"noopener\" target=\"_blank\">Using the built-in registry<\/a> for more information on the built-in registry.<\/em><\/p>\n<p>Before going any further, I&#8217;m using Ubuntu and micro8s, so will need to enable the local registry using<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nmicrok8s enable registry\r\n<\/pre>\n<p>I can&#8217;t recall if this is required, but I also enabled k8s DNS using<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nmicrok8s.enable dns\r\n<\/pre>\n<p>Find the image ID for our generated image using<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndocker images\r\n<\/pre>\n<p>Now use the following commands, where {the image id} was the one found from the above command<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndocker tag {the image id} localhost:32000\/razordemo\r\ndocker push localhost:32000\/razordemo\r\n<\/pre>\n<p><strong>The configuration<\/strong><\/p>\n<p>This is a configuration based upon my previous post (the file is named razordemo.yaml)<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\napiVersion: apps\/v1\r\nkind: Deployment\r\nmetadata:\r\n  name: webapp\r\nspec:\r\n  selector:\r\n    matchLabels:\r\n      run: webapp\r\n  replicas: 1\r\n  template:\r\n    metadata:\r\n      labels:\r\n        run: webapp\r\n    spec:\r\n      containers:\r\n      - name: webapp\r\n        image: localhost:32000\/razordemo\r\n        imagePullPolicy: IfNotPresent\r\n        ports:\r\n        - containerPort: 80\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: webapp\r\n  labels:\r\n    run: webapp\r\nspec:\r\n  ports:\r\n    - port: 80\r\n      protocol: TCP\r\n  selector:\r\n    run: webapp\r\n---\r\napiVersion: networking.k8s.io\/v1\r\nkind: Ingress\r\nmetadata:\r\n  name: razor-ingress\r\nspec:\r\n  rules:\r\n  - http:\r\n      paths:\r\n      - path: \/\r\n        pathType: Prefix\r\n        backend:\r\n          service:\r\n            name: webapp\r\n            port: \r\n              number: 80\r\n<\/pre>\n<p>Now apply this configuration to k8s using (don&#8217;t forget to change the file name to whatever you named your file) <\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nkubectl apply -f .\/razordemo.yaml\r\n<\/pre>\n<p>Now we should be able to check the deployed image, by either using the k8s dashboard or run<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nkubectl get ep webapp\r\n<\/pre>\n<p>Note the endpoint and curl to that endpoint, if all worked well you should be able to see the ASP.NET generate home page HTML and better still access http:\/\/your-server-ip from another machine and see the webpage.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the previous post we looked and an &#8220;off the shelf&#8221; image of nginx, which we deployed to Kubernetes and were able to access externally using Ingress. This post follows on from that one, so do refer back to it if you have any issues with the following configurations etc. Let&#8217;s look at the steps [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[200,102,314],"tags":[],"class_list":["post-8718","post","type-post","status-publish","format-standard","hentry","category-asp-net-core","category-docker","category-kubernetes"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/8718","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=8718"}],"version-history":[{"count":5,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/8718\/revisions"}],"predecessor-version":[{"id":9983,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/8718\/revisions\/9983"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=8718"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=8718"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=8718"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}