Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kubernetes job and deployment

can I run a job and a deploy in a single config file/action Where the deploy will wait for the job to finish and check if it's successful so it can continue with the deployment?

like image 292
Igor Igeto Mitkovski Avatar asked Mar 18 '20 11:03

Igor Igeto Mitkovski


2 Answers

Based on the information you provided I believe you can achieve your goal using a Kubernetes feature called InitContainer:

Init containers are exactly like regular containers, except:

  • Init containers always run to completion.
  • Each init container must complete successfully before the next one starts.

If a Pod’s init container fails, Kubernetes repeatedly restarts the Pod until the init container succeeds. However, if the Pod has a restartPolicy of Never, Kubernetes does not restart the Pod.

  • I'll create a initContainer with a busybox to run a command linux to wait for the service mydb to be running before proceeding with the deployment.

Steps to Reproduce: - Create a Deployment with an initContainer which will run the job that needs to be completed before doing the deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: my-app
  name: my-app
spec:
  replicas: 2
  selector:
    matchLabels:
      run: my-app
  template:
    metadata:
      labels:
        run: my-app
    spec:
      restartPolicy: Always
      containers:
      - name: myapp-container
        image: busybox:1.28
        command: ['sh', '-c', 'echo The app is running! && sleep 3600']
      initContainers:
      - name: init-mydb
        image: busybox:1.28
        command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]

Many kinds of commands can be used in this field, you just have to select a docker image that contains the binary you need (including your sequelize job)

  • Now let's apply it see the status of the deployment:
$ kubectl apply -f my-app.yaml 
deployment.apps/my-app created

$ kubectl get pods
NAME                      READY   STATUS     RESTARTS   AGE
my-app-6b4fb4958f-44ds7   0/1     Init:0/1   0          4s
my-app-6b4fb4958f-s7wmr   0/1     Init:0/1   0          4s

The pods are hold on Init:0/1 status waiting for the completion of the init container. - Now let's create the service which the initcontainer is waiting to be running before completing his task:

apiVersion: v1
kind: Service
metadata:
  name: mydb
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9377
  • We will apply it and monitor the changes in the pods:
$ kubectl apply -f mydb-svc.yaml 
service/mydb created

$ kubectl get pods -w
NAME                      READY   STATUS     RESTARTS   AGE
my-app-6b4fb4958f-44ds7   0/1     Init:0/1   0          91s
my-app-6b4fb4958f-s7wmr   0/1     Init:0/1   0          91s
my-app-6b4fb4958f-s7wmr   0/1     PodInitializing   0          93s
my-app-6b4fb4958f-44ds7   0/1     PodInitializing   0          94s
my-app-6b4fb4958f-s7wmr   1/1     Running           0          94s
my-app-6b4fb4958f-44ds7   1/1     Running           0          95s
^C
$ kubectl get all
NAME                          READY   STATUS    RESTARTS   AGE
pod/my-app-6b4fb4958f-44ds7   1/1     Running   0          99s
pod/my-app-6b4fb4958f-s7wmr   1/1     Running   0          99s

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/mydb         ClusterIP   10.100.106.67   <none>        80/TCP    14s

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/my-app   2/2     2            2           99s

NAME                                DESIRED   CURRENT   READY   AGE
replicaset.apps/my-app-6b4fb4958f   2         2         2       99s

If you need help to apply this to your environment let me know.

like image 183
Will R.O.F. Avatar answered Oct 24 '22 07:10

Will R.O.F.


Although initContainers are a viable option for this solution, there is another if you use helm to manage and deploy to your cluster.

Helm has chart hooks that allow you to run a Job before other installations in the helm chart occur. You mentioned that this is for a database migration before a service deployment. Some example helm config to get this done could be...

apiVersion: batch/v1
kind: Job
metadata:
  name: api-migration-job
  namespace: default
  labels:
    app: api-migration-job
  annotations:
    "helm.sh/hook": pre-install,pre-upgrade
    "helm.sh/hook-weight": "-1"
    "helm.sh/hook-delete-policy": before-hook-creation
spec:
  template:
    spec:
      containers:
        - name: platform-migration
        ...

This will run the job to completion before moving on to the installation / upgrade phases in the helm chart. You can see there is a 'hook-weight' variable that allows you to order these hooks if you desire.

This in my opinion is a more elegant solution than init containers, and allows for better control.

like image 22
iquestionshard Avatar answered Oct 24 '22 05:10

iquestionshard