Skip to content

Creating Kubernetes Jobs.

Sometimes you need to run a container to execute a specific task and then stop it.

Normally in Kubernetes, if you try just to run it, it will actually create a deployment,
meaning you container will keep running all the time. That is because by default kubectl runs with ‘–restart=”Always”‘ policy.
So if you don’t want to create a yaml file where you specify pod ‘kind’ as a Job, but simply use kubectl run, you can set restart policy to ‘OnFailure’.
Let’s run simple container as a job. It is a simple web crawler which I have written for one of my job interviews, it has many bugs and incomplete,
but sometimes it actually works 🙂 So let’s run it:

➜  ~ kubectl run crawler --restart=OnFailure --image=kayan/web-crawler \
 -- http://www.gamesyscorporate.com http://www.gamesyscorporate.com 3
job "crawler" created

Now we can check the state of the pod:

➜  ~ kubectl get pod
NAME            READY     STATUS              RESTARTS   AGE
crawler-k57bh   0/1       ContainerCreating   0          2s

it will take a while, as it needs to download the image first, to check run:

kubectl describe pod crawler

You should see something like below:

➜  ~ kubectl describe pod crawler
Name:		crawler-k57bh
Namespace:	default
Node:		minikube/192.168.99.100
Start Time:	Sun, 26 Nov 2017 22:20:28 +0000
Labels:		controller-uid=01e62349-d2f8-11e7-accd-08002739d83b
		job-name=crawler
		run=crawler
Annotations:	kubernetes.io/created-by={"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"Job","namespace":"default","name":"crawler","uid":"01e62349-d2f8-11e7-accd-08002739d83b","apiVersion":"bat...
Status:		Running
IP:		172.17.0.5
Created By:	Job/crawler
Controlled By:	Job/crawler
Containers:
  crawler:
    Container ID:	docker://059c0a13f7963401a6e20eb7d6eb540a77e75384ba4d7311b435f88b8a00b669
    Image:		kayan/web-crawler
    Image ID:		docker-pullable://kayan/web-crawler@sha256:e2eb8c3b16d4749ab7f2c0708424e407aa82d487ac800ee05ecf87a4c9c54243
    Port:		<none>
    Args:
      http://www.gamesyscorporate.com
      http://www.gamesyscorporate.com
      3
    State:		Running
      Started:		Sun, 26 Nov 2017 22:20:31 +0000
    Ready:		True
    Restart Count:	0
    Environment:	<none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-r89kc (ro)
Conditions:
  Type		Status
  Initialized 	True
  Ready 	True
  PodScheduled 	True
Volumes:
  default-token-r89kc:
    Type:	Secret (a volume populated by a Secret)
    SecretName:	default-token-r89kc
    Optional:	false
QoS Class:	BestEffort
Node-Selectors:	<none>
Tolerations:	<none>
Events:
  FirstSeen	LastSeen	Count	From			SubObjectPath			Type		Reason			Message
  ---------	--------	-----	----			-------------			--------	------			-------
  40s		40s		1	default-scheduler					Normal		Scheduled		Successfully assigned crawler-k57bh to minikube
  40s		40s		1	kubelet, minikube					Normal		SuccessfulMountVolume	MountVolume.SetUp succeeded for volume "default-token-r89kc"
  40s		40s		1	kubelet, minikube	spec.containers{crawler}	Normal		Pulling			pulling image "kayan/web-crawler"

Last line is about a last event, “pulling image “kayan/web-crawler” – once this is done, it should create and then run it, so if you describe it again later you should see more events:

  38s		38s		1	kubelet, minikube	spec.containers{crawler}	Normal		Pulled			Successfully pulled image "kayan/web-crawler"
  38s		38s		1	kubelet, minikube	spec.containers{crawler}	Normal		Created			Created container
  37s		37s		1	kubelet, minikube	spec.containers{crawler}	Normal		Started			Started container

Now I would like to check the jobs’s state:

➜  ~ kubectl get job
NAME      DESIRED   SUCCESSFUL   AGE
crawler   1         0            8s

As you can see it is still running the job, and once finished, SUCCESSFUL will be changed to 1:

➜  ~ kubectl get job
NAME      DESIRED   SUCCESSFUL   AGE
crawler   1         1            1m

Once job is done, pod will disappear:

➜  ~ kubectl get pod
No resources found, use --show-all to see completed objects.

But hold on, how we will check the logs of completed pod if it is not here?

Thankfully there is a way to show terminated pods with ‘-a’ argument, which stands for ‘all’:

➜  ~ kubectl get pod -a
NAME            READY     STATUS      RESTARTS   AGE
crawler-qmzpp   0/1       Completed   0          10h

Now, knowing the name of the pod we can show it’s logs:

➜  ~ kubectl logs  crawler-97d6q | grep "Java Developer"

<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=923720" target="_blank"><span class="title">Java Developer </span><span class="location">Estonia </span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=493517" target="_blank"><span class="title">Java Developer </span><span class="location">Estonia </span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=493500" target="_blank"><span class="title">Java Developer - Cloud Platform</span><span class="location">Estonia </span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=721812" target="_blank"><span class="title">Java Developer - Games Development</span><span class="location">London, Piccadilly</span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=927697" target="_blank"><span class="title">Java Developer - Games Development (Bingo)</span><span class="location">London, Piccadilly</span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=874603" target="_blank"><span class="title">Senior Java Developer - Payments</span><span class="location">London, Piccadilly</span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=923720" target="_blank"><span class="title">Java Developer </span><span class="location">Estonia </span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=493517" target="_blank"><span class="title">Java Developer </span><span class="location">Estonia </span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=493500" target="_blank"><span class="title">Java Developer - Cloud Platform</span><span class="location">Estonia </span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=721812" target="_blank"><span class="title">Java Developer - Games Development</span><span class="location">London, Piccadilly</span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=927697" target="_blank"><span class="title">Java Developer - Games Development (Bingo)</span><span class="location">London, Piccadilly</span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=874603" target="_blank"><span class="title">Senior Java Developer - Payments</span><span class="location">London, Piccadilly</span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=923720" target="_blank"><span class="title">Java Developer </span><span class="location">Estonia </span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=493517" target="_blank"><span class="title">Java Developer </span><span class="location">Estonia </span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=493500" target="_blank"><span class="title">Java Developer - Cloud Platform</span><span class="location">Estonia </span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=721812" target="_blank"><span class="title">Java Developer - Games Development</span><span class="location">London, Piccadilly</span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=927697" target="_blank"><span class="title">Java Developer - Games Development (Bingo)</span><span class="location">London, Piccadilly</span></a>
<a href="http://www.gamesyscorporate.com/careers/jobs/?gh_jid=874603" target="_blank"><span class="title">Senior Java Developer - Payments</span><span class="location">London, Piccadilly</span></a>

As you can see, I retrieved the logs from web crawler, and then ran grep command to get latest “Java Developer” vacancies available 🙂

If you run the job again, with the same name, it will fail:

➜  ~ kubectl run crawler --restart=OnFailure --image=kayan/web-crawler -- http://www.gamesyscorporate.com http://www.gamesyscorporate.com 3
Error from server (AlreadyExists): jobs.batch "crawler" already exists
➜  ~

To do it again, you need to delete the job first, it might look strange, as even though pod doesn’t exists, the job will still be there:

➜  ~ kubectl delete job crawler
job "crawler" deleted

Now let’s run it again, and this time, retrieve the logs as it happens, real-time:

➜  ~ kubectl logs -f crawler-97d6q
crawling to: http://www.gamesyscorporate.com with domain: http://www.gamesyscorporate.com with number of threads: 3
jobs: 42
processed link: 4
jobs: 48
processed link: 6
jobs: 47
...
....
p