Skip to content

Deploy a Mock

TL;DR — Package a working mock as a container image and deploy it with the native Helm chart.

Once the mock works locally, package it as a container image and deploy it with a native Helm chart.

The finished chart lives alongside the sample project:

Build the Image

The project template already contains a Dockerfile. For a project named DummyAppMock, the final image can look like this:

ARG DOTNET_SDK_IMAGE=mcr.microsoft.com/dotnet/sdk:10.0
ARG DOTNET_RUNTIME_IMAGE=mcr.microsoft.com/dotnet/runtime:10.0

FROM ${DOTNET_SDK_IMAGE} AS build
WORKDIR /src
COPY . .
ARG QAAS_NUGET_SOURCE_NAME=nuget_feed
ARG QAAS_NUGET_SOURCE_URL=https://api.nuget.org/v3/index.json
RUN dotnet nuget remove source "${QAAS_NUGET_SOURCE_NAME}" --configfile NuGet.config || true \
 && dotnet nuget add source "${QAAS_NUGET_SOURCE_URL}" --name "${QAAS_NUGET_SOURCE_NAME}" --configfile NuGet.config
RUN dotnet restore DummyAppMock.sln --configfile NuGet.config
RUN dotnet publish DummyAppMock/DummyAppMock.csproj -c Release -o /app/publish --no-restore

FROM ${DOTNET_RUNTIME_IMAGE}
WORKDIR /app
COPY --from=build /app/publish .
ENV QAAS_MOCKER_CONFIG=mocker.qaas.yaml
ENTRYPOINT ["sh", "-c", "exec dotnet DummyAppMock.dll \"$QAAS_MOCKER_CONFIG\""]

⚠️ Important

Build the project as part of the Docker image build, then push that finished runtime image to your registry. The deployed container should only pull the published image and start the already-built application. It should not compile the project during pod startup.

The Dockerfile keeps the SDK image, runtime image, NuGet source name, NuGet source URL, and mocker configuration file configurable. Use build arguments for values needed before dotnet restore, and use the QAAS_MOCKER_CONFIG environment variable when the same image should start a different mocker YAML file.

Build and push the image to your registry:

docker build -t ghcr.io/my-org/dummy-app-mock:1.0.0 .
docker push ghcr.io/my-org/dummy-app-mock:1.0.0

For a private feed or a custom image mirror:

DOTNET_SDK_IMAGE=registry.example.com/dotnet/sdk:10.0
DOTNET_RUNTIME_IMAGE=registry.example.com/dotnet/runtime:10.0
QAAS_NUGET_SOURCE_URL=https://nuget.example.com/v3/index.json

docker build -t ghcr.io/my-org/dummy-app-mock:1.0.0 \
  --build-arg DOTNET_SDK_IMAGE="${DOTNET_SDK_IMAGE}" \
  --build-arg DOTNET_RUNTIME_IMAGE="${DOTNET_RUNTIME_IMAGE}" \
  --build-arg QAAS_NUGET_SOURCE_URL="${QAAS_NUGET_SOURCE_URL}" \
  .

After the image is published, Kubernetes only needs to pull ghcr.io/my-org/dummy-app-mock:1.0.0 and run it. Rebuilding is only needed when you publish a new image tag.

Native Helm Chart

This chart deploys:

  • the mocker container
  • a Redis instance for the optional Controller
  • a service for the mocker HTTP endpoint

Chart.yaml

apiVersion: v2
name: dummy-app-mock
description: Helm chart for deploying a QaaS.Mocker quick-start project
type: application
version: 0.1.0
appVersion: "1.0.0"

values.yaml

mocker:
  replicaCount: 1
  image:
    repository: ghcr.io/my-org/dummy-app-mock
    tag: 1.0.0
    pullPolicy: IfNotPresent
  service:
    type: ClusterIP
    port: 80
  controller:
    serverName: DummyAppMock
  configFile: mocker.qaas.yaml

redis:
  image:
    repository: redis
    tag: 7-alpine
    pullPolicy: IfNotPresent
  service:
    type: ClusterIP
    port: 6379

templates/mocker-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-mocker
spec:
  replicas: {{ .Values.mocker.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Release.Name }}-mocker
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}-mocker
    spec:
      containers:
        - name: mocker
          image: "{{ .Values.mocker.image.repository }}:{{ .Values.mocker.image.tag }}"
          imagePullPolicy: {{ .Values.mocker.image.pullPolicy }}
          ports:
            - containerPort: {{ .Values.mocker.service.port }}
          env:
            - name: QAAS_MOCKER_CONFIG
              value: {{ .Values.mocker.configFile | quote }}
            - name: Controller__ServerName
              value: {{ .Values.mocker.controller.serverName | quote }}
            - name: Controller__Redis__Host
              value: "{{ .Release.Name }}-redis:{{ .Values.redis.service.port }}"

templates/mocker-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: {{ .Release.Name }}-mocker
spec:
  type: {{ .Values.mocker.service.type }}
  selector:
    app: {{ .Release.Name }}-mocker
  ports:
    - name: http
      port: {{ .Values.mocker.service.port }}
      targetPort: {{ .Values.mocker.service.port }}
      protocol: TCP

templates/redis-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-redis
spec:
  replicas: 1
  selector:
    matchLabels:
      app: {{ .Release.Name }}-redis
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}-redis
    spec:
      containers:
        - name: redis
          image: "{{ .Values.redis.image.repository }}:{{ .Values.redis.image.tag }}"
          imagePullPolicy: {{ .Values.redis.image.pullPolicy }}
          ports:
            - containerPort: {{ .Values.redis.service.port }}

templates/redis-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: {{ .Release.Name }}-redis
spec:
  type: {{ .Values.redis.service.type }}
  selector:
    app: {{ .Release.Name }}-redis
  ports:
    - name: redis
      port: {{ .Values.redis.service.port }}
      targetPort: {{ .Values.redis.service.port }}
      protocol: TCP

Deploy

helm upgrade --install dummy-app-mock ./chart

The mocker becomes reachable through the mocker service, and the Controller connects to Redis through the injected Controller__Redis__Host environment variable.

See also