<p>I would like to create a kubernetes CronJob scheduler which can invoke .netcore console application every minute.</p>

<p><strong>CronJob Spec [cronjob-poc.yml]:</strong></p>

<pre><code>kind: CronJob

metadata:

  name: cronjob-poc

spec:

  schedule: "*/1 * * * *" #Every Minute

  jobTemplate:

    spec:

      template:

        spec:

          containers:

          - name: cronjob-poc

            image: cronjobpoc:dev

            command: ["/usr/local/bin/dotnet", "/app/CronJobPoc.dll"]

          restartPolicy: OnFailure
</code></pre>

<p><strong>Kind Commands:</strong></p>

<pre><code>kind create cluster --name=cronjob-poc

kind load docker-image cronjobpoc:dev --name=cronjob-poc

kubectl apply -f .\cronjob-poc.yml
</code></pre>

<p><strong>.netcore is a very simple app which just prints hello</strong></p>

<pre><code>using System;

namespace CronJobPoc{

    class Program{

        static void Main(string[] args)
        {
            Console.WriteLine($"{DateTime.Now} - Hello World!");
        }
    }
}
</code></pre>

<p>Docker File:</p>

<pre><code>FROM mcr.microsoft.com/dotnet/core/runtime:3.1-buster-slim AS base    
WORKDIR /app    
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build    
WORKDIR /src    
COPY ["CronJobPoc/CronJobPoc.csproj", "CronJobPoc/"]    
RUN dotnet restore "CronJobPoc/CronJobPoc.csproj"    
COPY . .    
WORKDIR "/src/CronJobPoc"    
RUN dotnet build "CronJobPoc.csproj" -c Release -o /app/build    
FROM build AS publish    
RUN dotnet publish "CronJobPoc.csproj" -c Release -o /app/publish    
FROM base AS final    
WORKDIR /app    
COPY --from=publish /app/publish .    
ENTRYPOINT ["dotnet", "CronJobPoc.dll"]
</code></pre>

<p>When I do <code>kubectl get pods</code> I see below information.</p>

<pre><code>NAME                           READY   STATUS             RESTARTS   AGE

cronjob-poc-1589463060-9dp8p   0/1     CrashLoopBackOff   4          2m51s
</code></pre>

<p>When I try to see logs using <code>kubectl logs cronjob-poc-1589463060-9dp8p</code> I do not see anything. The command returns empty.</p>

<p>Not sure how to see the logs. There is something wrong but not sure what?</p>

<p>I am expecting to see the output " - Hello World!" somewhere in the log. Not sure how to check what went wrong and where can the logs with proper error messages can be seen.</p>

<p>Any quick help on this would be highly appreciated.</p>

<p>I also tried using command argument as shown below in cronjob-poc.yml. I get CrashLoopBackOff status for the pod</p>

<pre><code>command:
- /bin/sh
- -c
- echo Invoking CronJobPoc.dll ...; /usr/local/bin/dotnet CronJobPoc.dll
</code></pre>

<p>When I try to check the log using kubectl logs , I see /bin/sh: 1: /usr/local/bin/dotnet: not found</p>

userpkp
<p>You could simplify the Dockerfile a bit. Here's an example I use in my cron job netcore apps:</p>

<pre><code># Copy csproj and restore as layer 1
FROM microsoft/dotnet:2.1-sdk-alpine AS build
ARG NUGET=https://api.nuget.org/v3/index.json
WORKDIR /app
COPY *.csproj ./
RUN dotnet restore --source $NUGET

# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out

# Build runtime image
FROM microsoft/dotnet:2.1-runtime-alpine AS final
WORKDIR /app
COPY --from=build /app/out .
CMD ["dotnet", "Custom.MetricScraper.dll"]
</code></pre>

<p>It's 3 steps, slightly easier to read. You'll notice the difference is that instead of ENTRYPOINT I'm using CMD at the end. You can modify this to fit your project name and netcore 3.1.</p>

<p>Here's the corresponding YAML:</p>

<pre><code>apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: metric-scraper-job
  labels:
    app: metric-scraper
spec: # Cron job wrapper around a job
  schedule: "* * * * *"
  jobTemplate:
    spec: # Job definition
      template:
        metadata:
          labels:
            app: metric-scraper
            is-cron: "true"
        spec: # Pod definition
          containers:
          - name: metric-scraper
            image: metricscraper:latest
            imagePullPolicy: IfNotPresent
            env:
              - name: ASPNETCORE_ENVIRONMENT
              value: Production
          restartPolicy: Never
      backoffLimit: 2
</code></pre>

<p>This YAML definition will run the image metricscraper:latest every minute.</p>

<p>One thing I noticed though about cron jobs in k8s is that the pods don't get cleaned up (at least on my 1.14 cluster). A workaround is setting a pod limit on a namespace via resourcequotas and sticking the cron jobs in there. Hope this helps!</p>
