Pull Image From Private Registry

In order to deploy an image into Kubernetes, the image must be available in a registry. I’m very much in the learning & experimenting phase of my Kubernetes journey, and I find myself using Docker Hub private registries for a lot of things. After using docker login I can docker push & docker pull images from a private registry just by naming them correctly with my Docker ID e.g. <my-docker-id>/some-image. However, kubectl doesn’t automatically inherit this knowledge and access, so what must be done to enable deployment of a locally-developed image into a locally-runing cluster? Let’s take a look!

The first thing we need to do is authenticate to the registry, which we can do using docker login. This will prompt for credentials and store an authorization token in ~/.docker/config.json. The lines below demonstrate how to do this and view the result.

docker login
cat ~/.docker/config.json

In order to make the authentication token accessible to the Kubernetes cluster, we can use Secrets. The following commands can be used to copy the credential from the Docker config.json into a Secret named regcred and inspect the result.

kubectl create secret generic regcred \
    --from-file=.dockerconfigjson=<path/to/.docker/config.json> \
    --type=kubernetes.io/dockerconfigjson
kubectl get secret regcred --output=yaml

Next, we’ll create a Deployment that includes our Secret. Create a new file my-app-deployment.yaml with the following contents:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: <my-docker-id>/my-app:latest
        ports:
        - containerPort: 80
      imagePullSecrets:
      - name: regcred

And we’ll need to expose the deployment with a Service, so create another file my-app-service.yaml with this for its contents:

apiVersion: v1
kind: Service
metadata:
  name: my-app-svc
  labels:
    app: my-app
spec:
  type: NodePort
  ports:
  - port: 80
    nodePort: 30080
  selector:
    app: my-app

Now we use these files to create the Deployment and Service in Kubernetes:

kubectl create -f my-app-deployment.yaml
kubectl create -f my-app-service.yaml

That should do the trick. You can inspect the Deployment and Service using kubectl get pods and kubectl describe service my-app-service respectively. Assuming everything deployed correctly, you should be able to access your app at http://cluster-host-ip:30080.

Run an ASP.NET Core App on Raspberry Pi With Docker

In my last article, I wrote about how to create a single-page Angular app using the .NET Core CLI, create a Docker image, and run it as a container in about 4 steps that take just minutes to execute. By modifying a single line in your Dockerfile, you can target the 32-bit ARM architecture needed to run the image as a container on a Raspberry Pi.

Here’s the one line that needs to change in the Dockerfile to make it runnable on ARM32 (old line is commented for reference):

# FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS base
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.2-buster-slim-arm32v7 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /src
COPY ["my-app.csproj", "./"]
RUN dotnet restore "./my-app.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "my-app.csproj" -c Release -o /app/build
RUN apt-get update && \
    apt-get install -y wget && \
    apt-get install -y gnupg2 && \
    wget -qO- https://deb.nodesource.com/setup_10.x | bash - && \
    apt-get install -y build-essential nodejs

FROM build AS publish
RUN dotnet publish "my-app.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "my-app.dll"]

Note that the official list of available tags for different architectures can be found here. Consult this list to determine if newer images are available.

That’s it, though. Create your image, push it to Docker Hub, pull it on your Raspberry Pi, and run it just as you would locally. If you haven’t used Docker Hub before, you’ll need to login and create a repository. Check out the Docker Hub Quickstart for help. You may also need to run docker login on both machines to access your new repo.

# dev machine
docker build -t <dockerID>/repo .
docker push <dockerID>/repo

# raspberry pi
docker pull <dockerID>/repo
docker run -d -p 5000:80 <dockerID>/repo
The default dotnet new Angular app running locally on Raspberry Pi.

10 Minutes to Create & Run .NET Core Angular SPA in Docker

In this article, I’ll demonstrate how to create an ASP.NET Core Angular single-page application using the .NET Core CLI, create a Docker image, and run it as a container. The entire process is just 4 steps, each of which takes about a minute to perform–although creating the Docker image takes a couple minutes to complete. Note, also, that these same steps work from both Linux and Windows.

  1. Create Angular application
  2. Create Dockerfile
  3. Create Docker image
  4. Run container

Before you start, make sure you have the following prerequisites installed.

  • .NET Core SDK
  • Visual Studio Code with Docker extension
  • Docker

Installation can be verified by running these commands:

dotnet --version
code --version
code --install-extension ms-azuretools.vscode-docker
docker --version

Create the Application

We begin by creating our Angular application using the dotnet new command and specifying the angular template. The -o argument will cause the new project to be created in a sub-folder named my-app. This will create a .NET Core ASP.NET project with an Angular app in its ClientApp folder. After running the command, go into the new directory and launch Visual Studio Code.

dotnet new angular -o my-app
cd my-app
code .

Add Docker Files

With the Docker extension for VS Code installed, you can add Docker files easily via the command palette. Open the command palette using ctrl+shift+P or View > Command Palette menu options, and run the command Docker: Add Docker Files to Workspace. (Tip: type “docker” to filter commands.)

Selecting the command will ask you a series of questions:

  • Application Platform: ASP.NET Core
  • Operating System: Linux
  • What port(s) does your app listen on? 80, 443

If you’re running Docker on Windows, it’s important to make sure Docker is configured to run the right type of containers (Windows vs Linux). I answered “Linux” above, and I can confirm that my Docker for Windows is configured to run Linux containers by clicking the Docker icon in my system tray, as shown in the screenshot below. It shows “Switch to Windows containers” which means it’s currently using Linux containers. It’s fine to use Windows containers, too, but you’ll need to adjust installation instructions for NodeJS in the Dockerfile further down.

Once you’ve answered the Docker extention’s questions, a Dockerfile is generated. One modification is needed to also install NodeJS for our client app. The lines needed to do this are highlighted in the complete Dockerfile below.

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /src
COPY ["my-app.csproj", "./"]
RUN dotnet restore "./my-app.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "my-app.csproj" -c Release -o /app/build
RUN apt-get update && \
    apt-get install -y wget && \
    apt-get install -y gnupg2 && \
    wget -qO- https://deb.nodesource.com/setup_10.x | bash - && \
    apt-get install -y build-essential nodejs
    
FROM build AS publish
RUN dotnet publish "my-app.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "my-app.dll"]

Build the Image

When you’re done editing your Dockerfile in VS Code, save changes and head back to the command line. Run the following command to build your image:

docker build -t my-app .

Verify that the image was created by running another command:

docker image ls my-app

Run a Container

Now we’ll use the docker run command to run a container using our image. We’ll specify two arguments: -d to run in detached mode and -p to map ports on the local machine to the container.

docker run -d -p 5000:80 my-app

Verify that the app is running by browsing to the localhost:5000: